diff --git a/.cspell/config.txt b/.cspell/config.txt index d672b2c5..c5b08d09 100644 --- a/.cspell/config.txt +++ b/.cspell/config.txt @@ -198,3 +198,11 @@ difftool apos hpdy tagname +Aftertabs +GKHF +cyclonedx +cpes +UNINDEXED +unindexed +logrus +JSONLINT diff --git a/.ecrc b/.ecrc new file mode 100644 index 00000000..d5485de8 --- /dev/null +++ b/.ecrc @@ -0,0 +1,20 @@ +{ + "Verbose": false, + "Debug": false, + "IgnoreDefaults": false, + "SpacesAftertabs": false, + "NoColor": false, + "Exclude": [ + "/testsData/" + ], + "AllowedContentTypes": [], + "PassedFiles": [], + "Disable": { + "EndOfLine": false, + "Indentation": false, + "IndentSize": false, + "InsertFinalNewline": false, + "TrimTrailingWhitespace": false, + "MaxLineLength": false + } +} diff --git a/.editorconfig b/.editorconfig index ef6f79f3..d2e3815a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,3 +9,6 @@ indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true + +[.vscode/*.json] +indent_size = unset diff --git a/.eslintrc.js b/.eslintrc.js index 7aa56036..baf95796 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,5 +24,21 @@ module.exports = { commonjs: true, node: true, }, - extends: ['eslint:recommended', 'plugin:prettier/recommended'], + plugins: ['json'], + extends: [ + 'eslint:recommended', + 'plugin:json/recommended', + 'eslint-config-prettier', + ], + rules: { + 'json/*': ['error', {allowComments: false}], + }, + overrides: [ + { + files: ['.vscode/*.json'], + rules: { + 'json/*': ['error', {allowComments: true}], + }, + }, + ], }; diff --git a/.framework-config b/.framework-config index 75f39500..919cd65d 100755 --- a/.framework-config +++ b/.framework-config @@ -2,11 +2,14 @@ # shellcheck disable=SC2034 BASH_TOOLS_ROOT_DIR="$(cd -- "$(dirname -- "${CURRENT_LOADED_ENV_FILE}")" &>/dev/null && pwd -P)" -FRAMEWORK_ROOT_DIR="${FRAMEWORK_ROOT_DIR:-${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework}" -FRAMEWORK_SRC_DIR="${FRAMEWORK_SRC_DIR:-${FRAMEWORK_ROOT_DIR}/src}" -FRAMEWORK_BIN_DIR="${FRAMEWORK_BIN_DIR:-${FRAMEWORK_ROOT_DIR}/bin}" -FRAMEWORK_VENDOR_DIR="${FRAMEWORK_VENDOR_DIR:-${FRAMEWORK_ROOT_DIR}/vendor}" -FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_VENDOR_BIN_DIR:-${FRAMEWORK_ROOT_DIR}/vendor/bin}" +FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" +FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" +FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" +FRAMEWORK_VENDOR_DIR="${BASH_TOOLS_ROOT_DIR}/vendor" +FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_VENDOR_DIR}/bin" + +# allows to generate bin file in the right directory +export BASH_TOOLS_ROOT_DIR # compile parameters # srcFile : file that needs to be compiled @@ -16,7 +19,7 @@ FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_VENDOR_BIN_DIR:-${FRAMEWORK_ROOT_DIR}/vend # srcDirs : additional directories where to find the functions COMPILE_PARAMETERS=( --src-dir "${BASH_TOOLS_ROOT_DIR}/src" - --src-dir "${FRAMEWORK_SRC_DIR}" + --src-dir "${FRAMEWORK_ROOT_DIR}/src" --bin-dir "${BASH_TOOLS_ROOT_DIR}/bin" --root-dir "${BASH_TOOLS_ROOT_DIR}" --template-dir "${BASH_TOOLS_ROOT_DIR}/src" @@ -40,6 +43,7 @@ fi # export here all the variables that will be used in your templates export REPOSITORY_URL="${REPOSITORY_URL:-https://github.com/fchastanet/bash-tools}" +SRC_FILE_PATH="${CURRENT_COMPILED_RELATIVE_FILE#/}" BASH_FRAMEWORK_THEME="${BASH_FRAMEWORK_THEME:-default}" BASH_FRAMEWORK_LOG_LEVEL="${BASH_FRAMEWORK_LOG_LEVEL:-0}" diff --git a/.github/workflows/docsify-gh-pages.yml b/.github/workflows/docsify-gh-pages.yml index 7c786cba..ce53e628 100644 --- a/.github/workflows/docsify-gh-pages.yml +++ b/.github/workflows/docsify-gh-pages.yml @@ -31,6 +31,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Docker Buildx + # kics-scan ignore-line uses: docker/setup-buildx-action@v3 - name: docker pull image diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml index 07b508c9..4f60bbde 100644 --- a/.github/workflows/lint-test.yml +++ b/.github/workflows/lint-test.yml @@ -9,6 +9,8 @@ on: # yamllint disable-line rule:truthy - '**' workflow_dispatch: +permissions: read-all + jobs: build: runs-on: ubuntu-22.04 @@ -55,17 +57,21 @@ jobs: runPrecommitTests: false steps: - name: Checkout + # kics-scan ignore-line uses: actions/checkout@v4 - name: Set up Docker Buildx + # kics-scan ignore-line uses: docker/setup-buildx-action@v3 - name: Login to DockerHub + # kics-scan ignore-line uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + # kics-scan ignore-line - uses: ouzi-dev/commit-status-updater@v2 with: name: build bash-tools-${{matrix.vendor}}-${{matrix.bashTarVersion}} @@ -74,6 +80,7 @@ jobs: # only if pre-commit - name: Set up Python if: matrix.runPrecommitTests + # kics-scan ignore-line uses: actions/setup-python@v4 with: python-version: 3.9 @@ -82,6 +89,7 @@ jobs: if: matrix.runPrecommitTests run: pip install pre-commit + # kics-scan ignore-line - uses: ouzi-dev/commit-status-updater@v2 if: matrix.runPrecommitTests with: @@ -95,6 +103,7 @@ jobs: - name: Archive results if: matrix.runPrecommitTests && always() continue-on-error: true + # kics-scan ignore-line uses: actions/upload-artifact@v3 with: name: linter-reports @@ -103,6 +112,7 @@ jobs: - name: Create Pull Request if: matrix.runPrecommitTests && failure() + # kics-scan ignore-line uses: peter-evans/create-pull-request@v5 with: branch: update/pre-commit-fixes @@ -112,6 +122,7 @@ jobs: some auto fixes have been generated during pre-commit run labels: updates + # kics-scan ignore-line - uses: ouzi-dev/commit-status-updater@v2 if: matrix.runPrecommitTests && always() with: @@ -139,11 +150,13 @@ jobs: - name: Upload Test Results if: always() + # kics-scan ignore-line uses: actions/upload-artifact@v3 with: name: Test Results ${{matrix.vendor}} ${{matrix.bashTarVersion}} path: logs/report.xml + # kics-scan ignore-line - uses: ouzi-dev/commit-status-updater@v2 if: always() with: @@ -165,19 +178,23 @@ jobs: pull-requests: write steps: - name: Download Artifacts + # kics-scan ignore-line uses: actions/download-artifact@v3 with: path: artifacts - name: Checkstyle aggregation + # kics-scan ignore-line uses: lcollins/checkstyle-github-action@v2.0.0 with: path: 'artifacts/**/*.xml' # run this action to get the workflow conclusion # You can get the conclusion via env (env.WORKFLOW_CONCLUSION) + # kics-scan ignore-line - uses: technote-space/workflow-conclusion-action@v3 + # kics-scan ignore-line - uses: ouzi-dev/commit-status-updater@v2 with: name: build diff --git a/.github/workflows/precommit-autoupdate.yml b/.github/workflows/precommit-autoupdate.yml index e66e4db0..07fa3313 100644 --- a/.github/workflows/precommit-autoupdate.yml +++ b/.github/workflows/precommit-autoupdate.yml @@ -7,13 +7,18 @@ on: schedule: # https://crontab.cronhub.io/ - cron: '30 10 * * *' + +permissions: read-all + jobs: auto-update: runs-on: ubuntu-22.04 steps: + # kics-scan ignore-line - uses: actions/checkout@v4 - name: Set up Python + # kics-scan ignore-line uses: actions/setup-python@v4 with: python-version: 3.9 @@ -25,6 +30,7 @@ jobs: run: pre-commit autoupdate - name: Create Pull Request + # kics-scan ignore-line uses: peter-evans/create-pull-request@v5 with: branch: update/pre-commit-autoupdate diff --git a/.github/workflows/set-github-status-on-pr-approved.yml b/.github/workflows/set-github-status-on-pr-approved.yml index fa00d283..b2885b2b 100644 --- a/.github/workflows/set-github-status-on-pr-approved.yml +++ b/.github/workflows/set-github-status-on-pr-approved.yml @@ -6,13 +6,17 @@ on: pull_request_review: types: [submitted] +permissions: read-all + jobs: build: if: github.event.review.state == 'approved' runs-on: ubuntu-22.04 steps: + # kics-scan ignore-line - uses: actions/checkout@v4 - name: Run the action # You would run your tests before this using the output to set state/desc + # kics-scan ignore-line uses: Sibz/github-status-action@v1 with: authToken: ${{secrets.GITHUB_TOKEN}} diff --git a/.gitignore b/.gitignore index efb08e98..99231b08 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,8 @@ bin/runBuildContainer /bin/test /bin/buildPushDockerImages /bin/buildPushDockerImage + +# node modules +node_modules/ +package*.json +yarn.lock diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 00000000..0579adfd --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,20 @@ + +title = "gitleaks config" + +[extend] +# useDefault will extend the base configuration with the default gitleaks config: +# https://github.com/zricethezav/gitleaks/blob/master/config/gitleaks.toml +useDefault = true + +[allowlist] + description = "Allowlisted files" + paths = [ + '''.automation/test''', + '''megalinter-reports''', + '''.github/linters''', + '''(.*?)/testsData/''', + '''(.*?)tests/data/''', + '''(.*?)tests/tools/data/''', + '''(.*?)gitleaks\.toml$''', + '''(.*?)(png|jpg|gif|doc|docx|pdf|bin|xls|pyc|zip)$''' + ] diff --git a/.grype.yaml b/.grype.yaml new file mode 100644 index 00000000..a1c0278a --- /dev/null +++ b/.grype.yaml @@ -0,0 +1,144 @@ +# enable/disable checking for application updates on startup +# same as GRYPE_CHECK_FOR_APP_UPDATE env var +# check-for-app-update: true + +# allows users to specify which image source should be used to generate the sbom +# valid values are: registry, docker, podman +# same as GRYPE_DEFAULT_IMAGE_PULL_SOURCE env var +# default-image-pull-source: "" + +# same as --name; set the name of the target being analyzed +# name: "" + +# upon scanning, if a severity is found at or above the given severity then the return code will be 1 +# default is unset which will skip this validation (options: negligible, low, medium, high, critical) +# same as --fail-on ; GRYPE_FAIL_ON_SEVERITY env var +fail-on-severity: 'high' + +# the output format of the vulnerability report (options: table, json, cyclonedx) +# same as -o ; GRYPE_OUTPUT env var +# output: "table" + +# suppress all output (except for the vulnerability list) +# same as -q ; GRYPE_QUIET env var +# quiet: false + +# write output report to a file (default is to write to stdout) +# same as --file; GRYPE_FILE env var +# file: "" + +# a list of globs to exclude from scanning, for example: +# exclude: +# - '/etc/**' +# - './out/**/*.json' +# same as --exclude ; GRYPE_EXCLUDE env var +# exclude: [] + +# os and/or architecture to use when referencing container images (e.g. "windows/armv6" or "arm64") +# same as --platform; GRYPE_PLATFORM env var +# platform: "" + +# If using SBOM input, automatically generate CPEs when packages have none +# add-cpes-if-none: false + +# Explicitly specify a linux distribution to use as : like alpine:3.10 +# distro: + +# db: +# check for database updates on execution +# same as GRYPE_DB_AUTO_UPDATE env var +# auto-update: true + +# location to write the vulnerability database cache +# same as GRYPE_DB_CACHE_DIR env var +# cache-dir: "$XDG_CACHE_HOME/grype/db" + +# URL of the vulnerability database +# same as GRYPE_DB_UPDATE_URL env var +# update-url: "https://toolbox-data.anchore.io/grype/databases/listing.json" + +# it ensures db build is no older than the max-allowed-built-age +# set to false to disable check +# validate-age: true + +# Max allowed age for vulnerability database, +# age being the time since it was built +# Default max age is 120h (or five days) +# max-allowed-built-age: "120h" + +# search: +# the search space to look for packages (options: all-layers, squashed) +# same as -s ; GRYPE_SEARCH_SCOPE env var +# scope: "squashed" + +# search within archives that do contain a file index to search against (zip) +# note: for now this only applies to the java package cataloger +# same as GRYPE_PACKAGE_SEARCH_INDEXED_ARCHIVES env var +# indexed-archives: true + +# search within archives that do not contain a file index to search against (tar, tar.gz, tar.bz2, etc) +# note: enabling this may result in a performance impact since all discovered compressed tars will be decompressed +# note: for now this only applies to the java package cataloger +# same as GRYPE_PACKAGE_SEARCH_UNINDEXED_ARCHIVES env var +# unindexed-archives: false + +# options when pulling directly from a registry via the "registry:" scheme +# registry: +# skip TLS verification when communicating with the registry +# same as GRYPE_REGISTRY_INSECURE_SKIP_TLS_VERIFY env var +# insecure-skip-tls-verify: false +# use http instead of https when connecting to the registry +# same as GRYPE_REGISTRY_INSECURE_USE_HTTP env var +# insecure-use-http: false + +# credentials for specific registries +# auth: +# - # the URL to the registry (e.g. "docker.io", "localhost:5000", etc.) +# same as GRYPE_REGISTRY_AUTH_AUTHORITY env var +# authority: "" +# same as GRYPE_REGISTRY_AUTH_USERNAME env var +# username: "" +# same as GRYPE_REGISTRY_AUTH_PASSWORD env var +# password: "" +# note: token and username/password are mutually exclusive +# same as GRYPE_REGISTRY_AUTH_TOKEN env var +# token: "" +# - ... # note, more credentials can be provided via config file only + +# log: +# use structured logging +# same as GRYPE_LOG_STRUCTURED env var +# structured: false + +# the log level; note: detailed logging suppress the ETUI +# same as GRYPE_LOG_LEVEL env var +# Uses logrus logging levels: https://github.com/sirupsen/logrus#level-logging +# level: "error" + +# location to write the log file (default is not to have a log file) +# same as GRYPE_LOG_FILE env var +# file: "" + +# match: +# sets the matchers below to use cpes when trying to find +# vulnerability matches. The stock matcher is the default +# when no primary matcher can be identified +# java: +# using-cpes: true +# python: +# using-cpes: true +# javascript: +# using-cpes: true +# ruby: +# using-cpes: true +# dotnet: +# using-cpes: true +# golang: +# using-cpes: true +# stock: +# using-cpes: true + +ignore: + # Ignored by default; disputed and unwarranted CVE that causes Megalinter to fail + # @link https://nvd.nist.gov/vuln/detail/CVE-2018-20225 + - vulnerability: CVE-2018-20225 diff --git a/.lycheeignore b/.lycheeignore index 2b8a17b1..089d95dd 100644 --- a/.lycheeignore +++ b/.lycheeignore @@ -13,3 +13,4 @@ https://github.com/plantuml/plantuml/releases/download/v@version@/plantuml-@vers https://github.com/docker/docker-credential-helpers/releases/download/v@version@/docker-credential-wincred-v@version@.windows* https://github.com/Versent/saml2aws/releases/download/v@version@/saml2aws_@version@_linux_amd64.tar.gz https://github.com/fchastanet/bash-tools/tree/master/src/_binaries* +Commands.md diff --git a/.markdown-link-check.json b/.markdown-link-check.json index 642f3823..133fa58c 100644 --- a/.markdown-link-check.json +++ b/.markdown-link-check.json @@ -4,6 +4,9 @@ "ignorePatterns": [ { "pattern": "^http://localhost:.*/" + }, + { + "pattern": "^Commands.md$" } ] } diff --git a/.mega-linter-githubAction.yml b/.mega-linter-githubAction.yml new file mode 100644 index 00000000..9a3ef9c0 --- /dev/null +++ b/.mega-linter-githubAction.yml @@ -0,0 +1,4 @@ +--- +EXTENDS: + - .mega-linter.yml +SHOW_ELAPSED_TIME: false diff --git a/.mega-linter-light.yml b/.mega-linter-light.yml index 4378a2da..40144cf8 100644 --- a/.mega-linter-light.yml +++ b/.mega-linter-light.yml @@ -15,3 +15,4 @@ DISABLE_LINTERS: - REPOSITORY_TRUFFLEHOG # REPOSITORY_GRYPE disabled because too slow - REPOSITORY_GRYPE + - JSON_JSONLINT diff --git a/.mega-linter.yml b/.mega-linter.yml index b1f13524..8e0aba5e 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -18,23 +18,28 @@ DISABLE_LINTERS: - SPELL_VALE - SPELL_LYCHEE - SPELL_PROSELINT + - JSON_JSONLINT # DISABLE_ERRORS: true # Uncomment if you want MegaLinter to detect errors but not block CI to pass EXCLUDED_DIRECTORIES: - '.history' - '.git' - '.idea' - 'logs' + - 'node_modules' FILTER_REGEX_EXCLUDE: | (?x)( \.git/| \.history/| \.idea/| - ^vendor/ + ^vendor/| + ^node_modules/ ) FILEIO_REPORTER: false PRE_COMMANDS: - command: env cwd: 'workspace' + - command: yarn add --dev eslint-plugin-json eslint-config-prettier + cwd: 'workspace' POST_COMMANDS: # FIX files set as root user # HOST_USER_ID and HOST_GROUP_ID set in package.json @@ -66,13 +71,11 @@ CREDENTIALS_SECRETLINT_CONFIG_FILE: .secretlintrc.yml EDITORCONFIG_EDITORCONFIG_CHECKER_FILTER_REGEX_EXCLUDE: | (?x)( \.git/| - /testsData/.*\.(txt|help)| + /testsData/| ^manualTests/data/| - ^src/Log/testsData| - ^Gemfile.lock$| bin/bash-tpl| ^doc/guides/Options/generate.*\.md$| - ^pages/Commands.md + ^pages/Commands.md| ^.*-megalinter_file_names_cspell.txt ) @@ -95,9 +98,14 @@ JAVASCRIPT_DEFAULT_STYLE: prettier JAVASCRIPT_ES_CONFIG_FILE: .eslintrc.js JAVASCRIPT_ES_FILTER_REGEX_EXCLUDE: (report/) -JSON_JSONLINT_FILTER_REGEX_EXCLUDE: (.vscode/) - -MARKDOWN_MARKDOWN_LINK_CHECK_FILTER_REGEX_EXCLUDE: (report) +MARKDOWN_MARKDOWN_LINK_CHECK_FILTER_REGEX_EXCLUDE: (report/) SPELL_CSPELL_FILTER_REGEX_EXCLUDE: (\.git/|\.history/|IDE/.*/.idea|.*-megalinter_file_names_cspell.txt) SPELL_FILTER_REGEX_EXCLUDE: (\.git/|\.history/|IDE/.*/.idea) + +SPELL_LYCHEE_FILTER_REGEX_EXCLUDE: | + (?x)( + ^pages/Commands.md$ + ) + +JSON_ESLINT_PLUGIN_JSONC_FILE_NAME: .eslintrc.js diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c73fcf60..92b6068e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -63,7 +63,7 @@ repos: exclude: /testsData/ - repo: https://github.com/fchastanet/bash-tools-framework - rev: 2.0.2 + rev: 2.1.0 hooks: - id: fixShebangExecutionBit - id: fixShebangExecutionBitGithubActions @@ -98,6 +98,7 @@ repos: - id: buildShFiles - id: buildShFilesGithubAction - id: runUnitTests + args: [-r, src, -j, '1'] # not manual as github will run UT with several versions of bash and arch stages: [pre-commit] - id: megalinterCheckVersion diff --git a/.secretlintrc.json b/.secretlintrc.json new file mode 100644 index 00000000..7a1a5df3 --- /dev/null +++ b/.secretlintrc.json @@ -0,0 +1,7 @@ +{ + "rules": [ + { + "id": "@secretlint/secretlint-rule-preset-recommend" + } + ] +} diff --git a/bin/cli b/bin/cli index ecfad827..f233db79 100755 --- a/bin/cli +++ b/bin/cli @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/cli +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/cli # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if command specified exists or return 1 # with error and message if not # @@ -1180,6 +1203,7 @@ cliCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1472,11 +1496,11 @@ cliCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "easy connection to docker container")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "easy connection to docker container")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1485,89 +1509,93 @@ cliCommand() { local -a helpArray # shellcheck disable=SC2054,SC2206 mapfile -t helpArray < <(containerArgHelpCallback) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " [${__HELP_OPTION_COLOR}user${__HELP_NORMAL} {single}]" local -a helpArray # shellcheck disable=SC2054,SC2206 mapfile -t helpArray < <(userArgHelpCallback) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " [${__HELP_OPTION_COLOR}commandArg${__HELP_NORMAL} {single}]" local -a helpArray # shellcheck disable=SC2054,SC2206 mapfile -t helpArray < <(commandArgHelpCallback) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}AVAILABLE PROFILES (from ${PROFILES_DIR})${__HELP_NORMAL} This list can be overridden in ${HOME_PROFILES_DIR} @@ -1603,7 +1631,7 @@ variables ${__HELP_OPTION_COLOR}finalUserArg${__HELP_NORMAL}, ${__HELP_OPTION_CO echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 @@ -1613,36 +1641,36 @@ variables ${__HELP_OPTION_COLOR}finalUserArg${__HELP_NORMAL}, ${__HELP_OPTION_CO containerArgHelpCallback() { Conf::load "cliProfiles" "default" echo "container should be the name of a profile from profile list," - echo "check containers list below." $'\n' - echo "If not provided, it will load the container specified in default configuration." $'\n' - echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" $'\n' + echo "check containers list below." + echo "If not provided, it will load the container specified in default configuration." + echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" echo "Default container: ${__HELP_OPTION_COLOR}${finalContainerArg}${__HELP_NORMAL}" } userArgHelpCallback() { Conf::load "cliProfiles" "default" echo "user to connect on this container" $'\n' - echo "Default user: ${__HELP_OPTION_COLOR}${finalUserArg}${__HELP_NORMAL}" $'\n' - echo " loaded from profile selected as first arg" $'\n' + echo "Default user: ${__HELP_OPTION_COLOR}${finalUserArg}${__HELP_NORMAL}" + echo " loaded from profile selected as first arg" echo " or deduced from default configuration." $'\n' - echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" + echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" $'\n' echo "if first arg is not a profile" } commandArgHelpCallback() { Conf::load "cliProfiles" "default" echo "The command to execute" $'\n' - echo "Default command: ${__HELP_OPTION_COLOR}${finalCommandArg[*]}${__HELP_NORMAL}" $'\n' - echo " loaded from profile selected as first arg" $'\n' - echo " or deduced from default configuration." $'\n' - echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" + echo "Default command: ${__HELP_OPTION_COLOR}${finalCommandArg[*]}${__HELP_NORMAL}" + echo " loaded from profile selected as first arg" + echo " or deduced from default configuration." + echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" $'\n' echo "if first arg is not a profile" } optionHelpCallback() { local containers # shellcheck disable=SC2046 - containers="$(Array::wrap ", " 80 0 $(docker ps --format '{{.Names}}'))" + containers="$(Array::wrap2 ", " 80 0 $(docker ps --format '{{.Names}}'))" local profilesList="" Conf::load "cliProfiles" "default" diff --git a/bin/dbImport b/bin/dbImport index 8669380f..db0da220 100755 --- a/bin/dbImport +++ b/bin/dbImport @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbImport +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbImport # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -110,123 +110,146 @@ Array::contains() { # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if command specified exists or return 1 # with error and message if not # @@ -1544,6 +1567,7 @@ dbImportCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1961,11 +1985,11 @@ dbImportCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Import source db into target db using eventual table filter")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Import source db into target db using eventual table filter")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--profile|-p ]" "[--tables ]" "[--from-dsn|-f ]" "[--skip-schema|-s]" "[--from-aws|-a ]" "[--target-dsn|-t ]" "[--character-set|-c ]" "[--collation-name|-o ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1974,130 +1998,134 @@ dbImportCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ name\ of\ the\ source/remote\ database) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " [${__HELP_OPTION_COLOR}targetDbName${__HELP_NORMAL} {single}]" local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ name\ of\ the\ target\ database\,\ use\ fromDbName\(without\ extension\)\ if\ not\ provided) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}PROFILE OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--profile${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-p ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054,SC2206 mapfile -t helpArray < <(profileOptionHelpCallback) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--tables ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(import\ only\ table\ specified\ in\ the\ list.\ \ If\ aws\ mode\,\ ignore\ profile\ option) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}FROM OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--from-dsn${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-f ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=($'dsn to use for source database\n\\n this option is incompatible with -a|--from-aws option') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=($'dsn to use for source database\n\n this option is incompatible with -a|--from-aws option') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--skip-schema${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-s${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(avoid\ to\ import\ the\ schema) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--from-aws${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-a ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(db\ dump\ will\ be\ downloaded\ from\ s3\ instead\ of\ using\ remote\ db.\ The\ value\ \\ is\ the\ name\ of\ the\ file\ without\ s3\ location\ \(Only\ .gz\ or\ tar.gz\ file\ are\ supported\).\ This\ option\ is\ incompatible\ with\ -f\|--from-dsn\ option) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}TARGET OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--target-dsn${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-t ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(dsn\ to\ use\ for\ target\ database\ \(Default:\ default.local\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--character-set${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-c ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(change\ the\ character\ set\ used\ during\ database\ creation\ \(default\ value:\ utf8\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--collation-name${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-o ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(change\ the\ collation\ name\ used\ during\ database\ creation\ \(default\ value:\ utf8_general_ci\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL} ${PROFILES_DIR-configuration error} @@ -2133,7 +2161,7 @@ ${__HELP_EXAMPLE}TODO${__HELP_NORMAL}""" echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/dbImportProfile b/bin/dbImportProfile index c5ac70d5..dd8279d9 100755 --- a/bin/dbImportProfile +++ b/bin/dbImportProfile @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbImportProfile +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbImportProfile # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if command specified exists or return 1 # with error and message if not # @@ -1273,6 +1296,7 @@ dbImportProfileCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1600,11 +1624,11 @@ dbImportProfileCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "generate optimized profiles to be used by dbImport")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "generate optimized profiles to be used by dbImport")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--profile|-p ]" "[--from-dsn|-f ]" "[--ratio|-r ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1613,96 +1637,100 @@ dbImportProfileCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ name\ of\ the\ source/remote\ database) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--profile${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-p ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ name\ of\ the\ profile\ to\ write\ in\ profiles\ directory.\ \ If\ not\ provided\,\ the\ file\ name\ pattern\ will\ be\ \'auto_\_\.sh\') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--from-dsn${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-f ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(dsn\ to\ use\ for\ source\ database\ \(Default:\ default.remote\)\ if\ not\ provided\,\ the\ file\ name\ pattern\ will\ be\ \'auto_\_\.sh\') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--ratio${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-r ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(define\ the\ ratio\ to\ use\ \(0\ to\ 100%\ -\ default\ 70\).\ \ 0\ means\ profile\ will\ filter\ out\ all\ the\ tables.\ \ 100\ means\ profile\ will\ keep\ all\ the\ tables.\ \ Eg:\ 70\ means\ that\ tables\ with\ size\(table+index\)\ that\ are\ greater\ that\ 70%\ of\ the\ max\ table\ size\ will\ be\ excluded.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL} ${PROFILES_DIR-configuration error} @@ -1729,7 +1757,7 @@ ${dsnList}""" echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/dbImportStream b/bin/dbImportStream index 4b213b9b..9c822392 100755 --- a/bin/dbImportStream +++ b/bin/dbImportStream @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbImportStream +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbImportStream # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -110,123 +110,146 @@ Array::contains() { # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if command specified exists or return 1 # with error and message if not # @@ -1433,6 +1456,7 @@ dbImportStreamCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1795,11 +1819,11 @@ dbImportStreamCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "stream tar.gz file or gz file through mysql")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "stream tar.gz file or gz file through mysql")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--profile|-p ]" "[--tables ]" "[--target-dsn|-t ]" "[--character-set|-c ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1808,108 +1832,112 @@ dbImportStreamCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ of\ the\ file\ that\ will\ be\ streamed\ through\ mysql) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}argTargetDbName${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ name\ of\ the\ mysql\ target\ database) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}PROFILE OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--profile${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-p ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054,SC2206 mapfile -t helpArray < <(profileOptionHelpCallback) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--tables ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(import\ only\ table\ specified\ in\ the\ list.\ \ If\ aws\ mode\,\ ignore\ profile\ option) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}TARGET OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--target-dsn${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-t ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(dsn\ to\ use\ for\ target\ database\ \(Default:\ default.local\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--character-set${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-c ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(change\ the\ character\ set\ used\ during\ database\ creation\ \(default\ value:\ utf8\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL} ${PROFILES_DIR-configuration error} @@ -1936,7 +1964,7 @@ ${dsnList}""" echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/dbQueryAllDatabases b/bin/dbQueryAllDatabases index 40ff9db9..964884c0 100755 --- a/bin/dbQueryAllDatabases +++ b/bin/dbQueryAllDatabases @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbQueryAllDatabases +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbQueryAllDatabases # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # EMBED Db::queryOneDatabase as dbQueryOneDatabase @@ -95,123 +95,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if command specified exists or return 1 # with error and message if not # @@ -1094,8 +1117,8 @@ Log::logSkipped() { # @require Compiler::Embed::requireEmbedBinDir -declare -gx embed_function_DbQueryOneDatabase="${PERSISTENT_TMPDIR:-/tmp}/bin/f94f442fbdd0b7f3ff7df80421405d82/dbQueryOneDatabase" -declare -gx encoded_binary_file_DbQueryOneDatabase="IyEvdXNyL2Jpbi9lbnYgYmFzaAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgR0VORVJBVEVEIEZBQ0FERQojIERPIE5PVCBFRElUIElUCiMgQGdlbmVyYXRlZAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjI4OCxTQzIwMzQKIyBCSU5fRklMRT0ke0JJTl9GSUxFfQojIEZBQ0FERQoKIyBlbnN1cmUgdGhhdCBubyB1c2VyIGFsaWFzZXMgY291bGQgaW50ZXJmZXJlIHdpdGgKIyBjb21tYW5kcyB1c2VkIGluIHRoaXMgc2NyaXB0CnVuYWxpYXMgLWEgfHwgdHJ1ZQpzaG9wdCAtdSBleHBhbmRfYWxpYXNlcwoKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CigoZmFpbHVyZXMgPSAwKSkgfHwgdHJ1ZQoKIyBCYXNoIHdpbGwgcmVtZW1iZXIgJiByZXR1cm4gdGhlIGhpZ2hlc3QgZXhpdCBjb2RlIGluIGEgY2hhaW4gb2YgcGlwZXMuCiMgVGhpcyB3YXkgeW91IGNhbiBjYXRjaCB0aGUgZXJyb3IgaW5zaWRlIHBpcGVzLCBlLmcuIG15c3FsZHVtcCB8IGd6aXAKc2V0IC1vIHBpcGVmYWlsCnNldCAtbyBlcnJleGl0CgojIENvbW1hbmQgU3Vic3RpdHV0aW9uIGNhbiBpbmhlcml0IGVycmV4aXQgb3B0aW9uIHNpbmNlIGJhc2ggdjQuNApzaG9wdCAtcyBpbmhlcml0X2VycmV4aXQgfHwgdHJ1ZQoKIyBhIGxvZyBpcyBnZW5lcmF0ZWQgd2hlbiBhIGNvbW1hbmQgZmFpbHMKc2V0IC1vIGVycnRyYWNlCgojIHVzZSBudWxsZ2xvYiBzbyB0aGF0IChmaWxlKi5waHApIHdpbGwgcmV0dXJuIGFuIGVtcHR5IGFycmF5IGlmIG5vIGZpbGUgbWF0Y2hlcyB0aGUgd2lsZGNhcmQKc2hvcHQgLXMgbnVsbGdsb2IKCiMgZW5zdXJlIHJlZ2V4cCBhcmUgaW50ZXJwcmV0ZWQgd2l0aG91dCBhY2NlbnR1YXRlZCBjaGFyYWN0ZXJzCmV4cG9ydCBMQ19BTEw9UE9TSVgKCmV4cG9ydCBURVJNPXh0ZXJtLTI1NmNvbG9yCgojIGF2b2lkIGludGVyYWN0aXZlIGluc3RhbGwKZXhwb3J0IERFQklBTl9GUk9OVEVORD1ub25pbnRlcmFjdGl2ZQpleHBvcnQgREVCQ09ORl9OT05JTlRFUkFDVElWRV9TRUVOPXRydWUKCiMgc3RvcmUgY29tbWFuZCBhcmd1bWVudHMgZm9yIGxhdGVyIHVzYWdlCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNApkZWNsYXJlIC1hIEJBU0hfRlJBTUVXT1JLX0FSR1Y9KCIkQCIpCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNApkZWNsYXJlIC1hIE9SSUdJTkFMX0JBU0hfRlJBTUVXT1JLX0FSR1Y9KCIkQCIpCgojIEBzZWUgaHR0cHM6Ly91bml4LnN0YWNrZXhjaGFuZ2UuY29tL2EvMzg2ODU2CiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjMxNwppbnRlcnJ1cHRNYW5hZ2VtZW50KCkgewogICMgcmVzdG9yZSBTSUdJTlQgaGFuZGxlcgogIHRyYXAgLSBJTlQKICAjIGVuc3VyZSB0aGF0IEN0cmwtQyBpcyB0cmFwcGVkIGJ5IHRoaXMgc2NyaXB0IGFuZCBub3QgYnkgc3ViIHByb2Nlc3MKICAjIHJlcG9ydCB0byB0aGUgcGFyZW50IHRoYXQgd2UgaGF2ZSBpbmRlZWQgYmVlbiBpbnRlcnJ1cHRlZAogIGtpbGwgLXMgSU5UICIkJCIKfQp0cmFwIGludGVycnVwdE1hbmFnZW1lbnQgSU5UClNDUklQVF9OQU1FPSR7MCMjKi99ClJFQUxfU0NSSVBUX0ZJTEU9IiQocmVhZGxpbmsgLWUgIiQocmVhbHBhdGggIiR7QkFTSF9TT1VSQ0VbMF19IikiKSIKaWYgW1sgLW4gIiR7RU1CRURfQ1VSUkVOVF9ESVJ9IiBdXTsgdGhlbgogIENVUlJFTlRfRElSPSIke0VNQkVEX0NVUlJFTlRfRElSfSIKZWxzZQogIENVUlJFTlRfRElSPSIkKGNkICIkKHJlYWRsaW5rIC1lICIke1JFQUxfU0NSSVBUX0ZJTEUlLyp9IikiICYmIHB3ZCAtUCkiCmZpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBUZW1wIGRpciBtYW5hZ2VtZW50CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKS0VFUF9URU1QX0ZJTEVTPSIke0tFRVBfVEVNUF9GSUxFUzotMH0iCmV4cG9ydCBLRUVQX1RFTVBfRklMRVMKCiMgUEVSU0lTVEVOVF9UTVBESVIgaXMgbm90IGRlbGV0ZWQgYnkgdHJhcHMKUEVSU0lTVEVOVF9UTVBESVI9IiR7VE1QRElSOi0vdG1wfS9iYXNoLWZyYW1ld29yayIKZXhwb3J0IFBFUlNJU1RFTlRfVE1QRElSCm1rZGlyIC1wICIke1BFUlNJU1RFTlRfVE1QRElSfSIKCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNApUTVBESVI9IiQobWt0ZW1wIC1kIC1wICIke1BFUlNJU1RFTlRfVE1QRElSOi0vdG1wfSIgLXQgYmFzaC1mcmFtZXdvcmstJCQtWFhYWFhYKSIKZXhwb3J0IFRNUERJUgoKIyB0ZW1wIGRpciBjbGVhbmluZwojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIzMTcKY2xlYW5PbkV4aXQoKSB7CiAgaWYgW1sgIiR7S0VFUF9URU1QX0ZJTEVTOi0wfSIgPSAiMSIgXV07IHRoZW4KICAgIExvZzo6ZGlzcGxheUluZm8gIktFRVBfVEVNUF9GSUxFUz0xIHRlbXAgZmlsZXMga2VwdCBoZXJlICcke1RNUERJUn0nIgogIGVsaWYgW1sgLW4gIiR7VE1QRElSK3h4eH0iIF1dOyB0aGVuCiAgICBMb2c6OmRpc3BsYXlEZWJ1ZyAiS0VFUF9URU1QX0ZJTEVTPTAgcmVtb3ZpbmcgdGVtcCBmaWxlcyAnJHtUTVBESVJ9JyIKICAgIHJtIC1SZiAiJHtUTVBESVI6LS90bXAvZmFrZX0iID4vZGV2L251bGwgMj4mMQogIGZpCn0KdHJhcCBjbGVhbk9uRXhpdCBFWElUIEhVUCBRVUlUIEFCUlQgVEVSTQoKIyBWQVJfTUFJTl9GVU5DVElPTl9WQVJfTkFNRT1kYlF1ZXJ5QWxsRGF0YWJhc2VzRmFjYWRlCgojIEBkZXNjcmlwdGlvbiB1c2VkIHRvIGV4ZWN1dGUgZ2l2ZW4gcXVlcnkgd2hlbiB1c2luZwojIGRiU2NyaXB0QWxsRGF0YWJhc2VzCiMgQGFyZyAkMSBkc246U3RyaW5nCiMgQGFyZyAkMiBkYjpTdHJpbmcKIyBAZW52IHF1ZXJ5IFN0cmluZwojIEBlbnYgb3B0aW9uU2VwYXJhdG9yIFN0cmluZwojIEByZXF1aXJlIExpbnV4OjpyZXF1aXJlRXhlY3V0ZWRBc1VzZXIKRGI6OnF1ZXJ5T25lRGF0YWJhc2UoKSB7CiAgIyBxdWVyeSBhbmQgb3B0aW9uU2VwYXJhdG9yIGFyZSBwYXNzZWQgdmlhIGV4cG9ydAogIGxvY2FsIGRzbj0iJDEiCiAgbG9jYWwgZGI9IiQyIgoKICBsb2NhbCAtQSBkYkluc3RhbmNlCiAgRGF0YWJhc2U6Om5ld0luc3RhbmNlIGRiSW5zdGFuY2UgIiR7ZHNufSIKICBEYXRhYmFzZTo6c2V0UXVlcnlPcHRpb25zIGRiSW5zdGFuY2UgIiR7ZGJJbnN0YW5jZVtRVUVSWV9PUFRJT05TXX0gLS1jb25uZWN0LXRpbWVvdXQ9NSIKCiAgIyBpZGVudGlmeSBjb2x1bW5zIGhlYWRlcgogIGVjaG8gLW4gIkBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAIgogIERhdGFiYXNlOjpza2lwQ29sdW1uTmFtZXMgZGJJbnN0YW5jZSAwCgogICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NAogIGlmICEgRGF0YWJhc2U6OnF1ZXJ5IGRiSW5zdGFuY2UgIiR7cXVlcnl9IiAiJHtkYn0iIHwgc2VkICJzL1x0LyR7b3B0aW9uU2VwYXJhdG9yfS9nIjsgdGhlbgogICAgTG9nOjpmYXRhbCAiZGF0YWJhc2UgJHtkYn0gZXJyb3IiIDE+JjIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBMb2cgbmFtZXNwYWNlIHByb3ZpZGVzIDIga2luZCBvZiBmdW5jdGlvbnMKIyAtIExvZzo6ZGlzcGxheSogYWxsb3dzIHRvIGRpc3BsYXkgZ2l2ZW4gbWVzc2FnZSB3aXRoCiMgICBnaXZlbiBkaXNwbGF5IGxldmVsCiMgLSBMb2c6OmxvZyogYWxsb3dzIHRvIGxvZyBnaXZlbiBtZXNzYWdlIHdpdGgKIyAgIGdpdmVuIGxvZyBsZXZlbAojIExvZzo6ZGlzcGxheSogZnVuY3Rpb25zIGF1dG9tYXRpY2FsbHkgbG9nIHRoZSBtZXNzYWdlIHRvbwojIEBzZWUgRW52OjpyZXF1aXJlTG9hZCB0byBsb2FkIHRoZSBkaXNwbGF5IGFuZCBsb2cgbGV2ZWwgZnJvbSAuZW52IGZpbGUKCiMgQGRlc2NyaXB0aW9uIGxvZyBsZXZlbCBvZmYKZXhwb3J0IF9fTEVWRUxfT0ZGPTAKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIGVycm9yCmV4cG9ydCBfX0xFVkVMX0VSUk9SPTEKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIHdhcm5pbmcKZXhwb3J0IF9fTEVWRUxfV0FSTklORz0yCiMgQGRlc2NyaXB0aW9uIGxvZyBsZXZlbCBpbmZvCmV4cG9ydCBfX0xFVkVMX0lORk89MwojIEBkZXNjcmlwdGlvbiBsb2cgbGV2ZWwgc3VjY2VzcwpleHBvcnQgX19MRVZFTF9TVUNDRVNTPTMKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIGRlYnVnCmV4cG9ydCBfX0xFVkVMX0RFQlVHPTQKCiMgQGRlc2NyaXB0aW9uIHZlcmJvc2UgbGV2ZWwgb2ZmCmV4cG9ydCBfX1ZFUkJPU0VfTEVWRUxfT0ZGPTAKIyBAZGVzY3JpcHRpb24gdmVyYm9zZSBsZXZlbCBpbmZvCmV4cG9ydCBfX1ZFUkJPU0VfTEVWRUxfSU5GTz0xCiMgQGRlc2NyaXB0aW9uIHZlcmJvc2UgbGV2ZWwgaW5mbwpleHBvcnQgX19WRVJCT1NFX0xFVkVMX0RFQlVHPTIKIyBAZGVzY3JpcHRpb24gdmVyYm9zZSBsZXZlbCBpbmZvCmV4cG9ydCBfX1ZFUkJPU0VfTEVWRUxfVFJBQ0U9MwoKIyBAZGVzY3JpcHRpb24gRGlzcGxheSBtZXNzYWdlIHVzaW5nIGRlYnVnIGNvbG9yIChncmV5KQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlEZWJ1ZygpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgPj0gX19MRVZFTF9ERUJVRykpOyB0aGVuCiAgICBlY2hvIC1lICIke19fREVCVUdfQ09MT1J9REVCVUcgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nRGVidWcgIiQxIgp9CgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgaW5mbyBjb2xvciAoYmcgbGlnaHQgYmx1ZS9mZyB3aGl0ZSkKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpkaXNwbGF5SW5mbygpIHsKICBsb2NhbCB0eXBlPSIkezI6LUlORk99IgogIGlmICgoQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTCA+PSBfX0xFVkVMX0lORk8pKTsgdGhlbgogICAgZWNobyAtZSAiJHtfX0lORk9fQ09MT1J9JHt0eXBlfSAgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nSW5mbyAiJDEiICIke3R5cGV9Igp9CgojIEBkZXNjcmlwdGlvbiBlbnN1cmUgQ09NTUFORF9CSU5fRElSIGVudiB2YXIgaXMgc2V0CiMgYW5kIFBBVEggY29ycmVjdGx5IHByZXBhcmVkCiMgQG5vYXJncwojIEBzZXQgQ09NTUFORF9CSU5fRElSIHN0cmluZyB0aGUgZGlyZWN0b3J5IHdoZXJlIHRvIGZpbmQgdGhpcyBjb21tYW5kCiMgQHNldCBQQVRIIHN0cmluZyBhZGQgZGlyZWN0b3J5IHdoZXJlIHRvIGZpbmQgdGhpcyBjb21tYW5kIGJpbmFyeQpDb21waWxlcjo6RmFjYWRlOjpyZXF1aXJlQ29tbWFuZEJpbkRpcigpIHsKICBDT01NQU5EX0JJTl9ESVI9IiR7Q1VSUkVOVF9ESVJ9IgogIEVudjo6cGF0aFByZXBlbmQgIiR7Q09NTUFORF9CSU5fRElSfSIKfQoKIyBAZGVzY3JpcHRpb24gY3JlYXRlIGEgbmV3IGRiIGluc3RhbmNlCiMgUmV0dXJucyBpbW1lZGlhdGVseSBpZiB0aGUgaW5zdGFuY2UgaXMgYWxyZWFkeSBpbml0aWFsaXplZAojCiMgQGFyZyAkMSBpbnN0YW5jZU5ld0luc3RhbmNlOiZNYXA8U3RyaW5nLFN0cmluZz4gKHBhc3NlZCBieSByZWZlcmVuY2UpIGRhdGFiYXNlIGluc3RhbmNlIHRvIHVzZQojIEBhcmcgJDIgZHNuOlN0cmluZyBkc24gcHJvZmlsZSAtIGxvYWQgdGhlIGRzbi5lbnYgcHJvZmlsZSBkZWR1Y2VkIHVzaW5nIHJ1bGVzIGRlZmluZWQgaW4gQ29uZjo6Z2V0QWJzb2x1dGVGaWxlCiMKIyBAZXhhbXBsZQojICAgZGVjbGFyZSAtQWd4IGRiSW5zdGFuY2UKIyAgIERhdGFiYXNlOjpuZXdJbnN0YW5jZSBkYkluc3RhbmNlICJkZWZhdWx0LmxvY2FsIgojCiMgQGV4aXRjb2RlIDEgaWYgZG5zIGZpbGUgbm90IGFibGUgdG8gbG9hZGVkCkRhdGFiYXNlOjpuZXdJbnN0YW5jZSgpIHsKICBsb2NhbCAtbiBpbnN0YW5jZU5ld0luc3RhbmNlPSQxCiAgbG9jYWwgZHNuPSIkMiIKICBsb2NhbCBEU05fRklMRQoKICBpZiBbWyAtdiBpbnN0YW5jZU5ld0luc3RhbmNlWydJTklUSUFMSVpFRCddICYmICIke2luc3RhbmNlTmV3SW5zdGFuY2VbJ0lOSVRJQUxJWkVEJ106LTB9IiA9PSAiMSIgXV07IHRoZW4KICAgIHJldHVybgogIGZpCgogICMgZmluYWwgYXV0aCBmaWxlIGdlbmVyYXRlZCBmcm9tIGRucyBmaWxlCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnQVVUSF9GSUxFJ109IiIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydEU05fRklMRSddPSIiCgogICMgY2hlY2sgZHNuIGZpbGUKICBEU05fRklMRT0iJChDb25mOjpnZXRBYnNvbHV0ZUZpbGUgImRzbiIgIiR7ZHNufSIgImVudiIpIiB8fCByZXR1cm4gMQogIERhdGFiYXNlOjpjaGVja0RzbkZpbGUgIiR7RFNOX0ZJTEV9IiB8fCByZXR1cm4gMQogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0RTTl9GSUxFJ109IiR7RFNOX0ZJTEV9IgoKICAjIHNoZWxsY2hlY2sgc291cmNlPS9zcmMvRGF0YWJhc2UvdGVzdHNEYXRhL2Rzbl92YWxpZC5lbnYKICBzb3VyY2UgIiR7aW5zdGFuY2VOZXdJbnN0YW5jZVsnRFNOX0ZJTEUnXX0iCgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1VTRVInXT0iJHtVU0VSfSIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydQQVNTV09SRCddPSIke1BBU1NXT1JEfSIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydIT1NUTkFNRSddPSIke0hPU1ROQU1FfSIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydQT1JUJ109IiR7UE9SVH0iCgogICMgZ2VuZXJhdGUgYXV0aEZpbGUgZm9yIGVhc3kgYXV0aGVudGljYXRpb24KICBpbnN0YW5jZU5ld0luc3RhbmNlWydBVVRIX0ZJTEUnXT0kKG1rdGVtcCAtcCAiJHtUTVBESVI6LS90bXB9IiAtdCAibXlzcWwuWFhYWFhYWFhYWFhYIikKICAoCiAgICBlY2hvICJbY2xpZW50XSIKICAgIGVjaG8gInVzZXIgPSAke1VTRVJ9IgogICAgZWNobyAicGFzc3dvcmQgPSAke1BBU1NXT1JEfSIKICAgIGVjaG8gImhvc3QgPSAke0hPU1ROQU1FfSIKICAgIGVjaG8gInBvcnQgPSAke1BPUlR9IgogICkgPiIke2luc3RhbmNlTmV3SW5zdGFuY2VbJ0FVVEhfRklMRSddfSIKCiAgIyBzb21lIG9mIHRob3NlIHZhbHVlcyBjYW4gYmUgb3ZlcnJpZGRlbiB1c2luZyB0aGUgZHNuIGZpbGUKICAjIFNLSVBfQ09MVU1OX05BTUVTIGVuYWJsZWQgYnkgZGVmYXVsdAogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1NLSVBfQ09MVU1OX05BTUVTJ109IiR7U0tJUF9DT0xVTU5fTkFNRVM6LTF9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1NTTF9PUFRJT05TJ109IiR7TVlTUUxfU1NMX09QVElPTlM6LS0tc3NsLW1vZGU9RElTQUJMRUR9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1FVRVJZX09QVElPTlMnXT0iJHtNWVNRTF9RVUVSWV9PUFRJT05TOi0tLWJhdGNoIC0tcmF3IC0tZGVmYXVsdC1jaGFyYWN0ZXItc2V0PXV0Zjh9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0RVTVBfT1BUSU9OUyddPSIke01ZU1FMX0RVTVBfT1BUSU9OUzotLS1kZWZhdWx0LWNoYXJhY3Rlci1zZXQ9dXRmOCAtLWNvbXByZXNzIC0taGV4LWJsb2IgLS1yb3V0aW5lcyAtLXRyaWdnZXJzIC0tc2luZ2xlLXRyYW5zYWN0aW9uIC0tc2V0LWd0aWQtcHVyZ2VkPU9GRiAtLWNvbHVtbi1zdGF0aXN0aWNzPTAgJHtpbnN0YW5jZU5ld0luc3RhbmNlWydTU0xfT1BUSU9OUyddfX0iCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnREJfSU1QT1JUX09QVElPTlMnXT0iJHtEQl9JTVBPUlRfT1BUSU9OUzotLS1jb25uZWN0LXRpbWVvdXQ9NSAtLWJhdGNoIC0tcmF3IC0tZGVmYXVsdC1jaGFyYWN0ZXItc2V0PXV0Zjh9IgoKICBpbnN0YW5jZU5ld0luc3RhbmNlWydJTklUSUFMSVpFRCddPTEKfQoKIyBAZGVzY3JpcHRpb24gbXlzcWwgcXVlcnkgb24gYSBnaXZlbiBkYgojIEB3YXJuaW5nIGNvdWxkIHVzZSBRVUVSWV9PUFRJT05TIHZhcmlhYmxlIGZyb20gZHNuIGlmIGRlZmluZWQKIyBAZXhhbXBsZQojICAgY2F0IGZpbGUuc3FsIHwgRGF0YWJhc2U6OnF1ZXJ5IC4uLgojIEBhcmcgJDEgaW5zdGFuY2VRdWVyeTomTWFwPFN0cmluZyxTdHJpbmc+IChwYXNzZWQgYnkgcmVmZXJlbmNlKSBkYXRhYmFzZSBpbnN0YW5jZSB0byB1c2UKIyBAYXJnICQyIHNxbFF1ZXJ5OlN0cmluZyAob3B0aW9uYWwpIHNxbCBxdWVyeSBvciBzcWwgZmlsZSB0byBleGVjdXRlLiBpZiBub3QgcHJvdmlkZWQgb3IgZW1wdHksIHRoZSBjb21tYW5kIGNhbiBiZSBwaXBlZAojIEBhcmcgJDMgZGJOYW1lOlN0cmluZyAob3B0aW9uYWwpIHRoZSBkYiBuYW1lCiMKIyBAZXhpdGNvZGUgbXlzcWwgY29tbWFuZCBzdGF0dXMgY29kZQpEYXRhYmFzZTo6cXVlcnkoKSB7CiAgbG9jYWwgLW4gaW5zdGFuY2VRdWVyeT0kMQogIGxvY2FsIC1hIG15c3FsQ29tbWFuZD0oKQogIGxvY2FsIC1hIHF1ZXJ5T3B0aW9ucwoKICBteXNxbENvbW1hbmQrPShteXNxbCkKICBteXNxbENvbW1hbmQrPSgiLS1kZWZhdWx0cy1leHRyYS1maWxlPSR7aW5zdGFuY2VRdWVyeVsnQVVUSF9GSUxFJ119IikKICBJRlM9JyAnIHJlYWQgLXIgLWEgcXVlcnlPcHRpb25zIDw8PCIke2luc3RhbmNlUXVlcnlbJ1FVRVJZX09QVElPTlMnXX0iCiAgbXlzcWxDb21tYW5kKz0oIiR7cXVlcnlPcHRpb25zW0BdfSIpCiAgaWYgW1sgIiR7aW5zdGFuY2VRdWVyeVsnU0tJUF9DT0xVTU5fTkFNRVMnXX0iID0gIjEiIF1dOyB0aGVuCiAgICBteXNxbENvbW1hbmQrPSgiLXMiICItLXNraXAtY29sdW1uLW5hbWVzIikKICBmaQogICMgYWRkIG9wdGlvbmFsIGRiIG5hbWUKICBpZiBbWyAtbiAiJHszK3h9IiBdXTsgdGhlbgogICAgbXlzcWxDb21tYW5kKz0oIiQzIikKICBmaQogICMgYWRkIG9wdGlvbmFsIHNxbCBxdWVyeQogIGlmIFtbIC1uICIkezIreH0iICYmIC1uICIkMiIgJiYgISAtZiAiJDIiIF1dOyB0aGVuCiAgICBteXNxbENvbW1hbmQrPSgiLWUiKQogICAgbXlzcWxDb21tYW5kKz0oIiQyIikKICBmaQogIExvZzo6ZGlzcGxheURlYnVnICIkKHByaW50ZiAiZXhlY3V0ZSBjb21tYW5kOiAnJXMnIiAiJHtteXNxbENvbW1hbmRbKl19IikiCgogIGlmIFtbIC1mICIkMiIgXV07IHRoZW4KICAgICIke215c3FsQ29tbWFuZFtAXX0iIDwiJDIiCiAgZWxzZQogICAgIiR7bXlzcWxDb21tYW5kW0BdfSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBzZXQgdGhlIGdlbmVyYWwgb3B0aW9ucyB0byB1c2Ugb24gbXlzcWwgY29tbWFuZCB0byBxdWVyeSB0aGUgZGF0YWJhc2UKIyBEaWZmZXJzIHRoYW4gc2V0T3B0aW9ucyBpbiB0aGUgd2F5IHRoYXQgdGhlc2Ugb3B0aW9ucyBjb3VsZCBjaGFuZ2UgZWFjaCB0aW1lCiMKIyBAYXJnICQxIGluc3RhbmNlU2V0UXVlcnlPcHRpb25zOiZNYXA8U3RyaW5nLFN0cmluZz4gKHBhc3NlZCBieSByZWZlcmVuY2UpIGRhdGFiYXNlIGluc3RhbmNlIHRvIHVzZQojIEBhcmcgJDIgb3B0aW9uc0xpc3Q6U3RyaW5nIHF1ZXJ5IG9wdGlvbnMgbGlzdApEYXRhYmFzZTo6c2V0UXVlcnlPcHRpb25zKCkgewogIGxvY2FsIC1uIGluc3RhbmNlU2V0UXVlcnlPcHRpb25zPSQxCiAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CiAgaW5zdGFuY2VTZXRRdWVyeU9wdGlvbnNbJ1FVRVJZX09QVElPTlMnXT0iJDIiCn0KCiMgQGRlc2NyaXB0aW9uIGJ5IGRlZmF1bHQgd2Ugc2tpcCB0aGUgY29sdW1uIG5hbWVzCiMgYnV0IHNvbWV0aW1lcyB3ZSBuZWVkIGNvbHVtbiBuYW1lcyB0byBkaXNwbGF5IHNvbWUgcmVzdWx0cwojIGRpc2FibGUgdGhpcyBvcHRpb24gdGVtcG9yYXJpbHkgYW5kIHRoZW4gcmVzdG9yZSBpdCB0byB0cnVlCiMKIyBAYXJnICQxIGluc3RhbmNlU2V0UXVlcnlPcHRpb25zOiZNYXA8U3RyaW5nLFN0cmluZz4gKHBhc3NlZCBieSByZWZlcmVuY2UpIGRhdGFiYXNlIGluc3RhbmNlIHRvIHVzZQojIEBhcmcgJDIgc2tpcENvbHVtbk5hbWVzOkJvb2xlYW4gMCB0byBkaXNhYmxlLCAxIHRvIGVuYWJsZSAoaGlkZSBjb2x1bW4gbmFtZXMpCkRhdGFiYXNlOjpza2lwQ29sdW1uTmFtZXMoKSB7CiAgbG9jYWwgLW4gaW5zdGFuY2VTa2lwQ29sdW1uTmFtZXM9JDEKICAjIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKICBpbnN0YW5jZVNraXBDb2x1bW5OYW1lc1snU0tJUF9DT0xVTU5fTkFNRVMnXT0iJDIiCn0KCiMgQGRlc2NyaXB0aW9uIHByZXBlbmQgZGlyZWN0b3JpZXMgdG8gdGhlIFBBVEggZW52aXJvbm1lbnQgdmFyaWFibGUKIyBAYXJnICRAIGFyZ3M6U3RyaW5nW10gbGlzdCBvZiBkaXJlY3RvcmllcyB0byBwcmVwZW5kCiMgQHNldCBQQVRIIHVwZGF0ZSBQQVRIIHdpdGggdGhlIGRpcmVjdG9yaWVzIHByZXBlbmRlZApFbnY6OnBhdGhQcmVwZW5kKCkgewogIGxvY2FsIGFyZwogIGZvciBhcmcgaW4gIiRAIjsgZG8KICAgIGlmIFtbIC1kICIke2FyZ30iICYmICI6JHtQQVRIfToiICE9ICoiOiR7YXJnfToiKiBdXTsgdGhlbgogICAgICBQQVRIPSIkKHJlYWxwYXRoICIke2FyZ30iKToke1BBVEh9IgogICAgZmkKICBkb25lCn0KCiMgQGRlc2NyaXB0aW9uIERpc3BsYXkgbWVzc2FnZSB1c2luZyBlcnJvciBjb2xvciAocmVkKSBhbmQgZXhpdCBpbW1lZGlhdGVseSB3aXRoIGVycm9yIHN0YXR1cyAxCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6ZmF0YWwoKSB7CiAgZWNobyAtZSAiJHtfX0VSUk9SX0NPTE9SfUZBVEFMICAgLSAkezF9JHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgTG9nOjpsb2dGYXRhbCAiJDEiCiAgZXhpdCAxCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dEZWJ1ZygpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+PSBfX0xFVkVMX0RFQlVHKSk7IHRoZW4KICAgIExvZzo6bG9nTWVzc2FnZSAiJHsyOi1ERUJVR30iICIkMSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBsb2cgbWVzc2FnZSB0byBmaWxlCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6bG9nSW5mbygpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+PSBfX0xFVkVMX0lORk8pKTsgdGhlbgogICAgTG9nOjpsb2dNZXNzYWdlICIkezI6LUlORk99IiAiJDEiCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gZW5zdXJlIHJ1bm5pbmcgdXNlciBpcyBub3Qgcm9vdAojIEBleGl0Y29kZSAxIGlmIGN1cnJlbnQgdXNlciBpcyByb290CiMgQHN0ZGVyciBkaWFnbm9zdGljcyBpbmZvcm1hdGlvbiBpcyBkaXNwbGF5ZWQKTGludXg6OnJlcXVpcmVFeGVjdXRlZEFzVXNlcigpIHsKICBpZiBbWyAiJChpZCAtdSkiID0gIjAiIF1dOyB0aGVuCiAgICBMb2c6OmZhdGFsICJ0aGlzIHNjcmlwdCBzaG91bGQgYmUgZXhlY3V0ZWQgYXMgbm9ybWFsIHVzZXIiCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gZ2V0IGFic29sdXRlIGNvbmYgZmlsZSBmcm9tIHNwZWNpZmllZCBjb25mIGZvbGRlciBkZWR1Y2VkIHVzaW5nIHRoZXNlIHJ1bGVzCiMgICAqIGZyb20gYWJzb2x1dGUgZmlsZSAoaWdub3JlcyA8Y29uZkZvbGRlcj4gYW5kIDxleHRlbnNpb24+KQojICAgKiByZWxhdGl2ZSB0byB3aGVyZSBzY3JpcHQgaXMgZXhlY3V0ZWQgKGlnbm9yZXMgPGNvbmZGb2xkZXI+IGFuZCA8ZXh0ZW5zaW9uPikKIyAgICogZnJvbSBob21lLy5iYXNoLXRvb2xzLzxjb25mRm9sZGVyPgojICAgKiBmcm9tIGZyYW1ld29yayBjb25mLzxjb25mRm9sZGVyPgojCiMgQGFyZyAkMSBjb25mRm9sZGVyOlN0cmluZyB0aGUgZGlyZWN0b3J5IG5hbWUgKG5vdCB0aGUgcGF0aCkgdG8gbGlzdAojIEBhcmcgJDIgY29uZjpTdHJpbmcgZmlsZSB0byB1c2Ugd2l0aG91dCBleHRlbnNpb24KIyBAYXJnICQzIGV4dGVuc2lvbjpTdHJpbmcgdGhlIGV4dGVuc2lvbiAoLnNoIGJ5IGRlZmF1bHQpCiMKIyBAc3Rkb3V0IGFic29sdXRlIGNvbmYgZmlsZW5hbWUKIyBAZXhpdGNvZGUgMSBpZiBmaWxlIGlzIG5vdCBmb3VuZCBpbiBhbnkgbG9jYXRpb24KQ29uZjo6Z2V0QWJzb2x1dGVGaWxlKCkgewogIGxvY2FsIGNvbmZGb2xkZXI9IiQxIgogIGxvY2FsIGNvbmY9IiQyIgogIGxvY2FsIGV4dGVuc2lvbj0iJHszLS5zaH0iCiAgaWYgW1sgLW4gIiR7ZXh0ZW5zaW9ufSIgJiYgIiR7ZXh0ZW5zaW9uOjA6MX0iICE9ICIuIiBdXTsgdGhlbgogICAgZXh0ZW5zaW9uPSIuJHtleHRlbnNpb259IgogIGZpCgogIHRlc3RBYnMoKSB7CiAgICBsb2NhbCByZXN1bHQKICAgIHJlc3VsdD0iJChyZWFscGF0aCAtZSAiJDEiIDI+L2Rldi9udWxsKSIKICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE4MQogICAgaWYgW1sgIiQ/IiA9ICIwIiAmJiAtZiAiJHtyZXN1bHR9IiBdXTsgdGhlbgogICAgICBlY2hvICIke3Jlc3VsdH0iCiAgICAgIHJldHVybiAwCiAgICBmaQogICAgcmV0dXJuIDEKICB9CgogICMgY29uZiBpcyBhYnNvbHV0ZSBmaWxlIChpbmNsdWRpbmcgZXh0ZW5zaW9uKQogIHRlc3RBYnMgIiR7Y29uZkZvbGRlcn0ke2V4dGVuc2lvbn0iICYmIHJldHVybiAwCiAgIyBjb25mIGlzIGFic29sdXRlIGZpbGUKICB0ZXN0QWJzICIke2NvbmZGb2xkZXJ9IiAmJiByZXR1cm4gMAogICMgY29uZiBpcyBhYnNvbHV0ZSBmaWxlIChpbmNsdWRpbmcgZXh0ZW5zaW9uKQogIHRlc3RBYnMgIiR7Y29uZn0ke2V4dGVuc2lvbn0iICYmIHJldHVybiAwCiAgIyBjb25mIGlzIGFic29sdXRlIGZpbGUKICB0ZXN0QWJzICIke2NvbmZ9IiAmJiByZXR1cm4gMAoKICAjIHJlbGF0aXZlIHRvIHdoZXJlIHNjcmlwdCBpcyBleGVjdXRlZCAoaW5jbHVkaW5nIGV4dGVuc2lvbikKICBpZiBbWyAtbiAiJHtDVVJSRU5UX0RJUit4eHh9IiBdXTsgdGhlbgogICAgdGVzdEFicyAiJChGaWxlOjpjb25jYXRlbmF0ZVBhdGggIiR7Q1VSUkVOVF9ESVJ9IiAiJHtjb25mRm9sZGVyfSIpLyR7Y29uZn0ke2V4dGVuc2lvbn0iICYmIHJldHVybiAwCiAgZmkKICAjIGZyb20gaG9tZS8uYmFzaC10b29scy88Y29uZkZvbGRlcj4KICB0ZXN0QWJzICIkKEZpbGU6OmNvbmNhdGVuYXRlUGF0aCAiJHtIT01FfS8uYmFzaC10b29scyIgIiR7Y29uZkZvbGRlcn0iKS8ke2NvbmZ9JHtleHRlbnNpb259IiAmJiByZXR1cm4gMAoKICBpZiBbWyAtbiAiJHtGUkFNRVdPUktfUk9PVF9ESVIreHh4fSIgXV07IHRoZW4KICAgICMgZnJvbSBmcmFtZXdvcmsgY29uZi88Y29uZkZvbGRlcj4gKGluY2x1ZGluZyBleHRlbnNpb24pCiAgICB0ZXN0QWJzICIkKEZpbGU6OmNvbmNhdGVuYXRlUGF0aCAiJHtGUkFNRVdPUktfUk9PVF9ESVJ9L2NvbmYiICIke2NvbmZGb2xkZXJ9IikvJHtjb25mfSR7ZXh0ZW5zaW9ufSIgJiYgcmV0dXJuIDAKCiAgICAjIGZyb20gZnJhbWV3b3JrIGNvbmYvPGNvbmZGb2xkZXI+CiAgICB0ZXN0QWJzICIkKEZpbGU6OmNvbmNhdGVuYXRlUGF0aCAiJHtGUkFNRVdPUktfUk9PVF9ESVJ9L2NvbmYiICIke2NvbmZGb2xkZXJ9IikvJHtjb25mfSIgJiYgcmV0dXJuIDAKICBmaQoKICAjIGZpbGUgbm90IGZvdW5kCiAgTG9nOjpkaXNwbGF5RXJyb3IgImNvbmYgZmlsZSAnJHtjb25mfScgbm90IGZvdW5kIgoKICByZXR1cm4gMQp9CgojIEBkZXNjcmlwdGlvbiBjaGVjayBpZiBkc24gZmlsZSBoYXMgYWxsIHRoZSBtYW5kYXRvcnkgdmFyaWFibGVzIHNldAojIE1hbmRhdG9yeSB2YXJpYWJsZXMgYXJlOiBIT1NUTkFNRSwgVVNFUiwgUEFTU1dPUkQsIFBPUlQKIwojIEBhcmcgJDEgZHNuRmlsZU5hbWU6U3RyaW5nIGRzbiBhYnNvbHV0ZSBmaWxlbmFtZQojIEBzZXQgSE9TVE5BTUUgbG9hZGVkIGZyb20gZHNuIGZpbGUKIyBAc2V0IFBPUlQgbG9hZGVkIGZyb20gZHNuIGZpbGUKIyBAc2V0IFVTRVIgbG9hZGVkIGZyb20gZHNuIGZpbGUKIyBAc2V0IFBBU1NXT1JEIGxvYWRlZCBmcm9tIGRzbiBmaWxlCiMgQGV4aXRjb2RlIDAgb24gdmFsaWQgZmlsZQojIEBleGl0Y29kZSAxIGlmIG9uZSBvZiB0aGUgcHJvcGVydGllcyBvZiB0aGUgY29uZiBmaWxlIGlzIGludmFsaWQgb3IgaWYgZmlsZSBub3QgZm91bmQKIyBAc3RkZXJyIGxvZyBvdXRwdXQgaWYgZXJyb3IgZm91bmQgaW4gY29uZiBmaWxlCkRhdGFiYXNlOjpjaGVja0RzbkZpbGUoKSB7CiAgbG9jYWwgZHNuRmlsZU5hbWU9IiQxIgogIGlmIFtbICEgLWYgIiR7ZHNuRmlsZU5hbWV9IiBdXTsgdGhlbgogICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IG5vdCBmb3VuZCIKICAgIHJldHVybiAxCiAgZmkKCiAgKAogICAgdW5zZXQgSE9TVE5BTUUgUE9SVCBQQVNTV09SRCBVU0VSCiAgICAjIHNoZWxsY2hlY2sgc291cmNlPS9zcmMvRGF0YWJhc2UvdGVzdHNEYXRhL2Rzbl92YWxpZC5lbnYKICAgIHNvdXJjZSAiJHtkc25GaWxlTmFtZX0iCiAgICBpZiBbWyAteiAke0hPU1ROQU1FK3h9IF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheUVycm9yICJkc24gZmlsZSAke2RzbkZpbGVOYW1lfSA6IEhPU1ROQU1FIG5vdCBwcm92aWRlZCIKICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiBbWyAteiAiJHtIT1NUTkFNRX0iIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheVdhcm5pbmcgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogSE9TVE5BTUUgdmFsdWUgbm90IHByb3ZpZGVkIgogICAgZmkKICAgIGlmIFtbICIke0hPU1ROQU1FfSIgPSAibG9jYWxob3N0IiBdXTsgdGhlbgogICAgICBMb2c6OmRpc3BsYXlXYXJuaW5nICJkc24gZmlsZSAke2RzbkZpbGVOYW1lfSA6IGNoZWNrIHRoYXQgSE9TVE5BTUUgc2hvdWxkIG5vdCBiZSAxMjcuMC4wLjEgaW5zdGVhZCBvZiBsb2NhbGhvc3QiCiAgICBmaQogICAgaWYgW1sgLXogIiR7UE9SVCt4fSIgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogUE9SVCBub3QgcHJvdmlkZWQiCiAgICAgIHJldHVybiAxCiAgICBmaQogICAgaWYgISBbWyAke1BPUlR9ID1+IF5bMC05XSskIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheUVycm9yICJkc24gZmlsZSAke2RzbkZpbGVOYW1lfSA6IFBPUlQgaW52YWxpZCIKICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiBbWyAteiAiJHtVU0VSK3h9IiBdXTsgdGhlbgogICAgICBMb2c6OmRpc3BsYXlFcnJvciAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gOiBVU0VSIG5vdCBwcm92aWRlZCIKICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiBbWyAteiAiJHtQQVNTV09SRCt4fSIgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogUEFTU1dPUkQgbm90IHByb3ZpZGVkIgogICAgICByZXR1cm4gMQogICAgZmkKICApCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dGYXRhbCgpIHsKICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotRkFUQUx9IiAiJDEiCn0KCiMgQGRlc2NyaXB0aW9uIEludGVybmFsOiBjb21tb24gbG9nIG1lc3NhZ2UKIyBAZXhhbXBsZSB0ZXh0CiMgICBbZGF0ZV18W2xldmVsTXNnXXxtZXNzYWdlCiMKIyBAZXhhbXBsZSB0ZXh0CiMgICAyMDIwLTAxLTE5IDE5OjIwOjIxfEVSUk9SICB8bG9nIGVycm9yCiMgICAyMDIwLTAxLTE5IDE5OjIwOjIxfFNLSVBQRUR8bG9nIHNraXBwZWQKIwojIEBhcmcgJDEgbGV2ZWxNc2c6U3RyaW5nIG1lc3NhZ2UncyBsZXZlbCBkZXNjcmlwdGlvbiAoZWc6IFNUQVRVUywgRVJST1IsIC4uLikKIyBAYXJnICQyIG1zZzpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQojIEBlbnYgQkFTSF9GUkFNRVdPUktfTE9HX0ZJTEUgU3RyaW5nIGxvZyBmaWxlIHRvIHVzZSwgZG8gbm90aGluZyBpZiBlbXB0eQojIEBlbnYgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMIGludCBsb2cgbGV2ZWwgbG9nIG9ubHkgaWYgPiBPRkYgb3IgZmF0YWwgbWVzc2FnZXMKIyBAc3RkZXJyIGRpYWdub3N0aWNzIGluZm9ybWF0aW9uIGlzIGRpc3BsYXllZAojIEByZXF1aXJlIEVudjo6cmVxdWlyZUxvYWQKIyBAcmVxdWlyZSBMb2c6OnJlcXVpcmVMb2FkCkxvZzo6bG9nTWVzc2FnZSgpIHsKICBsb2NhbCBsZXZlbE1zZz0iJDEiCiAgbG9jYWwgbXNnPSIkMiIKICBsb2NhbCBkYXRlCgogIGlmIFtbIC1uICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIgXV0gJiYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPiBfX0xFVkVMX09GRikpOyB0aGVuCiAgICBkYXRlPSIkKGRhdGUgJyslWS0lbS0lZCAlSDolTTolUycpIgogICAgdG91Y2ggIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IgogICAgcHJpbnRmICIlc3wlN3N8JXNcbiIgIiR7ZGF0ZX0iICIke2xldmVsTXNnfSIgIiR7bXNnfSIgPj4iJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gY29uY2F0ZW5hdGUgMiBwYXRocyBhbmQgZW5zdXJlIHRoZSBwYXRoIGlzIGNvcnJlY3QgdXNpbmcgcmVhbHBhdGggLW0KIyBAYXJnICQxIGJhc2VQYXRoOlN0cmluZwojIEBhcmcgJDIgc3ViUGF0aDpTdHJpbmcKIyBAcmVxdWlyZSBMaW51eDo6cmVxdWlyZVJlYWxwYXRoQ29tbWFuZApGaWxlOjpjb25jYXRlbmF0ZVBhdGgoKSB7CiAgbG9jYWwgYmFzZVBhdGg9IiQxIgogIGxvY2FsIHN1YlBhdGg9IiQyIgogIGxvY2FsIGZ1bGxQYXRoPSIke2Jhc2VQYXRoOiske2Jhc2VQYXRofS99JHtzdWJQYXRofSIKCiAgcmVhbHBhdGggLW0gIiR7ZnVsbFBhdGh9IiAyPi9kZXYvbnVsbAp9CgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgZXJyb3IgY29sb3IgKHJlZCkKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpkaXNwbGF5RXJyb3IoKSB7CiAgaWYgKChCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMID49IF9fTEVWRUxfRVJST1IpKTsgdGhlbgogICAgZWNobyAtZSAiJHtfX0VSUk9SX0NPTE9SfUVSUk9SICAgLSAkezF9JHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgZmkKICBMb2c6OmxvZ0Vycm9yICIkMSIKfQoKIyBAZGVzY3JpcHRpb24gRGlzcGxheSBtZXNzYWdlIHVzaW5nIHdhcm5pbmcgY29sb3IgKHllbGxvdykKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpkaXNwbGF5V2FybmluZygpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgPj0gX19MRVZFTF9XQVJOSU5HKSk7IHRoZW4KICAgIGVjaG8gLWUgIiR7X19XQVJOSU5HX0NPTE9SfVdBUk4gICAgLSAkezF9JHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgZmkKICBMb2c6OmxvZ1dhcm5pbmcgIiQxIgp9CgojIEBkZXNjcmlwdGlvbiBlbnN1cmUgZW52IGZpbGVzIGFyZSBsb2FkZWQKIyBAYXJnICRAIGxpc3Qgb2YgZGVmYXVsdCBmaWxlcyB0byBsb2FkIGF0IHRoZSBlbmQKIyBAZXhpdGNvZGUgMSBpZiBvbmUgb2YgZW52IGZpbGVzIGZhaWxzIHRvIGxvYWQKIyBAc3RkZXJyIGRpYWdub3N0aWNzIGluZm9ybWF0aW9uIGlzIGRpc3BsYXllZAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIxMjAKRW52OjpyZXF1aXJlTG9hZCgpIHsKICBsb2NhbCAtYSBkZWZhdWx0RmlsZXM9KCIkQCIpCiAgIyBnZXQgbGlzdCBvZiBwb3NzaWJsZSBjb25maWcgZmlsZXMKICBsb2NhbCAtYSBjb25maWdGaWxlcz0oKQogIGlmIFtbIC1uICIke0JBU0hfRlJBTUVXT1JLX0VOVl9GSUxFU1swXSsxfSIgXV07IHRoZW4KICAgICMgQkFTSF9GUkFNRVdPUktfRU5WX0ZJTEVTIGlzIGFuIGFycmF5CiAgICBjb25maWdGaWxlcys9KCIke0JBU0hfRlJBTUVXT1JLX0VOVl9GSUxFU1tAXX0iKQogIGZpCiAgaWYgW1sgLWYgIiQocHdkKS8uZnJhbWV3b3JrLWNvbmZpZyIgXV07IHRoZW4KICAgIGNvbmZpZ0ZpbGVzKz0oIiQocHdkKS8uZnJhbWV3b3JrLWNvbmZpZyIpCiAgZmkKICBpZiBbWyAtZiAiJHtGUkFNRVdPUktfUk9PVF9ESVJ9Ly5mcmFtZXdvcmstY29uZmlnIiBdXTsgdGhlbgogICAgY29uZmlnRmlsZXMrPSgiJHtGUkFNRVdPUktfUk9PVF9ESVJ9Ly5mcmFtZXdvcmstY29uZmlnIikKICBmaQogIGlmIFtbIC1uICIke29wdGlvbkJhc2hGcmFtZXdvcmtDb25maWd9IiAmJiAtZiAiJHtvcHRpb25CYXNoRnJhbWV3b3JrQ29uZmlnfSIgXV07IHRoZW4KICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNAogICAgY29uZmlnRmlsZXMrPSgiJHtvcHRpb25CYXNoRnJhbWV3b3JrQ29uZmlnfSIpCiAgZmkKICBjb25maWdGaWxlcys9KCIke29wdGlvbkVudkZpbGVzW0BdfSIpCiAgY29uZmlnRmlsZXMrPSgiJHtkZWZhdWx0RmlsZXNbQF19IikKCiAgZm9yIGZpbGUgaW4gIiR7Y29uZmlnRmlsZXNbQF19IjsgZG8KICAgICMgc2hlbGxjaGVjayBzb3VyY2U9Ly5mcmFtZXdvcmstY29uZmlnCiAgICBDVVJSRU5UX0xPQURFRF9FTlZfRklMRT0iJHtmaWxlfSIgc291cmNlICIke2ZpbGV9IiB8fCB7CiAgICAgIExvZzo6ZGlzcGxheUVycm9yICJ3aGlsZSBsb2FkaW5nIGNvbmZpZyBmaWxlOiAke2ZpbGV9IgogICAgICByZXR1cm4gMQogICAgfQogIGRvbmUKfQoKIyBAZGVzY3JpcHRpb24gYWN0aXZhdGUgb3Igbm90IExvZzo6ZGlzcGxheSogYW5kIExvZzo6bG9nKiBmdW5jdGlvbnMKIyBiYXNlZCBvbiBCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMIGFuZCBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwKIyBlbnZpcm9ubWVudCB2YXJpYWJsZXMgbG9hZGVkIGJ5IEVudjo6cmVxdWlyZUxvYWQKIyB0cnkgdG8gY3JlYXRlIGxvZyBmaWxlIGFuZCByb3RhdGUgaXQgaWYgbmVjZXNzYXJ5CiMgQG5vYXJncwojIEBzZXQgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMIGludCB0byBPRkYgbGV2ZWwgaWYgQkFTSF9GUkFNRVdPUktfTE9HX0ZJTEUgaXMgZW1wdHkgb3Igbm90IHdyaXRhYmxlCiMgQGVudiBCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMIGludAojIEBlbnYgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMIGludAojIEBlbnYgQkFTSF9GUkFNRVdPUktfTE9HX0ZJTEUgU3RyaW5nCiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfRklMRV9NQVhfUk9UQVRJT04gaW50IGRvIGxvZyByb3RhdGlvbiBpZiA+IDAKIyBAZXhpdGNvZGUgMCBhbHdheXMgc3VjY2Vzc2Z1bAojIEBzdGRlcnIgZGlhZ25vc3RpY3MgaW5mb3JtYXRpb24gYWJvdXQgbG9nIGZpbGUgaXMgZGlzcGxheWVkCiMgQHJlcXVpcmUgRW52OjpyZXF1aXJlTG9hZAojIEByZXF1aXJlIFVJOjpyZXF1aXJlVGhlbWUKTG9nOjpyZXF1aXJlTG9hZCgpIHsKICBpZiBbWyAteiAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRTotfSIgXV07IHRoZW4KICAgIEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTD0ke19fTEVWRUxfT0ZGfQogICAgZXhwb3J0IEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTAogIGZpCgogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID4gX19MRVZFTF9PRkYpKTsgdGhlbgogICAgaWYgW1sgISAtZiAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iIF1dOyB0aGVuCiAgICAgIGlmCiAgICAgICAgISBta2RpciAtcCAiJChkaXJuYW1lICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIpIiAyPi9kZXYvbnVsbCB8fAogICAgICAgICAgISB0b3VjaCAtLW5vLWNyZWF0ZSAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iIDI+L2Rldi9udWxsCiAgICAgIHRoZW4KICAgICAgICBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtfX0xFVkVMX09GRn0KICAgICAgICBlY2hvIC1lICIke19fRVJST1JfQ09MT1J9RVJST1IgICAtIEZpbGUgJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0gaXMgbm90IHdyaXRhYmxlJHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgICAgIGZpCiAgICBlbGlmIFtbICEgLXcgIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IiBdXTsgdGhlbgogICAgICBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtfX0xFVkVMX09GRn0KICAgICAgZWNobyAtZSAiJHtfX0VSUk9SX0NPTE9SfUVSUk9SICAgLSBGaWxlICR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IGlzIG5vdCB3cml0YWJsZSR7X19SRVNFVF9DT0xPUn0iID4mMgogICAgZmkKCiAgZmkKCiAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPiBfX0xFVkVMX09GRikpOyB0aGVuCiAgICAjIHdpbGwgYWx3YXlzIGJlIGNyZWF0ZWQgZXZlbiBpZiBub3QgaW4gaW5mbyBsZXZlbAogICAgTG9nOjpsb2dNZXNzYWdlICJJTkZPIiAiTG9nZ2luZyB0byBmaWxlICR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IC0gTG9nIGxldmVsICR7QkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMfSIKICAgIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0ZJTEVfTUFYX1JPVEFUSU9OID4gMCkpOyB0aGVuCiAgICAgIExvZzo6cm90YXRlICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIgIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEVfTUFYX1JPVEFUSU9OfSIKICAgIGZpCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gbG9nIG1lc3NhZ2UgdG8gZmlsZQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmxvZ0Vycm9yKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfRVJST1IpKTsgdGhlbgogICAgTG9nOjpsb2dNZXNzYWdlICIkezI6LUVSUk9SfSIgIiQxIgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dXYXJuaW5nKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfV0FSTklORykpOyB0aGVuCiAgICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotV0FSTklOR30iICIkMSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBUbyBiZSBjYWxsZWQgYmVmb3JlIGxvZ2dpbmcgaW4gdGhlIGxvZyBmaWxlCiMgQGFyZyAkMSBmaWxlOnN0cmluZyBsb2cgZmlsZSBuYW1lCiMgQGFyZyAkMiBtYXhMb2dGaWxlc0NvdW50OmludCBtYXhpbXVtIG51bWJlciBvZiBsb2cgZmlsZXMKTG9nOjpyb3RhdGUoKSB7CiAgbG9jYWwgZmlsZT0iJDEiCiAgbG9jYWwgbWF4TG9nRmlsZXNDb3VudD0iJHsyOi01fSIKCiAgaWYgW1sgISAtZiAiJHtmaWxlfSIgXV07IHRoZW4KICAgIExvZzo6ZGlzcGxheVNraXBwZWQgIkxvZyBmaWxlICR7ZmlsZX0gZG9lc24ndCBleGlzdCB5ZXQiCiAgICByZXR1cm4gMAogIGZpCiAgZm9yIGkgaW4gJChzZXEgJCgobWF4TG9nRmlsZXNDb3VudCAtIDEpKSAtMSAxKTsgZG8KICAgIExvZzo6ZGlzcGxheUluZm8gIkxvZyByb3RhdGlvbiAke2ZpbGV9LiR7aX0gdG8gJHtmaWxlfS4kKChpICsgMSkpIgogICAgbXYgIiR7ZmlsZX0uInsiJHtpfSIsIiQoKGkgKyAxKSkifSAmPi9kZXYvbnVsbCB8fCB0cnVlCiAgZG9uZQogIGlmIGNwICIke2ZpbGV9IiAiJHtmaWxlfS4xIiAmPi9kZXYvbnVsbDsgdGhlbgogICAgZWNobyA+IiR7ZmlsZX0iICMgcmVzZXQgbG9nIGZpbGUKICAgIExvZzo6ZGlzcGxheUluZm8gIkxvZyByb3RhdGlvbiAke2ZpbGV9IHRvICR7ZmlsZX0uMSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBlbnN1cmUgY29tbWFuZCByZWFscGF0aCBpcyBhdmFpbGFibGUKIyBAZXhpdGNvZGUgMSBpZiByZWFscGF0aCBjb21tYW5kIG5vdCBhdmFpbGFibGUKIyBAc3RkZXJyIGRpYWdub3N0aWNzIGluZm9ybWF0aW9uIGlzIGRpc3BsYXllZApMaW51eDo6cmVxdWlyZVJlYWxwYXRoQ29tbWFuZCgpIHsKICBBc3NlcnQ6OmNvbW1hbmRFeGlzdHMgcmVhbHBhdGgKfQoKIyBAZGVzY3JpcHRpb24gbG9hZCBjb2xvciB0aGVtZQojIEBub2FyZ3MKIyBAZW52IEJBU0hfRlJBTUVXT1JLX1RIRU1FIFN0cmluZyB0aGVtZSB0byB1c2UKIyBAZXhpdGNvZGUgMCBhbHdheXMgc3VjY2Vzc2Z1bApVSTo6cmVxdWlyZVRoZW1lKCkgewogIFVJOjp0aGVtZSAiJHtCQVNIX0ZSQU1FV09SS19USEVNRS1kZWZhdWx0fSIKfQoKIyBAZGVzY3JpcHRpb24gY2hlY2sgaWYgY29tbWFuZCBzcGVjaWZpZWQgZXhpc3RzIG9yIHJldHVybiAxCiMgd2l0aCBlcnJvciBhbmQgbWVzc2FnZSBpZiBub3QKIwojIEBhcmcgJDEgY29tbWFuZE5hbWU6U3RyaW5nIG9uIHdoaWNoIGV4aXN0ZW5jZSBtdXN0IGJlIGNoZWNrZWQKIyBAYXJnICQyIGhlbHBJZk5vdEV4aXN0czpTdHJpbmcgYSBoZWxwIGNvbW1hbmQgdG8gZGlzcGxheSBpZiB0aGUgY29tbWFuZCBkb2VzIG5vdCBleGlzdAojCiMgQGV4aXRjb2RlIDEgaWYgdGhlIGNvbW1hbmQgc3BlY2lmaWVkIGRvZXMgbm90IGV4aXN0CiMgQHN0ZGVyciBkaWFnbm9zdGljIGluZm9ybWF0aW9uICsgaGVscCBpZiBzZWNvbmQgYXJndW1lbnQgaXMgcHJvdmlkZWQKQXNzZXJ0Ojpjb21tYW5kRXhpc3RzKCkgewogIGxvY2FsIGNvbW1hbmROYW1lPSIkMSIKICBsb2NhbCBoZWxwSWZOb3RFeGlzdHM9IiQyIgoKICAiJHtCQVNIX0ZSQU1FV09SS19DT01NQU5EOi1jb21tYW5kfSIgLXYgIiR7Y29tbWFuZE5hbWV9IiA+L2Rldi9udWxsIDI+L2Rldi9udWxsIHx8IHsKICAgIExvZzo6ZGlzcGxheUVycm9yICIke2NvbW1hbmROYW1lfSBpcyBub3QgaW5zdGFsbGVkLCBwbGVhc2UgaW5zdGFsbCBpdCIKICAgIGlmIFtbIC1uICIke2hlbHBJZk5vdEV4aXN0c30iIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheUluZm8gIiR7aGVscElmTm90RXhpc3RzfSIKICAgIGZpCiAgICByZXR1cm4gMQogIH0KICByZXR1cm4gMAp9CgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgc2tpcCBjb2xvciAoeWVsbG93KQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlTa2lwcGVkKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTCA+PSBfX0xFVkVMX0lORk8pKTsgdGhlbgogICAgZWNobyAtZSAiJHtfX1NLSVBQRURfQ09MT1J9U0tJUFBFRCAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nU2tpcHBlZCAiJDEiCn0KCiMgQGRlc2NyaXB0aW9uIGxvYWQgY29sb3JzIHRoZW1lIGNvbnN0YW50cwojIEB3YXJuaW5nIGlmIHR0eSBub3Qgb3BlbmVkLCBub0NvbG9yIHRoZW1lIHdpbGwgYmUgY2hvc2VuCiMgQGFyZyAkMSB0aGVtZTpTdHJpbmcgdGhlIHRoZW1lIHRvIHVzZSAoZGVmYXVsdCwgbm9Db2xvcikKIyBAYXJnICRAIGFyZ3M6U3RyaW5nW10KIyBAc2V0IF9fRVJST1JfQ09MT1IgU3RyaW5nIGluZGljYXRlIGVycm9yIHN0YXR1cwojIEBzZXQgX19JTkZPX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSBpbmZvIHN0YXR1cwojIEBzZXQgX19TVUNDRVNTX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSBzdWNjZXNzIHN0YXR1cwojIEBzZXQgX19XQVJOSU5HX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSB3YXJuaW5nIHN0YXR1cwojIEBzZXQgX19TS0lQUEVEX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSBza2lwcGVkIHN0YXR1cwojIEBzZXQgX19ERUJVR19DT0xPUiBTdHJpbmcgaW5kaWNhdGUgZGVidWcgc3RhdHVzCiMgQHNldCBfX0hFTFBfQ09MT1IgU3RyaW5nIGluZGljYXRlIGhlbHAgc3RhdHVzCiMgQHNldCBfX1RFU1RfQ09MT1IgU3RyaW5nIG5vdCB1c2VkCiMgQHNldCBfX1RFU1RfRVJST1JfQ09MT1IgU3RyaW5nIG5vdCB1c2VkCiMgQHNldCBfX0hFTFBfVElUTEVfQ09MT1IgU3RyaW5nIHVzZWQgdG8gZGlzcGxheSBoZWxwIHRpdGxlIGluIGhlbHAgc3RyaW5ncwojIEBzZXQgX19IRUxQX09QVElPTl9DT0xPUiBTdHJpbmcgdXNlZCB0byBkaXNwbGF5IGhpZ2hsaWdodCBvcHRpb25zIGluIGhlbHAgc3RyaW5ncwojCiMgQHNldCBfX1JFU0VUX0NPTE9SIFN0cmluZyByZXNldCBkZWZhdWx0IGNvbG9yCiMKIyBAc2V0IF9fSEVMUF9FWEFNUExFIFN0cmluZyB0byByZW1vdmUKIyBAc2V0IF9fSEVMUF9USVRMRSBTdHJpbmcgdG8gcmVtb3ZlCiMgQHNldCBfX0hFTFBfTk9STUFMIFN0cmluZyB0byByZW1vdmUKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0ClVJOjp0aGVtZSgpIHsKICBsb2NhbCB0aGVtZT0iJHsxLWRlZmF1bHR9IgogIGlmIFtbICEgIiR7dGhlbWV9IiA9fiAtZm9yY2UkIF1dICYmICEgQXNzZXJ0Ojp0dHk7IHRoZW4KICAgIHRoZW1lPSJub0NvbG9yIgogIGZpCiAgY2FzZSAiJHt0aGVtZX0iIGluCiAgICBkZWZhdWx0IHwgZGVmYXVsdC1mb3JjZSkKICAgICAgdGhlbWU9ImRlZmF1bHQiCiAgICAgIDs7CiAgICBub0NvbG9yKSA7OwogICAgKikKICAgICAgTG9nOjpmYXRhbCAiaW52YWxpZCB0aGVtZSBwcm92aWRlZCIKICAgICAgOzsKICBlc2FjCiAgaWYgW1sgIiR7dGhlbWV9IiA9ICJkZWZhdWx0IiBdXTsgdGhlbgogICAgQkFTSF9GUkFNRVdPUktfVEhFTUU9ImRlZmF1bHQiCiAgICAjIGNoZWNrIGNvbG9ycyBhcHBsaWNhYmxlIGh0dHBzOi8vbWlzYy5mbG9naXNvZnQuY29tL2Jhc2gvdGlwX2NvbG9yc19hbmRfZm9ybWF0dGluZwogICAgX19FUlJPUl9DT0xPUj0nXGVbMzFtJyAgICAgICAgICMgUmVkCiAgICBfX0lORk9fQ09MT1I9J1xlWzQ0bScgICAgICAgICAgIyB3aGl0ZSBvbiBsaWdodEJsdWUKICAgIF9fU1VDQ0VTU19DT0xPUj0nXGVbMzJtJyAgICAgICAjIEdyZWVuCiAgICBfX1dBUk5JTkdfQ09MT1I9J1xlWzMzbScgICAgICAgIyBZZWxsb3cKICAgIF9fU0tJUFBFRF9DT0xPUj0nXGVbMzNtJyAgICAgICAjIFllbGxvdwogICAgX19ERUJVR19DT0xPUj0nXGVbMzdtJyAgICAgICAgICMgR3JleQogICAgX19IRUxQX0NPTE9SPSdcZVs3OzQ5OzMzbScgICAgICMgQmxhY2sgb24gR29sZAogICAgX19URVNUX0NPTE9SPSdcZVsxMDBtJyAgICAgICAgICMgTGlnaHQgbWFnZW50YQogICAgX19URVNUX0VSUk9SX0NPTE9SPSdcZVs0MW0nICAgICMgd2hpdGUgb24gcmVkCiAgICBfX0hFTFBfVElUTEVfQ09MT1I9IlxlWzE7MzdtIiAgIyBCb2xkCiAgICBfX0hFTFBfT1BUSU9OX0NPTE9SPSJcZVsxOzM0bSIgIyBCbHVlCiAgICAjIEludGVybmFsOiByZXNldCBjb2xvcgogICAgX19SRVNFVF9DT0xPUj0nXGVbMG0nICMgUmVzZXQgQ29sb3IKICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NSxTQzIwMzQKICAgIF9fSEVMUF9FWEFNUExFPSIkKGVjaG8gLWUgIlxlWzI7OTdtIikiCiAgICAjIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIxNTUsU0MyMDM0CiAgICBfX0hFTFBfVElUTEU9IiQoZWNobyAtZSAiXGVbMTszN20iKSIKICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NSxTQzIwMzQKICAgIF9fSEVMUF9OT1JNQUw9IiQoZWNobyAtZSAiXDAzM1swbSIpIgogIGVsc2UKICAgIEJBU0hfRlJBTUVXT1JLX1RIRU1FPSJub0NvbG9yIgogICAgIyBjaGVjayBjb2xvcnMgYXBwbGljYWJsZSBodHRwczovL21pc2MuZmxvZ2lzb2Z0LmNvbS9iYXNoL3RpcF9jb2xvcnNfYW5kX2Zvcm1hdHRpbmcKICAgIF9fRVJST1JfQ09MT1I9JycKICAgIF9fSU5GT19DT0xPUj0nJwogICAgX19TVUNDRVNTX0NPTE9SPScnCiAgICBfX1dBUk5JTkdfQ09MT1I9JycKICAgIF9fU0tJUFBFRF9DT0xPUj0nJwogICAgX19ERUJVR19DT0xPUj0nJwogICAgX19IRUxQX0NPTE9SPScnCiAgICBfX1RFU1RfQ09MT1I9JycKICAgIF9fVEVTVF9FUlJPUl9DT0xPUj0nJwogICAgX19IRUxQX1RJVExFX0NPTE9SPScnCiAgICBfX0hFTFBfT1BUSU9OX0NPTE9SPScnCiAgICAjIEludGVybmFsOiByZXNldCBjb2xvcgogICAgX19SRVNFVF9DT0xPUj0nJwogICAgX19IRUxQX0VYQU1QTEU9JycKICAgIF9fSEVMUF9USVRMRT0nJwogICAgX19IRUxQX05PUk1BTD0nJwogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIGNoZWNrIGlmIHR0eSAoaW50ZXJhY3RpdmUgbW9kZSkgaXMgYWN0aXZlCiMgQG5vYXJncwojIEBleGl0Y29kZSAxIGlmIHR0eSBub3QgYWN0aXZlCiMgQGVudiBOT05fSU5URVJBQ1RJVkUgaWYgMSBjb25zaWRlciBhcyBub3QgaW50ZXJhY3RpdmUgZXZlbiBpZiBlbnZpcm9ubWVudCBpcyBpbnRlcmFjdGl2ZQojIEBlbnYgSU5URVJBQ1RJVkUgaWYgMSBjb25zaWRlciBhcyBpbnRlcmFjdGl2ZSBldmVuIGlmIGVudmlyb25tZW50IGlzIG5vdCBpbnRlcmFjdGl2ZQojIEBzdGRlcnIgZGlhZ25vc3RpYyBpbmZvcm1hdGlvbiArIGhlbHAgaWYgc2Vjb25kIGFyZ3VtZW50IGlzIHByb3ZpZGVkCkFzc2VydDo6dHR5KCkgewogIGlmIFtbICIke05PTl9JTlRFUkFDVElWRTotMH0iID0gIjEiIF1dOyB0aGVuCiAgICByZXR1cm4gMQogIGZpCiAgaWYgW1sgIiR7SU5URVJBQ1RJVkU6LTB9IiA9ICIxIiBdXTsgdGhlbgogICAgcmV0dXJuIDAKICBmaQogIFtbIC10IDEgfHwgLXQgMiBdXQp9CgojIEBkZXNjcmlwdGlvbiBsb2cgbWVzc2FnZSB0byBmaWxlCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6bG9nU2tpcHBlZCgpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+PSBfX0xFVkVMX0lORk8pKTsgdGhlbgogICAgTG9nOjpsb2dNZXNzYWdlICIkezI6LVNLSVBQRUR9IiAiJDEiCiAgZmkKfQoKIyBGVU5DVElPTlMKCmZhY2FkZV9tYWluX2VtYmVkRnJhbWV3b3JrRnVuY3Rpb25iaW5GaWxldHBsKCkgewojIFJFUVVJUkVTCkxpbnV4OjpyZXF1aXJlRXhlY3V0ZWRBc1VzZXIKRW52OjpyZXF1aXJlTG9hZApMb2c6OnJlcXVpcmVMb2FkCkxpbnV4OjpyZXF1aXJlUmVhbHBhdGhDb21tYW5kClVJOjpyZXF1aXJlVGhlbWUKQ29tcGlsZXI6OkZhY2FkZTo6cmVxdWlyZUNvbW1hbmRCaW5EaXIKCiMgQHJlcXVpcmUgQ29tcGlsZXI6OkZhY2FkZTo6cmVxdWlyZUNvbW1hbmRCaW5EaXIKCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NCxTQzIwMTYKZnVuY3Rpb25Ub0NhbGw9J0RiOjpxdWVyeU9uZURhdGFiYXNlJwoiJHtmdW5jdGlvblRvQ2FsbH0iICIkQCIKCn0KCmZhY2FkZV9tYWluX2VtYmVkRnJhbWV3b3JrRnVuY3Rpb25iaW5GaWxldHBsICIkQCIK" +declare -gx embed_function_DbQueryOneDatabase="${PERSISTENT_TMPDIR:-/tmp}/bin/e36a5808727f397f60db02f81c9ecc2e/dbQueryOneDatabase" +declare -gx encoded_binary_file_DbQueryOneDatabase="IyEvdXNyL2Jpbi9lbnYgYmFzaAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgR0VORVJBVEVEIEZBQ0FERSBGUk9NIGh0dHBzOi8vZ2l0aHViLmNvbS9mY2hhc3RhbmV0L2Jhc2gtdG9vbHMvdHJlZS9tYXN0ZXIvaG9tZS93c2wvZmNoYXN0YW5ldC9iYXNoLWRldi1lbnYvdmVuZG9yL2Jhc2gtdG9vbHMtZnJhbWV3b3JrL3NyYy9Db21waWxlci9FbWJlZC9lbWJlZEZyYW1ld29ya0Z1bmN0aW9uLmJpbkZpbGUudHBsCiMgRE8gTk9UIEVESVQgSVQKIyBAZ2VuZXJhdGVkCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMjg4LFNDMjAzNAojIEJJTl9GSUxFPSR7QklOX0ZJTEV9CiMgRkFDQURFCgojIGVuc3VyZSB0aGF0IG5vIHVzZXIgYWxpYXNlcyBjb3VsZCBpbnRlcmZlcmUgd2l0aAojIGNvbW1hbmRzIHVzZWQgaW4gdGhpcyBzY3JpcHQKdW5hbGlhcyAtYSB8fCB0cnVlCnNob3B0IC11IGV4cGFuZF9hbGlhc2VzCgojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKKChmYWlsdXJlcyA9IDApKSB8fCB0cnVlCgojIEJhc2ggd2lsbCByZW1lbWJlciAmIHJldHVybiB0aGUgaGlnaGVzdCBleGl0IGNvZGUgaW4gYSBjaGFpbiBvZiBwaXBlcy4KIyBUaGlzIHdheSB5b3UgY2FuIGNhdGNoIHRoZSBlcnJvciBpbnNpZGUgcGlwZXMsIGUuZy4gbXlzcWxkdW1wIHwgZ3ppcApzZXQgLW8gcGlwZWZhaWwKc2V0IC1vIGVycmV4aXQKCiMgQ29tbWFuZCBTdWJzdGl0dXRpb24gY2FuIGluaGVyaXQgZXJyZXhpdCBvcHRpb24gc2luY2UgYmFzaCB2NC40CnNob3B0IC1zIGluaGVyaXRfZXJyZXhpdCB8fCB0cnVlCgojIGEgbG9nIGlzIGdlbmVyYXRlZCB3aGVuIGEgY29tbWFuZCBmYWlscwpzZXQgLW8gZXJydHJhY2UKCiMgdXNlIG51bGxnbG9iIHNvIHRoYXQgKGZpbGUqLnBocCkgd2lsbCByZXR1cm4gYW4gZW1wdHkgYXJyYXkgaWYgbm8gZmlsZSBtYXRjaGVzIHRoZSB3aWxkY2FyZApzaG9wdCAtcyBudWxsZ2xvYgoKIyBlbnN1cmUgcmVnZXhwIGFyZSBpbnRlcnByZXRlZCB3aXRob3V0IGFjY2VudHVhdGVkIGNoYXJhY3RlcnMKZXhwb3J0IExDX0FMTD1QT1NJWAoKZXhwb3J0IFRFUk09eHRlcm0tMjU2Y29sb3IKCiMgYXZvaWQgaW50ZXJhY3RpdmUgaW5zdGFsbApleHBvcnQgREVCSUFOX0ZST05URU5EPW5vbmludGVyYWN0aXZlCmV4cG9ydCBERUJDT05GX05PTklOVEVSQUNUSVZFX1NFRU49dHJ1ZQoKIyBzdG9yZSBjb21tYW5kIGFyZ3VtZW50cyBmb3IgbGF0ZXIgdXNhZ2UKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CmRlY2xhcmUgLWEgQkFTSF9GUkFNRVdPUktfQVJHVj0oIiRAIikKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CmRlY2xhcmUgLWEgT1JJR0lOQUxfQkFTSF9GUkFNRVdPUktfQVJHVj0oIiRAIikKCiMgQHNlZSBodHRwczovL3VuaXguc3RhY2tleGNoYW5nZS5jb20vYS8zODY4NTYKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMzE3CmludGVycnVwdE1hbmFnZW1lbnQoKSB7CiAgIyByZXN0b3JlIFNJR0lOVCBoYW5kbGVyCiAgdHJhcCAtIElOVAogICMgZW5zdXJlIHRoYXQgQ3RybC1DIGlzIHRyYXBwZWQgYnkgdGhpcyBzY3JpcHQgYW5kIG5vdCBieSBzdWIgcHJvY2VzcwogICMgcmVwb3J0IHRvIHRoZSBwYXJlbnQgdGhhdCB3ZSBoYXZlIGluZGVlZCBiZWVuIGludGVycnVwdGVkCiAga2lsbCAtcyBJTlQgIiQkIgp9CnRyYXAgaW50ZXJydXB0TWFuYWdlbWVudCBJTlQKU0NSSVBUX05BTUU9JHswIyMqL30KUkVBTF9TQ1JJUFRfRklMRT0iJChyZWFkbGluayAtZSAiJChyZWFscGF0aCAiJHtCQVNIX1NPVVJDRVswXX0iKSIpIgppZiBbWyAtbiAiJHtFTUJFRF9DVVJSRU5UX0RJUn0iIF1dOyB0aGVuCiAgQ1VSUkVOVF9ESVI9IiR7RU1CRURfQ1VSUkVOVF9ESVJ9IgplbHNlCiAgQ1VSUkVOVF9ESVI9IiQoY2QgIiQocmVhZGxpbmsgLWUgIiR7UkVBTF9TQ1JJUFRfRklMRSUvKn0iKSIgJiYgcHdkIC1QKSIKZmkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFRlbXAgZGlyIG1hbmFnZW1lbnQKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpLRUVQX1RFTVBfRklMRVM9IiR7S0VFUF9URU1QX0ZJTEVTOi0wfSIKZXhwb3J0IEtFRVBfVEVNUF9GSUxFUwoKIyBQRVJTSVNURU5UX1RNUERJUiBpcyBub3QgZGVsZXRlZCBieSB0cmFwcwpQRVJTSVNURU5UX1RNUERJUj0iJHtUTVBESVI6LS90bXB9L2Jhc2gtZnJhbWV3b3JrIgpleHBvcnQgUEVSU0lTVEVOVF9UTVBESVIKbWtkaXIgLXAgIiR7UEVSU0lTVEVOVF9UTVBESVJ9IgoKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0ClRNUERJUj0iJChta3RlbXAgLWQgLXAgIiR7UEVSU0lTVEVOVF9UTVBESVI6LS90bXB9IiAtdCBiYXNoLWZyYW1ld29yay0kJC1YWFhYWFgpIgpleHBvcnQgVE1QRElSCgojIHRlbXAgZGlyIGNsZWFuaW5nCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjMxNwpjbGVhbk9uRXhpdCgpIHsKICBpZiBbWyAiJHtLRUVQX1RFTVBfRklMRVM6LTB9IiA9ICIxIiBdXTsgdGhlbgogICAgTG9nOjpkaXNwbGF5SW5mbyAiS0VFUF9URU1QX0ZJTEVTPTEgdGVtcCBmaWxlcyBrZXB0IGhlcmUgJyR7VE1QRElSfSciCiAgZWxpZiBbWyAtbiAiJHtUTVBESVIreHh4fSIgXV07IHRoZW4KICAgIExvZzo6ZGlzcGxheURlYnVnICJLRUVQX1RFTVBfRklMRVM9MCByZW1vdmluZyB0ZW1wIGZpbGVzICcke1RNUERJUn0nIgogICAgcm0gLVJmICIke1RNUERJUjotL3RtcC9mYWtlfSIgPi9kZXYvbnVsbCAyPiYxCiAgZmkKfQp0cmFwIGNsZWFuT25FeGl0IEVYSVQgSFVQIFFVSVQgQUJSVCBURVJNCgojIFZBUl9NQUlOX0ZVTkNUSU9OX1ZBUl9OQU1FPWRiUXVlcnlBbGxEYXRhYmFzZXNGYWNhZGUKCiMgQGRlc2NyaXB0aW9uIHVzZWQgdG8gZXhlY3V0ZSBnaXZlbiBxdWVyeSB3aGVuIHVzaW5nCiMgZGJTY3JpcHRBbGxEYXRhYmFzZXMKIyBAYXJnICQxIGRzbjpTdHJpbmcKIyBAYXJnICQyIGRiOlN0cmluZwojIEBlbnYgcXVlcnkgU3RyaW5nCiMgQGVudiBvcHRpb25TZXBhcmF0b3IgU3RyaW5nCiMgQHJlcXVpcmUgTGludXg6OnJlcXVpcmVFeGVjdXRlZEFzVXNlcgpEYjo6cXVlcnlPbmVEYXRhYmFzZSgpIHsKICAjIHF1ZXJ5IGFuZCBvcHRpb25TZXBhcmF0b3IgYXJlIHBhc3NlZCB2aWEgZXhwb3J0CiAgbG9jYWwgZHNuPSIkMSIKICBsb2NhbCBkYj0iJDIiCgogIGxvY2FsIC1BIGRiSW5zdGFuY2UKICBEYXRhYmFzZTo6bmV3SW5zdGFuY2UgZGJJbnN0YW5jZSAiJHtkc259IgogIERhdGFiYXNlOjpzZXRRdWVyeU9wdGlvbnMgZGJJbnN0YW5jZSAiJHtkYkluc3RhbmNlW1FVRVJZX09QVElPTlNdfSAtLWNvbm5lY3QtdGltZW91dD01IgoKICAjIGlkZW50aWZ5IGNvbHVtbnMgaGVhZGVyCiAgZWNobyAtbiAiQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAiCiAgRGF0YWJhc2U6OnNraXBDb2x1bW5OYW1lcyBkYkluc3RhbmNlIDAKCiAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTU0CiAgaWYgISBEYXRhYmFzZTo6cXVlcnkgZGJJbnN0YW5jZSAiJHtxdWVyeX0iICIke2RifSIgfCBzZWQgInMvXHQvJHtvcHRpb25TZXBhcmF0b3J9L2ciOyB0aGVuCiAgICBMb2c6OmZhdGFsICJkYXRhYmFzZSAke2RifSBlcnJvciIgMT4mMgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIExvZyBuYW1lc3BhY2UgcHJvdmlkZXMgMiBraW5kIG9mIGZ1bmN0aW9ucwojIC0gTG9nOjpkaXNwbGF5KiBhbGxvd3MgdG8gZGlzcGxheSBnaXZlbiBtZXNzYWdlIHdpdGgKIyAgIGdpdmVuIGRpc3BsYXkgbGV2ZWwKIyAtIExvZzo6bG9nKiBhbGxvd3MgdG8gbG9nIGdpdmVuIG1lc3NhZ2Ugd2l0aAojICAgZ2l2ZW4gbG9nIGxldmVsCiMgTG9nOjpkaXNwbGF5KiBmdW5jdGlvbnMgYXV0b21hdGljYWxseSBsb2cgdGhlIG1lc3NhZ2UgdG9vCiMgQHNlZSBFbnY6OnJlcXVpcmVMb2FkIHRvIGxvYWQgdGhlIGRpc3BsYXkgYW5kIGxvZyBsZXZlbCBmcm9tIC5lbnYgZmlsZQoKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIG9mZgpleHBvcnQgX19MRVZFTF9PRkY9MAojIEBkZXNjcmlwdGlvbiBsb2cgbGV2ZWwgZXJyb3IKZXhwb3J0IF9fTEVWRUxfRVJST1I9MQojIEBkZXNjcmlwdGlvbiBsb2cgbGV2ZWwgd2FybmluZwpleHBvcnQgX19MRVZFTF9XQVJOSU5HPTIKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIGluZm8KZXhwb3J0IF9fTEVWRUxfSU5GTz0zCiMgQGRlc2NyaXB0aW9uIGxvZyBsZXZlbCBzdWNjZXNzCmV4cG9ydCBfX0xFVkVMX1NVQ0NFU1M9MwojIEBkZXNjcmlwdGlvbiBsb2cgbGV2ZWwgZGVidWcKZXhwb3J0IF9fTEVWRUxfREVCVUc9NAoKIyBAZGVzY3JpcHRpb24gdmVyYm9zZSBsZXZlbCBvZmYKZXhwb3J0IF9fVkVSQk9TRV9MRVZFTF9PRkY9MAojIEBkZXNjcmlwdGlvbiB2ZXJib3NlIGxldmVsIGluZm8KZXhwb3J0IF9fVkVSQk9TRV9MRVZFTF9JTkZPPTEKIyBAZGVzY3JpcHRpb24gdmVyYm9zZSBsZXZlbCBpbmZvCmV4cG9ydCBfX1ZFUkJPU0VfTEVWRUxfREVCVUc9MgojIEBkZXNjcmlwdGlvbiB2ZXJib3NlIGxldmVsIGluZm8KZXhwb3J0IF9fVkVSQk9TRV9MRVZFTF9UUkFDRT0zCgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgZGVidWcgY29sb3IgKGdyZXkpCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6ZGlzcGxheURlYnVnKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTCA+PSBfX0xFVkVMX0RFQlVHKSk7IHRoZW4KICAgIGVjaG8gLWUgIiR7X19ERUJVR19DT0xPUn1ERUJVRyAgIC0gJHsxfSR7X19SRVNFVF9DT0xPUn0iID4mMgogIGZpCiAgTG9nOjpsb2dEZWJ1ZyAiJDEiCn0KCiMgQGRlc2NyaXB0aW9uIERpc3BsYXkgbWVzc2FnZSB1c2luZyBpbmZvIGNvbG9yIChiZyBsaWdodCBibHVlL2ZnIHdoaXRlKQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlJbmZvKCkgewogIGxvY2FsIHR5cGU9IiR7MjotSU5GT30iCiAgaWYgKChCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMID49IF9fTEVWRUxfSU5GTykpOyB0aGVuCiAgICBlY2hvIC1lICIke19fSU5GT19DT0xPUn0ke3R5cGV9ICAgIC0gJHsxfSR7X19SRVNFVF9DT0xPUn0iID4mMgogIGZpCiAgTG9nOjpsb2dJbmZvICIkMSIgIiR7dHlwZX0iCn0KCiMgQGRlc2NyaXB0aW9uIGVuc3VyZSBDT01NQU5EX0JJTl9ESVIgZW52IHZhciBpcyBzZXQKIyBhbmQgUEFUSCBjb3JyZWN0bHkgcHJlcGFyZWQKIyBAbm9hcmdzCiMgQHNldCBDT01NQU5EX0JJTl9ESVIgc3RyaW5nIHRoZSBkaXJlY3Rvcnkgd2hlcmUgdG8gZmluZCB0aGlzIGNvbW1hbmQKIyBAc2V0IFBBVEggc3RyaW5nIGFkZCBkaXJlY3Rvcnkgd2hlcmUgdG8gZmluZCB0aGlzIGNvbW1hbmQgYmluYXJ5CkNvbXBpbGVyOjpGYWNhZGU6OnJlcXVpcmVDb21tYW5kQmluRGlyKCkgewogIENPTU1BTkRfQklOX0RJUj0iJHtDVVJSRU5UX0RJUn0iCiAgRW52OjpwYXRoUHJlcGVuZCAiJHtDT01NQU5EX0JJTl9ESVJ9Igp9CgojIEBkZXNjcmlwdGlvbiBjcmVhdGUgYSBuZXcgZGIgaW5zdGFuY2UKIyBSZXR1cm5zIGltbWVkaWF0ZWx5IGlmIHRoZSBpbnN0YW5jZSBpcyBhbHJlYWR5IGluaXRpYWxpemVkCiMKIyBAYXJnICQxIGluc3RhbmNlTmV3SW5zdGFuY2U6Jk1hcDxTdHJpbmcsU3RyaW5nPiAocGFzc2VkIGJ5IHJlZmVyZW5jZSkgZGF0YWJhc2UgaW5zdGFuY2UgdG8gdXNlCiMgQGFyZyAkMiBkc246U3RyaW5nIGRzbiBwcm9maWxlIC0gbG9hZCB0aGUgZHNuLmVudiBwcm9maWxlIGRlZHVjZWQgdXNpbmcgcnVsZXMgZGVmaW5lZCBpbiBDb25mOjpnZXRBYnNvbHV0ZUZpbGUKIwojIEBleGFtcGxlCiMgICBkZWNsYXJlIC1BZ3ggZGJJbnN0YW5jZQojICAgRGF0YWJhc2U6Om5ld0luc3RhbmNlIGRiSW5zdGFuY2UgImRlZmF1bHQubG9jYWwiCiMKIyBAZXhpdGNvZGUgMSBpZiBkbnMgZmlsZSBub3QgYWJsZSB0byBsb2FkZWQKRGF0YWJhc2U6Om5ld0luc3RhbmNlKCkgewogIGxvY2FsIC1uIGluc3RhbmNlTmV3SW5zdGFuY2U9JDEKICBsb2NhbCBkc249IiQyIgogIGxvY2FsIERTTl9GSUxFCgogIGlmIFtbIC12IGluc3RhbmNlTmV3SW5zdGFuY2VbJ0lOSVRJQUxJWkVEJ10gJiYgIiR7aW5zdGFuY2VOZXdJbnN0YW5jZVsnSU5JVElBTElaRUQnXTotMH0iID09ICIxIiBdXTsgdGhlbgogICAgcmV0dXJuCiAgZmkKCiAgIyBmaW5hbCBhdXRoIGZpbGUgZ2VuZXJhdGVkIGZyb20gZG5zIGZpbGUKICBpbnN0YW5jZU5ld0luc3RhbmNlWydBVVRIX0ZJTEUnXT0iIgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0RTTl9GSUxFJ109IiIKCiAgIyBjaGVjayBkc24gZmlsZQogIERTTl9GSUxFPSIkKENvbmY6OmdldEFic29sdXRlRmlsZSAiZHNuIiAiJHtkc259IiAiZW52IikiIHx8IHJldHVybiAxCiAgRGF0YWJhc2U6OmNoZWNrRHNuRmlsZSAiJHtEU05fRklMRX0iIHx8IHJldHVybiAxCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnRFNOX0ZJTEUnXT0iJHtEU05fRklMRX0iCgogICMgc2hlbGxjaGVjayBzb3VyY2U9L3NyYy9EYXRhYmFzZS90ZXN0c0RhdGEvZHNuX3ZhbGlkLmVudgogIHNvdXJjZSAiJHtpbnN0YW5jZU5ld0luc3RhbmNlWydEU05fRklMRSddfSIKCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnVVNFUiddPSIke1VTRVJ9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1BBU1NXT1JEJ109IiR7UEFTU1dPUkR9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0hPU1ROQU1FJ109IiR7SE9TVE5BTUV9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1BPUlQnXT0iJHtQT1JUfSIKCiAgIyBnZW5lcmF0ZSBhdXRoRmlsZSBmb3IgZWFzeSBhdXRoZW50aWNhdGlvbgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0FVVEhfRklMRSddPSQobWt0ZW1wIC1wICIke1RNUERJUjotL3RtcH0iIC10ICJteXNxbC5YWFhYWFhYWFhYWFgiKQogICgKICAgIGVjaG8gIltjbGllbnRdIgogICAgZWNobyAidXNlciA9ICR7VVNFUn0iCiAgICBlY2hvICJwYXNzd29yZCA9ICR7UEFTU1dPUkR9IgogICAgZWNobyAiaG9zdCA9ICR7SE9TVE5BTUV9IgogICAgZWNobyAicG9ydCA9ICR7UE9SVH0iCiAgKSA+IiR7aW5zdGFuY2VOZXdJbnN0YW5jZVsnQVVUSF9GSUxFJ119IgoKICAjIHNvbWUgb2YgdGhvc2UgdmFsdWVzIGNhbiBiZSBvdmVycmlkZGVuIHVzaW5nIHRoZSBkc24gZmlsZQogICMgU0tJUF9DT0xVTU5fTkFNRVMgZW5hYmxlZCBieSBkZWZhdWx0CiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnU0tJUF9DT0xVTU5fTkFNRVMnXT0iJHtTS0lQX0NPTFVNTl9OQU1FUzotMX0iCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnU1NMX09QVElPTlMnXT0iJHtNWVNRTF9TU0xfT1BUSU9OUzotLS1zc2wtbW9kZT1ESVNBQkxFRH0iCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnUVVFUllfT1BUSU9OUyddPSIke01ZU1FMX1FVRVJZX09QVElPTlM6LS0tYmF0Y2ggLS1yYXcgLS1kZWZhdWx0LWNoYXJhY3Rlci1zZXQ9dXRmOH0iCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnRFVNUF9PUFRJT05TJ109IiR7TVlTUUxfRFVNUF9PUFRJT05TOi0tLWRlZmF1bHQtY2hhcmFjdGVyLXNldD11dGY4IC0tY29tcHJlc3MgLS1oZXgtYmxvYiAtLXJvdXRpbmVzIC0tdHJpZ2dlcnMgLS1zaW5nbGUtdHJhbnNhY3Rpb24gLS1zZXQtZ3RpZC1wdXJnZWQ9T0ZGIC0tY29sdW1uLXN0YXRpc3RpY3M9MCAke2luc3RhbmNlTmV3SW5zdGFuY2VbJ1NTTF9PUFRJT05TJ119fSIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydEQl9JTVBPUlRfT1BUSU9OUyddPSIke0RCX0lNUE9SVF9PUFRJT05TOi0tLWNvbm5lY3QtdGltZW91dD01IC0tYmF0Y2ggLS1yYXcgLS1kZWZhdWx0LWNoYXJhY3Rlci1zZXQ9dXRmOH0iCgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0lOSVRJQUxJWkVEJ109MQp9CgojIEBkZXNjcmlwdGlvbiBteXNxbCBxdWVyeSBvbiBhIGdpdmVuIGRiCiMgQHdhcm5pbmcgY291bGQgdXNlIFFVRVJZX09QVElPTlMgdmFyaWFibGUgZnJvbSBkc24gaWYgZGVmaW5lZAojIEBleGFtcGxlCiMgICBjYXQgZmlsZS5zcWwgfCBEYXRhYmFzZTo6cXVlcnkgLi4uCiMgQGFyZyAkMSBpbnN0YW5jZVF1ZXJ5OiZNYXA8U3RyaW5nLFN0cmluZz4gKHBhc3NlZCBieSByZWZlcmVuY2UpIGRhdGFiYXNlIGluc3RhbmNlIHRvIHVzZQojIEBhcmcgJDIgc3FsUXVlcnk6U3RyaW5nIChvcHRpb25hbCkgc3FsIHF1ZXJ5IG9yIHNxbCBmaWxlIHRvIGV4ZWN1dGUuIGlmIG5vdCBwcm92aWRlZCBvciBlbXB0eSwgdGhlIGNvbW1hbmQgY2FuIGJlIHBpcGVkCiMgQGFyZyAkMyBkYk5hbWU6U3RyaW5nIChvcHRpb25hbCkgdGhlIGRiIG5hbWUKIwojIEBleGl0Y29kZSBteXNxbCBjb21tYW5kIHN0YXR1cyBjb2RlCkRhdGFiYXNlOjpxdWVyeSgpIHsKICBsb2NhbCAtbiBpbnN0YW5jZVF1ZXJ5PSQxCiAgbG9jYWwgLWEgbXlzcWxDb21tYW5kPSgpCiAgbG9jYWwgLWEgcXVlcnlPcHRpb25zCgogIG15c3FsQ29tbWFuZCs9KG15c3FsKQogIG15c3FsQ29tbWFuZCs9KCItLWRlZmF1bHRzLWV4dHJhLWZpbGU9JHtpbnN0YW5jZVF1ZXJ5WydBVVRIX0ZJTEUnXX0iKQogIElGUz0nICcgcmVhZCAtciAtYSBxdWVyeU9wdGlvbnMgPDw8IiR7aW5zdGFuY2VRdWVyeVsnUVVFUllfT1BUSU9OUyddfSIKICBteXNxbENvbW1hbmQrPSgiJHtxdWVyeU9wdGlvbnNbQF19IikKICBpZiBbWyAiJHtpbnN0YW5jZVF1ZXJ5WydTS0lQX0NPTFVNTl9OQU1FUyddfSIgPSAiMSIgXV07IHRoZW4KICAgIG15c3FsQ29tbWFuZCs9KCItcyIgIi0tc2tpcC1jb2x1bW4tbmFtZXMiKQogIGZpCiAgIyBhZGQgb3B0aW9uYWwgZGIgbmFtZQogIGlmIFtbIC1uICIkezMreH0iIF1dOyB0aGVuCiAgICBteXNxbENvbW1hbmQrPSgiJDMiKQogIGZpCiAgIyBhZGQgb3B0aW9uYWwgc3FsIHF1ZXJ5CiAgaWYgW1sgLW4gIiR7Mit4fSIgJiYgLW4gIiQyIiAmJiAhIC1mICIkMiIgXV07IHRoZW4KICAgIG15c3FsQ29tbWFuZCs9KCItZSIpCiAgICBteXNxbENvbW1hbmQrPSgiJDIiKQogIGZpCiAgTG9nOjpkaXNwbGF5RGVidWcgIiQocHJpbnRmICJleGVjdXRlIGNvbW1hbmQ6ICclcyciICIke215c3FsQ29tbWFuZFsqXX0iKSIKCiAgaWYgW1sgLWYgIiQyIiBdXTsgdGhlbgogICAgIiR7bXlzcWxDb21tYW5kW0BdfSIgPCIkMiIKICBlbHNlCiAgICAiJHtteXNxbENvbW1hbmRbQF19IgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIHNldCB0aGUgZ2VuZXJhbCBvcHRpb25zIHRvIHVzZSBvbiBteXNxbCBjb21tYW5kIHRvIHF1ZXJ5IHRoZSBkYXRhYmFzZQojIERpZmZlcnMgdGhhbiBzZXRPcHRpb25zIGluIHRoZSB3YXkgdGhhdCB0aGVzZSBvcHRpb25zIGNvdWxkIGNoYW5nZSBlYWNoIHRpbWUKIwojIEBhcmcgJDEgaW5zdGFuY2VTZXRRdWVyeU9wdGlvbnM6Jk1hcDxTdHJpbmcsU3RyaW5nPiAocGFzc2VkIGJ5IHJlZmVyZW5jZSkgZGF0YWJhc2UgaW5zdGFuY2UgdG8gdXNlCiMgQGFyZyAkMiBvcHRpb25zTGlzdDpTdHJpbmcgcXVlcnkgb3B0aW9ucyBsaXN0CkRhdGFiYXNlOjpzZXRRdWVyeU9wdGlvbnMoKSB7CiAgbG9jYWwgLW4gaW5zdGFuY2VTZXRRdWVyeU9wdGlvbnM9JDEKICAjIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKICBpbnN0YW5jZVNldFF1ZXJ5T3B0aW9uc1snUVVFUllfT1BUSU9OUyddPSIkMiIKfQoKIyBAZGVzY3JpcHRpb24gYnkgZGVmYXVsdCB3ZSBza2lwIHRoZSBjb2x1bW4gbmFtZXMKIyBidXQgc29tZXRpbWVzIHdlIG5lZWQgY29sdW1uIG5hbWVzIHRvIGRpc3BsYXkgc29tZSByZXN1bHRzCiMgZGlzYWJsZSB0aGlzIG9wdGlvbiB0ZW1wb3JhcmlseSBhbmQgdGhlbiByZXN0b3JlIGl0IHRvIHRydWUKIwojIEBhcmcgJDEgaW5zdGFuY2VTZXRRdWVyeU9wdGlvbnM6Jk1hcDxTdHJpbmcsU3RyaW5nPiAocGFzc2VkIGJ5IHJlZmVyZW5jZSkgZGF0YWJhc2UgaW5zdGFuY2UgdG8gdXNlCiMgQGFyZyAkMiBza2lwQ29sdW1uTmFtZXM6Qm9vbGVhbiAwIHRvIGRpc2FibGUsIDEgdG8gZW5hYmxlIChoaWRlIGNvbHVtbiBuYW1lcykKRGF0YWJhc2U6OnNraXBDb2x1bW5OYW1lcygpIHsKICBsb2NhbCAtbiBpbnN0YW5jZVNraXBDb2x1bW5OYW1lcz0kMQogICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNAogIGluc3RhbmNlU2tpcENvbHVtbk5hbWVzWydTS0lQX0NPTFVNTl9OQU1FUyddPSIkMiIKfQoKIyBAZGVzY3JpcHRpb24gcHJlcGVuZCBkaXJlY3RvcmllcyB0byB0aGUgUEFUSCBlbnZpcm9ubWVudCB2YXJpYWJsZQojIEBhcmcgJEAgYXJnczpTdHJpbmdbXSBsaXN0IG9mIGRpcmVjdG9yaWVzIHRvIHByZXBlbmQKIyBAc2V0IFBBVEggdXBkYXRlIFBBVEggd2l0aCB0aGUgZGlyZWN0b3JpZXMgcHJlcGVuZGVkCkVudjo6cGF0aFByZXBlbmQoKSB7CiAgbG9jYWwgYXJnCiAgZm9yIGFyZyBpbiAiJEAiOyBkbwogICAgaWYgW1sgLWQgIiR7YXJnfSIgJiYgIjoke1BBVEh9OiIgIT0gKiI6JHthcmd9OiIqIF1dOyB0aGVuCiAgICAgIFBBVEg9IiQocmVhbHBhdGggIiR7YXJnfSIpOiR7UEFUSH0iCiAgICBmaQogIGRvbmUKfQoKIyBAZGVzY3JpcHRpb24gRGlzcGxheSBtZXNzYWdlIHVzaW5nIGVycm9yIGNvbG9yIChyZWQpIGFuZCBleGl0IGltbWVkaWF0ZWx5IHdpdGggZXJyb3Igc3RhdHVzIDEKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpmYXRhbCgpIHsKICBlY2hvIC1lICIke19fRVJST1JfQ09MT1J9RkFUQUwgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBMb2c6OmxvZ0ZhdGFsICIkMSIKICBleGl0IDEKfQoKIyBAZGVzY3JpcHRpb24gbG9nIG1lc3NhZ2UgdG8gZmlsZQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmxvZ0RlYnVnKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfREVCVUcpKTsgdGhlbgogICAgTG9nOjpsb2dNZXNzYWdlICIkezI6LURFQlVHfSIgIiQxIgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dJbmZvKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfSU5GTykpOyB0aGVuCiAgICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotSU5GT30iICIkMSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBlbnN1cmUgcnVubmluZyB1c2VyIGlzIG5vdCByb290CiMgQGV4aXRjb2RlIDEgaWYgY3VycmVudCB1c2VyIGlzIHJvb3QKIyBAc3RkZXJyIGRpYWdub3N0aWNzIGluZm9ybWF0aW9uIGlzIGRpc3BsYXllZApMaW51eDo6cmVxdWlyZUV4ZWN1dGVkQXNVc2VyKCkgewogIGlmIFtbICIkKGlkIC11KSIgPSAiMCIgXV07IHRoZW4KICAgIExvZzo6ZmF0YWwgInRoaXMgc2NyaXB0IHNob3VsZCBiZSBleGVjdXRlZCBhcyBub3JtYWwgdXNlciIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBnZXQgYWJzb2x1dGUgY29uZiBmaWxlIGZyb20gc3BlY2lmaWVkIGNvbmYgZm9sZGVyIGRlZHVjZWQgdXNpbmcgdGhlc2UgcnVsZXMKIyAgICogZnJvbSBhYnNvbHV0ZSBmaWxlIChpZ25vcmVzIDxjb25mRm9sZGVyPiBhbmQgPGV4dGVuc2lvbj4pCiMgICAqIHJlbGF0aXZlIHRvIHdoZXJlIHNjcmlwdCBpcyBleGVjdXRlZCAoaWdub3JlcyA8Y29uZkZvbGRlcj4gYW5kIDxleHRlbnNpb24+KQojICAgKiBmcm9tIGhvbWUvLmJhc2gtdG9vbHMvPGNvbmZGb2xkZXI+CiMgICAqIGZyb20gZnJhbWV3b3JrIGNvbmYvPGNvbmZGb2xkZXI+CiMKIyBAYXJnICQxIGNvbmZGb2xkZXI6U3RyaW5nIHRoZSBkaXJlY3RvcnkgbmFtZSAobm90IHRoZSBwYXRoKSB0byBsaXN0CiMgQGFyZyAkMiBjb25mOlN0cmluZyBmaWxlIHRvIHVzZSB3aXRob3V0IGV4dGVuc2lvbgojIEBhcmcgJDMgZXh0ZW5zaW9uOlN0cmluZyB0aGUgZXh0ZW5zaW9uICguc2ggYnkgZGVmYXVsdCkKIwojIEBzdGRvdXQgYWJzb2x1dGUgY29uZiBmaWxlbmFtZQojIEBleGl0Y29kZSAxIGlmIGZpbGUgaXMgbm90IGZvdW5kIGluIGFueSBsb2NhdGlvbgpDb25mOjpnZXRBYnNvbHV0ZUZpbGUoKSB7CiAgbG9jYWwgY29uZkZvbGRlcj0iJDEiCiAgbG9jYWwgY29uZj0iJDIiCiAgbG9jYWwgZXh0ZW5zaW9uPSIkezMtLnNofSIKICBpZiBbWyAtbiAiJHtleHRlbnNpb259IiAmJiAiJHtleHRlbnNpb246MDoxfSIgIT0gIi4iIF1dOyB0aGVuCiAgICBleHRlbnNpb249Ii4ke2V4dGVuc2lvbn0iCiAgZmkKCiAgdGVzdEFicygpIHsKICAgIGxvY2FsIHJlc3VsdAogICAgcmVzdWx0PSIkKHJlYWxwYXRoIC1lICIkMSIgMj4vZGV2L251bGwpIgogICAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTgxCiAgICBpZiBbWyAiJD8iID0gIjAiICYmIC1mICIke3Jlc3VsdH0iIF1dOyB0aGVuCiAgICAgIGVjaG8gIiR7cmVzdWx0fSIKICAgICAgcmV0dXJuIDAKICAgIGZpCiAgICByZXR1cm4gMQogIH0KCiAgIyBjb25mIGlzIGFic29sdXRlIGZpbGUgKGluY2x1ZGluZyBleHRlbnNpb24pCiAgdGVzdEFicyAiJHtjb25mRm9sZGVyfSR7ZXh0ZW5zaW9ufSIgJiYgcmV0dXJuIDAKICAjIGNvbmYgaXMgYWJzb2x1dGUgZmlsZQogIHRlc3RBYnMgIiR7Y29uZkZvbGRlcn0iICYmIHJldHVybiAwCiAgIyBjb25mIGlzIGFic29sdXRlIGZpbGUgKGluY2x1ZGluZyBleHRlbnNpb24pCiAgdGVzdEFicyAiJHtjb25mfSR7ZXh0ZW5zaW9ufSIgJiYgcmV0dXJuIDAKICAjIGNvbmYgaXMgYWJzb2x1dGUgZmlsZQogIHRlc3RBYnMgIiR7Y29uZn0iICYmIHJldHVybiAwCgogICMgcmVsYXRpdmUgdG8gd2hlcmUgc2NyaXB0IGlzIGV4ZWN1dGVkIChpbmNsdWRpbmcgZXh0ZW5zaW9uKQogIGlmIFtbIC1uICIke0NVUlJFTlRfRElSK3h4eH0iIF1dOyB0aGVuCiAgICB0ZXN0QWJzICIkKEZpbGU6OmNvbmNhdGVuYXRlUGF0aCAiJHtDVVJSRU5UX0RJUn0iICIke2NvbmZGb2xkZXJ9IikvJHtjb25mfSR7ZXh0ZW5zaW9ufSIgJiYgcmV0dXJuIDAKICBmaQogICMgZnJvbSBob21lLy5iYXNoLXRvb2xzLzxjb25mRm9sZGVyPgogIHRlc3RBYnMgIiQoRmlsZTo6Y29uY2F0ZW5hdGVQYXRoICIke0hPTUV9Ly5iYXNoLXRvb2xzIiAiJHtjb25mRm9sZGVyfSIpLyR7Y29uZn0ke2V4dGVuc2lvbn0iICYmIHJldHVybiAwCgogIGlmIFtbIC1uICIke0ZSQU1FV09SS19ST09UX0RJUit4eHh9IiBdXTsgdGhlbgogICAgIyBmcm9tIGZyYW1ld29yayBjb25mLzxjb25mRm9sZGVyPiAoaW5jbHVkaW5nIGV4dGVuc2lvbikKICAgIHRlc3RBYnMgIiQoRmlsZTo6Y29uY2F0ZW5hdGVQYXRoICIke0ZSQU1FV09SS19ST09UX0RJUn0vY29uZiIgIiR7Y29uZkZvbGRlcn0iKS8ke2NvbmZ9JHtleHRlbnNpb259IiAmJiByZXR1cm4gMAoKICAgICMgZnJvbSBmcmFtZXdvcmsgY29uZi88Y29uZkZvbGRlcj4KICAgIHRlc3RBYnMgIiQoRmlsZTo6Y29uY2F0ZW5hdGVQYXRoICIke0ZSQU1FV09SS19ST09UX0RJUn0vY29uZiIgIiR7Y29uZkZvbGRlcn0iKS8ke2NvbmZ9IiAmJiByZXR1cm4gMAogIGZpCgogICMgZmlsZSBub3QgZm91bmQKICBMb2c6OmRpc3BsYXlFcnJvciAiY29uZiBmaWxlICcke2NvbmZ9JyBub3QgZm91bmQiCgogIHJldHVybiAxCn0KCiMgQGRlc2NyaXB0aW9uIGNoZWNrIGlmIGRzbiBmaWxlIGhhcyBhbGwgdGhlIG1hbmRhdG9yeSB2YXJpYWJsZXMgc2V0CiMgTWFuZGF0b3J5IHZhcmlhYmxlcyBhcmU6IEhPU1ROQU1FLCBVU0VSLCBQQVNTV09SRCwgUE9SVAojCiMgQGFyZyAkMSBkc25GaWxlTmFtZTpTdHJpbmcgZHNuIGFic29sdXRlIGZpbGVuYW1lCiMgQHNldCBIT1NUTkFNRSBsb2FkZWQgZnJvbSBkc24gZmlsZQojIEBzZXQgUE9SVCBsb2FkZWQgZnJvbSBkc24gZmlsZQojIEBzZXQgVVNFUiBsb2FkZWQgZnJvbSBkc24gZmlsZQojIEBzZXQgUEFTU1dPUkQgbG9hZGVkIGZyb20gZHNuIGZpbGUKIyBAZXhpdGNvZGUgMCBvbiB2YWxpZCBmaWxlCiMgQGV4aXRjb2RlIDEgaWYgb25lIG9mIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBjb25mIGZpbGUgaXMgaW52YWxpZCBvciBpZiBmaWxlIG5vdCBmb3VuZAojIEBzdGRlcnIgbG9nIG91dHB1dCBpZiBlcnJvciBmb3VuZCBpbiBjb25mIGZpbGUKRGF0YWJhc2U6OmNoZWNrRHNuRmlsZSgpIHsKICBsb2NhbCBkc25GaWxlTmFtZT0iJDEiCiAgaWYgW1sgISAtZiAiJHtkc25GaWxlTmFtZX0iIF1dOyB0aGVuCiAgICBMb2c6OmRpc3BsYXlFcnJvciAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gbm90IGZvdW5kIgogICAgcmV0dXJuIDEKICBmaQoKICAoCiAgICB1bnNldCBIT1NUTkFNRSBQT1JUIFBBU1NXT1JEIFVTRVIKICAgICMgc2hlbGxjaGVjayBzb3VyY2U9L3NyYy9EYXRhYmFzZS90ZXN0c0RhdGEvZHNuX3ZhbGlkLmVudgogICAgc291cmNlICIke2RzbkZpbGVOYW1lfSIKICAgIGlmIFtbIC16ICR7SE9TVE5BTUUreH0gXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogSE9TVE5BTUUgbm90IHByb3ZpZGVkIgogICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmIFtbIC16ICIke0hPU1ROQU1FfSIgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5V2FybmluZyAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gOiBIT1NUTkFNRSB2YWx1ZSBub3QgcHJvdmlkZWQiCiAgICBmaQogICAgaWYgW1sgIiR7SE9TVE5BTUV9IiA9ICJsb2NhbGhvc3QiIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheVdhcm5pbmcgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogY2hlY2sgdGhhdCBIT1NUTkFNRSBzaG91bGQgbm90IGJlIDEyNy4wLjAuMSBpbnN0ZWFkIG9mIGxvY2FsaG9zdCIKICAgIGZpCiAgICBpZiBbWyAteiAiJHtQT1JUK3h9IiBdXTsgdGhlbgogICAgICBMb2c6OmRpc3BsYXlFcnJvciAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gOiBQT1JUIG5vdCBwcm92aWRlZCIKICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiAhIFtbICR7UE9SVH0gPX4gXlswLTldKyQgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogUE9SVCBpbnZhbGlkIgogICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmIFtbIC16ICIke1VTRVIreH0iIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheUVycm9yICJkc24gZmlsZSAke2RzbkZpbGVOYW1lfSA6IFVTRVIgbm90IHByb3ZpZGVkIgogICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmIFtbIC16ICIke1BBU1NXT1JEK3h9IiBdXTsgdGhlbgogICAgICBMb2c6OmRpc3BsYXlFcnJvciAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gOiBQQVNTV09SRCBub3QgcHJvdmlkZWQiCiAgICAgIHJldHVybiAxCiAgICBmaQogICkKfQoKIyBAZGVzY3JpcHRpb24gbG9nIG1lc3NhZ2UgdG8gZmlsZQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmxvZ0ZhdGFsKCkgewogIExvZzo6bG9nTWVzc2FnZSAiJHsyOi1GQVRBTH0iICIkMSIKfQoKIyBAZGVzY3JpcHRpb24gSW50ZXJuYWw6IGNvbW1vbiBsb2cgbWVzc2FnZQojIEBleGFtcGxlIHRleHQKIyAgIFtkYXRlXXxbbGV2ZWxNc2ddfG1lc3NhZ2UKIwojIEBleGFtcGxlIHRleHQKIyAgIDIwMjAtMDEtMTkgMTk6MjA6MjF8RVJST1IgIHxsb2cgZXJyb3IKIyAgIDIwMjAtMDEtMTkgMTk6MjA6MjF8U0tJUFBFRHxsb2cgc2tpcHBlZAojCiMgQGFyZyAkMSBsZXZlbE1zZzpTdHJpbmcgbWVzc2FnZSdzIGxldmVsIGRlc2NyaXB0aW9uIChlZzogU1RBVFVTLCBFUlJPUiwgLi4uKQojIEBhcmcgJDIgbXNnOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfRklMRSBTdHJpbmcgbG9nIGZpbGUgdG8gdXNlLCBkbyBub3RoaW5nIGlmIGVtcHR5CiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgaW50IGxvZyBsZXZlbCBsb2cgb25seSBpZiA+IE9GRiBvciBmYXRhbCBtZXNzYWdlcwojIEBzdGRlcnIgZGlhZ25vc3RpY3MgaW5mb3JtYXRpb24gaXMgZGlzcGxheWVkCiMgQHJlcXVpcmUgRW52OjpyZXF1aXJlTG9hZAojIEByZXF1aXJlIExvZzo6cmVxdWlyZUxvYWQKTG9nOjpsb2dNZXNzYWdlKCkgewogIGxvY2FsIGxldmVsTXNnPSIkMSIKICBsb2NhbCBtc2c9IiQyIgogIGxvY2FsIGRhdGUKCiAgaWYgW1sgLW4gIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IiBdXSAmJiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+IF9fTEVWRUxfT0ZGKSk7IHRoZW4KICAgIGRhdGU9IiQoZGF0ZSAnKyVZLSVtLSVkICVIOiVNOiVTJykiCiAgICB0b3VjaCAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iCiAgICBwcmludGYgIiVzfCU3c3wlc1xuIiAiJHtkYXRlfSIgIiR7bGV2ZWxNc2d9IiAiJHttc2d9IiA+PiIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBjb25jYXRlbmF0ZSAyIHBhdGhzIGFuZCBlbnN1cmUgdGhlIHBhdGggaXMgY29ycmVjdCB1c2luZyByZWFscGF0aCAtbQojIEBhcmcgJDEgYmFzZVBhdGg6U3RyaW5nCiMgQGFyZyAkMiBzdWJQYXRoOlN0cmluZwojIEByZXF1aXJlIExpbnV4OjpyZXF1aXJlUmVhbHBhdGhDb21tYW5kCkZpbGU6OmNvbmNhdGVuYXRlUGF0aCgpIHsKICBsb2NhbCBiYXNlUGF0aD0iJDEiCiAgbG9jYWwgc3ViUGF0aD0iJDIiCiAgbG9jYWwgZnVsbFBhdGg9IiR7YmFzZVBhdGg6KyR7YmFzZVBhdGh9L30ke3N1YlBhdGh9IgoKICByZWFscGF0aCAtbSAiJHtmdWxsUGF0aH0iIDI+L2Rldi9udWxsCn0KCiMgQGRlc2NyaXB0aW9uIERpc3BsYXkgbWVzc2FnZSB1c2luZyBlcnJvciBjb2xvciAocmVkKQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlFcnJvcigpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgPj0gX19MRVZFTF9FUlJPUikpOyB0aGVuCiAgICBlY2hvIC1lICIke19fRVJST1JfQ09MT1J9RVJST1IgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nRXJyb3IgIiQxIgp9CgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgd2FybmluZyBjb2xvciAoeWVsbG93KQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlXYXJuaW5nKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTCA+PSBfX0xFVkVMX1dBUk5JTkcpKTsgdGhlbgogICAgZWNobyAtZSAiJHtfX1dBUk5JTkdfQ09MT1J9V0FSTiAgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nV2FybmluZyAiJDEiCn0KCiMgQGRlc2NyaXB0aW9uIGVuc3VyZSBlbnYgZmlsZXMgYXJlIGxvYWRlZAojIEBhcmcgJEAgbGlzdCBvZiBkZWZhdWx0IGZpbGVzIHRvIGxvYWQgYXQgdGhlIGVuZAojIEBleGl0Y29kZSAxIGlmIG9uZSBvZiBlbnYgZmlsZXMgZmFpbHMgdG8gbG9hZAojIEBzdGRlcnIgZGlhZ25vc3RpY3MgaW5mb3JtYXRpb24gaXMgZGlzcGxheWVkCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjEyMApFbnY6OnJlcXVpcmVMb2FkKCkgewogIGxvY2FsIC1hIGRlZmF1bHRGaWxlcz0oIiRAIikKICAjIGdldCBsaXN0IG9mIHBvc3NpYmxlIGNvbmZpZyBmaWxlcwogIGxvY2FsIC1hIGNvbmZpZ0ZpbGVzPSgpCiAgaWYgW1sgLW4gIiR7QkFTSF9GUkFNRVdPUktfRU5WX0ZJTEVTWzBdKzF9IiBdXTsgdGhlbgogICAgIyBCQVNIX0ZSQU1FV09SS19FTlZfRklMRVMgaXMgYW4gYXJyYXkKICAgIGNvbmZpZ0ZpbGVzKz0oIiR7QkFTSF9GUkFNRVdPUktfRU5WX0ZJTEVTW0BdfSIpCiAgZmkKICBpZiBbWyAtZiAiJChwd2QpLy5mcmFtZXdvcmstY29uZmlnIiBdXTsgdGhlbgogICAgY29uZmlnRmlsZXMrPSgiJChwd2QpLy5mcmFtZXdvcmstY29uZmlnIikKICBmaQogIGlmIFtbIC1mICIke0ZSQU1FV09SS19ST09UX0RJUn0vLmZyYW1ld29yay1jb25maWciIF1dOyB0aGVuCiAgICBjb25maWdGaWxlcys9KCIke0ZSQU1FV09SS19ST09UX0RJUn0vLmZyYW1ld29yay1jb25maWciKQogIGZpCiAgaWYgW1sgLW4gIiR7b3B0aW9uQmFzaEZyYW1ld29ya0NvbmZpZ30iICYmIC1mICIke29wdGlvbkJhc2hGcmFtZXdvcmtDb25maWd9IiBdXTsgdGhlbgogICAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CiAgICBjb25maWdGaWxlcys9KCIke29wdGlvbkJhc2hGcmFtZXdvcmtDb25maWd9IikKICBmaQogIGNvbmZpZ0ZpbGVzKz0oIiR7b3B0aW9uRW52RmlsZXNbQF19IikKICBjb25maWdGaWxlcys9KCIke2RlZmF1bHRGaWxlc1tAXX0iKQoKICBmb3IgZmlsZSBpbiAiJHtjb25maWdGaWxlc1tAXX0iOyBkbwogICAgIyBzaGVsbGNoZWNrIHNvdXJjZT0vLmZyYW1ld29yay1jb25maWcKICAgIENVUlJFTlRfTE9BREVEX0VOVl9GSUxFPSIke2ZpbGV9IiBzb3VyY2UgIiR7ZmlsZX0iIHx8IHsKICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgIndoaWxlIGxvYWRpbmcgY29uZmlnIGZpbGU6ICR7ZmlsZX0iCiAgICAgIHJldHVybiAxCiAgICB9CiAgZG9uZQp9CgojIEBkZXNjcmlwdGlvbiBhY3RpdmF0ZSBvciBub3QgTG9nOjpkaXNwbGF5KiBhbmQgTG9nOjpsb2cqIGZ1bmN0aW9ucwojIGJhc2VkIG9uIEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgYW5kIEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTAojIGVudmlyb25tZW50IHZhcmlhYmxlcyBsb2FkZWQgYnkgRW52OjpyZXF1aXJlTG9hZAojIHRyeSB0byBjcmVhdGUgbG9nIGZpbGUgYW5kIHJvdGF0ZSBpdCBpZiBuZWNlc3NhcnkKIyBAbm9hcmdzCiMgQHNldCBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgaW50IHRvIE9GRiBsZXZlbCBpZiBCQVNIX0ZSQU1FV09SS19MT0dfRklMRSBpcyBlbXB0eSBvciBub3Qgd3JpdGFibGUKIyBAZW52IEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgaW50CiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgaW50CiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfRklMRSBTdHJpbmcKIyBAZW52IEJBU0hfRlJBTUVXT1JLX0xPR19GSUxFX01BWF9ST1RBVElPTiBpbnQgZG8gbG9nIHJvdGF0aW9uIGlmID4gMAojIEBleGl0Y29kZSAwIGFsd2F5cyBzdWNjZXNzZnVsCiMgQHN0ZGVyciBkaWFnbm9zdGljcyBpbmZvcm1hdGlvbiBhYm91dCBsb2cgZmlsZSBpcyBkaXNwbGF5ZWQKIyBAcmVxdWlyZSBFbnY6OnJlcXVpcmVMb2FkCiMgQHJlcXVpcmUgVUk6OnJlcXVpcmVUaGVtZQpMb2c6OnJlcXVpcmVMb2FkKCkgewogIGlmIFtbIC16ICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFOi19IiBdXTsgdGhlbgogICAgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMPSR7X19MRVZFTF9PRkZ9CiAgICBleHBvcnQgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMCiAgZmkKCiAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPiBfX0xFVkVMX09GRikpOyB0aGVuCiAgICBpZiBbWyAhIC1mICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIgXV07IHRoZW4KICAgICAgaWYKICAgICAgICAhIG1rZGlyIC1wICIkKGRpcm5hbWUgIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IikiIDI+L2Rldi9udWxsIHx8CiAgICAgICAgICAhIHRvdWNoIC0tbm8tY3JlYXRlICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIgMj4vZGV2L251bGwKICAgICAgdGhlbgogICAgICAgIEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTD0ke19fTEVWRUxfT0ZGfQogICAgICAgIGVjaG8gLWUgIiR7X19FUlJPUl9DT0xPUn1FUlJPUiAgIC0gRmlsZSAke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSBpcyBub3Qgd3JpdGFibGUke19fUkVTRVRfQ09MT1J9IiA+JjIKICAgICAgZmkKICAgIGVsaWYgW1sgISAtdyAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iIF1dOyB0aGVuCiAgICAgIEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTD0ke19fTEVWRUxfT0ZGfQogICAgICBlY2hvIC1lICIke19fRVJST1JfQ09MT1J9RVJST1IgICAtIEZpbGUgJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0gaXMgbm90IHdyaXRhYmxlJHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgICBmaQoKICBmaQoKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+IF9fTEVWRUxfT0ZGKSk7IHRoZW4KICAgICMgd2lsbCBhbHdheXMgYmUgY3JlYXRlZCBldmVuIGlmIG5vdCBpbiBpbmZvIGxldmVsCiAgICBMb2c6OmxvZ01lc3NhZ2UgIklORk8iICJMb2dnaW5nIHRvIGZpbGUgJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0gLSBMb2cgbGV2ZWwgJHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUx9IgogICAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfRklMRV9NQVhfUk9UQVRJT04gPiAwKSk7IHRoZW4KICAgICAgTG9nOjpyb3RhdGUgIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IiAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRV9NQVhfUk9UQVRJT059IgogICAgZmkKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBsb2cgbWVzc2FnZSB0byBmaWxlCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6bG9nRXJyb3IoKSB7CiAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPj0gX19MRVZFTF9FUlJPUikpOyB0aGVuCiAgICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotRVJST1J9IiAiJDEiCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gbG9nIG1lc3NhZ2UgdG8gZmlsZQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmxvZ1dhcm5pbmcoKSB7CiAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPj0gX19MRVZFTF9XQVJOSU5HKSk7IHRoZW4KICAgIExvZzo6bG9nTWVzc2FnZSAiJHsyOi1XQVJOSU5HfSIgIiQxIgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIFRvIGJlIGNhbGxlZCBiZWZvcmUgbG9nZ2luZyBpbiB0aGUgbG9nIGZpbGUKIyBAYXJnICQxIGZpbGU6c3RyaW5nIGxvZyBmaWxlIG5hbWUKIyBAYXJnICQyIG1heExvZ0ZpbGVzQ291bnQ6aW50IG1heGltdW0gbnVtYmVyIG9mIGxvZyBmaWxlcwpMb2c6OnJvdGF0ZSgpIHsKICBsb2NhbCBmaWxlPSIkMSIKICBsb2NhbCBtYXhMb2dGaWxlc0NvdW50PSIkezI6LTV9IgoKICBpZiBbWyAhIC1mICIke2ZpbGV9IiBdXTsgdGhlbgogICAgTG9nOjpkaXNwbGF5U2tpcHBlZCAiTG9nIGZpbGUgJHtmaWxlfSBkb2Vzbid0IGV4aXN0IHlldCIKICAgIHJldHVybiAwCiAgZmkKICBmb3IgaSBpbiAkKHNlcSAkKChtYXhMb2dGaWxlc0NvdW50IC0gMSkpIC0xIDEpOyBkbwogICAgTG9nOjpkaXNwbGF5SW5mbyAiTG9nIHJvdGF0aW9uICR7ZmlsZX0uJHtpfSB0byAke2ZpbGV9LiQoKGkgKyAxKSkiCiAgICBtdiAiJHtmaWxlfS4ieyIke2l9IiwiJCgoaSArIDEpKSJ9ICY+L2Rldi9udWxsIHx8IHRydWUKICBkb25lCiAgaWYgY3AgIiR7ZmlsZX0iICIke2ZpbGV9LjEiICY+L2Rldi9udWxsOyB0aGVuCiAgICBlY2hvID4iJHtmaWxlfSIgIyByZXNldCBsb2cgZmlsZQogICAgTG9nOjpkaXNwbGF5SW5mbyAiTG9nIHJvdGF0aW9uICR7ZmlsZX0gdG8gJHtmaWxlfS4xIgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIGVuc3VyZSBjb21tYW5kIHJlYWxwYXRoIGlzIGF2YWlsYWJsZQojIEBleGl0Y29kZSAxIGlmIHJlYWxwYXRoIGNvbW1hbmQgbm90IGF2YWlsYWJsZQojIEBzdGRlcnIgZGlhZ25vc3RpY3MgaW5mb3JtYXRpb24gaXMgZGlzcGxheWVkCkxpbnV4OjpyZXF1aXJlUmVhbHBhdGhDb21tYW5kKCkgewogIEFzc2VydDo6Y29tbWFuZEV4aXN0cyByZWFscGF0aAp9CgojIEBkZXNjcmlwdGlvbiBsb2FkIGNvbG9yIHRoZW1lCiMgQG5vYXJncwojIEBlbnYgQkFTSF9GUkFNRVdPUktfVEhFTUUgU3RyaW5nIHRoZW1lIHRvIHVzZQojIEBleGl0Y29kZSAwIGFsd2F5cyBzdWNjZXNzZnVsClVJOjpyZXF1aXJlVGhlbWUoKSB7CiAgVUk6OnRoZW1lICIke0JBU0hfRlJBTUVXT1JLX1RIRU1FLWRlZmF1bHR9Igp9CgojIEBkZXNjcmlwdGlvbiBjaGVjayBpZiBjb21tYW5kIHNwZWNpZmllZCBleGlzdHMgb3IgcmV0dXJuIDEKIyB3aXRoIGVycm9yIGFuZCBtZXNzYWdlIGlmIG5vdAojCiMgQGFyZyAkMSBjb21tYW5kTmFtZTpTdHJpbmcgb24gd2hpY2ggZXhpc3RlbmNlIG11c3QgYmUgY2hlY2tlZAojIEBhcmcgJDIgaGVscElmTm90RXhpc3RzOlN0cmluZyBhIGhlbHAgY29tbWFuZCB0byBkaXNwbGF5IGlmIHRoZSBjb21tYW5kIGRvZXMgbm90IGV4aXN0CiMKIyBAZXhpdGNvZGUgMSBpZiB0aGUgY29tbWFuZCBzcGVjaWZpZWQgZG9lcyBub3QgZXhpc3QKIyBAc3RkZXJyIGRpYWdub3N0aWMgaW5mb3JtYXRpb24gKyBoZWxwIGlmIHNlY29uZCBhcmd1bWVudCBpcyBwcm92aWRlZApBc3NlcnQ6OmNvbW1hbmRFeGlzdHMoKSB7CiAgbG9jYWwgY29tbWFuZE5hbWU9IiQxIgogIGxvY2FsIGhlbHBJZk5vdEV4aXN0cz0iJDIiCgogICIke0JBU0hfRlJBTUVXT1JLX0NPTU1BTkQ6LWNvbW1hbmR9IiAtdiAiJHtjb21tYW5kTmFtZX0iID4vZGV2L251bGwgMj4vZGV2L251bGwgfHwgewogICAgTG9nOjpkaXNwbGF5RXJyb3IgIiR7Y29tbWFuZE5hbWV9IGlzIG5vdCBpbnN0YWxsZWQsIHBsZWFzZSBpbnN0YWxsIGl0IgogICAgaWYgW1sgLW4gIiR7aGVscElmTm90RXhpc3RzfSIgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5SW5mbyAiJHtoZWxwSWZOb3RFeGlzdHN9IgogICAgZmkKICAgIHJldHVybiAxCiAgfQogIHJldHVybiAwCn0KCiMgQGRlc2NyaXB0aW9uIERpc3BsYXkgbWVzc2FnZSB1c2luZyBza2lwIGNvbG9yICh5ZWxsb3cpCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6ZGlzcGxheVNraXBwZWQoKSB7CiAgaWYgKChCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMID49IF9fTEVWRUxfSU5GTykpOyB0aGVuCiAgICBlY2hvIC1lICIke19fU0tJUFBFRF9DT0xPUn1TS0lQUEVEIC0gJHsxfSR7X19SRVNFVF9DT0xPUn0iID4mMgogIGZpCiAgTG9nOjpsb2dTa2lwcGVkICIkMSIKfQoKIyBAZGVzY3JpcHRpb24gbG9hZCBjb2xvcnMgdGhlbWUgY29uc3RhbnRzCiMgQHdhcm5pbmcgaWYgdHR5IG5vdCBvcGVuZWQsIG5vQ29sb3IgdGhlbWUgd2lsbCBiZSBjaG9zZW4KIyBAYXJnICQxIHRoZW1lOlN0cmluZyB0aGUgdGhlbWUgdG8gdXNlIChkZWZhdWx0LCBub0NvbG9yKQojIEBhcmcgJEAgYXJnczpTdHJpbmdbXQojIEBzZXQgX19FUlJPUl9DT0xPUiBTdHJpbmcgaW5kaWNhdGUgZXJyb3Igc3RhdHVzCiMgQHNldCBfX0lORk9fQ09MT1IgU3RyaW5nIGluZGljYXRlIGluZm8gc3RhdHVzCiMgQHNldCBfX1NVQ0NFU1NfQ09MT1IgU3RyaW5nIGluZGljYXRlIHN1Y2Nlc3Mgc3RhdHVzCiMgQHNldCBfX1dBUk5JTkdfQ09MT1IgU3RyaW5nIGluZGljYXRlIHdhcm5pbmcgc3RhdHVzCiMgQHNldCBfX1NLSVBQRURfQ09MT1IgU3RyaW5nIGluZGljYXRlIHNraXBwZWQgc3RhdHVzCiMgQHNldCBfX0RFQlVHX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSBkZWJ1ZyBzdGF0dXMKIyBAc2V0IF9fSEVMUF9DT0xPUiBTdHJpbmcgaW5kaWNhdGUgaGVscCBzdGF0dXMKIyBAc2V0IF9fVEVTVF9DT0xPUiBTdHJpbmcgbm90IHVzZWQKIyBAc2V0IF9fVEVTVF9FUlJPUl9DT0xPUiBTdHJpbmcgbm90IHVzZWQKIyBAc2V0IF9fSEVMUF9USVRMRV9DT0xPUiBTdHJpbmcgdXNlZCB0byBkaXNwbGF5IGhlbHAgdGl0bGUgaW4gaGVscCBzdHJpbmdzCiMgQHNldCBfX0hFTFBfT1BUSU9OX0NPTE9SIFN0cmluZyB1c2VkIHRvIGRpc3BsYXkgaGlnaGxpZ2h0IG9wdGlvbnMgaW4gaGVscCBzdHJpbmdzCiMKIyBAc2V0IF9fUkVTRVRfQ09MT1IgU3RyaW5nIHJlc2V0IGRlZmF1bHQgY29sb3IKIwojIEBzZXQgX19IRUxQX0VYQU1QTEUgU3RyaW5nIHRvIHJlbW92ZQojIEBzZXQgX19IRUxQX1RJVExFIFN0cmluZyB0byByZW1vdmUKIyBAc2V0IF9fSEVMUF9OT1JNQUwgU3RyaW5nIHRvIHJlbW92ZQojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKVUk6OnRoZW1lKCkgewogIGxvY2FsIHRoZW1lPSIkezEtZGVmYXVsdH0iCiAgaWYgW1sgISAiJHt0aGVtZX0iID1+IC1mb3JjZSQgXV0gJiYgISBBc3NlcnQ6OnR0eTsgdGhlbgogICAgdGhlbWU9Im5vQ29sb3IiCiAgZmkKICBjYXNlICIke3RoZW1lfSIgaW4KICAgIGRlZmF1bHQgfCBkZWZhdWx0LWZvcmNlKQogICAgICB0aGVtZT0iZGVmYXVsdCIKICAgICAgOzsKICAgIG5vQ29sb3IpIDs7CiAgICAqKQogICAgICBMb2c6OmZhdGFsICJpbnZhbGlkIHRoZW1lIHByb3ZpZGVkIgogICAgICA7OwogIGVzYWMKICBpZiBbWyAiJHt0aGVtZX0iID0gImRlZmF1bHQiIF1dOyB0aGVuCiAgICBCQVNIX0ZSQU1FV09SS19USEVNRT0iZGVmYXVsdCIKICAgICMgY2hlY2sgY29sb3JzIGFwcGxpY2FibGUgaHR0cHM6Ly9taXNjLmZsb2dpc29mdC5jb20vYmFzaC90aXBfY29sb3JzX2FuZF9mb3JtYXR0aW5nCiAgICBfX0VSUk9SX0NPTE9SPSdcZVszMW0nICAgICAgICAgIyBSZWQKICAgIF9fSU5GT19DT0xPUj0nXGVbNDRtJyAgICAgICAgICAjIHdoaXRlIG9uIGxpZ2h0Qmx1ZQogICAgX19TVUNDRVNTX0NPTE9SPSdcZVszMm0nICAgICAgICMgR3JlZW4KICAgIF9fV0FSTklOR19DT0xPUj0nXGVbMzNtJyAgICAgICAjIFllbGxvdwogICAgX19TS0lQUEVEX0NPTE9SPSdcZVszM20nICAgICAgICMgWWVsbG93CiAgICBfX0RFQlVHX0NPTE9SPSdcZVszN20nICAgICAgICAgIyBHcmV5CiAgICBfX0hFTFBfQ09MT1I9J1xlWzc7NDk7MzNtJyAgICAgIyBCbGFjayBvbiBHb2xkCiAgICBfX1RFU1RfQ09MT1I9J1xlWzEwMG0nICAgICAgICAgIyBMaWdodCBtYWdlbnRhCiAgICBfX1RFU1RfRVJST1JfQ09MT1I9J1xlWzQxbScgICAgIyB3aGl0ZSBvbiByZWQKICAgIF9fSEVMUF9USVRMRV9DT0xPUj0iXGVbMTszN20iICAjIEJvbGQKICAgIF9fSEVMUF9PUFRJT05fQ09MT1I9IlxlWzE7MzRtIiAjIEJsdWUKICAgICMgSW50ZXJuYWw6IHJlc2V0IGNvbG9yCiAgICBfX1JFU0VUX0NPTE9SPSdcZVswbScgIyBSZXNldCBDb2xvcgogICAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTU1LFNDMjAzNAogICAgX19IRUxQX0VYQU1QTEU9IiQoZWNobyAtZSAiXGVbMjs5N20iKSIKICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NSxTQzIwMzQKICAgIF9fSEVMUF9USVRMRT0iJChlY2hvIC1lICJcZVsxOzM3bSIpIgogICAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTU1LFNDMjAzNAogICAgX19IRUxQX05PUk1BTD0iJChlY2hvIC1lICJcMDMzWzBtIikiCiAgZWxzZQogICAgQkFTSF9GUkFNRVdPUktfVEhFTUU9Im5vQ29sb3IiCiAgICAjIGNoZWNrIGNvbG9ycyBhcHBsaWNhYmxlIGh0dHBzOi8vbWlzYy5mbG9naXNvZnQuY29tL2Jhc2gvdGlwX2NvbG9yc19hbmRfZm9ybWF0dGluZwogICAgX19FUlJPUl9DT0xPUj0nJwogICAgX19JTkZPX0NPTE9SPScnCiAgICBfX1NVQ0NFU1NfQ09MT1I9JycKICAgIF9fV0FSTklOR19DT0xPUj0nJwogICAgX19TS0lQUEVEX0NPTE9SPScnCiAgICBfX0RFQlVHX0NPTE9SPScnCiAgICBfX0hFTFBfQ09MT1I9JycKICAgIF9fVEVTVF9DT0xPUj0nJwogICAgX19URVNUX0VSUk9SX0NPTE9SPScnCiAgICBfX0hFTFBfVElUTEVfQ09MT1I9JycKICAgIF9fSEVMUF9PUFRJT05fQ09MT1I9JycKICAgICMgSW50ZXJuYWw6IHJlc2V0IGNvbG9yCiAgICBfX1JFU0VUX0NPTE9SPScnCiAgICBfX0hFTFBfRVhBTVBMRT0nJwogICAgX19IRUxQX1RJVExFPScnCiAgICBfX0hFTFBfTk9STUFMPScnCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gY2hlY2sgaWYgdHR5IChpbnRlcmFjdGl2ZSBtb2RlKSBpcyBhY3RpdmUKIyBAbm9hcmdzCiMgQGV4aXRjb2RlIDEgaWYgdHR5IG5vdCBhY3RpdmUKIyBAZW52IE5PTl9JTlRFUkFDVElWRSBpZiAxIGNvbnNpZGVyIGFzIG5vdCBpbnRlcmFjdGl2ZSBldmVuIGlmIGVudmlyb25tZW50IGlzIGludGVyYWN0aXZlCiMgQGVudiBJTlRFUkFDVElWRSBpZiAxIGNvbnNpZGVyIGFzIGludGVyYWN0aXZlIGV2ZW4gaWYgZW52aXJvbm1lbnQgaXMgbm90IGludGVyYWN0aXZlCiMgQHN0ZGVyciBkaWFnbm9zdGljIGluZm9ybWF0aW9uICsgaGVscCBpZiBzZWNvbmQgYXJndW1lbnQgaXMgcHJvdmlkZWQKQXNzZXJ0Ojp0dHkoKSB7CiAgaWYgW1sgIiR7Tk9OX0lOVEVSQUNUSVZFOi0wfSIgPSAiMSIgXV07IHRoZW4KICAgIHJldHVybiAxCiAgZmkKICBpZiBbWyAiJHtJTlRFUkFDVElWRTotMH0iID0gIjEiIF1dOyB0aGVuCiAgICByZXR1cm4gMAogIGZpCiAgW1sgLXQgMSB8fCAtdCAyIF1dCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dTa2lwcGVkKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfSU5GTykpOyB0aGVuCiAgICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotU0tJUFBFRH0iICIkMSIKICBmaQp9CgojIEZVTkNUSU9OUwoKZmFjYWRlX21haW5fZW1iZWRGcmFtZXdvcmtGdW5jdGlvbmJpbkZpbGV0cGwoKSB7CiMgUkVRVUlSRVMKTGludXg6OnJlcXVpcmVFeGVjdXRlZEFzVXNlcgpFbnY6OnJlcXVpcmVMb2FkCkxvZzo6cmVxdWlyZUxvYWQKTGludXg6OnJlcXVpcmVSZWFscGF0aENvbW1hbmQKVUk6OnJlcXVpcmVUaGVtZQpDb21waWxlcjo6RmFjYWRlOjpyZXF1aXJlQ29tbWFuZEJpbkRpcgoKIyBAcmVxdWlyZSBDb21waWxlcjo6RmFjYWRlOjpyZXF1aXJlQ29tbWFuZEJpbkRpcgoKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTU0LFNDMjAxNgpmdW5jdGlvblRvQ2FsbD0nRGI6OnF1ZXJ5T25lRGF0YWJhc2UnCiIke2Z1bmN0aW9uVG9DYWxsfSIgIiRAIgoKfQoKZmFjYWRlX21haW5fZW1iZWRGcmFtZXdvcmtGdW5jdGlvbmJpbkZpbGV0cGwgIiRAIgo=" Compiler::Embed::extractFileFromBase64 \ "${embed_function_DbQueryOneDatabase}" \ @@ -1427,6 +1450,7 @@ dbQueryAllDatabasesCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1769,11 +1793,11 @@ dbQueryAllDatabasesCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Execute a query on multiple databases in order to generate a report with tsv format, query can be parallelized on multiple databases")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Execute a query on multiple databases in order to generate a report with tsv format, query can be parallelized on multiple databases")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--jobs|-j ]" "[--bar|-b]" "[--separator|-s ]" "[--from-dsn|-f ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1782,25 +1806,25 @@ dbQueryAllDatabasesCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=($'Query to execute \n - , try to execute the mysql query provided by the file \n - , search for query file in queries directory (see below) \n - else the argument is interpreted as query string') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--jobs${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-j ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(specify\ the\ number\ of\ db\ to\ query\ in\ parallel) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo ' Default value: 1' echo -e " ${__HELP_OPTION_COLOR}--bar${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-b${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Show\ progress\ as\ a\ progress\ bar.\ In\ the\ bar\ is\ shown:\ %\ of\ jobs\ completed\,\ estimated\ seconds\ left\,\ and\ number\ of\ jobs\ started.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--separator${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-s ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(character\ to\ use\ to\ separate\ mysql\ column) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo ' Default value: |' echo echo -e "${__HELP_TITLE_COLOR}QUERY OPTIONS:${__RESET_COLOR}" @@ -1808,79 +1832,83 @@ dbQueryAllDatabasesCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(target\ mysql\ server) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}LIST OF AVAILABLE DSN:${__HELP_NORMAL} ${dsnList} @@ -1910,7 +1938,7 @@ ${__HELP_EXAMPLE}${example1}${__HELP_NORMAL}""" echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/dbScriptAllDatabases b/bin/dbScriptAllDatabases index 4fb771f4..4bab4274 100755 --- a/bin/dbScriptAllDatabases +++ b/bin/dbScriptAllDatabases @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbScriptAllDatabases +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbScriptAllDatabases # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # EMBED Db::queryOneDatabase as dbQueryOneDatabase @@ -95,123 +95,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if command specified exists or return 1 # with error and message if not # @@ -1014,8 +1037,8 @@ Log::logSkipped() { # @require Compiler::Embed::requireEmbedBinDir -declare -gx embed_function_DbQueryOneDatabase="${PERSISTENT_TMPDIR:-/tmp}/bin/f94f442fbdd0b7f3ff7df80421405d82/dbQueryOneDatabase" -declare -gx encoded_binary_file_DbQueryOneDatabase="IyEvdXNyL2Jpbi9lbnYgYmFzaAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgR0VORVJBVEVEIEZBQ0FERQojIERPIE5PVCBFRElUIElUCiMgQGdlbmVyYXRlZAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjI4OCxTQzIwMzQKIyBCSU5fRklMRT0ke0JJTl9GSUxFfQojIEZBQ0FERQoKIyBlbnN1cmUgdGhhdCBubyB1c2VyIGFsaWFzZXMgY291bGQgaW50ZXJmZXJlIHdpdGgKIyBjb21tYW5kcyB1c2VkIGluIHRoaXMgc2NyaXB0CnVuYWxpYXMgLWEgfHwgdHJ1ZQpzaG9wdCAtdSBleHBhbmRfYWxpYXNlcwoKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CigoZmFpbHVyZXMgPSAwKSkgfHwgdHJ1ZQoKIyBCYXNoIHdpbGwgcmVtZW1iZXIgJiByZXR1cm4gdGhlIGhpZ2hlc3QgZXhpdCBjb2RlIGluIGEgY2hhaW4gb2YgcGlwZXMuCiMgVGhpcyB3YXkgeW91IGNhbiBjYXRjaCB0aGUgZXJyb3IgaW5zaWRlIHBpcGVzLCBlLmcuIG15c3FsZHVtcCB8IGd6aXAKc2V0IC1vIHBpcGVmYWlsCnNldCAtbyBlcnJleGl0CgojIENvbW1hbmQgU3Vic3RpdHV0aW9uIGNhbiBpbmhlcml0IGVycmV4aXQgb3B0aW9uIHNpbmNlIGJhc2ggdjQuNApzaG9wdCAtcyBpbmhlcml0X2VycmV4aXQgfHwgdHJ1ZQoKIyBhIGxvZyBpcyBnZW5lcmF0ZWQgd2hlbiBhIGNvbW1hbmQgZmFpbHMKc2V0IC1vIGVycnRyYWNlCgojIHVzZSBudWxsZ2xvYiBzbyB0aGF0IChmaWxlKi5waHApIHdpbGwgcmV0dXJuIGFuIGVtcHR5IGFycmF5IGlmIG5vIGZpbGUgbWF0Y2hlcyB0aGUgd2lsZGNhcmQKc2hvcHQgLXMgbnVsbGdsb2IKCiMgZW5zdXJlIHJlZ2V4cCBhcmUgaW50ZXJwcmV0ZWQgd2l0aG91dCBhY2NlbnR1YXRlZCBjaGFyYWN0ZXJzCmV4cG9ydCBMQ19BTEw9UE9TSVgKCmV4cG9ydCBURVJNPXh0ZXJtLTI1NmNvbG9yCgojIGF2b2lkIGludGVyYWN0aXZlIGluc3RhbGwKZXhwb3J0IERFQklBTl9GUk9OVEVORD1ub25pbnRlcmFjdGl2ZQpleHBvcnQgREVCQ09ORl9OT05JTlRFUkFDVElWRV9TRUVOPXRydWUKCiMgc3RvcmUgY29tbWFuZCBhcmd1bWVudHMgZm9yIGxhdGVyIHVzYWdlCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNApkZWNsYXJlIC1hIEJBU0hfRlJBTUVXT1JLX0FSR1Y9KCIkQCIpCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNApkZWNsYXJlIC1hIE9SSUdJTkFMX0JBU0hfRlJBTUVXT1JLX0FSR1Y9KCIkQCIpCgojIEBzZWUgaHR0cHM6Ly91bml4LnN0YWNrZXhjaGFuZ2UuY29tL2EvMzg2ODU2CiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjMxNwppbnRlcnJ1cHRNYW5hZ2VtZW50KCkgewogICMgcmVzdG9yZSBTSUdJTlQgaGFuZGxlcgogIHRyYXAgLSBJTlQKICAjIGVuc3VyZSB0aGF0IEN0cmwtQyBpcyB0cmFwcGVkIGJ5IHRoaXMgc2NyaXB0IGFuZCBub3QgYnkgc3ViIHByb2Nlc3MKICAjIHJlcG9ydCB0byB0aGUgcGFyZW50IHRoYXQgd2UgaGF2ZSBpbmRlZWQgYmVlbiBpbnRlcnJ1cHRlZAogIGtpbGwgLXMgSU5UICIkJCIKfQp0cmFwIGludGVycnVwdE1hbmFnZW1lbnQgSU5UClNDUklQVF9OQU1FPSR7MCMjKi99ClJFQUxfU0NSSVBUX0ZJTEU9IiQocmVhZGxpbmsgLWUgIiQocmVhbHBhdGggIiR7QkFTSF9TT1VSQ0VbMF19IikiKSIKaWYgW1sgLW4gIiR7RU1CRURfQ1VSUkVOVF9ESVJ9IiBdXTsgdGhlbgogIENVUlJFTlRfRElSPSIke0VNQkVEX0NVUlJFTlRfRElSfSIKZWxzZQogIENVUlJFTlRfRElSPSIkKGNkICIkKHJlYWRsaW5rIC1lICIke1JFQUxfU0NSSVBUX0ZJTEUlLyp9IikiICYmIHB3ZCAtUCkiCmZpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBUZW1wIGRpciBtYW5hZ2VtZW50CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKS0VFUF9URU1QX0ZJTEVTPSIke0tFRVBfVEVNUF9GSUxFUzotMH0iCmV4cG9ydCBLRUVQX1RFTVBfRklMRVMKCiMgUEVSU0lTVEVOVF9UTVBESVIgaXMgbm90IGRlbGV0ZWQgYnkgdHJhcHMKUEVSU0lTVEVOVF9UTVBESVI9IiR7VE1QRElSOi0vdG1wfS9iYXNoLWZyYW1ld29yayIKZXhwb3J0IFBFUlNJU1RFTlRfVE1QRElSCm1rZGlyIC1wICIke1BFUlNJU1RFTlRfVE1QRElSfSIKCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNApUTVBESVI9IiQobWt0ZW1wIC1kIC1wICIke1BFUlNJU1RFTlRfVE1QRElSOi0vdG1wfSIgLXQgYmFzaC1mcmFtZXdvcmstJCQtWFhYWFhYKSIKZXhwb3J0IFRNUERJUgoKIyB0ZW1wIGRpciBjbGVhbmluZwojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIzMTcKY2xlYW5PbkV4aXQoKSB7CiAgaWYgW1sgIiR7S0VFUF9URU1QX0ZJTEVTOi0wfSIgPSAiMSIgXV07IHRoZW4KICAgIExvZzo6ZGlzcGxheUluZm8gIktFRVBfVEVNUF9GSUxFUz0xIHRlbXAgZmlsZXMga2VwdCBoZXJlICcke1RNUERJUn0nIgogIGVsaWYgW1sgLW4gIiR7VE1QRElSK3h4eH0iIF1dOyB0aGVuCiAgICBMb2c6OmRpc3BsYXlEZWJ1ZyAiS0VFUF9URU1QX0ZJTEVTPTAgcmVtb3ZpbmcgdGVtcCBmaWxlcyAnJHtUTVBESVJ9JyIKICAgIHJtIC1SZiAiJHtUTVBESVI6LS90bXAvZmFrZX0iID4vZGV2L251bGwgMj4mMQogIGZpCn0KdHJhcCBjbGVhbk9uRXhpdCBFWElUIEhVUCBRVUlUIEFCUlQgVEVSTQoKIyBWQVJfTUFJTl9GVU5DVElPTl9WQVJfTkFNRT1kYlF1ZXJ5QWxsRGF0YWJhc2VzRmFjYWRlCgojIEBkZXNjcmlwdGlvbiB1c2VkIHRvIGV4ZWN1dGUgZ2l2ZW4gcXVlcnkgd2hlbiB1c2luZwojIGRiU2NyaXB0QWxsRGF0YWJhc2VzCiMgQGFyZyAkMSBkc246U3RyaW5nCiMgQGFyZyAkMiBkYjpTdHJpbmcKIyBAZW52IHF1ZXJ5IFN0cmluZwojIEBlbnYgb3B0aW9uU2VwYXJhdG9yIFN0cmluZwojIEByZXF1aXJlIExpbnV4OjpyZXF1aXJlRXhlY3V0ZWRBc1VzZXIKRGI6OnF1ZXJ5T25lRGF0YWJhc2UoKSB7CiAgIyBxdWVyeSBhbmQgb3B0aW9uU2VwYXJhdG9yIGFyZSBwYXNzZWQgdmlhIGV4cG9ydAogIGxvY2FsIGRzbj0iJDEiCiAgbG9jYWwgZGI9IiQyIgoKICBsb2NhbCAtQSBkYkluc3RhbmNlCiAgRGF0YWJhc2U6Om5ld0luc3RhbmNlIGRiSW5zdGFuY2UgIiR7ZHNufSIKICBEYXRhYmFzZTo6c2V0UXVlcnlPcHRpb25zIGRiSW5zdGFuY2UgIiR7ZGJJbnN0YW5jZVtRVUVSWV9PUFRJT05TXX0gLS1jb25uZWN0LXRpbWVvdXQ9NSIKCiAgIyBpZGVudGlmeSBjb2x1bW5zIGhlYWRlcgogIGVjaG8gLW4gIkBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAIgogIERhdGFiYXNlOjpza2lwQ29sdW1uTmFtZXMgZGJJbnN0YW5jZSAwCgogICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NAogIGlmICEgRGF0YWJhc2U6OnF1ZXJ5IGRiSW5zdGFuY2UgIiR7cXVlcnl9IiAiJHtkYn0iIHwgc2VkICJzL1x0LyR7b3B0aW9uU2VwYXJhdG9yfS9nIjsgdGhlbgogICAgTG9nOjpmYXRhbCAiZGF0YWJhc2UgJHtkYn0gZXJyb3IiIDE+JjIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBMb2cgbmFtZXNwYWNlIHByb3ZpZGVzIDIga2luZCBvZiBmdW5jdGlvbnMKIyAtIExvZzo6ZGlzcGxheSogYWxsb3dzIHRvIGRpc3BsYXkgZ2l2ZW4gbWVzc2FnZSB3aXRoCiMgICBnaXZlbiBkaXNwbGF5IGxldmVsCiMgLSBMb2c6OmxvZyogYWxsb3dzIHRvIGxvZyBnaXZlbiBtZXNzYWdlIHdpdGgKIyAgIGdpdmVuIGxvZyBsZXZlbAojIExvZzo6ZGlzcGxheSogZnVuY3Rpb25zIGF1dG9tYXRpY2FsbHkgbG9nIHRoZSBtZXNzYWdlIHRvbwojIEBzZWUgRW52OjpyZXF1aXJlTG9hZCB0byBsb2FkIHRoZSBkaXNwbGF5IGFuZCBsb2cgbGV2ZWwgZnJvbSAuZW52IGZpbGUKCiMgQGRlc2NyaXB0aW9uIGxvZyBsZXZlbCBvZmYKZXhwb3J0IF9fTEVWRUxfT0ZGPTAKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIGVycm9yCmV4cG9ydCBfX0xFVkVMX0VSUk9SPTEKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIHdhcm5pbmcKZXhwb3J0IF9fTEVWRUxfV0FSTklORz0yCiMgQGRlc2NyaXB0aW9uIGxvZyBsZXZlbCBpbmZvCmV4cG9ydCBfX0xFVkVMX0lORk89MwojIEBkZXNjcmlwdGlvbiBsb2cgbGV2ZWwgc3VjY2VzcwpleHBvcnQgX19MRVZFTF9TVUNDRVNTPTMKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIGRlYnVnCmV4cG9ydCBfX0xFVkVMX0RFQlVHPTQKCiMgQGRlc2NyaXB0aW9uIHZlcmJvc2UgbGV2ZWwgb2ZmCmV4cG9ydCBfX1ZFUkJPU0VfTEVWRUxfT0ZGPTAKIyBAZGVzY3JpcHRpb24gdmVyYm9zZSBsZXZlbCBpbmZvCmV4cG9ydCBfX1ZFUkJPU0VfTEVWRUxfSU5GTz0xCiMgQGRlc2NyaXB0aW9uIHZlcmJvc2UgbGV2ZWwgaW5mbwpleHBvcnQgX19WRVJCT1NFX0xFVkVMX0RFQlVHPTIKIyBAZGVzY3JpcHRpb24gdmVyYm9zZSBsZXZlbCBpbmZvCmV4cG9ydCBfX1ZFUkJPU0VfTEVWRUxfVFJBQ0U9MwoKIyBAZGVzY3JpcHRpb24gRGlzcGxheSBtZXNzYWdlIHVzaW5nIGRlYnVnIGNvbG9yIChncmV5KQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlEZWJ1ZygpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgPj0gX19MRVZFTF9ERUJVRykpOyB0aGVuCiAgICBlY2hvIC1lICIke19fREVCVUdfQ09MT1J9REVCVUcgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nRGVidWcgIiQxIgp9CgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgaW5mbyBjb2xvciAoYmcgbGlnaHQgYmx1ZS9mZyB3aGl0ZSkKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpkaXNwbGF5SW5mbygpIHsKICBsb2NhbCB0eXBlPSIkezI6LUlORk99IgogIGlmICgoQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTCA+PSBfX0xFVkVMX0lORk8pKTsgdGhlbgogICAgZWNobyAtZSAiJHtfX0lORk9fQ09MT1J9JHt0eXBlfSAgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nSW5mbyAiJDEiICIke3R5cGV9Igp9CgojIEBkZXNjcmlwdGlvbiBlbnN1cmUgQ09NTUFORF9CSU5fRElSIGVudiB2YXIgaXMgc2V0CiMgYW5kIFBBVEggY29ycmVjdGx5IHByZXBhcmVkCiMgQG5vYXJncwojIEBzZXQgQ09NTUFORF9CSU5fRElSIHN0cmluZyB0aGUgZGlyZWN0b3J5IHdoZXJlIHRvIGZpbmQgdGhpcyBjb21tYW5kCiMgQHNldCBQQVRIIHN0cmluZyBhZGQgZGlyZWN0b3J5IHdoZXJlIHRvIGZpbmQgdGhpcyBjb21tYW5kIGJpbmFyeQpDb21waWxlcjo6RmFjYWRlOjpyZXF1aXJlQ29tbWFuZEJpbkRpcigpIHsKICBDT01NQU5EX0JJTl9ESVI9IiR7Q1VSUkVOVF9ESVJ9IgogIEVudjo6cGF0aFByZXBlbmQgIiR7Q09NTUFORF9CSU5fRElSfSIKfQoKIyBAZGVzY3JpcHRpb24gY3JlYXRlIGEgbmV3IGRiIGluc3RhbmNlCiMgUmV0dXJucyBpbW1lZGlhdGVseSBpZiB0aGUgaW5zdGFuY2UgaXMgYWxyZWFkeSBpbml0aWFsaXplZAojCiMgQGFyZyAkMSBpbnN0YW5jZU5ld0luc3RhbmNlOiZNYXA8U3RyaW5nLFN0cmluZz4gKHBhc3NlZCBieSByZWZlcmVuY2UpIGRhdGFiYXNlIGluc3RhbmNlIHRvIHVzZQojIEBhcmcgJDIgZHNuOlN0cmluZyBkc24gcHJvZmlsZSAtIGxvYWQgdGhlIGRzbi5lbnYgcHJvZmlsZSBkZWR1Y2VkIHVzaW5nIHJ1bGVzIGRlZmluZWQgaW4gQ29uZjo6Z2V0QWJzb2x1dGVGaWxlCiMKIyBAZXhhbXBsZQojICAgZGVjbGFyZSAtQWd4IGRiSW5zdGFuY2UKIyAgIERhdGFiYXNlOjpuZXdJbnN0YW5jZSBkYkluc3RhbmNlICJkZWZhdWx0LmxvY2FsIgojCiMgQGV4aXRjb2RlIDEgaWYgZG5zIGZpbGUgbm90IGFibGUgdG8gbG9hZGVkCkRhdGFiYXNlOjpuZXdJbnN0YW5jZSgpIHsKICBsb2NhbCAtbiBpbnN0YW5jZU5ld0luc3RhbmNlPSQxCiAgbG9jYWwgZHNuPSIkMiIKICBsb2NhbCBEU05fRklMRQoKICBpZiBbWyAtdiBpbnN0YW5jZU5ld0luc3RhbmNlWydJTklUSUFMSVpFRCddICYmICIke2luc3RhbmNlTmV3SW5zdGFuY2VbJ0lOSVRJQUxJWkVEJ106LTB9IiA9PSAiMSIgXV07IHRoZW4KICAgIHJldHVybgogIGZpCgogICMgZmluYWwgYXV0aCBmaWxlIGdlbmVyYXRlZCBmcm9tIGRucyBmaWxlCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnQVVUSF9GSUxFJ109IiIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydEU05fRklMRSddPSIiCgogICMgY2hlY2sgZHNuIGZpbGUKICBEU05fRklMRT0iJChDb25mOjpnZXRBYnNvbHV0ZUZpbGUgImRzbiIgIiR7ZHNufSIgImVudiIpIiB8fCByZXR1cm4gMQogIERhdGFiYXNlOjpjaGVja0RzbkZpbGUgIiR7RFNOX0ZJTEV9IiB8fCByZXR1cm4gMQogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0RTTl9GSUxFJ109IiR7RFNOX0ZJTEV9IgoKICAjIHNoZWxsY2hlY2sgc291cmNlPS9zcmMvRGF0YWJhc2UvdGVzdHNEYXRhL2Rzbl92YWxpZC5lbnYKICBzb3VyY2UgIiR7aW5zdGFuY2VOZXdJbnN0YW5jZVsnRFNOX0ZJTEUnXX0iCgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1VTRVInXT0iJHtVU0VSfSIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydQQVNTV09SRCddPSIke1BBU1NXT1JEfSIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydIT1NUTkFNRSddPSIke0hPU1ROQU1FfSIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydQT1JUJ109IiR7UE9SVH0iCgogICMgZ2VuZXJhdGUgYXV0aEZpbGUgZm9yIGVhc3kgYXV0aGVudGljYXRpb24KICBpbnN0YW5jZU5ld0luc3RhbmNlWydBVVRIX0ZJTEUnXT0kKG1rdGVtcCAtcCAiJHtUTVBESVI6LS90bXB9IiAtdCAibXlzcWwuWFhYWFhYWFhYWFhYIikKICAoCiAgICBlY2hvICJbY2xpZW50XSIKICAgIGVjaG8gInVzZXIgPSAke1VTRVJ9IgogICAgZWNobyAicGFzc3dvcmQgPSAke1BBU1NXT1JEfSIKICAgIGVjaG8gImhvc3QgPSAke0hPU1ROQU1FfSIKICAgIGVjaG8gInBvcnQgPSAke1BPUlR9IgogICkgPiIke2luc3RhbmNlTmV3SW5zdGFuY2VbJ0FVVEhfRklMRSddfSIKCiAgIyBzb21lIG9mIHRob3NlIHZhbHVlcyBjYW4gYmUgb3ZlcnJpZGRlbiB1c2luZyB0aGUgZHNuIGZpbGUKICAjIFNLSVBfQ09MVU1OX05BTUVTIGVuYWJsZWQgYnkgZGVmYXVsdAogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1NLSVBfQ09MVU1OX05BTUVTJ109IiR7U0tJUF9DT0xVTU5fTkFNRVM6LTF9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1NTTF9PUFRJT05TJ109IiR7TVlTUUxfU1NMX09QVElPTlM6LS0tc3NsLW1vZGU9RElTQUJMRUR9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1FVRVJZX09QVElPTlMnXT0iJHtNWVNRTF9RVUVSWV9PUFRJT05TOi0tLWJhdGNoIC0tcmF3IC0tZGVmYXVsdC1jaGFyYWN0ZXItc2V0PXV0Zjh9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0RVTVBfT1BUSU9OUyddPSIke01ZU1FMX0RVTVBfT1BUSU9OUzotLS1kZWZhdWx0LWNoYXJhY3Rlci1zZXQ9dXRmOCAtLWNvbXByZXNzIC0taGV4LWJsb2IgLS1yb3V0aW5lcyAtLXRyaWdnZXJzIC0tc2luZ2xlLXRyYW5zYWN0aW9uIC0tc2V0LWd0aWQtcHVyZ2VkPU9GRiAtLWNvbHVtbi1zdGF0aXN0aWNzPTAgJHtpbnN0YW5jZU5ld0luc3RhbmNlWydTU0xfT1BUSU9OUyddfX0iCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnREJfSU1QT1JUX09QVElPTlMnXT0iJHtEQl9JTVBPUlRfT1BUSU9OUzotLS1jb25uZWN0LXRpbWVvdXQ9NSAtLWJhdGNoIC0tcmF3IC0tZGVmYXVsdC1jaGFyYWN0ZXItc2V0PXV0Zjh9IgoKICBpbnN0YW5jZU5ld0luc3RhbmNlWydJTklUSUFMSVpFRCddPTEKfQoKIyBAZGVzY3JpcHRpb24gbXlzcWwgcXVlcnkgb24gYSBnaXZlbiBkYgojIEB3YXJuaW5nIGNvdWxkIHVzZSBRVUVSWV9PUFRJT05TIHZhcmlhYmxlIGZyb20gZHNuIGlmIGRlZmluZWQKIyBAZXhhbXBsZQojICAgY2F0IGZpbGUuc3FsIHwgRGF0YWJhc2U6OnF1ZXJ5IC4uLgojIEBhcmcgJDEgaW5zdGFuY2VRdWVyeTomTWFwPFN0cmluZyxTdHJpbmc+IChwYXNzZWQgYnkgcmVmZXJlbmNlKSBkYXRhYmFzZSBpbnN0YW5jZSB0byB1c2UKIyBAYXJnICQyIHNxbFF1ZXJ5OlN0cmluZyAob3B0aW9uYWwpIHNxbCBxdWVyeSBvciBzcWwgZmlsZSB0byBleGVjdXRlLiBpZiBub3QgcHJvdmlkZWQgb3IgZW1wdHksIHRoZSBjb21tYW5kIGNhbiBiZSBwaXBlZAojIEBhcmcgJDMgZGJOYW1lOlN0cmluZyAob3B0aW9uYWwpIHRoZSBkYiBuYW1lCiMKIyBAZXhpdGNvZGUgbXlzcWwgY29tbWFuZCBzdGF0dXMgY29kZQpEYXRhYmFzZTo6cXVlcnkoKSB7CiAgbG9jYWwgLW4gaW5zdGFuY2VRdWVyeT0kMQogIGxvY2FsIC1hIG15c3FsQ29tbWFuZD0oKQogIGxvY2FsIC1hIHF1ZXJ5T3B0aW9ucwoKICBteXNxbENvbW1hbmQrPShteXNxbCkKICBteXNxbENvbW1hbmQrPSgiLS1kZWZhdWx0cy1leHRyYS1maWxlPSR7aW5zdGFuY2VRdWVyeVsnQVVUSF9GSUxFJ119IikKICBJRlM9JyAnIHJlYWQgLXIgLWEgcXVlcnlPcHRpb25zIDw8PCIke2luc3RhbmNlUXVlcnlbJ1FVRVJZX09QVElPTlMnXX0iCiAgbXlzcWxDb21tYW5kKz0oIiR7cXVlcnlPcHRpb25zW0BdfSIpCiAgaWYgW1sgIiR7aW5zdGFuY2VRdWVyeVsnU0tJUF9DT0xVTU5fTkFNRVMnXX0iID0gIjEiIF1dOyB0aGVuCiAgICBteXNxbENvbW1hbmQrPSgiLXMiICItLXNraXAtY29sdW1uLW5hbWVzIikKICBmaQogICMgYWRkIG9wdGlvbmFsIGRiIG5hbWUKICBpZiBbWyAtbiAiJHszK3h9IiBdXTsgdGhlbgogICAgbXlzcWxDb21tYW5kKz0oIiQzIikKICBmaQogICMgYWRkIG9wdGlvbmFsIHNxbCBxdWVyeQogIGlmIFtbIC1uICIkezIreH0iICYmIC1uICIkMiIgJiYgISAtZiAiJDIiIF1dOyB0aGVuCiAgICBteXNxbENvbW1hbmQrPSgiLWUiKQogICAgbXlzcWxDb21tYW5kKz0oIiQyIikKICBmaQogIExvZzo6ZGlzcGxheURlYnVnICIkKHByaW50ZiAiZXhlY3V0ZSBjb21tYW5kOiAnJXMnIiAiJHtteXNxbENvbW1hbmRbKl19IikiCgogIGlmIFtbIC1mICIkMiIgXV07IHRoZW4KICAgICIke215c3FsQ29tbWFuZFtAXX0iIDwiJDIiCiAgZWxzZQogICAgIiR7bXlzcWxDb21tYW5kW0BdfSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBzZXQgdGhlIGdlbmVyYWwgb3B0aW9ucyB0byB1c2Ugb24gbXlzcWwgY29tbWFuZCB0byBxdWVyeSB0aGUgZGF0YWJhc2UKIyBEaWZmZXJzIHRoYW4gc2V0T3B0aW9ucyBpbiB0aGUgd2F5IHRoYXQgdGhlc2Ugb3B0aW9ucyBjb3VsZCBjaGFuZ2UgZWFjaCB0aW1lCiMKIyBAYXJnICQxIGluc3RhbmNlU2V0UXVlcnlPcHRpb25zOiZNYXA8U3RyaW5nLFN0cmluZz4gKHBhc3NlZCBieSByZWZlcmVuY2UpIGRhdGFiYXNlIGluc3RhbmNlIHRvIHVzZQojIEBhcmcgJDIgb3B0aW9uc0xpc3Q6U3RyaW5nIHF1ZXJ5IG9wdGlvbnMgbGlzdApEYXRhYmFzZTo6c2V0UXVlcnlPcHRpb25zKCkgewogIGxvY2FsIC1uIGluc3RhbmNlU2V0UXVlcnlPcHRpb25zPSQxCiAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CiAgaW5zdGFuY2VTZXRRdWVyeU9wdGlvbnNbJ1FVRVJZX09QVElPTlMnXT0iJDIiCn0KCiMgQGRlc2NyaXB0aW9uIGJ5IGRlZmF1bHQgd2Ugc2tpcCB0aGUgY29sdW1uIG5hbWVzCiMgYnV0IHNvbWV0aW1lcyB3ZSBuZWVkIGNvbHVtbiBuYW1lcyB0byBkaXNwbGF5IHNvbWUgcmVzdWx0cwojIGRpc2FibGUgdGhpcyBvcHRpb24gdGVtcG9yYXJpbHkgYW5kIHRoZW4gcmVzdG9yZSBpdCB0byB0cnVlCiMKIyBAYXJnICQxIGluc3RhbmNlU2V0UXVlcnlPcHRpb25zOiZNYXA8U3RyaW5nLFN0cmluZz4gKHBhc3NlZCBieSByZWZlcmVuY2UpIGRhdGFiYXNlIGluc3RhbmNlIHRvIHVzZQojIEBhcmcgJDIgc2tpcENvbHVtbk5hbWVzOkJvb2xlYW4gMCB0byBkaXNhYmxlLCAxIHRvIGVuYWJsZSAoaGlkZSBjb2x1bW4gbmFtZXMpCkRhdGFiYXNlOjpza2lwQ29sdW1uTmFtZXMoKSB7CiAgbG9jYWwgLW4gaW5zdGFuY2VTa2lwQ29sdW1uTmFtZXM9JDEKICAjIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKICBpbnN0YW5jZVNraXBDb2x1bW5OYW1lc1snU0tJUF9DT0xVTU5fTkFNRVMnXT0iJDIiCn0KCiMgQGRlc2NyaXB0aW9uIHByZXBlbmQgZGlyZWN0b3JpZXMgdG8gdGhlIFBBVEggZW52aXJvbm1lbnQgdmFyaWFibGUKIyBAYXJnICRAIGFyZ3M6U3RyaW5nW10gbGlzdCBvZiBkaXJlY3RvcmllcyB0byBwcmVwZW5kCiMgQHNldCBQQVRIIHVwZGF0ZSBQQVRIIHdpdGggdGhlIGRpcmVjdG9yaWVzIHByZXBlbmRlZApFbnY6OnBhdGhQcmVwZW5kKCkgewogIGxvY2FsIGFyZwogIGZvciBhcmcgaW4gIiRAIjsgZG8KICAgIGlmIFtbIC1kICIke2FyZ30iICYmICI6JHtQQVRIfToiICE9ICoiOiR7YXJnfToiKiBdXTsgdGhlbgogICAgICBQQVRIPSIkKHJlYWxwYXRoICIke2FyZ30iKToke1BBVEh9IgogICAgZmkKICBkb25lCn0KCiMgQGRlc2NyaXB0aW9uIERpc3BsYXkgbWVzc2FnZSB1c2luZyBlcnJvciBjb2xvciAocmVkKSBhbmQgZXhpdCBpbW1lZGlhdGVseSB3aXRoIGVycm9yIHN0YXR1cyAxCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6ZmF0YWwoKSB7CiAgZWNobyAtZSAiJHtfX0VSUk9SX0NPTE9SfUZBVEFMICAgLSAkezF9JHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgTG9nOjpsb2dGYXRhbCAiJDEiCiAgZXhpdCAxCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dEZWJ1ZygpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+PSBfX0xFVkVMX0RFQlVHKSk7IHRoZW4KICAgIExvZzo6bG9nTWVzc2FnZSAiJHsyOi1ERUJVR30iICIkMSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBsb2cgbWVzc2FnZSB0byBmaWxlCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6bG9nSW5mbygpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+PSBfX0xFVkVMX0lORk8pKTsgdGhlbgogICAgTG9nOjpsb2dNZXNzYWdlICIkezI6LUlORk99IiAiJDEiCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gZW5zdXJlIHJ1bm5pbmcgdXNlciBpcyBub3Qgcm9vdAojIEBleGl0Y29kZSAxIGlmIGN1cnJlbnQgdXNlciBpcyByb290CiMgQHN0ZGVyciBkaWFnbm9zdGljcyBpbmZvcm1hdGlvbiBpcyBkaXNwbGF5ZWQKTGludXg6OnJlcXVpcmVFeGVjdXRlZEFzVXNlcigpIHsKICBpZiBbWyAiJChpZCAtdSkiID0gIjAiIF1dOyB0aGVuCiAgICBMb2c6OmZhdGFsICJ0aGlzIHNjcmlwdCBzaG91bGQgYmUgZXhlY3V0ZWQgYXMgbm9ybWFsIHVzZXIiCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gZ2V0IGFic29sdXRlIGNvbmYgZmlsZSBmcm9tIHNwZWNpZmllZCBjb25mIGZvbGRlciBkZWR1Y2VkIHVzaW5nIHRoZXNlIHJ1bGVzCiMgICAqIGZyb20gYWJzb2x1dGUgZmlsZSAoaWdub3JlcyA8Y29uZkZvbGRlcj4gYW5kIDxleHRlbnNpb24+KQojICAgKiByZWxhdGl2ZSB0byB3aGVyZSBzY3JpcHQgaXMgZXhlY3V0ZWQgKGlnbm9yZXMgPGNvbmZGb2xkZXI+IGFuZCA8ZXh0ZW5zaW9uPikKIyAgICogZnJvbSBob21lLy5iYXNoLXRvb2xzLzxjb25mRm9sZGVyPgojICAgKiBmcm9tIGZyYW1ld29yayBjb25mLzxjb25mRm9sZGVyPgojCiMgQGFyZyAkMSBjb25mRm9sZGVyOlN0cmluZyB0aGUgZGlyZWN0b3J5IG5hbWUgKG5vdCB0aGUgcGF0aCkgdG8gbGlzdAojIEBhcmcgJDIgY29uZjpTdHJpbmcgZmlsZSB0byB1c2Ugd2l0aG91dCBleHRlbnNpb24KIyBAYXJnICQzIGV4dGVuc2lvbjpTdHJpbmcgdGhlIGV4dGVuc2lvbiAoLnNoIGJ5IGRlZmF1bHQpCiMKIyBAc3Rkb3V0IGFic29sdXRlIGNvbmYgZmlsZW5hbWUKIyBAZXhpdGNvZGUgMSBpZiBmaWxlIGlzIG5vdCBmb3VuZCBpbiBhbnkgbG9jYXRpb24KQ29uZjo6Z2V0QWJzb2x1dGVGaWxlKCkgewogIGxvY2FsIGNvbmZGb2xkZXI9IiQxIgogIGxvY2FsIGNvbmY9IiQyIgogIGxvY2FsIGV4dGVuc2lvbj0iJHszLS5zaH0iCiAgaWYgW1sgLW4gIiR7ZXh0ZW5zaW9ufSIgJiYgIiR7ZXh0ZW5zaW9uOjA6MX0iICE9ICIuIiBdXTsgdGhlbgogICAgZXh0ZW5zaW9uPSIuJHtleHRlbnNpb259IgogIGZpCgogIHRlc3RBYnMoKSB7CiAgICBsb2NhbCByZXN1bHQKICAgIHJlc3VsdD0iJChyZWFscGF0aCAtZSAiJDEiIDI+L2Rldi9udWxsKSIKICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE4MQogICAgaWYgW1sgIiQ/IiA9ICIwIiAmJiAtZiAiJHtyZXN1bHR9IiBdXTsgdGhlbgogICAgICBlY2hvICIke3Jlc3VsdH0iCiAgICAgIHJldHVybiAwCiAgICBmaQogICAgcmV0dXJuIDEKICB9CgogICMgY29uZiBpcyBhYnNvbHV0ZSBmaWxlIChpbmNsdWRpbmcgZXh0ZW5zaW9uKQogIHRlc3RBYnMgIiR7Y29uZkZvbGRlcn0ke2V4dGVuc2lvbn0iICYmIHJldHVybiAwCiAgIyBjb25mIGlzIGFic29sdXRlIGZpbGUKICB0ZXN0QWJzICIke2NvbmZGb2xkZXJ9IiAmJiByZXR1cm4gMAogICMgY29uZiBpcyBhYnNvbHV0ZSBmaWxlIChpbmNsdWRpbmcgZXh0ZW5zaW9uKQogIHRlc3RBYnMgIiR7Y29uZn0ke2V4dGVuc2lvbn0iICYmIHJldHVybiAwCiAgIyBjb25mIGlzIGFic29sdXRlIGZpbGUKICB0ZXN0QWJzICIke2NvbmZ9IiAmJiByZXR1cm4gMAoKICAjIHJlbGF0aXZlIHRvIHdoZXJlIHNjcmlwdCBpcyBleGVjdXRlZCAoaW5jbHVkaW5nIGV4dGVuc2lvbikKICBpZiBbWyAtbiAiJHtDVVJSRU5UX0RJUit4eHh9IiBdXTsgdGhlbgogICAgdGVzdEFicyAiJChGaWxlOjpjb25jYXRlbmF0ZVBhdGggIiR7Q1VSUkVOVF9ESVJ9IiAiJHtjb25mRm9sZGVyfSIpLyR7Y29uZn0ke2V4dGVuc2lvbn0iICYmIHJldHVybiAwCiAgZmkKICAjIGZyb20gaG9tZS8uYmFzaC10b29scy88Y29uZkZvbGRlcj4KICB0ZXN0QWJzICIkKEZpbGU6OmNvbmNhdGVuYXRlUGF0aCAiJHtIT01FfS8uYmFzaC10b29scyIgIiR7Y29uZkZvbGRlcn0iKS8ke2NvbmZ9JHtleHRlbnNpb259IiAmJiByZXR1cm4gMAoKICBpZiBbWyAtbiAiJHtGUkFNRVdPUktfUk9PVF9ESVIreHh4fSIgXV07IHRoZW4KICAgICMgZnJvbSBmcmFtZXdvcmsgY29uZi88Y29uZkZvbGRlcj4gKGluY2x1ZGluZyBleHRlbnNpb24pCiAgICB0ZXN0QWJzICIkKEZpbGU6OmNvbmNhdGVuYXRlUGF0aCAiJHtGUkFNRVdPUktfUk9PVF9ESVJ9L2NvbmYiICIke2NvbmZGb2xkZXJ9IikvJHtjb25mfSR7ZXh0ZW5zaW9ufSIgJiYgcmV0dXJuIDAKCiAgICAjIGZyb20gZnJhbWV3b3JrIGNvbmYvPGNvbmZGb2xkZXI+CiAgICB0ZXN0QWJzICIkKEZpbGU6OmNvbmNhdGVuYXRlUGF0aCAiJHtGUkFNRVdPUktfUk9PVF9ESVJ9L2NvbmYiICIke2NvbmZGb2xkZXJ9IikvJHtjb25mfSIgJiYgcmV0dXJuIDAKICBmaQoKICAjIGZpbGUgbm90IGZvdW5kCiAgTG9nOjpkaXNwbGF5RXJyb3IgImNvbmYgZmlsZSAnJHtjb25mfScgbm90IGZvdW5kIgoKICByZXR1cm4gMQp9CgojIEBkZXNjcmlwdGlvbiBjaGVjayBpZiBkc24gZmlsZSBoYXMgYWxsIHRoZSBtYW5kYXRvcnkgdmFyaWFibGVzIHNldAojIE1hbmRhdG9yeSB2YXJpYWJsZXMgYXJlOiBIT1NUTkFNRSwgVVNFUiwgUEFTU1dPUkQsIFBPUlQKIwojIEBhcmcgJDEgZHNuRmlsZU5hbWU6U3RyaW5nIGRzbiBhYnNvbHV0ZSBmaWxlbmFtZQojIEBzZXQgSE9TVE5BTUUgbG9hZGVkIGZyb20gZHNuIGZpbGUKIyBAc2V0IFBPUlQgbG9hZGVkIGZyb20gZHNuIGZpbGUKIyBAc2V0IFVTRVIgbG9hZGVkIGZyb20gZHNuIGZpbGUKIyBAc2V0IFBBU1NXT1JEIGxvYWRlZCBmcm9tIGRzbiBmaWxlCiMgQGV4aXRjb2RlIDAgb24gdmFsaWQgZmlsZQojIEBleGl0Y29kZSAxIGlmIG9uZSBvZiB0aGUgcHJvcGVydGllcyBvZiB0aGUgY29uZiBmaWxlIGlzIGludmFsaWQgb3IgaWYgZmlsZSBub3QgZm91bmQKIyBAc3RkZXJyIGxvZyBvdXRwdXQgaWYgZXJyb3IgZm91bmQgaW4gY29uZiBmaWxlCkRhdGFiYXNlOjpjaGVja0RzbkZpbGUoKSB7CiAgbG9jYWwgZHNuRmlsZU5hbWU9IiQxIgogIGlmIFtbICEgLWYgIiR7ZHNuRmlsZU5hbWV9IiBdXTsgdGhlbgogICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IG5vdCBmb3VuZCIKICAgIHJldHVybiAxCiAgZmkKCiAgKAogICAgdW5zZXQgSE9TVE5BTUUgUE9SVCBQQVNTV09SRCBVU0VSCiAgICAjIHNoZWxsY2hlY2sgc291cmNlPS9zcmMvRGF0YWJhc2UvdGVzdHNEYXRhL2Rzbl92YWxpZC5lbnYKICAgIHNvdXJjZSAiJHtkc25GaWxlTmFtZX0iCiAgICBpZiBbWyAteiAke0hPU1ROQU1FK3h9IF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheUVycm9yICJkc24gZmlsZSAke2RzbkZpbGVOYW1lfSA6IEhPU1ROQU1FIG5vdCBwcm92aWRlZCIKICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiBbWyAteiAiJHtIT1NUTkFNRX0iIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheVdhcm5pbmcgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogSE9TVE5BTUUgdmFsdWUgbm90IHByb3ZpZGVkIgogICAgZmkKICAgIGlmIFtbICIke0hPU1ROQU1FfSIgPSAibG9jYWxob3N0IiBdXTsgdGhlbgogICAgICBMb2c6OmRpc3BsYXlXYXJuaW5nICJkc24gZmlsZSAke2RzbkZpbGVOYW1lfSA6IGNoZWNrIHRoYXQgSE9TVE5BTUUgc2hvdWxkIG5vdCBiZSAxMjcuMC4wLjEgaW5zdGVhZCBvZiBsb2NhbGhvc3QiCiAgICBmaQogICAgaWYgW1sgLXogIiR7UE9SVCt4fSIgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogUE9SVCBub3QgcHJvdmlkZWQiCiAgICAgIHJldHVybiAxCiAgICBmaQogICAgaWYgISBbWyAke1BPUlR9ID1+IF5bMC05XSskIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheUVycm9yICJkc24gZmlsZSAke2RzbkZpbGVOYW1lfSA6IFBPUlQgaW52YWxpZCIKICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiBbWyAteiAiJHtVU0VSK3h9IiBdXTsgdGhlbgogICAgICBMb2c6OmRpc3BsYXlFcnJvciAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gOiBVU0VSIG5vdCBwcm92aWRlZCIKICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiBbWyAteiAiJHtQQVNTV09SRCt4fSIgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogUEFTU1dPUkQgbm90IHByb3ZpZGVkIgogICAgICByZXR1cm4gMQogICAgZmkKICApCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dGYXRhbCgpIHsKICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotRkFUQUx9IiAiJDEiCn0KCiMgQGRlc2NyaXB0aW9uIEludGVybmFsOiBjb21tb24gbG9nIG1lc3NhZ2UKIyBAZXhhbXBsZSB0ZXh0CiMgICBbZGF0ZV18W2xldmVsTXNnXXxtZXNzYWdlCiMKIyBAZXhhbXBsZSB0ZXh0CiMgICAyMDIwLTAxLTE5IDE5OjIwOjIxfEVSUk9SICB8bG9nIGVycm9yCiMgICAyMDIwLTAxLTE5IDE5OjIwOjIxfFNLSVBQRUR8bG9nIHNraXBwZWQKIwojIEBhcmcgJDEgbGV2ZWxNc2c6U3RyaW5nIG1lc3NhZ2UncyBsZXZlbCBkZXNjcmlwdGlvbiAoZWc6IFNUQVRVUywgRVJST1IsIC4uLikKIyBAYXJnICQyIG1zZzpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQojIEBlbnYgQkFTSF9GUkFNRVdPUktfTE9HX0ZJTEUgU3RyaW5nIGxvZyBmaWxlIHRvIHVzZSwgZG8gbm90aGluZyBpZiBlbXB0eQojIEBlbnYgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMIGludCBsb2cgbGV2ZWwgbG9nIG9ubHkgaWYgPiBPRkYgb3IgZmF0YWwgbWVzc2FnZXMKIyBAc3RkZXJyIGRpYWdub3N0aWNzIGluZm9ybWF0aW9uIGlzIGRpc3BsYXllZAojIEByZXF1aXJlIEVudjo6cmVxdWlyZUxvYWQKIyBAcmVxdWlyZSBMb2c6OnJlcXVpcmVMb2FkCkxvZzo6bG9nTWVzc2FnZSgpIHsKICBsb2NhbCBsZXZlbE1zZz0iJDEiCiAgbG9jYWwgbXNnPSIkMiIKICBsb2NhbCBkYXRlCgogIGlmIFtbIC1uICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIgXV0gJiYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPiBfX0xFVkVMX09GRikpOyB0aGVuCiAgICBkYXRlPSIkKGRhdGUgJyslWS0lbS0lZCAlSDolTTolUycpIgogICAgdG91Y2ggIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IgogICAgcHJpbnRmICIlc3wlN3N8JXNcbiIgIiR7ZGF0ZX0iICIke2xldmVsTXNnfSIgIiR7bXNnfSIgPj4iJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gY29uY2F0ZW5hdGUgMiBwYXRocyBhbmQgZW5zdXJlIHRoZSBwYXRoIGlzIGNvcnJlY3QgdXNpbmcgcmVhbHBhdGggLW0KIyBAYXJnICQxIGJhc2VQYXRoOlN0cmluZwojIEBhcmcgJDIgc3ViUGF0aDpTdHJpbmcKIyBAcmVxdWlyZSBMaW51eDo6cmVxdWlyZVJlYWxwYXRoQ29tbWFuZApGaWxlOjpjb25jYXRlbmF0ZVBhdGgoKSB7CiAgbG9jYWwgYmFzZVBhdGg9IiQxIgogIGxvY2FsIHN1YlBhdGg9IiQyIgogIGxvY2FsIGZ1bGxQYXRoPSIke2Jhc2VQYXRoOiske2Jhc2VQYXRofS99JHtzdWJQYXRofSIKCiAgcmVhbHBhdGggLW0gIiR7ZnVsbFBhdGh9IiAyPi9kZXYvbnVsbAp9CgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgZXJyb3IgY29sb3IgKHJlZCkKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpkaXNwbGF5RXJyb3IoKSB7CiAgaWYgKChCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMID49IF9fTEVWRUxfRVJST1IpKTsgdGhlbgogICAgZWNobyAtZSAiJHtfX0VSUk9SX0NPTE9SfUVSUk9SICAgLSAkezF9JHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgZmkKICBMb2c6OmxvZ0Vycm9yICIkMSIKfQoKIyBAZGVzY3JpcHRpb24gRGlzcGxheSBtZXNzYWdlIHVzaW5nIHdhcm5pbmcgY29sb3IgKHllbGxvdykKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpkaXNwbGF5V2FybmluZygpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgPj0gX19MRVZFTF9XQVJOSU5HKSk7IHRoZW4KICAgIGVjaG8gLWUgIiR7X19XQVJOSU5HX0NPTE9SfVdBUk4gICAgLSAkezF9JHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgZmkKICBMb2c6OmxvZ1dhcm5pbmcgIiQxIgp9CgojIEBkZXNjcmlwdGlvbiBlbnN1cmUgZW52IGZpbGVzIGFyZSBsb2FkZWQKIyBAYXJnICRAIGxpc3Qgb2YgZGVmYXVsdCBmaWxlcyB0byBsb2FkIGF0IHRoZSBlbmQKIyBAZXhpdGNvZGUgMSBpZiBvbmUgb2YgZW52IGZpbGVzIGZhaWxzIHRvIGxvYWQKIyBAc3RkZXJyIGRpYWdub3N0aWNzIGluZm9ybWF0aW9uIGlzIGRpc3BsYXllZAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIxMjAKRW52OjpyZXF1aXJlTG9hZCgpIHsKICBsb2NhbCAtYSBkZWZhdWx0RmlsZXM9KCIkQCIpCiAgIyBnZXQgbGlzdCBvZiBwb3NzaWJsZSBjb25maWcgZmlsZXMKICBsb2NhbCAtYSBjb25maWdGaWxlcz0oKQogIGlmIFtbIC1uICIke0JBU0hfRlJBTUVXT1JLX0VOVl9GSUxFU1swXSsxfSIgXV07IHRoZW4KICAgICMgQkFTSF9GUkFNRVdPUktfRU5WX0ZJTEVTIGlzIGFuIGFycmF5CiAgICBjb25maWdGaWxlcys9KCIke0JBU0hfRlJBTUVXT1JLX0VOVl9GSUxFU1tAXX0iKQogIGZpCiAgaWYgW1sgLWYgIiQocHdkKS8uZnJhbWV3b3JrLWNvbmZpZyIgXV07IHRoZW4KICAgIGNvbmZpZ0ZpbGVzKz0oIiQocHdkKS8uZnJhbWV3b3JrLWNvbmZpZyIpCiAgZmkKICBpZiBbWyAtZiAiJHtGUkFNRVdPUktfUk9PVF9ESVJ9Ly5mcmFtZXdvcmstY29uZmlnIiBdXTsgdGhlbgogICAgY29uZmlnRmlsZXMrPSgiJHtGUkFNRVdPUktfUk9PVF9ESVJ9Ly5mcmFtZXdvcmstY29uZmlnIikKICBmaQogIGlmIFtbIC1uICIke29wdGlvbkJhc2hGcmFtZXdvcmtDb25maWd9IiAmJiAtZiAiJHtvcHRpb25CYXNoRnJhbWV3b3JrQ29uZmlnfSIgXV07IHRoZW4KICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNAogICAgY29uZmlnRmlsZXMrPSgiJHtvcHRpb25CYXNoRnJhbWV3b3JrQ29uZmlnfSIpCiAgZmkKICBjb25maWdGaWxlcys9KCIke29wdGlvbkVudkZpbGVzW0BdfSIpCiAgY29uZmlnRmlsZXMrPSgiJHtkZWZhdWx0RmlsZXNbQF19IikKCiAgZm9yIGZpbGUgaW4gIiR7Y29uZmlnRmlsZXNbQF19IjsgZG8KICAgICMgc2hlbGxjaGVjayBzb3VyY2U9Ly5mcmFtZXdvcmstY29uZmlnCiAgICBDVVJSRU5UX0xPQURFRF9FTlZfRklMRT0iJHtmaWxlfSIgc291cmNlICIke2ZpbGV9IiB8fCB7CiAgICAgIExvZzo6ZGlzcGxheUVycm9yICJ3aGlsZSBsb2FkaW5nIGNvbmZpZyBmaWxlOiAke2ZpbGV9IgogICAgICByZXR1cm4gMQogICAgfQogIGRvbmUKfQoKIyBAZGVzY3JpcHRpb24gYWN0aXZhdGUgb3Igbm90IExvZzo6ZGlzcGxheSogYW5kIExvZzo6bG9nKiBmdW5jdGlvbnMKIyBiYXNlZCBvbiBCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMIGFuZCBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwKIyBlbnZpcm9ubWVudCB2YXJpYWJsZXMgbG9hZGVkIGJ5IEVudjo6cmVxdWlyZUxvYWQKIyB0cnkgdG8gY3JlYXRlIGxvZyBmaWxlIGFuZCByb3RhdGUgaXQgaWYgbmVjZXNzYXJ5CiMgQG5vYXJncwojIEBzZXQgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMIGludCB0byBPRkYgbGV2ZWwgaWYgQkFTSF9GUkFNRVdPUktfTE9HX0ZJTEUgaXMgZW1wdHkgb3Igbm90IHdyaXRhYmxlCiMgQGVudiBCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMIGludAojIEBlbnYgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMIGludAojIEBlbnYgQkFTSF9GUkFNRVdPUktfTE9HX0ZJTEUgU3RyaW5nCiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfRklMRV9NQVhfUk9UQVRJT04gaW50IGRvIGxvZyByb3RhdGlvbiBpZiA+IDAKIyBAZXhpdGNvZGUgMCBhbHdheXMgc3VjY2Vzc2Z1bAojIEBzdGRlcnIgZGlhZ25vc3RpY3MgaW5mb3JtYXRpb24gYWJvdXQgbG9nIGZpbGUgaXMgZGlzcGxheWVkCiMgQHJlcXVpcmUgRW52OjpyZXF1aXJlTG9hZAojIEByZXF1aXJlIFVJOjpyZXF1aXJlVGhlbWUKTG9nOjpyZXF1aXJlTG9hZCgpIHsKICBpZiBbWyAteiAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRTotfSIgXV07IHRoZW4KICAgIEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTD0ke19fTEVWRUxfT0ZGfQogICAgZXhwb3J0IEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTAogIGZpCgogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID4gX19MRVZFTF9PRkYpKTsgdGhlbgogICAgaWYgW1sgISAtZiAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iIF1dOyB0aGVuCiAgICAgIGlmCiAgICAgICAgISBta2RpciAtcCAiJChkaXJuYW1lICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIpIiAyPi9kZXYvbnVsbCB8fAogICAgICAgICAgISB0b3VjaCAtLW5vLWNyZWF0ZSAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iIDI+L2Rldi9udWxsCiAgICAgIHRoZW4KICAgICAgICBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtfX0xFVkVMX09GRn0KICAgICAgICBlY2hvIC1lICIke19fRVJST1JfQ09MT1J9RVJST1IgICAtIEZpbGUgJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0gaXMgbm90IHdyaXRhYmxlJHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgICAgIGZpCiAgICBlbGlmIFtbICEgLXcgIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IiBdXTsgdGhlbgogICAgICBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtfX0xFVkVMX09GRn0KICAgICAgZWNobyAtZSAiJHtfX0VSUk9SX0NPTE9SfUVSUk9SICAgLSBGaWxlICR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IGlzIG5vdCB3cml0YWJsZSR7X19SRVNFVF9DT0xPUn0iID4mMgogICAgZmkKCiAgZmkKCiAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPiBfX0xFVkVMX09GRikpOyB0aGVuCiAgICAjIHdpbGwgYWx3YXlzIGJlIGNyZWF0ZWQgZXZlbiBpZiBub3QgaW4gaW5mbyBsZXZlbAogICAgTG9nOjpsb2dNZXNzYWdlICJJTkZPIiAiTG9nZ2luZyB0byBmaWxlICR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IC0gTG9nIGxldmVsICR7QkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMfSIKICAgIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0ZJTEVfTUFYX1JPVEFUSU9OID4gMCkpOyB0aGVuCiAgICAgIExvZzo6cm90YXRlICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIgIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEVfTUFYX1JPVEFUSU9OfSIKICAgIGZpCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gbG9nIG1lc3NhZ2UgdG8gZmlsZQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmxvZ0Vycm9yKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfRVJST1IpKTsgdGhlbgogICAgTG9nOjpsb2dNZXNzYWdlICIkezI6LUVSUk9SfSIgIiQxIgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dXYXJuaW5nKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfV0FSTklORykpOyB0aGVuCiAgICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotV0FSTklOR30iICIkMSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBUbyBiZSBjYWxsZWQgYmVmb3JlIGxvZ2dpbmcgaW4gdGhlIGxvZyBmaWxlCiMgQGFyZyAkMSBmaWxlOnN0cmluZyBsb2cgZmlsZSBuYW1lCiMgQGFyZyAkMiBtYXhMb2dGaWxlc0NvdW50OmludCBtYXhpbXVtIG51bWJlciBvZiBsb2cgZmlsZXMKTG9nOjpyb3RhdGUoKSB7CiAgbG9jYWwgZmlsZT0iJDEiCiAgbG9jYWwgbWF4TG9nRmlsZXNDb3VudD0iJHsyOi01fSIKCiAgaWYgW1sgISAtZiAiJHtmaWxlfSIgXV07IHRoZW4KICAgIExvZzo6ZGlzcGxheVNraXBwZWQgIkxvZyBmaWxlICR7ZmlsZX0gZG9lc24ndCBleGlzdCB5ZXQiCiAgICByZXR1cm4gMAogIGZpCiAgZm9yIGkgaW4gJChzZXEgJCgobWF4TG9nRmlsZXNDb3VudCAtIDEpKSAtMSAxKTsgZG8KICAgIExvZzo6ZGlzcGxheUluZm8gIkxvZyByb3RhdGlvbiAke2ZpbGV9LiR7aX0gdG8gJHtmaWxlfS4kKChpICsgMSkpIgogICAgbXYgIiR7ZmlsZX0uInsiJHtpfSIsIiQoKGkgKyAxKSkifSAmPi9kZXYvbnVsbCB8fCB0cnVlCiAgZG9uZQogIGlmIGNwICIke2ZpbGV9IiAiJHtmaWxlfS4xIiAmPi9kZXYvbnVsbDsgdGhlbgogICAgZWNobyA+IiR7ZmlsZX0iICMgcmVzZXQgbG9nIGZpbGUKICAgIExvZzo6ZGlzcGxheUluZm8gIkxvZyByb3RhdGlvbiAke2ZpbGV9IHRvICR7ZmlsZX0uMSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBlbnN1cmUgY29tbWFuZCByZWFscGF0aCBpcyBhdmFpbGFibGUKIyBAZXhpdGNvZGUgMSBpZiByZWFscGF0aCBjb21tYW5kIG5vdCBhdmFpbGFibGUKIyBAc3RkZXJyIGRpYWdub3N0aWNzIGluZm9ybWF0aW9uIGlzIGRpc3BsYXllZApMaW51eDo6cmVxdWlyZVJlYWxwYXRoQ29tbWFuZCgpIHsKICBBc3NlcnQ6OmNvbW1hbmRFeGlzdHMgcmVhbHBhdGgKfQoKIyBAZGVzY3JpcHRpb24gbG9hZCBjb2xvciB0aGVtZQojIEBub2FyZ3MKIyBAZW52IEJBU0hfRlJBTUVXT1JLX1RIRU1FIFN0cmluZyB0aGVtZSB0byB1c2UKIyBAZXhpdGNvZGUgMCBhbHdheXMgc3VjY2Vzc2Z1bApVSTo6cmVxdWlyZVRoZW1lKCkgewogIFVJOjp0aGVtZSAiJHtCQVNIX0ZSQU1FV09SS19USEVNRS1kZWZhdWx0fSIKfQoKIyBAZGVzY3JpcHRpb24gY2hlY2sgaWYgY29tbWFuZCBzcGVjaWZpZWQgZXhpc3RzIG9yIHJldHVybiAxCiMgd2l0aCBlcnJvciBhbmQgbWVzc2FnZSBpZiBub3QKIwojIEBhcmcgJDEgY29tbWFuZE5hbWU6U3RyaW5nIG9uIHdoaWNoIGV4aXN0ZW5jZSBtdXN0IGJlIGNoZWNrZWQKIyBAYXJnICQyIGhlbHBJZk5vdEV4aXN0czpTdHJpbmcgYSBoZWxwIGNvbW1hbmQgdG8gZGlzcGxheSBpZiB0aGUgY29tbWFuZCBkb2VzIG5vdCBleGlzdAojCiMgQGV4aXRjb2RlIDEgaWYgdGhlIGNvbW1hbmQgc3BlY2lmaWVkIGRvZXMgbm90IGV4aXN0CiMgQHN0ZGVyciBkaWFnbm9zdGljIGluZm9ybWF0aW9uICsgaGVscCBpZiBzZWNvbmQgYXJndW1lbnQgaXMgcHJvdmlkZWQKQXNzZXJ0Ojpjb21tYW5kRXhpc3RzKCkgewogIGxvY2FsIGNvbW1hbmROYW1lPSIkMSIKICBsb2NhbCBoZWxwSWZOb3RFeGlzdHM9IiQyIgoKICAiJHtCQVNIX0ZSQU1FV09SS19DT01NQU5EOi1jb21tYW5kfSIgLXYgIiR7Y29tbWFuZE5hbWV9IiA+L2Rldi9udWxsIDI+L2Rldi9udWxsIHx8IHsKICAgIExvZzo6ZGlzcGxheUVycm9yICIke2NvbW1hbmROYW1lfSBpcyBub3QgaW5zdGFsbGVkLCBwbGVhc2UgaW5zdGFsbCBpdCIKICAgIGlmIFtbIC1uICIke2hlbHBJZk5vdEV4aXN0c30iIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheUluZm8gIiR7aGVscElmTm90RXhpc3RzfSIKICAgIGZpCiAgICByZXR1cm4gMQogIH0KICByZXR1cm4gMAp9CgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgc2tpcCBjb2xvciAoeWVsbG93KQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlTa2lwcGVkKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTCA+PSBfX0xFVkVMX0lORk8pKTsgdGhlbgogICAgZWNobyAtZSAiJHtfX1NLSVBQRURfQ09MT1J9U0tJUFBFRCAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nU2tpcHBlZCAiJDEiCn0KCiMgQGRlc2NyaXB0aW9uIGxvYWQgY29sb3JzIHRoZW1lIGNvbnN0YW50cwojIEB3YXJuaW5nIGlmIHR0eSBub3Qgb3BlbmVkLCBub0NvbG9yIHRoZW1lIHdpbGwgYmUgY2hvc2VuCiMgQGFyZyAkMSB0aGVtZTpTdHJpbmcgdGhlIHRoZW1lIHRvIHVzZSAoZGVmYXVsdCwgbm9Db2xvcikKIyBAYXJnICRAIGFyZ3M6U3RyaW5nW10KIyBAc2V0IF9fRVJST1JfQ09MT1IgU3RyaW5nIGluZGljYXRlIGVycm9yIHN0YXR1cwojIEBzZXQgX19JTkZPX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSBpbmZvIHN0YXR1cwojIEBzZXQgX19TVUNDRVNTX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSBzdWNjZXNzIHN0YXR1cwojIEBzZXQgX19XQVJOSU5HX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSB3YXJuaW5nIHN0YXR1cwojIEBzZXQgX19TS0lQUEVEX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSBza2lwcGVkIHN0YXR1cwojIEBzZXQgX19ERUJVR19DT0xPUiBTdHJpbmcgaW5kaWNhdGUgZGVidWcgc3RhdHVzCiMgQHNldCBfX0hFTFBfQ09MT1IgU3RyaW5nIGluZGljYXRlIGhlbHAgc3RhdHVzCiMgQHNldCBfX1RFU1RfQ09MT1IgU3RyaW5nIG5vdCB1c2VkCiMgQHNldCBfX1RFU1RfRVJST1JfQ09MT1IgU3RyaW5nIG5vdCB1c2VkCiMgQHNldCBfX0hFTFBfVElUTEVfQ09MT1IgU3RyaW5nIHVzZWQgdG8gZGlzcGxheSBoZWxwIHRpdGxlIGluIGhlbHAgc3RyaW5ncwojIEBzZXQgX19IRUxQX09QVElPTl9DT0xPUiBTdHJpbmcgdXNlZCB0byBkaXNwbGF5IGhpZ2hsaWdodCBvcHRpb25zIGluIGhlbHAgc3RyaW5ncwojCiMgQHNldCBfX1JFU0VUX0NPTE9SIFN0cmluZyByZXNldCBkZWZhdWx0IGNvbG9yCiMKIyBAc2V0IF9fSEVMUF9FWEFNUExFIFN0cmluZyB0byByZW1vdmUKIyBAc2V0IF9fSEVMUF9USVRMRSBTdHJpbmcgdG8gcmVtb3ZlCiMgQHNldCBfX0hFTFBfTk9STUFMIFN0cmluZyB0byByZW1vdmUKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0ClVJOjp0aGVtZSgpIHsKICBsb2NhbCB0aGVtZT0iJHsxLWRlZmF1bHR9IgogIGlmIFtbICEgIiR7dGhlbWV9IiA9fiAtZm9yY2UkIF1dICYmICEgQXNzZXJ0Ojp0dHk7IHRoZW4KICAgIHRoZW1lPSJub0NvbG9yIgogIGZpCiAgY2FzZSAiJHt0aGVtZX0iIGluCiAgICBkZWZhdWx0IHwgZGVmYXVsdC1mb3JjZSkKICAgICAgdGhlbWU9ImRlZmF1bHQiCiAgICAgIDs7CiAgICBub0NvbG9yKSA7OwogICAgKikKICAgICAgTG9nOjpmYXRhbCAiaW52YWxpZCB0aGVtZSBwcm92aWRlZCIKICAgICAgOzsKICBlc2FjCiAgaWYgW1sgIiR7dGhlbWV9IiA9ICJkZWZhdWx0IiBdXTsgdGhlbgogICAgQkFTSF9GUkFNRVdPUktfVEhFTUU9ImRlZmF1bHQiCiAgICAjIGNoZWNrIGNvbG9ycyBhcHBsaWNhYmxlIGh0dHBzOi8vbWlzYy5mbG9naXNvZnQuY29tL2Jhc2gvdGlwX2NvbG9yc19hbmRfZm9ybWF0dGluZwogICAgX19FUlJPUl9DT0xPUj0nXGVbMzFtJyAgICAgICAgICMgUmVkCiAgICBfX0lORk9fQ09MT1I9J1xlWzQ0bScgICAgICAgICAgIyB3aGl0ZSBvbiBsaWdodEJsdWUKICAgIF9fU1VDQ0VTU19DT0xPUj0nXGVbMzJtJyAgICAgICAjIEdyZWVuCiAgICBfX1dBUk5JTkdfQ09MT1I9J1xlWzMzbScgICAgICAgIyBZZWxsb3cKICAgIF9fU0tJUFBFRF9DT0xPUj0nXGVbMzNtJyAgICAgICAjIFllbGxvdwogICAgX19ERUJVR19DT0xPUj0nXGVbMzdtJyAgICAgICAgICMgR3JleQogICAgX19IRUxQX0NPTE9SPSdcZVs3OzQ5OzMzbScgICAgICMgQmxhY2sgb24gR29sZAogICAgX19URVNUX0NPTE9SPSdcZVsxMDBtJyAgICAgICAgICMgTGlnaHQgbWFnZW50YQogICAgX19URVNUX0VSUk9SX0NPTE9SPSdcZVs0MW0nICAgICMgd2hpdGUgb24gcmVkCiAgICBfX0hFTFBfVElUTEVfQ09MT1I9IlxlWzE7MzdtIiAgIyBCb2xkCiAgICBfX0hFTFBfT1BUSU9OX0NPTE9SPSJcZVsxOzM0bSIgIyBCbHVlCiAgICAjIEludGVybmFsOiByZXNldCBjb2xvcgogICAgX19SRVNFVF9DT0xPUj0nXGVbMG0nICMgUmVzZXQgQ29sb3IKICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NSxTQzIwMzQKICAgIF9fSEVMUF9FWEFNUExFPSIkKGVjaG8gLWUgIlxlWzI7OTdtIikiCiAgICAjIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIxNTUsU0MyMDM0CiAgICBfX0hFTFBfVElUTEU9IiQoZWNobyAtZSAiXGVbMTszN20iKSIKICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NSxTQzIwMzQKICAgIF9fSEVMUF9OT1JNQUw9IiQoZWNobyAtZSAiXDAzM1swbSIpIgogIGVsc2UKICAgIEJBU0hfRlJBTUVXT1JLX1RIRU1FPSJub0NvbG9yIgogICAgIyBjaGVjayBjb2xvcnMgYXBwbGljYWJsZSBodHRwczovL21pc2MuZmxvZ2lzb2Z0LmNvbS9iYXNoL3RpcF9jb2xvcnNfYW5kX2Zvcm1hdHRpbmcKICAgIF9fRVJST1JfQ09MT1I9JycKICAgIF9fSU5GT19DT0xPUj0nJwogICAgX19TVUNDRVNTX0NPTE9SPScnCiAgICBfX1dBUk5JTkdfQ09MT1I9JycKICAgIF9fU0tJUFBFRF9DT0xPUj0nJwogICAgX19ERUJVR19DT0xPUj0nJwogICAgX19IRUxQX0NPTE9SPScnCiAgICBfX1RFU1RfQ09MT1I9JycKICAgIF9fVEVTVF9FUlJPUl9DT0xPUj0nJwogICAgX19IRUxQX1RJVExFX0NPTE9SPScnCiAgICBfX0hFTFBfT1BUSU9OX0NPTE9SPScnCiAgICAjIEludGVybmFsOiByZXNldCBjb2xvcgogICAgX19SRVNFVF9DT0xPUj0nJwogICAgX19IRUxQX0VYQU1QTEU9JycKICAgIF9fSEVMUF9USVRMRT0nJwogICAgX19IRUxQX05PUk1BTD0nJwogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIGNoZWNrIGlmIHR0eSAoaW50ZXJhY3RpdmUgbW9kZSkgaXMgYWN0aXZlCiMgQG5vYXJncwojIEBleGl0Y29kZSAxIGlmIHR0eSBub3QgYWN0aXZlCiMgQGVudiBOT05fSU5URVJBQ1RJVkUgaWYgMSBjb25zaWRlciBhcyBub3QgaW50ZXJhY3RpdmUgZXZlbiBpZiBlbnZpcm9ubWVudCBpcyBpbnRlcmFjdGl2ZQojIEBlbnYgSU5URVJBQ1RJVkUgaWYgMSBjb25zaWRlciBhcyBpbnRlcmFjdGl2ZSBldmVuIGlmIGVudmlyb25tZW50IGlzIG5vdCBpbnRlcmFjdGl2ZQojIEBzdGRlcnIgZGlhZ25vc3RpYyBpbmZvcm1hdGlvbiArIGhlbHAgaWYgc2Vjb25kIGFyZ3VtZW50IGlzIHByb3ZpZGVkCkFzc2VydDo6dHR5KCkgewogIGlmIFtbICIke05PTl9JTlRFUkFDVElWRTotMH0iID0gIjEiIF1dOyB0aGVuCiAgICByZXR1cm4gMQogIGZpCiAgaWYgW1sgIiR7SU5URVJBQ1RJVkU6LTB9IiA9ICIxIiBdXTsgdGhlbgogICAgcmV0dXJuIDAKICBmaQogIFtbIC10IDEgfHwgLXQgMiBdXQp9CgojIEBkZXNjcmlwdGlvbiBsb2cgbWVzc2FnZSB0byBmaWxlCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6bG9nU2tpcHBlZCgpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+PSBfX0xFVkVMX0lORk8pKTsgdGhlbgogICAgTG9nOjpsb2dNZXNzYWdlICIkezI6LVNLSVBQRUR9IiAiJDEiCiAgZmkKfQoKIyBGVU5DVElPTlMKCmZhY2FkZV9tYWluX2VtYmVkRnJhbWV3b3JrRnVuY3Rpb25iaW5GaWxldHBsKCkgewojIFJFUVVJUkVTCkxpbnV4OjpyZXF1aXJlRXhlY3V0ZWRBc1VzZXIKRW52OjpyZXF1aXJlTG9hZApMb2c6OnJlcXVpcmVMb2FkCkxpbnV4OjpyZXF1aXJlUmVhbHBhdGhDb21tYW5kClVJOjpyZXF1aXJlVGhlbWUKQ29tcGlsZXI6OkZhY2FkZTo6cmVxdWlyZUNvbW1hbmRCaW5EaXIKCiMgQHJlcXVpcmUgQ29tcGlsZXI6OkZhY2FkZTo6cmVxdWlyZUNvbW1hbmRCaW5EaXIKCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NCxTQzIwMTYKZnVuY3Rpb25Ub0NhbGw9J0RiOjpxdWVyeU9uZURhdGFiYXNlJwoiJHtmdW5jdGlvblRvQ2FsbH0iICIkQCIKCn0KCmZhY2FkZV9tYWluX2VtYmVkRnJhbWV3b3JrRnVuY3Rpb25iaW5GaWxldHBsICIkQCIK" +declare -gx embed_function_DbQueryOneDatabase="${PERSISTENT_TMPDIR:-/tmp}/bin/e36a5808727f397f60db02f81c9ecc2e/dbQueryOneDatabase" +declare -gx encoded_binary_file_DbQueryOneDatabase="IyEvdXNyL2Jpbi9lbnYgYmFzaAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgR0VORVJBVEVEIEZBQ0FERSBGUk9NIGh0dHBzOi8vZ2l0aHViLmNvbS9mY2hhc3RhbmV0L2Jhc2gtdG9vbHMvdHJlZS9tYXN0ZXIvaG9tZS93c2wvZmNoYXN0YW5ldC9iYXNoLWRldi1lbnYvdmVuZG9yL2Jhc2gtdG9vbHMtZnJhbWV3b3JrL3NyYy9Db21waWxlci9FbWJlZC9lbWJlZEZyYW1ld29ya0Z1bmN0aW9uLmJpbkZpbGUudHBsCiMgRE8gTk9UIEVESVQgSVQKIyBAZ2VuZXJhdGVkCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMjg4LFNDMjAzNAojIEJJTl9GSUxFPSR7QklOX0ZJTEV9CiMgRkFDQURFCgojIGVuc3VyZSB0aGF0IG5vIHVzZXIgYWxpYXNlcyBjb3VsZCBpbnRlcmZlcmUgd2l0aAojIGNvbW1hbmRzIHVzZWQgaW4gdGhpcyBzY3JpcHQKdW5hbGlhcyAtYSB8fCB0cnVlCnNob3B0IC11IGV4cGFuZF9hbGlhc2VzCgojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKKChmYWlsdXJlcyA9IDApKSB8fCB0cnVlCgojIEJhc2ggd2lsbCByZW1lbWJlciAmIHJldHVybiB0aGUgaGlnaGVzdCBleGl0IGNvZGUgaW4gYSBjaGFpbiBvZiBwaXBlcy4KIyBUaGlzIHdheSB5b3UgY2FuIGNhdGNoIHRoZSBlcnJvciBpbnNpZGUgcGlwZXMsIGUuZy4gbXlzcWxkdW1wIHwgZ3ppcApzZXQgLW8gcGlwZWZhaWwKc2V0IC1vIGVycmV4aXQKCiMgQ29tbWFuZCBTdWJzdGl0dXRpb24gY2FuIGluaGVyaXQgZXJyZXhpdCBvcHRpb24gc2luY2UgYmFzaCB2NC40CnNob3B0IC1zIGluaGVyaXRfZXJyZXhpdCB8fCB0cnVlCgojIGEgbG9nIGlzIGdlbmVyYXRlZCB3aGVuIGEgY29tbWFuZCBmYWlscwpzZXQgLW8gZXJydHJhY2UKCiMgdXNlIG51bGxnbG9iIHNvIHRoYXQgKGZpbGUqLnBocCkgd2lsbCByZXR1cm4gYW4gZW1wdHkgYXJyYXkgaWYgbm8gZmlsZSBtYXRjaGVzIHRoZSB3aWxkY2FyZApzaG9wdCAtcyBudWxsZ2xvYgoKIyBlbnN1cmUgcmVnZXhwIGFyZSBpbnRlcnByZXRlZCB3aXRob3V0IGFjY2VudHVhdGVkIGNoYXJhY3RlcnMKZXhwb3J0IExDX0FMTD1QT1NJWAoKZXhwb3J0IFRFUk09eHRlcm0tMjU2Y29sb3IKCiMgYXZvaWQgaW50ZXJhY3RpdmUgaW5zdGFsbApleHBvcnQgREVCSUFOX0ZST05URU5EPW5vbmludGVyYWN0aXZlCmV4cG9ydCBERUJDT05GX05PTklOVEVSQUNUSVZFX1NFRU49dHJ1ZQoKIyBzdG9yZSBjb21tYW5kIGFyZ3VtZW50cyBmb3IgbGF0ZXIgdXNhZ2UKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CmRlY2xhcmUgLWEgQkFTSF9GUkFNRVdPUktfQVJHVj0oIiRAIikKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CmRlY2xhcmUgLWEgT1JJR0lOQUxfQkFTSF9GUkFNRVdPUktfQVJHVj0oIiRAIikKCiMgQHNlZSBodHRwczovL3VuaXguc3RhY2tleGNoYW5nZS5jb20vYS8zODY4NTYKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMzE3CmludGVycnVwdE1hbmFnZW1lbnQoKSB7CiAgIyByZXN0b3JlIFNJR0lOVCBoYW5kbGVyCiAgdHJhcCAtIElOVAogICMgZW5zdXJlIHRoYXQgQ3RybC1DIGlzIHRyYXBwZWQgYnkgdGhpcyBzY3JpcHQgYW5kIG5vdCBieSBzdWIgcHJvY2VzcwogICMgcmVwb3J0IHRvIHRoZSBwYXJlbnQgdGhhdCB3ZSBoYXZlIGluZGVlZCBiZWVuIGludGVycnVwdGVkCiAga2lsbCAtcyBJTlQgIiQkIgp9CnRyYXAgaW50ZXJydXB0TWFuYWdlbWVudCBJTlQKU0NSSVBUX05BTUU9JHswIyMqL30KUkVBTF9TQ1JJUFRfRklMRT0iJChyZWFkbGluayAtZSAiJChyZWFscGF0aCAiJHtCQVNIX1NPVVJDRVswXX0iKSIpIgppZiBbWyAtbiAiJHtFTUJFRF9DVVJSRU5UX0RJUn0iIF1dOyB0aGVuCiAgQ1VSUkVOVF9ESVI9IiR7RU1CRURfQ1VSUkVOVF9ESVJ9IgplbHNlCiAgQ1VSUkVOVF9ESVI9IiQoY2QgIiQocmVhZGxpbmsgLWUgIiR7UkVBTF9TQ1JJUFRfRklMRSUvKn0iKSIgJiYgcHdkIC1QKSIKZmkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFRlbXAgZGlyIG1hbmFnZW1lbnQKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpLRUVQX1RFTVBfRklMRVM9IiR7S0VFUF9URU1QX0ZJTEVTOi0wfSIKZXhwb3J0IEtFRVBfVEVNUF9GSUxFUwoKIyBQRVJTSVNURU5UX1RNUERJUiBpcyBub3QgZGVsZXRlZCBieSB0cmFwcwpQRVJTSVNURU5UX1RNUERJUj0iJHtUTVBESVI6LS90bXB9L2Jhc2gtZnJhbWV3b3JrIgpleHBvcnQgUEVSU0lTVEVOVF9UTVBESVIKbWtkaXIgLXAgIiR7UEVSU0lTVEVOVF9UTVBESVJ9IgoKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0ClRNUERJUj0iJChta3RlbXAgLWQgLXAgIiR7UEVSU0lTVEVOVF9UTVBESVI6LS90bXB9IiAtdCBiYXNoLWZyYW1ld29yay0kJC1YWFhYWFgpIgpleHBvcnQgVE1QRElSCgojIHRlbXAgZGlyIGNsZWFuaW5nCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjMxNwpjbGVhbk9uRXhpdCgpIHsKICBpZiBbWyAiJHtLRUVQX1RFTVBfRklMRVM6LTB9IiA9ICIxIiBdXTsgdGhlbgogICAgTG9nOjpkaXNwbGF5SW5mbyAiS0VFUF9URU1QX0ZJTEVTPTEgdGVtcCBmaWxlcyBrZXB0IGhlcmUgJyR7VE1QRElSfSciCiAgZWxpZiBbWyAtbiAiJHtUTVBESVIreHh4fSIgXV07IHRoZW4KICAgIExvZzo6ZGlzcGxheURlYnVnICJLRUVQX1RFTVBfRklMRVM9MCByZW1vdmluZyB0ZW1wIGZpbGVzICcke1RNUERJUn0nIgogICAgcm0gLVJmICIke1RNUERJUjotL3RtcC9mYWtlfSIgPi9kZXYvbnVsbCAyPiYxCiAgZmkKfQp0cmFwIGNsZWFuT25FeGl0IEVYSVQgSFVQIFFVSVQgQUJSVCBURVJNCgojIFZBUl9NQUlOX0ZVTkNUSU9OX1ZBUl9OQU1FPWRiUXVlcnlBbGxEYXRhYmFzZXNGYWNhZGUKCiMgQGRlc2NyaXB0aW9uIHVzZWQgdG8gZXhlY3V0ZSBnaXZlbiBxdWVyeSB3aGVuIHVzaW5nCiMgZGJTY3JpcHRBbGxEYXRhYmFzZXMKIyBAYXJnICQxIGRzbjpTdHJpbmcKIyBAYXJnICQyIGRiOlN0cmluZwojIEBlbnYgcXVlcnkgU3RyaW5nCiMgQGVudiBvcHRpb25TZXBhcmF0b3IgU3RyaW5nCiMgQHJlcXVpcmUgTGludXg6OnJlcXVpcmVFeGVjdXRlZEFzVXNlcgpEYjo6cXVlcnlPbmVEYXRhYmFzZSgpIHsKICAjIHF1ZXJ5IGFuZCBvcHRpb25TZXBhcmF0b3IgYXJlIHBhc3NlZCB2aWEgZXhwb3J0CiAgbG9jYWwgZHNuPSIkMSIKICBsb2NhbCBkYj0iJDIiCgogIGxvY2FsIC1BIGRiSW5zdGFuY2UKICBEYXRhYmFzZTo6bmV3SW5zdGFuY2UgZGJJbnN0YW5jZSAiJHtkc259IgogIERhdGFiYXNlOjpzZXRRdWVyeU9wdGlvbnMgZGJJbnN0YW5jZSAiJHtkYkluc3RhbmNlW1FVRVJZX09QVElPTlNdfSAtLWNvbm5lY3QtdGltZW91dD01IgoKICAjIGlkZW50aWZ5IGNvbHVtbnMgaGVhZGVyCiAgZWNobyAtbiAiQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAiCiAgRGF0YWJhc2U6OnNraXBDb2x1bW5OYW1lcyBkYkluc3RhbmNlIDAKCiAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTU0CiAgaWYgISBEYXRhYmFzZTo6cXVlcnkgZGJJbnN0YW5jZSAiJHtxdWVyeX0iICIke2RifSIgfCBzZWQgInMvXHQvJHtvcHRpb25TZXBhcmF0b3J9L2ciOyB0aGVuCiAgICBMb2c6OmZhdGFsICJkYXRhYmFzZSAke2RifSBlcnJvciIgMT4mMgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIExvZyBuYW1lc3BhY2UgcHJvdmlkZXMgMiBraW5kIG9mIGZ1bmN0aW9ucwojIC0gTG9nOjpkaXNwbGF5KiBhbGxvd3MgdG8gZGlzcGxheSBnaXZlbiBtZXNzYWdlIHdpdGgKIyAgIGdpdmVuIGRpc3BsYXkgbGV2ZWwKIyAtIExvZzo6bG9nKiBhbGxvd3MgdG8gbG9nIGdpdmVuIG1lc3NhZ2Ugd2l0aAojICAgZ2l2ZW4gbG9nIGxldmVsCiMgTG9nOjpkaXNwbGF5KiBmdW5jdGlvbnMgYXV0b21hdGljYWxseSBsb2cgdGhlIG1lc3NhZ2UgdG9vCiMgQHNlZSBFbnY6OnJlcXVpcmVMb2FkIHRvIGxvYWQgdGhlIGRpc3BsYXkgYW5kIGxvZyBsZXZlbCBmcm9tIC5lbnYgZmlsZQoKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIG9mZgpleHBvcnQgX19MRVZFTF9PRkY9MAojIEBkZXNjcmlwdGlvbiBsb2cgbGV2ZWwgZXJyb3IKZXhwb3J0IF9fTEVWRUxfRVJST1I9MQojIEBkZXNjcmlwdGlvbiBsb2cgbGV2ZWwgd2FybmluZwpleHBvcnQgX19MRVZFTF9XQVJOSU5HPTIKIyBAZGVzY3JpcHRpb24gbG9nIGxldmVsIGluZm8KZXhwb3J0IF9fTEVWRUxfSU5GTz0zCiMgQGRlc2NyaXB0aW9uIGxvZyBsZXZlbCBzdWNjZXNzCmV4cG9ydCBfX0xFVkVMX1NVQ0NFU1M9MwojIEBkZXNjcmlwdGlvbiBsb2cgbGV2ZWwgZGVidWcKZXhwb3J0IF9fTEVWRUxfREVCVUc9NAoKIyBAZGVzY3JpcHRpb24gdmVyYm9zZSBsZXZlbCBvZmYKZXhwb3J0IF9fVkVSQk9TRV9MRVZFTF9PRkY9MAojIEBkZXNjcmlwdGlvbiB2ZXJib3NlIGxldmVsIGluZm8KZXhwb3J0IF9fVkVSQk9TRV9MRVZFTF9JTkZPPTEKIyBAZGVzY3JpcHRpb24gdmVyYm9zZSBsZXZlbCBpbmZvCmV4cG9ydCBfX1ZFUkJPU0VfTEVWRUxfREVCVUc9MgojIEBkZXNjcmlwdGlvbiB2ZXJib3NlIGxldmVsIGluZm8KZXhwb3J0IF9fVkVSQk9TRV9MRVZFTF9UUkFDRT0zCgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgZGVidWcgY29sb3IgKGdyZXkpCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6ZGlzcGxheURlYnVnKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTCA+PSBfX0xFVkVMX0RFQlVHKSk7IHRoZW4KICAgIGVjaG8gLWUgIiR7X19ERUJVR19DT0xPUn1ERUJVRyAgIC0gJHsxfSR7X19SRVNFVF9DT0xPUn0iID4mMgogIGZpCiAgTG9nOjpsb2dEZWJ1ZyAiJDEiCn0KCiMgQGRlc2NyaXB0aW9uIERpc3BsYXkgbWVzc2FnZSB1c2luZyBpbmZvIGNvbG9yIChiZyBsaWdodCBibHVlL2ZnIHdoaXRlKQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlJbmZvKCkgewogIGxvY2FsIHR5cGU9IiR7MjotSU5GT30iCiAgaWYgKChCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMID49IF9fTEVWRUxfSU5GTykpOyB0aGVuCiAgICBlY2hvIC1lICIke19fSU5GT19DT0xPUn0ke3R5cGV9ICAgIC0gJHsxfSR7X19SRVNFVF9DT0xPUn0iID4mMgogIGZpCiAgTG9nOjpsb2dJbmZvICIkMSIgIiR7dHlwZX0iCn0KCiMgQGRlc2NyaXB0aW9uIGVuc3VyZSBDT01NQU5EX0JJTl9ESVIgZW52IHZhciBpcyBzZXQKIyBhbmQgUEFUSCBjb3JyZWN0bHkgcHJlcGFyZWQKIyBAbm9hcmdzCiMgQHNldCBDT01NQU5EX0JJTl9ESVIgc3RyaW5nIHRoZSBkaXJlY3Rvcnkgd2hlcmUgdG8gZmluZCB0aGlzIGNvbW1hbmQKIyBAc2V0IFBBVEggc3RyaW5nIGFkZCBkaXJlY3Rvcnkgd2hlcmUgdG8gZmluZCB0aGlzIGNvbW1hbmQgYmluYXJ5CkNvbXBpbGVyOjpGYWNhZGU6OnJlcXVpcmVDb21tYW5kQmluRGlyKCkgewogIENPTU1BTkRfQklOX0RJUj0iJHtDVVJSRU5UX0RJUn0iCiAgRW52OjpwYXRoUHJlcGVuZCAiJHtDT01NQU5EX0JJTl9ESVJ9Igp9CgojIEBkZXNjcmlwdGlvbiBjcmVhdGUgYSBuZXcgZGIgaW5zdGFuY2UKIyBSZXR1cm5zIGltbWVkaWF0ZWx5IGlmIHRoZSBpbnN0YW5jZSBpcyBhbHJlYWR5IGluaXRpYWxpemVkCiMKIyBAYXJnICQxIGluc3RhbmNlTmV3SW5zdGFuY2U6Jk1hcDxTdHJpbmcsU3RyaW5nPiAocGFzc2VkIGJ5IHJlZmVyZW5jZSkgZGF0YWJhc2UgaW5zdGFuY2UgdG8gdXNlCiMgQGFyZyAkMiBkc246U3RyaW5nIGRzbiBwcm9maWxlIC0gbG9hZCB0aGUgZHNuLmVudiBwcm9maWxlIGRlZHVjZWQgdXNpbmcgcnVsZXMgZGVmaW5lZCBpbiBDb25mOjpnZXRBYnNvbHV0ZUZpbGUKIwojIEBleGFtcGxlCiMgICBkZWNsYXJlIC1BZ3ggZGJJbnN0YW5jZQojICAgRGF0YWJhc2U6Om5ld0luc3RhbmNlIGRiSW5zdGFuY2UgImRlZmF1bHQubG9jYWwiCiMKIyBAZXhpdGNvZGUgMSBpZiBkbnMgZmlsZSBub3QgYWJsZSB0byBsb2FkZWQKRGF0YWJhc2U6Om5ld0luc3RhbmNlKCkgewogIGxvY2FsIC1uIGluc3RhbmNlTmV3SW5zdGFuY2U9JDEKICBsb2NhbCBkc249IiQyIgogIGxvY2FsIERTTl9GSUxFCgogIGlmIFtbIC12IGluc3RhbmNlTmV3SW5zdGFuY2VbJ0lOSVRJQUxJWkVEJ10gJiYgIiR7aW5zdGFuY2VOZXdJbnN0YW5jZVsnSU5JVElBTElaRUQnXTotMH0iID09ICIxIiBdXTsgdGhlbgogICAgcmV0dXJuCiAgZmkKCiAgIyBmaW5hbCBhdXRoIGZpbGUgZ2VuZXJhdGVkIGZyb20gZG5zIGZpbGUKICBpbnN0YW5jZU5ld0luc3RhbmNlWydBVVRIX0ZJTEUnXT0iIgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0RTTl9GSUxFJ109IiIKCiAgIyBjaGVjayBkc24gZmlsZQogIERTTl9GSUxFPSIkKENvbmY6OmdldEFic29sdXRlRmlsZSAiZHNuIiAiJHtkc259IiAiZW52IikiIHx8IHJldHVybiAxCiAgRGF0YWJhc2U6OmNoZWNrRHNuRmlsZSAiJHtEU05fRklMRX0iIHx8IHJldHVybiAxCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnRFNOX0ZJTEUnXT0iJHtEU05fRklMRX0iCgogICMgc2hlbGxjaGVjayBzb3VyY2U9L3NyYy9EYXRhYmFzZS90ZXN0c0RhdGEvZHNuX3ZhbGlkLmVudgogIHNvdXJjZSAiJHtpbnN0YW5jZU5ld0luc3RhbmNlWydEU05fRklMRSddfSIKCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnVVNFUiddPSIke1VTRVJ9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1BBU1NXT1JEJ109IiR7UEFTU1dPUkR9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0hPU1ROQU1FJ109IiR7SE9TVE5BTUV9IgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ1BPUlQnXT0iJHtQT1JUfSIKCiAgIyBnZW5lcmF0ZSBhdXRoRmlsZSBmb3IgZWFzeSBhdXRoZW50aWNhdGlvbgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0FVVEhfRklMRSddPSQobWt0ZW1wIC1wICIke1RNUERJUjotL3RtcH0iIC10ICJteXNxbC5YWFhYWFhYWFhYWFgiKQogICgKICAgIGVjaG8gIltjbGllbnRdIgogICAgZWNobyAidXNlciA9ICR7VVNFUn0iCiAgICBlY2hvICJwYXNzd29yZCA9ICR7UEFTU1dPUkR9IgogICAgZWNobyAiaG9zdCA9ICR7SE9TVE5BTUV9IgogICAgZWNobyAicG9ydCA9ICR7UE9SVH0iCiAgKSA+IiR7aW5zdGFuY2VOZXdJbnN0YW5jZVsnQVVUSF9GSUxFJ119IgoKICAjIHNvbWUgb2YgdGhvc2UgdmFsdWVzIGNhbiBiZSBvdmVycmlkZGVuIHVzaW5nIHRoZSBkc24gZmlsZQogICMgU0tJUF9DT0xVTU5fTkFNRVMgZW5hYmxlZCBieSBkZWZhdWx0CiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnU0tJUF9DT0xVTU5fTkFNRVMnXT0iJHtTS0lQX0NPTFVNTl9OQU1FUzotMX0iCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnU1NMX09QVElPTlMnXT0iJHtNWVNRTF9TU0xfT1BUSU9OUzotLS1zc2wtbW9kZT1ESVNBQkxFRH0iCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnUVVFUllfT1BUSU9OUyddPSIke01ZU1FMX1FVRVJZX09QVElPTlM6LS0tYmF0Y2ggLS1yYXcgLS1kZWZhdWx0LWNoYXJhY3Rlci1zZXQ9dXRmOH0iCiAgaW5zdGFuY2VOZXdJbnN0YW5jZVsnRFVNUF9PUFRJT05TJ109IiR7TVlTUUxfRFVNUF9PUFRJT05TOi0tLWRlZmF1bHQtY2hhcmFjdGVyLXNldD11dGY4IC0tY29tcHJlc3MgLS1oZXgtYmxvYiAtLXJvdXRpbmVzIC0tdHJpZ2dlcnMgLS1zaW5nbGUtdHJhbnNhY3Rpb24gLS1zZXQtZ3RpZC1wdXJnZWQ9T0ZGIC0tY29sdW1uLXN0YXRpc3RpY3M9MCAke2luc3RhbmNlTmV3SW5zdGFuY2VbJ1NTTF9PUFRJT05TJ119fSIKICBpbnN0YW5jZU5ld0luc3RhbmNlWydEQl9JTVBPUlRfT1BUSU9OUyddPSIke0RCX0lNUE9SVF9PUFRJT05TOi0tLWNvbm5lY3QtdGltZW91dD01IC0tYmF0Y2ggLS1yYXcgLS1kZWZhdWx0LWNoYXJhY3Rlci1zZXQ9dXRmOH0iCgogIGluc3RhbmNlTmV3SW5zdGFuY2VbJ0lOSVRJQUxJWkVEJ109MQp9CgojIEBkZXNjcmlwdGlvbiBteXNxbCBxdWVyeSBvbiBhIGdpdmVuIGRiCiMgQHdhcm5pbmcgY291bGQgdXNlIFFVRVJZX09QVElPTlMgdmFyaWFibGUgZnJvbSBkc24gaWYgZGVmaW5lZAojIEBleGFtcGxlCiMgICBjYXQgZmlsZS5zcWwgfCBEYXRhYmFzZTo6cXVlcnkgLi4uCiMgQGFyZyAkMSBpbnN0YW5jZVF1ZXJ5OiZNYXA8U3RyaW5nLFN0cmluZz4gKHBhc3NlZCBieSByZWZlcmVuY2UpIGRhdGFiYXNlIGluc3RhbmNlIHRvIHVzZQojIEBhcmcgJDIgc3FsUXVlcnk6U3RyaW5nIChvcHRpb25hbCkgc3FsIHF1ZXJ5IG9yIHNxbCBmaWxlIHRvIGV4ZWN1dGUuIGlmIG5vdCBwcm92aWRlZCBvciBlbXB0eSwgdGhlIGNvbW1hbmQgY2FuIGJlIHBpcGVkCiMgQGFyZyAkMyBkYk5hbWU6U3RyaW5nIChvcHRpb25hbCkgdGhlIGRiIG5hbWUKIwojIEBleGl0Y29kZSBteXNxbCBjb21tYW5kIHN0YXR1cyBjb2RlCkRhdGFiYXNlOjpxdWVyeSgpIHsKICBsb2NhbCAtbiBpbnN0YW5jZVF1ZXJ5PSQxCiAgbG9jYWwgLWEgbXlzcWxDb21tYW5kPSgpCiAgbG9jYWwgLWEgcXVlcnlPcHRpb25zCgogIG15c3FsQ29tbWFuZCs9KG15c3FsKQogIG15c3FsQ29tbWFuZCs9KCItLWRlZmF1bHRzLWV4dHJhLWZpbGU9JHtpbnN0YW5jZVF1ZXJ5WydBVVRIX0ZJTEUnXX0iKQogIElGUz0nICcgcmVhZCAtciAtYSBxdWVyeU9wdGlvbnMgPDw8IiR7aW5zdGFuY2VRdWVyeVsnUVVFUllfT1BUSU9OUyddfSIKICBteXNxbENvbW1hbmQrPSgiJHtxdWVyeU9wdGlvbnNbQF19IikKICBpZiBbWyAiJHtpbnN0YW5jZVF1ZXJ5WydTS0lQX0NPTFVNTl9OQU1FUyddfSIgPSAiMSIgXV07IHRoZW4KICAgIG15c3FsQ29tbWFuZCs9KCItcyIgIi0tc2tpcC1jb2x1bW4tbmFtZXMiKQogIGZpCiAgIyBhZGQgb3B0aW9uYWwgZGIgbmFtZQogIGlmIFtbIC1uICIkezMreH0iIF1dOyB0aGVuCiAgICBteXNxbENvbW1hbmQrPSgiJDMiKQogIGZpCiAgIyBhZGQgb3B0aW9uYWwgc3FsIHF1ZXJ5CiAgaWYgW1sgLW4gIiR7Mit4fSIgJiYgLW4gIiQyIiAmJiAhIC1mICIkMiIgXV07IHRoZW4KICAgIG15c3FsQ29tbWFuZCs9KCItZSIpCiAgICBteXNxbENvbW1hbmQrPSgiJDIiKQogIGZpCiAgTG9nOjpkaXNwbGF5RGVidWcgIiQocHJpbnRmICJleGVjdXRlIGNvbW1hbmQ6ICclcyciICIke215c3FsQ29tbWFuZFsqXX0iKSIKCiAgaWYgW1sgLWYgIiQyIiBdXTsgdGhlbgogICAgIiR7bXlzcWxDb21tYW5kW0BdfSIgPCIkMiIKICBlbHNlCiAgICAiJHtteXNxbENvbW1hbmRbQF19IgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIHNldCB0aGUgZ2VuZXJhbCBvcHRpb25zIHRvIHVzZSBvbiBteXNxbCBjb21tYW5kIHRvIHF1ZXJ5IHRoZSBkYXRhYmFzZQojIERpZmZlcnMgdGhhbiBzZXRPcHRpb25zIGluIHRoZSB3YXkgdGhhdCB0aGVzZSBvcHRpb25zIGNvdWxkIGNoYW5nZSBlYWNoIHRpbWUKIwojIEBhcmcgJDEgaW5zdGFuY2VTZXRRdWVyeU9wdGlvbnM6Jk1hcDxTdHJpbmcsU3RyaW5nPiAocGFzc2VkIGJ5IHJlZmVyZW5jZSkgZGF0YWJhc2UgaW5zdGFuY2UgdG8gdXNlCiMgQGFyZyAkMiBvcHRpb25zTGlzdDpTdHJpbmcgcXVlcnkgb3B0aW9ucyBsaXN0CkRhdGFiYXNlOjpzZXRRdWVyeU9wdGlvbnMoKSB7CiAgbG9jYWwgLW4gaW5zdGFuY2VTZXRRdWVyeU9wdGlvbnM9JDEKICAjIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKICBpbnN0YW5jZVNldFF1ZXJ5T3B0aW9uc1snUVVFUllfT1BUSU9OUyddPSIkMiIKfQoKIyBAZGVzY3JpcHRpb24gYnkgZGVmYXVsdCB3ZSBza2lwIHRoZSBjb2x1bW4gbmFtZXMKIyBidXQgc29tZXRpbWVzIHdlIG5lZWQgY29sdW1uIG5hbWVzIHRvIGRpc3BsYXkgc29tZSByZXN1bHRzCiMgZGlzYWJsZSB0aGlzIG9wdGlvbiB0ZW1wb3JhcmlseSBhbmQgdGhlbiByZXN0b3JlIGl0IHRvIHRydWUKIwojIEBhcmcgJDEgaW5zdGFuY2VTZXRRdWVyeU9wdGlvbnM6Jk1hcDxTdHJpbmcsU3RyaW5nPiAocGFzc2VkIGJ5IHJlZmVyZW5jZSkgZGF0YWJhc2UgaW5zdGFuY2UgdG8gdXNlCiMgQGFyZyAkMiBza2lwQ29sdW1uTmFtZXM6Qm9vbGVhbiAwIHRvIGRpc2FibGUsIDEgdG8gZW5hYmxlIChoaWRlIGNvbHVtbiBuYW1lcykKRGF0YWJhc2U6OnNraXBDb2x1bW5OYW1lcygpIHsKICBsb2NhbCAtbiBpbnN0YW5jZVNraXBDb2x1bW5OYW1lcz0kMQogICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjAzNAogIGluc3RhbmNlU2tpcENvbHVtbk5hbWVzWydTS0lQX0NPTFVNTl9OQU1FUyddPSIkMiIKfQoKIyBAZGVzY3JpcHRpb24gcHJlcGVuZCBkaXJlY3RvcmllcyB0byB0aGUgUEFUSCBlbnZpcm9ubWVudCB2YXJpYWJsZQojIEBhcmcgJEAgYXJnczpTdHJpbmdbXSBsaXN0IG9mIGRpcmVjdG9yaWVzIHRvIHByZXBlbmQKIyBAc2V0IFBBVEggdXBkYXRlIFBBVEggd2l0aCB0aGUgZGlyZWN0b3JpZXMgcHJlcGVuZGVkCkVudjo6cGF0aFByZXBlbmQoKSB7CiAgbG9jYWwgYXJnCiAgZm9yIGFyZyBpbiAiJEAiOyBkbwogICAgaWYgW1sgLWQgIiR7YXJnfSIgJiYgIjoke1BBVEh9OiIgIT0gKiI6JHthcmd9OiIqIF1dOyB0aGVuCiAgICAgIFBBVEg9IiQocmVhbHBhdGggIiR7YXJnfSIpOiR7UEFUSH0iCiAgICBmaQogIGRvbmUKfQoKIyBAZGVzY3JpcHRpb24gRGlzcGxheSBtZXNzYWdlIHVzaW5nIGVycm9yIGNvbG9yIChyZWQpIGFuZCBleGl0IGltbWVkaWF0ZWx5IHdpdGggZXJyb3Igc3RhdHVzIDEKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpmYXRhbCgpIHsKICBlY2hvIC1lICIke19fRVJST1JfQ09MT1J9RkFUQUwgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBMb2c6OmxvZ0ZhdGFsICIkMSIKICBleGl0IDEKfQoKIyBAZGVzY3JpcHRpb24gbG9nIG1lc3NhZ2UgdG8gZmlsZQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmxvZ0RlYnVnKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfREVCVUcpKTsgdGhlbgogICAgTG9nOjpsb2dNZXNzYWdlICIkezI6LURFQlVHfSIgIiQxIgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dJbmZvKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfSU5GTykpOyB0aGVuCiAgICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotSU5GT30iICIkMSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBlbnN1cmUgcnVubmluZyB1c2VyIGlzIG5vdCByb290CiMgQGV4aXRjb2RlIDEgaWYgY3VycmVudCB1c2VyIGlzIHJvb3QKIyBAc3RkZXJyIGRpYWdub3N0aWNzIGluZm9ybWF0aW9uIGlzIGRpc3BsYXllZApMaW51eDo6cmVxdWlyZUV4ZWN1dGVkQXNVc2VyKCkgewogIGlmIFtbICIkKGlkIC11KSIgPSAiMCIgXV07IHRoZW4KICAgIExvZzo6ZmF0YWwgInRoaXMgc2NyaXB0IHNob3VsZCBiZSBleGVjdXRlZCBhcyBub3JtYWwgdXNlciIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBnZXQgYWJzb2x1dGUgY29uZiBmaWxlIGZyb20gc3BlY2lmaWVkIGNvbmYgZm9sZGVyIGRlZHVjZWQgdXNpbmcgdGhlc2UgcnVsZXMKIyAgICogZnJvbSBhYnNvbHV0ZSBmaWxlIChpZ25vcmVzIDxjb25mRm9sZGVyPiBhbmQgPGV4dGVuc2lvbj4pCiMgICAqIHJlbGF0aXZlIHRvIHdoZXJlIHNjcmlwdCBpcyBleGVjdXRlZCAoaWdub3JlcyA8Y29uZkZvbGRlcj4gYW5kIDxleHRlbnNpb24+KQojICAgKiBmcm9tIGhvbWUvLmJhc2gtdG9vbHMvPGNvbmZGb2xkZXI+CiMgICAqIGZyb20gZnJhbWV3b3JrIGNvbmYvPGNvbmZGb2xkZXI+CiMKIyBAYXJnICQxIGNvbmZGb2xkZXI6U3RyaW5nIHRoZSBkaXJlY3RvcnkgbmFtZSAobm90IHRoZSBwYXRoKSB0byBsaXN0CiMgQGFyZyAkMiBjb25mOlN0cmluZyBmaWxlIHRvIHVzZSB3aXRob3V0IGV4dGVuc2lvbgojIEBhcmcgJDMgZXh0ZW5zaW9uOlN0cmluZyB0aGUgZXh0ZW5zaW9uICguc2ggYnkgZGVmYXVsdCkKIwojIEBzdGRvdXQgYWJzb2x1dGUgY29uZiBmaWxlbmFtZQojIEBleGl0Y29kZSAxIGlmIGZpbGUgaXMgbm90IGZvdW5kIGluIGFueSBsb2NhdGlvbgpDb25mOjpnZXRBYnNvbHV0ZUZpbGUoKSB7CiAgbG9jYWwgY29uZkZvbGRlcj0iJDEiCiAgbG9jYWwgY29uZj0iJDIiCiAgbG9jYWwgZXh0ZW5zaW9uPSIkezMtLnNofSIKICBpZiBbWyAtbiAiJHtleHRlbnNpb259IiAmJiAiJHtleHRlbnNpb246MDoxfSIgIT0gIi4iIF1dOyB0aGVuCiAgICBleHRlbnNpb249Ii4ke2V4dGVuc2lvbn0iCiAgZmkKCiAgdGVzdEFicygpIHsKICAgIGxvY2FsIHJlc3VsdAogICAgcmVzdWx0PSIkKHJlYWxwYXRoIC1lICIkMSIgMj4vZGV2L251bGwpIgogICAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTgxCiAgICBpZiBbWyAiJD8iID0gIjAiICYmIC1mICIke3Jlc3VsdH0iIF1dOyB0aGVuCiAgICAgIGVjaG8gIiR7cmVzdWx0fSIKICAgICAgcmV0dXJuIDAKICAgIGZpCiAgICByZXR1cm4gMQogIH0KCiAgIyBjb25mIGlzIGFic29sdXRlIGZpbGUgKGluY2x1ZGluZyBleHRlbnNpb24pCiAgdGVzdEFicyAiJHtjb25mRm9sZGVyfSR7ZXh0ZW5zaW9ufSIgJiYgcmV0dXJuIDAKICAjIGNvbmYgaXMgYWJzb2x1dGUgZmlsZQogIHRlc3RBYnMgIiR7Y29uZkZvbGRlcn0iICYmIHJldHVybiAwCiAgIyBjb25mIGlzIGFic29sdXRlIGZpbGUgKGluY2x1ZGluZyBleHRlbnNpb24pCiAgdGVzdEFicyAiJHtjb25mfSR7ZXh0ZW5zaW9ufSIgJiYgcmV0dXJuIDAKICAjIGNvbmYgaXMgYWJzb2x1dGUgZmlsZQogIHRlc3RBYnMgIiR7Y29uZn0iICYmIHJldHVybiAwCgogICMgcmVsYXRpdmUgdG8gd2hlcmUgc2NyaXB0IGlzIGV4ZWN1dGVkIChpbmNsdWRpbmcgZXh0ZW5zaW9uKQogIGlmIFtbIC1uICIke0NVUlJFTlRfRElSK3h4eH0iIF1dOyB0aGVuCiAgICB0ZXN0QWJzICIkKEZpbGU6OmNvbmNhdGVuYXRlUGF0aCAiJHtDVVJSRU5UX0RJUn0iICIke2NvbmZGb2xkZXJ9IikvJHtjb25mfSR7ZXh0ZW5zaW9ufSIgJiYgcmV0dXJuIDAKICBmaQogICMgZnJvbSBob21lLy5iYXNoLXRvb2xzLzxjb25mRm9sZGVyPgogIHRlc3RBYnMgIiQoRmlsZTo6Y29uY2F0ZW5hdGVQYXRoICIke0hPTUV9Ly5iYXNoLXRvb2xzIiAiJHtjb25mRm9sZGVyfSIpLyR7Y29uZn0ke2V4dGVuc2lvbn0iICYmIHJldHVybiAwCgogIGlmIFtbIC1uICIke0ZSQU1FV09SS19ST09UX0RJUit4eHh9IiBdXTsgdGhlbgogICAgIyBmcm9tIGZyYW1ld29yayBjb25mLzxjb25mRm9sZGVyPiAoaW5jbHVkaW5nIGV4dGVuc2lvbikKICAgIHRlc3RBYnMgIiQoRmlsZTo6Y29uY2F0ZW5hdGVQYXRoICIke0ZSQU1FV09SS19ST09UX0RJUn0vY29uZiIgIiR7Y29uZkZvbGRlcn0iKS8ke2NvbmZ9JHtleHRlbnNpb259IiAmJiByZXR1cm4gMAoKICAgICMgZnJvbSBmcmFtZXdvcmsgY29uZi88Y29uZkZvbGRlcj4KICAgIHRlc3RBYnMgIiQoRmlsZTo6Y29uY2F0ZW5hdGVQYXRoICIke0ZSQU1FV09SS19ST09UX0RJUn0vY29uZiIgIiR7Y29uZkZvbGRlcn0iKS8ke2NvbmZ9IiAmJiByZXR1cm4gMAogIGZpCgogICMgZmlsZSBub3QgZm91bmQKICBMb2c6OmRpc3BsYXlFcnJvciAiY29uZiBmaWxlICcke2NvbmZ9JyBub3QgZm91bmQiCgogIHJldHVybiAxCn0KCiMgQGRlc2NyaXB0aW9uIGNoZWNrIGlmIGRzbiBmaWxlIGhhcyBhbGwgdGhlIG1hbmRhdG9yeSB2YXJpYWJsZXMgc2V0CiMgTWFuZGF0b3J5IHZhcmlhYmxlcyBhcmU6IEhPU1ROQU1FLCBVU0VSLCBQQVNTV09SRCwgUE9SVAojCiMgQGFyZyAkMSBkc25GaWxlTmFtZTpTdHJpbmcgZHNuIGFic29sdXRlIGZpbGVuYW1lCiMgQHNldCBIT1NUTkFNRSBsb2FkZWQgZnJvbSBkc24gZmlsZQojIEBzZXQgUE9SVCBsb2FkZWQgZnJvbSBkc24gZmlsZQojIEBzZXQgVVNFUiBsb2FkZWQgZnJvbSBkc24gZmlsZQojIEBzZXQgUEFTU1dPUkQgbG9hZGVkIGZyb20gZHNuIGZpbGUKIyBAZXhpdGNvZGUgMCBvbiB2YWxpZCBmaWxlCiMgQGV4aXRjb2RlIDEgaWYgb25lIG9mIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBjb25mIGZpbGUgaXMgaW52YWxpZCBvciBpZiBmaWxlIG5vdCBmb3VuZAojIEBzdGRlcnIgbG9nIG91dHB1dCBpZiBlcnJvciBmb3VuZCBpbiBjb25mIGZpbGUKRGF0YWJhc2U6OmNoZWNrRHNuRmlsZSgpIHsKICBsb2NhbCBkc25GaWxlTmFtZT0iJDEiCiAgaWYgW1sgISAtZiAiJHtkc25GaWxlTmFtZX0iIF1dOyB0aGVuCiAgICBMb2c6OmRpc3BsYXlFcnJvciAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gbm90IGZvdW5kIgogICAgcmV0dXJuIDEKICBmaQoKICAoCiAgICB1bnNldCBIT1NUTkFNRSBQT1JUIFBBU1NXT1JEIFVTRVIKICAgICMgc2hlbGxjaGVjayBzb3VyY2U9L3NyYy9EYXRhYmFzZS90ZXN0c0RhdGEvZHNuX3ZhbGlkLmVudgogICAgc291cmNlICIke2RzbkZpbGVOYW1lfSIKICAgIGlmIFtbIC16ICR7SE9TVE5BTUUreH0gXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogSE9TVE5BTUUgbm90IHByb3ZpZGVkIgogICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmIFtbIC16ICIke0hPU1ROQU1FfSIgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5V2FybmluZyAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gOiBIT1NUTkFNRSB2YWx1ZSBub3QgcHJvdmlkZWQiCiAgICBmaQogICAgaWYgW1sgIiR7SE9TVE5BTUV9IiA9ICJsb2NhbGhvc3QiIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheVdhcm5pbmcgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogY2hlY2sgdGhhdCBIT1NUTkFNRSBzaG91bGQgbm90IGJlIDEyNy4wLjAuMSBpbnN0ZWFkIG9mIGxvY2FsaG9zdCIKICAgIGZpCiAgICBpZiBbWyAteiAiJHtQT1JUK3h9IiBdXTsgdGhlbgogICAgICBMb2c6OmRpc3BsYXlFcnJvciAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gOiBQT1JUIG5vdCBwcm92aWRlZCIKICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICBpZiAhIFtbICR7UE9SVH0gPX4gXlswLTldKyQgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgImRzbiBmaWxlICR7ZHNuRmlsZU5hbWV9IDogUE9SVCBpbnZhbGlkIgogICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmIFtbIC16ICIke1VTRVIreH0iIF1dOyB0aGVuCiAgICAgIExvZzo6ZGlzcGxheUVycm9yICJkc24gZmlsZSAke2RzbkZpbGVOYW1lfSA6IFVTRVIgbm90IHByb3ZpZGVkIgogICAgICByZXR1cm4gMQogICAgZmkKICAgIGlmIFtbIC16ICIke1BBU1NXT1JEK3h9IiBdXTsgdGhlbgogICAgICBMb2c6OmRpc3BsYXlFcnJvciAiZHNuIGZpbGUgJHtkc25GaWxlTmFtZX0gOiBQQVNTV09SRCBub3QgcHJvdmlkZWQiCiAgICAgIHJldHVybiAxCiAgICBmaQogICkKfQoKIyBAZGVzY3JpcHRpb24gbG9nIG1lc3NhZ2UgdG8gZmlsZQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmxvZ0ZhdGFsKCkgewogIExvZzo6bG9nTWVzc2FnZSAiJHsyOi1GQVRBTH0iICIkMSIKfQoKIyBAZGVzY3JpcHRpb24gSW50ZXJuYWw6IGNvbW1vbiBsb2cgbWVzc2FnZQojIEBleGFtcGxlIHRleHQKIyAgIFtkYXRlXXxbbGV2ZWxNc2ddfG1lc3NhZ2UKIwojIEBleGFtcGxlIHRleHQKIyAgIDIwMjAtMDEtMTkgMTk6MjA6MjF8RVJST1IgIHxsb2cgZXJyb3IKIyAgIDIwMjAtMDEtMTkgMTk6MjA6MjF8U0tJUFBFRHxsb2cgc2tpcHBlZAojCiMgQGFyZyAkMSBsZXZlbE1zZzpTdHJpbmcgbWVzc2FnZSdzIGxldmVsIGRlc2NyaXB0aW9uIChlZzogU1RBVFVTLCBFUlJPUiwgLi4uKQojIEBhcmcgJDIgbXNnOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfRklMRSBTdHJpbmcgbG9nIGZpbGUgdG8gdXNlLCBkbyBub3RoaW5nIGlmIGVtcHR5CiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgaW50IGxvZyBsZXZlbCBsb2cgb25seSBpZiA+IE9GRiBvciBmYXRhbCBtZXNzYWdlcwojIEBzdGRlcnIgZGlhZ25vc3RpY3MgaW5mb3JtYXRpb24gaXMgZGlzcGxheWVkCiMgQHJlcXVpcmUgRW52OjpyZXF1aXJlTG9hZAojIEByZXF1aXJlIExvZzo6cmVxdWlyZUxvYWQKTG9nOjpsb2dNZXNzYWdlKCkgewogIGxvY2FsIGxldmVsTXNnPSIkMSIKICBsb2NhbCBtc2c9IiQyIgogIGxvY2FsIGRhdGUKCiAgaWYgW1sgLW4gIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IiBdXSAmJiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+IF9fTEVWRUxfT0ZGKSk7IHRoZW4KICAgIGRhdGU9IiQoZGF0ZSAnKyVZLSVtLSVkICVIOiVNOiVTJykiCiAgICB0b3VjaCAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iCiAgICBwcmludGYgIiVzfCU3c3wlc1xuIiAiJHtkYXRlfSIgIiR7bGV2ZWxNc2d9IiAiJHttc2d9IiA+PiIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBjb25jYXRlbmF0ZSAyIHBhdGhzIGFuZCBlbnN1cmUgdGhlIHBhdGggaXMgY29ycmVjdCB1c2luZyByZWFscGF0aCAtbQojIEBhcmcgJDEgYmFzZVBhdGg6U3RyaW5nCiMgQGFyZyAkMiBzdWJQYXRoOlN0cmluZwojIEByZXF1aXJlIExpbnV4OjpyZXF1aXJlUmVhbHBhdGhDb21tYW5kCkZpbGU6OmNvbmNhdGVuYXRlUGF0aCgpIHsKICBsb2NhbCBiYXNlUGF0aD0iJDEiCiAgbG9jYWwgc3ViUGF0aD0iJDIiCiAgbG9jYWwgZnVsbFBhdGg9IiR7YmFzZVBhdGg6KyR7YmFzZVBhdGh9L30ke3N1YlBhdGh9IgoKICByZWFscGF0aCAtbSAiJHtmdWxsUGF0aH0iIDI+L2Rldi9udWxsCn0KCiMgQGRlc2NyaXB0aW9uIERpc3BsYXkgbWVzc2FnZSB1c2luZyBlcnJvciBjb2xvciAocmVkKQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlFcnJvcigpIHsKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgPj0gX19MRVZFTF9FUlJPUikpOyB0aGVuCiAgICBlY2hvIC1lICIke19fRVJST1JfQ09MT1J9RVJST1IgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nRXJyb3IgIiQxIgp9CgojIEBkZXNjcmlwdGlvbiBEaXNwbGF5IG1lc3NhZ2UgdXNpbmcgd2FybmluZyBjb2xvciAoeWVsbG93KQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmRpc3BsYXlXYXJuaW5nKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTCA+PSBfX0xFVkVMX1dBUk5JTkcpKTsgdGhlbgogICAgZWNobyAtZSAiJHtfX1dBUk5JTkdfQ09MT1J9V0FSTiAgICAtICR7MX0ke19fUkVTRVRfQ09MT1J9IiA+JjIKICBmaQogIExvZzo6bG9nV2FybmluZyAiJDEiCn0KCiMgQGRlc2NyaXB0aW9uIGVuc3VyZSBlbnYgZmlsZXMgYXJlIGxvYWRlZAojIEBhcmcgJEAgbGlzdCBvZiBkZWZhdWx0IGZpbGVzIHRvIGxvYWQgYXQgdGhlIGVuZAojIEBleGl0Y29kZSAxIGlmIG9uZSBvZiBlbnYgZmlsZXMgZmFpbHMgdG8gbG9hZAojIEBzdGRlcnIgZGlhZ25vc3RpY3MgaW5mb3JtYXRpb24gaXMgZGlzcGxheWVkCiMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjEyMApFbnY6OnJlcXVpcmVMb2FkKCkgewogIGxvY2FsIC1hIGRlZmF1bHRGaWxlcz0oIiRAIikKICAjIGdldCBsaXN0IG9mIHBvc3NpYmxlIGNvbmZpZyBmaWxlcwogIGxvY2FsIC1hIGNvbmZpZ0ZpbGVzPSgpCiAgaWYgW1sgLW4gIiR7QkFTSF9GUkFNRVdPUktfRU5WX0ZJTEVTWzBdKzF9IiBdXTsgdGhlbgogICAgIyBCQVNIX0ZSQU1FV09SS19FTlZfRklMRVMgaXMgYW4gYXJyYXkKICAgIGNvbmZpZ0ZpbGVzKz0oIiR7QkFTSF9GUkFNRVdPUktfRU5WX0ZJTEVTW0BdfSIpCiAgZmkKICBpZiBbWyAtZiAiJChwd2QpLy5mcmFtZXdvcmstY29uZmlnIiBdXTsgdGhlbgogICAgY29uZmlnRmlsZXMrPSgiJChwd2QpLy5mcmFtZXdvcmstY29uZmlnIikKICBmaQogIGlmIFtbIC1mICIke0ZSQU1FV09SS19ST09UX0RJUn0vLmZyYW1ld29yay1jb25maWciIF1dOyB0aGVuCiAgICBjb25maWdGaWxlcys9KCIke0ZSQU1FV09SS19ST09UX0RJUn0vLmZyYW1ld29yay1jb25maWciKQogIGZpCiAgaWYgW1sgLW4gIiR7b3B0aW9uQmFzaEZyYW1ld29ya0NvbmZpZ30iICYmIC1mICIke29wdGlvbkJhc2hGcmFtZXdvcmtDb25maWd9IiBdXTsgdGhlbgogICAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMDM0CiAgICBjb25maWdGaWxlcys9KCIke29wdGlvbkJhc2hGcmFtZXdvcmtDb25maWd9IikKICBmaQogIGNvbmZpZ0ZpbGVzKz0oIiR7b3B0aW9uRW52RmlsZXNbQF19IikKICBjb25maWdGaWxlcys9KCIke2RlZmF1bHRGaWxlc1tAXX0iKQoKICBmb3IgZmlsZSBpbiAiJHtjb25maWdGaWxlc1tAXX0iOyBkbwogICAgIyBzaGVsbGNoZWNrIHNvdXJjZT0vLmZyYW1ld29yay1jb25maWcKICAgIENVUlJFTlRfTE9BREVEX0VOVl9GSUxFPSIke2ZpbGV9IiBzb3VyY2UgIiR7ZmlsZX0iIHx8IHsKICAgICAgTG9nOjpkaXNwbGF5RXJyb3IgIndoaWxlIGxvYWRpbmcgY29uZmlnIGZpbGU6ICR7ZmlsZX0iCiAgICAgIHJldHVybiAxCiAgICB9CiAgZG9uZQp9CgojIEBkZXNjcmlwdGlvbiBhY3RpdmF0ZSBvciBub3QgTG9nOjpkaXNwbGF5KiBhbmQgTG9nOjpsb2cqIGZ1bmN0aW9ucwojIGJhc2VkIG9uIEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgYW5kIEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTAojIGVudmlyb25tZW50IHZhcmlhYmxlcyBsb2FkZWQgYnkgRW52OjpyZXF1aXJlTG9hZAojIHRyeSB0byBjcmVhdGUgbG9nIGZpbGUgYW5kIHJvdGF0ZSBpdCBpZiBuZWNlc3NhcnkKIyBAbm9hcmdzCiMgQHNldCBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgaW50IHRvIE9GRiBsZXZlbCBpZiBCQVNIX0ZSQU1FV09SS19MT0dfRklMRSBpcyBlbXB0eSBvciBub3Qgd3JpdGFibGUKIyBAZW52IEJBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUwgaW50CiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgaW50CiMgQGVudiBCQVNIX0ZSQU1FV09SS19MT0dfRklMRSBTdHJpbmcKIyBAZW52IEJBU0hfRlJBTUVXT1JLX0xPR19GSUxFX01BWF9ST1RBVElPTiBpbnQgZG8gbG9nIHJvdGF0aW9uIGlmID4gMAojIEBleGl0Y29kZSAwIGFsd2F5cyBzdWNjZXNzZnVsCiMgQHN0ZGVyciBkaWFnbm9zdGljcyBpbmZvcm1hdGlvbiBhYm91dCBsb2cgZmlsZSBpcyBkaXNwbGF5ZWQKIyBAcmVxdWlyZSBFbnY6OnJlcXVpcmVMb2FkCiMgQHJlcXVpcmUgVUk6OnJlcXVpcmVUaGVtZQpMb2c6OnJlcXVpcmVMb2FkKCkgewogIGlmIFtbIC16ICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFOi19IiBdXTsgdGhlbgogICAgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMPSR7X19MRVZFTF9PRkZ9CiAgICBleHBvcnQgQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMCiAgZmkKCiAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPiBfX0xFVkVMX09GRikpOyB0aGVuCiAgICBpZiBbWyAhIC1mICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIgXV07IHRoZW4KICAgICAgaWYKICAgICAgICAhIG1rZGlyIC1wICIkKGRpcm5hbWUgIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IikiIDI+L2Rldi9udWxsIHx8CiAgICAgICAgICAhIHRvdWNoIC0tbm8tY3JlYXRlICIke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSIgMj4vZGV2L251bGwKICAgICAgdGhlbgogICAgICAgIEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTD0ke19fTEVWRUxfT0ZGfQogICAgICAgIGVjaG8gLWUgIiR7X19FUlJPUl9DT0xPUn1FUlJPUiAgIC0gRmlsZSAke0JBU0hfRlJBTUVXT1JLX0xPR19GSUxFfSBpcyBub3Qgd3JpdGFibGUke19fUkVTRVRfQ09MT1J9IiA+JjIKICAgICAgZmkKICAgIGVsaWYgW1sgISAtdyAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0iIF1dOyB0aGVuCiAgICAgIEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTD0ke19fTEVWRUxfT0ZGfQogICAgICBlY2hvIC1lICIke19fRVJST1JfQ09MT1J9RVJST1IgICAtIEZpbGUgJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0gaXMgbm90IHdyaXRhYmxlJHtfX1JFU0VUX0NPTE9SfSIgPiYyCiAgICBmaQoKICBmaQoKICBpZiAoKEJBU0hfRlJBTUVXT1JLX0xPR19MRVZFTCA+IF9fTEVWRUxfT0ZGKSk7IHRoZW4KICAgICMgd2lsbCBhbHdheXMgYmUgY3JlYXRlZCBldmVuIGlmIG5vdCBpbiBpbmZvIGxldmVsCiAgICBMb2c6OmxvZ01lc3NhZ2UgIklORk8iICJMb2dnaW5nIHRvIGZpbGUgJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRX0gLSBMb2cgbGV2ZWwgJHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUx9IgogICAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfRklMRV9NQVhfUk9UQVRJT04gPiAwKSk7IHRoZW4KICAgICAgTG9nOjpyb3RhdGUgIiR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEV9IiAiJHtCQVNIX0ZSQU1FV09SS19MT0dfRklMRV9NQVhfUk9UQVRJT059IgogICAgZmkKICBmaQp9CgojIEBkZXNjcmlwdGlvbiBsb2cgbWVzc2FnZSB0byBmaWxlCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6bG9nRXJyb3IoKSB7CiAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPj0gX19MRVZFTF9FUlJPUikpOyB0aGVuCiAgICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotRVJST1J9IiAiJDEiCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gbG9nIG1lc3NhZ2UgdG8gZmlsZQojIEBhcmcgJDEgbWVzc2FnZTpTdHJpbmcgdGhlIG1lc3NhZ2UgdG8gZGlzcGxheQpMb2c6OmxvZ1dhcm5pbmcoKSB7CiAgaWYgKChCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUwgPj0gX19MRVZFTF9XQVJOSU5HKSk7IHRoZW4KICAgIExvZzo6bG9nTWVzc2FnZSAiJHsyOi1XQVJOSU5HfSIgIiQxIgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIFRvIGJlIGNhbGxlZCBiZWZvcmUgbG9nZ2luZyBpbiB0aGUgbG9nIGZpbGUKIyBAYXJnICQxIGZpbGU6c3RyaW5nIGxvZyBmaWxlIG5hbWUKIyBAYXJnICQyIG1heExvZ0ZpbGVzQ291bnQ6aW50IG1heGltdW0gbnVtYmVyIG9mIGxvZyBmaWxlcwpMb2c6OnJvdGF0ZSgpIHsKICBsb2NhbCBmaWxlPSIkMSIKICBsb2NhbCBtYXhMb2dGaWxlc0NvdW50PSIkezI6LTV9IgoKICBpZiBbWyAhIC1mICIke2ZpbGV9IiBdXTsgdGhlbgogICAgTG9nOjpkaXNwbGF5U2tpcHBlZCAiTG9nIGZpbGUgJHtmaWxlfSBkb2Vzbid0IGV4aXN0IHlldCIKICAgIHJldHVybiAwCiAgZmkKICBmb3IgaSBpbiAkKHNlcSAkKChtYXhMb2dGaWxlc0NvdW50IC0gMSkpIC0xIDEpOyBkbwogICAgTG9nOjpkaXNwbGF5SW5mbyAiTG9nIHJvdGF0aW9uICR7ZmlsZX0uJHtpfSB0byAke2ZpbGV9LiQoKGkgKyAxKSkiCiAgICBtdiAiJHtmaWxlfS4ieyIke2l9IiwiJCgoaSArIDEpKSJ9ICY+L2Rldi9udWxsIHx8IHRydWUKICBkb25lCiAgaWYgY3AgIiR7ZmlsZX0iICIke2ZpbGV9LjEiICY+L2Rldi9udWxsOyB0aGVuCiAgICBlY2hvID4iJHtmaWxlfSIgIyByZXNldCBsb2cgZmlsZQogICAgTG9nOjpkaXNwbGF5SW5mbyAiTG9nIHJvdGF0aW9uICR7ZmlsZX0gdG8gJHtmaWxlfS4xIgogIGZpCn0KCiMgQGRlc2NyaXB0aW9uIGVuc3VyZSBjb21tYW5kIHJlYWxwYXRoIGlzIGF2YWlsYWJsZQojIEBleGl0Y29kZSAxIGlmIHJlYWxwYXRoIGNvbW1hbmQgbm90IGF2YWlsYWJsZQojIEBzdGRlcnIgZGlhZ25vc3RpY3MgaW5mb3JtYXRpb24gaXMgZGlzcGxheWVkCkxpbnV4OjpyZXF1aXJlUmVhbHBhdGhDb21tYW5kKCkgewogIEFzc2VydDo6Y29tbWFuZEV4aXN0cyByZWFscGF0aAp9CgojIEBkZXNjcmlwdGlvbiBsb2FkIGNvbG9yIHRoZW1lCiMgQG5vYXJncwojIEBlbnYgQkFTSF9GUkFNRVdPUktfVEhFTUUgU3RyaW5nIHRoZW1lIHRvIHVzZQojIEBleGl0Y29kZSAwIGFsd2F5cyBzdWNjZXNzZnVsClVJOjpyZXF1aXJlVGhlbWUoKSB7CiAgVUk6OnRoZW1lICIke0JBU0hfRlJBTUVXT1JLX1RIRU1FLWRlZmF1bHR9Igp9CgojIEBkZXNjcmlwdGlvbiBjaGVjayBpZiBjb21tYW5kIHNwZWNpZmllZCBleGlzdHMgb3IgcmV0dXJuIDEKIyB3aXRoIGVycm9yIGFuZCBtZXNzYWdlIGlmIG5vdAojCiMgQGFyZyAkMSBjb21tYW5kTmFtZTpTdHJpbmcgb24gd2hpY2ggZXhpc3RlbmNlIG11c3QgYmUgY2hlY2tlZAojIEBhcmcgJDIgaGVscElmTm90RXhpc3RzOlN0cmluZyBhIGhlbHAgY29tbWFuZCB0byBkaXNwbGF5IGlmIHRoZSBjb21tYW5kIGRvZXMgbm90IGV4aXN0CiMKIyBAZXhpdGNvZGUgMSBpZiB0aGUgY29tbWFuZCBzcGVjaWZpZWQgZG9lcyBub3QgZXhpc3QKIyBAc3RkZXJyIGRpYWdub3N0aWMgaW5mb3JtYXRpb24gKyBoZWxwIGlmIHNlY29uZCBhcmd1bWVudCBpcyBwcm92aWRlZApBc3NlcnQ6OmNvbW1hbmRFeGlzdHMoKSB7CiAgbG9jYWwgY29tbWFuZE5hbWU9IiQxIgogIGxvY2FsIGhlbHBJZk5vdEV4aXN0cz0iJDIiCgogICIke0JBU0hfRlJBTUVXT1JLX0NPTU1BTkQ6LWNvbW1hbmR9IiAtdiAiJHtjb21tYW5kTmFtZX0iID4vZGV2L251bGwgMj4vZGV2L251bGwgfHwgewogICAgTG9nOjpkaXNwbGF5RXJyb3IgIiR7Y29tbWFuZE5hbWV9IGlzIG5vdCBpbnN0YWxsZWQsIHBsZWFzZSBpbnN0YWxsIGl0IgogICAgaWYgW1sgLW4gIiR7aGVscElmTm90RXhpc3RzfSIgXV07IHRoZW4KICAgICAgTG9nOjpkaXNwbGF5SW5mbyAiJHtoZWxwSWZOb3RFeGlzdHN9IgogICAgZmkKICAgIHJldHVybiAxCiAgfQogIHJldHVybiAwCn0KCiMgQGRlc2NyaXB0aW9uIERpc3BsYXkgbWVzc2FnZSB1c2luZyBza2lwIGNvbG9yICh5ZWxsb3cpCiMgQGFyZyAkMSBtZXNzYWdlOlN0cmluZyB0aGUgbWVzc2FnZSB0byBkaXNwbGF5CkxvZzo6ZGlzcGxheVNraXBwZWQoKSB7CiAgaWYgKChCQVNIX0ZSQU1FV09SS19ESVNQTEFZX0xFVkVMID49IF9fTEVWRUxfSU5GTykpOyB0aGVuCiAgICBlY2hvIC1lICIke19fU0tJUFBFRF9DT0xPUn1TS0lQUEVEIC0gJHsxfSR7X19SRVNFVF9DT0xPUn0iID4mMgogIGZpCiAgTG9nOjpsb2dTa2lwcGVkICIkMSIKfQoKIyBAZGVzY3JpcHRpb24gbG9hZCBjb2xvcnMgdGhlbWUgY29uc3RhbnRzCiMgQHdhcm5pbmcgaWYgdHR5IG5vdCBvcGVuZWQsIG5vQ29sb3IgdGhlbWUgd2lsbCBiZSBjaG9zZW4KIyBAYXJnICQxIHRoZW1lOlN0cmluZyB0aGUgdGhlbWUgdG8gdXNlIChkZWZhdWx0LCBub0NvbG9yKQojIEBhcmcgJEAgYXJnczpTdHJpbmdbXQojIEBzZXQgX19FUlJPUl9DT0xPUiBTdHJpbmcgaW5kaWNhdGUgZXJyb3Igc3RhdHVzCiMgQHNldCBfX0lORk9fQ09MT1IgU3RyaW5nIGluZGljYXRlIGluZm8gc3RhdHVzCiMgQHNldCBfX1NVQ0NFU1NfQ09MT1IgU3RyaW5nIGluZGljYXRlIHN1Y2Nlc3Mgc3RhdHVzCiMgQHNldCBfX1dBUk5JTkdfQ09MT1IgU3RyaW5nIGluZGljYXRlIHdhcm5pbmcgc3RhdHVzCiMgQHNldCBfX1NLSVBQRURfQ09MT1IgU3RyaW5nIGluZGljYXRlIHNraXBwZWQgc3RhdHVzCiMgQHNldCBfX0RFQlVHX0NPTE9SIFN0cmluZyBpbmRpY2F0ZSBkZWJ1ZyBzdGF0dXMKIyBAc2V0IF9fSEVMUF9DT0xPUiBTdHJpbmcgaW5kaWNhdGUgaGVscCBzdGF0dXMKIyBAc2V0IF9fVEVTVF9DT0xPUiBTdHJpbmcgbm90IHVzZWQKIyBAc2V0IF9fVEVTVF9FUlJPUl9DT0xPUiBTdHJpbmcgbm90IHVzZWQKIyBAc2V0IF9fSEVMUF9USVRMRV9DT0xPUiBTdHJpbmcgdXNlZCB0byBkaXNwbGF5IGhlbHAgdGl0bGUgaW4gaGVscCBzdHJpbmdzCiMgQHNldCBfX0hFTFBfT1BUSU9OX0NPTE9SIFN0cmluZyB1c2VkIHRvIGRpc3BsYXkgaGlnaGxpZ2h0IG9wdGlvbnMgaW4gaGVscCBzdHJpbmdzCiMKIyBAc2V0IF9fUkVTRVRfQ09MT1IgU3RyaW5nIHJlc2V0IGRlZmF1bHQgY29sb3IKIwojIEBzZXQgX19IRUxQX0VYQU1QTEUgU3RyaW5nIHRvIHJlbW92ZQojIEBzZXQgX19IRUxQX1RJVExFIFN0cmluZyB0byByZW1vdmUKIyBAc2V0IF9fSEVMUF9OT1JNQUwgU3RyaW5nIHRvIHJlbW92ZQojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKVUk6OnRoZW1lKCkgewogIGxvY2FsIHRoZW1lPSIkezEtZGVmYXVsdH0iCiAgaWYgW1sgISAiJHt0aGVtZX0iID1+IC1mb3JjZSQgXV0gJiYgISBBc3NlcnQ6OnR0eTsgdGhlbgogICAgdGhlbWU9Im5vQ29sb3IiCiAgZmkKICBjYXNlICIke3RoZW1lfSIgaW4KICAgIGRlZmF1bHQgfCBkZWZhdWx0LWZvcmNlKQogICAgICB0aGVtZT0iZGVmYXVsdCIKICAgICAgOzsKICAgIG5vQ29sb3IpIDs7CiAgICAqKQogICAgICBMb2c6OmZhdGFsICJpbnZhbGlkIHRoZW1lIHByb3ZpZGVkIgogICAgICA7OwogIGVzYWMKICBpZiBbWyAiJHt0aGVtZX0iID0gImRlZmF1bHQiIF1dOyB0aGVuCiAgICBCQVNIX0ZSQU1FV09SS19USEVNRT0iZGVmYXVsdCIKICAgICMgY2hlY2sgY29sb3JzIGFwcGxpY2FibGUgaHR0cHM6Ly9taXNjLmZsb2dpc29mdC5jb20vYmFzaC90aXBfY29sb3JzX2FuZF9mb3JtYXR0aW5nCiAgICBfX0VSUk9SX0NPTE9SPSdcZVszMW0nICAgICAgICAgIyBSZWQKICAgIF9fSU5GT19DT0xPUj0nXGVbNDRtJyAgICAgICAgICAjIHdoaXRlIG9uIGxpZ2h0Qmx1ZQogICAgX19TVUNDRVNTX0NPTE9SPSdcZVszMm0nICAgICAgICMgR3JlZW4KICAgIF9fV0FSTklOR19DT0xPUj0nXGVbMzNtJyAgICAgICAjIFllbGxvdwogICAgX19TS0lQUEVEX0NPTE9SPSdcZVszM20nICAgICAgICMgWWVsbG93CiAgICBfX0RFQlVHX0NPTE9SPSdcZVszN20nICAgICAgICAgIyBHcmV5CiAgICBfX0hFTFBfQ09MT1I9J1xlWzc7NDk7MzNtJyAgICAgIyBCbGFjayBvbiBHb2xkCiAgICBfX1RFU1RfQ09MT1I9J1xlWzEwMG0nICAgICAgICAgIyBMaWdodCBtYWdlbnRhCiAgICBfX1RFU1RfRVJST1JfQ09MT1I9J1xlWzQxbScgICAgIyB3aGl0ZSBvbiByZWQKICAgIF9fSEVMUF9USVRMRV9DT0xPUj0iXGVbMTszN20iICAjIEJvbGQKICAgIF9fSEVMUF9PUFRJT05fQ09MT1I9IlxlWzE7MzRtIiAjIEJsdWUKICAgICMgSW50ZXJuYWw6IHJlc2V0IGNvbG9yCiAgICBfX1JFU0VUX0NPTE9SPSdcZVswbScgIyBSZXNldCBDb2xvcgogICAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTU1LFNDMjAzNAogICAgX19IRUxQX0VYQU1QTEU9IiQoZWNobyAtZSAiXGVbMjs5N20iKSIKICAgICMgc2hlbGxjaGVjayBkaXNhYmxlPVNDMjE1NSxTQzIwMzQKICAgIF9fSEVMUF9USVRMRT0iJChlY2hvIC1lICJcZVsxOzM3bSIpIgogICAgIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTU1LFNDMjAzNAogICAgX19IRUxQX05PUk1BTD0iJChlY2hvIC1lICJcMDMzWzBtIikiCiAgZWxzZQogICAgQkFTSF9GUkFNRVdPUktfVEhFTUU9Im5vQ29sb3IiCiAgICAjIGNoZWNrIGNvbG9ycyBhcHBsaWNhYmxlIGh0dHBzOi8vbWlzYy5mbG9naXNvZnQuY29tL2Jhc2gvdGlwX2NvbG9yc19hbmRfZm9ybWF0dGluZwogICAgX19FUlJPUl9DT0xPUj0nJwogICAgX19JTkZPX0NPTE9SPScnCiAgICBfX1NVQ0NFU1NfQ09MT1I9JycKICAgIF9fV0FSTklOR19DT0xPUj0nJwogICAgX19TS0lQUEVEX0NPTE9SPScnCiAgICBfX0RFQlVHX0NPTE9SPScnCiAgICBfX0hFTFBfQ09MT1I9JycKICAgIF9fVEVTVF9DT0xPUj0nJwogICAgX19URVNUX0VSUk9SX0NPTE9SPScnCiAgICBfX0hFTFBfVElUTEVfQ09MT1I9JycKICAgIF9fSEVMUF9PUFRJT05fQ09MT1I9JycKICAgICMgSW50ZXJuYWw6IHJlc2V0IGNvbG9yCiAgICBfX1JFU0VUX0NPTE9SPScnCiAgICBfX0hFTFBfRVhBTVBMRT0nJwogICAgX19IRUxQX1RJVExFPScnCiAgICBfX0hFTFBfTk9STUFMPScnCiAgZmkKfQoKIyBAZGVzY3JpcHRpb24gY2hlY2sgaWYgdHR5IChpbnRlcmFjdGl2ZSBtb2RlKSBpcyBhY3RpdmUKIyBAbm9hcmdzCiMgQGV4aXRjb2RlIDEgaWYgdHR5IG5vdCBhY3RpdmUKIyBAZW52IE5PTl9JTlRFUkFDVElWRSBpZiAxIGNvbnNpZGVyIGFzIG5vdCBpbnRlcmFjdGl2ZSBldmVuIGlmIGVudmlyb25tZW50IGlzIGludGVyYWN0aXZlCiMgQGVudiBJTlRFUkFDVElWRSBpZiAxIGNvbnNpZGVyIGFzIGludGVyYWN0aXZlIGV2ZW4gaWYgZW52aXJvbm1lbnQgaXMgbm90IGludGVyYWN0aXZlCiMgQHN0ZGVyciBkaWFnbm9zdGljIGluZm9ybWF0aW9uICsgaGVscCBpZiBzZWNvbmQgYXJndW1lbnQgaXMgcHJvdmlkZWQKQXNzZXJ0Ojp0dHkoKSB7CiAgaWYgW1sgIiR7Tk9OX0lOVEVSQUNUSVZFOi0wfSIgPSAiMSIgXV07IHRoZW4KICAgIHJldHVybiAxCiAgZmkKICBpZiBbWyAiJHtJTlRFUkFDVElWRTotMH0iID0gIjEiIF1dOyB0aGVuCiAgICByZXR1cm4gMAogIGZpCiAgW1sgLXQgMSB8fCAtdCAyIF1dCn0KCiMgQGRlc2NyaXB0aW9uIGxvZyBtZXNzYWdlIHRvIGZpbGUKIyBAYXJnICQxIG1lc3NhZ2U6U3RyaW5nIHRoZSBtZXNzYWdlIHRvIGRpc3BsYXkKTG9nOjpsb2dTa2lwcGVkKCkgewogIGlmICgoQkFTSF9GUkFNRVdPUktfTE9HX0xFVkVMID49IF9fTEVWRUxfSU5GTykpOyB0aGVuCiAgICBMb2c6OmxvZ01lc3NhZ2UgIiR7MjotU0tJUFBFRH0iICIkMSIKICBmaQp9CgojIEZVTkNUSU9OUwoKZmFjYWRlX21haW5fZW1iZWRGcmFtZXdvcmtGdW5jdGlvbmJpbkZpbGV0cGwoKSB7CiMgUkVRVUlSRVMKTGludXg6OnJlcXVpcmVFeGVjdXRlZEFzVXNlcgpFbnY6OnJlcXVpcmVMb2FkCkxvZzo6cmVxdWlyZUxvYWQKTGludXg6OnJlcXVpcmVSZWFscGF0aENvbW1hbmQKVUk6OnJlcXVpcmVUaGVtZQpDb21waWxlcjo6RmFjYWRlOjpyZXF1aXJlQ29tbWFuZEJpbkRpcgoKIyBAcmVxdWlyZSBDb21waWxlcjo6RmFjYWRlOjpyZXF1aXJlQ29tbWFuZEJpbkRpcgoKIyBzaGVsbGNoZWNrIGRpc2FibGU9U0MyMTU0LFNDMjAxNgpmdW5jdGlvblRvQ2FsbD0nRGI6OnF1ZXJ5T25lRGF0YWJhc2UnCiIke2Z1bmN0aW9uVG9DYWxsfSIgIiRAIgoKfQoKZmFjYWRlX21haW5fZW1iZWRGcmFtZXdvcmtGdW5jdGlvbmJpbkZpbGV0cGwgIiRAIgo=" Compiler::Embed::extractFileFromBase64 \ "${embed_function_DbQueryOneDatabase}" \ @@ -1350,6 +1373,7 @@ dbScriptAllDatabasesCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1731,11 +1755,11 @@ dbScriptAllDatabasesCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Allows to execute a script on each database of specified mysql server")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Allows to execute a script on each database of specified mysql server")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--jobs|-j ]" "[--bar|-b]" "[--from-dsn|-f ]" "[--database ]" "[--output|-o ]" "[--log-format|-l ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1744,120 +1768,125 @@ dbScriptAllDatabasesCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ script\ that\ will\ be\ executed\ on\ each\ databases) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " [${__HELP_OPTION_COLOR}scriptArguments${__HELP_NORMAL} {list} (optional)]" local -a helpArray # shellcheck disable=SC2054 helpArray=(optional\ parameters\ to\ pass\ to\ the\ script) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--jobs${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-j ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(specify\ the\ number\ of\ db\ to\ query\ in\ parallel) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo ' Default value: 1' echo -e " ${__HELP_OPTION_COLOR}--bar${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-b${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Show\ progress\ as\ a\ progress\ bar.\ In\ the\ bar\ is\ shown:\ %\ of\ jobs\ completed\,\ estimated\ seconds\ left\,\ and\ number\ of\ jobs\ started.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}SCRIPT OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--from-dsn${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-f ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(target\ mysql\ server) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--database ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(if\ provided\ will\ check\ only\ this\ db\,\ otherwise\ script\ will\ be\ executed\ on\ all\ dbs\ of\ mysql\ server) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--output${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-o ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(output\ directory\,\ see\ log-format\ option) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-format${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-l ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(if\ output\ dir\ provided\,\ will\ log\ each\ db\ result\ to\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo ' Default value: none' + echo ' Possible values: none|log' echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}NOTE:${__HELP_NORMAL} the use of output, log-format, verbose options highly depends on the script used @@ -1903,7 +1932,7 @@ ${__HELP_TITLE}USE CASES:${__HELP_NORMAL} echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/doc b/bin/doc index c14e887e..cce6f470 100755 --- a/bin/doc +++ b/bin/doc @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/doc +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/doc # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description checkout usage doc below # # [DockerNamespace usage](DockerUsage.md ':include') @@ -247,6 +270,8 @@ Docker::runBuildContainer() { if [[ "${optionContinuousIntegrationMode}" = "0" ]]; then localDockerRunArgs+=(-v "/tmp:/tmp") fi + localDockerRunArgs+=(-e KEEP_TEMP_FILES="${KEEP_TEMP_FILES}") + localDockerRunArgs+=(-e BATS_FIX_TEST="${BATS_FIX_TEST:-0}") # shellcheck disable=SC2154 Log::displayInfo "Using ${optionVendor}:${optionBashVersion}" @@ -1198,6 +1223,7 @@ docCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1466,11 +1492,11 @@ docCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "generate markdown documentation")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "generate markdown documentation")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--skip-docker-build]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1479,79 +1505,83 @@ docCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(skip\ docker\ image\ build\ if\ option\ provided) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo echo -n -e "${__HELP_TITLE_COLOR}VERSION: ${__RESET_COLOR}" echo '1.0' @@ -1565,7 +1595,7 @@ docCommand() { echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/gitIsAncestorOf b/bin/gitIsAncestorOf index dcb86112..17890304 100755 --- a/bin/gitIsAncestorOf +++ b/bin/gitIsAncestorOf @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/gitIsAncestorOf +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/gitIsAncestorOf # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -911,6 +934,7 @@ gitIsAncestorOfCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1205,11 +1229,11 @@ gitIsAncestorOfCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "check if commit is inside a given branch")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "check if commit is inside a given branch")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1218,84 +1242,88 @@ gitIsAncestorOfCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ branch\ in\ which\ the\ commit\ will\ be\ searched) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}commit${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ commit\ oid\ to\ check) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}EXIT CODES:${__HELP_NORMAL} ${__HELP_OPTION_COLOR}1${__HELP_NORMAL}: if commit does not exists @@ -1313,7 +1341,7 @@ ${__HELP_OPTION_COLOR}2${__HELP_NORMAL}: if commit is not included in given bran echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/gitIsBranch b/bin/gitIsBranch index 695f839c..b9177817 100755 --- a/bin/gitIsBranch +++ b/bin/gitIsBranch @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/gitIsBranch +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/gitIsBranch # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -910,6 +933,7 @@ gitIsBranchCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1188,11 +1212,11 @@ gitIsBranchCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "show an error if branchName is not a known branch")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "show an error if branchName is not a known branch")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1201,79 +1225,83 @@ gitIsBranchCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ branch\ name\ to\ check) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo echo -n -e "${__HELP_TITLE_COLOR}VERSION: ${__RESET_COLOR}" echo '1.0' @@ -1287,7 +1315,7 @@ gitIsBranchCommand() { echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/gitRenameBranch b/bin/gitRenameBranch index edae7127..8ab896d6 100755 --- a/bin/gitRenameBranch +++ b/bin/gitRenameBranch @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/gitRenameBranch +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/gitRenameBranch # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if tty (interactive mode) is active # @noargs # @exitcode 1 if tty not active @@ -948,6 +971,7 @@ gitRenameBranchCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1272,11 +1296,11 @@ gitRenameBranchCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "rename git local branch, push new branch and delete old branch")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "rename git local branch, push new branch and delete old branch")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--assume-yes|--yes|-y]" "[--push|-p]" "[--delete|-d]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1285,101 +1309,105 @@ gitRenameBranchCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ branch\ name\ to\ check) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " [${__HELP_OPTION_COLOR}oldBranchName${__HELP_NORMAL} {single}]" local -a helpArray # shellcheck disable=SC2054 helpArray=(the\ name\ of\ the\ old\ branch\ if\ not\ current\ one) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--assume-yes${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}--yes${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-y${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054,SC2206 mapfile -t helpArray < <(assumeYesHelpCallback) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--push${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-p${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(push\ the\ new\ branch) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--delete${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-d${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(delete\ the\ old\ remote\ branch) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}EXIT CODES:${__HELP_NORMAL} ${__HELP_OPTION_COLOR}1${__HELP_NORMAL} : if current directory is not a git repository @@ -1406,7 +1434,7 @@ ${__HELP_OPTION_COLOR}9${__HELP_NORMAL} : if failed to push the new branch""" echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 @@ -1414,8 +1442,8 @@ ${__HELP_OPTION_COLOR}9${__HELP_NORMAL} : if failed to push the new branch""" } assumeYesHelpCallback() { - echo "do not ask for confirmation (use with caution)" $'\n' - echo ' Automatic yes to prompts; assume "y" as answer to all prompts' $'\n' + echo "do not ask for confirmation (use with caution)" + echo ' Automatic yes to prompts; assume "y" as answer to all prompts' echo ' and run non-interactively.' } diff --git a/bin/installRequirements b/bin/installRequirements index 161d9568..945a7c8a 100755 --- a/bin/installRequirements +++ b/bin/installRequirements @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/installRequirements +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/installRequirements # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -110,123 +110,146 @@ Array::join() { # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -1022,6 +1045,7 @@ installRequirementsCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1278,11 +1302,11 @@ installRequirementsCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "installs requirements")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "installs requirements")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1291,72 +1315,76 @@ installRequirementsCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}INSTALLS REQUIREMENTS:${__HELP_NORMAL} - fchastanet/bash-tools-framework @@ -1375,7 +1403,7 @@ ${__HELP_TITLE}INSTALLS REQUIREMENTS:${__HELP_NORMAL} echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/mysql2puml b/bin/mysql2puml index b0ee2a1c..c22dd18d 100755 --- a/bin/mysql2puml +++ b/bin/mysql2puml @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/mysql2puml +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/mysql2puml # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -110,123 +110,146 @@ Array::contains() { # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description get absolute conf file from specified conf folder deduced using these rules # * from absolute file (ignores and ) # * relative to where script is executed (ignores and ) @@ -1112,6 +1135,7 @@ mysql2pumlCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1404,11 +1428,11 @@ mysql2pumlCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "convert mysql dump sql schema to plantuml format")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "convert mysql dump sql schema to plantuml format")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--skin ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1417,14 +1441,14 @@ mysql2pumlCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(sql\ filepath\ to\ parse\ \(read\ from\ stdin\ if\ not\ provided\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--skin ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(header\ configuration\ of\ the\ plant\ uml\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo ' Default value: default' echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" @@ -1432,72 +1456,76 @@ mysql2pumlCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}EXAMPLE 1:${__HELP_NORMAL} ${__HELP_EXAMPLE}mysql2puml dump.dql${__HELP_NORMAL} @@ -1526,7 +1554,7 @@ ${__HELP_TITLE}LIST OF AVAILABLE SKINS:${__HELP_NORMAL} echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/upgradeGithubRelease b/bin/upgradeGithubRelease index 20e4b8b1..3c5dc3a5 100755 --- a/bin/upgradeGithubRelease +++ b/bin/upgradeGithubRelease @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/upgradeGithubRelease +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/upgradeGithubRelease # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # Checks if file can be created in folder # @@ -1238,6 +1261,7 @@ upgradeGithubReleaseCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1599,11 +1623,11 @@ upgradeGithubReleaseCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "retrieve latest binary release from github and install it")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "retrieve latest binary release from github and install it")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--version-arg ]" "[--current-version|-c ]" "[--exact-version|-e ]" "[--minimal-version|-m ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1611,108 +1635,112 @@ upgradeGithubReleaseCommand() { echo -e " ${__HELP_OPTION_COLOR}targetFile${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 - helpArray=(the\ binary\ downloaded\ will\ e\ written\ to\ this\ file\ path.\ Ensure\ the\ path\ is\ writable.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=($'the binary downloaded will be written to this file path.\n\n Ensure the path is writable.') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}githubUrlPattern${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 - helpArray=($'the url pattern to use to download the binary, see examples below. \n @version@ is template variable that will be replaced by the latest \n version tag found on github.') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=($'the url pattern to use to download the binary, see examples below.\n\n @version@ is template variable that will be replaced by the latest \n\n version tag found on github.') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}VERSION MANAGEMENT:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--version-arg ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=($'The argument that will be provided to the currently installed binary\nto check the version of the software. See options constraints below.') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=($'The argument that will be provided to the currently installed binary\n\n to check the version of the software. \n\n See options constraints below.') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo ' Default value: --version' echo -e " ${__HELP_OPTION_COLOR}--current-version${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-c ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=($'Sometimes the command to retrieve the version is complicated.\nSome command needs you to parse json or other commands provides\nmultiple sub command versions. In this case you can provide the\nversion you currently have, see examples below.\nSee options constraints below.') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=($'Sometimes the command to retrieve the version is complicated. \n\n Some command needs you to parse json or other commands provides multiple \n\n sub command versions. In this case you can provide the version you \n\n currently have, see examples below. \n\n See options constraints below.') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--exact-version${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-e ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=($'if provided and currently installed binary is not this exactVersion,\n This exact version of the binary will be installed.\n See options constraints below.') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=($'if provided and currently installed binary is not this exactVersion,\n\n This exact version of the binary will be installed.\n\n See options constraints below.') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--minimal-version${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-m ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=($'if provided and currently installed binary is below this minimalVersion,\na new version of the binary will be installed.\nIf this argument is not provided, the latest binary is unconditionally downloaded from github.\nSee options constraints below.') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=($'if provided and currently installed binary is below this \n\n minimalVersion, a new version of the binary will be installed. \n\n If this argument is not provided, the latest binary is unconditionally \n\n downloaded from github. \n\n See options constraints below.') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}OPTIONS CONSTRAINTS:${__HELP_NORMAL} @@ -1764,7 +1792,7 @@ ${__HELP_EXAMPLE}upgradeGithubRelease /usr/local/bin/oq --exact-version 1.3.4 -- echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/waitForIt b/bin/waitForIt index 2bc03784..c2dd886e 100755 --- a/bin/waitForIt +++ b/bin/waitForIt @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/waitForIt +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/waitForIt # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -110,123 +110,146 @@ Array::contains() { # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if command specified exists or return 1 # with error and message if not # @@ -971,6 +994,7 @@ waitForItCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1322,11 +1346,11 @@ waitForItCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "wait for host:port to be available")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "wait for host:port to be available")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--timeout|-t ]" "--host|-i " "--port|-p " "[--algorithm|--algo ]" "[--exec-command-on-success-only|--strict|-s]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1335,107 +1359,111 @@ waitForItCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(Execute\ command\ with\ args\ after\ the\ test\ finishes\ or\ exit\ with\ status\ code\ if\ no\ command\ provided.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--timeout${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-t ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Timeout\ in\ seconds\,\ zero\ for\ no\ timeout.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo ' Default value: 15' echo -e " ${__HELP_OPTION_COLOR}--host${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-i ${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Host\ or\ IP\ under\ test.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--port${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-p ${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 helpArray=(TCP\ port\ under\ test.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--algorithm${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}--algo ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=($'Algorithm to use Check algorithms list below. \n (default: automatic selection based on commands availability and timeout option value).') - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--exec-command-on-success-only${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}--strict${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-s${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Only\ execute\ sub-command\ if\ the\ test\ succeeds.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}EXIT STATUS CODES:${__HELP_NORMAL} ${__HELP_OPTION_COLOR}0${__HELP_NORMAL}: the host/port is available @@ -1462,7 +1490,7 @@ ${__HELP_OPTION_COLOR}whileLoopWithTcp${__HELP_NORMAL}: timeout command simulate echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/bin/waitForMysql b/bin/waitForMysql index 6ac9b60a..50f512de 100755 --- a/bin/waitForMysql +++ b/bin/waitForMysql @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/waitForMysql +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/waitForMysql # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description check if command specified exists or return 1 # with error and message if not # @@ -939,6 +962,7 @@ waitForMysqlCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1283,11 +1307,11 @@ waitForMysqlCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "wait for mysql to be ready")" + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "wait for mysql to be ready")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--timeout|-t ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1296,29 +1320,29 @@ waitForMysqlCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(Mysql\ host\ name) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}mysqlPort${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Mysql\ port) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}mysqlUserArg${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Mysql\ user\ name) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}mysqlPasswordArg${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Mysql\ password) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--timeout${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-t ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Timeout\ in\ seconds\,\ zero\ for\ no\ timeout.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo ' Default value: 15' echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" @@ -1326,72 +1350,76 @@ waitForMysqlCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e """ ${__HELP_TITLE}EXIT STATUS CODES:${__HELP_NORMAL} ${__HELP_OPTION_COLOR}0${__HELP_NORMAL}: mysql is available @@ -1410,7 +1438,7 @@ ${__HELP_OPTION_COLOR}2${__HELP_NORMAL}: timeout reached""" echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/conf/dbScripts/extractData b/conf/dbScripts/extractData index 2a801303..b53f7701 100755 --- a/conf/dbScripts/extractData +++ b/conf/dbScripts/extractData @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/conf/dbScripts/extractData +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/conf/dbScripts/extractData # FACADE # ensure that no user aliases could interfere with diff --git a/install b/install index 3c177e36..02423c2e 100755 --- a/install +++ b/install @@ -5,7 +5,7 @@ # @generated ############################################################################### # shellcheck disable=SC2288,SC2034 -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/install +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/install # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=. # FACADE @@ -94,123 +94,146 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument -# The algorithm will try not to cut the array element if can +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. # # @arg $1 glue:String # @arg $2 maxLineLength:int # @arg $3 indentNextLine:int # @arg $@ array:String[] -Array::wrap() { +Array::wrap2() { local glue="${1-}" - local -i glueLength=0 + local -i glueLength="${#glue}" shift || true local -i maxLineLength=$1 shift || true local -i indentNextLine=$1 + shift || true local indentStr="" if ((indentNextLine > 0)); then indentStr="$(head -c "${indentNextLine}" 0)); do - argNoAnsi="$(echo "${arg%%*( )}" | Filters::removeAnsiCodes)" - ((argNoAnsiLength = ${#argNoAnsi})) || true - if (($# < 1 && argNoAnsiLength == 0)); then - break + eatNextSpaces() { + if [[ "${currentChar}" != [[:space:]] ]]; then + ((i--)) || true + return 0 fi - if [[ "${arg}" = $'\n' ]]; then - if [[ "${needEcho}" = "1" ]]; then - needEcho="0" + for (( ; i < textLength; i++)); do + if [[ "${text:${i}:1}" != [[:space:]] ]]; then + ((i--)) || true + break fi - echo "" - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - shift || return 0 - arg="$1" - elif ((argNoAnsiLength < maxLineLength - currentLineLength - glueLength)); then - # arg can be stored as a whole on current line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + done + } + printCurrentLine() { + echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + ((isNewline = 1)) + currentLine="${indentStr}" + ((currentLineLength = indentNextLine)) || true + } + nextLine() { + printCurrentLine + eatNextSpaces + } + local currentLine currentChar ansiCode + local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 + local text="" + local arg="" + while (($# > 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi - echo -e -n "${arg}" | sed 's/[\t ]*$//g' - needEcho="1" - ((currentLineLength += argNoAnsiLength)) - ((glueLength = ${#glue})) || true - shift || return 0 - arg="$1" + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true else - if ((argNoAnsiLength >= (maxLineLength - indentNextLine))); then - if ((currentLineLength == 0 && firstLine == 0)); then - echo -n "${indentStr}" - ((currentLineLength += indentNextLine)) - fi - # arg can be stored on a whole line - if ((glueLength > 0)); then - echo -e -n "${glue}" - ((currentLineLength += glueLength)) + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" fi - local -i length - ((length = maxLineLength - currentLineLength)) || true - echo -e "${arg:0:${length}}" | sed 's/[\t ]*$//g' - ((currentLineLength = 0)) || true - ((glueLength = 0)) || true - arg="${arg:${length}}" - needEcho="0" else - # arg cannot be stored on a whole line, so we add it on next line as a whole - echo - echo -e -n "${indentStr}${arg}" | sed 's/[\t ]*$//g' - ((glueLength = ${#glue})) || true - ((currentLineLength = argNoAnsiLength)) - arg="" # allows to go to next arg - needEcho="1" - fi - if [[ -z "${arg}" ]]; then - shift || return 0 - arg="$1" + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi fi - fi - ((firstLine = 0)) || true + done done - if [[ "${needEcho}" = "1" ]]; then - echo + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine fi } -#set -x -#Array::wrap ":" 40 0 "Lorem ipsum dolor sit amet," "consectetur adipiscing elit." "Curabitur ac elit id massa" "condimentum finibus." - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -910,6 +933,7 @@ installCommand() { optionNoColor="0" local -i options_parse_optionParsedCountOptionNoColor ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" local -i options_parse_optionParsedCountOptionTheme ((options_parse_optionParsedCountOptionTheme = 0)) || true optionHelp="0" @@ -1166,13 +1190,13 @@ installCommand() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" elif [[ "${options_parse_cmd}" = "help" ]]; then - echo -e "$(Array::wrap " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Install dependent softwares and configuration needed to use bash-tools + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Install dependent softwares and configuration needed to use bash-tools - GNU parallel - Install default configuration files")" echo - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]")" - echo -e "$(Array::wrap " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "${SCRIPT_NAME}" \ "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" echo @@ -1181,72 +1205,76 @@ installCommand() { local -a helpArray # shellcheck disable=SC2054 helpArray=(use\ alternate\ bash\ framework\ configuration.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ configuration) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" local -a helpArray # shellcheck disable=SC2054 helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(choose\ color\ theme\ \(default\,\ default-force\ or\ noColor\)\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Default value: default' + echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Display\ this\ command\ help) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Print\ version\ information\ and\ quit) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(Set\ log\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(Set\ log\ file) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=(set\ display\ level\ \(one\ of\ OFF\,\ ERROR\,\ WARNING\,\ INFO\,\ DEBUG\,\ TRACE\ value\)) - echo -e " $(Array::wrap " " 76 4 "${helpArray[@]}")" + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE' echo echo -n -e "${__HELP_TITLE_COLOR}VERSION: ${__RESET_COLOR}" echo '1.0' @@ -1260,7 +1288,7 @@ installCommand() { echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" echo 'MIT License' echo - Array::wrap ' ' 76 4 "$(copyrightCallback)" + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" else Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" return 1 diff --git a/kics.config b/kics.config index 07532ee4..7484fca7 100644 --- a/kics.config +++ b/kics.config @@ -1,2 +1,2 @@ -exclude-paths: - - "vendor/" +--- +exclude-paths: "vendor/**" diff --git a/src/_binaries/Converters/mysql2puml.options.tpl b/src/_binaries/Converters/mysql2puml.options.tpl index ee06be75..36da7671 100644 --- a/src/_binaries/Converters/mysql2puml.options.tpl +++ b/src/_binaries/Converters/mysql2puml.options.tpl @@ -4,6 +4,7 @@ declare commandFunctionName="mysql2pumlCommand" declare optionSkinDefault="default" declare help="convert mysql dump sql schema to plantuml format" # shellcheck disable=SC2016 +# kics-scan disable=487f4be7-3fd9-4506-a07a-eae252180c08 declare longDescription=''' ${__HELP_TITLE}EXAMPLE 1:${__HELP_NORMAL} ${__HELP_EXAMPLE}mysql2puml dump.dql${__HELP_NORMAL} diff --git a/src/_binaries/Converters/mysql2puml.sh b/src/_binaries/Converters/mysql2puml.sh index 13723c29..eceb16bf 100755 --- a/src/_binaries/Converters/mysql2puml.sh +++ b/src/_binaries/Converters/mysql2puml.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/mysql2puml +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/mysql2puml # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/Converters/testsData/mysql2puml.help.txt b/src/_binaries/Converters/testsData/mysql2puml.help.txt index 570d3da5..dc8a81da 100644 --- a/src/_binaries/Converters/testsData/mysql2puml.help.txt +++ b/src/_binaries/Converters/testsData/mysql2puml.help.txt @@ -1,10 +1,11 @@ DESCRIPTION: convert mysql dump sql schema to plantuml format USAGE: mysql2puml [OPTIONS] [ARGUMENTS] -USAGE: mysql2puml [--skin ] [--bash-framework-config ] - [--config] [--verbose|-v] [-vv] [-vvv] [--env-file ] [--no-color] - [--theme ] [--help|-h] [--version] [--quiet|-q] [--log-level ] - [--log-file ] [--display-level ] +USAGE: mysql2puml [--skin ] + [--bash-framework-config ] [--config] [--verbose|-v] [-vv] [-vvv] + [--env-file ] [--no-color] [--theme ] [--help|-h] [--version] + [--quiet|-q] [--log-level ] [--log-file ] + [--display-level ] ARGUMENTS: [inputSqlFile {single}] @@ -32,8 +33,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -41,11 +44,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE EXAMPLE 1: mysql2puml dump.dql diff --git a/src/_binaries/DbImport/dbImport.options.tpl b/src/_binaries/DbImport/dbImport.options.tpl index ed9fcd87..e8977fef 100644 --- a/src/_binaries/DbImport/dbImport.options.tpl +++ b/src/_binaries/DbImport/dbImport.options.tpl @@ -26,7 +26,7 @@ ${__HELP_EXAMPLE}TODO${__HELP_NORMAL} ${__HELP_TITLE}Example 2: import from S3${__HELP_NORMAL} ${__HELP_EXAMPLE}TODO${__HELP_NORMAL}''' # shellcheck disable=SC2116 -declare defaultFromDsnHelp=$'dsn to use for source database\n\ +declare defaultFromDsnHelp=$'dsn to use for source database\n this option is incompatible with -a|--from-aws option' % diff --git a/src/_binaries/DbImport/dbImport.sh b/src/_binaries/DbImport/dbImport.sh index 02443200..13a0b5ab 100755 --- a/src/_binaries/DbImport/dbImport.sh +++ b/src/_binaries/DbImport/dbImport.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbImport +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbImport # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/DbImport/dbImportProfile.bats b/src/_binaries/DbImport/dbImportProfile.bats index 9a40d19f..d7a483b6 100755 --- a/src/_binaries/DbImport/dbImportProfile.bats +++ b/src/_binaries/DbImport/dbImportProfile.bats @@ -118,7 +118,8 @@ function Database::dbImportProfile::remote_db_fully_functional_ratio_20 { #@test run "${binDir}/dbImportProfile" --verbose -f default.local -r 20 fromDb 2>&1 [[ -f "${HOME}/tableSizeQuery.sql" ]] - assert_lines_count 3 + + assert_lines_count 3 || assert_output "" assert_line --index 0 --partial "INFO - Using from dsn" assert_line --index 1 --partial "Profile generated - 2/3 tables bigger than 20% of max table size (29MB) automatically excluded" assert_line --index 2 --partial "INFO - File saved in" diff --git a/src/_binaries/DbImport/dbImportProfile.sh b/src/_binaries/DbImport/dbImportProfile.sh index bc4a7c53..559d1ee9 100755 --- a/src/_binaries/DbImport/dbImportProfile.sh +++ b/src/_binaries/DbImport/dbImportProfile.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbImportProfile +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbImportProfile # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/DbImport/dbImportStream.sh b/src/_binaries/DbImport/dbImportStream.sh index 5e8af990..e716c4eb 100755 --- a/src/_binaries/DbImport/dbImportStream.sh +++ b/src/_binaries/DbImport/dbImportStream.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbImportStream +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbImportStream # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/DbImport/testsData/auto_default.local_fromDb_20.sh b/src/_binaries/DbImport/testsData/auto_default.local_fromDb_20.sh index 33f38ff5..a332f1c1 100755 --- a/src/_binaries/DbImport/testsData/auto_default.local_fromDb_20.sh +++ b/src/_binaries/DbImport/testsData/auto_default.local_fromDb_20.sh @@ -4,5 +4,5 @@ cat | grep -v '^table1$' | # table size 29MB grep -v '^table2$' | # table size 10MB -# grep -v '^table3$' | # table size 4MB -cat + # grep -v '^table3$' | # table size 4MB + cat diff --git a/src/_binaries/DbImport/testsData/auto_default.local_fromDb_70.sh b/src/_binaries/DbImport/testsData/auto_default.local_fromDb_70.sh index 8dcd2195..a6919c07 100755 --- a/src/_binaries/DbImport/testsData/auto_default.local_fromDb_70.sh +++ b/src/_binaries/DbImport/testsData/auto_default.local_fromDb_70.sh @@ -3,6 +3,6 @@ # cat represents the whole list of tables cat | grep -v '^table1$' | # table size 29MB -# grep -v '^table2$' | # table size 10MB -# grep -v '^table3$' | # table size 4MB -cat + # grep -v '^table2$' | # table size 10MB + # grep -v '^table3$' | # table size 4MB + cat diff --git a/src/_binaries/DbImport/testsData/dbImport.help.txt b/src/_binaries/DbImport/testsData/dbImport.help.txt index d0d27835..1ec2c9cb 100644 --- a/src/_binaries/DbImport/testsData/dbImport.help.txt +++ b/src/_binaries/DbImport/testsData/dbImport.help.txt @@ -1,13 +1,15 @@ -DESCRIPTION: Import source db into target db using eventual table filter +DESCRIPTION: +Import source db into target db using eventual table filter USAGE: dbImport [OPTIONS] [ARGUMENTS] -USAGE: dbImport [--profile|-p ] [--tables ] - [--from-dsn|-f ] [--skip-schema|-s] [--from-aws|-a ] - [--target-dsn|-t ] [--character-set|-c ] - [--collation-name|-o ] [--bash-framework-config ] [--config] - [--verbose|-v] [-vv] [-vvv] [--env-file ] [--no-color] - [--theme ] [--help|-h] [--version] [--quiet|-q] [--log-level ] - [--log-file ] [--display-level ] +USAGE: dbImport [--profile|-p ] + [--tables ] [--from-dsn|-f ] + [--skip-schema|-s] [--from-aws|-a ] [--target-dsn|-t ] + [--character-set|-c ] [--collation-name|-o ] + [--bash-framework-config ] [--config] [--verbose|-v] [-vv] [-vvv] + [--env-file ] [--no-color] [--theme ] [--help|-h] [--version] + [--quiet|-q] [--log-level ] [--log-file ] + [--display-level ] ARGUMENTS: fromDbName {single} (mandatory) @@ -18,22 +20,23 @@ PROFILE OPTIONS: --profile, -p  {single} - the name of the profile to use in order to include or exclude tables (if not - specified in default.sh from 'User profiles directory' if exists or 'De - fault profiles directory') + the name of the profile to use in order to include or exclude tables + (if not specified in default.sh from 'User profiles directory' if exists + or 'Default profiles directory') --tables  {single} import only table specified in the list. If aws mode, ignore profile option FROM OPTIONS: --from-dsn, -f  {single} dsn to use for source database - this option is incompatible with -a|--from-aws option + this option is incompatible with -a|--from-aws option --skip-schema, -s {single} avoid to import the schema --from-aws, -a  {single} db dump will be downloaded from s3 instead of using remote db. The value is the name of the file without s3 location (Only .gz or tar.gz f - ile are supported). This option is incompatible with -f|--from-dsn option + ile are supported). This option is incompatible with -f|--from-dsn optio + n TARGET OPTIONS: --target-dsn, -t  {single} @@ -61,8 +64,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -70,11 +75,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE Default profiles directory: /bash/conf/dbImportProfiles diff --git a/src/_binaries/DbImport/testsData/dbImportProfile.help.txt b/src/_binaries/DbImport/testsData/dbImportProfile.help.txt index eed43c23..543e137e 100644 --- a/src/_binaries/DbImport/testsData/dbImportProfile.help.txt +++ b/src/_binaries/DbImport/testsData/dbImportProfile.help.txt @@ -1,11 +1,12 @@ DESCRIPTION: generate optimized profiles to be used by dbImport USAGE: dbImportProfile [OPTIONS] [ARGUMENTS] -USAGE: dbImportProfile [--profile|-p ] [--from-dsn|-f ] - [--ratio|-r ] [--bash-framework-config ] [--config] - [--verbose|-v] [-vv] [-vvv] [--env-file ] [--no-color] - [--theme ] [--help|-h] [--version] [--quiet|-q] [--log-level ] - [--log-file ] [--display-level ] +USAGE: dbImportProfile [--profile|-p ] + [--from-dsn|-f ] [--ratio|-r ] + [--bash-framework-config ] [--config] [--verbose|-v] [-vv] [-vvv] + [--env-file ] [--no-color] [--theme ] [--help|-h] [--version] + [--quiet|-q] [--log-level ] [--log-file ] + [--display-level ] ARGUMENTS: fromDbName {single} (mandatory) @@ -21,8 +22,8 @@ --ratio, -r  {single} define the ratio to use (0 to 100% - default 70). 0 means profile will filt er out all the tables. 100 means profile will keep all the tables. Eg: - 70 means that tables with size(table+index) that are greater that 70% o - f the max table size will be excluded. + 70 means that tables with size(table+index) that are greater that 70% of + the max table size will be excluded. GLOBAL OPTIONS: --bash-framework-config  {single} @@ -41,8 +42,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -50,11 +53,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE Default profiles directory: /bash/conf/dbImportProfiles diff --git a/src/_binaries/DbImport/testsData/dbImportStream.help.txt b/src/_binaries/DbImport/testsData/dbImportStream.help.txt index 14739ed6..6c9ee1cb 100644 --- a/src/_binaries/DbImport/testsData/dbImportStream.help.txt +++ b/src/_binaries/DbImport/testsData/dbImportStream.help.txt @@ -16,9 +16,9 @@ PROFILE OPTIONS: --profile, -p  {single} - the name of the profile to use in order to include or exclude tables (if not - specified in default.sh from 'User profiles directory' if exists or 'De - fault profiles directory') + the name of the profile to use in order to include or exclude tables + (if not specified in default.sh from 'User profiles directory' if exists + or 'Default profiles directory') --tables  {single} import only table specified in the list. If aws mode, ignore profile option @@ -45,8 +45,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -54,11 +56,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE Default profiles directory: /bash/conf/dbImportProfiles diff --git a/src/_binaries/DbQueryAllDatabases/dbQueryAllDatabases.sh b/src/_binaries/DbQueryAllDatabases/dbQueryAllDatabases.sh index 4d54b8cc..1d5af64d 100755 --- a/src/_binaries/DbQueryAllDatabases/dbQueryAllDatabases.sh +++ b/src/_binaries/DbQueryAllDatabases/dbQueryAllDatabases.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbQueryAllDatabases +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbQueryAllDatabases # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # EMBED Db::queryOneDatabase as dbQueryOneDatabase diff --git a/src/_binaries/DbQueryAllDatabases/testsData/dbQueryAllDatabases.help.txt b/src/_binaries/DbQueryAllDatabases/testsData/dbQueryAllDatabases.help.txt index 8c57c76a..975d868c 100644 --- a/src/_binaries/DbQueryAllDatabases/testsData/dbQueryAllDatabases.help.txt +++ b/src/_binaries/DbQueryAllDatabases/testsData/dbQueryAllDatabases.help.txt @@ -1,5 +1,6 @@ -DESCRIPTION: Execute a query on multiple databases in order to generate a report - with tsv format, query can be parallelized on multiple databases +DESCRIPTION: +Execute a query on multiple databases in order to generate a report with tsv for +mat, query can be parallelized on multiple databases USAGE: dbQueryAllDatabases [OPTIONS] [ARGUMENTS] USAGE: dbQueryAllDatabases [--jobs|-j ] [--bar|-b] @@ -11,10 +12,10 @@ ARGUMENTS: argQuery {single} (mandatory) - Query to execute - - , try to execute the mysql query provided by the file - - , search for query file in queries directory (see below) - - else the argument is interpreted as query string + Query to execute - , try to execute the mysql query provided by the f + ile + - , search for query file in queries directory (see below) + - else the argument is interpreted as query string OPTIONS: --jobs, -j  {single} @@ -48,8 +49,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -57,11 +60,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE LIST OF AVAILABLE DSN: - dsn_local diff --git a/src/_binaries/DbScriptAllDatabases/dbScriptAllDatabases.sh b/src/_binaries/DbScriptAllDatabases/dbScriptAllDatabases.sh index 2f718e88..eb9f508d 100755 --- a/src/_binaries/DbScriptAllDatabases/dbScriptAllDatabases.sh +++ b/src/_binaries/DbScriptAllDatabases/dbScriptAllDatabases.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/dbScriptAllDatabases +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/dbScriptAllDatabases # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # EMBED Db::queryOneDatabase as dbQueryOneDatabase diff --git a/src/_binaries/DbScriptAllDatabases/extractData.sh b/src/_binaries/DbScriptAllDatabases/extractData.sh index 76609436..a32f2b7a 100755 --- a/src/_binaries/DbScriptAllDatabases/extractData.sh +++ b/src/_binaries/DbScriptAllDatabases/extractData.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/conf/dbScripts/extractData +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/conf/dbScripts/extractData # FACADE # shellcheck disable=SC2154 diff --git a/src/_binaries/DbScriptAllDatabases/testsData/dbScriptAllDatabases.help.txt b/src/_binaries/DbScriptAllDatabases/testsData/dbScriptAllDatabases.help.txt index 4e8b2e67..ce5564d4 100644 --- a/src/_binaries/DbScriptAllDatabases/testsData/dbScriptAllDatabases.help.txt +++ b/src/_binaries/DbScriptAllDatabases/testsData/dbScriptAllDatabases.help.txt @@ -34,6 +34,7 @@ Allows to execute a script on each database of specified mysql server --log-format, -l  {single} if output dir provided, will log each db result to log file Default value: none + Possible values: none|log GLOBAL OPTIONS: --bash-framework-config  {single} @@ -52,8 +53,10 @@ Allows to execute a script on each database of specified mysql server --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -61,11 +64,13 @@ Allows to execute a script on each database of specified mysql server --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE NOTE: the use of output, log-format, verbose options highly depends on the script used diff --git a/src/_binaries/Docker/cli.options.tpl b/src/_binaries/Docker/cli.options.tpl index 81277e2e..1898170b 100644 --- a/src/_binaries/Docker/cli.options.tpl +++ b/src/_binaries/Docker/cli.options.tpl @@ -70,36 +70,36 @@ Options::generateCommand "${options[@]}" containerArgHelpCallback() { Conf::load "cliProfiles" "default" echo "container should be the name of a profile from profile list," - echo "check containers list below." $'\n' - echo "If not provided, it will load the container specified in default configuration." $'\n' - echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" $'\n' + echo "check containers list below." + echo "If not provided, it will load the container specified in default configuration." + echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" echo "Default container: ${__HELP_OPTION_COLOR}${finalContainerArg}${__HELP_NORMAL}" } userArgHelpCallback() { Conf::load "cliProfiles" "default" echo "user to connect on this container" $'\n' - echo "Default user: ${__HELP_OPTION_COLOR}${finalUserArg}${__HELP_NORMAL}" $'\n' - echo " loaded from profile selected as first arg" $'\n' + echo "Default user: ${__HELP_OPTION_COLOR}${finalUserArg}${__HELP_NORMAL}" + echo " loaded from profile selected as first arg" echo " or deduced from default configuration." $'\n' - echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" + echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" $'\n' echo "if first arg is not a profile" } commandArgHelpCallback() { Conf::load "cliProfiles" "default" echo "The command to execute" $'\n' - echo "Default command: ${__HELP_OPTION_COLOR}${finalCommandArg[*]}${__HELP_NORMAL}" $'\n' - echo " loaded from profile selected as first arg" $'\n' - echo " or deduced from default configuration." $'\n' - echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" + echo "Default command: ${__HELP_OPTION_COLOR}${finalCommandArg[*]}${__HELP_NORMAL}" + echo " loaded from profile selected as first arg" + echo " or deduced from default configuration." + echo "Default configuration: ${__HELP_OPTION_COLOR}${containerArg}${__HELP_NORMAL}" $'\n' echo "if first arg is not a profile" } optionHelpCallback() { local containers # shellcheck disable=SC2046 - containers="$(Array::wrap ", " 80 0 $(docker ps --format '{{.Names}}'))" + containers="$(Array::wrap2 ", " 80 0 $(docker ps --format '{{.Names}}'))" local profilesList="" Conf::load "cliProfiles" "default" diff --git a/src/_binaries/Docker/cli.sh b/src/_binaries/Docker/cli.sh index 6e0f8aaf..376c78e2 100755 --- a/src/_binaries/Docker/cli.sh +++ b/src/_binaries/Docker/cli.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/cli +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/cli # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/Docker/testsData/cli.help.txt b/src/_binaries/Docker/testsData/cli.help.txt index 8fd39f97..db28871b 100644 --- a/src/_binaries/Docker/testsData/cli.help.txt +++ b/src/_binaries/Docker/testsData/cli.help.txt @@ -1,31 +1,37 @@ DESCRIPTION: easy connection to docker container USAGE: cli [OPTIONS] [ARGUMENTS] -USAGE: cli [--bash-framework-config ] [--config] [--verbose|-v] [-vv] - [-vvv] [--env-file ] [--no-color] [--theme ] [--help|-h] - [--version] [--quiet|-q] [--log-level ] [--log-file ] - [--display-level ] +USAGE: cli [--bash-framework-config ] [--config] + [--verbose|-v] [-vv] [-vvv] [--env-file ] [--no-color] + [--theme ] [--help|-h] [--version] [--quiet|-q] [--log-level ] + [--log-file ] [--display-level ] ARGUMENTS: [container {single}] container should be the name of a profile from profile list, check containers list below. If not provided, it will load the container specified in default configu - ration. - Default configuration: default + ration. Default configuration: default Default container: project-apache2 [user {single}] user to connect on this container + Default user: www-data loaded from profile selected as first arg or deduced from default configuration. - Default configuration: default if first arg is not a profile + + Default configuration: default + + if first arg is not a profile [commandArg {single}] The command to execute + Default command: /bin/bash loaded from profile selected as first arg or deduced from default configuration. - Default configuration: default if first arg is not a profile + Default configuration: default + + if first arg is not a profile GLOBAL OPTIONS: --bash-framework-config  {single} @@ -44,8 +50,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -53,11 +61,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE AVAILABLE PROFILES (from /bash/conf/cliProfiles) This list can be overridden in home/.bash-tools/cliProfiles diff --git a/src/_binaries/Git/gitIsAncestorOf.sh b/src/_binaries/Git/gitIsAncestorOf.sh index 66173eb0..86020d89 100755 --- a/src/_binaries/Git/gitIsAncestorOf.sh +++ b/src/_binaries/Git/gitIsAncestorOf.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/gitIsAncestorOf +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/gitIsAncestorOf # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/Git/gitIsBranch.sh b/src/_binaries/Git/gitIsBranch.sh index bb8af53e..dd10bb03 100755 --- a/src/_binaries/Git/gitIsBranch.sh +++ b/src/_binaries/Git/gitIsBranch.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/gitIsBranch +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/gitIsBranch # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/Git/gitRenameBranch.options.tpl b/src/_binaries/Git/gitRenameBranch.options.tpl index 4c720a28..bbabcfcf 100644 --- a/src/_binaries/Git/gitRenameBranch.options.tpl +++ b/src/_binaries/Git/gitRenameBranch.options.tpl @@ -74,8 +74,8 @@ Options::generateCommand "${options[@]}" % assumeYesHelpCallback() { - echo "do not ask for confirmation (use with caution)" $'\n' - echo ' Automatic yes to prompts; assume "y" as answer to all prompts' $'\n' + echo "do not ask for confirmation (use with caution)" + echo ' Automatic yes to prompts; assume "y" as answer to all prompts' echo ' and run non-interactively.' } diff --git a/src/_binaries/Git/gitRenameBranch.sh b/src/_binaries/Git/gitRenameBranch.sh index a356254f..17487f57 100755 --- a/src/_binaries/Git/gitRenameBranch.sh +++ b/src/_binaries/Git/gitRenameBranch.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/gitRenameBranch +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/gitRenameBranch # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/Git/testsData/gitIsAncestorOf.help.txt b/src/_binaries/Git/testsData/gitIsAncestorOf.help.txt index 65fbf775..903ccfd7 100644 --- a/src/_binaries/Git/testsData/gitIsAncestorOf.help.txt +++ b/src/_binaries/Git/testsData/gitIsAncestorOf.help.txt @@ -1,8 +1,8 @@ DESCRIPTION: check if commit is inside a given branch USAGE: gitIsAncestorOf [OPTIONS] [ARGUMENTS] -USAGE: gitIsAncestorOf [--bash-framework-config ] [--config] - [--verbose|-v] [-vv] [-vvv] [--env-file ] [--no-color] +USAGE: gitIsAncestorOf [--bash-framework-config ] + [--config] [--verbose|-v] [-vv] [-vvv] [--env-file ] [--no-color] [--theme ] [--help|-h] [--version] [--quiet|-q] [--log-level ] [--log-file ] [--display-level ] @@ -29,8 +29,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -38,11 +40,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE EXIT CODES: 1: if commit does not exists diff --git a/src/_binaries/Git/testsData/gitRenameBranch.help.txt b/src/_binaries/Git/testsData/gitRenameBranch.help.txt index 88207f95..eeb66481 100644 --- a/src/_binaries/Git/testsData/gitRenameBranch.help.txt +++ b/src/_binaries/Git/testsData/gitRenameBranch.help.txt @@ -1,10 +1,11 @@ -DESCRIPTION: rename git local branch, push new branch and delete old branch +DESCRIPTION: +rename git local branch, push new branch and delete old branch USAGE: gitRenameBranch [OPTIONS] [ARGUMENTS] -USAGE: gitRenameBranch [--assume-yes|--yes|-y] [--push|-p] [--delete|-d] - [--bash-framework-config ] [--config] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--no-color] [--theme ] [--help|-h] [--version] - [--quiet|-q] [--log-level ] [--log-file ] +USAGE: gitRenameBranch [--assume-yes|--yes|-y] [--push|-p] + [--delete|-d] [--bash-framework-config ] [--config] [--verbose|-v] + [-vv] [-vvv] [--env-file ] [--no-color] [--theme ] [--help|-h] + [--version] [--quiet|-q] [--log-level ] [--log-file ] [--display-level ] ARGUMENTS: @@ -40,8 +41,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -49,11 +52,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE EXIT CODES: 1 : if current directory is not a git repository diff --git a/src/_binaries/Git/testsData/upgradeGithubRelease.help.txt b/src/_binaries/Git/testsData/upgradeGithubRelease.help.txt index a1c8fbd7..7623eafe 100644 --- a/src/_binaries/Git/testsData/upgradeGithubRelease.help.txt +++ b/src/_binaries/Git/testsData/upgradeGithubRelease.help.txt @@ -1,4 +1,5 @@ -DESCRIPTION: retrieve latest binary release from github and install it +DESCRIPTION: +retrieve latest binary release from github and install it USAGE: upgradeGithubRelease [OPTIONS] [ARGUMENTS] USAGE: upgradeGithubRelease [--version-arg ] @@ -10,32 +11,34 @@ ARGUMENTS: targetFile {single} (mandatory) - the binary downloaded will e written to this file path. Ensure the path is w - ritable. + the binary downloaded will be written to this file path. + Ensure the path is writable. githubUrlPattern {single} (mandatory) the url pattern to use to download the binary, see examples below. - @version@ is template variable that will be replaced by the latest - version tag found on github. + @version@ is template variable that will be replaced by the latest + version tag found on github. VERSION MANAGEMENT: --version-arg  {single} The argument that will be provided to the currently installed binary - to check the version of the software. See options constraints below. + to check the version of the software. + See options constraints below. Default value: --version --current-version, -c  {single} Sometimes the command to retrieve the version is complicated. - Some command needs you to parse json or other commands provides - multiple sub command versions. In this case you can provide the - version you currently have, see examples below. + Some command needs you to parse json or other commands provides multiple + sub command versions. In this case you can provide the version you + currently have, see examples below. See options constraints below. --exact-version, -e  {single} if provided and currently installed binary is not this exactVersion, - This exact version of the binary will be installed. - See options constraints below. + This exact version of the binary will be installed. + See options constraints below. --minimal-version, -m  {single} - if provided and currently installed binary is below this minimalVersion, - a new version of the binary will be installed. If this argument is not provi - ded, the latest binary is unconditionally downloaded from github. + if provided and currently installed binary is below this + minimalVersion, a new version of the binary will be installed. + If this argument is not provided, the latest binary is unconditionally + downloaded from github. See options constraints below. GLOBAL OPTIONS: @@ -55,8 +58,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -64,11 +69,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE OPTIONS CONSTRAINTS: diff --git a/src/_binaries/Git/upgradeGithubRelease.options.tpl b/src/_binaries/Git/upgradeGithubRelease.options.tpl index 11e79954..d2178adb 100644 --- a/src/_binaries/Git/upgradeGithubRelease.options.tpl +++ b/src/_binaries/Git/upgradeGithubRelease.options.tpl @@ -21,7 +21,8 @@ declare defaultVersionArg="--version" source <( targetFileArgCallback() { :; } Options::generateArg \ - --help "the binary downloaded will e written to this file path. Ensure the path is writable." \ + --help $'the binary downloaded will be written to this file path.\n + Ensure the path is writable.' \ --min 1 \ --max 1 \ --name "targetFile" \ @@ -32,11 +33,9 @@ source <( githubUrlPatternArgCallback() { :; } # shellcheck disable=SC2116 Options::generateArg \ - --help "$(echo \ - "the url pattern to use to download the binary, see examples below." $'\n' \ - "@version@ is template variable that will be replaced by the latest" $'\n' \ - "version tag found on github." \ - )" \ + --help $'the url pattern to use to download the binary, see examples below.\n + @version@ is template variable that will be replaced by the latest \n + version tag found on github.' \ --min 1 \ --max 1 \ --name "githubUrlPattern" \ @@ -52,8 +51,9 @@ source <( Options::generateOption \ --help-value-name "versionArg" \ --default-value "${defaultVersionArg}" \ - --help "The argument that will be provided to the currently installed binary -to check the version of the software. See options constraints below." \ + --help $'The argument that will be provided to the currently installed binary\n + to check the version of the software. \n + See options constraints below.' \ --group groupVersionManagementFunction \ --alt "--version-arg" \ --variable-type "String" \ @@ -63,11 +63,11 @@ to check the version of the software. See options constraints below." \ # shellcheck disable=SC2116 Options::generateOption \ --help-value-name "currentVersion" \ - --help "Sometimes the command to retrieve the version is complicated. -Some command needs you to parse json or other commands provides -multiple sub command versions. In this case you can provide the -version you currently have, see examples below. -See options constraints below." \ + --help $'Sometimes the command to retrieve the version is complicated. \n + Some command needs you to parse json or other commands provides multiple \n + sub command versions. In this case you can provide the version you \n + currently have, see examples below. \n + See options constraints below.' \ --group groupVersionManagementFunction \ --alt "--current-version" \ --alt "-c" \ @@ -78,10 +78,11 @@ See options constraints below." \ # shellcheck disable=SC2116,SC2016 Options::generateOption \ --help-value-name "minimalVersion" \ - --help 'if provided and currently installed binary is below this minimalVersion, -a new version of the binary will be installed. -If this argument is not provided, the latest binary is unconditionally downloaded from github. -See options constraints below.' \ + --help $'if provided and currently installed binary is below this \n + minimalVersion, a new version of the binary will be installed. \n + If this argument is not provided, the latest binary is unconditionally \n + downloaded from github. \n + See options constraints below.' \ --group groupVersionManagementFunction \ --alt "--minimal-version" \ --alt "-m" \ @@ -92,8 +93,8 @@ See options constraints below.' \ # shellcheck disable=SC2116,SC2016 Options::generateOption \ --help-value-name "exactVersion" \ - --help 'if provided and currently installed binary is not this exactVersion, - This exact version of the binary will be installed. + --help $'if provided and currently installed binary is not this exactVersion,\n + This exact version of the binary will be installed.\n See options constraints below.' \ --group groupVersionManagementFunction \ --alt "--exact-version" \ diff --git a/src/_binaries/Git/upgradeGithubRelease.sh b/src/_binaries/Git/upgradeGithubRelease.sh index f7d7ec97..cfee457c 100755 --- a/src/_binaries/Git/upgradeGithubRelease.sh +++ b/src/_binaries/Git/upgradeGithubRelease.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/upgradeGithubRelease +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/upgradeGithubRelease # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/Utils/testsData/waitForIt.help.txt b/src/_binaries/Utils/testsData/waitForIt.help.txt index 1ef282b6..940050ba 100644 --- a/src/_binaries/Utils/testsData/waitForIt.help.txt +++ b/src/_binaries/Utils/testsData/waitForIt.help.txt @@ -1,8 +1,9 @@ DESCRIPTION: wait for host:port to be available USAGE: waitForIt [OPTIONS] [ARGUMENTS] -USAGE: waitForIt [--timeout|-t ] --host|-i --port|-p - [--algorithm|--algo ] [--exec-command-on-success-only|--strict|-s] +USAGE: waitForIt [--timeout|-t ] --host|-i + --port|-p [--algorithm|--algo ] + [--exec-command-on-success-only|--strict|-s] [--bash-framework-config ] [--config] [--verbose|-v] [-vv] [-vvv] [--env-file ] [--no-color] [--theme ] [--help|-h] [--version] [--quiet|-q] [--log-level ] [--log-file ] @@ -22,8 +23,8 @@ --port, -p  {single} (mandatory) TCP port under test. --algorithm, --algo  {single} - Algorithm to use Check algorithms list below. (default: automatic selectio - n based on commands availability and timeout option value). + Algorithm to use Check algorithms list below. (default: automatic selection + based on commands availability and timeout option value). --exec-command-on-success-only, --strict, -s {single} Only execute sub-command if the test succeeds. @@ -44,8 +45,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -53,11 +56,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE EXIT STATUS CODES: 0: the host/port is available diff --git a/src/_binaries/Utils/testsData/waitForMysql.help.txt b/src/_binaries/Utils/testsData/waitForMysql.help.txt index 373497f3..dd8dce4c 100644 --- a/src/_binaries/Utils/testsData/waitForMysql.help.txt +++ b/src/_binaries/Utils/testsData/waitForMysql.help.txt @@ -1,10 +1,11 @@ DESCRIPTION: wait for mysql to be ready USAGE: waitForMysql [OPTIONS] [ARGUMENTS] -USAGE: waitForMysql [--timeout|-t ] [--bash-framework-config ] - [--config] [--verbose|-v] [-vv] [-vvv] [--env-file ] [--no-color] - [--theme ] [--help|-h] [--version] [--quiet|-q] [--log-level ] - [--log-file ] [--display-level ] +USAGE: waitForMysql [--timeout|-t ] + [--bash-framework-config ] [--config] [--verbose|-v] [-vv] [-vvv] + [--env-file ] [--no-color] [--theme ] [--help|-h] [--version] + [--quiet|-q] [--log-level ] [--log-file ] + [--display-level ] ARGUMENTS: mysqlHost {single} (mandatory) @@ -38,8 +39,10 @@ --no-color {single} Produce monochrome output. alias of --theme noColor. --theme  {single} - choose color theme (default, default-force or noColor) - default-force means - colors will be produced even if command is piped + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor --help, -h {single} Display this command help --version {single} @@ -47,11 +50,13 @@ --quiet, -q {single} quiet mode, doesn't display any output --log-level  {single} - Set log level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + Set log level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE --log-file  {single} Set log file --display-level  {single} - set display level (one of OFF, ERROR, WARNING, INFO, DEBUG, TRACE value) + set display level + Possible values: OFF|ERROR|WARNING|INFO|DEBUG|TRACE EXIT STATUS CODES: 0: mysql is available diff --git a/src/_binaries/Utils/waitForIt.sh b/src/_binaries/Utils/waitForIt.sh index d4c0929b..11ff8264 100755 --- a/src/_binaries/Utils/waitForIt.sh +++ b/src/_binaries/Utils/waitForIt.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/waitForIt +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/waitForIt # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/Utils/waitForMysql.sh b/src/_binaries/Utils/waitForMysql.sh index 28bd2255..aad4c9c8 100755 --- a/src/_binaries/Utils/waitForMysql.sh +++ b/src/_binaries/Utils/waitForMysql.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/waitForMysql +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/waitForMysql # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/build/doc.sh b/src/_binaries/build/doc.sh index e2d6a6a4..a01c80c2 100755 --- a/src/_binaries/build/doc.sh +++ b/src/_binaries/build/doc.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/doc +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/doc # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/build/install.sh b/src/_binaries/build/install.sh index 6acc4ba9..dd75f55d 100755 --- a/src/_binaries/build/install.sh +++ b/src/_binaries/build/install.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/install +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/install # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=. # FACADE # shellcheck disable=SC2034 diff --git a/src/_binaries/build/installRequirements.sh b/src/_binaries/build/installRequirements.sh index 6ec19cbf..0337dd96 100755 --- a/src/_binaries/build/installRequirements.sh +++ b/src/_binaries/build/installRequirements.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# BIN_FILE=${FRAMEWORK_ROOT_DIR}/bin/installRequirements +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/installRequirements # VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. # FACADE # shellcheck disable=SC2034,SC2154