diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 67e815cded9300f5bae38733b11f9ab110e261ea..49ff0c6df109e2b80507eabf968a0cd559f981a2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,7 +20,7 @@ workflow: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' # Runs for merge requests - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Pushes to main - if: $CI_PIPELINE_SOURCE == 'schedule' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Scheduled in main - - if: $CI_PIPELINE_SOURCE == "web" + - if: $CI_PIPELINE_SOURCE == 'web' # for testing stages: - maintenance @@ -28,6 +28,7 @@ stages: - test - compare - validate + - deploy # --------------------------------------------------------------- # Generic script anchors @@ -919,10 +920,213 @@ coverage-test-on-main-scheduled: - coverage.info - coverage + +# --------------------------------------------------------------- +# Complexity measurement jobs +# --------------------------------------------------------------- + +.complexity-measurements-setup: &complexity-measurements-setup + # create necessary environment + - mkdir -p wmops/logs + + - job_id=$(python3 ci/get_id_of_last_job_occurence.py $CI_COMMIT_REF_NAME $CI_JOB_NAME) + - echo $job_id + - curl --request GET "https://forge.3gpp.org/rep/api/v4/projects/$CI_PROJECT_ID/jobs/$job_id/artifacts" --output artifacts.zip + - unzip artifacts.zip || true # this may fail on first run, when there are no artifacts there and the zip file is actually just "404"-html + - ls + - public_dir="$CI_JOB_NAME-public" + # if is needed to catch case when no artifact is there (first run), similarly as above + - if [[ -d $public_dir ]]; then mv $public_dir/* wmops/; fi + - ls wmops + - rm artifacts.zip + - rm -rf $public_dir + +.complexity-measurements-prepare-artifacts: &complexity-measurements-prepare-artifacts + # prepare artifacts -> move to public directory + - public_dir="$CI_JOB_NAME-public" + - mkdir $public_dir + - mv -f wmops/log_*_all.txt wmops/*.js ${public_dir}/ + # move logfiles for links + - mkdir $public_dir/logs + # first move logs for "native" sampling rate + - log_files=$(cat $public_dir/graphs_wmops_flc.js | grep logFile | sed "s/.*\(wmops_newsletter_.*\.csv\).*/\1/g") + - echo $log_files + - ls wmops/logs + - for f in $log_files; do [ -f wmops/logs/$f ] && mv wmops/logs/$f $public_dir/logs/$f; done + - log_files_48=$(cat $public_dir/graphs_wmops_flc_48kHz.js | grep logFile | sed "s/.*\(wmops_newsletter_.*\.csv\).*/\1/g") + - echo $log_files_48 + - for f in $log_files_48; do [ -f wmops/logs/$f ] && mv wmops/logs/$f $public_dir/logs/$f; done + # copy index page blueprint + - cp ci/complexity_measurements/index_complexity.html ${public_dir}/index.html + # patch the format in the title + - sed -i "s/IVAS FORMAT/IVAS $in_format to $out_format/g" ${public_dir}/index.html + # do separately here to avoid overwrite complaints by mv + - mv -f ci/complexity_measurements/style.css ${public_dir}/ + +.complexity-template: + extends: + # still needed as long as no long MASA testvectors are there + - .test-job-linux-needs-testv-dir + tags: + - test-complexity-measurement + timeout: 3 hours + stage: test + artifacts: + name: "$CI_JOB_NAME--$CI_COMMIT_REF_NAME--sha-$CI_COMMIT_SHA" + paths: + - $CI_JOB_NAME-public + +complexity-stereo-in-stereo-out: + extends: + - .complexity-template + rules: + - if: $MEASURE_COMPLEXITY_LINUX + script: + - *print-common-info + - *update-ltv-repo + - *complexity-measurements-setup + - in_format=stereo + - out_format=stereo + - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - *complexity-measurements-prepare-artifacts + +complexity-ism-in-binaural-out: + extends: + - .complexity-template + rules: + - if: $MEASURE_COMPLEXITY_LINUX + when: delayed + start_in: 1 hour + script: + - *print-common-info + - *update-ltv-repo + - *complexity-measurements-setup + - in_format=ISM + - out_format=BINAURAL + - bash ci/complexity_measurements/getWmops.sh "ISM1 ISM2 ISM3 ISM4" "$out_format" + - *complexity-measurements-prepare-artifacts + +complexity-sba-hoa3-in-hoa3-out: + extends: + - .complexity-template + rules: + - if: $MEASURE_COMPLEXITY_LINUX + when: delayed + start_in: 3 hours + script: + - *print-common-info + - *update-ltv-repo + - *complexity-measurements-setup + - in_format=SBA + - out_format=HOA3 + - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - *complexity-measurements-prepare-artifacts + +complexity-mc-in-7_1_4-out: + extends: + - .complexity-template + rules: + - if: $MEASURE_COMPLEXITY_LINUX + when: delayed + start_in: 6 hours + script: + - *print-common-info + - *update-ltv-repo + - *complexity-measurements-setup + - in_format=MC + - out_format=7_1_4 + - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - *complexity-measurements-prepare-artifacts + +complexity-masa-in-7_1_4-out: + extends: + - .complexity-template + rules: + - if: $MEASURE_COMPLEXITY_LINUX + when: delayed + start_in: 9 hours + script: + - *print-common-info + - *update-ltv-repo + - *complexity-measurements-setup + - in_format=MASA + - out_format=7_1_4 + - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - *complexity-measurements-prepare-artifacts + +complexity-StereoDmxEVS-stereo-in-mono-out: + extends: + - .complexity-template + rules: + - if: $MEASURE_COMPLEXITY_LINUX + when: delayed + start_in: 10 hours + script: + - *print-common-info + - *update-ltv-repo + - *complexity-measurements-setup + - in_format=StereoDmxEVS + - out_format=mono + - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - *complexity-measurements-prepare-artifacts + # --------------------------------------------------------------- # Other jobs # --------------------------------------------------------------- +pages: + stage: deploy + tags: + - test-complexity-measurement + rules: + # only run for pipelines that affect the data for the page + - if: $MEASURE_COMPLEXITY_LINUX + # TODO: add coverage job + script: + + - API_URL_BASE=https://forge.3gpp.org/rep/api/v4/projects/$CI_PROJECT_ID/jobs + - branch=$CI_COMMIT_REF_NAME + + - mkdir public + # get artifacts for complexity jobs + - job_id=$(python3 ci/get_id_of_last_job_occurence.py $branch complexity-stereo-in-stereo-out) + - echo $job_id + - echo "$API_URL_BASE/$job_id/artifacts" + - curl --request GET "$API_URL_BASE/$job_id/artifacts" --output artifacts_comp_stereo.zip + - cat artifacts_comp_stereo.zip + - unzip -o artifacts_comp_stereo.zip + - mv complexity-stereo-in-stereo-out-public ./public/ + + - job_id=$(python3 ci/get_id_of_last_job_occurence.py $branch complexity-ism-in-binaural-out) + - curl --request GET "$API_URL_BASE/$job_id/artifacts" --output artifacts_comp_ism.zip + - unzip -o artifacts_comp_ism.zip + - mv complexity-ism-in-binaural-out-public ./public/ + + - job_id=$(python3 ci/get_id_of_last_job_occurence.py $branch complexity-sba-hoa3-in-hoa3-out) + - curl --request GET "$API_URL_BASE/$job_id/artifacts" --output artifacts_comp_sba.zip + - unzip -o artifacts_comp_sba.zip + - mv complexity-sba-hoa3-in-hoa3-out-public ./public/ + + - job_id=$(python3 ci/get_id_of_last_job_occurence.py $branch complexity-mc-in-7_1_4-out) + - curl --request GET "$API_URL_BASE/$job_id/artifacts" --output artifacts_comp_mc.zip + - unzip -o artifacts_comp_mc.zip + - mv complexity-mc-in-7_1_4-out-public ./public/ + + - job_id=$(python3 ci/get_id_of_last_job_occurence.py $branch complexity-masa-in-7_1_4-out) + - curl --request GET "$API_URL_BASE/$job_id/artifacts" --output artifacts_comp_masa.zip + - unzip -o artifacts_comp_masa.zip + - mv complexity-masa-in-7_1_4-out-public ./public/ + + - job_id=$(python3 ci/get_id_of_last_job_occurence.py $branch complexity-StereoDmxEVS-stereo-in-mono-out) + - curl --request GET "$API_URL_BASE/$job_id/artifacts" --output artifacts_comp_StereoDmxEVS.zip + - unzip -o artifacts_comp_StereoDmxEVS.zip + - mv complexity-StereoDmxEVS-stereo-in-mono-out-public ./public/ + + - cp ci/index-pages.html public/index.html + artifacts: + paths: + - public + # Pull state of a branch on 3GPP repo, push to a mirror repo. pull-from-3gpp-forge: stage: maintenance diff --git a/ci/build_all_linux.sh b/ci/build_all_linux.sh index 6dcfd92ad9549ba1314a67607b4996cf5b4c4e1f..f1c701a0d966b417203d83f67f8ce5f678462674 100755 --- a/ci/build_all_linux.sh +++ b/ci/build_all_linux.sh @@ -1,5 +1,33 @@ #! /usr/bin/bash +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + if [ ! -d "lib_com" ]; then echo "not in root directory! - please run in IVAS root" exit 1 diff --git a/ci/build_codec_instrumented_linux.sh b/ci/build_codec_instrumented_linux.sh index e98547c5fa667f65fcf9380fba294784ebd6e6dd..9f875f28fbe04ecab16d44422bfebf3eeedcb168 100755 --- a/ci/build_codec_instrumented_linux.sh +++ b/ci/build_codec_instrumented_linux.sh @@ -1,5 +1,33 @@ #! /usr/bin/bash +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + if [ ! -d "lib_com" ]; then echo "not in root directory! - please run in IVAS root" exit 1 diff --git a/ci/build_codec_sanitizers_linux.sh b/ci/build_codec_sanitizers_linux.sh index 65c520d25a42a444b78ced332e076495d4d732f3..d5891e43ad7d549d660c91ec0b768aef7c15490d 100755 --- a/ci/build_codec_sanitizers_linux.sh +++ b/ci/build_codec_sanitizers_linux.sh @@ -1,5 +1,33 @@ #! /usr/bin/bash +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + if [ ! -d "lib_com" ]; then echo "not in root directory! - please run in IVAS root" exit 1 diff --git a/ci/check_for_warnings.py b/ci/check_for_warnings.py index cc658b3d40f75cf81cd45348a257a9f34df4980f..76a0bc917a689dc68c67a24ebc943fa3c0007c07 100755 --- a/ci/check_for_warnings.py +++ b/ci/check_for_warnings.py @@ -1,4 +1,33 @@ #!/usr/bin/env python3 +""" + (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. +""" import argparse import sys diff --git a/ci/complexity_measurements/ep_10pct_fer.g192 b/ci/complexity_measurements/ep_10pct_fer.g192 new file mode 100755 index 0000000000000000000000000000000000000000..ba6bfc78b30bed13fa038fadb24f81b4aa99c59e --- /dev/null +++ b/ci/complexity_measurements/ep_10pct_fer.g192 @@ -0,0 +1 @@ +!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k k k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k k!k!k k!k!k!k!k!k!k k k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k k!k!k k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k!k!k!k k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k k k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k k!k!k k!k!k k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k k k!k!k k k!k!k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k k k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k k!k!k!k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k k!k!k!k!k!k k k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k k!k!k!k k k k!k!k!k!k k k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k k!k k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k k k!k k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k k!k!k!k k k!k!k!k k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k k!k!k!k k k!k!k!k!k k!k k!k!k k!k k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k k k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k k!k!k!k!k!k k k!k k!k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k k!k!k!k!k k!k k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k k k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k k!k!k!k k!k k!k k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k k!k k k!k!k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k!k k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k k k!k!k!k k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k k k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k k!k k!k k!k!k k k!k!k!k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k k k!k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k k!k!k!k k k!k!k!k k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k k!k!k!k!k!k k k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k k!k!k!k k!k!k!k!k!k k!k k!k k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k k!k!k!k k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k k k!k!k!k k!k!k!k!k!k k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k k k!k!k!k!k!k k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k!k!k!k k!k k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k k!k!k!k k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k!k!k!k k!k!k k k!k!k k k!k!k!k!k!k!k!k!k!k!k!k k k!k k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k k!k k!k k k!k!k!k!k!k!k!k k!k!k!k k k!k k k!k!k!k!k!k!k!k k!k k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k k k!k!k!k!k!k!k!k!k!k!k k!k!k k!k!k!k!k!k k!k k!k k!k!k!k!k!k k!k!k!k!k!k k k!k!k!k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k k!k!k k!k k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k!k \ No newline at end of file diff --git a/ci/complexity_measurements/genWebpageData_Prom.csh b/ci/complexity_measurements/genWebpageData_Prom.csh new file mode 100755 index 0000000000000000000000000000000000000000..d6e716f0c5455228478c620a759148b00a6aacc5 --- /dev/null +++ b/ci/complexity_measurements/genWebpageData_Prom.csh @@ -0,0 +1,220 @@ +#!/bin/tcsh + +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + +set maxValues = 40 + +if (${#argv} != 3) then + echo usage: $0 \ \ \ + exit +endif + +set srcFile1 = $1 + +set file_final = $2 +set file = ${file_final}_new_$$ + +set graphName = $3 + +set tmpBase = `basename $0` +set tmpFile1 = /tmp/${tmpBase}1_$$ +rm -f ${tmpFile1} +cat ${srcFile1} | tail -n ${maxValues} > ${tmpFile1} +set nLines1 = `cat ${tmpFile1} | wc -l` +set maxNumWordsLine = 7 + +rm -f $file +touch $file + +echo "var $graphName = {" >> $file +echo ' prom_worstcase: {' >> $file +echo ' description: "Worst Case PROM",' >> $file +echo ' direction: -1,' >> $file +echo ' runs: [' >> $file + + +@ i = 0 +foreach line ( "`cat ${tmpFile1}`" ) + @ i++ + set separator = "," + if ( $i == $nLines1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set revision = $tmp[1] + set shortDate = `echo $tmp[2] | sed -e "s/_/\ /g"` + set fullDate = `echo $tmp[3] | sed -e "s/_/\ /g"` + set logFileFlc = $tmp[5] + set logFileBasop = $tmp[7] + + echo ' {' >> $file + echo ' fullDate: "'${fullDate}'",' >> $file + echo ' shortDate: "'${shortDate}'",' >> $file + echo ' revision: "'${revision}'",' >> $file + echo ' logFileFlc: "'${logFileFlc}'",' >> $file + echo ' logFileBasop: "'${logFileBasop}'",' >> $file + echo ' }'${separator} >> $file + +end +echo ' ],' >> $file + +# begin displays +echo ' displays: [' >> $file + +# requirement PROM +echo ' {' >> $file +echo ' lines: { show: false },' >> $file +echo ' points: { show: false, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#000000",' >> $file +echo ' id: "requirementProm",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile1}`" ) + set separator = "," + if ( $i == $nLines1 - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + # TODO: add real requirement once decided on + set score = 0 + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# requirement ROM + +# measured ops FLC +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#FF8000",' >> $file +echo ' id: "promOpsFlc",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile1}`" ) + set separator = "," + if ( $i == $nLines1 - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[4] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# measured ops FLC + +# measured ops BASOP +echo ' {' >> $file +echo ' lines: { show: false },' >> $file +echo ' points: { show: false, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#0080FF",' >> $file +echo ' id: "promOpsBasop",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile1}`" ) + set separator = "," + if ( $i == $nLines1 - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[6] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' }' >> $file + +echo ' ]' >> $file + +echo ' }' >> $file +echo '};' >> $file + +mv -f $file $file_final +rm -f ${tmpFile1} diff --git a/ci/complexity_measurements/genWebpageData_Ram.csh b/ci/complexity_measurements/genWebpageData_Ram.csh new file mode 100755 index 0000000000000000000000000000000000000000..a8dbc0e2f9dedf8c6758b1e2dd93d1660ad61bc7 --- /dev/null +++ b/ci/complexity_measurements/genWebpageData_Ram.csh @@ -0,0 +1,504 @@ +#!/bin/tcsh + +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + +set maxValues = 40 + +if (${#argv} != 3) then + echo usage: $0 \ \ \ + exit +endif + +set srcFile = $1 +set file_final = $2 +set file = ${file_final}_new_$$ +set graphName = $3 + + +set tmpBase = `basename $0` +set tmpFile = /tmp/${tmpBase}_$$ +rm -f ${tmpFile} +cat ${srcFile} | tail -n ${maxValues} > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +set maxNumWordsLine = 19 + +rm -f $file +touch $file + +echo "var $graphName = {" >> $file +echo ' ram_worstcase: {' >> $file +echo ' description: "Worst Case RAM",' >> $file +echo ' direction: -1,' >> $file +echo ' runs: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + @ i++ + set separator = "," + if ( $i == $nLines ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set revision = $tmp[1] + set shortDate = `echo $tmp[2] | sed -e "s/_/\ /g"` + set fullDate = `echo $tmp[3] | sed -e "s/_/\ /g"` + set maxTotalRamEnc = $tmp[5] + set maxTotalRamDec = $tmp[7] + set maxDynamicRamEnc = $tmp[10] + set maxDynamicRamDec = $tmp[12] + set maxStaticRamEnc = $tmp[15] + set maxStaticRamDec = $tmp[17] + set logFile = $tmp[19] + + echo ' {' >> $file + echo ' fullDate: "'${fullDate}'",' >> $file + echo ' shortDate: "'${shortDate}'",' >> $file + echo ' revision: "'${revision}'",' >> $file + echo ' maxTotalRamEnc: "'${maxTotalRamEnc}'",' >> $file + echo ' maxTotalRamDec: "'${maxTotalRamDec}'",' >> $file + echo ' maxDynamicRamEnc: "'${maxDynamicRamEnc}'",' >> $file + echo ' maxDynamicRamDec: "'${maxDynamicRamDec}'",' >> $file + echo ' maxStaticRamEnc: "'${maxStaticRamEnc}'",' >> $file + echo ' maxStaticRamDec: "'${maxStaticRamDec}'",' >> $file + echo ' logFile: "'${logFile}'"' >> $file + echo ' }'${separator} >> $file + +end +echo ' ],' >> $file + +# begin displays +echo ' displays: [' >> $file + +# requirement RAM +echo ' {' >> $file +echo ' lines: { show: false },' >> $file +echo ' points: { show: false, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#000000",' >> $file +echo ' id: "requirementRam",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + # TODO: add real requirement once decided on + set score = 0 + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# requirement RAM + +# maxTotalRamCodecScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#FF0000",' >> $file +echo ' id: "maxTotalRamCodecScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[4] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# maxTotalRamCodecScore + +# maxTotalRamEncScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#FF8000",' >> $file +echo ' id: "maxTotalRamEncScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[6] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# maxTotalRamEncScore + +# maxTotalRamDecScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#FFFF00",' >> $file +echo ' id: "maxTotalRamDecScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[8] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# maxTotalRamDecScore + +# maxDynamicRamCodecScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#004000",' >> $file +echo ' id: "maxDynamicRamCodecScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[9] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# maxDynamicRamCodecScore + + +# maxDynamicRamEncScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#008000",' >> $file +echo ' id: "maxDynamicRamEncScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[11] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# maxDynamicRamEncScore + +# maxDynamicRamDecScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#00FF00",' >> $file +echo ' id: "maxDynamicRamDecScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[13] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# maxDynamicRamDecScore + +# maxStaticRamCodecScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#800080",' >> $file +echo ' id: "maxStaticRamCodecScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[14] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# maxStaticRamCodecScore + +# maxStaticRamEncScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#0000FF",' >> $file +echo ' id: "maxStaticRamEncScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[16] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# maxStaticRamEncScore + +# maxStaticRamDecScore +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#0080C0",' >> $file +echo ' id: "maxStaticRamDecScore",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine ) then + continue + endif + + set score = $tmp[18] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' }' >> $file +# maxStaticRamDecScore + +echo ' ]' >> $file +# end displays + +echo ' }' >> $file +echo '};' >> $file + +mv -f $file $file_final +rm -f $tmpFile diff --git a/ci/complexity_measurements/genWebpageData_Rom.csh b/ci/complexity_measurements/genWebpageData_Rom.csh new file mode 100755 index 0000000000000000000000000000000000000000..d2ef2daf15fb02538a1e7f553b68ec95468b3805 --- /dev/null +++ b/ci/complexity_measurements/genWebpageData_Rom.csh @@ -0,0 +1,182 @@ +#!/bin/tcsh + +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + +set maxValues = 40 + +if (${#argv} != 3) then + echo usage: $0 \ \ \ \ + exit +endif + +set srcFile1 = $1 + +set file_final = $2 +set file = ${file_final}_new_$$ +set graphName = $3 + +set tmpBase = `basename $0` +set tmpFile1 = /tmp/${tmpBase}1_$$ +set tmpFile2 = /tmp/${tmpBase}2_$$ +rm -f ${tmpFile1} ${tmpFile2} +cat ${srcFile1} | tail -n ${maxValues} > ${tmpFile1} +set nLines1 = `cat ${tmpFile1} | wc -l` +set maxNumWordsLine1 = 5 +set maxNumWordsLine2 = 5 + +rm -f $file +touch $file + +echo "var $graphName = {" >> $file +echo ' rom_worstcase: {' >> $file +echo ' description: "Worst Case ROM",' >> $file +echo ' direction: -1,' >> $file +echo ' runs: [' >> $file + + +@ i = 0 +foreach line ( "`cat ${tmpFile1}`" ) + @ i++ + set separator = "," + if ( $i == $nLines1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine1 ) then + continue + endif + + set revision = $tmp[1] + set shortDate = `echo $tmp[2] | sed -e "s/_/\ /g"` + set fullDate = `echo $tmp[3] | sed -e "s/_/\ /g"` + set logFileFlc = $tmp[5] + + echo ' {' >> $file + echo ' fullDate: "'${fullDate}'",' >> $file + echo ' shortDate: "'${shortDate}'",' >> $file + echo ' revision: "'${revision}'",' >> $file + echo ' logFileFlc: "'${logFileFlc}'",' >> $file +# echo ' logFileBasop: "'${logFileBasop[$i]}'"' >> $file + echo ' }'${separator} >> $file + +end +echo ' ],' >> $file + +# begin displays +echo ' displays: [' >> $file + +# requirement ROM +echo ' {' >> $file +echo ' lines: { show: false },' >> $file +echo ' points: { show: false, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#000000",' >> $file +echo ' id: "requirementRom",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile1}`" ) + set separator = "," + if ( $i == $nLines1 - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine1 ) then + continue + endif + + # TODO: add real requirement once decided on + set score = 0 + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# requirement ROM + +# maxTablesizeCodecScore FLC +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#FF8000",' >> $file +echo ' id: "maxRomFlc",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile1}`" ) + set separator = "," + if ( $i == $nLines1 - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLine1 ) then + continue + endif + + set score = $tmp[4] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' }' >> $file +# maxTablesizeCodecScore FLC +echo ' ]' >> $file +# end displays + +echo ' }' >> $file +echo '};' >> $file + +mv -f $file $file_final +rm -f $tmpFile1 diff --git a/ci/complexity_measurements/genWebpageData_WMOPS.csh b/ci/complexity_measurements/genWebpageData_WMOPS.csh new file mode 100755 index 0000000000000000000000000000000000000000..c030f4afac7ada79ddb0258e3bbf02b18f060ece --- /dev/null +++ b/ci/complexity_measurements/genWebpageData_WMOPS.csh @@ -0,0 +1,500 @@ +#!/bin/tcsh + +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + +set maxValues = 40 + +if (${#argv} != 3) then + echo usage: $0 \ \ \ + exit +endif + +set srcFile = $1 +set file_final = $2 +set file = ${file_final}_new_$$ +set graphName = $3 + + +set tmpBase = `basename $0` +set tmpFile = /tmp/${tmpBase}_$$ +rm -f ${tmpFile} +cat ${srcFile} | tail -n ${maxValues} > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +set maxNumWordsLineOld = 12 +set maxNumWordsLineNew = 19 + +rm -f $file +touch $file + +echo "var $graphName = {" >> $file +echo ' wmops_worstcase: {' >> $file +echo ' description: "Worst Case WMOPS",' >> $file +echo ' direction: -1,' >> $file +echo ' runs: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + @ i++ + set separator = "," + if ( $i == $nLines ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + set revision = $tmp[1] + set shortDate = `echo $tmp[2] | sed -e "s/_/\ /g"` + set fullDate = `echo $tmp[3] | sed -e "s/_/\ /g"` + set worstCaseEnc = $tmp[5] + set worstCaseDec = $tmp[7] + set worstCaseCodec = $tmp[9] + set fixpointScalingFac = $tmp[11] + if ( $numWords == $maxNumWordsLineOld ) then + set logFile = $tmp[12] + set worstCaseEncRs = "" + set worstCaseDecRs = "" + set worstCaseCodecRs = "" + else if ( $numWords < $maxNumWordsLineNew ) then + set logFile = "" + set worstCaseEncRs = "" + set worstCaseDecRs = "" + set worstCaseCodecRs = "" + else + set logFile = $tmp[19] + set worstCaseEncRs = $tmp[13] + set worstCaseDecRs = $tmp[15] + set worstCaseCodecRs = $tmp[17] + endif + + + echo ' {' >> $file + echo ' fullDate: "'${fullDate}'",' >> $file + echo ' shortDate: "'${shortDate}'",' >> $file + echo ' revision: "'${revision}'",' >> $file + echo ' worstCaseEnc: "'${worstCaseEnc}'",' >> $file + echo ' worstCaseDec: "'${worstCaseDec}'",' >> $file + echo ' worstCaseCodec: "'${worstCaseCodec}'",'>> $file + echo ' worstCaseEncRs: "'${worstCaseEncRs}'",' >> $file + echo ' worstCaseDecRs: "'${worstCaseDecRs}'",' >> $file + echo ' worstCaseCodecRs: "'${worstCaseCodecRs}'",'>> $file + echo ' fixpointScalingFac: "'${fixpointScalingFac}'",'>> $file + echo ' logFile: "'${logFile}'"' >> $file + echo ' }'${separator} >> $file + +end +echo ' ],' >> $file + +# begin displays +echo ' displays: [' >> $file + +# 135 WMOPS boundary +echo ' {' >> $file +echo ' lines: { show: false },' >> $file +echo ' points: { show: false, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: false,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#000000",' >> $file +echo ' id: "requirement",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + # TODO: add real requirement once decided on + set score = 0 + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# 135 WMOPS boundary + +# worst case codec +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#0080FF",' >> $file +echo ' id: "worst case codec",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + set score = $tmp[10] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# end worst case codec + +# worst case enc/dec +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#FF8000",' >> $file +echo ' id: "worst case enc/dec",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + set score = $tmp[4] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# worst case enc/dec + +# worst case encoder +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#CF4B4B",' >> $file +echo ' id: "worst case enc",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + set score = $tmp[6] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# end worst case encoder + +# worst case decoder +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#008040",' >> $file +echo ' id: "worst case dec",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + set score = $tmp[8] + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# end worst case decoder + +########### rateswitching ############### + +# worst case codec rateswitching +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#40C4FF",' >> $file +echo ' id: "worst case codec rs",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + if ( $numWords < $maxNumWordsLineNew ) then + set score = 0 + else + set score = $tmp[18] + endif + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# end worst case codec rateswitching + +# worst case enc/dec rateswitching +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#FFC480",' >> $file +echo ' id: "worst case enc/dec rs",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + if ( $numWords < $maxNumWordsLineNew ) then + set score = 0 + else + set score = $tmp[12] + endif + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# worst case enc/dec rateswitching + +# worst case encoder rateswitching +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#CF8080",' >> $file +echo ' id: "worst case enc rs",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + if ( $numWords < $maxNumWordsLineNew ) then + set score = 0 + else + set score = $tmp[14] + endif + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' },' >> $file +# end worst case encoder rateswitching + +# worst case decoder rateswitching +echo ' {' >> $file +echo ' lines: { show: true },' >> $file +echo ' points: { show: true, fillColor: "#ffffff" },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: true,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#00F040",' >> $file +echo ' id: "worst case dec rs",' >> $file +echo ' data: [' >> $file + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + set separator = "," + if ( $i == $nLines - 1 ) then + set separator = "" + endif + + set tmp = ( $line ) + + set numWords = `echo $tmp | wc -w` + if ( $numWords < $maxNumWordsLineOld ) then + continue + endif + + if ( $numWords < $maxNumWordsLineNew ) then + set score = 0 + else + set score = $tmp[16] + endif + + echo ' ['"${i}, ${score}"']'${separator} >> $file + @ i++ + +end + +echo ' ]' >> $file +echo ' }' >> $file +# end worst case decoder rateswitching + +########### end rateswitching ############### + +echo ' ]' >> $file +# end displays + +echo ' }' >> $file +echo '};' >> $file + +mv -f $file $file_final +rm -f $tmpFile diff --git a/ci/complexity_measurements/genWebpageData_WmopPerOperatingpoint.csh b/ci/complexity_measurements/genWebpageData_WmopPerOperatingpoint.csh new file mode 100755 index 0000000000000000000000000000000000000000..cac8183bda7ee07199a4e2bfd6a94978f1767b05 --- /dev/null +++ b/ci/complexity_measurements/genWebpageData_WmopPerOperatingpoint.csh @@ -0,0 +1,503 @@ +#!/bin/tcsh + +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + +set srcFile = $1 +set file_final = $2 +set file = ${file_final}.new +set graphName = $3 + +set tmpBase = `basename $0` +set tmpFile = /tmp/${tmpBase}_$$ + +rm -f $file +touch $file + +set worstCaseCodec +set worstCaseEnc +set worstCaseDec +@ numEntries = 0; +@ offsetTicks = 0; + +echo "var $graphName = {" >> $file +echo ' wmops_worstcase_per_op: {' >> $file +echo ' description: "Worst Case WMOPS per OP",' >> $file +echo ' direction: -1,' >> $file +echo ' runs: [' >> $file + +# +# NB modes +# +if (0) then # don't use! +rm -f ${tmpFile} +cat ${srcFile} | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_NB_" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksNB = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "NB"' >> $file + echo ' },' >> $file + +end + +set worstCaseCodec = ( $worstCaseCodec 0 ) +set worstCaseEnc = ( $worstCaseEnc 0 ) +set worstCaseDec = ( $worstCaseDec 0 ) +@ numEntries++ + +echo ' {' >> $file +echo ' operatingPoint: "",' >> $file +echo ' mode: ""' >> $file +echo ' },' >> $file + +# +# NB modes, rateswitching +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_NB_RS" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksNB_RS = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "NB RS"' >> $file + echo ' },' >> $file + +end + +set worstCaseCodec = ( $worstCaseCodec 0 ) +set worstCaseEnc = ( $worstCaseEnc 0 ) +set worstCaseDec = ( $worstCaseDec 0 ) +@ numEntries++ + +echo ' {' >> $file +echo ' operatingPoint: "",' >> $file +echo ' mode: ""' >> $file +echo ' },' >> $file + +# +# AMR-WB IO modes +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_WB_" | grep "AMR" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksWBIO = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "AMR-WB IO"' >> $file + echo ' },' >> $file + +end + +set worstCaseCodec = ( $worstCaseCodec 0 ) +set worstCaseEnc = ( $worstCaseEnc 0 ) +set worstCaseDec = ( $worstCaseDec 0 ) +@ numEntries++ + +echo ' {' >> $file +echo ' operatingPoint: "",' >> $file +echo ' mode: ""' >> $file +echo ' },' >> $file + +# +# AMR-WB IO modes rateswitching +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_WB_RS" | grep "AMR" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksWBIO_RS = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "AMR-WB IO RS"' >> $file + echo ' },' >> $file + +end + +set worstCaseCodec = ( $worstCaseCodec 0 ) +set worstCaseEnc = ( $worstCaseEnc 0 ) +set worstCaseDec = ( $worstCaseDec 0 ) +@ numEntries++ + +echo ' {' >> $file +echo ' operatingPoint: "",' >> $file +echo ' mode: ""' >> $file +echo ' },' >> $file +endif + +# +# WB modes +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_WB_" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksWB = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "WB"' >> $file + echo ' },' >> $file + +end + +set worstCaseCodec = ( $worstCaseCodec 0 ) +set worstCaseEnc = ( $worstCaseEnc 0 ) +set worstCaseDec = ( $worstCaseDec 0 ) +@ numEntries++ + +echo ' {' >> $file +echo ' operatingPoint: "",' >> $file +echo ' mode: ""' >> $file +echo ' },' >> $file + +# +# WB modes rateswitching +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_WB_RS" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksWB_RS = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "WB RS"' >> $file + echo ' },' >> $file + +end + +set worstCaseCodec = ( $worstCaseCodec 0 ) +set worstCaseEnc = ( $worstCaseEnc 0 ) +set worstCaseDec = ( $worstCaseDec 0 ) +@ numEntries++ + +echo ' {' >> $file +echo ' operatingPoint: "",' >> $file +echo ' mode: ""' >> $file +echo ' },' >> $file + +# +# SWB modes +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_SWB_" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksSWB = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "SWB"' >> $file + echo ' },' >> $file + +end + +set worstCaseCodec = ( $worstCaseCodec 0 ) +set worstCaseEnc = ( $worstCaseEnc 0 ) +set worstCaseDec = ( $worstCaseDec 0 ) +@ numEntries++ + +echo ' {' >> $file +echo ' operatingPoint: "",' >> $file +echo ' mode: ""' >> $file +echo ' },' >> $file + + +# +# SWB modes rateswitching +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_SWB_RS" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksSWB_RS = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "SWB RS"' >> $file + echo ' },' >> $file + +end + +# +# FB modes +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_FB_" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksFB = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +foreach line ( "`cat ${tmpFile}`" ) + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "FB"' >> $file + echo ' },' >> $file + +end + +set worstCaseCodec = ( $worstCaseCodec 0 ) +set worstCaseEnc = ( $worstCaseEnc 0 ) +set worstCaseDec = ( $worstCaseDec 0 ) +@ numEntries++ + +echo ' {' >> $file +echo ' operatingPoint: "",' >> $file +echo ' mode: ""' >> $file +echo ' },' >> $file + + +# +# FB modes rateswitching +# +rm -f ${tmpFile} +cat $srcFile | grep "[0-9]" | sed -e "s/\ /_/g" | sed -e "s/;/\ /g" | grep "_FB_RS" > ${tmpFile} +set nLines = `cat ${tmpFile} | wc -l` +@ ticksFB_RS = $offsetTicks + ( $nLines / 2 ) +@ offsetTicks += ($nLines + 1) + +@ i = 0 +foreach line ( "`cat ${tmpFile}`" ) + @ i++ + set separator = "," + if ( $i == $nLines ) then + set separator = "" + endif + + set tmp = `echo $line` + + set operatingPoint = $tmp[1] + set worstCaseCodec = ( $worstCaseCodec $tmp[4] ) + set worstCaseEnc = ( $worstCaseEnc $tmp[2] ) + set worstCaseDec = ( $worstCaseDec $tmp[3] ) + @ numEntries++ + + echo ' {' >> $file + echo ' operatingPoint: "'${operatingPoint}'",' >> $file + echo ' mode: "SWB RS"' >> $file + echo ' }'${separator} >> $file + +end + +echo ' ],' >> $file + +# +# ticks +# +echo ' ticks: [' >> $file +if (0) then +echo ' ['$ticksNB', "NB"],' >> $file +echo ' ['$ticksNB_RS', "NB RS"],' >> $file +echo ' ['$ticksWBIO', "AMR-WB IO"],' >> $file +endif +echo ' ['$ticksWB', "WB"],' >> $file +echo ' ['$ticksWB_RS', "WB RS"],' >> $file +echo ' ['$ticksSWB', "SWB"],' >> $file +echo ' ['$ticksSWB_RS', "SWB RS"],' >> $file +echo ' ['$ticksFB', "FB"],' >> $file +echo ' ['$ticksFB_RS', "FB RS"]' >> $file +echo ' ],' >> $file + + +# begin displays +echo ' displays: [' >> $file + +# Start: Worse case encoder +echo ' {' >> $file +echo ' lines: { show: false },' >> $file +echo ' points: { show: false },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: false,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#CF4B4B",' >> $file +echo ' id: "worstCaseEnc",' >> $file +echo ' label: "Encoder",' >> $file +echo ' data: [' >> $file + +@ i = 0 +while($i < $numEntries) + + set separator = "," + if ( $i == $numEntries - 1 ) then + set separator = "" + endif + + @ j = $i + 1 + + echo ' ['"${i}, $worstCaseEnc[$j]"']'${separator} >> $file + + @ i++ +end + +echo ' ]' >> $file +echo ' },' >> $file +# End: Worst case encoder + +# Start: Worse case decoder +echo ' {' >> $file +echo ' lines: { show: false },' >> $file +echo ' points: { show: false },' >> $file +echo ' borderWidth: 1.5,' >> $file +echo ' borderColor: "#BEBEBE",' >> $file +echo ' markingsLineWidth: .75,' >> $file +echo ' hoverable: true,' >> $file +echo ' clickable: false,' >> $file +echo ' shadowSize: 0,' >> $file +echo ' color: "#008040",' >> $file +echo ' id: "worstCaseDec",' >> $file +echo ' label: "Decoder",' >> $file +echo ' data: [' >> $file + +@ i = 0 +while($i < $numEntries) + + set separator = "," + if ( $i == $numEntries - 1 ) then + set separator = "" + endif + + @ j = $i + 1 + + echo ' ['"${i}, $worstCaseDec[$j]"']'${separator} >> $file + + @ i++ +end + +echo ' ]' >> $file +echo ' }' >> $file +# End: Worst case encoder + +echo ' ]' >> $file +# end displays + +echo ' }' >> $file +echo '};' >> $file + +mv -f $file $file_final +rm -f $tmpFile diff --git a/ci/complexity_measurements/getWmops.sh b/ci/complexity_measurements/getWmops.sh new file mode 100755 index 0000000000000000000000000000000000000000..40b58370170706b7b60dbc46f96dacc88e10c53b --- /dev/null +++ b/ci/complexity_measurements/getWmops.sh @@ -0,0 +1,98 @@ +#! /bin/bash + +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + +# get format from command line +if [ $# -ne 2 ]; then + echo "Usage: $0 \"ivas-format(s)\" \"output-format(s)\"" + exit 1 +fi + +ivas_format=$1 +output_format=$2 + +date=`date +%Y%m%d` # used for log-file file ending +shortDate=`date "+%b %d" | sed -e "s/\ /_/g"` # stored in the log-file +fullDate=`date "+%c" | sed -e "s/\ /_/g"` # stored in the log-file + +commit_sha=`git rev-parse --short HEAD` + +destDir="." +scriptDir="ci/complexity_measurements" +ep="${scriptDir}/ep_10pct_fer.g192" + +config_file="scripts/config/ci_linux_ltv.json" + +# get wmops newsletter +wmopsFilenameFlcLast=wmops_newsletter_stereo__${commit_sha}_${date} +wmopsFilenameFlc=${destDir}/wmops/logs/${wmopsFilenameFlcLast} +wmopsFilenameFlc48kHzLast=wmops_newsletter_stereo_48kHz__${commit_sha}_${date} +wmopsFilenameFlc48kHz=${destDir}/wmops/logs/${wmopsFilenameFlc48kHzLast} + +# instrument and build +./scripts/IvasBuildAndRunChecks.py -p $config_file --checks COMPLEXITY --create_complexity_tables ${wmopsFilenameFlc} -C $ivas_format -f ${ep} --oc $output_format +./scripts/IvasBuildAndRunChecks.py -p $config_file --checks COMPLEXITY --create_complexity_tables ${wmopsFilenameFlc48kHz} -C $ivas_format -R 48 -S 48 -f ${ep} --oc $output_format + +# now get the info on worst case operating point: WMOPS number, enc-operating mode, dec-operating mode +### WMOPS +${scriptDir}/parseNewsletterWmops.py ${wmopsFilenameFlc}_WMOPS.csv ${wmopsFilenameFlcLast}_WMOPS.csv ${commit_sha} ${shortDate} ${fullDate} >> ${destDir}/wmops/log_wmops_all.txt +${scriptDir}/parseNewsletterWmops.py ${wmopsFilenameFlc48kHz}_WMOPS.csv ${wmopsFilenameFlc48kHzLast}_WMOPS.csv ${commit_sha} ${shortDate} ${fullDate} >> ${destDir}/wmops/log_wmops_48kHz_all.txt + +# now update the webpage +tcsh ${scriptDir}/genWebpageData_WMOPS.csh ${destDir}/wmops/log_wmops_all.txt ${destDir}/wmops/graphs_wmops_flc.js Graphs_WMOPS +tcsh ${scriptDir}/genWebpageData_WMOPS.csh ${destDir}/wmops/log_wmops_48kHz_all.txt ${destDir}/wmops/graphs_wmops_flc_48kHz.js Graphs_WMOPS_48kHz + +# per mode graph +tcsh ${scriptDir}/genWebpageData_WmopPerOperatingpoint.csh ${wmopsFilenameFlc}_WMOPS.csv ${destDir}/wmops/graphs_wmops_flc_perOP.js Graphs_WMOPS_perOP +tcsh ${scriptDir}/genWebpageData_WmopPerOperatingpoint.csh ${wmopsFilenameFlc48kHz}_WMOPS.csv ${destDir}/wmops/graphs_wmops_flc_perOP_48kHz.js Graphs_WMOPS_perOP_48kHz + +# get memory info for webpage +### RAM +${scriptDir}/mergeNewsletterRam.py ${wmopsFilenameFlc48kHz}_SRAM.csv ${wmopsFilenameFlc48kHz}_DRAM.csv > ${wmopsFilenameFlc48kHz}_RAM.csv +${scriptDir}/parseNewsletterRam.py ${wmopsFilenameFlc48kHz}_SRAM.csv ${wmopsFilenameFlc48kHz}_DRAM.csv ${wmopsFilenameFlc48kHzLast}_RAM.csv ${commit_sha} ${shortDate} ${fullDate} >> ${destDir}/wmops/log_ram_all.txt + +# generate java script from database +tcsh ${scriptDir}/genWebpageData_Ram.csh ${destDir}/wmops/log_ram_all.txt ${destDir}/wmops/graphs_ram_flc.js Graphs_RAM + +### ROM +${scriptDir}/parseNewsletterRom.py ${wmopsFilenameFlc}_TABLES.csv ${wmopsFilenameFlcLast}_TABLES.csv ${commit_sha} ${shortDate} ${fullDate} >> ${destDir}/wmops/log_rom_all.txt + +# generate java script from database +tcsh ${scriptDir}/genWebpageData_Rom.csh ${destDir}/wmops/log_rom_all.txt ${destDir}/wmops/graphs_rom_flc.js Graphs_ROM + +# now go on with BASOP +promFilenameBasopLast="null" +promScoreBasop=0 + +### PROM +${scriptDir}/parseNewsletterProm.py ${wmopsFilenameFlc}_PROM.csv ${wmopsFilenameFlcLast}_PROM.csv ${commit_sha} ${shortDate} ${fullDate} ${promScoreBasop} ${promFilenameBasopLast} >> ${destDir}/wmops/log_prom_all.txt + +# generate java script from database +tcsh ${scriptDir}/genWebpageData_Prom.csh ${destDir}/wmops/log_prom_all.txt ${destDir}/wmops/graphs_prom_flc.js Graphs_PROM + diff --git a/ci/complexity_measurements/index_complexity.html b/ci/complexity_measurements/index_complexity.html new file mode 100755 index 0000000000000000000000000000000000000000..c2d3c951b6d42bb4687270e3f742fb1e1901db7d --- /dev/null +++ b/ci/complexity_measurements/index_complexity.html @@ -0,0 +1,1571 @@ + + + + + + + + + + + IVAS FORMAT - Worst Case WMOPS/Memory Performance + + + + + + + + + + + + + + + + + + + + + + + + +
+

IVAS FORMAT - Worst Case WMOPS Performance (Float, native SR)

+ +
+
+
+ +
+
    +
  • Worst case encoder + decoder performance: Encoder and decoder mode might be different.
  • +
  • Worst case encoder + decoder performance (rateswitching): Encoder and decoder mode might be different.
  • +
  • Worst case codec performance: Encoder and decoder modes are identical.
  • +
  • Worst case codec performance (rateswitching): Encoder and decoder modes are identical.
  • +
  • Worst case encoder performance
  • +
  • Worst case encoder performance (rateswitching)
  • +
  • Worst case decoder performance
  • +
  • Worst case decoder performance (rateswitching)
  • +
+
+ +
+ +

IVAS FORMAT - Worst Case WMOPS Performance + per Operating Point (Float, native SR)

+ +
+
+
+ +
+
+
+ +
+ + +

IVAS FORMAT - Worst Case WMOPS Performance (Float, 48 kHz)

+ +
+
+
+ +
+
    +
  • Worst case encoder + decoder performance: Encoder and decoder mode might be different.
  • +
  • Worst case encoder + decoder performance (rateswitching): Encoder and decoder mode might be different.
  • +
  • Worst case codec performance: Encoder and decoder modes are identical.
  • +
  • Worst case codec performance (rateswitching): Encoder and decoder modes are identical.
  • +
  • Worst case encoder performance
  • +
  • Worst case encoder performance (rateswitching)
  • +
  • Worst case decoder performance
  • +
  • Worst case decoder performance (rateswitching)
  • +
+
+ +
+ +

IVAS FORMAT - Worst Case WMOPS Performance + per Operating Point (Float, 48 kHz)

+ +
+
+
+ +
+
+
+ +
+ + + + + +

IVAS FORMAT - Worst Case RAM Demand (Float)

+ +
+
+
+ +
+
    +
  • Max. total RAM Codec: + Dynamic + Static RAM, 32 bit words, Encoder + Decoder
  • +
  • Max. total RAM + Encoder: Dynamic + Static RAM, 32 bit words, Encoder only
  • +
  • Max. total RAM + Decoder: Dynamic + Static RAM, 32 bit words, Decoder only
  • + +
  • Max. static RAM Codec: + Static RAM, 32 bit words, Encoder + Decoder
  • +
  • Max. static RAM + Encoder: Static RAM, 32 bit words,, Encoder only
  • +
  • Max. static RAM + Decoder: Static RAM, 32 bit words, Decoder only
  • + +
  • Max. dynamic RAM + Codec: Dynamic RAM, 32 bit words, Encoder + Decoder
  • +
  • Max. dynamic RAM + Encoder: Dynamic RAM, 32 bit words, Encoder only
  • +
  • Max. dynamic RAM + Decoder: Dynamic RAM, 32 bit words, Decoder only
  • +
+
+ +
+ + + +

IVAS FORMAT - Worst Case ROM Demand (Float)

+ +
+
+
+ +
+
    +
  • Measured ROM table size, 32 + bit words (Float)
  • +
+
+ + + +

IVAS FORMAT - Worst Case PROM Demand

+ +
+
+
+ +
+
    +
  • Measured PROM (Float, + trunk)
  • + +
+
+ +
+ +

FAQ

+
+
Q:
What does "native SR" mean? What is the difference between the graphs titled "native SR" and "48 kHz"?
+
A:
The graphs titled "native SR" run encoder/decoder at the native input/output sampling-rate per operating point. This is 16 kHz for WB, 32 kHz for SWB etc. The graphs titled "48 kHz" use 48 kHz input/output sampling rate, independent of the supported bandwidth, which is set by using the "-max_band" commandline switch.
+
Q:
What is the meaning of these funny symbols in the navigation box, in the left upper corner of this page?
+
A:
+ 1) Traffic light , or : !!!CURRENTLY NOT WORKING CORRECTLY AS NO REQUIREMENTS DEFINED YET!!! The traffic light symbols show, whether the last datapoint matches the requirement (green) or not (red). A yellow traffic light means that the requirement is matched, but the score is very close (within a 3% margin) to the requirement.
+ 2) Arrow , , : The arrow indicates the trend of the last datapoint, compared to the last but one. An upwards arrow means that the score got higher (i.e. worse), downwards arrow arrow means that the score got lower (i.e. better), and a rightwards arrow means that the score was kept constant (within a 1% margin). +
+
Q:
Which input files are used for audio-input? What error pattern is used?
+
A:
The input files can be found here. The error pattern is here. +
+ + +
+

Legal notice

+
+ This webpage uses jQuery and Flot.js libraries for which the following licenses apply: +
+
jQuery:
+
+ Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +
+
Flot.js:
+
+ Copyright (c) 2007-2014 IOLA and Ole Laursen + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. +
+
+
+
+ + + + + diff --git a/ci/complexity_measurements/mergeNewsletterRam.py b/ci/complexity_measurements/mergeNewsletterRam.py new file mode 100755 index 0000000000000000000000000000000000000000..c5e61a98548b481cd6712f7c4263ae2bcd81603b --- /dev/null +++ b/ci/complexity_measurements/mergeNewsletterRam.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. +import csv +import sys +import re + +newsletterFilename = "" +newsletterFilenameLast = "" +revision = "" +shortDate = "" +fullDate = "" + +if __name__ == "__main__": + newsletterFilenameSram = sys.argv[1] + newsletterFilenameDram = sys.argv[2] + +ram_table = {} + +with open(newsletterFilenameSram, "r") as csvfile: + SRAM = csv.reader(csvfile, delimiter=";") + for row in SRAM: + if row[0] == "conf": + continue + key = row[0] + lst = row[1:] + ram_table[key] = lst + +with open(newsletterFilenameDram, "r") as csvfile: + DRAM = csv.reader(csvfile, delimiter=";") + for row in DRAM: + if row[0] == "conf": + continue + key = row[0] + lst = row[1:] + ram_table[key] += lst + +# now we have the following format +# SRAM enc, SRAM dec, SRAM total, DRAM enc, DRAM dec, DRAM max(enc, dec) + +print("conf;sram enc;sram dec;sram total;dram enc;dram dec;dram max;total") + +for key in ram_table: + ram = ram_table[key] + total = int(ram[1]) + int(ram[2]) + int(ram[5]) + print( + key, + ";", + ram[0], + ";", + ram[1], + ";", + ram[2], + ";", + ram[3], + ";", + ram[4], + ";", + ram[5], + ";", + total, + sep="", + ) diff --git a/ci/complexity_measurements/parseNewsletterProm.py b/ci/complexity_measurements/parseNewsletterProm.py new file mode 100755 index 0000000000000000000000000000000000000000..072cb03c21a7b022819ab63350d313f62e7c8182 --- /dev/null +++ b/ci/complexity_measurements/parseNewsletterProm.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# coding: utf-8 +""" + (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. +""" + +import csv +import sys +import re + +newsletterFilename = "" +newsletterFilenameLast = "" +revision = "" +shortDate = "" +fullDate = "" +maxPromOpsBasop = "" +logfileBasop = "" + +if __name__ == "__main__": + newsletterFilename = sys.argv[1] + newsletterFilenameLast = sys.argv[2] + revision = sys.argv[3] + shortDate = sys.argv[4] + fullDate = sys.argv[5] + maxPromOpsBasop = sys.argv[6] + logfileBasop = sys.argv[7] + +max_total = ["", 0] + +with open(newsletterFilename, "r") as csvfile: + prom = csv.reader(csvfile, delimiter=";") + for row in prom: + if row[0] == "conf": + continue + if int(row[4]) > max_total[1]: + max_total[0] = re.sub(" ", "_", row[0]) + max_total[1] = int(row[4]) + +print( + revision, + shortDate, + fullDate, + max_total[1], + newsletterFilenameLast, + maxPromOpsBasop, + logfileBasop, +) diff --git a/ci/complexity_measurements/parseNewsletterRam.py b/ci/complexity_measurements/parseNewsletterRam.py new file mode 100755 index 0000000000000000000000000000000000000000..b099fb450f955bccb69bb683ddcdc025192f633a --- /dev/null +++ b/ci/complexity_measurements/parseNewsletterRam.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +# coding: utf-8 +""" + (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. +""" + +import csv +import sys +import re + +newsletterFilename = "" +newsletterFilenameLast = "" +revision = "" +shortDate = "" +fullDate = "" + +if __name__ == "__main__": + newsletterFilenameSram = sys.argv[1] + newsletterFilenameDram = sys.argv[2] + newsletterFilenameLast = sys.argv[3] + revision = sys.argv[4] + shortDate = sys.argv[5] + fullDate = sys.argv[6] + +max_total_enc = ["", 0] +max_total_dec = ["", 0] +max_total_encdec = ["", 0] + +max_dynamic_enc = ["", 0] +max_dynamic_dec = ["", 0] +max_dynamic_encdec = ["", 0] + +max_static_enc = ["", 0] +max_static_dec = ["", 0] +max_static_encdec = ["", 0] + +ram_table = {} + +with open(newsletterFilenameSram, "r") as csvfile: + SRAM = csv.reader(csvfile, delimiter=";") + for row in SRAM: + if row[0] == "conf": + continue + key = row[0] + lst = row[1:] + ram_table[key] = lst + +with open(newsletterFilenameDram, "r") as csvfile: + DRAM = csv.reader(csvfile, delimiter=";") + for row in DRAM: + if row[0] == "conf": + continue + key = row[0] + lst = row[1:] + ram_table[key] += lst + +# now we have the following format +# SRAM enc, SRAM dec, SRAM total, DRAM enc, DRAM dec, DRAM max(enc, dec) + +for key in ram_table: + ram = ram_table[key] + static_enc = int(ram[0]) + static_dec = int(ram[1]) + static_encdec = static_enc + static_dec + + dynamic_enc = int(ram[3]) + dynamic_dec = int(ram[4]) + dynamic_encdec = int(ram[5]) + + total_enc = static_enc + dynamic_enc + total_dec = static_dec + dynamic_dec + total_encdec = static_encdec + dynamic_encdec + + if static_enc > max_static_enc[1]: + max_static_enc[0] = re.sub(" ", "_", key) + max_static_enc[1] = static_enc + + if static_dec > max_static_dec[1]: + max_static_dec[0] = re.sub(" ", "_", key) + max_static_dec[1] = static_dec + + if static_encdec > max_static_encdec[1]: + max_static_encdec[0] = re.sub(" ", "_", key) + max_static_encdec[1] = static_encdec + + if dynamic_enc > max_dynamic_enc[1]: + max_dynamic_enc[0] = re.sub(" ", "_", key) + max_dynamic_enc[1] = dynamic_enc + + if dynamic_dec > max_dynamic_dec[1]: + max_dynamic_dec[0] = re.sub(" ", "_", key) + max_dynamic_dec[1] = dynamic_dec + + if dynamic_encdec > max_dynamic_encdec[1]: + max_dynamic_encdec[0] = re.sub(" ", "_", key) + max_dynamic_encdec[1] = dynamic_encdec + + if total_enc > max_total_enc[1]: + max_total_enc[0] = re.sub(" ", "_", key) + max_total_enc[1] = total_enc + + if total_dec > max_static_dec[1]: + max_total_dec[0] = re.sub(" ", "_", key) + max_total_dec[1] = total_dec + + if total_encdec > max_static_encdec[1]: + max_total_encdec[0] = re.sub(" ", "_", key) + max_total_encdec[1] = total_encdec + +print( + revision, + shortDate, + fullDate, + max_total_encdec[1], + max_total_enc[0], + max_total_enc[1], + max_total_dec[0], + max_total_dec[1], + max_dynamic_encdec[1], + max_dynamic_encdec[0], + max_dynamic_enc[1], + max_dynamic_dec[0], + max_dynamic_dec[1], + max_static_enc[1] + max_static_dec[1], + max_static_enc[0], + max_static_enc[1], + max_static_dec[0], + max_static_dec[1], + newsletterFilenameLast, +) diff --git a/ci/complexity_measurements/parseNewsletterRom.py b/ci/complexity_measurements/parseNewsletterRom.py new file mode 100755 index 0000000000000000000000000000000000000000..aeb7ee26507afecf3c2f5f3b54add17e2a61fd5a --- /dev/null +++ b/ci/complexity_measurements/parseNewsletterRom.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +""" + (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. +""" + +import csv +import sys +import re + +newsletterFilename = "" +newsletterFilenameLast = "" +revision = "" +shortDate = "" +fullDate = "" + +if __name__ == "__main__": + newsletterFilename = sys.argv[1] + newsletterFilenameLast = sys.argv[2] + revision = sys.argv[3] + shortDate = sys.argv[4] + fullDate = sys.argv[5] + +max_total = ["", 0] + +with open(newsletterFilename, "r") as csvfile: + rom = csv.reader(csvfile, delimiter=";") + for row in rom: + if row[0] == "conf": + continue + if int(row[4]) > max_total[1]: + max_total[0] = re.sub(" ", "_", row[0]) + max_total[1] = int(row[4]) + +print(revision, shortDate, fullDate, max_total[1], newsletterFilenameLast) diff --git a/ci/complexity_measurements/parseNewsletterWmops.py b/ci/complexity_measurements/parseNewsletterWmops.py new file mode 100755 index 0000000000000000000000000000000000000000..06943726a00bd40115bec901a2aa101098be7dfc --- /dev/null +++ b/ci/complexity_measurements/parseNewsletterWmops.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +# coding: utf-8 +""" + (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. +""" + +import csv +import sys +import re + +newsletterFilename = "" +newsletterFilenameLast = "" +revision = "" +shortDate = "" +fullDate = "" + +if __name__ == "__main__": + newsletterFilename = sys.argv[1] + newsletterFilenameLast = sys.argv[2] + revision = sys.argv[3] + shortDate = sys.argv[4] + fullDate = sys.argv[5] + +max_enc = ["", 0] +max_dec = ["", 0] +max_total = ["", 0] +fixedpointScalingFac = 1.0 + +with open(newsletterFilename, "r") as csvfile: + wmops = csv.reader(csvfile, delimiter=";") + for row in wmops: + if row[0] == "conf": + continue + if float(row[1]) > max_enc[1]: + max_enc[0] = re.sub(" ", "_", row[0]) + max_enc[1] = float(row[1]) + if float(row[2]) > max_dec[1]: + max_dec[0] = re.sub(" ", "_", row[0]) + max_dec[1] = float(row[2]) + if float(row[3]) > max_total[1]: + max_total[0] = re.sub(" ", "_", row[0]) + max_total[1] = float(row[3]) + +print( + revision, + shortDate, + fullDate, + max_enc[1] + max_dec[1], + max_enc[0], + max_enc[1], + max_dec[0], + max_dec[1], + max_total[0], + max_total[1], + fixedpointScalingFac, + max_enc[1] + max_dec[1], + max_enc[0], + max_enc[1], + max_dec[0], + max_dec[1], + max_total[0], + max_total[1], + newsletterFilenameLast, +) diff --git a/ci/complexity_measurements/style.css b/ci/complexity_measurements/style.css new file mode 100755 index 0000000000000000000000000000000000000000..44fb55de46125fbad0e32bceb11b3395f355fbd1 --- /dev/null +++ b/ci/complexity_measurements/style.css @@ -0,0 +1,220 @@ +body { + background-color:#FFF; + font:.6875em Verdana, Arial, Helvetica, sans-serif; + color:#000; +} +a { + color:#000; + text-decoration:underline; +} +a:hover { + text-decoration:none; +} +h1 { + font-size:2.265em; + font-weight:700; + text-align: center; +} +em { + font-style: normal; + font-weight: bold; +} +hr { + margin-top: 30px; + margin-bottom: 30px; + margin-left: 150px; + margin-right:150px; + height: 0px; + border-top-width: 2px; + border-bottom-width: 0px; + border-left-width: 0px; + border-right-width: 0px; + border-top-style: solid; + color: #606060; +} +.graph { + width: 800px; + height: 350px; +} +.graph-container { + margin: 0 auto; + width:800px; +} +.message-box { + margin-top: 2em; + padding: 1em; + background-color: #FF8000; + border-radius: 20px; +} +#wmops-graph { + height:500px; + width:800px; + float:left; +} +#wmops_per_op-graph { + height:500px; + width:800px; + float:left; +} +#wmops-48kHz-graph { + height:500px; + width:800px; + float:left; +} +#wmops_per_op-48kHz-graph { + height:500px; + width:800px; + float:left; +} +#wmops_basop_per_op-graph { + height:500px; + width:800px; + float:left; +} +#wmops-graph-basop { + height:500px; + width:800px; + float:left; +} +#conversion_factors_basop_flc { + height:500px; + width:800px; + float:left; +} +#ram-graph { + height:500px; + width:800px; + float:left; +} +#ram-graph-basop { + height:500px; + width:800px; + float:left; +} +#rom-graph { + height:500px; + width:800px; + float:left; +} +#rom-graph-basop{ + height:500px; + width:800px; + float:left; +} +#prom-graph { + height:500px; + width:800px; + float:left; +} +#tooltip { + border-radius:.35em; + border-radius:.35em; + background-color:#000; + color:#FFF; + display:none; + opacity:0.8; + padding:.25em; + position:absolute; + box-shadow: 6px 6px 6px #666; +} +#tooltip a:link, #tooltip a:active, #tooltip a:visited { + color:#FFF; + text-decoration: underline; +} +#tooltip a:hover { + color:#FFF; + text-decoration: none; +} +.legend { + display: inline; +} +.legend li { + border-left: 1.2em solid #FFF; + margin-right: 2em; + padding-left: .3em; + margin-bottom: .2em; + list-style-type: none; +} + +#menu { + color: #FFFFFF; +} + +#menu ul { + color: #FFFFFF; + list-style: none; + margin-left: -1em; + position: relative; + margin-top: 1.5em; + margin-bottom: 1.5em; +} + +#menu li { + margin-left: -1em; + margin-bottom: 1.0em; + margin-top: 1.0em; +} + +#menu a { + color: #FFFFFF; +} + +dt { + font-weight: bold; +} + +dd hr { + margin-top: 0.1em; + margin-bottom: 0.1em; + margin-left: 48%; + margin-right: 48%; +} + +#menu { + float: left; + margin-left: 1em; + margin-top: 1em; + width: 22em; + border-radius: 1em; + position: fixed; + background-color: #000000; + opacity: 0.8; + box-shadow: 6px 6px 6px #666; +} + +#content { + margin-left: 17em; +} + +.symbols { + float: right; + font-weight: bolder; + font-size: 2em; + margin-top: -0.4em; +} + +.trafficlight { + margin-right: 0px; + margin-left: 0px; + position: absolute; + right: 2em; + color: #202020; +} + +.trend { + margin-right: 0.5em; + margin-left: 0.2em; +} + +th, td { + padding: 0.5em 2em; + border: 1px solid #606060; +} + +th { + text-align: left; +} + +td#number { + text-align: right; +} diff --git a/ci/get_id_of_last_job_occurence.py b/ci/get_id_of_last_job_occurence.py new file mode 100755 index 0000000000000000000000000000000000000000..f6223d998063d6d92db1e0ea9e376607a1767658 --- /dev/null +++ b/ci/get_id_of_last_job_occurence.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +""" + (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. +""" + +import argparse +import requests + +PER_PAGE_SUFFIX = "?per_page=50" +PAGE_SUFFIX = "&page={}" +API_BASE_URL = "https://forge.3gpp.org/rep/api/v4/projects/49" + + +parser = argparse.ArgumentParser() +parser.add_argument("branch_name") +parser.add_argument("job_name") + +args = parser.parse_args() + +branch_name = args.branch_name +job_name = args.job_name + + +job_id = -1 +# check last 500 pipelines max +for page in range(100): + url_pls = API_BASE_URL + "/pipelines" + + # need both suffixes here to descend through the pages and get also older pipelines + suffix = PER_PAGE_SUFFIX + PAGE_SUFFIX.format(page) + resp_pls = requests.get(url_pls + suffix) + for pl in resp_pls.json(): + if pl["ref"] == branch_name: + url_jobs = url_pls + f"/{pl['id']}/jobs" + + # only one of the suffixes here - this assumes only max of 50 jobs per pipeline + # so only one page needed + resp_jobs = requests.get(url_jobs + PER_PAGE_SUFFIX) + + if job_name not in resp_jobs.text: + continue + + # find actual job by name + for job in resp_jobs.json(): + if job["name"] == job_name and job["status"] == "success": + job_id = job["id"] + break + if job_id >= 0: + break + + if job_id >= 0: + break + +print(job_id) diff --git a/ci/index-pages.html b/ci/index-pages.html new file mode 100644 index 0000000000000000000000000000000000000000..f8b0709b03a6e8f0af817cfe294d171339bbd0ba --- /dev/null +++ b/ci/index-pages.html @@ -0,0 +1,19 @@ + + + + + +

Ivas Codec Development

+ +

Complexity Reports

+ + + + diff --git a/ci/run_evs_be_test.py b/ci/run_evs_be_test.py index 9fa64877f2ed44034c69bad4715e71aa3d40fa07..e3c6c750bba92b053f44230747416bdc19d17779 100755 --- a/ci/run_evs_be_test.py +++ b/ci/run_evs_be_test.py @@ -1,4 +1,33 @@ #!/usr/bin/env python3 +""" + (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. +""" import subprocess import pathlib import sys diff --git a/ci/run_scheduled_sanitizer_test.py b/ci/run_scheduled_sanitizer_test.py index 686e61822cf92850ced2624f2388bcaab6ba9575..b07a42d6acaeef2747692be7861ac6449d34595c 100755 --- a/ci/run_scheduled_sanitizer_test.py +++ b/ci/run_scheduled_sanitizer_test.py @@ -1,4 +1,33 @@ #!/usr/bin/env python3 +""" + (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. +""" import argparse import sys diff --git a/ci/smoke_test.sh b/ci/smoke_test.sh index e3caac3533d9e9be04427f10e5c01701b713f03a..3d7b85fdba1a61cf1202a4f13672efd550346297 100755 --- a/ci/smoke_test.sh +++ b/ci/smoke_test.sh @@ -1,5 +1,33 @@ #! /usr/bin/bash +# (C) 2022 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. + +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. + +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. + +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. + +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + if [ ! -d "lib_com" ]; then echo "not in root directory! - please run in IVAS root" exit 1