diff --git a/.circleci/config.yml b/.circleci/config.yml index a6c596b75598f66495ed8cef6e99dcffd693e860..f297a047b0c968a1bb951528b726ac80e435022d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,51 +1,251 @@ version: 2.1 orbs: android: circleci/android@0.2.1 - sonarcloud: sonarsource/sonarcloud@1.0.1 + sonarcloud: sonarsource/sonarcloud@1.0.2 commands: install-ndk: android/install-ndk - restore-build-cache: android/restore-build-cache - save-build-cache: android/save-build-cache + restore-android-build-cache: android/restore-build-cache + save-android-build-cache: android/save-build-cache scan-sonar: sonarcloud/scan -jobs: - quickBuildReleaseWithTestsAndChecks: - executor: android/android + restore-gradle-cache: + description: "Restore gradle caches" steps: - - checkout - - install-ndk: - ndk-sha: "c81a5bcb4672a18d3647bf6898cd4dbcb978d0e8" - ndk-version: "android-ndk-r21c" - - restore-build-cache - restore_cache: key: jars-{{ checksum "build.gradle" }}-{{ checksum "Corona-Warn-App/build.gradle" }}-{{ checksum "Server-Protocol-Buffer/build.gradle" }} - - run: - name: Quick Build - command: ./gradlew quickBuild - environment: - JVM_OPTS: -Xmx2048m - GRADLE_OPTS: -Xmx1536m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false - - save-build-cache + save-gradle-cache: + description: "Save gradle caches" + steps: - save_cache: paths: - ~/.gradle key: jars-{{ checksum "build.gradle" }}-{{ checksum "Corona-Warn-App/build.gradle" }}-{{ checksum "Server-Protocol-Buffer/build.gradle" }} + require-version-bump: + description: "Require version bump for binary assembling" + steps: + - run: + name: "Check if assemble required" + command: | + last_commit=$(git log -1 --pretty=%B) + if [[ $last_commit != *"Version bump"* ]]; then + circleci-agent step halt + echo "Skipping job" + fi + run-gradle-cmd: + description: "Running gradle command with environment options" + parameters: + desc: + type: string + default: "Running gradle command" + cmd: + type: string + steps: + - run: + name: << parameters.desc >> + command: ./gradlew << parameters.cmd >> + environment: + JVM_OPTS: -Xmx2048m + GRADLE_OPTS: -Xmx1536m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false + run-gradle-cmd-test-splitting: + description: "Running gradle command with environment options and test splitting" + parameters: + desc: + type: string + default: "Running gradle command" + cmd: + type: string + steps: - run: - name: JaCoCo report - command: ./gradlew :Corona-Warn-App:jacocoTestReportDeviceRelease + name: Test splitting output + command: circleci tests glob "**/test*/**/*.kt" | circleci tests split | xargs -n 1 echo + - run: + name: << parameters.desc >> + command: ./gradlew << parameters.cmd >> -i -PtestFilter="`circleci tests glob "**/test*/**/*.kt" | circleci tests split`" environment: JVM_OPTS: -Xmx2048m GRADLE_OPTS: -Xmx1536m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false + +jobs: + quick_build_device_release_no_tests: + executor: android/android + resource_class: large + working_directory: ~/project + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - require-version-bump + - install-ndk: + ndk-sha: "c81a5bcb4672a18d3647bf6898cd4dbcb978d0e8" + ndk-version: "android-ndk-r21c" + - run-gradle-cmd: + desc: Quick Build + cmd: "assembleDeviceRelease" + - save-gradle-cache + - save-android-build-cache + - store_artifacts: + path: Corona-Warn-App/build/reports + destination: reports + quick_build_device_for_testers_release_no_tests: + executor: android/android + resource_class: large + working_directory: ~/project + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - require-version-bump + - install-ndk: + ndk-sha: "c81a5bcb4672a18d3647bf6898cd4dbcb978d0e8" + ndk-version: "android-ndk-r21c" + - run-gradle-cmd: + desc: Quick Build + cmd: ":Corona-Warn-App:assembleDeviceForTestersRelease" + - save-gradle-cache + - save-android-build-cache + - store_artifacts: + path: Corona-Warn-App/build/reports + destination: reports + device_release_unit_tests: + executor: android/android + resource_class: large + working_directory: ~/project + parallelism: 3 + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - run-gradle-cmd-test-splitting: + desc: Unit tests + cmd: ":Corona-Warn-App:testDeviceReleaseUnitTest -i" + - save-gradle-cache + - save-android-build-cache - store_artifacts: path: Corona-Warn-App/build/reports destination: reports - store_test_results: path: Corona-Warn-App/build/test-results + - persist_to_workspace: + root: /home/circleci + paths: + - ./project + device_for_testers_release_unit_tests: + executor: android/android + resource_class: large + working_directory: ~/project + parallelism: 3 + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - run-gradle-cmd-test-splitting: + desc: Unit tests with splitting + cmd: ":Corona-Warn-App:testDeviceForTestersReleaseUnitTest" + - save-gradle-cache + - save-android-build-cache + - store_artifacts: + path: Corona-Warn-App/build/reports + destination: reports + - store_test_results: + path: Corona-Warn-App/build/test-results + lint_device_release_check: + executor: android/android + resource_class: large + working_directory: ~/project + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - run-gradle-cmd: + desc: Lint check deviceRelease + cmd: ":Corona-Warn-App:lintDeviceRelease -i" + - store_artifacts: + path: Corona-Warn-App/build/reports + destination: reports + ktlint_device_release_check: + executor: android/android + resource_class: medium + working_directory: ~/project + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - run-gradle-cmd: + desc: Ktlint check deviceRelease + cmd: ":Corona-Warn-App:ktlintDeviceReleaseCheck" + - store_artifacts: + path: Corona-Warn-App/build/reports + destination: reports + lint_device_for_testers_release_check: + executor: android/android + resource_class: large + working_directory: ~/project + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - run-gradle-cmd: + desc: Lint check deviceForTestersRelease + cmd: ":Corona-Warn-App:lintDeviceForTestersRelease -i" + - store_artifacts: + path: Corona-Warn-App/build/reports + destination: reports + ktlint_device_for_testers_release_check: + executor: android/android + resource_class: medium + working_directory: ~/project + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - run-gradle-cmd: + desc: Ktlint check deviceForTestersRelease + cmd: ":Corona-Warn-App:ktlintDeviceForTestersReleaseCheck" + - store_artifacts: + path: Corona-Warn-App/build/reports + destination: reports + detekt: + executor: android/android + resource_class: medium + working_directory: ~/project + steps: + - checkout + - restore-gradle-cache + - restore-android-build-cache + - run-gradle-cmd: + desc: Detekt check + cmd: ":Corona-Warn-App:detekt" + - store_artifacts: + path: Corona-Warn-App/build/reports + destination: reports + run_sonar: + executor: android/android + resource_class: large + working_directory: ~/project + steps: + - attach_workspace: + at: /home/circleci + - restore-gradle-cache + - restore-android-build-cache + - run-gradle-cmd: + desc: JaCoCo report + cmd: ":Corona-Warn-App:jacocoTestReportDeviceRelease -i" - run: name: Skip SonarCloud for external Pull Requests command: '[[ -v CIRCLE_PR_REPONAME ]] && circleci-agent step halt || true' - scan-sonar workflows: version: 2 - workflow: + quick_build: jobs: - - quickBuildReleaseWithTestsAndChecks + - quick_build_device_release_no_tests + - quick_build_device_for_testers_release_no_tests + - device_release_unit_tests + - device_for_testers_release_unit_tests + - lint_device_release_check + - lint_device_for_testers_release_check + - ktlint_device_release_check + - ktlint_device_for_testers_release_check + - detekt + - run_sonar: + requires: + - device_release_unit_tests diff --git a/.editorconfig b/.editorconfig index bf9d722a793b4fd16c0faad77e037bf6f4733c05..b9faf287b62f7d560a42d520f226271c15262f52 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,3 @@ [*.{kt, kts}] -disabled_rules = import-ordering \ No newline at end of file +disabled_rules = import-ordering +insert_final_newline = true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7aab3fb4e331226065e513841448ffbc68f8a2b6..5b75aebd94871c4b9fd4b57f986af43e1fafc09e 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,18 +1,44 @@ <!-- Thank you for supporting us with your Pull Request! 🙌 â¤ï¸ Before submitting, please take the time to check the points below and provide some descriptive information. + +Remove the checklist after fulfilling all the relevant points, and before creating the PR, thank you. --> -## Checklist +### Checklist + +__Thank you for this this PR! Please consider the following:__ + +* To the _Community_ :heart:: + * Please link to an issue ticket where your code change has been greenlit, otherwise it's unlikely it can be merged. + * Use a descriptive title: {task_name} (closes #{issue_number}), e.g.: `Use logger (closes # 41)`. + * If this PR comes from a fork, please [Allow edits from maintainers](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) + * The PR can not contain changes in localization files, e.g. `values-[LANGUAGE-CODE]/strings/*` and `/` or `assets/*` (see [#332](https://github.com/corona-warn-app/cwa-app-android/issues/332) for further information). +* To the _Maintainers_ :coffee:: + * Title structure: `Jira ticket name (EXPOSUREAPP-XXXX)`. + * Set labels: `maintainers`, `sprintX`. + * Update Jira status: `In Review`. + * Fulfill internal `Acceptance Criteria`. + * If mentioned in the Jira ticket link all corresponding GitHub issues in the sidebar. +* To _everyone_ :world_map:: + * Describe your changes in detail, if you changed the UI, screenshots or GIFs would be awesome! + * Short step by step instructions help the reviewer test your changes, e.g. how to navigate to a new UI element you added. + * The PR _won't be reviewed_ if CircleCi is failing or if there are merge conflicts. If Circle CI is still failing mark the PR as a draft and write a little comment on your status. + * Provide at least a few unit and/or instrumentation tests. + * Use a meaning full branch name. Use either `fix` or `feature` as prefix for your branch, e.g. `fix/prevent-npe-on-device-rotation-issue_123` + * Test your changes thoroughly. Only open PRs which you think is ready to be merged. If you explicitly need feedback mark the PR as `DRAFT` on Github. + * Don't introduce unrelated code reformatting (e.g., on-save hooks in your IDE) + * Remove this checklist before creating your pull request. -* [ ] Test your changes as thoroughly as possible before you commit them. Preferably, automate your test by unit/integration tests. -* [ ] If this PR comes from a fork, please [Allow edits from maintainers](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) -* [ ] Set a speaking title. Format: {task_name} (closes #{issue_number}). For example: Use logger (closes # 41) -* [ ] [Link your Pull Request to an issue](https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) - Pull Requests that are not linked to an issue with you as an assignee will be closed, except for minor fixes for typos or grammar mistakes in *documentation or code comments*. -* [ ] Create Work In Progress [WIP] pull requests only if you need clarification or an explicit review before you can continue your work item. -* [ ] Make sure that your PR is not introducing _unnecessary_ reformatting (e.g., introduced by on-save hooks in your IDE) -* [ ] Make sure that your PR does not contain changes in text files, therefore the PR must not contain changes in values/strings/* and / or assets/* (see issue #332 for further information) -* [ ] Make sure that your PR does not contain compiled sources (already set by the default .gitignore) and / or binary files +### Description -## Description -<!-- Please be brief in describing which issue is solved by your PR or which enhancement it brings --> +<!-- +Please be brief in describing which issue is solved by your PR or which enhancement it brings. Link related issues! +--> + +### Steps to reproduce +<!-- +How can your changes be tested? +1. First step +2. Second step + --> diff --git a/.gitignore b/.gitignore index 7da76f859c5c71c0684c2423e040524382f5a70e..30e7583245dcdea48efe48cb1215dd246aac0b38 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,7 @@ /captures .externalNativeBuild .cxx -/.idea/ +/.idea/**/* +!/.idea/codeStyles/ +!/.idea/codeStyles/**/* +/test_environments.json diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000000000000000000000000000000000000..098fe846891336dbe9c4465f59ebbba03506e4f1 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,136 @@ +<component name="ProjectCodeStyleConfiguration"> + <code_scheme name="Project" version="173"> + <JetCodeStyleSettings> + <option name="PACKAGES_TO_USE_STAR_IMPORTS"> + <value> + <package name="kotlinx.android.synthetic" withSubpackages="true" static="false" /> + </value> + </option> + <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="99" /> + <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="99" /> + <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> + </JetCodeStyleSettings> + <codeStyleSettings language="XML"> + <indentOptions> + <option name="CONTINUATION_INDENT_SIZE" value="4" /> + </indentOptions> + <arrangement> + <rules> + <section> + <rule> + <match> + <AND> + <NAME>xmlns:android</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>xmlns:.*</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:id</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*:name</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>name</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>style</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>^$</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> + </AND> + </match> + <order>ANDROID_ATTRIBUTE_ORDER</order> + </rule> + </section> + <section> + <rule> + <match> + <AND> + <NAME>.*</NAME> + <XML_ATTRIBUTE /> + <XML_NAMESPACE>.*</XML_NAMESPACE> + </AND> + </match> + <order>BY_NAME</order> + </rule> + </section> + </rules> + </arrangement> + </codeStyleSettings> + <codeStyleSettings language="kotlin"> + <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> + <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" /> + <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> + <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" /> + <option name="FIELD_ANNOTATION_WRAP" value="1" /> + <indentOptions> + <option name="CONTINUATION_INDENT_SIZE" value="4" /> + </indentOptions> + </codeStyleSettings> + </code_scheme> +</component> \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000000000000000000000000000000000..79ee123c2b23e069e35ed634d687e17f731cc702 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ +<component name="ProjectCodeStyleConfiguration"> + <state> + <option name="USE_PER_PROJECT_SETTINGS" value="true" /> + </state> +</component> \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index 32e4e4c272321c258ca23796e68cee4d04f18706..889237e4267d9de3958cc27f4e0801d0fad009cc 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,3 +6,6 @@ # These are the default owners for the whole content of this repository. The default owners are automatically added as reviewers when you open a pull request, unless different owners are specified in the file. * @corona-warn-app/cwa-app-android-maintainers + +# Code Onwer of all german texts +/Corona-Warn-App/src/main/res/values-de/ @janetback @SabineLoss diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle index 215d1c63d4a6e1e0eb43ed82fde1540d18c70767..b6d471b6ce16d2a6fb54c2b96d5446cf281d028d 100644 --- a/Corona-Warn-App/build.gradle +++ b/Corona-Warn-App/build.gradle @@ -24,6 +24,13 @@ apply plugin: 'kotlin-kapt' apply plugin: "androidx.navigation.safeargs.kotlin" apply plugin: 'jacoco' + +def environmentExtractor = { File path -> + def rawJson = path.text + def escapedJson = rawJson.replace("\"", "\\\"").replace("\n", "").replace("\r", "") + return "\"${escapedJson}\"" +} + android { ndkVersion "21.2.6472646" compileSdkVersion 29 @@ -33,42 +40,20 @@ android { applicationId 'de.rki.coronawarnapp' minSdkVersion 23 targetSdkVersion 29 - versionCode 38 - versionName "1.3.1" + versionCode 47 + versionName "1.5.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - - resConfigs "de", "en", "tr", "bg", "pl", "ro" - - buildConfigField "String", "DOWNLOAD_CDN_URL", "\"$DOWNLOAD_CDN_URL\"" - buildConfigField "String", "SUBMISSION_CDN_URL", "\"$SUBMISSION_CDN_URL\"" - buildConfigField "String", "VERIFICATION_CDN_URL", "\"$VERIFICATION_CDN_URL\"" - buildConfigField "String", "PUB_KEYS_SIGNATURE_VERIFICATION", "\"$PUB_KEYS_SIGNATURE_VERIFICATION\"" - - //override URLs. Use local.properties if exist. - // If environment.properties also exist, override local.properties - def propertiesFile = project.rootProject.file('local.properties') - - - if (propertiesFile.exists()) { - Properties overridingProperties = new Properties() - overridingProperties.load(propertiesFile.newDataInputStream()) - - def DOWNLOAD_CDN_URL = overridingProperties.getProperty('DOWNLOAD_CDN_URL') - if (DOWNLOAD_CDN_URL) - buildConfigField "String", "DOWNLOAD_CDN_URL", "\"$DOWNLOAD_CDN_URL\"" - def SUBMISSION_CDN_URL = overridingProperties.getProperty('SUBMISSION_CDN_URL') - if (SUBMISSION_CDN_URL) - buildConfigField "String", "SUBMISSION_CDN_URL", "\"$SUBMISSION_CDN_URL\"" + resConfigs "de", "en", "tr", "bg", "pl", "ro" - def VERIFICATION_CDN_URL = overridingProperties.getProperty('VERIFICATION_CDN_URL') - if (VERIFICATION_CDN_URL) - buildConfigField "String", "VERIFICATION_CDN_URL", "\"$VERIFICATION_CDN_URL\"" + def prodEnvJson = environmentExtractor(file("../prod_environments.json")) + buildConfigField "String", "ENVIRONMENT_JSONDATA", prodEnvJson - def PUB_KEYS_SIGNATURE_VERIFICATION = overridingProperties.getProperty('PUB_KEYS_SIGNATURE_VERIFICATION') - if (PUB_KEYS_SIGNATURE_VERIFICATION) - buildConfigField "String", "PUB_KEYS_SIGNATURE_VERIFICATION", "\"$PUB_KEYS_SIGNATURE_VERIFICATION\"" + def devEnvironmentFile = file("../test_environments.json") + if (devEnvironmentFile.exists()) { + def devEnvJson = environmentExtractor(devEnvironmentFile) + buildConfigField "String", "ENVIRONMENT_JSONDATA", devEnvJson } javaCompileOptions { @@ -79,6 +64,8 @@ android { } buildTypes { + debug { + } release { minifyEnabled true shrinkResources true @@ -86,43 +73,33 @@ android { } } - // One version contains our Test Fragments + flavorDimensions "version" productFlavors { device { dimension "version" - buildConfigField "String", "BUILD_VARIANT", "\"device\"" resValue "string", "app_name", "Corona-Warn" + + ext { + envTypeDefault = [debug: "INT", release: "PROD"] + } } deviceForTesters { + // Contains test fragments dimension "version" - buildConfigField "String", "BUILD_VARIANT", "\"deviceForTesters\"" resValue "string", "app_name", "CWA TEST" applicationIdSuffix '.dev' - def environmentPropertiesFile = project.rootProject.file('environment.properties') - if (environmentPropertiesFile.exists()) { - Properties overridingProperties = new Properties() - overridingProperties.load(environmentPropertiesFile.newDataInputStream()) - - def DOWNLOAD_CDN_URL = overridingProperties.getProperty('DOWNLOAD_CDN_URL') - if (DOWNLOAD_CDN_URL) - buildConfigField "String", "DOWNLOAD_CDN_URL", "\"$DOWNLOAD_CDN_URL\"" - - def SUBMISSION_CDN_URL = overridingProperties.getProperty('SUBMISSION_CDN_URL') - if (SUBMISSION_CDN_URL) - buildConfigField "String", "SUBMISSION_CDN_URL", "\"$SUBMISSION_CDN_URL\"" - - def VERIFICATION_CDN_URL = overridingProperties.getProperty('VERIFICATION_CDN_URL') - if (VERIFICATION_CDN_URL) - buildConfigField "String", "VERIFICATION_CDN_URL", "\"$VERIFICATION_CDN_URL\"" - - def PUB_KEYS_SIGNATURE_VERIFICATION = overridingProperties.getProperty('PUB_KEYS_SIGNATURE_VERIFICATION') - if (PUB_KEYS_SIGNATURE_VERIFICATION) - buildConfigField "String", "PUB_KEYS_SIGNATURE_VERIFICATION", "\"$PUB_KEYS_SIGNATURE_VERIFICATION\"" + ext { + envTypeDefault = [debug: "INT", release: "WRU-XD"] } } } + applicationVariants.all { variant -> + def flavor = variant.productFlavors[0] + def typeName = variant.buildType.name // debug/release + variant.buildConfigField "String", "ENVIRONMENT_TYPE_DEFAULT", "\"${flavor.envTypeDefault[typeName]}\"" + } buildFeatures { dataBinding true @@ -137,11 +114,32 @@ android { jvmTarget = "1.8" } + def jvmCompilerArgs = ["-Xno-kotlin-nothing-value-exception"] + + tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile) { + kotlinOptions { + freeCompilerArgs = jvmCompilerArgs + } + } + lintOptions { checkAllWarnings = true } testOptions { + unitTests.all { + useJUnitPlatform() + if (project.hasProperty('testFilter')) { + List<String> props = project.getProperties().get("testFilter").split("\\s+") + props.each { + def replaced = it + .replaceFirst("^(Corona-Warn-App/src/test.*/java/)(.+)\$", "**/\$2") + .replace(".kt", ".class") + project.logger.lifecycle("testFilter File: before=$it, after=$replaced") + include(replaced) + } + } + } unitTests { includeAndroidResources = true returnDefaultValues = true @@ -179,7 +177,6 @@ android { } } } - } task jacocoTestReportDeviceRelease(type: JacocoReport, dependsOn: 'testDeviceReleaseUnitTest') { @@ -205,10 +202,10 @@ task jacocoTestReportDeviceRelease(type: JacocoReport, dependsOn: 'testDeviceRel ] def classPaths = [ - "**/intermediates/classes/deviceRelease/**", - "**/intermediates/javac/deviceRelease/*/classes/**", // Android Gradle Plugin 3.2.x support. - "**/intermediates/javac/deviceRelease/classes/**", // Android Gradle Plugin 3.4 and 3.5 support. - "**/tmp/kotlin-classes/deviceRelease/**" + "**/intermediates/classes/deviceRelease/**", + "**/intermediates/javac/deviceRelease/*/classes/**", // Android Gradle Plugin 3.2.x support. + "**/intermediates/javac/deviceRelease/classes/**", // Android Gradle Plugin 3.4 and 3.5 support. + "**/tmp/kotlin-classes/deviceRelease/**" ] def debugTree = fileTree(dir: "$buildDir", includes: classPaths, excludes: excludes) @@ -234,24 +231,58 @@ dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.work:work-runtime-ktx:2.3.4' - implementation 'android.arch.lifecycle:extensions:1.1.1' + implementation 'android.arch.lifecycle:extensions:2.2.0' + implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0' implementation 'androidx.annotation:annotation:1.1.0' + implementation "androidx.recyclerview:recyclerview:1.1.0" + implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc02" + + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' + + + // DAGGER + implementation 'com.google.dagger:dagger:2.28.1' + implementation 'com.google.dagger:dagger-android:2.28.1' + implementation 'com.google.dagger:dagger-android-support:2.28.1' + kapt 'com.google.dagger:dagger-compiler:2.28.1' + kapt 'com.google.dagger:dagger-android-processor:2.28.1' + + compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.2' + kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.2' // QR implementation('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false } // noinspection GradleDependency - needed for SDK 23 compatibility, in combination with com.journeyapps:zxing-android-embedded:4.1.0 implementation 'com.google.zxing:core:3.3.0' - // TESTING - testImplementation 'junit:junit:4.13' + //ENA + implementation files('libs\\play-services-nearby-exposurenotification-1.6.1-eap.aar') + + // Testing testImplementation "android.arch.core:core-testing:1.1.1" - testImplementation "org.mockito:mockito-core:3.3.3" testImplementation('org.robolectric:robolectric:4.3.1') { exclude group: 'com.google.protobuf' } testImplementation "io.mockk:mockk:1.10.0" testImplementation "com.squareup.okhttp3:mockwebserver:4.8.0" testImplementation 'org.hamcrest:hamcrest-library:2.2' + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9' + + // Testing - jUnit4 + testImplementation 'junit:junit:4.13' + testImplementation "org.junit.vintage:junit-vintage-engine:5.6.2" + + // Testing - jUnit5 + testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.6.2" + testImplementation "org.junit.jupiter:junit-jupiter-params:5.6.2" + testImplementation "io.kotest:kotest-runner-junit5:4.2.0" + testImplementation "io.kotest:kotest-assertions-core-jvm:4.2.0" + testImplementation "io.kotest:kotest-property-jvm:4.2.0" + androidTestImplementation "io.kotest:kotest-assertions-core-jvm:4.2.0" + androidTestImplementation "io.kotest:kotest-property-jvm:4.2.0" + + // Testing - Instrumentation androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -268,7 +299,6 @@ dependencies { implementation 'com.google.android.gms:play-services-basement:17.3.0' implementation 'com.google.android.gms:play-services-safetynet:17.0.0' implementation 'com.google.android.gms:play-services-tasks:17.1.0' - api fileTree(dir: 'libs', include: ['play-services-nearby-18.0.3-eap.aar']) // HTTP implementation 'com.squareup.retrofit2:retrofit:2.9.0' @@ -294,7 +324,7 @@ dependencies { implementation 'joda-time:joda-time:2.10.6' // SECURITY - implementation "androidx.security:security-crypto:1.0.0-rc02" + implementation "androidx.security:security-crypto:1.0.0-rc03" implementation 'net.zetetic:android-database-sqlcipher:4.4.0' implementation 'org.conscrypt:conscrypt-android:2.4.0' diff --git a/Corona-Warn-App/config/detekt.yml b/Corona-Warn-App/config/detekt.yml index 1a5fd4a6d97d1f13e143788f0f59c9d3b2bdc5cc..0d06a280c125c8b8c72ebac0e0e8d104882ef824 100644 --- a/Corona-Warn-App/config/detekt.yml +++ b/Corona-Warn-App/config/detekt.yml @@ -100,7 +100,7 @@ complexity: ignoreStringsRegex: '$^' TooManyFunctions: active: true - excludes: ['**/test/**', '**/androidTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt', '**/LocalData.kt', '**/formatter/*Helper.kt'] + excludes: ['**/test/**', '**/androidTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt', '**/LocalData.kt', '**/formatter/*Helper.kt', '**/*ViewModel.kt'] thresholdInFiles: 20 thresholdInClasses: 20 thresholdInInterfaces: 20 @@ -568,11 +568,11 @@ style: active: false ReturnCount: active: true - max: 2 + max: 6 excludedFunctions: 'equals' excludeLabeled: false excludeReturnFromLambda: true - excludeGuardClauses: false + excludeGuardClauses: true SafeCast: active: true SerialVersionUIDInSerializableClass: diff --git a/Corona-Warn-App/libs/play-services-nearby-18.0.3-eap.aar b/Corona-Warn-App/libs/play-services-nearby-18.0.3-eap.aar deleted file mode 100644 index e962ff05fe26d42afcad95658a864d98995b0df8..0000000000000000000000000000000000000000 Binary files a/Corona-Warn-App/libs/play-services-nearby-18.0.3-eap.aar and /dev/null differ diff --git a/Corona-Warn-App/libs/play-services-nearby-exposurenotification-1.6.1-eap.aar b/Corona-Warn-App/libs/play-services-nearby-exposurenotification-1.6.1-eap.aar new file mode 100644 index 0000000000000000000000000000000000000000..6eddb67adf1c8419af03a6c68153ba5dbb7397b1 Binary files /dev/null and b/Corona-Warn-App/libs/play-services-nearby-exposurenotification-1.6.1-eap.aar differ diff --git a/Corona-Warn-App/proguard-rules.pro b/Corona-Warn-App/proguard-rules.pro index 067b7d21c059535c5904f766d6e1ed0dd58f1a9c..13dfa13cd055802fd1285f1182d31af5f22bf11a 100644 --- a/Corona-Warn-App/proguard-rules.pro +++ b/Corona-Warn-App/proguard-rules.pro @@ -59,5 +59,32 @@ -if interface * { @retrofit2.http.* <methods>; } -keep,allowobfuscation interface <1> --keep class de.rki.coronawarnapp.http.requests.* { *; } --keep class de.rki.coronawarnapp.http.responses.* { *; } \ No newline at end of file + +##---------------Begin: proguard configuration for Gson ---------- +# Gson uses generic type information stored in a class file when working with fields. Proguard +# removes such information by default, so configure it to keep all of it. +-keepattributes Signature + +# For using GSON @Expose annotation +-keepattributes *Annotation* + +# Gson specific classes +-dontwarn sun.misc.** +#-keep class com.google.gson.stream.** { *; } + +# Application classes that will be serialized/deserialized over Gson +-keep class com.google.gson.examples.android.model.** { <fields>; } + +# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory, +# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) +-keep class * extends com.google.gson.TypeAdapter +-keep class * implements com.google.gson.TypeAdapterFactory +-keep class * implements com.google.gson.JsonSerializer +-keep class * implements com.google.gson.JsonDeserializer + +# Prevent R8 from leaving Data object members always null +-keepclassmembers,allowobfuscation class * { + @com.google.gson.annotations.SerializedName <fields>; +} + +##---------------End: proguard configuration for Gson ---------- \ No newline at end of file diff --git a/Corona-Warn-App/schemas/de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheDatabase/1.json b/Corona-Warn-App/schemas/de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheDatabase/1.json new file mode 100644 index 0000000000000000000000000000000000000000..72e78dde4ed14af776eb7965dd3234b4da1db874 --- /dev/null +++ b/Corona-Warn-App/schemas/de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheDatabase/1.json @@ -0,0 +1,76 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "c4ef5f7d4d9672d11c8eb97a63d4a3c5", + "entities": [ + { + "tableName": "keyfiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` TEXT NOT NULL, `location` TEXT NOT NULL, `day` TEXT NOT NULL, `hour` TEXT, `createdAt` TEXT NOT NULL, `checksumMD5` TEXT, `completed` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "location", + "columnName": "location", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "day", + "columnName": "day", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hour", + "columnName": "hour", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "checksumMD5", + "columnName": "checksumMD5", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDownloadComplete", + "columnName": "completed", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c4ef5f7d4d9672d11c8eb97a63d4a3c5')" + ] + } +} \ No newline at end of file diff --git a/Corona-Warn-App/schemas/de.rki.coronawarnapp.storage.keycache.KeyCacheDatabase/1.json b/Corona-Warn-App/schemas/de.rki.coronawarnapp.storage.keycache.KeyCacheDatabase/1.json new file mode 100644 index 0000000000000000000000000000000000000000..9d856a5a015c0bef5716d2c808ee37e5f6b95d8e --- /dev/null +++ b/Corona-Warn-App/schemas/de.rki.coronawarnapp.storage.keycache.KeyCacheDatabase/1.json @@ -0,0 +1,82 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "03f6e8cba631c8ef60e506006913a1ad", + "entities": [ + { + "tableName": "keyfiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` TEXT NOT NULL, `location` TEXT NOT NULL, `day` TEXT NOT NULL, `hour` TEXT, `sourceUrl` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `checksumMD5` TEXT, `completed` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "location", + "columnName": "location", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "day", + "columnName": "day", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hour", + "columnName": "hour", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sourceUrl", + "columnName": "sourceUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "checksumMD5", + "columnName": "checksumMD5", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDownloadComplete", + "columnName": "completed", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '03f6e8cba631c8ef60e506006913a1ad')" + ] + } +} \ No newline at end of file diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheDatabaseTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheDatabaseTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..ac0ccdefe87983cc638001ef67e900c75810b44a --- /dev/null +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheDatabaseTest.kt @@ -0,0 +1,79 @@ +package de.rki.coronawarnapp.diagnosiskeys.storage + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.runBlocking +import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class KeyCacheDatabaseTest { + private val database = KeyCacheDatabase.Factory( + ApplicationProvider.getApplicationContext<Context>() + ).create() + private val dao = database.cachedKeyFiles() + + @Test + fun crud() { + val keyDay = CachedKeyInfo( + type = CachedKeyInfo.Type.COUNTRY_DAY, + location = LocationCode("DE"), + day = LocalDate.now(), + hour = null, + createdAt = Instant.now() + ) + val keyHour = CachedKeyInfo( + type = CachedKeyInfo.Type.COUNTRY_HOUR, + location = LocationCode("DE"), + day = LocalDate.now(), + hour = LocalTime.now(), + createdAt = Instant.now() + ) + runBlocking { + dao.clear() + + dao.insertEntry(keyDay) + dao.insertEntry(keyHour) + dao.getAllEntries() shouldBe listOf(keyDay, keyHour) + dao.getEntriesForType(CachedKeyInfo.Type.COUNTRY_DAY.typeValue) shouldBe listOf(keyDay) + dao.getEntriesForType(CachedKeyInfo.Type.COUNTRY_HOUR.typeValue) shouldBe listOf(keyHour) + + dao.updateDownloadState(keyDay.toDownloadUpdate("coffee")) + dao.getEntriesForType(CachedKeyInfo.Type.COUNTRY_DAY.typeValue).single().apply { + isDownloadComplete shouldBe true + checksumMD5 shouldBe "coffee" + } + dao.getEntriesForType(CachedKeyInfo.Type.COUNTRY_HOUR.typeValue).single().apply { + isDownloadComplete shouldBe false + checksumMD5 shouldBe null + } + + dao.updateDownloadState(keyHour.toDownloadUpdate("with milk")) + dao.getEntriesForType(CachedKeyInfo.Type.COUNTRY_DAY.typeValue).single().apply { + isDownloadComplete shouldBe true + checksumMD5 shouldBe "coffee" + } + dao.getEntriesForType(CachedKeyInfo.Type.COUNTRY_HOUR.typeValue).single().apply { + isDownloadComplete shouldBe true + checksumMD5 shouldBe "with milk" + } + + dao.deleteEntry(keyDay) + dao.getAllEntries() shouldBe listOf( + keyHour.copy( + isDownloadComplete = true, + checksumMD5 = "with milk" + ) + ) + + dao.clear() + dao.getAllEntries() shouldBe emptyList() + } + } +} diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/storage/keycache/KeyCacheDaoTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/storage/keycache/KeyCacheDaoTest.kt deleted file mode 100644 index 31f173f6c73eeed0e6be923f245476d8854b608e..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/storage/keycache/KeyCacheDaoTest.kt +++ /dev/null @@ -1,88 +0,0 @@ -package de.rki.coronawarnapp.storage.keycache - -import android.content.Context -import androidx.room.Room -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.google.common.truth.Truth.assertThat -import de.rki.coronawarnapp.storage.AppDatabase -import kotlinx.coroutines.runBlocking -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -/** - * KeyCacheDao test. - */ -@RunWith(AndroidJUnit4::class) -class KeyCacheDaoTest { - private lateinit var keyCacheDao: KeyCacheDao - private lateinit var db: AppDatabase - - @Before - fun setUp() { - val context = ApplicationProvider.getApplicationContext<Context>() - db = Room.inMemoryDatabaseBuilder( - context, AppDatabase::class.java - ).build() - keyCacheDao = db.dateDao() - } - - /** - * Test Create / Read / Delete DB operations. - */ - @Test - fun testCRDOperations() { - runBlocking { - val dates = KeyCacheEntity().apply { - this.id = "0" - this.path = "0" - this.type = 0 - } - val hours = KeyCacheEntity().apply { - this.id = "1" - this.path = "1" - this.type = 1 - } - - assertThat(keyCacheDao.getAllEntries().isEmpty()).isTrue() - - keyCacheDao.insertEntry(dates) - keyCacheDao.insertEntry(hours) - - var all = keyCacheDao.getAllEntries() - - assertThat(all.size).isEqualTo(2) - - val selectedDates = keyCacheDao.getDates() - assertThat(selectedDates.size).isEqualTo(1) - assertThat(selectedDates[0].type).isEqualTo(0) - assertThat(selectedDates[0].id).isEqualTo(dates.id) - - val selectedHours = keyCacheDao.getHours() - assertThat(selectedHours.size).isEqualTo(1) - assertThat(selectedHours[0].type).isEqualTo(1) - assertThat(selectedHours[0].id).isEqualTo(hours.id) - - keyCacheDao.clearHours() - - all = keyCacheDao.getAllEntries() - assertThat(all.size).isEqualTo(1) - assertThat(all[0].type).isEqualTo(0) - - keyCacheDao.insertEntry(hours) - - assertThat(keyCacheDao.getAllEntries().size).isEqualTo(2) - - keyCacheDao.clear() - - assertThat(keyCacheDao.getAllEntries().isEmpty()).isTrue() - } - } - - @After - fun closeDb() { - db.close() - } -} diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/DBPasswordTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/DBPasswordTest.kt index 5f1267524ea5ac46b4214d3eab5b483c1c0e12c2..efbab6568042db7b60157a13dcf0005d6b5e4b3d 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/DBPasswordTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/DBPasswordTest.kt @@ -22,7 +22,8 @@ package de.rki.coronawarnapp.util.security import android.content.Context import androidx.test.core.app.ApplicationProvider import de.rki.coronawarnapp.storage.AppDatabase -import de.rki.coronawarnapp.storage.keycache.KeyCacheEntity +import de.rki.coronawarnapp.storage.tracing.TracingIntervalEntity +import io.kotest.matchers.shouldBe import kotlinx.coroutines.runBlocking import net.sqlcipher.database.SQLiteException import org.hamcrest.Matchers.equalTo @@ -33,8 +34,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import java.util.UUID -import kotlin.random.Random @RunWith(JUnit4::class) class DBPasswordTest { @@ -70,16 +69,14 @@ class DBPasswordTest { @Test fun canLoadDataFromEncryptedDatabase() { runBlocking { - val id = UUID.randomUUID().toString() - val path = UUID.randomUUID().toString() - val type = Random.nextInt(1000) - - insertFakeEntity(id, path, type) - val keyCacheEntity = loadFakeEntity() - - assertThat(keyCacheEntity.id, equalTo(id)) - assertThat(keyCacheEntity.path, equalTo(path)) - assertThat(keyCacheEntity.type, equalTo(type)) + val from = 123L + val to = 456L + insertFakeEntity(from, to) + + loadFakeEntity().apply { + this.from shouldBe from + this.to shouldBe to + } } } @@ -95,34 +92,32 @@ class DBPasswordTest { @Test(expected = SQLiteException::class) fun loadingDataFromDatabaseWillFailWhenPassphraseIsIncorrect() { runBlocking { - val id = UUID.randomUUID().toString() - val path = UUID.randomUUID().toString() - val type = Random.nextInt(1000) - insertFakeEntity(id, path, type) + val from = 123L + val to = 456L + insertFakeEntity(from, to) clearSharedPreferences() AppDatabase.resetInstance() - val keyCacheEntity = loadFakeEntity() - assertThat(keyCacheEntity.id, equalTo(id)) - assertThat(keyCacheEntity.path, equalTo(path)) - assertThat(keyCacheEntity.type, equalTo(type)) + loadFakeEntity().apply { + this.from shouldBe from + this.to shouldBe to + } } } private suspend fun insertFakeEntity( - id: String, - path: String, - type: Int + from: Long, + to: Long ) { - db.dateDao().insertEntry(KeyCacheEntity().apply { - this.id = id - this.path = path - this.type = type + db.tracingIntervalDao().insertInterval(TracingIntervalEntity().apply { + this.from = from + this.to = to }) } - private suspend fun loadFakeEntity(): KeyCacheEntity = db.dateDao().getAllEntries().first() + private suspend fun loadFakeEntity(): TracingIntervalEntity = + db.tracingIntervalDao().getAllIntervals().first() private fun clearSharedPreferences() = SecurityHelper.globalEncryptedSharedPreferencesInstance.edit().clear().commit() diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/VerificationKeysTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/VerificationKeysTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..817159d6858f5663026ef68f0fc2c34efd8703d5 --- /dev/null +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/util/security/VerificationKeysTest.kt @@ -0,0 +1,86 @@ +package de.rki.coronawarnapp.util.security + +import de.rki.coronawarnapp.environment.EnvironmentSetup +import de.rki.coronawarnapp.exception.CwaSecurityException +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import okio.ByteString.Companion.decodeHex +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class VerificationKeysTest { + @MockK lateinit var environmentSetup: EnvironmentSetup + + @Before + fun setup() { + MockKAnnotations.init(this) + every { environmentSetup.appConfigVerificationKey } returns PUB_KEY + } + + private fun createTool() = VerificationKeys(environmentSetup) + + @Test + fun goodBinaryAndSignature() { + val tool = createTool() + tool.hasInvalidSignature( + GOOD_BINARY.decodeHex().toByteArray(), + GOOD_SIGNATURE.decodeHex().toByteArray() + ) shouldBe false + } + + @Test + fun badBinaryGoodSignature() { + val tool = createTool() + tool.hasInvalidSignature( + "123ABC".decodeHex().toByteArray(), + GOOD_SIGNATURE.decodeHex().toByteArray() + ) shouldBe true + } + + @Test + fun goodBinaryBadSignature() { + val tool = createTool() + shouldThrow<CwaSecurityException> { + tool.hasInvalidSignature( + GOOD_BINARY.decodeHex().toByteArray(), + "123ABC".decodeHex().toByteArray() + ) + } + } + + @Test + fun badEverything() { + val tool = createTool() + shouldThrow<CwaSecurityException> { + tool.hasInvalidSignature( + "123ABC".decodeHex().toByteArray(), + "123ABC".decodeHex().toByteArray() + ) + } + } + + companion object { + private const val PUB_KEY = + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg" + + "3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==" + private const val GOOD_BINARY = + "080b124e0a230a034c4f57180f221a68747470733a2f2f7777772e636f726f6e617761726e2e6170700a2" + + "70a0448494748100f188f4e221a68747470733a2f2f7777772e636f726f6e617761726e2e6170701a" + + "600a0c1803200428053006380740081100000000000049401a0a20012801300138014001210000000" + + "0000049402a10080510051805200528053005380540053100000000000034403a0e10021802200228" + + "02300238024002410000000000004940221c0a040837103f121209000000000000f03f11000000000" + + "000e03f20322a1a0a0a0a041008180212021005120c0a040801180412040801180432220a200a1c69" + + "73506c61757369626c6544656e696162696c6974794163746976651001" + private const val GOOD_SIGNATURE = + "0a83010a340a1464652e726b692e636f726f6e617761726e6170701a02763122033236322a13312e322e3" + + "834302e31303034352e342e332e32100118012247304502210099836666c962dd7a44292f6211b55e" + + "f2364ea3a5995238c862c3b58f774237da02200ae0e793d02f92826e5dea2d7758cbfb564089b1c2a" + + "f296d5bb80331bc5e0c5e" + } +} diff --git a/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt b/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..8cf4950155fce0e5dd3255ed9d5f8b1c7d511a4a --- /dev/null +++ b/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt @@ -0,0 +1,9 @@ +package de.rki.coronawarnapp.ui.main + +import dagger.Module + +@Module +abstract class MainActivityTestModule { + + // This is an empty placeholder so we can use the same one, but not empty via deviceForTesters +} diff --git a/Corona-Warn-App/src/device/res/navigation/test_nav_graph.xml b/Corona-Warn-App/src/device/res/navigation/test_nav_graph.xml new file mode 100644 index 0000000000000000000000000000000000000000..ed1d8a66ba51ded503486da1ea7c56f82c0bfae6 --- /dev/null +++ b/Corona-Warn-App/src/device/res/navigation/test_nav_graph.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<navigation xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/test_nav_graph"> + +</navigation> diff --git a/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestRiskLevelCalculation.kt b/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestRiskLevelCalculation.kt deleted file mode 100644 index 9128afba295c2866a3285f93add085aa98fae41b..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestRiskLevelCalculation.kt +++ /dev/null @@ -1,354 +0,0 @@ -package de.rki.coronawarnapp - -import android.content.Intent -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.EditText -import android.widget.Toast -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.viewModelScope -import com.google.android.gms.nearby.Nearby -import com.google.android.gms.nearby.exposurenotification.ExposureInformation -import com.google.zxing.integration.android.IntentIntegrator -import com.google.zxing.integration.android.IntentResult -import de.rki.coronawarnapp.databinding.FragmentTestRiskLevelCalculationBinding -import de.rki.coronawarnapp.exception.ExceptionCategory -import de.rki.coronawarnapp.exception.TransactionException -import de.rki.coronawarnapp.exception.reporting.report -import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient -import de.rki.coronawarnapp.risk.RiskLevel -import de.rki.coronawarnapp.risk.RiskLevelCalculation -import de.rki.coronawarnapp.risk.TimeVariables -import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange -import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService -import de.rki.coronawarnapp.sharing.ExposureSharingService -import de.rki.coronawarnapp.storage.AppDatabase -import de.rki.coronawarnapp.storage.FileStorageHelper -import de.rki.coronawarnapp.storage.LocalData -import de.rki.coronawarnapp.storage.RiskLevelRepository -import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction -import de.rki.coronawarnapp.transaction.RiskLevelTransaction -import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel -import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel -import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel -import de.rki.coronawarnapp.util.KeyFileHelper -import de.rki.coronawarnapp.util.security.SecurityHelper -import kotlinx.android.synthetic.deviceForTesters.fragment_test_risk_level_calculation.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import timber.log.Timber -import java.io.File -import java.util.UUID -import java.util.concurrent.TimeUnit -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -@Suppress("MagicNumber", "LongMethod") -class TestRiskLevelCalculation : Fragment() { - companion object { - val TAG: String? = TestRiskLevelCalculation::class.simpleName - } - - private val tracingViewModel: TracingViewModel by activityViewModels() - private val settingsViewModel: SettingsViewModel by activityViewModels() - private val submissionViewModel: SubmissionViewModel by activityViewModels() - private var _binding: FragmentTestRiskLevelCalculationBinding? = null - private val binding: FragmentTestRiskLevelCalculationBinding get() = _binding!! - - // reference to the client from the Google framework with the given application context - private val exposureNotificationClient by lazy { - Nearby.getExposureNotificationClient(CoronaWarnApplication.getAppContext()) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentTestRiskLevelCalculationBinding.inflate(inflater) - binding.tracingViewModel = tracingViewModel - binding.settingsViewModel = settingsViewModel - binding.submissionViewModel = submissionViewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - binding.buttonRetrieveDiagnosisKeys.setOnClickListener { - tracingViewModel.viewModelScope.launch { - retrieveDiagnosisKeys() - } - } - - binding.buttonProvideKeyViaQr.setOnClickListener { - scanLocalQRCodeAndProvide() - } - - binding.buttonCalculateRiskLevel.setOnClickListener { - tracingViewModel.viewModelScope.launch { - calculateRiskLevel() - } - } - - binding.buttonResetRiskLevel.setOnClickListener { - tracingViewModel.viewModelScope.launch { - withContext(Dispatchers.IO) { - try { - // Preference reset - SecurityHelper.resetSharedPrefs() - // Database Reset - AppDatabase.reset(requireContext()) - // Export File Reset - FileStorageHelper.getAllFilesInKeyExportDirectory().forEach { it.delete() } - - LocalData.lastCalculatedRiskLevel(RiskLevel.UNDETERMINED.raw) - LocalData.lastSuccessfullyCalculatedRiskLevel(RiskLevel.UNDETERMINED.raw) - LocalData.lastTimeDiagnosisKeysFromServerFetch(null) - LocalData.googleApiToken(null) - } catch (e: java.lang.Exception) { - e.report(ExceptionCategory.INTERNAL) - } - } - RiskLevelTransaction.start() - Toast.makeText( - requireContext(), "Reset done, please fetch diagnosis keys from server again", - Toast.LENGTH_SHORT - ).show() - } - } - - startObserving() - } - - override fun onResume() { - super.onResume() - tracingViewModel.viewModelScope.launch { - calculateRiskLevel() - } - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - - val result: IntentResult? = - IntentIntegrator.parseActivityResult(requestCode, resultCode, data) - if (result != null) { - if (result.contents == null) { - Toast.makeText(requireContext(), "Cancelled", Toast.LENGTH_LONG).show() - } else { - ExposureSharingService.getOthersKeys(result.contents, onScannedKey) - } - } else { - super.onActivityResult(requestCode, resultCode, data) - } - } - - private suspend fun retrieveDiagnosisKeys() { - try { - RetrieveDiagnosisKeysTransaction.start() - calculateRiskLevel() - } catch (e: Exception) { - e.report(ExceptionCategory.INTERNAL) - } - } - - private fun scanLocalQRCodeAndProvide() { - IntentIntegrator.forSupportFragment(this) - .setOrientationLocked(false) - .setBeepEnabled(false) - .initiateScan() - } - - private val onScannedKey = { key: AppleLegacyKeyExchange.Key? -> - Timber.i("keys scanned..") - provideDiagnosisKey(key) - } - - private fun provideDiagnosisKey(key: AppleLegacyKeyExchange.Key?) { - if (null == key) { - Toast.makeText(requireContext(), "No Key data found in QR code", Toast.LENGTH_SHORT) - .show() - } else { - val token = UUID.randomUUID().toString() - LocalData.googleApiToken(token) - - val appleKeyList = mutableListOf<AppleLegacyKeyExchange.Key>() - - val text = (transmission_number as EditText).text.toString() - var number = 5 - if (!text.isBlank()) { - number = Integer.valueOf(text) - } - - appleKeyList.add( - AppleLegacyKeyExchange.Key.newBuilder() - .setKeyData(key.keyData) - .setRollingPeriod(144) - .setRollingStartNumber(key.rollingStartNumber) - .setTransmissionRiskLevel(number) - .build() - ) - - val appleFiles = listOf( - AppleLegacyKeyExchange.File.newBuilder() - .addAllKeys(appleKeyList) - .build() - ) - - val dir = - File(File(requireContext().getExternalFilesDir(null), "key-export"), token) - dir.mkdirs() - - var googleFileList: List<File> - lifecycleScope.launch { - googleFileList = KeyFileHelper.asyncCreateExportFiles(appleFiles, dir) - - Timber.i("Provide ${googleFileList.count()} files with ${appleKeyList.size} keys with token $token") - try { - // only testing implementation: this is used to wait for the broadcastreceiver of the OS / EN API - InternalExposureNotificationClient.asyncProvideDiagnosisKeys( - googleFileList, - ApplicationConfigurationService.asyncRetrieveExposureConfiguration(), - token - ) - Toast.makeText( - requireContext(), - "Provided ${appleKeyList.size} keys to Google API with token $token", - Toast.LENGTH_SHORT - ).show() - } catch (e: Exception) { - e.report(ExceptionCategory.EXPOSURENOTIFICATION) - } - } - } - } - - private suspend fun calculateRiskLevel() { - try { - RiskLevelTransaction.start() - } catch (e: TransactionException) { - e.report(ExceptionCategory.INTERNAL) - } - } - - private fun startObserving() { - tracingViewModel.viewModelScope.launch { - try { - val googleToken = LocalData.googleApiToken() ?: UUID.randomUUID().toString() - val exposureSummary = - InternalExposureNotificationClient.asyncGetExposureSummary(googleToken) - - val appConfig = - ApplicationConfigurationService.asyncRetrieveApplicationConfiguration() - - val riskLevelScore = RiskLevelCalculation.calculateRiskScore( - appConfig.attenuationDuration, - exposureSummary - ) - - val riskAsString = "Level: ${RiskLevelRepository.getLastCalculatedScore()}\n" + - "Last successful Level: " + - "${LocalData.lastSuccessfullyCalculatedRiskLevel()}\n" + - "Calculated Score: ${riskLevelScore}\n" + - "Last Time Server Fetch: ${LocalData.lastTimeDiagnosisKeysFromServerFetch()}\n" + - "Tracing Duration: " + - "${TimeUnit.MILLISECONDS.toDays(TimeVariables.getTimeActiveTracingDuration())} days \n" + - "Tracing Duration in last 14 days: " + - "${TimeVariables.getActiveTracingDaysInRetentionPeriod()} days \n" + - "Last time risk level calculation ${LocalData.lastTimeRiskLevelCalculation()}" - - binding.labelRiskScore.text = riskAsString - - val lowClass = - appConfig.riskScoreClasses?.riskClassesList?.find { low -> low.label == "LOW" } - val highClass = - appConfig.riskScoreClasses?.riskClassesList?.find { high -> high.label == "HIGH" } - - val configAsString = - "Attenuation Weight Low: ${appConfig.attenuationDuration?.weights?.low}\n" + - "Attenuation Weight Mid: ${appConfig.attenuationDuration?.weights?.mid}\n" + - "Attenuation Weight High: ${appConfig.attenuationDuration?.weights?.high}\n\n" + - "Attenuation Offset: ${appConfig.attenuationDuration?.defaultBucketOffset}\n" + - "Attenuation Normalization: " + - "${appConfig.attenuationDuration?.riskScoreNormalizationDivisor}\n\n" + - "Risk Score Low Class: ${lowClass?.min ?: 0} - ${lowClass?.max ?: 0}\n" + - "Risk Score High Class: ${highClass?.min ?: 0} - ${highClass?.max ?: 0}" - - binding.labelBackendParameters.text = configAsString - - val summaryAsString = - "Days Since Last Exposure: ${exposureSummary.daysSinceLastExposure}\n" + - "Matched Key Count: ${exposureSummary.matchedKeyCount}\n" + - "Maximum Risk Score: ${exposureSummary.maximumRiskScore}\n" + - "Attenuation Durations: [${exposureSummary.attenuationDurationsInMinutes?.get( - 0 - )}," + - "${exposureSummary.attenuationDurationsInMinutes?.get(1)}," + - "${exposureSummary.attenuationDurationsInMinutes?.get(2)}]\n" + - "Summation Risk Score: ${exposureSummary.summationRiskScore}" - - binding.labelExposureSummary.text = summaryAsString - - val maxRisk = exposureSummary.maximumRiskScore - val atWeights = appConfig.attenuationDuration?.weights - val attenuationDurationInMin = - exposureSummary.attenuationDurationsInMinutes - val attenuationConfig = appConfig.attenuationDuration - val formulaString = - "($maxRisk / ${attenuationConfig?.riskScoreNormalizationDivisor}) * " + - "(${attenuationDurationInMin?.get(0)} * ${atWeights?.low} " + - "+ ${attenuationDurationInMin?.get(1)} * ${atWeights?.mid} " + - "+ ${attenuationDurationInMin?.get(2)} * ${atWeights?.high} " + - "+ ${attenuationConfig?.defaultBucketOffset})" - - binding.labelFormula.text = formulaString - - binding.labelFullConfig.text = appConfig.toString() - - val token = LocalData.googleApiToken() - if (token != null) { - val exposureInformation = asyncGetExposureInformation(token) - - var infoString = "" - exposureInformation.forEach { - infoString += "Attenuation duration in min.: " + - "[${it.attenuationDurationsInMinutes?.get(0)}, " + - "${it.attenuationDurationsInMinutes?.get(1)}," + - "${it.attenuationDurationsInMinutes?.get(2)}]\n" + - "Attenuation value: ${it.attenuationValue}\n" + - "Duration in min.: ${it.durationMinutes}\n" + - "Risk Score: ${it.totalRiskScore}\n" + - "Transmission Risk Level: ${it.transmissionRiskLevel}\n" + - "Date Millis Since Epoch: ${it.dateMillisSinceEpoch}\n\n" - } - - binding.labelExposureInfo.text = infoString - } - } catch (e: Exception) { - e.report(ExceptionCategory.EXPOSURENOTIFICATION) - } - } - } - - suspend fun asyncGetExposureInformation(token: String): List<ExposureInformation> = - suspendCoroutine { cont -> - exposureNotificationClient.getExposureInformation(token) - .addOnSuccessListener { - cont.resume(it) - }.addOnFailureListener { - cont.resumeWithException(it) - } - } -} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/ui/main/MainFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/ui/main/MainFragment.kt deleted file mode 100644 index e5a2150a53f111813134527a4488ed47ab2d9b80..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/ui/main/MainFragment.kt +++ /dev/null @@ -1,226 +0,0 @@ -package de.rki.coronawarnapp.ui.main - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.accessibility.AccessibilityEvent -import android.widget.PopupMenu -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.lifecycle.lifecycleScope -import androidx.navigation.fragment.findNavController -import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.databinding.FragmentMainBinding -import de.rki.coronawarnapp.risk.TimeVariables -import de.rki.coronawarnapp.storage.LocalData -import de.rki.coronawarnapp.timer.TimerHelper -import de.rki.coronawarnapp.ui.doNavigate -import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel -import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel -import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel -import de.rki.coronawarnapp.util.DialogHelper -import de.rki.coronawarnapp.util.ExternalActionHelper -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -/** - * After the user has finished the onboarding this fragment will be the heart of the application. - * Three ViewModels are needed that this fragment shows all relevant information to the user. - * Also the Menu is set here. - * - * @see tracingViewModel - * @see settingsViewModel - * @see submissionViewModel - * @see PopupMenu - */ -class MainFragment : Fragment() { - - companion object { - private val TAG: String? = MainFragment::class.simpleName - } - - private val tracingViewModel: TracingViewModel by activityViewModels() - private val settingsViewModel: SettingsViewModel by activityViewModels() - private val submissionViewModel: SubmissionViewModel by activityViewModels() - private var _binding: FragmentMainBinding? = null - private val binding: FragmentMainBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentMainBinding.inflate(inflater) - binding.tracingViewModel = tracingViewModel - binding.settingsViewModel = settingsViewModel - binding.submissionViewModel = submissionViewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setButtonOnClickListener() - - showOneTimeTracingExplanationDialog() - } - - override fun onResume() { - super.onResume() - // refresh required data - tracingViewModel.refreshRiskLevel() - tracingViewModel.refreshExposureSummary() - tracingViewModel.refreshLastTimeDiagnosisKeysFetchedDate() - tracingViewModel.refreshIsTracingEnabled() - tracingViewModel.refreshActiveTracingDaysInRetentionPeriod() - TimerHelper.checkManualKeyRetrievalTimer() - submissionViewModel.refreshDeviceUIState() - tracingViewModel.refreshLastSuccessfullyCalculatedScore() - binding.mainScrollview.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) - } - - override fun onStart() { - super.onStart() - binding.mainScrollview.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) - } - - private fun setButtonOnClickListener() { - binding.mainTestUnregistered.submissionStatusCardUnregistered.setOnClickListener { - toSubmissionIntro() - } - binding.mainTestUnregistered.submissionStatusCardUnregisteredButton.setOnClickListener { - toSubmissionIntro() - } - binding.mainTestDone.submissionStatusCardDone.setOnClickListener { - findNavController().doNavigate( - MainFragmentDirections.actionMainFragmentToSubmissionDoneFragment() - ) - } - binding.mainTestResult.submissionStatusCardContent.setOnClickListener { - toSubmissionResult() - } - binding.mainTestResult.submissionStatusCardContentButton.setOnClickListener { - toSubmissionResult() - } - binding.mainTestPositive.submissionStatusCardPositive.setOnClickListener { - toSubmissionResult() - } - binding.mainTestPositive.submissionStatusCardPositiveButton.setOnClickListener { - toSubmissionResult() - } - binding.mainTracing.setOnClickListener { - findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToSettingsTracingFragment()) - } - binding.mainRisk.riskCard.setOnClickListener { - findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToRiskDetailsFragment()) - } - binding.mainRisk.riskCardButtonUpdate.setOnClickListener { - tracingViewModel.refreshDiagnosisKeys() - settingsViewModel.updateManualKeyRetrievalEnabled(false) - } - binding.mainRisk.riskCardButtonEnableTracing.setOnClickListener { - findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToSettingsTracingFragment()) - } - binding.mainAbout.mainCard.setOnClickListener { - ExternalActionHelper.openUrl(this, requireContext().getString(R.string.main_about_link)) - } - binding.mainHeaderShare.buttonIcon.setOnClickListener { - findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToMainSharingFragment()) - } - binding.mainHeaderOptionsMenu.buttonIcon.setOnClickListener { - showPopup(it) - } - } - - private fun toSubmissionResult() { - findNavController().doNavigate( - MainFragmentDirections.actionMainFragmentToSubmissionResultFragment() - ) - } - - private fun toSubmissionIntro() { - findNavController().doNavigate( - MainFragmentDirections.actionMainFragmentToSubmissionIntroFragment() - ) - } - - private fun showPopup(view: View) { - val popup = PopupMenu(requireContext(), view) - popup.inflate(R.menu.menu_main) - popup.setOnMenuItemClickListener { - return@setOnMenuItemClickListener when (it.itemId) { - R.id.menu_help -> { - findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToMainOverviewFragment()) - true - } - R.id.menu_information -> { - findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToInformationFragment()) - true - } - R.id.menu_settings -> { - findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToSettingsFragment()) - true - } - R.id.menu_test_api -> { - findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToTestForAPIFragment()) - true - } - R.id.menu_test_risk_level -> { - findNavController().doNavigate( - MainFragmentDirections.actionMainFragmentToTestRiskLevelCalculation() - ) - true - } - else -> super.onOptionsItemSelected(it) - } - } - popup.show() - } - - private fun showOneTimeTracingExplanationDialog() { - - // check if the dialog explaining the tracing time was already shown - if (!LocalData.tracingExplanationDialogWasShown()) { - - val activity = this.requireActivity() - - lifecycleScope.launch { - - // get all text strings and the current active tracing time - val infoPeriodLogged = - getString(R.string.risk_details_information_body_period_logged) - val infoPeriodLoggedAssessment = - getString( - R.string.risk_details_information_body_period_logged_assessment, - (TimeVariables.getActiveTracingDaysInRetentionPeriod()).toString() - ) - val infoFAQ = getString(R.string.risk_details_explanation_dialog_faq_body) - - withContext(Dispatchers.Main) { - - // display the dialog - DialogHelper.showDialog( - DialogHelper.DialogInstance( - activity, - getString(R.string.risk_details_explanation_dialog_title), - "$infoPeriodLogged\n\n$infoPeriodLoggedAssessment\n\n$infoFAQ", - getString(R.string.errors_generic_button_positive), - null, - null, - { - LocalData.tracingExplanationDialogWasShown(true) - }, - {} - )) - } - } - } - } -} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/RiskLevelAndKeyRetrievalBenchmark.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/RiskLevelAndKeyRetrievalBenchmark.kt new file mode 100644 index 0000000000000000000000000000000000000000..e92c287573feaf421a6913cfd9eb95298ddaa549 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/RiskLevelAndKeyRetrievalBenchmark.kt @@ -0,0 +1,151 @@ +package de.rki.coronawarnapp + +import android.content.Context +import android.text.format.Formatter +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.TransactionException +import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction +import de.rki.coronawarnapp.transaction.RiskLevelTransaction +import de.rki.coronawarnapp.util.di.AppInjector +import timber.log.Timber +import kotlin.system.measureTimeMillis + +class RiskLevelAndKeyRetrievalBenchmark( + private val context: Context, + private val countries: List<String> +) { + + /** + * the key cache instance used to store queried dates and hours + */ + private val keyCache = AppInjector.component.keyCacheRepository + + /** + * Calls the RetrieveDiagnosisKeysTransaction and RiskLevelTransaction and measures them. + * Results are displayed using a label + * @param callCount defines how often the transactions should be called (each call will be + * measured separately) + */ + suspend fun start( + callCount: Int, + callback: (resultInfo: String) -> Unit + ) { + + var resultInfo = StringBuilder() + .append( + "MEASUREMENT Running for Countries:\n " + + "${countries.joinToString(", ")}\n\n" + ) + .append("Result: \n\n") + .append("#\t Combined \t Download \t Sub \t Risk \t File # \t F. size\n") + + callback(resultInfo.toString()) + + repeat(callCount) { index -> + + keyCache.clear() + + var keyRetrievalError = "" + var keyFileCount: Int = -1 + var keyFileDownloadDuration: Long = -1 + var keyFilesSize: Long = -1 + var apiSubmissionDuration: Long = -1 + + try { + measureDiagnosticKeyRetrieval( + label = "#$index", + countries = countries, + downloadFinished = { duration, keyCount, totalFileSize -> + keyFileCount = keyCount + keyFileDownloadDuration = duration + keyFilesSize = totalFileSize + }, apiSubmissionFinished = { duration -> + apiSubmissionDuration = duration + }) + } catch (e: TransactionException) { + keyRetrievalError = e.message.toString() + } + + var calculationDuration: Long = -1 + var calculationError = "" + + try { + calculationDuration = measureKeyCalculation("#$index") + } catch (e: TransactionException) { + calculationError = e.message.toString() + } + + // build result entry for current iteration with all gathered data + resultInfo.append( + "${index + 1}. \t ${calculationDuration + keyFileDownloadDuration + apiSubmissionDuration} ms \t " + + "$keyFileDownloadDuration ms " + "\t $apiSubmissionDuration ms" + + "\t $calculationDuration ms \t $keyFileCount \t " + + "${Formatter.formatFileSize(context, keyFilesSize)}\n" + ) + + if (keyRetrievalError.isNotEmpty()) { + resultInfo.append("Key Retrieval Error: $keyRetrievalError\n") + } + + if (calculationError.isNotEmpty()) { + resultInfo.append("Calculation Error: $calculationError\n") + } + + callback(resultInfo.toString()) + } + } + + private suspend fun measureKeyCalculation(label: String): Long { + try { + Timber.v("MEASURE [Risk Level Calculation] $label started") + // start risk level calculation and get duration + return measureTimeMillis { + RiskLevelTransaction.start() + }.also { + Timber.v("MEASURE [Risk Level Calculation] $label finished") + } + } catch (e: TransactionException) { + e.report(ExceptionCategory.INTERNAL) + throw e + } + } + + private suspend fun measureDiagnosticKeyRetrieval( + label: String, + countries: List<String>, + downloadFinished: (duration: Long, keyCount: Int, fileSize: Long) -> Unit, + apiSubmissionFinished: (duration: Long) -> Unit + ) { + var keyFileDownloadStart: Long = -1 + var apiSubmissionStarted: Long = -1 + + try { + RetrieveDiagnosisKeysTransaction.onKeyFilesDownloadStarted = { + Timber.v("MEASURE [Diagnostic Key Files] $label started") + keyFileDownloadStart = System.currentTimeMillis() + } + + RetrieveDiagnosisKeysTransaction.onKeyFilesDownloadFinished = { count, size -> + Timber.v("MEASURE [Diagnostic Key Files] $label finished") + val duration = System.currentTimeMillis() - keyFileDownloadStart + downloadFinished(duration, count, size) + } + + RetrieveDiagnosisKeysTransaction.onApiSubmissionStarted = { + apiSubmissionStarted = System.currentTimeMillis() + } + + RetrieveDiagnosisKeysTransaction.onApiSubmissionFinished = { + val duration = System.currentTimeMillis() - apiSubmissionStarted + apiSubmissionFinished(duration) + } + + // start diagnostic key transaction + RetrieveDiagnosisKeysTransaction.start(countries) + } catch (e: TransactionException) { + e.report(ExceptionCategory.INTERNAL) + throw e + } + } +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/DebugOptionsState.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/DebugOptionsState.kt new file mode 100644 index 0000000000000000000000000000000000000000..a86be3932b084a0c27af1488d8681d0aeab6e427 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/DebugOptionsState.kt @@ -0,0 +1,6 @@ +package de.rki.coronawarnapp.test.api.ui + +data class DebugOptionsState( + val areNotificationsEnabled: Boolean, + val is3HourModeEnabled: Boolean +) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/EnvironmentState.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/EnvironmentState.kt new file mode 100644 index 0000000000000000000000000000000000000000..239f7dcbb47ce8d504da94721fea6e76c02357b3 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/EnvironmentState.kt @@ -0,0 +1,21 @@ +package de.rki.coronawarnapp.test.api.ui + +import de.rki.coronawarnapp.environment.EnvironmentSetup + +data class EnvironmentState( + val current: EnvironmentSetup.Type, + val available: List<EnvironmentSetup.Type>, + val urlSubmission: String, + val urlDownload: String, + val urlVerification: String +) { + companion object { + internal fun EnvironmentSetup.toEnvironmentState() = EnvironmentState( + current = currentEnvironment, + available = EnvironmentSetup.Type.values().toList(), + urlSubmission = submissionCdnUrl, + urlDownload = downloadCdnUrl, + urlVerification = verificationCdnUrl + ) + } +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/GoogleServicesState.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/GoogleServicesState.kt new file mode 100644 index 0000000000000000000000000000000000000000..c6052212966e2cefdfc21a1e17751c79263c755e --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/GoogleServicesState.kt @@ -0,0 +1,5 @@ +package de.rki.coronawarnapp.test.api.ui + +data class GoogleServicesState( + val version: Long +) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/LoggerState.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/LoggerState.kt new file mode 100644 index 0000000000000000000000000000000000000000..3244c5f34b18712f59e379f811d8d198268bca99 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/LoggerState.kt @@ -0,0 +1,13 @@ +package de.rki.coronawarnapp.test.api.ui + +import de.rki.coronawarnapp.util.CWADebug + +data class LoggerState( + val isLogging: Boolean +) { + companion object { + internal fun CWADebug.toLoggerState() = LoggerState( + isLogging = fileLogger?.isLogging ?: false + ) + } +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestForAPIFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt similarity index 51% rename from Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestForAPIFragment.kt rename to Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt index 49c2a805947b7628eda76c0f4a6bb510cbb12bb5..92e6be5c83f319428b2baca75e9ac3ad10bb5172 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de.rki.coronawarnapp/TestForAPIFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForAPIFragment.kt @@ -1,5 +1,7 @@ -package de.rki.coronawarnapp +package de.rki.coronawarnapp.test.api.ui +import android.annotation.SuppressLint +import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.graphics.Color @@ -8,21 +10,24 @@ import android.util.Base64 import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputMethodManager import android.widget.ImageView -import android.widget.Switch +import android.widget.RadioButton +import android.widget.RadioGroup import android.widget.Toast -import androidx.core.content.pm.PackageInfoCompat +import androidx.core.view.ViewCompat.generateViewId +import androidx.core.view.children import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import androidx.lifecycle.viewModelScope import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 -import com.google.android.gms.common.GoogleApiAvailability -import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient import com.google.android.gms.nearby.exposurenotification.ExposureSummary import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import com.google.android.material.snackbar.Snackbar import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.google.protobuf.ByteString @@ -30,7 +35,10 @@ import com.google.zxing.BarcodeFormat import com.google.zxing.integration.android.IntentIntegrator import com.google.zxing.integration.android.IntentResult import com.google.zxing.qrcode.QRCodeWriter +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.RiskLevelAndKeyRetrievalBenchmark import de.rki.coronawarnapp.databinding.FragmentTestForAPIBinding +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL import de.rki.coronawarnapp.exception.TransactionException @@ -46,12 +54,17 @@ import de.rki.coronawarnapp.storage.AppDatabase import de.rki.coronawarnapp.storage.ExposureSummaryRepository import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository -import de.rki.coronawarnapp.transaction.RiskLevelTransaction +import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.util.KeyFileHelper -import kotlinx.android.synthetic.deviceForTesters.fragment_test_for_a_p_i.* +import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.setGone +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.joda.time.DateTime @@ -60,11 +73,21 @@ import timber.log.Timber import java.io.File import java.lang.reflect.Type import java.util.UUID +import javax.inject.Inject @SuppressWarnings("TooManyFunctions", "MagicNumber", "LongMethod") -class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHelper.Callback { +class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i), + InternalExposureNotificationPermissionHelper.Callback, AutoInject { + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val vm: TestForApiFragmentViewModel by cwaViewModels { viewModelFactory } companion object { + val MENU_ITEM = TestMenuItem( + title = "Test for API", + description = "A mix of API related test options.", + targetId = R.id.test_for_api_fragment + ) const val CONFIG_SCORE = 8 fun keysToJson(keys: List<TemporaryExposureKey>): String { @@ -77,6 +100,10 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel } } + private val enfClient by lazy { + AppInjector.component.enfClient + } + private var myExposureKeysJSON: String? = null private var myExposureKeys: List<TemporaryExposureKey>? = mutableListOf() private var otherExposureKey: AppleLegacyKeyExchange.Key? = null @@ -87,49 +114,21 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel private var token: String? = null // ViewModel for MainActivity - private val tracingViewModel: TracingViewModel by activityViewModels() + private val tracingVM: TracingViewModel by activityViewModels() private lateinit var qrPager: ViewPager2 private lateinit var qrPagerAdapter: RecyclerView.Adapter<QRPagerAdapter.QRViewHolder> // Data and View binding - private var _binding: FragmentTestForAPIBinding? = null - private val binding: FragmentTestForAPIBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - - // get the binding reference by inflating it with the current layout - _binding = FragmentTestForAPIBinding.inflate(inflater) + private val binding: FragmentTestForAPIBinding by viewBindingLazy() - // set the viewmmodel variable that will be used for data binding - binding.tracingViewModel = tracingViewModel - - // set the lifecycleowner for LiveData - binding.lifecycleOwner = this - - // Inflate the layout for this fragment - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private var lastSetCountries: List<String>? = null + @SuppressLint("SetTextI18n") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val v: Long = PackageInfoCompat.getLongVersionCode( - activity?.packageManager!!.getPackageInfo( - GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE, - 0 - ) - ) - label_googlePlayServices_version.text = "Google Play Services version: " + v.toString() + binding.tracingViewModel = tracingVM token = UUID.randomUUID().toString() @@ -138,163 +137,186 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel getExposureKeys() - qrPager = qr_code_viewpager + qrPager = binding.qrCodeViewpager qrPagerAdapter = QRPagerAdapter() qrPager.adapter = qrPagerAdapter - button_api_test_start.setOnClickListener { - start() + // Debug card + binding.threeHourModeToggle.apply { + setOnClickListener { vm.setLast3HoursMode(isChecked) } } - - button_api_get_exposure_keys.setOnClickListener { - getExposureKeys() + vm.last3HourToggleEvent.observe2(this) { + showToast("Last 3 Hours Mode is activated: $it") } - - val last3HoursSwitch = test_api_switch_last_three_hours_from_server as Switch - last3HoursSwitch.isChecked = LocalData.last3HoursMode() - last3HoursSwitch.setOnClickListener { - val isLast3HoursModeEnabled = last3HoursSwitch.isChecked - showToast("Last 3 Hours Mode is activated: $isLast3HoursModeEnabled") - LocalData.last3HoursMode(isLast3HoursModeEnabled) + binding.backgroundNotificationsToggle.apply { + setOnClickListener { vm.setBackgroundNotifications(isChecked) } } - - val backgroundNotificationSwitch = test_api_switch_background_notifications as Switch - backgroundNotificationSwitch.isChecked = LocalData.backgroundNotification() - backgroundNotificationSwitch.setOnClickListener { - val isBackgroundNotificationsActive = backgroundNotificationSwitch.isChecked - showToast("Background Notifications are activated: $isBackgroundNotificationsActive") - LocalData.backgroundNotification(isBackgroundNotificationsActive) + vm.backgroundNotificationsToggleEvent.observe2(this@TestForAPIFragment) { + showToast("Background Notifications are activated: $it") } - - button_api_get_check_exposure.setOnClickListener { - checkExposure() + vm.debugOptionsState.observe2(this) { state -> + binding.apply { + backgroundNotificationsToggle.isChecked = state.areNotificationsEnabled + threeHourModeToggle.isChecked = state.is3HourModeEnabled + } } - - button_api_scan_qr_code.setOnClickListener { - IntentIntegrator.forSupportFragment(this) - .setOrientationLocked(false) - .setBeepEnabled(false) - .initiateScan() + binding.testLogfileToggle.apply { + setOnClickListener { vm.setLoggerEnabled(isChecked) } } - - button_api_share_my_keys.setOnClickListener { - shareMyKeys() + vm.loggerState.observe2(this) { state -> + binding.apply { + testLogfileToggle.isChecked = state.isLogging + testLogfileShare.setGone(!state.isLogging) + } } - - button_api_enter_other_keys.setOnClickListener { - enterOtherKeys() + binding.testLogfileShare.setOnClickListener { vm.shareLogFile() } + vm.logShareEvent.observe2(this) { showToast("Logfile copied to $it") } + + // Server environment card + binding.environmentToggleGroup.apply { + setOnCheckedChangeListener { group, checkedId -> + val chip = group.findViewById<RadioButton>(checkedId) + if (!chip.isPressed) return@setOnCheckedChangeListener + vm.selectEnvironmentTytpe(chip.text.toString()) + } } - button_api_submit_keys.setOnClickListener { - tracingViewModel.viewModelScope.launch { - try { - internalExposureNotificationPermissionHelper.requestPermissionToShareKeys() - - // SubmitDiagnosisKeysTransaction.start("123") - withContext(Dispatchers.Main) { - showToast("Key submission successful") + vm.environmentState.observe2(this) { state -> + binding.apply { + if (environmentToggleGroup.childCount != state.available.size) { + environmentToggleGroup.removeAllViews() + state.available.forEach { type -> + RadioButton(requireContext()).apply { + id = generateViewId() + text = type.rawKey + layoutParams = RadioGroup.LayoutParams( + RadioGroup.LayoutParams.MATCH_PARENT, + RadioGroup.LayoutParams.WRAP_CONTENT + ) + environmentToggleGroup.addView(this) + } } - } catch (e: TransactionException) { - e.report(INTERNAL) } - } - } - button_calculate_risk_level.setOnClickListener { - tracingViewModel.viewModelScope.launch { - try { - RiskLevelTransaction.start() - } catch (e: TransactionException) { - e.report(INTERNAL) + environmentToggleGroup.children.forEach { + it as RadioButton + it.isChecked = it.text == state.current.rawKey } + + environmentCdnurlDownload.text = "Download CDN:\n${state.urlDownload}" + environmentCdnurlSubmission.text = "Submission CDN:\n${state.urlSubmission}" + environmentCdnurlVerification.text = "Verification CDN:\n${state.urlVerification}" } } + vm.environmentChangeEvent.observe2(this) { + showSnackBar("Environment changed to: $it\nForce stop & restart the app!") + } - button_insert_exposure_summary.setOnClickListener { - // Now broadcasts them to the worker. - val intent = Intent( - context, - ExposureStateUpdateReceiver::class.java - ) - intent.action = ExposureNotificationClient.ACTION_EXPOSURE_STATE_UPDATED - context?.sendBroadcast(intent) + // GMS Info card + vm.gmsState.observe2(this) { state -> + binding.googlePlayServicesVersionInfo.text = + "Google Play Services version: ${state.version}" } - button_retrieve_exposure_summary.setOnClickListener { - tracingViewModel.viewModelScope.launch { - showToast( - ExposureSummaryRepository.getExposureSummaryRepository() - .getExposureSummaryEntities().toString() - ) + // Test action card + binding.apply { + buttonApiTestStart.setOnClickListener { start() } + buttonApiGetExposureKeys.setOnClickListener { getExposureKeys() } + buttonApiGetCheckExposure.setOnClickListener { checkExposure() } + + buttonApiScanQrCode.setOnClickListener { + IntentIntegrator.forSupportFragment(this@TestForAPIFragment) + .setOrientationLocked(false) + .setBeepEnabled(false) + .initiateScan() } - } - button_clear_db.setOnClickListener { - tracingViewModel.viewModelScope.launch { - withContext(Dispatchers.IO) { - AppDatabase.getInstance(requireContext()).clearAllTables() + buttonApiShareMyKeys.setOnClickListener { shareMyKeys() } + buttonApiEnterOtherKeys.setOnClickListener { enterOtherKeys() } + + buttonApiSubmitKeys.setOnClickListener { + tracingVM.viewModelScope.launch { + try { + internalExposureNotificationPermissionHelper.requestPermissionToShareKeys() + + // SubmitDiagnosisKeysTransaction.start("123") + withContext(Dispatchers.Main) { + showToast("Key submission successful") + } + } catch (e: TransactionException) { + e.report(INTERNAL) + } } } - } - button_tracing_intervals.setOnClickListener { - tracingViewModel.viewModelScope.launch { - showToast( - TracingIntervalRepository.getDateRepository(requireContext()).getIntervals() - .toString() + buttonCalculateRiskLevel.setOnClickListener { vm.calculateRiskLevelClicked() } + + buttonInsertExposureSummary.setOnClickListener { + // Now broadcasts them to the worker. + val intent = Intent( + context, + ExposureStateUpdateReceiver::class.java ) + intent.action = ExposureNotificationClient.ACTION_EXPOSURE_STATE_UPDATED + context?.sendBroadcast(intent) } - } - button_tracing_duration_in_retention_period.setOnClickListener { - tracingViewModel.viewModelScope.launch { - showToast(TimeVariables.getActiveTracingDaysInRetentionPeriod().toString()) + buttonRetrieveExposureSummary.setOnClickListener { + tracingVM.viewModelScope.launch { + showToast( + ExposureSummaryRepository.getExposureSummaryRepository() + .getExposureSummaryEntities().toString() + ) + } } - } - binding.testLogfileToggle.isChecked = CoronaWarnApplication.fileLogger?.isLogging ?: false - binding.testLogfileToggle.setOnClickListener { buttonView -> - CoronaWarnApplication.fileLogger?.let { - if (binding.testLogfileToggle.isChecked) { - it.start() - } else { - it.stop() + buttonClearDb.setOnClickListener { + tracingVM.viewModelScope.launch { + withContext(Dispatchers.IO) { + AppDatabase.getInstance(requireContext()).clearAllTables() + } + } + } + + buttonTracingIntervals.setOnClickListener { + tracingVM.viewModelScope.launch { + showToast( + TracingIntervalRepository.getDateRepository(requireContext()).getIntervals() + .toString() + ) + } + } + + buttonTracingDurationInRetentionPeriod.setOnClickListener { + tracingVM.viewModelScope.launch { + showToast(TimeVariables.getActiveTracingDaysInRetentionPeriod().toString()) } } } - binding.testLogfileShare.setOnClickListener { - CoronaWarnApplication.fileLogger?.let { - lifecycleScope.launch { - val targetPath = withContext(Dispatchers.IO) { - async { - if (!it.logFile.exists()) return@async null + // Country benchmark card + // Load countries from App config and update Country UI element states + lifecycleScope.launch { + lastSetCountries = + ApplicationConfigurationService.asyncRetrieveApplicationConfiguration() + .supportedCountriesList - val externalPath = File( - requireContext().getExternalFilesDir(null), - "LogFile-${System.currentTimeMillis()}.log" - ) + binding.inputCountryCodesEditText.setText( + lastSetCountries?.joinToString(",") + ) - it.logFile.copyTo(externalPath) + updateCountryStatusLabel() + } + binding.buttonFilterCountryCodes.setOnClickListener { filterCountryCodes() } + binding.buttonRetrieveDiagnosisKeysAndCalcRiskLevel.setOnClickListener { + startKeyRetrievalAndRiskCalcBenchmark() + } - return@async externalPath - } - }.await() - if (targetPath != null) { - Toast.makeText( - requireActivity(), - "Logfile copied to $targetPath", - Toast.LENGTH_SHORT - ).show() - } else { - Toast.makeText( - requireActivity(), - "No log file available", - Toast.LENGTH_SHORT - ).show() - } - } + binding.inputMeasureRiskKeyRepeatCount.setOnEditorActionListener { v, actionCode, event -> + if (actionCode == EditorInfo.IME_ACTION_DONE) { + startKeyRetrievalAndRiskCalcBenchmark() } + false } } @@ -304,6 +326,56 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel updateExposureSummaryDisplay(null) } + private fun startKeyRetrievalAndRiskCalcBenchmark() { + hideKeyboard() + lifecycleScope.launch { + val repeatCount = + binding.inputMeasureRiskKeyRepeatCount.text.toString().toInt() + context?.let { + RiskLevelAndKeyRetrievalBenchmark( + it, + lastSetCountries ?: listOf("DE") + ).start(repeatCount) { status -> + binding.labelTestApiMeasureCalcKeyStatus.text = status + } + } + } + } + + private fun filterCountryCodes() { + hideKeyboard() + // Get user input country codes + val rawCountryCodes = binding.inputCountryCodesEditText.text.toString() + + // Country codes can be separated by space or , + val countryCodes = rawCountryCodes.split(',', ' ').filter { it.isNotEmpty() } + + lastSetCountries = countryCodes + + // Trigger asyncFetchFiles which will use all Countries passed as parameter + lifecycleScope.launch { + val locationCodes = countryCodes.map { LocationCode(it) } + AppInjector.component.keyFileDownloader.asyncFetchKeyFiles(locationCodes) + updateCountryStatusLabel() + } + } + + private fun hideKeyboard() { + activity?.currentFocus.let { + val inputManager = + context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + inputManager.hideSoftInputFromWindow(it?.windowToken, 0) + } + } + + /** + * Updates the Label for country filter + */ + private fun updateCountryStatusLabel() { + binding.labelCountryCodeFilterStatus.text = "Country filter applied for: \n " + + "${lastSetCountries?.joinToString(",")}" + } + private val prettyKey = { key: AppleLegacyKeyExchange.Key -> StringBuilder() .append("\nKey data: ${key.keyData}") @@ -315,9 +387,8 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel private val onScannedKey = { key: AppleLegacyKeyExchange.Key? -> Timber.i("keys scanned..") key?.let { - text_scanned_key.text = prettyKey(key) - text_scanned_key.visibility = View.VISIBLE -// text_scanned_key.movementMethod = ScrollingMovementMethod.getInstance() + binding.textScannedKey.text = prettyKey(key) + binding.textScannedKey.visibility = View.VISIBLE } otherExposureKeyList.add(key!!) otherExposureKey = key @@ -333,7 +404,7 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel IntentIntegrator.parseActivityResult(requestCode, resultCode, data) if (result != null) { if (result.contents == null) { - Toast.makeText(requireContext(), "Cancelled", Toast.LENGTH_LONG).show() + showToast("Cancelled") } else { ExposureSharingService.getOthersKeys(result.contents, onScannedKey) } @@ -389,8 +460,10 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel .build() ) - val dir = - File(File(requireContext().getExternalFilesDir(null), "key-export"), token ?: "") + val dir = File( + File(requireContext().getExternalFilesDir(null), "key-export"), + token ?: "" + ) dir.mkdirs() var googleFileList: List<File> @@ -400,7 +473,7 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel Timber.i("Provide ${googleFileList.count()} files with ${appleKeyList.size} keys with token $token") try { // only testing implementation: this is used to wait for the broadcastreceiver of the OS / EN API - InternalExposureNotificationClient.asyncProvideDiagnosisKeys( + enfClient.provideDiagnosisKeys( googleFileList, ApplicationConfigurationService.asyncRetrieveExposureConfiguration(), token!! @@ -432,27 +505,27 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel private fun updateExposureSummaryDisplay(exposureSummary: ExposureSummary?) { - label_exposure_summary_matchedKeyCount.text = getString( + binding.labelExposureSummaryMatchedKeyCount.text = getString( R.string.test_api_body_matchedKeyCount, (exposureSummary?.matchedKeyCount ?: "-").toString() ) - label_exposure_summary_daysSinceLastExposure.text = getString( + binding.labelExposureSummaryDaysSinceLastExposure.text = getString( R.string.test_api_body_daysSinceLastExposure, (exposureSummary?.daysSinceLastExposure ?: "-").toString() ) - label_exposure_summary_maximumRiskScore.text = getString( + binding.labelExposureSummaryMaximumRiskScore.text = getString( R.string.test_api_body_maximumRiskScore, (exposureSummary?.maximumRiskScore ?: "-").toString() ) - label_exposure_summary_summationRiskScore.text = getString( + binding.labelExposureSummarySummationRiskScore.text = getString( R.string.test_api_body_summation_risk, (exposureSummary?.summationRiskScore ?: "-").toString() ) - label_exposure_summary_attenuation.text = getString( + binding.labelExposureSummaryAttenuation.text = getString( R.string.test_api_body_attenuation, (exposureSummary?.attenuationDurationsInMinutes?.joinToString() ?: "-").toString() ) @@ -469,20 +542,26 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel R.string.test_api_body_my_keys, myKeys?.size ?: 0 ) - label_my_keys.text = myKeysLabelAndCount - text_my_keys.text = myExposureKeysJSON + binding.labelMyKeys.text = myKeysLabelAndCount + binding.textMyKeys.text = myExposureKeysJSON - myKeys?.maxBy { it.rollingStartIntervalNumber }?.rollingStartIntervalNumber?.toLong()?.let { - val ms = it * 60L * 10L * 1000L - val dateString = DateTime(ms, DateTimeZone.UTC) + myKeys + ?.maxByOrNull { it.rollingStartIntervalNumber } + ?.rollingStartIntervalNumber?.toLong() + ?.let { + val ms = it * 60L * 10L * 1000L + val dateString = DateTime(ms, DateTimeZone.UTC) - label_latest_key_date.text = "Latest key is from: $dateString" - } + binding.labelLatestKeyDate.text = "Latest key is from: $dateString" + } } private fun showToast(message: String) { - val toast = Toast.makeText(context, message, Toast.LENGTH_LONG) - toast.show() + Toast.makeText(context, message, Toast.LENGTH_LONG).show() + } + + private fun showSnackBar(message: String) { + Snackbar.make(requireView(), message, Snackbar.LENGTH_LONG).show() } override fun onFailure(exception: Exception?) { @@ -501,50 +580,6 @@ class TestForAPIFragment : Fragment(), InternalExposureNotificationPermissionHel updateKeysDisplay() } - private fun getCustomConfig(): ExposureConfiguration = ExposureConfiguration - .ExposureConfigurationBuilder() - .setAttenuationScores( - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE - ) - .setDaysSinceLastExposureScores( - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE - ) - .setDurationScores( - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE - ) - .setTransmissionRiskScores( - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE, - CONFIG_SCORE - ) - .build() - private inner class QRPagerAdapter : RecyclerView.Adapter<QRPagerAdapter.QRViewHolder>() { diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..38504b80936698889c42139f31388e5d4cf1f2e9 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentModule.kt @@ -0,0 +1,16 @@ +package de.rki.coronawarnapp.test.api.ui + +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey + +@Module +abstract class TestForApiFragmentModule { + @Binds + @IntoMap + @CWAViewModelKey(TestForApiFragmentViewModel::class) + abstract fun testRiskLevelFragment(factory: TestForApiFragmentViewModel.Factory): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..5593009bb47d1ae831c2a115032e0c8577a22119 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModel.kt @@ -0,0 +1,124 @@ +package de.rki.coronawarnapp.test.api.ui + +import android.content.Context +import androidx.core.content.pm.PackageInfoCompat +import androidx.lifecycle.viewModelScope +import com.google.android.gms.common.GoogleApiAvailability +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.environment.EnvironmentSetup +import de.rki.coronawarnapp.environment.EnvironmentSetup.Type.Companion.toEnvironmentType +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.TransactionException +import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.test.api.ui.EnvironmentState.Companion.toEnvironmentState +import de.rki.coronawarnapp.test.api.ui.LoggerState.Companion.toLoggerState +import de.rki.coronawarnapp.transaction.RiskLevelTransaction +import de.rki.coronawarnapp.util.CWADebug +import de.rki.coronawarnapp.util.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.ui.smartLiveData +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.io.File + +class TestForApiFragmentViewModel @AssistedInject constructor( + private val context: Context, + private val envSetup: EnvironmentSetup +) : CWAViewModel() { + + val debugOptionsState by smartLiveData { + DebugOptionsState( + areNotificationsEnabled = LocalData.backgroundNotification(), + is3HourModeEnabled = LocalData.last3HoursMode() + ) + } + + val last3HourToggleEvent = SingleLiveEvent<Boolean>() + + fun setLast3HoursMode(enabled: Boolean) { + debugOptionsState.update { + LocalData.last3HoursMode(enabled) + it.copy(is3HourModeEnabled = enabled) + } + last3HourToggleEvent.postValue(enabled) + } + + val environmentState by smartLiveData { + envSetup.toEnvironmentState() + } + val environmentChangeEvent = SingleLiveEvent<EnvironmentSetup.Type>() + + fun selectEnvironmentTytpe(type: String) { + environmentState.update { + envSetup.currentEnvironment = type.toEnvironmentType() + environmentChangeEvent.postValue(envSetup.currentEnvironment) + envSetup.toEnvironmentState() + } + } + + val backgroundNotificationsToggleEvent = SingleLiveEvent<Boolean>() + + fun setBackgroundNotifications(enabled: Boolean) { + debugOptionsState.update { + LocalData.backgroundNotification(enabled) + it.copy(areNotificationsEnabled = enabled) + } + backgroundNotificationsToggleEvent.postValue(enabled) + } + + val loggerState by smartLiveData { + CWADebug.toLoggerState() + } + + fun setLoggerEnabled(enable: Boolean) { + CWADebug.fileLogger?.let { + if (enable) it.start() else it.stop() + } + loggerState.update { CWADebug.toLoggerState() } + } + + fun calculateRiskLevelClicked() { + viewModelScope.launch { + try { + RiskLevelTransaction.start() + } catch (e: TransactionException) { + e.report(ExceptionCategory.INTERNAL) + } + } + } + + val logShareEvent = SingleLiveEvent<File?>() + + fun shareLogFile() { + CWADebug.fileLogger?.let { + viewModelScope.launch(context = Dispatchers.Default) { + if (!it.logFile.exists()) return@launch + + val externalPath = File( + context.getExternalFilesDir(null), + "LogFile-${System.currentTimeMillis()}.log" + ) + + it.logFile.copyTo(externalPath) + + logShareEvent.postValue(externalPath) + } + } + } + + val gmsState by smartLiveData { + GoogleServicesState( + version = PackageInfoCompat.getLongVersionCode( + context.packageManager.getPackageInfo( + GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE, + 0 + ) + ) + ) + } + + @AssistedInject.Factory + interface Factory : SimpleCWAViewModelFactory<TestForApiFragmentViewModel> +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuAdapter.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..246a6b59503db761c03b16f8f7bf911eb1905d65 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuAdapter.kt @@ -0,0 +1,45 @@ +package de.rki.coronawarnapp.test.menu.ui + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentTestMenuAdapterItemBinding +import de.rki.coronawarnapp.ui.lists.BaseAdapter +import javax.inject.Inject + +class TestMenuAdapter @Inject constructor() : BaseAdapter<TestMenuAdapter.VH>() { + + private val internalData = mutableListOf<TestMenuItem>() + + var data: List<TestMenuItem> + get() = internalData.toList() + set(value) { + internalData.clear() + internalData.addAll(value) + notifyDataSetChanged() + } + + var onItemClickListener: (TestMenuItem) -> Unit = {} + + override fun getItemCount(): Int = internalData.size + + override fun onCreateBaseVH(parent: ViewGroup, viewType: Int): VH = VH(parent) + + override fun onBindBaseVH(holder: VH, position: Int) { + holder.apply { + val item = internalData[position] + bind(item) + itemView.setOnClickListener { onItemClickListener(item) } + } + } + + class VH(parent: ViewGroup) : BaseAdapter.VH(R.layout.fragment_test_menu_adapter_item, parent) { + private val viewBinding: FragmentTestMenuAdapterItemBinding = + FragmentTestMenuAdapterItemBinding.bind(itemView) + + fun bind(item: TestMenuItem) = viewBinding.apply { + imageView.setImageResource(item.iconRes) + title.text = item.title + description.text = item.description + } + } +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..8ccbcf5f5490cd8f634ad1780f7d1345b38592d6 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragment.kt @@ -0,0 +1,41 @@ +package de.rki.coronawarnapp.test.menu.ui + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentTestMenuBinding +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModels +import javax.inject.Inject + +class TestMenuFragment : Fragment(R.layout.fragment_test_menu), AutoInject { + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val vm: TestMenuFragmentViewModel by cwaViewModels { viewModelFactory } + + private val binding: FragmentTestMenuBinding by viewBindingLazy() + + @Inject lateinit var menuAdapter: TestMenuAdapter + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.testMenuList.apply { + layoutManager = LinearLayoutManager(requireContext()) + adapter = menuAdapter + } + + vm.testMenuData.observe2(this) { menuAdapter.data = it } + menuAdapter.onItemClickListener = { vm.showTestScreen(it) } + + vm.showTestScreenEvent.observe2(this) { + findNavController().navigate(it.targetId) + } + } +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..caf82c2556ec48477edcee01578e088b678e96c5 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentModule.kt @@ -0,0 +1,16 @@ +package de.rki.coronawarnapp.test.menu.ui + +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey + +@Module +abstract class TestMenuFragmentModule { + @Binds + @IntoMap + @CWAViewModelKey(TestMenuFragmentViewModel::class) + abstract fun testRiskLevelFragment(factory: TestMenuFragmentViewModel.Factory): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..214735fd424d2efde9d88148f3fed4cbc2d1b8e8 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragmentViewModel.kt @@ -0,0 +1,27 @@ +package de.rki.coronawarnapp.test.menu.ui + +import androidx.lifecycle.MutableLiveData +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.test.api.ui.TestForAPIFragment +import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragment +import de.rki.coronawarnapp.util.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory + +class TestMenuFragmentViewModel @AssistedInject constructor() : CWAViewModel() { + + val testMenuData by lazy { + listOf( + TestForAPIFragment.MENU_ITEM, + TestRiskLevelCalculationFragment.MENU_ITEM + ).let { MutableLiveData(it) } + } + val showTestScreenEvent = SingleLiveEvent<TestMenuItem>() + + fun showTestScreen(it: TestMenuItem) { + showTestScreenEvent.postValue(it) + } + + @AssistedInject.Factory + interface Factory : SimpleCWAViewModelFactory<TestMenuFragmentViewModel> +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuItem.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..765012f4817f7c57dceab48e7139555172aeffb0 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuItem.kt @@ -0,0 +1,12 @@ +package de.rki.coronawarnapp.test.menu.ui + +import androidx.annotation.DrawableRes +import androidx.annotation.IdRes +import de.rki.coronawarnapp.R + +data class TestMenuItem( + @DrawableRes val iconRes: Int = R.drawable.ic_bug, + val title: String, + val description: String, + @IdRes val targetId: Int +) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..437122d7a6eb1f4b64fc3747eb2c518ab63f2bba --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt @@ -0,0 +1,131 @@ +package de.rki.coronawarnapp.test.risklevel.ui + +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.navArgs +import com.google.zxing.integration.android.IntentIntegrator +import com.google.zxing.integration.android.IntentResult +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentTestRiskLevelCalculationBinding +import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange +import de.rki.coronawarnapp.sharing.ExposureSharingService +import de.rki.coronawarnapp.test.menu.ui.TestMenuItem +import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel +import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel +import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted +import timber.log.Timber +import javax.inject.Inject + +@Suppress("MagicNumber", "LongMethod") +class TestRiskLevelCalculationFragment : Fragment(R.layout.fragment_test_risk_level_calculation), + AutoInject { + private val navArgs by navArgs<TestRiskLevelCalculationFragmentArgs>() + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val vm: TestRiskLevelCalculationFragmentCWAViewModel by cwaViewModelsAssisted( + { viewModelFactory }, + { factory, handle -> + factory as TestRiskLevelCalculationFragmentCWAViewModel.Factory + factory.create(handle, navArgs.exampleArgument) + } + ) + + private val tracingViewModel: TracingViewModel by activityViewModels() + private val settingsViewModel: SettingsViewModel by activityViewModels() + private val submissionViewModel: SubmissionViewModel by activityViewModels() + + private val binding: FragmentTestRiskLevelCalculationBinding by viewBindingLazy() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.tracingViewModel = tracingViewModel + binding.settingsViewModel = settingsViewModel + binding.submissionViewModel = submissionViewModel + + binding.buttonRetrieveDiagnosisKeys.setOnClickListener { vm.retrieveDiagnosisKeys() } + binding.buttonProvideKeyViaQr.setOnClickListener { vm.scanLocalQRCodeAndProvide() } + binding.buttonCalculateRiskLevel.setOnClickListener { vm.calculateRiskLevel() } + binding.buttonClearDiagnosisKeyCache.setOnClickListener { vm.clearKeyCache() } + + binding.buttonResetRiskLevel.setOnClickListener { vm.resetRiskLevel() } + vm.riskLevelResetEvent.observe2(this) { + Toast.makeText( + requireContext(), "Reset done, please fetch diagnosis keys from server again", + Toast.LENGTH_SHORT + ).show() + } + + vm.riskScoreState.observe2(this) { state -> + binding.labelRiskScore.text = state.riskScoreMsg + binding.labelBackendParameters.text = state.backendParameters + binding.labelExposureSummary.text = state.exposureSummary + binding.labelFormula.text = state.formula + binding.labelFullConfig.text = state.fullConfig + binding.labelExposureInfo.text = state.exposureInfo + } + vm.startENFObserver() + + vm.apiKeysProvidedEvent.observe2(this) { event -> + Toast.makeText( + requireContext(), + "Provided ${event.keyCount} keys to Google API with token ${event.token}", + Toast.LENGTH_SHORT + ).show() + } + + vm.startLocalQRCodeScanEvent.observe2(this) { + IntentIntegrator.forSupportFragment(this) + .setOrientationLocked(false) + .setBeepEnabled(false) + .initiateScan() + } + } + + override fun onResume() { + super.onResume() + vm.calculateRiskLevel() + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + val result: IntentResult = + IntentIntegrator.parseActivityResult(requestCode, resultCode, data) + ?: return super.onActivityResult(requestCode, resultCode, data) + + if (result.contents == null) { + Toast.makeText(requireContext(), "Cancelled", Toast.LENGTH_LONG).show() + return + } + + ExposureSharingService.getOthersKeys(result.contents) { key: AppleLegacyKeyExchange.Key? -> + Timber.i("Keys scanned: %s", key) + if (key == null) { + Toast.makeText( + requireContext(), "No Key data found in QR code", Toast.LENGTH_SHORT + ).show() + return@getOthersKeys Unit + } + + val text = binding.transmissionNumber.text.toString() + val number = if (!text.isBlank()) Integer.valueOf(text) else 5 + vm.provideDiagnosisKey(number, key) + } + } + + companion object { + val TAG: String = TestRiskLevelCalculationFragment::class.simpleName!! + val MENU_ITEM = TestMenuItem( + title = "Risklevel Calculation", + description = "Risklevel calculation related test options.", + targetId = R.id.test_risklevel_calculation_fragment + ) + } +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..7ba08ef6d67382d462fb1beca3af4f1519a90491 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModel.kt @@ -0,0 +1,295 @@ +package de.rki.coronawarnapp.test.risklevel.ui + +import android.content.Context +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import com.google.android.gms.nearby.exposurenotification.ExposureInformation +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.nearby.ENFClient +import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient +import de.rki.coronawarnapp.risk.DefaultRiskLevelCalculation +import de.rki.coronawarnapp.risk.RiskLevel +import de.rki.coronawarnapp.risk.TimeVariables +import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange +import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService +import de.rki.coronawarnapp.storage.AppDatabase +import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.storage.RiskLevelRepository +import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction +import de.rki.coronawarnapp.transaction.RiskLevelTransaction +import de.rki.coronawarnapp.util.KeyFileHelper +import de.rki.coronawarnapp.util.security.SecurityHelper +import de.rki.coronawarnapp.util.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import timber.log.Timber +import java.io.File +import java.util.UUID +import java.util.concurrent.TimeUnit +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +class TestRiskLevelCalculationFragmentCWAViewModel @AssistedInject constructor( + @Assisted private val handle: SavedStateHandle, + @Assisted private val exampleArg: String?, + private val context: Context, // App context + private val enfClient: ENFClient, + private val keyCacheRepository: KeyCacheRepository +) : CWAViewModel() { + + val startLocalQRCodeScanEvent = SingleLiveEvent<Unit>() + val riskLevelResetEvent = SingleLiveEvent<Unit>() + val apiKeysProvidedEvent = SingleLiveEvent<DiagnosisKeyProvidedEvent>() + val riskScoreState = MutableLiveData<RiskScoreState>(RiskScoreState()) + + init { + Timber.d("CWAViewModel: %s", this) + Timber.d("SavedStateHandle: %s", handle) + Timber.d("Example arg: %s", exampleArg) + } + + fun retrieveDiagnosisKeys() { + viewModelScope.launch { + try { + RetrieveDiagnosisKeysTransaction.start() + calculateRiskLevel() + } catch (e: Exception) { + e.report(ExceptionCategory.INTERNAL) + } + } + } + + fun calculateRiskLevel() { + viewModelScope.launch { + try { + RiskLevelTransaction.start() + } catch (e: Exception) { + e.report(ExceptionCategory.INTERNAL) + } + } + } + + fun resetRiskLevel() { + viewModelScope.launch { + withContext(Dispatchers.IO) { + try { + // Preference reset + SecurityHelper.resetSharedPrefs() + // Database Reset + AppDatabase.reset(context) + // Export File Reset + keyCacheRepository.clear() + + LocalData.lastCalculatedRiskLevel(RiskLevel.UNDETERMINED.raw) + LocalData.lastSuccessfullyCalculatedRiskLevel(RiskLevel.UNDETERMINED.raw) + LocalData.lastTimeDiagnosisKeysFromServerFetch(null) + LocalData.googleApiToken(null) + } catch (e: Exception) { + e.report(ExceptionCategory.INTERNAL) + } + } + RiskLevelTransaction.start() + riskLevelResetEvent.postValue(Unit) + } + } + + data class RiskScoreState( + val riskScoreMsg: String = "", + val backendParameters: String = "", + val exposureSummary: String = "", + val formula: String = "", + val fullConfig: String = "", + val exposureInfo: String = "" + ) + + fun startENFObserver() { + viewModelScope.launch { + try { + var workState = riskScoreState.value!! + + val googleToken = LocalData.googleApiToken() ?: UUID.randomUUID().toString() + val exposureSummary = + InternalExposureNotificationClient.asyncGetExposureSummary(googleToken) + + val appConfig = + ApplicationConfigurationService.asyncRetrieveApplicationConfiguration() + + val riskLevelScore = DefaultRiskLevelCalculation().calculateRiskScore( + appConfig.attenuationDuration, + exposureSummary + ) + + val riskAsString = "Level: ${RiskLevelRepository.getLastCalculatedScore()}\n" + + "Last successful Level: " + + "${LocalData.lastSuccessfullyCalculatedRiskLevel()}\n" + + "Calculated Score: ${riskLevelScore}\n" + + "Last Time Server Fetch: ${LocalData.lastTimeDiagnosisKeysFromServerFetch()}\n" + + "Tracing Duration: " + + "${TimeUnit.MILLISECONDS.toDays(TimeVariables.getTimeActiveTracingDuration())} days \n" + + "Tracing Duration in last 14 days: " + + "${TimeVariables.getActiveTracingDaysInRetentionPeriod()} days \n" + + "Last time risk level calculation ${LocalData.lastTimeRiskLevelCalculation()}" + + workState = workState.copy(riskScoreMsg = riskAsString) + + val lowClass = + appConfig.riskScoreClasses?.riskClassesList?.find { low -> low.label == "LOW" } + val highClass = + appConfig.riskScoreClasses?.riskClassesList?.find { high -> high.label == "HIGH" } + + val configAsString = + "Attenuation Weight Low: ${appConfig.attenuationDuration?.weights?.low}\n" + + "Attenuation Weight Mid: ${appConfig.attenuationDuration?.weights?.mid}\n" + + "Attenuation Weight High: ${appConfig.attenuationDuration?.weights?.high}\n\n" + + "Attenuation Offset: ${appConfig.attenuationDuration?.defaultBucketOffset}\n" + + "Attenuation Normalization: " + + "${appConfig.attenuationDuration?.riskScoreNormalizationDivisor}\n\n" + + "Risk Score Low Class: ${lowClass?.min ?: 0} - ${lowClass?.max ?: 0}\n" + + "Risk Score High Class: ${highClass?.min ?: 0} - ${highClass?.max ?: 0}" + + workState = workState.copy(backendParameters = configAsString) + + val summaryAsString = + "Days Since Last Exposure: ${exposureSummary.daysSinceLastExposure}\n" + + "Matched Key Count: ${exposureSummary.matchedKeyCount}\n" + + "Maximum Risk Score: ${exposureSummary.maximumRiskScore}\n" + + "Attenuation Durations: [${ + exposureSummary.attenuationDurationsInMinutes?.get( + 0 + ) + }," + + "${exposureSummary.attenuationDurationsInMinutes?.get(1)}," + + "${exposureSummary.attenuationDurationsInMinutes?.get(2)}]\n" + + "Summation Risk Score: ${exposureSummary.summationRiskScore}" + + workState = workState.copy(exposureSummary = summaryAsString) + + val maxRisk = exposureSummary.maximumRiskScore + val atWeights = appConfig.attenuationDuration?.weights + val attenuationDurationInMin = + exposureSummary.attenuationDurationsInMinutes + val attenuationConfig = appConfig.attenuationDuration + val formulaString = + "($maxRisk / ${attenuationConfig?.riskScoreNormalizationDivisor}) * " + + "(${attenuationDurationInMin?.get(0)} * ${atWeights?.low} " + + "+ ${attenuationDurationInMin?.get(1)} * ${atWeights?.mid} " + + "+ ${attenuationDurationInMin?.get(2)} * ${atWeights?.high} " + + "+ ${attenuationConfig?.defaultBucketOffset})" + + workState = + workState.copy(formula = formulaString, fullConfig = appConfig.toString()) + + val token = LocalData.googleApiToken() + if (token != null) { + val exposureInformation = asyncGetExposureInformation(token) + + var infoString = "" + exposureInformation.forEach { + infoString += "Attenuation duration in min.: " + + "[${it.attenuationDurationsInMinutes?.get(0)}, " + + "${it.attenuationDurationsInMinutes?.get(1)}," + + "${it.attenuationDurationsInMinutes?.get(2)}]\n" + + "Attenuation value: ${it.attenuationValue}\n" + + "Duration in min.: ${it.durationMinutes}\n" + + "Risk Score: ${it.totalRiskScore}\n" + + "Transmission Risk Level: ${it.transmissionRiskLevel}\n" + + "Date Millis Since Epoch: ${it.dateMillisSinceEpoch}\n\n" + } + + workState = workState.copy(exposureInfo = infoString) + } + + riskScoreState.postValue(workState) + } catch (e: Exception) { + e.report(ExceptionCategory.EXPOSURENOTIFICATION) + } + } + } + + private suspend fun asyncGetExposureInformation(token: String): List<ExposureInformation> = + suspendCoroutine { cont -> + enfClient.internalClient.getExposureInformation(token) + .addOnSuccessListener { + cont.resume(it) + }.addOnFailureListener { + cont.resumeWithException(it) + } + } + + data class DiagnosisKeyProvidedEvent( + val keyCount: Int, + val token: String + ) + + fun provideDiagnosisKey(transmissionNumber: Int, key: AppleLegacyKeyExchange.Key) { + val token = UUID.randomUUID().toString() + LocalData.googleApiToken(token) + + val appleKeyList = mutableListOf<AppleLegacyKeyExchange.Key>() + + AppleLegacyKeyExchange.Key.newBuilder() + .setKeyData(key.keyData) + .setRollingPeriod(144) + .setRollingStartNumber(key.rollingStartNumber) + .setTransmissionRiskLevel(transmissionNumber) + .build() + .also { appleKeyList.add(it) } + + val appleFiles = listOf( + AppleLegacyKeyExchange.File.newBuilder() + .addAllKeys(appleKeyList) + .build() + ) + + val dir = File(File(context.getExternalFilesDir(null), "key-export"), token) + dir.mkdirs() + + var googleFileList: List<File> + viewModelScope.launch { + googleFileList = KeyFileHelper.asyncCreateExportFiles(appleFiles, dir) + + Timber.i("Provide ${googleFileList.count()} files with ${appleKeyList.size} keys with token $token") + try { + // only testing implementation: this is used to wait for the broadcastreceiver of the OS / EN API + enfClient.provideDiagnosisKeys( + googleFileList, + ApplicationConfigurationService.asyncRetrieveExposureConfiguration(), + token + ) + apiKeysProvidedEvent.postValue( + DiagnosisKeyProvidedEvent( + keyCount = appleFiles.size, + token = token + ) + ) + } catch (e: Exception) { + e.report(ExceptionCategory.EXPOSURENOTIFICATION) + } + } + } + + fun scanLocalQRCodeAndProvide() { + startLocalQRCodeScanEvent.postValue(Unit) + } + + fun clearKeyCache() { + viewModelScope.launch { keyCacheRepository.clear() } + } + + @AssistedInject.Factory + interface Factory : CWAViewModelFactory<TestRiskLevelCalculationFragmentCWAViewModel> { + fun create( + handle: SavedStateHandle, + exampleArg: String? + ): TestRiskLevelCalculationFragmentCWAViewModel + } +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..1824e96499f7de067d31fa2630bf874b13d30cf5 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentModule.kt @@ -0,0 +1,16 @@ +package de.rki.coronawarnapp.test.risklevel.ui + +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey + +@Module +abstract class TestRiskLevelCalculationFragmentModule { + @Binds + @IntoMap + @CWAViewModelKey(TestRiskLevelCalculationFragmentCWAViewModel::class) + abstract fun testRiskLevelFragment(factory: TestRiskLevelCalculationFragmentCWAViewModel.Factory): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..21917dcf8a13dfd56e5854c2fa98438030748dce --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/ui/main/MainActivityTestModule.kt @@ -0,0 +1,23 @@ +package de.rki.coronawarnapp.ui.main + +import dagger.Module +import dagger.android.ContributesAndroidInjector +import de.rki.coronawarnapp.test.api.ui.TestForAPIFragment +import de.rki.coronawarnapp.test.api.ui.TestForApiFragmentModule +import de.rki.coronawarnapp.test.menu.ui.TestMenuFragment +import de.rki.coronawarnapp.test.menu.ui.TestMenuFragmentModule +import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragment +import de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragmentModule + +@Module +abstract class MainActivityTestModule { + + @ContributesAndroidInjector(modules = [TestMenuFragmentModule::class]) + abstract fun testMenuFragment(): TestMenuFragment + + @ContributesAndroidInjector(modules = [TestRiskLevelCalculationFragmentModule::class]) + abstract fun testRiskLevelCalculationFragment(): TestRiskLevelCalculationFragment + + @ContributesAndroidInjector(modules = [TestForApiFragmentModule::class]) + abstract fun testRiskLevelApiFragment(): TestForAPIFragment +} diff --git a/Corona-Warn-App/src/deviceForTesters/res/drawable/ic_bug.xml b/Corona-Warn-App/src/deviceForTesters/res/drawable/ic_bug.xml new file mode 100644 index 0000000000000000000000000000000000000000..ed88658407baec3e8107d6281f279e9d0af2f86c --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/res/drawable/ic_bug.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="24dp" + android:width="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#000" + android:pathData="M14,12H10V10H14M14,16H10V14H14M20,8H17.19C16.74,7.22 16.12,6.55 15.37,6.04L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.04,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6.04C7.88,6.55 7.26,7.22 6.81,8H4V10H6.09C6.04,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.04,15.67 6.09,16H4V18H6.81C7.85,19.79 9.78,21 12,21C14.22,21 16.15,19.79 17.19,18H20V16H17.91C17.96,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.96,10.33 17.91,10H20V8Z" /> +</vector> diff --git a/Corona-Warn-App/src/deviceForTesters/res/drawable/ic_coffee.xml b/Corona-Warn-App/src/deviceForTesters/res/drawable/ic_coffee.xml new file mode 100644 index 0000000000000000000000000000000000000000..95c65dbf1b3c2232925dc54ff1f98bc6e1c49567 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/res/drawable/ic_coffee.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="24dp" + android:width="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#000" + android:pathData="M2,21H20V19H2M20,8H18V5H20M20,3H4V13A4,4 0 0,0 8,17H14A4,4 0 0,0 18,13V10H20A2,2 0 0,0 22,8V5C22,3.89 21.1,3 20,3Z" /> +</vector> diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_main.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_main.xml deleted file mode 100644 index 6bc3b0d303336a278d750fbcdebb9470a884cbf7..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_main.xml +++ /dev/null @@ -1,235 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools"> - - <data> - - <import type="de.rki.coronawarnapp.util.formatter.FormatterSettingsHelper" /> - - <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> - - <variable - name="submissionViewModel" - type="de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel" /> - - <variable - name="tracingViewModel" - type="de.rki.coronawarnapp.ui.viewmodel.TracingViewModel" /> - - <variable - name="settingsViewModel" - type="de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel" /> - </data> - - <ScrollView - android:id="@+id/main_scrollview" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:contentDescription="@string/main_title" - android:fillViewport="true" - tools:context="de.rki.coronawarnapp.ui.main.MainFragment"> - - <!-- todo apply merge tags through xml when applicable (eod) --> - <androidx.constraintlayout.widget.ConstraintLayout - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <androidx.constraintlayout.widget.ConstraintLayout - android:id="@+id/main_header" - android:layout_width="@dimen/match_constraint" - android:layout_height="@dimen/header_main" - android:layout_margin="@dimen/spacing_small" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent"> - - <ImageView - android:id="@+id/main_header_logo" - android:layout_width="0dp" - android:layout_height="match_parent" - android:importantForAccessibility="no" - android:scaleType="fitStart" - android:src="@drawable/ic_main_header" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@+id/main_header_share" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - <include - android:id="@+id/main_header_share" - layout="@layout/include_button_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:icon="@{@drawable/ic_main_share}" - app:iconDescription="@{@string/main_share_title}" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@+id/main_header_options_menu" - app:layout_constraintTop_toTopOf="parent" /> - - <include - android:id="@+id/main_header_options_menu" - layout="@layout/include_button_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:icon="@{@drawable/ic_main_settings}" - app:iconDescription="@{@string/accessibility_menu}" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - </androidx.constraintlayout.widget.ConstraintLayout> - - <androidx.constraintlayout.widget.ConstraintLayout - android:id="@+id/main_tracing" - style="@style/buttonTracing" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:focusable="true" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.0" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/main_header"> - - <TextView - android:id="@+id/main_tracing_headline" - style="@style/bodyButton" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/spacing_small" - android:focusable="false" - android:contentDescription="@{FormatterSettingsHelper.formatTracingContentDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - android:text="@{FormatterSettingsHelper.formatTracingDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@id/main_tracing_icon" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - <com.airbnb.lottie.LottieAnimationView - android:id="@+id/main_tracing_icon" - android:layout_width="@dimen/icon_size_main_card" - android:layout_height="@dimen/icon_size_main_card" - android:importantForAccessibility="no" - app:animation="@{FormatterSettingsHelper.formatTracingIcon(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:animation_tint="@{FormatterSettingsHelper.formatTracingIconColor(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - </androidx.constraintlayout.widget.ConstraintLayout> - - <include - android:id="@+id/main_tracing_divider" - layout="@layout/include_divider" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/main_tracing" /> - - <include - android:id="@+id/main_risk" - layout="@layout/include_risk_card" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:visibility="@{FormatterSubmissionHelper.formatShowRiskStatusCard(submissionViewModel.deviceUiState)}" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/main_tracing_divider" - app:settingsViewModel="@{settingsViewModel}" - app:showDetails="@{false}" - app:tracingViewModel="@{tracingViewModel}" /> - - <!-- submission status cards --> - <include - android:id="@+id/main_test_unregistered" - layout="@layout/include_submission_status_card_unregistered" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:visibility="@{FormatterSubmissionHelper.formatSubmissionStatusCardUnregisteredVisible(submissionViewModel.deviceRegistered)}" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@id/main_risk" /> - - <include - android:id="@+id/main_test_result" - layout="@layout/include_submission_status_card_content" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:visibility="@{FormatterSubmissionHelper.formatSubmissionStatusCardContentVisible(submissionViewModel.deviceUiState)}" - app:deviceUIState="@{submissionViewModel.deviceUiState}" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@id/main_test_unregistered" /> - - <include - android:id="@+id/main_test_fetching" - layout="@layout/include_submission_status_card_fetching" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:visibility="@{FormatterSubmissionHelper.formatSubmissionStatusCardFetchingVisible(submissionViewModel.deviceRegistered, submissionViewModel.uiStateState)}" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@id/main_test_result" /> - - <include - android:id="@+id/main_test_positive" - layout="@layout/include_submission_status_card_positive" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:visibility="@{FormatterSubmissionHelper.formatShowSubmissionStatusPositiveCard(submissionViewModel.deviceUiState)}" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/main_test_fetching" - app:registerDate="@{submissionViewModel.testResultReceivedDate}" /> - - <include - android:id="@+id/main_test_done" - layout="@layout/include_submission_status_card_done" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - android:visibility="@{FormatterSubmissionHelper.formatShowSubmissionDoneCard(submissionViewModel.deviceUiState)}" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/main_test_positive" /> - - <androidx.constraintlayout.widget.Barrier - android:id="@+id/main_barrier" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:barrierDirection="bottom" - app:constraint_referenced_ids="main_test_done, main_risk" /> - - <include - android:id="@+id/main_about" - layout="@layout/include_main_faq_card" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_small" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/main_barrier" - app:layout_constraintBottom_toBottomOf="@+id/guideline_bottom" - app:layout_constraintVertical_bias="0.0"/> - - <include layout="@layout/merge_guidelines_side" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline_bottom" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_end="@dimen/spacing_small" /> - - <include layout="@layout/merge_guidelines_card" /> - - </androidx.constraintlayout.widget.ConstraintLayout> - - </ScrollView> -</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml index 2507759dc3d939671b1ca2fb9a715104020d0fe5..9f51b5f868023c208e1c39c163a1619ea9b76dcb 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_for_a_p_i.xml @@ -1,7 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> -<layout xmlns:tools="http://schemas.android.com/tools" - tools:ignore="HardcodedText" - xmlns:android="http://schemas.android.com/apk/res/android"> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:ignore="HardcodedText"> <data> @@ -10,300 +11,469 @@ type="de.rki.coronawarnapp.ui.viewmodel.TracingViewModel" /> </data> - <ScrollView + <androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_margin="@dimen/spacing_normal" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_margin="@dimen/spacing_normal" + android:layout_margin="@dimen/spacing_tiny" android:orientation="vertical"> - <TextView - android:id="@+id/label_googlePlayServices_version" + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/debug_container" + style="@style/card" + android:layout_margin="@dimen/spacing_tiny" android:layout_width="match_parent" - android:layout_height="wrap_content" /> - + android:layout_height="wrap_content"> - <Switch - android:id="@+id/test_api_switch_last_three_hours_from_server" - style="@style/body1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/test_api_switch_last_three_hours_from_server" - android:theme="@style/switchBase" /> + <TextView + android:id="@+id/debug_container_title" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Debug options" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - <Switch - android:id="@+id/test_api_switch_background_notifications" - style="@style/body1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/test_api_switch_background_notifications" - android:theme="@style/switchBase" /> + <Switch + android:id="@+id/three_hour_mode_toggle" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginTop="@dimen/spacing_small" + android:text="@string/test_api_switch_last_three_hours_from_server" + android:theme="@style/switchBase" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/debug_container_title" /> - <LinearLayout - android:layout_width="match_parent" - android:orientation="horizontal" - android:layout_height="wrap_content"> + <Switch + android:id="@+id/background_notifications_toggle" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/test_api_switch_background_notifications" + android:theme="@style/switchBase" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/three_hour_mode_toggle" /> <Switch android:id="@+id/test_logfile_toggle" style="@style/body1" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:layout_weight="1" android:text="Logfile enabled" - android:theme="@style/switchBase" /> + android:theme="@style/switchBase" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/background_notifications_toggle" /> <Button + android:id="@+id/test_logfile_share" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:id="@+id/test_logfile_share" - android:text="Share log" /> - - </LinearLayout> + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Share log" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/test_logfile_toggle" /> + </androidx.constraintlayout.widget.ConstraintLayout> - <TextView - android:id="@+id/label_exposure_summary" - style="@style/headline6" - android:accessibilityHeading="true" + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/environment_container" + style="@style/card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/test_api_exposure_summary_headline" /> + android:layout_margin="@dimen/spacing_tiny"> - <TextView - android:id="@+id/label_exposure_summary_matchedKeyCount" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/test_api_body_matchedKeyCount" /> + <TextView + android:id="@+id/environment_title" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Server environment" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/environment_cdnurl_download" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/environment_title" + tools:text="Download: ?" /> + + <TextView + android:id="@+id/environment_cdnurl_submission" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/environment_cdnurl_download" + tools:text="Submission: ?" /> + + <TextView + android:id="@+id/environment_cdnurl_verification" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/environment_cdnurl_submission" + tools:text="Verification: ?" /> + + <RadioGroup + android:id="@+id/environment_toggle_group" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:orientation="vertical" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/environment_cdnurl_verification" /> + </androidx.constraintlayout.widget.ConstraintLayout> - <TextView - android:id="@+id/label_exposure_summary_daysSinceLastExposure" + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/gms_container" + style="@style/card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/test_api_body_daysSinceLastExposure" /> + android:layout_margin="@dimen/spacing_tiny"> - <TextView - android:id="@+id/label_exposure_summary_maximumRiskScore" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/test_api_body_maximumRiskScore" /> + <TextView + android:id="@+id/gms_container_title" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="GMS Infos" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/google_play_services_version_info" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Google Play Services Version: ?" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/gms_container_title" /> - <TextView - android:id="@+id/label_exposure_summary_summationRiskScore" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/test_api_body_summation_risk" /> + </androidx.constraintlayout.widget.ConstraintLayout> - <TextView - android:id="@+id/label_exposure_summary_attenuation" + <LinearLayout + android:id="@+id/exposure_summary_container" + style="@style/card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/test_api_body_attenuation" /> + android:layout_margin="@dimen/spacing_tiny" + android:orientation="vertical"> - <Button - android:id="@+id/button_api_scan_qr_code" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/test_api_button_scan_qr_code" /> + <TextView + android:id="@+id/label_exposure_summary" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_tiny" + android:text="@string/test_api_exposure_summary_headline" /> - <Button - android:id="@+id/button_api_enter_other_keys" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/test_api_button_enter_other_keys" /> + <TextView + android:id="@+id/label_exposure_summary_matchedKeyCount" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/test_api_body_matchedKeyCount" /> - <Button - android:id="@+id/button_api_get_check_exposure" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/test_api_button_check_exposure" /> + <TextView + android:id="@+id/label_exposure_summary_daysSinceLastExposure" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/test_api_body_daysSinceLastExposure" /> - <TextView - android:id="@+id/label_my_keys" - style="@style/headline6" - android:accessibilityHeading="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/test_api_body_my_keys" /> + <TextView + android:id="@+id/label_exposure_summary_maximumRiskScore" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/test_api_body_maximumRiskScore" /> - <TextView - android:id="@+id/label_latest_key_date" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="Latest key is from: -" /> + <TextView + android:id="@+id/label_exposure_summary_summationRiskScore" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/test_api_body_summation_risk" /> - <TextView - android:id="@+id/text_my_keys" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="Your keys will be displayed here" - android:lines="5" - android:visibility="gone" /> + <TextView + android:id="@+id/label_exposure_summary_attenuation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/test_api_body_attenuation" /> - <androidx.viewpager2.widget.ViewPager2 - android:id="@+id/qr_code_viewpager" - android:layout_width="match_parent" - android:layout_height="200dp" /> + <Button + android:id="@+id/button_api_scan_qr_code" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@string/test_api_button_scan_qr_code" /> - <TextView - android:id="@+id/label_other_keys" - style="@style/headline6" - android:accessibilityHeading="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/test_api_body_other_keys" /> + <Button + android:id="@+id/button_api_enter_other_keys" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/test_api_button_enter_other_keys" /> - <TextView - android:id="@+id/text_scanned_key" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> + <Button + android:id="@+id/button_api_get_check_exposure" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/test_api_button_check_exposure" /> + </LinearLayout> - <Button - android:id="@+id/button_api_test_start" - style="@style/buttonPrimary" + <LinearLayout + android:id="@+id/mykeys_container" + style="@style/card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/test_api_button_start" /> + android:layout_margin="@dimen/spacing_tiny" + android:orientation="vertical"> - <Button - android:id="@+id/button_api_get_exposure_keys" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/test_api_button_get_exposure_keys" /> + <TextView + android:id="@+id/label_my_keys" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_tiny" + android:text="@string/test_api_body_my_keys" /> - <Button - android:id="@+id/button_api_submit_keys" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/test_api_button_submit_keys" /> + <TextView + android:id="@+id/label_latest_key_date" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Latest key is from: -" /> - <Button - android:id="@+id/button_api_share_my_keys" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/test_api_button_share_my_keys" /> + <TextView + android:id="@+id/text_my_keys" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="Your keys will be displayed here" + android:lines="5" + android:visibility="gone" /> + + <androidx.viewpager2.widget.ViewPager2 + android:id="@+id/qr_code_viewpager" + android:layout_width="match_parent" + android:layout_height="200dp" /> + + <TextView + android:id="@+id/label_other_keys" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/test_api_body_other_keys" /> - <Button - android:id="@+id/button_calculate_risk_level" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/test_api_calculate_risk_level" /> + <TextView + android:id="@+id/text_scanned_key" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> - <Button - android:id="@+id/button_insert_exposure_summary" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="Insert ExposureSummary" /> + </LinearLayout> - <Button - android:id="@+id/button_retrieve_exposure_summary" - style="@style/buttonPrimary" + <LinearLayout + android:id="@+id/testactions_container" + style="@style/card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="Retrieve ExposureSummary" /> + android:layout_margin="@dimen/spacing_tiny" + android:orientation="vertical"> - <Button - android:id="@+id/button_clear_db" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="Clear Internal DB" /> + <Button + android:id="@+id/button_api_test_start" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/test_api_button_start" /> - <Button - android:id="@+id/button_tracing_intervals" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="Get Inactive Tracing Intervals" /> + <Button + android:id="@+id/button_api_get_exposure_keys" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/test_api_button_get_exposure_keys" /> - <Button - android:id="@+id/button_tracing_duration_in_retention_period" - style="@style/buttonPrimary" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:layout_marginBottom="@dimen/spacing_normal" - android:text="Get Active Tracing Duration in Retention Period" /> + <Button + android:id="@+id/button_api_submit_keys" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/test_api_button_submit_keys" /> - <TextView - style="@style/headline4" - android:accessibilityHeading="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="headline4" /> + <Button + android:id="@+id/button_api_share_my_keys" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/test_api_button_share_my_keys" /> - <TextView - style="@style/headline5" - android:accessibilityHeading="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="headline5" /> + <Button + android:id="@+id/button_calculate_risk_level" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="@string/test_api_calculate_risk_level" /> - <TextView - style="@style/headline6" - android:accessibilityHeading="true" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="headline6" /> + <Button + android:id="@+id/button_insert_exposure_summary" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Insert ExposureSummary" /> - <TextView - style="@style/subtitle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="subtitle" /> + <Button + android:id="@+id/button_retrieve_exposure_summary" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Retrieve ExposureSummary" /> - <TextView - style="@style/subtitleMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="subtitleMedium" /> + <Button + android:id="@+id/button_clear_db" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Clear Internal DB" /> - <TextView - style="@style/body1" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="body1" /> + <Button + android:id="@+id/button_tracing_intervals" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Get Inactive Tracing Intervals" /> - <TextView - style="@style/body2" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="body2" /> + <Button + android:id="@+id/button_tracing_duration_in_retention_period" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:text="Get Active Tracing Duration in Retention Period" /> + </LinearLayout> - <TextView - style="@style/body2Medium" + <LinearLayout + android:id="@+id/country_container" + style="@style/card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="body2medium" /> + android:layout_margin="@dimen/spacing_tiny" + android:orientation="vertical"> + + <TextView + android:id="@+id/label_country_filter" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Country Settings" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <EditText + android:id="@+id/input_country_codes_editText" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" /> + + <Button + android:id="@+id/button_filter_country_codes" + style="@style/buttonPrimary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Apply" /> + </LinearLayout> + + <TextView + android:id="@+id/label_country_code_filter_status" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Country filter applied for:"> + + </TextView> + + <TextView + android:id="@+id/label_test_api_measure" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="Statistics" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal"> + + <EditText + android:id="@+id/input_measure_risk_key_repeat_count" + android:layout_width="90dp" + android:layout_height="wrap_content" + android:inputType="number" + android:text="1" /> + + <Button + android:id="@+id/button_retrieve_diagnosis_keys_and_calc_risk_level" + style="@style/buttonPrimary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginBottom="@dimen/spacing_normal" + android:layout_weight="1" + android:imeOptions="actionDone" + android:text="Measure: Calculate Risk Level / Key Retrieval" /> + + </LinearLayout> + + <TextView + android:id="@+id/label_test_api_measure_calc_key_status" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Result: " /> - <TextView - style="@style/bodyButton" + </LinearLayout> + + <de.rki.coronawarnapp.ui.calendar.CalendarView + android:id="@+id/calendar_container" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="button" /> + android:layout_height="match_parent" /> + </LinearLayout> - </ScrollView> + </androidx.core.widget.NestedScrollView> </layout> diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_menu.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_menu.xml new file mode 100644 index 0000000000000000000000000000000000000000..32e387a62f941248a3155341818bf9ad30c82d6c --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_menu.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.appcompat.widget.Toolbar + android:id="@+id/toolbar" + style="@style/Widget.AppCompat.Toolbar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="parent" + app:navigationIcon="@drawable/ic_coffee" + app:layout_constraintStart_toStartOf="parent" + app:subtitle="For testers ;)" + app:layout_constraintTop_toTopOf="parent" + app:title="Test Menu" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/test_menu_list" + android:layout_width="match_parent" + android:layout_height="0dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/toolbar" /> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_menu_adapter_item.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_menu_adapter_item.xml new file mode 100644 index 0000000000000000000000000000000000000000..52d7e53e0e39b5f4eea259031d559ecc58373d95 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_menu_adapter_item.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:background="?selectableItemBackground" + android:layout_height="wrap_content" + xmlns:tools="http://schemas.android.com/tools"> + + <ImageView + android:id="@+id/imageView" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + style="@style/MaterialAlertDialog.MaterialComponents.Title.Icon" + android:layout_marginBottom="8dp" + tools:src="@drawable/circle" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:ignore="ContentDescription" /> + + <TextView + android:id="@+id/title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + style="@style/body1" + app:layout_constraintVertical_chainStyle="packed" + android:layout_marginEnd="16dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/imageView" + app:layout_constraintTop_toTopOf="parent" + tools:text="Title" /> + + <TextView + android:id="@+id/description" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp" + style="@style/body2" + android:layout_marginBottom="8dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/imageView" + app:layout_constraintTop_toBottomOf="@+id/title" + tools:text="Description" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml index a2fe370331b0ad99655b6481a915145af3763125..83c27d3f815fa0441cc67307e55cfe81f2e91c5e 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_risk_level_calculation.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:ignore="HardcodedText"> <data> @@ -103,6 +105,14 @@ android:layout_marginTop="@dimen/spacing_normal" android:text="Reset Risk Level" /> + <Button + android:id="@+id/button_clear_diagnosis_key_cache" + style="@style/buttonPrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="Clear Diagnosis-Key cache" /> + <TextView android:id="@+id/label_exposure_summary_title" style="@style/headline6" diff --git a/Corona-Warn-App/src/deviceForTesters/res/menu/menu_main.xml b/Corona-Warn-App/src/deviceForTesters/res/menu/menu_main.xml deleted file mode 100644 index 680f4bd138172b7caab32caba8e1d768f73f43a1..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/deviceForTesters/res/menu/menu_main.xml +++ /dev/null @@ -1,19 +0,0 @@ -<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item - android:id="@+id/menu_help" - android:title="@string/menu_help" /> - <item - android:id="@+id/menu_information" - android:title="@string/menu_information" /> - <item - android:id="@+id/menu_settings" - android:title="@string/menu_settings" /> - - <!-- These are for testing --> - <item - android:id="@+id/menu_test_api" - android:title="@string/menu_test_api" /> - <item - android:id="@+id/menu_test_risk_level" - android:title="@string/menu_test_risk_level" /> -</menu> diff --git a/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml b/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml deleted file mode 100644 index 58d6e0bd796160ee52a7719df0972f20daabb9e5..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/deviceForTesters/res/navigation/nav_graph.xml +++ /dev/null @@ -1,312 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<navigation xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/nav_graph" - app:startDestination="@id/mainFragment"> - - <!-- Main --> - <fragment - android:id="@+id/mainFragment" - android:name="de.rki.coronawarnapp.ui.main.MainFragment" - android:label="MainFragment" - tools:layout="@layout/fragment_main"> - <action - android:id="@+id/action_mainFragment_to_settingsTracingFragment" - app:destination="@id/settingsTracingFragment" /> - <action - android:id="@+id/action_mainFragment_to_riskDetailsFragment" - app:destination="@id/riskDetailsFragment" /> - <action - android:id="@+id/action_mainFragment_to_settingsFragment" - app:destination="@id/settingsFragment" /> - <action - android:id="@+id/action_mainFragment_to_testForAPIFragment" - app:destination="@id/testForAPIFragment" /> - <action - android:id="@+id/action_mainFragment_to_informationFragment" - app:destination="@id/informationFragment" /> - <action - android:id="@+id/action_mainFragment_to_mainSharingFragment" - app:destination="@id/mainSharingFragment" /> - <action - android:id="@+id/action_mainFragment_to_submissionIntroFragment" - app:destination="@id/submissionIntroFragment" /> - <action - android:id="@+id/action_mainFragment_to_submissionResultFragment" - app:destination="@id/submissionResultFragment" /> - <action - android:id="@+id/action_mainFragment_to_submissionDoneFragment" - app:destination="@id/submissionDoneFragment" /> - <action - android:id="@+id/action_mainFragment_to_mainOverviewFragment" - app:destination="@id/mainOverviewFragment" /> - <action - android:id="@+id/action_mainFragment_to_testRiskLevelCalculation" - app:destination="@id/testRiskLevelCalculation" /> - </fragment> - - <fragment - android:id="@+id/mainSharingFragment" - android:name="de.rki.coronawarnapp.ui.main.MainShareFragment" - android:label="@layout/fragment_main_share" - tools:layout="@layout/fragment_main_share" /> - - <fragment - android:id="@+id/mainOverviewFragment" - android:name="de.rki.coronawarnapp.ui.main.MainOverviewFragment" - android:label="@layout/fragment_main_overview" - tools:layout="@layout/fragment_main_overview" /> - - <!-- Settings --> - <fragment - android:id="@+id/settingsFragment" - android:name="de.rki.coronawarnapp.ui.settings.SettingsFragment" - android:label="@layout/fragment_settings" - tools:layout="@layout/fragment_settings"> - <action - android:id="@+id/action_settingsFragment_to_settingsResetFragment" - app:destination="@id/settingsResetFragment" /> - <action - android:id="@+id/action_settingsFragment_to_settingsTracingFragment" - app:destination="@id/settingsTracingFragment" /> - <action - android:id="@+id/action_settingsFragment_self" - app:destination="@id/settingsFragment" /> - <action - android:id="@+id/action_settingsFragment_to_settingsNotificationFragment" - app:destination="@id/settingsNotificationFragment" /> - <action - android:id="@+id/action_settingsFragment_to_settingsBackgroundPriorityFragment" - app:destination="@id/settingsBackgroundPriorityFragment" /> - </fragment> - - <fragment - android:id="@+id/settingsTracingFragment" - android:name="de.rki.coronawarnapp.ui.settings.SettingsTracingFragment" - android:label="@layout/fragment_settings_tracing" - tools:layout="@layout/fragment_settings_tracing" /> - - <fragment - android:id="@+id/settingsNotificationFragment" - android:name="de.rki.coronawarnapp.ui.settings.SettingsNotificationFragment" - android:label="SettingsNotificationFragment" - tools:layout="@layout/fragment_settings_notifications" /> - - <fragment - android:id="@+id/settingsBackgroundPriorityFragment" - android:name="de.rki.coronawarnapp.ui.settings.SettingsBackgroundPriorityFragment" - android:label="SettingsBackgroundPriorityFragment" - tools:layout="@layout/fragment_settings_background_priority" /> - - <fragment - android:id="@+id/settingsResetFragment" - android:name="de.rki.coronawarnapp.ui.settings.SettingsResetFragment" - android:label="@layout/fragment_settings_reset" - tools:layout="@layout/fragment_settings_reset"> - <action - android:id="@+id/action_settingsResetFragment_to_mainFragment" - app:destination="@id/mainFragment" /> - </fragment> - - <!-- Information --> - <fragment - android:id="@+id/informationFragment" - android:name="de.rki.coronawarnapp.ui.information.InformationFragment" - android:label="@layout/fragment_information" - tools:layout="@layout/fragment_information"> - <action - android:id="@+id/action_informationFragment_to_informationLegalFragment" - app:destination="@id/informationLegalFragment" /> - <action - android:id="@+id/action_informationFragment_to_informationTermsFragment" - app:destination="@id/informationTermsFragment" /> - <action - android:id="@+id/action_informationFragment_to_informationPrivacyFragment" - app:destination="@id/informationPrivacyFragment" /> - <action - android:id="@+id/action_informationFragment_to_informationAboutFragment" - app:destination="@id/informationAboutFragment" /> - <action - android:id="@+id/action_informationFragment_to_informationContactFragment" - app:destination="@id/informationContactFragment" /> - <action - android:id="@+id/action_informationFragment_to_informationTechnicalFragment" - app:destination="@id/informationTechnicalFragment" /> - </fragment> - - <fragment - android:id="@+id/informationAboutFragment" - android:name="de.rki.coronawarnapp.ui.information.InformationAboutFragment" - android:label="@layout/fragment_information_about" - tools:layout="@layout/fragment_information_about" /> - - <fragment - android:id="@+id/informationPrivacyFragment" - android:name="de.rki.coronawarnapp.ui.information.InformationPrivacyFragment" - android:label="@layout/fragment_information_privacy" - tools:layout="@layout/fragment_information_privacy" /> - - <fragment - android:id="@+id/informationTermsFragment" - android:name="de.rki.coronawarnapp.ui.information.InformationTermsFragment" - android:label="@layout/fragment_information_terms" - tools:layout="@layout/fragment_information_terms" /> - - <fragment - android:id="@+id/informationContactFragment" - android:name="de.rki.coronawarnapp.ui.information.InformationContactFragment" - android:label="@layout/fragment_information_contact" - tools:layout="@layout/fragment_information_contact" /> - - <fragment - android:id="@+id/informationLegalFragment" - android:name="de.rki.coronawarnapp.ui.information.InformationLegalFragment" - android:label="@layout/fragment_information_legal" - tools:layout="@layout/fragment_information_legal" /> - - <fragment - android:id="@+id/informationTechnicalFragment" - android:name="de.rki.coronawarnapp.ui.information.InformationTechnicalFragment" - android:label="InformationTechnicalFragment" - tools:layout="@layout/fragment_information_technical" /> - - <!-- Submission --> - <fragment - android:id="@+id/testForAPIFragment" - android:name="de.rki.coronawarnapp.TestForAPIFragment" - android:label="@layout/fragment_test_for_a_p_i" - tools:layout="@layout/fragment_test_for_a_p_i" /> - - <fragment - android:id="@+id/riskDetailsFragment" - android:name="de.rki.coronawarnapp.ui.riskdetails.RiskDetailsFragment" - android:label="@layout/fragment_risk_details" - tools:layout="@layout/fragment_risk_details"> - <action - android:id="@+id/action_riskDetailsFragment_to_settingsTracingFragment" - app:destination="@id/settingsTracingFragment" /> - </fragment> - - <fragment - android:id="@+id/submissionDispatcherFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionDispatcherFragment" - android:label="fragment_submission_dispatcher" - tools:layout="@layout/fragment_submission_dispatcher"> - <action - android:id="@+id/action_submissionDispatcherFragment_to_submissionTanFragment" - app:destination="@id/submissionTanFragment" /> - <action - android:id="@+id/action_submissionDispatcherFragment_to_submissionQRCodeScanFragment" - app:destination="@id/submissionQRCodeScanFragment" /> - <action - android:id="@+id/action_submissionDispatcherFragment_to_submissionContactFragment" - app:destination="@id/submissionContactFragment" /> - </fragment> - <fragment - android:id="@+id/submissionResultPositiveOtherWarningFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionResultPositiveOtherWarningFragment" - android:label="fragment_submission_result_positive_other_warning" - tools:layout="@layout/fragment_submission_positive_other_warning"> - <action - android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionResultFragment" - app:destination="@id/submissionResultFragment" - app:popUpTo="@id/submissionResultFragment" - app:popUpToInclusive="true" /> - <action - android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionDoneFragment" - app:destination="@id/submissionDoneFragment" - app:popUpTo="@id/submissionDoneFragment" - app:popUpToInclusive="true" /> - </fragment> - <fragment - android:id="@+id/submissionResultFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionTestResultFragment" - android:label="fragment_submission_result" - tools:layout="@layout/fragment_submission_test_result"> - <action - android:id="@+id/action_submissionResultFragment_to_mainFragment" - app:destination="@id/mainFragment" - app:popUpTo="@id/mainFragment" - app:popUpToInclusive="true" /> - <action - android:id="@+id/action_submissionResultFragment_to_submissionResultPositiveOtherWarningFragment" - app:destination="@id/submissionResultPositiveOtherWarningFragment" /> - </fragment> - - <fragment - android:id="@+id/submissionTanFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionTanFragment" - android:label="fragment_submission_tan" - tools:layout="@layout/fragment_submission_tan"> - <action - android:id="@+id/action_submissionTanFragment_to_submissionDispatcherFragment" - app:destination="@id/submissionDispatcherFragment" - app:popUpTo="@id/submissionDispatcherFragment" - app:popUpToInclusive="true" /> - <action - android:id="@+id/action_submissionTanFragment_to_submissionResultFragment" - app:destination="@id/submissionResultFragment" - app:popUpTo="@id/submissionResultFragment" - app:popUpToInclusive="true" /> - </fragment> - - <fragment - android:id="@+id/submissionIntroFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionIntroFragment" - android:label="SubmissionIntroFragment"> - <action - android:id="@+id/action_submissionIntroFragment_to_mainFragment" - app:destination="@id/mainFragment" - app:popUpTo="@+id/mainFragment" - app:popUpToInclusive="true" /> - <action - android:id="@+id/action_submissionIntroFragment_to_submissionDispatcherFragment" - app:destination="@id/submissionDispatcherFragment" /> - </fragment> - <activity - android:id="@+id/launcherActivity" - android:name="de.rki.coronawarnapp.ui.LauncherActivity" - android:label="LauncherActivity"> - <deepLink - android:id="@+id/deepLink" - app:uri="coronawarnapp://launch" /> - </activity> - <fragment - android:id="@+id/submissionQRCodeScanFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionQRCodeScanFragment" - android:label="SubmissionQRCodeScanFragment"> - <action - android:id="@+id/action_submissionQRCodeScanFragment_to_submissionDispatcherFragment" - app:destination="@id/submissionDispatcherFragment" - app:popUpTo="@id/submissionDispatcherFragment" - app:popUpToInclusive="true" /> - <action - android:id="@+id/action_submissionQRCodeScanFragment_to_submissionResultFragment" - app:destination="@id/submissionResultFragment" - app:popUpTo="@id/submissionResultFragment" /> - </fragment> - <fragment - android:id="@+id/submissionDoneFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionDoneFragment" - android:label="SubmissionDoneFragment"> - <action - android:id="@+id/action_submissionDoneFragment_to_mainFragment" - app:destination="@id/mainFragment" - app:popUpTo="@id/mainFragment" - app:popUpToInclusive="true" /> - </fragment> - <fragment - android:id="@+id/submissionContactFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionContactFragment" - android:label="SubmissionContactFragment"> - <action - android:id="@+id/action_submissionContactFragment_to_submissionTanFragment" - app:destination="@id/submissionTanFragment" /> - </fragment> - <fragment - android:id="@+id/testRiskLevelCalculation" - android:name="de.rki.coronawarnapp.TestRiskLevelCalculation" - android:label="fragment_test_risk_level_calculation" - tools:layout="@layout/fragment_test_risk_level_calculation" /> -</navigation> diff --git a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml new file mode 100644 index 0000000000000000000000000000000000000000..f4e587edd02f7688d7ef6b78a1793a60cabfcc33 --- /dev/null +++ b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<navigation xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/test_nav_graph" + app:startDestination="@id/test_menu_fragment"> + + <fragment + android:id="@+id/test_menu_fragment" + android:name="de.rki.coronawarnapp.test.menu.ui.TestMenuFragment" + android:label="TestMenuFragment"> + <action + android:id="@+id/action_testMenuFragment_to_testForAPIFragment" + app:destination="@id/test_for_api_fragment" /> + <action + android:id="@+id/action_testMenuFragment_to_testRiskLevelCalculation" + app:destination="@id/test_risklevel_calculation_fragment" /> + </fragment> + + <fragment + android:id="@+id/test_for_api_fragment" + android:name="de.rki.coronawarnapp.test.api.ui.TestForAPIFragment" + android:label="@layout/fragment_test_for_a_p_i" + tools:layout="@layout/fragment_test_for_a_p_i" /> + + <fragment + android:id="@+id/test_risklevel_calculation_fragment" + android:name="de.rki.coronawarnapp.test.risklevel.ui.TestRiskLevelCalculationFragment" + android:label="fragment_test_risk_level_calculation" + tools:layout="@layout/fragment_test_risk_level_calculation"> + <argument + android:name="exampleArgument" + app:argType="string" + android:defaultValue="null" + app:nullable="true" /> + </fragment> + +</navigation> diff --git a/Corona-Warn-App/src/main/assets/privacy_de.html b/Corona-Warn-App/src/main/assets/privacy_de.html index 544c54fcf9ecfa0faa8246607f41d56821067916..ef95dc99ffd7ded32261d06b2f8ccba4283c5686 100644 --- a/Corona-Warn-App/src/main/assets/privacy_de.html +++ b/Corona-Warn-App/src/main/assets/privacy_de.html @@ -2,331 +2,342 @@ Datenschutzerklärung </p> <p> - Corona-Warn-App + In dieser Datenschutzerklärung erfahren Sie, wie Ihre Daten verarbeitet + werden und welche Datenschutzrechte Sie haben, wenn Sie die offizielle + Corona-Warn-App der deutschen Bundesregierung nutzen. </p> <p> - In dieser Datenschutzerklärung erfahren Sie, welche Daten bei der Nutzung - der Corona-Warn-App erhoben werden, wie sie verwendet werden und welche - Datenschutzrechte Sie haben. + Folgende Themen werden behandelt: </p> <p> - Damit diese Datenschutzerklärung für alle Nutzer verständlich ist, bemühen - wir uns um eine einfache und möglichst untechnische Darstellung. + <strong>1. Wer ist Herausgeber der Corona-Warn-App?</strong> </p> -<h2> - 1. Wer stellt Ihnen diese App zur Verfügung? -</h2> <p> - Der Anbieter der Corona-Warn-App (im Folgenden die „<strong>App</strong>“) - ist das Robert Koch-Institut, Nordufer 20, 13353 Berlin (im Folgenden „<strong>RKI</strong>“). + <strong>2. Ist die Nutzung der App freiwillig?</strong> </p> <p> - Das RKI ist auch der datenschutzrechtlich Verantwortliche für die - Verarbeitung von personenbezogenen Daten der App-Nutzer. + <strong> + Auf welcher Rechtsgrundlage werden Ihre Daten verarbeitet? + </strong> </p> <p> - Den Datenschutzbeauftragten des RKI erreichen Sie unter der oben genannten - Anschrift (zu Händen „Behördlicher Datenschutzbeauftragter“) und per E-Mail - an: datenschutz@rki.de). + <strong>4. An wen richtet sich die App?</strong> </p> -<h2> - 2. Ist die Nutzung der App freiwillig? -</h2> <p> - Die Benutzung der App basiert ausschließlich auf Freiwilligkeit. Es ist - daher allein Ihre Entscheidung, ob und wie Sie die App nutzen. + <strong>5. Welche Daten werden verarbeitet?</strong> </p> <p> - Auch wenn die Installation und die Benutzung der App freiwillig sind, - müssen Sie nach dem erstmaligen Aufruf der App gegenüber dem RKI durch - Antippen des Buttons „Risiko-Ermittlung aktivieren“ zustimmen, dass die App - im Rahmen der Risiko-Ermittlung Ihre personenbezogenen Daten verarbeiten - darf. Falls die App dabei ein Infektionsrisiko für Sie ermittelt, stellen - Ihre Daten auch Gesundheitsdaten dar. Ihre Zustimmung ist erforderlich, da - andernfalls die App nicht auf die Kontaktaufzeichnungs-Funktion Ihres - Smartphones zugreifen kann. Sie können die Risiko-Ermittlung jedoch - jederzeit über den Schieberegler innerhalb der App deaktivieren. In diesem - Fall stehen Ihnen nicht alle Funktionen der App zur Verfügung. Gesonderte - Einwilligungen sind darüber hinaus für die Datenverarbeitung der folgenden - Funktionen erforderlich: + <strong>6. Wofür werden Ihre Daten verarbeitet?</strong> </p> -<ul> - <li> - Test registrieren (siehe Ziffer 6 b.) - </li> - <li> - Testergebnis teilen (siehe Ziffer 6 c.) - </li> -</ul> <p> - Die Datenverarbeitung im Rahmen dieser Funktionen wird in den folgenden - Abschnitten näher beschrieben. + <strong>7. Wie funktioniert das länderübergreifende Warnsystem?</strong> </p> -<h2> +<p> + <strong>8. Welche Berechtigungen benötigt die App?</strong> +</p> +<p> + <strong>9. Wann werden Ihre Daten gelöscht?</strong> +</p> +<p> + <strong>10. An wen werden Ihre Daten weitergegeben?</strong> +</p> +<p> + <strong>11. Werden Ihre Daten in Länder außerhalb der EU übermittelt?</strong> +</p> +<p> + <strong>12. Wie können Sie Ihre Einwilligungen widerrufen?</strong> +</p> +<p> + <strong>13. Welche weiteren Datenschutzrechte haben Sie?</strong> +</p> +<p> + <strong>14. Datenschutzbeauftragter und Kontakt</strong> +</p> +<p> + Damit dieser Text für alle Nutzer verständlich ist, bemühen wir uns um eine + einfache und möglichst untechnische Darstellung. +</p> +<h1> + 1. Wer ist Herausgeber der Corona-Warn-App? +</h1> +<p> + Diese App wird vom Robert Koch-Institut (<strong>RKI</strong>) für die + deutsche Bundesregierung herausgegeben. Das RKI ist auch dafür + verantwortlich, dass Ihre Daten in Ãœbereinstimmung mit den Vorschriften + über den Datenschutz verarbeitet werden. +</p> +<p> + Wenn Sie sich infiziert haben und freiwillig eine länderübergreifende + Warnung auslösen, können auch die Nutzer der offiziellen Corona-Apps + anderer teilnehmender Länder, mit denen Sie Kontakt hatten, gewarnt werden. + In diesem Fall sind das RKI und die zuständigen Gesundheitsbehörden der am + länderübergreifenden Warnsystem teilnehmenden Länder für die + Datenverarbeitung gemeinsam verantwortlich. Einzelheiten erfahren Sie unter + Punkt 7. +</p> +<h1> + 2. Ist die Nutzung der App freiwillig? +</h1> +<p> + Die Nutzung der App ist freiwillig. Es ist allein Ihre Entscheidung, ob Sie + die App installieren, welche App-Funktionen Sie nutzen und ob Sie Daten mit + anderen teilen. Alle App-Funktionen, die eine Datenweitergabe erfordern, + holen vorher Ihre ausdrückliche Einwilligung ein. Falls Sie eine + Einwilligung nicht erteilen oder nachträglich widerrufen, entstehen Ihnen + keine Nachteile. +</p> +<h1> 3. Auf welcher Rechtsgrundlage werden Ihre Daten verarbeitet? -</h2> +</h1> <p> - Das RKI verarbeitet Ihre personenbezogenen Daten grundsätzlich nur auf - Grundlage einer von Ihnen erteilten Einwilligung nach Artikel 6 Absatz 1 - Satz 1 Buchstabe a und Artikel 9 Absatz 2 Buchstabe a der - Datenschutzgrundverordnung (DSGVO). Sie können eine von Ihnen erteilte - Einwilligung jederzeit widerrufen. Weitere Informationen zu Ihrem - Widerrufsrecht und Hinweise, wie Sie dieses ausüben können, finden Sie - unter Ziffer 11. + Ihre Daten werden grundsätzlich nur auf Grundlage einer von Ihnen erteilten + ausdrücklichen Einwilligung verarbeitet. Die Rechtsgrundlage ist Art. 6 + Abs. 1 S. 1 lit. a DSGVO sowie im Falle von Gesundheitsdaten Art. 9 Abs. 2 + lit. a DSGVO. Sie können eine erteilte Einwilligung jederzeit widerrufen. + Weitere Informationen zu Ihrem Widerrufsrecht finden Sie unter Punkt 12. </p> -<h2> +<h1> 4. An wen richtet sich die App? -</h2> +</h1> <p> Die App richtet sich an Personen, die sich in Deutschland aufhalten und mindestens 16 Jahre alt sind. </p> -<h2> - 5. Welche personenbezogenen Daten werden verarbeitet? -</h2> +<h1> + 5. Welche Daten werden verarbeitet? +</h1> <p> - Die App ist so konzipiert, dass so wenig personenbezogene Daten wie möglich - verarbeitet werden. Das bedeutet zum Beispiel, dass die App keine Daten - erfasst, die es dem RKI oder anderen Nutzern ermöglichen, auf Ihre - Identität, Ihren Gesundheitsstatus oder Ihren Standort zu schließen. Zudem - verzichtet die App bewusst auf jegliche Erfassung oder Analyse Ihres - Nutzungsverhaltens durch Tracking-Tools. + Die App ist so programmiert, dass so wenig personenbezogene Daten wie + möglich verarbeitet werden. Das bedeutet, dass die App keine Daten erfasst, + die es dem RKI oder anderen Nutzern ermöglichen, auf Ihre Identität, Ihren + Namen, Ihren Standort oder andere persönliche Details zu schließen. Die App + verzichtet daher auch auf jegliche Auswertung Ihres Nutzungsverhaltens + durch Analyse-Tools. </p> <p> Die von der App verarbeiteten Daten lassen sich den folgenden Kategorien zuordnen: </p> +<h2> + a. Zugriffsdaten +</h2> <p> - <strong>a. Zugriffsdaten</strong> -</p> -<p> - Zugriffsdaten fallen an, wenn Sie die folgenden Funktionen nutzen bzw. - aktivieren: + Bei jedem Internet-Datenaustausch der App mit dem Serversystem des RKI (im + Folgenden: <strong>Serversystem</strong>) werden vom Serversystem + sogenannte Zugriffsdaten verarbeitet. Dies ist erforderlich, damit die App + aktuelle Daten (z. B. für Warnungen) abrufen oder bestimmte auf dem + Smartphone gespeicherte Daten an das Serversystem übermitteln kann. Die + Zugriffsdaten umfassen folgende Daten: </p> <ul> <li> - Risiko-Ermittlung + IP-Adresse </li> <li> - Test registrieren + Datum und Uhrzeit des Abrufs </li> <li> - Testergebnis teilen + übertragene Datenmenge (bzw. Paketlänge) + </li> + <li> + Meldung, ob der Datenaustausch erfolgreich war </li> </ul> <p> - Bei jedem Abruf von Daten vom Serversystem der App wird Ihre IP-Adresse - (auf dem vorgelagerten Load Balancer) maskiert und im Weiteren nicht mehr - innerhalb des Serversystems der App verarbeitet. + Diese Zugriffsdaten werden verarbeitet, um den technischen Betrieb der App + und des Serversystems aufrechtzuerhalten und abzusichern. Sie werden dabei + nicht als Nutzer der App persönlich identifiziert und es wird kein + Nutzungsprofil erstellt. Eine Speicherung der IP-Adresse über das Ende des + Nutzungsvorgangs hinaus erfolgt nicht. </p> <p> - Zusätzlich werden folgende Daten verarbeitet: + Um eine unbefugte Zuordnung Ihrer Daten anhand Ihrer IP-Adresse schon + während eines Nutzungsvorgangs zu verhindern, greift die App nur über einen + speziellen Eingangsserver auf das Serversystem zu. Der Eingangsserver + leitet die von der App angeforderten oder übermittelten Daten dann ohne die + IP-Adresse an den jeweils zuständigen Server weiter, so dass die IP-Adresse + innerhalb des Serversystems nicht verarbeitet wird. +</p> +<h2> + b. Begegnungsdaten +</h2> +<p> + Sobald Sie das COVID-19-Benachrichtigungssystem Ihres iPhones (dort + „Begegnungsmitteilungen“ genannt) oder Ihres Android-Smartphones (dort + „COVID-19-Benachrichtigungen“ genannt) aktivieren, sendet Ihr Smartphone + per Bluetooth sogenannte Begegnungsdaten aus, die von anderen Smartphones + in Ihrer Nähe aufgezeichnet werden können. Umgekehrt empfängt Ihr + Smartphone auch die Begegnungsdaten von anderen Smartphones. Die + ausgesendeten Begegnungsdaten umfassen: </p> <ul> <li> - Datum und Uhrzeit des Abrufs (Zeitstempel) + zufällige Kennnummern (im Folgenden: <strong>Zufalls-IDs</strong>) </li> <li> - übertragene Datenmenge (bzw. Paketlänge) + Bluetooth-Protokollversion </li> <li> - Meldung über erfolgreichen Abruf + Bluetooth-Sendeleistung in Dezibel Milliwatt (dBm) </li> </ul> <p> - Diese Zugriffsdaten werden nur zur Sicherung und Aufrechterhaltung der - technischen Infrastruktur verarbeitet. Sie werden dabei nicht als Nutzer - der App persönlich identifiziert und es kann kein Nutzungsprofil erstellt - werden. Eine Speicherung der IP-Adresse über das Ende des Nutzungsvorgangs - hinaus erfolgt nicht. -</p> -<p> - <strong>b. Begegnungsdaten</strong> -</p> -<p> - Wenn Sie auf Ihrem Smartphone die betriebssystemseitige Funktion zur - Aufzeichnung von Kontakten zu anderen Nutzern aktivieren, versendet Ihr - Smartphone per Bluetooth Low Energy kontinuierlich zufallsgenerierte - Kennnummern, auch als Zufallscodes zu bezeichnet (im Folgenden: „<strong>Zufalls-IDs“</strong>), - die von anderen Smartphones in Ihrer Nähe - mit ebenfalls aktivierter Kontaktaufzeichnung empfangen werden können. - Umgekehrt empfängt Ihr Smartphone auch die Zufalls-IDs der anderen - Smartphones. Zu den von anderen Smartphones empfangenen Zufalls-IDs werden - von der Kontaktaufzeichnungs-Funktion Ihres Smartphones zusätzlich folgende - Begegnungsdaten aufgezeichnet und gespeichert: + Bei aufgezeichneten Begegnungen umfassen die Begegnungsdaten zusätzlich: </p> <ul> <li> - Datum und Zeitpunkt des Kontakts + Tag, Zeitpunkt und Dauer der Begegnung </li> <li> - Dauer des Kontakts + Bluetooth-Empfangsstärke in dBm </li> +</ul> +<p> + Die Zufalls-IDs werden regelmäßig geändert. Dies trägt dazu bei, dass Ihr + Smartphone nicht über diese Zufalls-IDs identifiziert werden kann. Die von + Ihrem Smartphone ausgesendeten eigenen Begegnungsdaten und die + aufgezeichneten Begegnungsdaten der Personen, mit denen Sie Kontakt hatten, + werden auf Ihrem Smartphone gespeichert und jeweils nach 14 Tage gelöscht. + Auf die gleiche Weise werden Ihre ausgesendeten Begegnungsdaten + verarbeitet, wenn sie von den Smartphones anderer App-Nutzer aufgezeichnet + werden. +</p> +<p> + Bitte beachten Sie: Das COVID-19-Benachrichtigungssystem ist eine Funktion + Ihres Betriebssystems. Anbieter und Verantwortliche für dieses System sind + daher Apple (wenn Sie ein iPhone haben) und Google (wenn Sie ein + Android-Smartphone haben). Insoweit unterliegt die Datenverarbeitung den + Datenschutzbestimmungen dieser Unternehmen und liegt außerhalb des + Verantwortungs- und Einflussbereichs des RKI. Die tatsächlichen + Bezeichnungen, Bedienschritte und Einstellmöglichkeiten können je nach + Version und Einstellung Ihres Betriebssystems von der Darstellung in dieser + Datenschutzerklärung abweichen. Weitere Informationen stellen Ihnen die + jeweiligen Hersteller zur Verfügung: +</p> +<ul> <li> - Bluetooth-Signalstärke des Kontakts + Informationen von Google für Android-Smartphones finden Sie auf Ihrem + Gerät unter „Einstellungen“ > Google > + COVID-19-Benachrichtigungen unter dem Link „Weitere Informationen“ </li> <li> - Verschlüsselte Metadaten (Protokollversion und Sendestärke). + Informationen von Apple für iPhones finden Sie auf Ihrem Gerät unter + „Einstellungen“ > "Begegnungsmitteilungen“ unter dem Link „So + funktionieren Begegnungsmitteilungen …“. </li> </ul> -<p> - Die eigenen und von anderen Smartphones empfangenen Zufalls-IDs und die - weiteren Begegnungsdaten (Datum und Zeitpunkt des Kontakts, Dauer des - Kontakts, Signalstärke des Kontakts und verschlüsselte Metadaten) werden - von Ihrem Smartphone in einem Kontaktprotokoll der - Kontaktaufzeichnungs-Funktion erfasst und dort zurzeit für 14 Tage - gespeichert. -</p> -<p> - Die Kontaktaufzeichnungs-Funktion heißt bei Android-Smartphones - "Benachrichtigungen zu möglicher Begegnung mit Infizierten" und bei iPhones - „COVID-19-Kontaktprotokoll“. Wir weisen Sie darauf hin, dass diese - Kontaktaufzeichnungs-Funktionen kein Bestandteil der App, sondern ein - integraler Bestandteil des Betriebssystems Ihres Smartphones sind. Die - Kontaktaufzeichnungs-Funktion wird Ihnen daher von Apple (iPhones) bzw. - Google (Android-Smartphones) bereitgestellt und unterliegt dementsprechend - den Datenschutzbestimmungen dieser Unternehmen. Die betriebssystemseitige - Datenverarbeitung im Rahmen der Kontaktaufzeichnungs-Funktion liegt - außerhalb des Einflussbereichs des RKI. -</p> -<p> - Weitere Informationen zu der Kontaktaufzeichnungs-Funktion von - Android-Smartphones finden Sie unter: - https://support.google.com/android/answer/9888358?hl=de. -</p> -<p> - Weitere Informationen zu der Kontaktaufzeichnungs-Funktion von Apple finden - Sie in den Einstellungen Ihres iPhones unter "Datenschutz“ > „Health" - > „COVID-19-Kontaktprotokoll“. Bitte beachten Sie: Die - Kontaktaufzeichnungs-Funktion steht Ihnen nur zur Verfügung, wenn auf Ihrem - iPhone das Betriebssystem iOS ab Version 13.5 installiert ist. -</p> -<p> - Die vom Smartphone erzeugten und gespeicherten Begegnungsdaten werden von - der App nur verarbeitet, wenn die Risiko-Ermittlung aktiviert ist. -</p> -<h3> - a. Gesundheitsdaten -</h3> +<h2> + c. Gesundheitsdaten +</h2> <p> Gesundheitsdaten sind alle Daten, die Informationen zum Gesundheitszustand - einer bestimmten Person enthalten. Dazu gehören nicht nur Angaben zu - früheren und aktuellen Krankheiten, sondern auch zu Krankheitsrisiken einer - Person (z. B. das Risiko, dass eine Person sich mit dem Corona-Virus - infiziert hat). -</p> -<p> - In den folgenden Fällen handelt es sich um eine Verarbeitung von - Gesundheitsdaten: + einer Person enthalten. Dazu gehören nicht nur Angaben zu früheren und + aktuellen Krankheiten, sondern auch zu Krankheitsrisiken einer Person (z. + B. das Risiko, dass eine Person sich mit dem Coronavirus infiziert hat). + Die App verarbeitet Gesundheitsdaten in folgenden Fällen: </p> <ul> <li> - Wenn die Risiko-Ermittlung erkennt, dass Sie möglicherweise Kontakt zu - einer Person hatten, die sich mit dem Corona-Virus infiziert hat. + wenn eine Risiko-Begegnung erkannt wird </li> <li> - Wenn Sie einen Test registrieren. + wenn Sie einen Test oder einen positiven Befundbrief registrieren </li> <li> - Wenn Sie ein positives Testergebnis teilen. + wenn Sie in der App ein positives Testergebnis abrufen + </li> + <li> + wenn Sie Ihre Begegnungen über die App vor einer möglichen Infektion + warnen + </li> + <li> + wenn Sie Angaben zum Beginn von eventuellen Corona-Symptomen machen </li> </ul> +<p> + Die Einzelheiten werden unter Punkt 6 erläutert. +</p> +<h1> + 6. Wofür werden Ihre Daten verarbeitet? +</h1> <h2> - 6. Funktionen der App -</h2> -<h3> a. Risiko-Ermittlung -</h3> -<p> - Die Risiko-Ermittlung ist die Kernfunktion der App. Sie dient dazu, - mögliche Kontakte zu mit dem Corona-Virus infizierten anderen Nutzern der - App nachzuverfolgen, das infolge für Sie bestehende Infektionsrisiko zu - bewerten und Ihnen, basierend auf dem für Sie ermittelten Risikowert, - Verhaltens- und Gesundheitshinweise bereitzustellen. -</p> -<p> - Wenn Sie die Risiko-Ermittlung aktivieren, ruft die App von den - Serversystemen der App im Hintergrundbetrieb mehrmals täglich (oder wenn - Sie auf „Aktualisieren“ tippen) eine Liste mit Zufalls-IDs von Nutzern ab, - die positiv getestet wurden und Ihre eigenen Zufalls-IDs geteilt haben. Die - App gibt die Zufalls-IDs an die Kontaktaufzeichnungs-Funktion Ihres - Smartphones weiter, welche diese dann mit den im Kontaktprotokoll Ihres - Smartphones gespeicherten Zufalls-IDs abgleicht. Wenn die - Kontaktaufzeichnungs-Funktion Ihres Smartphones eine Ãœbereinstimmung - feststellt, übergibt sie der App die Begegnungsdaten (Datum, Dauer, - Signalstärke), nicht jedoch die Zufalls-ID des betreffenden Kontakts. -</p> -<p> - Im Fall eines Kontakts werden die von der Kontaktaufzeichnungs-Funktion - übergebenen Begegnungsdaten von der App analysiert, um Ihr individuelles - Infektionsrisiko zu ermitteln. Der Bewertungsalgorithmus, der festlegt, wie - die Begegnungsdaten interpretiert werden (z. B. welchen Einfluss die Dauer - eines Kontakts auf das Infektionsrisiko hat) basiert auf den aktuellen - wissenschaftlichen Erkenntnissen. Bei neuen Erkenntnissen kann der - Bewertungsalgorithmus daher durch das RKI aktualisiert werden, indem die - Einstellungen für den Bewertungsalgorithmus neu gesetzt werden. Die - Einstellungen für den Bewertungsalgorithmus werden dann zusammen mit der - Liste der Zufalls-IDs infizierter Personen an die App übermittelt. -</p> -<p> - Die Ermittlung des Infektionsrisikos findet ausschließlich lokal auf Ihrem - Smartphone statt, das heißt die Daten werden offline verarbeitet. Das - ermittelte Infektionsrisiko wird ebenfalls ausschließlich in der App - gespeichert und an keine anderen Empfänger (auch nicht an das RKI, Apple, - Google und sonstige Dritte) weitergegeben. -</p> -<p> - Rechtsgrundlage der oben beschriebenen Verarbeitung Ihrer Zugriffsdaten, - Begegnungsdaten und ggf. Gesundheitsdaten (sofern für Sie ein - Infektionsrisiko ermittelt wird) ist Ihre Einwilligung, die Sie bei der - Aktivierung der Risiko-Ermittlung erteilt haben. -</p> -<h3> - b. Test registrieren -</h3> +</h2> <p> - Wenn Sie auf eine Infektion mit dem Corona-Virus getestet wurden, können - Sie den Test in der App registrieren, indem Sie den QR-Code, den Sie von - Ihrem Arzt bzw. der Testeinrichtung erhalten haben, in der App einscannen. - Die App informiert Sie dann, sobald das Testergebnis des Labors vorliegt. + Die Risiko-Ermittlung ist eine Hauptfunktion der App. Sie dient dazu, Sie + bei möglichen Kontakten mit Corona-positiv getesteten Personen + (Risiko-Begegnungen) länderübergreifend zu warnen, das für Sie bestehende + Infektionsrisiko zu bewerten und Ihnen entsprechende Verhaltens- und + Gesundheitshinweise zu geben. +</p> +<p> + Hierzu ruft die App im Hintergrundbetrieb vom Serversystem täglich eine + aktuelle Liste mit den Zufalls-IDs und eventuellen Angaben zum + Symptombeginn von Nutzern ab, die Corona-positiv getestet wurden und + freiwillig über die offizielle Corona-App eines am länderübergreifenden + Warnsystem teilnehmenden Landes (siehe hierzu Punkt 7) eine Warnung + ausgelöst haben (im Folgenden: <strong>Positiv-Liste</strong>). Die + Zufalls-IDs in der Positiv-Liste enthalten zusätzlich einen + Ãœbertragungsrisiko-Wert und eine Angabe zur Art der Diagnose (siehe hierzu + Punkt 6 c.). +</p> +<p> + Die App gibt die Zufalls-IDs an das COVID-19-Benachrichtigungssystem + weiter, welches diese mit den aufgezeichneten Zufalls-IDs abgleicht. Wenn + das COVID-19-Benachrichtigungssystem dabei eine Ãœbereinstimmung feststellt, + übergibt es der App die zu der jeweiligen Risiko-Begegnung aufgezeichneten + Begegnungsdaten. Diese und die Angaben in der Positiv-Liste + (Ãœbertragungsrisiko-Wert, Angaben zum Symptombeginn) werden von der App + bewertet, um Ihr Infektionsrisiko zu ermitteln. Der Bewertungsalgorithmus, + der festlegt, wie diese Informationen bewertet werden (beispielsweise + welchen Einfluss die Dauer eines Kontakts auf das Infektionsrisiko hat), + basiert auf den aktuellen wissenschaftlichen Erkenntnissen des RKI. Bei + neuen Erkenntnissen kann das RKI den Bewertungsalgorithmus aktualisieren, + indem die Bewertungseinstellungen der App angepasst werden. Die neuen + Bewertungseinstellungen werden in diesem Fall zusammen mit der + Positiv-Liste an die App übermittelt. +</p> +<p> + Das Infektionsrisiko wird ausschließlich innerhalb der App berechnet und + weder an das COVID-19-Benachrichtigungssystem noch an sonstige Empfänger + (auch nicht an das RKI, andere Gesundheitsbehörden in Deutschland oder + anderen Ländern, Apple, Google und sonstige Dritte) weitergegeben. </p> +<h2> + b. Test registrieren +</h2> <p> - Dies setzt voraus, dass das Testlabor an das Serversystem der App + Wenn Sie auf Corona getestet wurden, können Sie Ihren Test in der App + registrieren. Die App benachrichtigt Sie dann, sobald das Testergebnis + vorliegt. Dies setzt voraus, dass das Testlabor an das Serversystem angeschlossen ist und Sie im Rahmen der Testdurchführung gesondert in die - Ãœbermittlung Ihres Testergebnisses durch das Labor an das Serversystem der - App (Testergebnis-Datenbank) eingewilligt haben. Testergebnisse von - Laboren, die nicht an das Serversystem der App angeschlossen sind, können - nicht in der App angezeigt werden. Wenn Sie keinen QR-Code erhalten haben, - ist das Testlabor nicht angeschlossen. In diesem Fall können Sie diese + Ãœbermittlung Ihres Testergebnisses durch das Labor an das Serversystem + (Testergebnis-Datenbank) eingewilligt haben. Testergebnisse von Laboren, + die nicht an das Serversystem der App angeschlossen sind, können nicht + angezeigt werden. Wenn Sie keinen QR-Code erhalten haben, können Sie diese Funktion nicht nutzen. </p> <p> <u>Testregistrierung</u> </p> <p> - Damit Sie das Testergebnis in der App erhalten können, müssen Sie den - durchgeführten Test zunächst in der App registrieren. Hierzu erhalten Sie - von Ihrem Arzt bzw. der Testeinrichtung im Rahmen der Probenentnahme einen - QR-Code. Dieser QR-Code enthält eine Kennzahl, die mit einem - QR-Code-Scanner ausgelesen werden kann. Zur Testregistrierung müssen Sie - den QR-Code in der App mit der Kamera Ihres Smartphones scannen. -</p> -<p> - Die aus dem QR-Code ausgelesene Kennzahl wird von der App dann gehasht, das - bedeutet, die Kennzahl wird nach einem bestimmten mathematischen Verfahren - so verfremdet, dass die dahinterstehende Kennzahl nicht mehr erkennbar ist. - Sobald Ihr Smartphone eine Verbindung zum Internet hat, wird die App die - gehashte Kennzahl an die Serversysteme der App übermitteln. Im Gegenzug + Damit Sie das Testergebnis per App abrufen können, müssen Sie Ihren Test + registrieren. Hierzu erhalten Sie von Ihrem Arzt bzw. der Testeinrichtung + einen QR-Code. Dieser QR-Code enthält eine Kennzahl, die mit der App + ausgelesen werden kann. Zur Testregistrierung müssen Sie den QR-Code in der + App mit der Kamera Ihres Smartphones scannen. Die ausgelesene Kennzahl wird + von der App gehasht. Das bedeutet, dass die Kennzahl nach einem bestimmten + mathematischen Verfahren so verfremdet wird, dass sie nicht mehr erkennbar + ist. Sobald Ihr Smartphone eine Verbindung zum Internet hat, wird die + gehashte Kennzahl von der App an das Serversystem übermittelt. Im Gegenzug erhält die App vom Serversystem einen Token, also einen digitalen Zugangsschlüssel, der in der App gespeichert wird. Das Token ist auf dem Serversystem mit der gehashten Kennzahl verknüpft. Die App löscht dann die - auf Ihrem Smartphone gehashte Kennzahl. Das Serversystem wird für jede - gehashte Kennzahl nur ein einziges Mal einen Token vergeben. Auf diese - Weise wird sichergestellt, dass Ihr QR-Code nicht von anderen Nutzern der - App für die Abfrage von Testergebnissen verwendet werden kann. -</p> -<p> - Die Registrierung Ihres Tests ist damit abgeschlossen. + auf Ihrem Smartphone gehashte Kennzahl. Die Registrierung Ihres Tests ist + damit abgeschlossen. Das Serversystem wird für jede gehashte Kennzahl nur + ein einziges Mal einen Token vergeben. Auf diese Weise wird sichergestellt, + dass Ihr QR-Code nicht von anderen Nutzern der App für die Abfrage von + Testergebnissen verwendet werden kann. </p> <p> <u>Hinterlegung des Testergebnisses</u> @@ -334,414 +345,399 @@ <p> Sobald dem Testlabor das Testergebnis vorliegt, hinterlegt es das Ergebnis unter Angabe der gehashten Kennzahl in der vom RKI betriebenen - Testergebnis-Datenbank. Die Testergebnis-Datenbank wird vom RKI auf einem - speziellen Server innerhalb des Serversystems der App betrieben. Das - Testlabor erzeugt die gehashte Kennzahl ebenfalls auf Basis der an Sie im - ausgegebenen QR-Code enthaltenen Kennzahl unter Verwendung des gleichen - mathematischen Verfahrens, das auch die App einsetzt.<u></u> + Testergebnis-Datenbank. Die Testergebnis-Datenbank befindet sich auf einem + speziellen Server innerhalb des Serversystems. Das Testlabor erzeugt die + gehashte Kennzahl ebenfalls auf Basis der an Sie im ausgegebenen QR-Code + enthaltenen Kennzahl unter Verwendung des gleichen mathematischen + Verfahrens, das auch die App einsetzt. </p> <p> <u>Abruf des Testergebnisses</u> </p> <p> - Die App fragt bei dem Serversystem der App unter Verwendung des Tokens - regelmäßig den Status des registrierten Tests ab. Das Serversystem ordnet - das Token dann der gehashten Kennzahl zu und übermittelt diese an die - Testergebnis-Datenbank. Ist das Testergebnis dort mittlerweile abgelegt, - sendet die Testergebnis-Datenbank das Testergebnis an das Serversystem - zurück, der dieses ohne Kenntnisnahme des Inhalts an die App weiterleitet. + Die App fragt bei dem Serversystem unter Verwendung des Tokens regelmäßig + den Status des registrierten Tests ab. Das Serversystem ordnet das Token + dann der gehashten Kennzahl zu und übermittelt diese an die + Testergebnis-Datenbank. Diese prüft, ob zu der gehashten Kennzahl ein + Testergebnis abgelegt ist und gibt das Ergebnis zurück. Das Serversystem + leitet den Status sowie das von der Testergebnis-Datenbank abgefragte + Testergebnis selbst (also ob Ihr Befund positiv oder negativ ist) dann an + die App weiter. Wenn Sie die Mitteilungen zum Teststatus in der App + aktiviert haben (unter „Einstellungen“ > „Mitteilungen“), erhalten Sie + eine entsprechende Benachrichtigung. Das Testergebnis wird Ihnen angezeigt, + wenn Sie die App öffnen. +</p> +<p> + Wenn Sie Corona-positiv getestet wurden, fordert die App bei dem + Serversystem unter erneuter Verwendung des Tokens eine TAN + (Transaktionsnummer) an. Die TAN wird benötigt, um im Fall einer später per + App ausgelösten Warnung sicherzustellen, dass keine Falschwarnungen an + andere Nutzer ausgegeben werden. Das Serversystem ordnet das Token hierzu + wieder der gehashten Kennzahl zu und fordert von der Testergebnis-Datenbank + eine Bestätigung an, dass zu der gehashten Kennzahl tatsächlich ein + positives Testergebnis vorliegt. Sofern dies bestätigt wird, erzeugt das + Serversystem die TAN und übermittelt sie an die App. Eine Kopie der TAN + verbleibt auf dem Serversystem. </p> +<h2> + c. Andere warnen +</h2> <p> - Im Fall eines positiven Testergebnis fordert die App beim Serversystem - unter erneuter Verwendung des Tokens eine TAN (Transaktionsnummer) an. Das - Serversystem ordnet das Token wieder der gehashten Kennzahl zu und fordert - von der Testergebnis-Datenbank eine Bestätigung an, dass zu der gehashten - Kennzahl ein positives Testergebnis vorliegt. Sofern die - Testergebnis-Datenbank dies bestätigt, erzeugt das Serversystem die TAN und - übermittelt sie an die App. Eine Kopie der TAN verbleibt auf dem - Serversystem. + Wenn Sie Corona-positiv getestet wurden, können Sie die länderübergreifende + Warnfunktion nutzen, um andere Nutzer zu warnen, die diese App oder eine + andere offizielle Corona-App der teilnehmenden Länder verwenden. In diesem + Fall übermittelt die App folgende Daten an das Serversystem: </p> +<ul> + <li> + Ihre eigenen Zufalls-IDs der letzten 14 Tage + </li> + <li> + eventuelle Angaben zum Symptombeginn + </li> + <li> + Ihre TAN (siehe Punkt 6 b.) + </li> +</ul> <p> - Die TAN wird benötigt, um im Fall einer Ãœbermittlung des positiven - Testergebnisses sicherzustellen, dass keine falschen Informationen an - andere Nutzer verteilt werden. + Möglicherweise bittet Sie Ihr Smartphone zunächst um Erlaubnis, dass es + Ihre eigenen Zufalls-IDs aus dem COVID-19-Benachrichtigungssystem an die + App weitergeben darf. </p> <p> - Rechtsgrundlage der oben beschriebenen Verarbeitung der zuvor genannten - Daten ist Ihre Einwilligung für die Funktion „Test registrieren“. + Vor der Ãœbermittlung der Zufalls-IDs an das Serversystem fügt die App den + Zufalls-IDs jeweils einen Ãœbertragungsrisiko-Wert und eine Angabe zur Art + der Diagnose hinzu (siehe hierzu auch Punkt 6 a.). Da die Warnfunktion der + App nur bei im Labor bestätigten Diagnosen genutzt werden kann, ist die + Diagnoseart für alle Nutzer gleich. Der Ãœbertragungsrisiko-Wert ist ein + Schätzwert zur Ansteckungswahrscheinlichkeit an dem Tag, an dem die + jeweilige Zufalls-ID verwendet worden ist. Da die + Ansteckungswahrscheinlichkeit von der Dauer und dem Verlauf der Infektion + abhängt, kann so beispielsweise berücksichtigt werden, dass am Tag einer + Risiko-Begegnung die Gefahr einer Ansteckung in der Regel je geringer ist, + desto mehr Zeit seit Symptombeginn verstrichen ist. </p> -<h3> - c. Testergebnis teilen -</h3> <p> - Wenn Sie die Funktion „Testergebnis teilen“ nutzen um andere Nutzer zu - warnen, überträgt die App die von Ihrem Smartphone gespeicherten eigenen - Zufalls-IDs der letzten 14 Tage und die TAN an das Serversystem der App. - Dieses prüft zunächst, ob die TAN gültig ist und trägt Ihre Zufalls-IDs - sodann in die Liste der Zufalls-IDs von Nutzern, die ihr positives - Testergebnis geteilt haben, ein. Ihre Zufalls-IDs können nun von anderen - Nutzern im Rahmen der Risiko-Ermittlung heruntergeladen werden. + Die abgefragten Angaben zum Symptombeginn sind optional. Diese Angaben + können jedoch helfen, den Ãœbertragungsrisiko-Wert genauer zu berechnen. + Wenn Sie keine Angaben machen, werden die Ãœbertragungsrisiko-Werte unter + Annahme eines typischen Infektionsverlaufs berechnet, d. h. je mehr Zeit + seit Verwendung einer Zufalls-ID vergangen ist, desto kleiner ist der + zugehörige Ãœbertragungsrisiko-Wert. </p> <p> <u>Wenn Sie Ihr Testergebnis nicht in der App abgerufen haben:</u> </p> <p> - Auch wenn Sie ein positives Testergebnis nicht in der App abgerufen haben, - können Sie das Testergebnis per App teilen, um andere Nutzer zu warnen. In - diesem Fall fordert Sie die App zur Eingabe einer sogenannten TeleTAN auf, - die als TAN fungiert. -</p> -<p> - Für den Erhalt der TeleTAN können Sie die Hotline der Corona-Warn-App unter - der Nummer +49 (0)800 7540002 anrufen. Der dort für Sie zuständige - Ansprechpartner wird Ihnen zunächst am Telefon einige Fragen stellen, um - die Plausibilität Ihres Anrufs zu überprüfen. Diese Fragen dienen der - Vorbeugung einer missbräuchlichen Infektionsmeldung und daraus - resultierender fehlerhafter Warnungen und Risikowerte. Nach ausreichender - Beantwortung dieser Fragen werden Sie nach Ihrer Handy-/Telefonnummer - gefragt. Dies dient dazu, Sie später zurückrufen zu können, um Ihnen eine - TeleTAN zur Eingabe in der App mitzuteilen. Ihre Handy-/Telefonnummer wird - nur zu diesem Zweck vorübergehend gespeichert und spätestens innerhalb - einer Stunde gelöscht. -</p> -<p> - Nach Ihrem Anruf wird der Hotline-Mitarbeiter über einen speziellen Zugang - zum Serversystem der App eine TeleTAN generieren und Sie sodann anrufen, um - Ihnen die TeleTAN mitzuteilen. Wenn Sie die TeleTAN in der App eingeben, - wird die TeleTAN von der App zum Abgleich und Verifizierung an das - Serversystem der App zurückgesendet. Im Gegenzug erhält die App vom - Serversystem einen Token, also einen digitalen Zugangsschlüssel, der in der - App gespeichert wird. Mit diesem Token fordert die App beim Serversystem - dann eine TAN an. -</p> -<p> - Rechtsgrundlage dieser Verarbeitung Ihrer Zugriffsdaten und - Gesundheitsdaten (Zufalls-IDs, Testergebnis, TAN und ggf. TeleTAN) ist Ihre - Einwilligung für die Funktion „Testergebnis teilen“. -</p> -<p> - <strong>d. Informatorische Nutzung der App</strong> -</p> -<p> - Soweit Sie die App nur informatorisch nutzen, also keine der oben genannten - Funktionen der App verwenden und keine Daten eingeben, findet die - Verarbeitung ausschließlich lokal auf Ihrem Smartphone statt und es fallen - keine personenbezogenen Daten an. In der App verlinkte Webseiten z.B.: - www.bundesregierung.de werden im Standard-Browser Ihres Smartphones - geöffnet und angezeigt. Welche Daten dabei verarbeitet werden hängt von dem - genutzten Browser, dessen Konfiguration sowie der Datenverarbeitungspraxis - der aufgerufenen Webseite ab. + Auch wenn Sie Ihr positives Testergebnis nicht in der App abgerufen haben, + können Sie Ihre Mitmenschen warnen. Wählen Sie hierzu das Verfahren „TAN + anfragen“. Die App fordert Sie dann auf, die Hotline der App anzurufen. Ein + Hotline-Mitarbeiter wird Ihnen dann einige Fragen stellen, um + sicherzugehen, dass Sie tatsächlich Corona-positiv getestet worden sind. + Damit soll verhindert werden, dass versehentlich oder absichtlich + Falschwarnungen ausgelöst werden. Nach ausreichender Beantwortung dieser + Fragen werden Sie nach Ihrer Handy-/Telefonnummer und Ihrem Namen gefragt. + Dies dient dazu, Sie später zurückrufen zu können, um Ihnen eine sogenannte + TeleTAN zur Eingabe in der App mitzuteilen. Ihre Handy-/Telefonnummer und + Ihr Name werden nur zu diesem Zweck vorübergehend gespeichert und + spätestens nach einer Stunde gelöscht. Unmittelbar nach Ihrem Anruf wird + der Hotline-Mitarbeiter über einen speziellen Zugang zum Serversystem Ihre + TeleTAN erzeugen und Sie zurückrufen, um Ihnen diese mitzuteilen. Eine + TeleTAN ist nur eine Stunde gültig und wird daher unmittelbar nach der + Weitergabe an Sie, spätestens aber nach Ablauf einer Stunde, von der + Hotline gelöscht. Nach Eingabe einer gültigen TeleTAN in der App wird diese + zur Verifizierung an das Serversystem übermittelt. Bei erfolgreicher + Verifizierung erhält die App vom Serversystem einen Token, also einen + digitalen Zugangsschlüssel, der in der App gespeichert wird. Mit diesem + Token fordert die App beim Serversystem dann eine TAN an. </p> <h2> - 7. Welche Berechtigungen und Funktionen benötigt die App? + d. Informatorische Nutzung der App </h2> +<p> + Soweit Sie die App nur informatorisch nutzen, also keine der oben genannten + Funktionen verwenden, findet die Verarbeitung ausschließlich lokal auf + Ihrem Smartphone statt und es werden keine personenbezogenen Daten durch + das RKI verarbeitet. In der App verlinkte Webseiten, z. B.: www.bundesregierung.de, werden im + Standard-Browser + (Android-Smartphones) oder in der App (iPhones) geöffnet und angezeigt. + Welche Daten dabei verarbeitet werden, wird von den jeweiligen Anbietern + der aufgerufenen Webseite festgelegt. +</p> +<h1> + 7. Wie funktioniert das länderübergreifende Warnsystem? +</h1> +<p> + Damit auch Nutzer von den offiziellen Corona-Apps anderer Länder gewarnt + werden, hat das RKI zusammen mit mehreren in anderen Ländern für + Gesundheitsaufgaben zuständigen amtlichen Stellen und Behörden (im + Folgenden: <strong>Gesundheitsbehörden</strong>) einen zentralen Warnserver + zum länderübergreifenden Austausch von Warnungen (im Folgenden: + <strong>Austausch-Server</strong>) eingerichtet. Der Austausch-Server nutzt + die digitale Infrastruktur des zwischen den Mitgliedsstaaten eingerichteten + Netzwerks für elektronische Gesundheitsdienste. +</p> +<p> + Die nationalen Serversysteme der am Austausch-Server angebundenen + Corona-Apps übermitteln ihre eigenen Positiv-Listen regelmäßig an den + Austausch-Server und erhalten die Positiv-Listen der anderen Länder. +</p> +<p> + Das Serversystem führt die erhaltenen Positiv-Listen mit der eigenen + Positiv-Liste zusammen, so dass die Risiko-Ermittlung auch + Risiko-Begegnungen mit Nutzern einer anderen Corona-App berücksichtigen + kann (siehe Ziffer 6 c.). Die anderen teilnehmenden Länder verfahren + entsprechend mit den vom RKI bereitgestellten Positiv-Listen. +</p> +<p> + Am gemeinsam betriebenen Austausch-Server können nur Länder teilnehmen, + deren Corona-Apps zueinander kompatibel sind und die ein vergleichbar hohes + Datenschutzniveau gewährleisten. Dies setzt insbesondere voraus, dass die + Corona-Apps der teilnehmenden Länder ebenfalls das + COVID-19-Benachrichtigungssystem nutzen, von der jeweiligen nationalen + Gesundheitsbehörde zugelassen sind und die Privatsphäre ihrer Nutzer + wahren. Die technischen und organisatorischen Einzelheiten der + Zusammenarbeit werden in einem Beschluss der EU-Kommission festgelegt + (Durchführungsbeschluss (EU) 2020/1023 vom 15. Juli 2020, abrufbar unter + https://eur-lex.europa.eu/eli/dec_impl/2020/1023/oj). +</p> +<p> + Für die Verarbeitung der in den Positiv-Listen enthaltenen Angaben + (Zufalls-IDs und eventuelle Angaben zum Symptombeginn) auf dem + Austausch-Server zur Ermöglichung der länderübergreifenden + Risiko-Ermittlung und Warnung ist das RKI mit den jeweils zuständigen + Gesundheitsbehörden der teilnehmenden Länder gemeinsam verantwortlich. +</p> +<p> + Bitte beachten Sie, dass sich die Liste der teilnehmenden Länder ändern + kann. Die aktuelle Liste mit Angaben zu den jeweils verantwortlichen + Gesundheitsbehörden finden Sie in den FAQ: abrufbar unter + https://www.coronawarn.app/de/faq/#interoperability_countries. +</p> +<h1> + 8. Welche Berechtigungen benötigt die App? +</h1> <p> Die App benötigt Zugriff auf verschiedene Funktionen und Schnittstellen Ihres Smartphones. Dazu ist es erforderlich, dass Sie der App bestimmte - Berechtigungen erteilen. Die Berechtigungen sind von den verschiedenen - Herstellern unterschiedlich programmiert. So können z. B. - Einzelberechtigungen zu Berechtigungskategorien zusammengefasst sein, wobei - Sie der Berechtigungskategorie nur insgesamt zustimmen können. Bitte - beachten Sie, dass Sie im Falle der Ablehnung eines Zugriffs durch die App - keine oder nur wenige Funktionen der App nutzen können. -</p> -<h3> + Berechtigungen erteilen. Das Berechtigungssystem richtet sich nach den + Vorgaben Ihres Betriebssystems. So können auf Ihrem Smartphone + beispielsweise Einzelberechtigungen zu Berechtigungskategorien + zusammengefasst sein, wobei Sie der Berechtigungskategorie nur insgesamt + zustimmen können. Bitte beachten Sie, dass ohne die von der App + angeforderten Berechtigungen keine oder nur wenige App-Funktionen genutzt + werden können. +</p> +<h2> a. Technische Voraussetzungen (alle Smartphones) -</h3> +</h2> <ul> <li> - Internet + Die App benötigt eine Internetverbindung, um mit dem Serversystem Daten + austauschen zu können. </li> -</ul> -<p> - Die App benötigt für die Funktionen Risiko-Ermittlung, Testergebnisse - erhalten und Testergebnis übermitteln eine Internetverbindung, um mit den - Serversystemen der App kommunizieren zu können. -</p> -<ul> <li> - Bluetooth + Die Bluetooth-Funktion muss aktiviert sein, damit Ihr Smartphone eigene + Zufalls-IDs aussenden und die Zufalls-IDs von anderen Smartphones + aufzeichnen kann. </li> -</ul> -<p> - Die Bluetooth-Schnittstelle Ihres Smartphones muss aktiviert sein, damit - Ihr Smartphone Zufalls-IDs von anderen Smartphones erfassen und im - Kontaktprotokoll des Geräts speichern kann. -</p> -<ul> <li> - Kamera + Die App muss auf Ihrem Smartphone im Hintergrundbetrieb laufen können, + um Ihr Infektionsrisiko automatisch zu ermitteln und den Status eines + registrierten Tests abfragen zu können. Wenn Sie den Hintergrundbetrieb + deaktivieren, müssen Sie alle Aktionen in der App selbst starten. </li> </ul> -<p> - Ihr Smartphone benötigt eine Kamera, um damit einen QR-Code im Rahmen der - Testregistrierung scannen können. -</p> -<ul> - <li> - Hintergrundbetrieb - </li> -</ul> -<p> - Die App nutzt den Hintergrundbetrieb (also wenn Sie die App nicht gerade - aktiv nutzen), um Ihr Risiko automatisch zu ermitteln und den Status eines - registrierten Tests abfragen zu können. Wenn Sie den Hintergrundbetrieb im - Betriebssystem Ihres Smartphones deaktivieren, müssen Sie alle Aktionen in - der App selbst starten. -</p> -<h3> +<h2> b. Android-Smartphones -</h3> +</h2> <p> - Wenn Sie ein Android-Gerät verwenden, müssen außerdem folgende + Wenn Sie ein Android-Smartphone verwenden, müssen außerdem folgende Systemfunktionen aktiviert sein: </p> <ul> <li> - Benachrichtigungen zu möglicher Begegnung mit COVID-19-Infizierten + Das COVID-19-Benachrichtigungssystem von Android + (COVID-19-Benachrichtigungen) </li> -</ul> -<p> - Die Risiko-Ermittlung benötigt diese Funktion, da andernfalls kein - Kontaktprotokoll mit den Zufalls-IDs Ihrer Kontakte zur Verfügung steht. - Die Funktion muss innerhalb der App aktiviert werden, damit die App auf das - Kontaktprotokoll zugreifen darf. -</p> -<ul> <li> - Standortermittlung + Die Standortermittlung muss unter Android bis Version 10 aktiviert + sein, damit Ihr Smartphone nach Bluetooth-Signalen anderer Smartphones + sucht. Standortdaten werden dabei jedoch nicht erhoben. </li> -</ul> -<p> - Die Standortermittlung Ihres Smartphones muss aktiviert sein, damit Ihr - Gerät nach Bluetooth-Signalen anderer Smartphones sucht. Standortdaten - werden dabei jedoch nicht erhoben. -</p> -<ul> <li> - Benachrichtigung + Um über Änderungen Ihres Infektionsrisikos und den Status von + Testergebnissen benachrichtigt werden zu können, muss die + Benachrichtigungsfunktion aktiviert sein. Die Benachrichtigungsfunktion + ist im Betriebssystem standardmäßig aktiviert. </li> </ul> -<p> - Der Nutzer wird lokal über die Risiko-Ermittlung und vorhandene - Testergebnisse benachrichtigt. Die dafür notwendige - Benachrichtigungsfunktion ist im Betriebssystem bereits aktiviert. -</p> <p> Daneben benötigt die App folgende Berechtigungen: </p> <ul> <li> - Kamera + Die Funktion „Test registrieren“ benötigt Zugriff auf die Kamera, um + den QR-Code auslesen zu können. </li> </ul> -<p> - Die App benötigt Zugriff auf die Kamera, um bei der Testregistrierung den - QR-Code auslesen zu können. -</p> -<h3> +<h2> c. iPhones (Apple iOS) -</h3> +</h2> <p> Wenn Sie ein iPhone verwenden, müssen folgende Systemfunktionen aktiviert sein: </p> <ul> <li> - COVID-19-Kontaktprotokoll + Das COVID-19-Benachrichtigungssystem von iOS (Begegnungsmitteilungen) </li> -</ul> -<p> - Die Risiko-Ermittlung benötigt diese Funktion, da andernfalls kein - Kontaktprotokoll mit den Zufalls-IDs Ihrer Kontakte zur Verfügung steht. - Die Funktion muss innerhalb der App aktiviert werden, damit die App auf das - Kontaktprotokoll zugreifen darf. -</p> -<ul> <li> - Mitteilungen + Um über Änderungen Ihres Infektionsrisikos und den Status von + Testergebnissen benachrichtigt werden zu können, müssen Mitteilungen + aktiviert sein. </li> </ul> -<p> - Der Nutzer wird lokal über die Risiko-Ermittlung und vorhandene - Testergebnisse benachrichtigt. Mitteilungen müssen dafür aktiviert sein. -</p> <p> Die App benötigt zudem folgende Berechtigungen: </p> <ul> <li> - Kamera + Die Funktion „Test registrieren“ benötigt Zugriff auf die Kamera, um + den QR-Code auslesen zu können. </li> </ul> -<p> - Die App benötigt Zugriff auf die Kamera, um bei der Testregistrierung den - QR-Code auslesen zu können. +<h1> + 9. Wann werden Ihre Daten gelöscht? +</h1> +<p> + Die Speicherdauer richtet sich danach, für welche Zwecke bzw. + App-Funktionen Ihre Daten jeweils gespeichert worden sind. Bei der + Festlegung der Speicherdauer berücksichtigt das RKI die aktuellen + wissenschaftlichen Erkenntnisse zur Inkubationszeit (bis zu 14 Tage) und + zur Dauer des Ansteckungsrisikos für Mitmenschen einer infizierten Person + nach dem Ende der Inkubationszeit. Soweit unter Punkt 6 keine kürzere + Speicherdauer genannt wird, gelten folgende Fristen: </p> <h2> - 8. Wann werden die Daten gelöscht? + a. Daten auf Ihrem Smartphone </h2> <p> - Alle in der App gespeicherten Daten werden gelöscht, sobald sie für die - Funktionen der App nicht mehr benötigt werden: + Die abgerufenen Positiv-Listen werden nach 14 Tagen aus dem App-Speicher + gelöscht. Das in der App ermittelte Infektionsrisiko (z. B. „niedriges + Risiko“) wird nach jeder Aktualisierung, spätestens aber nach 14 Tagen aus + dem App-Speicher gelöscht. Sofern Sie einen Corona-positiven Test + registriert haben, wird das Token im App-Speicher gelöscht, sobald Sie eine + Warnung auslösen. </p> -<h3> - a. Risiko-Ermittlung -</h3> -<ul> - <li> - Die Liste der Zufalls-IDs von Nutzern, die ein positives Testergebnis - geteilt haben, wird in der App unverzüglich und im Ãœbrigen im - Kontaktprotokoll Ihres Smartphones nach 14 Tagen automatisch gelöscht. - </li> - <li> - Auf die Löschung der Begegnungsdaten im Kontaktprotokoll Ihres - Smartphones (einschließlich Ihrer eigenen Zufalls-IDs) und die - Begegnungsdaten auf anderen Smartphones hat das RKI keinen Einfluss, da - diese Funktion von Apple bzw. Google bereitgestellt werden. Die - Löschung richtet sich nach den Festlegungen von Apple bzw. Google. - Zurzeit werden die Daten nach 14 Tagen automatisch gelöscht. Zudem - können Sie im Rahmen der von Apple und Google bereitgestellten - Funktionalitäten in den Systemeinstellungen Ihres Geräts gegebenenfalls - eine manuelle Löschung anstoßen. - </li> - <li> - Der in der App angezeigte Risikowert wird gelöscht, sobald ein neuer - Risikowert ermittelt worden ist. Ein neuer Risikowert wird in der Regel - ermittelt, nachdem die App eine neue Liste mit Zufalls-IDs erhalten - hat. - </li> -</ul> -<h3> - b. Test registrieren -</h3> -<ul> - <li> - Die gehashte Kennzahl wird auf dem Serversystem der App nach 21 Tagen - gelöscht. - </li> - <li> - Die gehashte Kennzahl und das Testergebnis in der - Testergebnis-Datenbank werden im Fall eines negativen Testergebnisses - unmittelbar nach dem Abruf des Testergebnisses und im Fall eines - positiven Testergebnissen unmittelbar nach dem Löschen der auf - Serversystem gespeicherten Kopie der TAN gelöscht (s.u.). - </li> - <li> - Das Token, das auf dem Serversystem gespeichert ist, wird nach 21 Tagen - gelöscht. - </li> - <li> - Das Token, das in der App gespeichert ist, wird nach Löschung der App - vom Smartphone oder nach Ausführung der Funktion „Testergebnis teilen“ - gelöscht. - </li> -</ul> -<h3> - c. Testergebnis teilen -</h3> -<ul> - <li> - Die in der App geteilten eigenen Zufalls-IDs werden nach 14 Tagen vom - Serversystem gelöscht. - </li> - <li> - Die Kopie der TAN, die auf dem Serversystem gespeichert ist, wird nach - 21 Tagen gelöscht. - </li> - <li> - Die TAN, die in der App gespeichert ist, wird nach Teilen des - Testergebnisses gelöscht. - </li> - <li> - Die TeleTAN, die in der App gespeichert ist, wird nach Teilen des - Testergebnisses gelöscht. - </li> - <li> - Die TeleTAN, die auf dem Serversystem gespeichert ist, wird nach 21 - Tagen gelöscht. - </li> - <li> - Die TeleTAN, die dem Mitarbeiter der Hotline übermittelt wird, wird - dort direkt nach der telefonischen Weitergabe an Sie gelöscht. - </li> - <li> - Das Token, das auf dem Serversystem gespeichert ist, wird nach 21 Tagen - gelöscht. - </li> - <li> - Das Token, das in der App gespeichert ist, wird nach Teilen des - Testergebnisses gelöscht. - </li> -</ul> <h2> - 9. An wen werden Ihre Daten weitergegeben? + b. Daten auf Serversystemen </h2> <p> - Wenn Sie ein Testergebnis teilen, um andere Nutzer zu warnen, werden Ihre - Zufalls-IDs der letzten 14 Tage an die Apps der anderen Nutzer - weitergegeben. + Positiv-Listen werden nach 14 Tagen von allen Serversystemen + (einschließlich Austausch-Server) gelöscht. Alle anderen Daten werden + spätestens nach 21 Tagen gelöscht. +</p> +<h1> + 10. An wen werden Ihre Daten weitergegeben? +</h1> +<p> + Wenn Sie andere Nutzer über die App warnen, werden Ihre Zufalls-IDs der + letzten 14 Tage sowie optionale Angaben zum Symptombeginn an die jeweils + verantwortlichen Gesundheitsbehörden der am Austausch-Server teilnehmenden + Länder und von dort an die Serversysteme der an den länderübergreifenden + Warnungen teilnehmenden Corona-Apps weitergegeben. Die Serversysteme der + nationalen Corona-Apps verteilen Ihre Daten dann als Bestandteil der + Positiv-Listen an ihre jeweiligen eigenen Nutzer. +</p> +<p> + Mit dem Betrieb und der Wartung des gemeinsam betriebenen Warnsystems haben + die zuständigen nationalen Gesundheitsbehörden der teilnehmenden Länder die + EU-Kommission als Auftragsverarbeiter beauftragt. </p> <p> Mit dem Betrieb und der Wartung eines Teils der technischen Infrastruktur der App (z. B. Serversysteme, Hotline) hat das RKI die T-Systems International GmbH und die SAP Deutschland SE & Co. KG beauftragt, die - insoweit als Auftragsverarbeiter des RKI tätig werden (Artikel 28 DSGVO). + als Auftragsverarbeiter des RKI tätig werden. Diese Unternehmen sind von + der EU-Kommission zudem als Unterauftragsverarbeiter mit der technischen + Bereitstellung und Verwaltung des gemeinsam betriebenen Warnsystems der + teilnehmenden Länder beauftragt. </p> <p> - Im Ãœbrigen gibt das RKI personenbezogene Daten, die im Zusammenhang mit der - Nutzung der App erhoben werden, nur an Dritte weiter, soweit das RKI - rechtlich dazu verpflichtet ist oder die Weitergabe im Falle von Angriffen - auf die technische Infrastruktur der App zur Rechts- oder Strafverfolgung + Im Ãœbrigen gibt das RKI Ihre Daten, die im Zusammenhang mit der Nutzung der + App erhoben werden, nur an Dritte weiter, soweit das RKI rechtlich dazu + verpflichtet ist oder die Weitergabe im Falle von Angriffen auf die + technische Infrastruktur der App zur Rechts- oder Strafverfolgung erforderlich ist. Eine Weitergabe in anderen Fällen erfolgt grundsätzlich nicht. </p> -<h2> - 10. Werden Daten in ein Drittland übermittelt? -</h2> +<h1> + 11. Werden Ihre Daten in Länder außerhalb der EU übermittelt? +</h1> <p> - Die bei der Nutzung der App anfallenden Daten werden ausschließlich auf - Servern in Deutschland oder in einem anderem EU- oder EWR-Mitgliedsstaat - verarbeitet. + Wenn Sie eine Warnung auslösen, können die am gemeinsamen Austausch-Server + angebundenen Corona-Apps die aktuellen Positiv-Listen weltweit abrufen, so + dass auch Nutzer etwa im Urlaub oder auf Geschäftsreise gewarnt werden + können. Im Ãœbrigen werden die von der App übermittelten Daten + ausschließlich auf Servern in Deutschland oder in einem anderem Land in der + EU (oder dem Europäischen Wirtschaftsraum) verarbeitet, die somit den + strengen Anforderungen der Datenschutz-Grundverordnung (DSGVO) unterliegen. </p> -<h2> - 11. Widerruf von Einwilligungen -</h2> +<h1> + 12. Wie können Sie Ihre Einwilligungen widerrufen? + +</h1> <p> Ihnen steht das Recht zu, die in der App erteilten Einwilligungen gegenüber dem RKI jederzeit mit Wirkung für die Zukunft zu widerrufen. Die Rechtmäßigkeit der Verarbeitung bis zum Widerruf wird dadurch jedoch nicht berührt. </p> +<h2> + a. Einwilligung für die Risiko-Ermittlung +</h2> <p> - Zum Widerruf Ihrer Einwilligung in die Risiko-Ermittlung können Sie die - Funktion über den Schieberegler innerhalb der App deaktivieren oder die App - löschen. Wenn Sie die Risiko-Ermittlung wieder nutzen möchten, können Sie - den Schieberegler erneut aktivieren oder die App erneut installieren. -</p> -<p> - Zum Widerruf Ihrer Einwilligung für die Funktion „Test registrieren“ können - Sie die Testregistrierung in der App löschen. Das Token zum Abruf des - Testergebnisses wird dann von Ihrem Gerät gelöscht. Weder das RKI noch das - Testlabor können die übermittelten Daten dann Ihrer App oder Ihrem - Smartphone zuordnen. Wenn Sie einen weiteren Test registrieren möchten, - werden Sie um eine neue Einwilligung gebeten. + Zum Widerruf Ihrer Einwilligung können Sie die Risiko-Ermittlung + deaktivieren oder die App löschen. Wenn Sie die Risiko-Ermittlung wieder + nutzen möchten, können Sie die Funktion erneut aktivieren oder die App + erneut installieren. </p> +<h2> + b. Einwilligung für die Testregistrierung +</h2> <p> - Zum Widerruf Ihrer Einwilligung für die Funktion „Testergebnis teilen“ - müssen Sie die App löschen. Sämtliche Ihrer in der App gespeicherten - Zufalls-IDs werden dann entfernt und können Ihrem Smartphone nicht mehr - zugeordnet werden. Wenn Sie erneut ein Testergebnis melden möchten, können - Sie in der App erneut installieren und eine neue Einwilligung erteilen. - Alternativ können Sie Ihre eigenen Zufalls-IDs gegebenenfalls im Rahmen der - Kontaktaufzeichnungs-Funktion in den Systemeinstellungen Ihres Smartphones - löschen. Bitte beachten Sie, dass das RKI keine Möglichkeit hat, um Ihre - bereits übermittelten Zufalls-IDs unmittelbar aus den bereitgestellten - Listen und von Smartphones anderer Nutzer zu löschen. + Zum Widerruf Ihrer Einwilligung können Sie die Testregistrierung in der App + löschen. Das Token zum Abruf des Testergebnisses wird dadurch aus dem + App-Speicher gelöscht, sodass das Token auf dem Serversystem nicht mehr + zugeordnet werden kann. Eine erneute Registrierung des gleichen Tests ist + dann nicht möglich. Wenn Sie einen neuen Test registrieren möchten, werden + Sie um eine neue Einwilligung gebeten. </p> <h2> - 12. Ihre weiteren Datenschutzrechte + c. Einwilligung für die Warnfunktion </h2> +<p> + Zum Widerruf Ihrer Einwilligung müssen Sie die App löschen. Ihre bereits an + das Serversystem übermittelten Zufalls-IDs werden dadurch aus dem + App-Speicher gelöscht und können dann nicht mehr zugeordnet werden. Wenn + Sie erneut eine Warnung auslösen möchten, müssen Sie die App erneut + installieren und eine neue Einwilligung erteilen. Ein einmal in der App + registriertes Testergebnis kann nicht erneut verwendet werden, um andere zu + warnen. +</p> +<p> + Das RKI hat keine Möglichkeit, um Ihre bereits übermittelten Zufalls-IDs + und Ãœbertragungsrisiko-Werte aus den vom Serversystem verteilten + Positiv-Listen und von Smartphones der Nutzer zu löschen. Um auch Ihre im + COVID-19-Benachrichtigungssystem gespeicherten Begegnungsdaten zu löschen, + können Sie in den Systemeinstellungen Ihres Smartphones möglicherweise eine + manuelle Löschung vornehmen. Beachten Sie hierzu auch die Hinweise unter + Punkt 5 b. +</p> +<h1> + 13. Welche weiteren Datenschutzrechte haben Sie? +</h1> <p> Soweit das RKI personenbezogene Daten von Ihnen verarbeitet, stehen Ihnen außerdem folgende Datenschutzrechte zu: @@ -751,35 +747,49 @@ die Rechte aus den Artikeln 15, 16, 17, 18, 20 und 21 DSGVO, </li> <li> - das Recht, den behördlichen Datenschutzbeauftragten des RKI zu - kontaktieren und Ihr Anliegen vorzubringen (Artikel 38 Abs. 4 DSGVO) + das Recht, den behördlichen Datenschutzbeauftragten des RKI + (https://www.rki.de/DE/Content/Institut/OrgEinheiten/Datenschutz/Datenschutz_node.html) + zu kontaktieren und Ihr Anliegen vorzubringen (Art. 38 Abs. 4 DSGVO) und </li> <li> das Recht, sich bei einer zuständigen Aufsichtsbehörde für den Datenschutz zu beschweren. Dazu können Sie sich entweder an die - zuständige Aufsichtsbehörde an Ihrem Wohnort oder an die am Sitz des - RKI zuständige Behörde wenden. Die zuständige Aufsichtsbehörde für das - RKI ist der Bundesbeauftragte für den Datenschutz und die + zuständige Aufsichtsbehörde an Ihrem Wohnort oder an die für des RKI + zuständige Behörde wenden. Die zuständige Aufsichtsbehörde für das RKI + ist der Bundesbeauftragte für den Datenschutz und die Informationsfreiheit, Graurheindorfer Str. 153, 53117 Bonn. </li> </ul> <p> - Es wird darauf hingewiesen, dass die vorgenannten Rechte vom RKI nur - erfüllt werden können, wenn die Daten, auf die sich die geltend gemachten - Ansprüche beziehen, eindeutig Ihrer Person zugeordnet werden können. Dies - wäre nur möglich, wenn das RKI weitere personenbezogene Daten erhebt, die - eine eindeutige Zuordnung der oben genannten Daten zu Ihrer Person oder - Ihrem Smartphone erlaubt. Da dies für die Zwecke der App nicht erforderlich - – und auch nicht gewollt – ist, ist das RKI zu einer solchen zusätzlichen - Datenerhebung nicht verpflichtet (Artikel 11 Abs. 2 DSGVO). Zudem würde - dies dem erklärten Ziel zuwiderlaufen, die Datenverarbeitung im Rahmen der - App so datensparsam wie möglich durchzuführen. Aus diesem Hintergrund - werden die vorgenannten Datenschutzrechte aus den Artikeln 15, 16, 17, 18, - 20 und 21 DSGVO in der Regel nicht unmittelbar und nur mit zusätzlichen - Informationen zu Ihrer Person, die dem RKI nicht vorliegen, erfüllt werden - können. -</p> -<p> - Stand: 12.06.2020 + Diese Datenschutzrechte stehen Ihnen in Bezug auf die gemeinsame + Verarbeitung durch den länderübergreifenden Austausch-Server auch gegenüber + den für die Datenverarbeitung verantwortlichen Gesundheitsbehörden der am + Austausch-Server teilnehmenden Länder zu (siehe Punkt 7). +</p> +<p> + Bitte beachten Sie, dass die vorgenannten Datenschutzrechte nur erfüllt + werden können, wenn die Daten, auf die sich die geltend gemachten Ansprüche + beziehen, eindeutig Ihrer Person zugeordnet werden können. Dies wäre nur + möglich, wenn über die App weitere personenbezogene Daten erhoben würden, + die eine eindeutige Zuordnung der an das Serversystem übermittelten Daten + zu Ihrer Person oder Ihrem Smartphone ermöglichen. Da dies für die Zwecke + der App nicht erforderlich ist, ist das RKI zu einer solchen zusätzlichen + Datenerhebung nicht verpflichtet (Art. 11 Abs. 2 DSGVO). Zudem würde dies + dem erklärten Ziel zuwiderlaufen, so wenige Daten wie möglich zu erheben. + Deshalb werden die vorgenannten Datenschutzrechte auch mit zusätzlich von + Ihnen bereitgestellten Informationen zu Ihrer Identität in der Regel nicht + erfüllt werden können. +</p> +<h1> + 14. Datenschutzbeauftragter und Kontakt +</h1> +<p> + Fragen und Anliegen zum Datenschutz können Sie an den behördlichen + Datenschutzbeauftragten des RKI senden: Robert Koch-Institut, z. H. des + Datenschutzbeauftragten, Nordufer 20, 13353 Berlin oder per E-Mail an: + datenschutz@rki.de. +</p> +<p> + Stand: 15.10.2020 </p> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/assets/privacy_en.html b/Corona-Warn-App/src/main/assets/privacy_en.html index 44edf5a86ba02563c67c8c807de87a5534b86902..ffce0a25d17049236cf4e60689b8a29d14b1e00d 100644 --- a/Corona-Warn-App/src/main/assets/privacy_en.html +++ b/Corona-Warn-App/src/main/assets/privacy_en.html @@ -2,314 +2,337 @@ Privacy notice </p> <p> - Corona-Warn-App + Last amended: 17 October 2020. </p> <p> - This privacy notice explains what data is collected when you use the - Corona-Warn-App, how that data is used, and your rights under data - protection law. + This privacy notice explains how your data is processed and what data + protection rights you have when using the German Federal Government’s + official coronavirus app, the Corona-Warn-App. </p> <p> - To ensure that this privacy notice can be understood by all users, we have - made every effort to make it simple and as non-technical as possible. + It covers the following topics: </p> -<h2> - 1. Who has provided you with this app? -</h2> <p> - The Corona-Warn-App (the “<strong>App</strong>â€) is provided by the Robert - Koch Institute, Nordufer 20, 13353 Berlin (the “<strong>RKI</strong>â€). + 1. Who is the Corona-Warn-App published by? </p> <p> - The RKI is also what is called the controller under data protection law, - meaning it is responsible for the processing of App users’ data. + 2. Is using the app voluntary? </p> <p> - You can contact the RKI’s data protection officer at the above address - (“FAO the data protection officerâ€) and by emailing: datenschutz@rki.de. + 3. On what legal basis is your data processed? </p> -<h2> - 2. Is using the App voluntary? -</h2> <p> - Using the App is entirely voluntary. It is your decision alone whether and - how you use the App. + 4. Who is the app aimed at? </p> <p> - Although installing and using the App is voluntary, if you wish to use the - exposure logging feature you still have to grant the RKI your consent to - let the App process your personal data. You do this by tapping on the - “Enable Exposure Logging†button the first time you open the App. If the - App identifies a potential risk of infection for you, then your data also - includes health data. Your consent is necessary because otherwise the App - will not be able to access your smartphone’s exposure logging feature. You - can, however, use the toggle switch in the App to disable the exposure - logging feature at any time. Doing this will mean that you are unable to - use the full functionality of the App. Separate consent is also required - for the data processing performed for the following features: + 5. What data is processed? </p> -<ul> - <li> - Registering a test (see 6 b.) - </li> - <li> - Sharing your test result (see 6 c.). - </li> -</ul> <p> - The data processing performed in connection with these features is - described in more detail in the following sections. + 6. Why is your data processed? </p> -<h2> +<p> + 7. How does the transnational warning system work? +</p> +<p> + 8. What permissions does the app require? +</p> +<p> + 9. When will your data be deleted? +</p> +<p> + 10. Who will receive your data? +</p> +<p> + 11. Is your data transferred to countries outside the EU? +</p> +<p> + 12. How can you withdraw your consent? +</p> +<p> + 13. What other rights do you have under data protection law? +</p> +<p> + 14. Data protection officer and contact +</p> +<p> + To make sure that this text can be understood by all users, we have made + every effort to make it simple and as non-technical as possible. +</p> +<h1> + 1. Who is the Corona-Warn-App published by? +</h1> +<p> + This app is published by the Robert Koch Institute (<strong>RKI</strong>) + for the German Federal Government. The RKI is also responsible for ensuring + that your data is processed in accordance with data protection regulations. +</p> +<p> + If you are infected and voluntarily use the transnational warning feature, + it is also possible to warn users of the official coronavirus apps of other + participating countries with whom you have been in contact. In this case, + the RKI and the competent health authorities of the countries participating + in the transnational warning system are so-called joint controllers, + meaning they are jointly responsible for data processing. Please refer to + Section 7 for more details. +</p> +<h1> + 2. Is using the app voluntary? +</h1> +<p> + Using the app is voluntary. It is entirely up to you whether you install + the app, which of the app’s features you use, and whether you share data + with others. All of the app’s features that require data transfer will + obtain your express consent in advance. If you do not give your consent or + if you subsequently withdraw it, this will not result in any disadvantages + for you. +</p> +<h1> + 3. On what legal basis is your data processed? -</h2> +</h1> <p> - In principle, the RKI will process your personal data only on the basis of - your consent granted pursuant to Article 6(1) Sentence 1(a) and Article - 9(2)(a) of the General Data Protection Regulation (GDPR). If you have - granted your consent, you can withdraw it at any time. Further information - on your right of withdrawal and instructions on how to exercise this right - can be found under 11. + Your data will only be processed on the basis of your explicit consent. The + legal basis is Art. 6(1) Sentence 1(a) GDPR and, in the case of health + data, Art. 9(2)(a) GDPR. After granting your consent, you can withdraw it + at any time. Please refer to Section 12 for further information about your + right of withdrawal. </p> -<h2> - 4. Who is the App aimed at? -</h2> +<h1> + 4. Who is the app aimed at? +</h1> <p> - The App is aimed at people who are resident in Germany and at least 16 + The app is aimed at people who are resident in Germany and at least 16 years old. </p> -<h2> - 5. What personal data is processed? -</h2> +<h1> + 5. What data is processed? +</h1> <p> - The App is designed to process as little personal data as possible. This - means, for example, that the App does not collect any data that would allow - the RKI or other users to infer your identity, health status or location. - In addition, the App deliberately refrains from using tracking tools to - record or analyse how you use the App. + The app has been programmed to process as little personal data as possible. + This means that the app does not collect any data that would allow the RKI + or other users to infer your identity, your name, your location or other + personal details. The app does not therefore use any analysis tools to + evaluate the way you use it. </p> <p> - The data processed by the App can be grouped into the following categories: + The data processed by the app can be grouped into the following categories: </p> -<h3> +<h2> a. Access data -</h3> +</h2> <p> - Access data is generated when you use or enable the following features: + Every time the app exchanges data over the internet with the RKI’s server + system (hereinafter referred to as the <strong>server system</strong>), the + server system processes so-called access data. This is necessary so that + the app can retrieve current data (e.g. for warnings) or transmit certain + data stored on your smartphone to the server system. This access data + includes the following: </p> <ul> <li> - Exposure Logging + IP address + </li> + <li> + Date and time of retrieval </li> <li> - Registering a test + Transmitted data volume (or packet length) </li> <li> - Sharing your test result. + Notification of whether the data exchange was a success. </li> </ul> <p> - Each time data is retrieved from the App’s server system, your IP address - (on the upstream load balancer) is masked and no longer used within the - App’s server system. + This access data is processed to maintain and secure the technical + operation of the app and the server system. You are not identified + personally as a user of the app and no user profile will be created. Your + IP address will not be stored beyond the end of the usage procedure. </p> <p> - The following data is also processed: + In order to prevent unauthorised parties from using your IP address to + associate your data with you when you use the app, the app only ever + accesses the server system via a special access server. This access server + then forwards the data requested or transmitted by the app to the + appropriate server, but without your IP address, meaning that your IP + address is no longer processed within the server system. +</p> +<h2> + b. Exposure data +</h2> +<p> + As soon as you enable your iPhone’s or your Android smartphone’s COVID-19 + Exposure Notification System (which is called “Exposure Notification†or + “COVID-19 Exposure Notifications†respectively), your smartphone transmits + so-called exposure data via Bluetooth, which other smartphones in your + vicinity can record. Your smartphone, in turn, also receives the exposure + data of other smartphones. The exposure data transmitted by your smartphone + comprises: </p> <ul> <li> - Date and time of retrieval (time stamp) + Random identification numbers (hereinafter referred to as <strong>random IDs</strong>) </li> <li> - Transmitted data volume (or packet length) + Bluetooth protocol version </li> <li> - Notification of successful retrieval. + Bluetooth transmit power in decibel-milliwatts (dBm). </li> </ul> <p> - This access data is only processed to secure and maintain the technical - infrastructure. You are not identified personally as a user of the App and - it is not possible to create a user profile. The IP address will not be - saved beyond the end of the period of use. -</p> -<h3> - b. Contact data -</h3> -<p> - If you enable exposure logging in your smartphone’s operating system, which - serves to record encounters (contacts) with other users, then your - smartphone will continuously send out randomly generated identification - numbers (“<strong>random IDs</strong>â€) via Bluetooth Low Energy, which - other smartphones in your vicinity can receive if exposure logging is also - enabled on them. Your smartphone, in turn, also receives the random IDs of - the other smartphones. In addition to the random IDs received from other - smartphones, your smartphone’s exposure logging functionality records and - stores the following contact data: + If exposure to another smartphone is recorded, the exposure data also + includes: </p> <ul> <li> - Date and time of the contact + Day, time and duration of the contact </li> <li> - Duration of the contact + Bluetooth signal strength in dBm. </li> +</ul> +<p> + The random IDs are changed regularly. This helps prevent your smartphone + from being identified using these random IDs. The exposure data transmitted + by your smartphone and the exposure data recorded when you come into + contact with other app users are stored on your smartphone and deleted + after 14 days. The exposure data transmitted by your smartphone is + processed in the same way when it is recorded by the smartphones of other + app users. +</p> +<p> + Please note: the COVID-19 Exposure Notification System functionality is + part of your operating system. The providers responsible for this system + are therefore Apple (if you have an iPhone) and Google (if you have an + Android smartphone). In this respect, the data processing is subject to + these companies’ own privacy policies, which means that the RKI is not + responsible for this and has no influence on it. Depending on the version + and configuration of your operating system, the actual names, operating + steps and settings options may differ from those described in this privacy + notice. More information is available from the respective providers: +</p> +<ul> <li> - Bluetooth signal strength of the contact + If you have an Android smartphone, you can find information from Google + on your device by going to “Settings†> “Google†> “COVID-19 + exposure notifications†and tapping on “Learn moreâ€. </li> <li> - Encrypted metadata (protocol version and transmission strength). + If you have an iPhone, you can find information from Apple on your + device by going to “Settings†> “Exposure Notifications†and tapping + on “How Exposure Notifications work ...â€. </li> </ul> -<p> - Your own random IDs and those received from other smartphones as well as - the other contact data (date and time of the contact, duration of the - contact, signal strength of the contact and encrypted metadata) are - recorded by your smartphone in an exposure log and currently stored there - for 14 days. -</p> -<p> - The functionality used to record encounters with other users is called - “COVID-19 Exposure Notifications†on Android smartphones and “COVID-19 - Exposure Logging†on iPhones. Please note that this exposure logging - functionality is not part of the App, but an integral part of your - smartphone's operating system. This means that the exposure logging - functionality is provided to you by Apple (iPhones) or Google (Android - smartphones) and is subject to these companies’ respective privacy - policies. The RKI has no influence on data processing performed by the - operating system in connection with exposure logging. -</p> -<p> - More information about the exposure logging functionality on Android - smartphones is available at: - https://support.google.com/android/answer/9888358?hl=en. -</p> -<p> - More information about Apple’s exposure logging functionality can be found - in your iPhone’s settings under “Privacy†> “Health†> "COVID-19 - Exposure Loggingâ€. Please note that the exposure logging functionality is - only available if iOS version 13.5 or higher is installed on your iPhone. -</p> -<p> - The App will only process the contact data generated and stored by your - smartphone if the App’s exposure logging feature is enabled. -</p> -<h3> +<h2> c. Health data -</h3> -<p> - Health data is any data containing information about the health of a - particular individual. This includes not only information about past and - current illnesses, but also about a person’s risk of illness (such as the - risk that the person has been infected with the coronavirus). -</p> +</h2> <p> - The following cases involve processing health data: + Health data is any data containing information about a person’s health. + This includes not only information about past and current illnesses, but + also about a person’s risk of illness (such as the risk that a person has + been infected with coronavirus). The app processes health data in the + following cases: </p> <ul> <li> - If the exposure logging feature detects that you may have been in - contact with a person who has been infected with the coronavirus. + When a possible exposure is identified </li> <li> - If you register your test. + If you register a test or a positive test result </li> <li> - If you share a positive test result. + If you retrieve a positive test result in the app + </li> + <li> + If you use the app to warn other users that they may be infected + </li> + <li> + If you provide information about the onset of any coronavirus symptoms. </li> </ul> +<p> + Section 6 explains this in more detail. +</p> +<h1> + 6. Why is your data processed? +</h1> <h2> - 6. App features -</h2> -<h3> a. Exposure Logging -</h3> +</h2> <p> - The App’s core functionality is exposure logging. This serves to track - possible contacts with other users of the App who are infected with the - coronavirus, to evaluate the risk that you yourself have been infected, and - – based on the risk identified – to provide you with health advice and + Exposure logging is part of the app’s main functionality. It serves to + warn you of possible contacts with persons who have tested positive for + coronavirus (“possible exposuresâ€) in a number of different countries, to + assess the risk that you yourself have been infected as a result of one of + those contacts, and to provide you with appropriate health advice and recommendations for what to do next. </p> <p> - If you enable the exposure logging feature, then several times a day while - the App runs in the background (or when you tap on “Updateâ€), the App will - retrieve a list from the App’s server system of random IDs from users who - have tested positive and shared their own random IDs. The App shares these - random IDs with your smartphone’s exposure logging functionality, which - then compares them with the random IDs stored in your smartphone’s exposure - log. If your smartphone’s exposure logging functionality detects a match, - it transfers the contact data (date, duration, signal strength) to the App, - but not the random ID of the contact in question. -</p> -<p> - In the event of a contact, the App analyses the contact data provided by - the exposure logging functionality in order to determine your individual - risk of infection. The evaluation algorithm which determines how the - contact data is interpreted (for example, how the duration of a contact - influences the risk of infection) is based on current scientific findings. - To account for new findings as and when they arise, the RKI can update the - evaluation algorithm by adjusting its settings. The settings for the - evaluation algorithm are sent to the App together with the list of random - IDs of infected users. -</p> -<p> - The identification of your risk of infection is only carried out locally on - your smartphone, meaning that the data is processed offline. Once - identified, the risk of infection is also only stored in the App and is not - passed on to any other recipients (including the RKI, Apple, Google and - other third parties). -</p> -<p> - The legal basis for the processing of your access data, contact data and, - if applicable, health data (if the App determines that you may have been - infected) described above is your consent which you gave when enabling the - exposure logging feature. + For this purpose, the app runs in the background and retrieves an + up-to-date list every day of random IDs, and possible information about the + onset of symptoms, from the server system. This list contains the random + IDs and possible symptom information of users who have tested positive for + coronavirus and voluntarily used the warning feature in their app, which is + the official coronavirus app in any country participating in the + transnational warning system (see Section 7) (hereinafter referred to as a <strong>positive + list</strong>). The random IDs in the positive list also + contain a transmission risk value and an indication of the type of + diagnosis (see Section 6 c.). +</p> +<p> + The app passes the random IDs to the COVID-19 Exposure Notification System, + which compares them with the random IDs it has recorded. If the COVID-19 + Exposure Notification System detects a match, it transfers to the app the + exposure data recorded for the possible exposure in question. The app + evaluates this data as well as the information in the positive list + (transmission risk value; information about the onset of symptoms) in order + to determine your risk of infection. The evaluation algorithm which + determines how this information is evaluated (for example, how the duration + of a contact influences the risk of infection) is based on the RKI’s latest + scientific findings. In the event of new findings, the RKI can update the + evaluation algorithm by adjusting the evaluation settings in the app. In + this case, the new evaluation settings are sent to the app together with + the positive list. +</p> +<p> + The risk of infection is calculated exclusively within the app and is not + passed on to the COVID-19 Exposure Notification System or any other + recipient (including the RKI, other health authorities in Germany or other + countries, Apple, Google and other third parties). </p> -<h3> +<h2> b. Registering a test -</h3> -<p> - If you have been tested for the coronavirus, you can register the test in - the App by scanning the QR code which you received from your doctor or the - testing facility. The app will then inform you as soon as the test result - is available from the laboratory. -</p> +</h2> <p> - For this to work, the testing laboratory needs to be connected to the App’s + If you have been tested for coronavirus, you can register your test in the + app. The app will then notify you as soon as the test result is available. + For this to work, the testing laboratory needs to be connected to the server system and, as part of the testing procedure, you must have agreed - separately to the laboratory transmitting your test result to the App’s - server system (test result database). Test results from laboratories that - are not connected to the App’s server system cannot be displayed in the - App. If you have not received a QR code, the testing laboratory is not - connected. In this case you will not be able to use this feature. + separately to the laboratory transmitting your test result to the server + system (test result database). It is not possible to display test results + from laboratories that are not connected to the server system. If you have + not received a QR code, then you cannot use this feature. </p> <p> <u>Registering a test</u> </p> <p> - To receive the test result in the App, you must first register the test you - have taken in the App. For this purpose, your doctor or the testing - facility will provide you with a QR code when taking the sample. This QR - code contains a code number which can be read with a QR code scanner. To - register your test, you will need to scan the QR code in the App using your - smartphone’s camera. -</p> -<p> - The code number read from the QR code is then hashed by the App, which - means that the App performs a certain mathematical procedure in order to - convert the code number in such a way that it can no longer be recognised. - As soon as your smartphone is connected to the internet, the App will - transmit the hashed code number to the App’s server system. In return, the - App receives a token from the server system, i.e. a digital access key that - is stored in the App. The token is linked to the hashed code number on the - server system. The App then deletes the hashed code number on your - smartphone. The server system will only issue a token once for each hashed - code number. This ensures that your QR code cannot be used by other users - of the App to retrieve test results. -</p> -<p> - This completes the registration of your test. + To be able to retrieve your test result in the app, you must first register + your test. Your doctor or the testing facility will provide you with a QR + code for this purpose. This QR code contains a code number which the app + can read. To register your test, you will need to scan the QR code in the + app using your smartphone’s camera. After reading the code number, the app + ‘hashes’ it. This means that the app performs a certain mathematical + procedure in order to convert the code number in such a way that it can no + longer be identified. As soon as your smartphone is connected to the + internet, the app will transmit the hashed code number to the server + system. In return, the app receives a token from the server system, i.e. a + digital access key that is stored in the app. The token is linked to the + hashed code number in the server system. The app then deletes the hashed + code number on your smartphone. This completes the registration of your + test. The server system will only issue a token once for each hashed code + number. This ensures that your QR code cannot be used by other users of the + app to retrieve test results. </p> <p> <u>Filing of the test result</u> @@ -317,429 +340,432 @@ <p> As soon as the testing laboratory receives the test result, it stores the result in the RKI’s test result database, indicating the hashed code - number. The test result database is operated by the RKI on a special server - within the App’s server system. Based on the code number contained in the - QR code issued to you, the testing laboratory also generates the hashed - code number using the same mathematical procedure as the App. + number. The test result database is located on a special server within the + server system. Based on the code number contained in the QR code issued to + you, the testing laboratory also generates the hashed code number using the + same mathematical procedure as the app. </p> <p> <u>Retrieval of the test result</u> </p> <p> - Using the token, the App regularly requests the status of the registered - test from the App’s server system. The server system then assigns the token - to the hashed code number and transfers it to the test result database. If - the test result has now been stored there, the test result database sends - the test result back to the server system, which forwards it to the App - without gaining any knowledge of the content. -</p> -<p> - If the test result is positive, the App uses the token again to request a - TAN (transaction number) from the server system. The server system - reassigns the token to the hashed code number and requests confirmation - from the test result database that a positive test result exists for the - hashed code number. If the test result database confirms this, the server - system generates the TAN and transmits it to the App. A copy of the TAN - remains on the server system. -</p> -<p> - The TAN is required to ensure that no false information is distributed to - other users in the event of a positive test result being transmitted. -</p> -<p> - The legal basis for the processing described above of the data mentioned - above is your consent to using the test registration feature. -</p> -<h3> - c. Sharing your test result -</h3> -<p> - If you use the feature for sharing your test result in order to warn other - users, the App will transfer the random IDs generated and stored by your - smartphone from the last 14 days and the TAN to the App’s server system. - The server system first checks whether the TAN is valid and then adds your - random IDs to the list of random IDs of users who have shared a positive - test result. Your random IDs can now be downloaded by other users as part - of the exposure logging process. -</p> -<p> - <u>If you have not retrieved your test result in the App:</u> -</p> -<p> - Even if you have not retrieved a positive test result in the app, you can - share the test result via the App to warn other users. In this case, the - App prompts you to enter a so-called TeleTAN, which acts as a TAN. -</p> -<p> - To obtain a TeleTAN, please call the Corona-Warn-App hotline on +49 (0)800 - 7540002. The operator will first ask you some questions over the phone to - check the plausibility of your call. These questions serve to prevent - fraudulent reports of infections and any resulting incorrect warnings and - risk status. Once you have answered these questions sufficiently, you will - be asked for your mobile/telephone number. This is so that you can be - called back later and given a TeleTAN to enter in the App. Your - mobile/telephone number will only be temporarily stored for this purpose - and deleted within one hour at the latest. -</p> -<p> - After your call, the hotline employee will generate a TeleTAN via a special - access to the App’s server system and then call you to tell you the - TeleTAN. If you enter the TeleTAN in the App, the TeleTAN will be sent back - from the App to the App’s server system for comparison and verification. In - return, the App receives a token from the server system, i.e. a digital - access key that is stored in the App. Using this token, the App then - requests a TAN from the server system. -</p> -<p> - The legal basis for this processing of your access data and health data - (random IDs, test result, TAN and, if applicable, TeleTAN) is your consent - to using the feature for sharing your test result. -</p> -<h3> - d. Using the App for information purposes only -</h3> -<p> - As long as you use the App for information purposes only, i.e. do not use - any of the App features mentioned above and do not enter any data, then - processing only takes place locally on your smartphone and no personal data - is generated. Websites linked in the app, such as www.bundesregierung.de, - will open in your smartphone’s standard browser. The data processed here - depends on the browser used, your browser settings, and the data processing - practices of the website you are visiting. + Using the token, the app regularly requests the status of the registered + test from the server system. The server system then assigns the token to + the hashed code number and transfers it to the test result database. This + checks whether a test result has now been stored for the hashed code number + and returns the result. The server system then forwards the status and the + test result requested from the test database (i.e. whether your result is + positive or negative) to the app. If you have enabled the test status + notification in the app (under “Settings†> “Notificationsâ€), you will + be notified accordingly. The test result will be displayed when you open + the app. +</p> +<p> + If you have tested positive for coronavirus, the app uses the token again + to request a TAN (transaction number) from the server system. The TAN is + required to ensure that no false warnings are transmitted to other users if + you subsequently activate the app’s warning feature. To this end, the + server system reassigns the token to the hashed code number and requests + confirmation from the test result database that a positive test result + really does exist for that hashed code number. If this is confirmed, the + server system generates the TAN and transmits it to the app. A copy of the + TAN remains on the server system. </p> <h2> - 7. What permissions and functionality does the App require? + c. Warning others </h2> <p> - The App requires access to a number of your smartphone’s features and - interfaces. For this purpose, you need to grant the App certain - permissions. Permissions are programmed differently by different - manufacturers. For example, individual permissions may be combined into - permission categories, where you can only agree to the permission category - as a whole. Please note that if the App is denied access, you will not be - able to use any or all of the App’s features. + If you have tested positive for coronavirus, you can use the transnational + warning feature to warn other people who use this app or any other official + coronavirus app in participating countries. In this case, the app transmits + the following data to the server system: </p> -<h3> - a. Technical requirements (all smartphones) -</h3> <ul> <li> - Internet + Your own random IDs from the last 14 days </li> -</ul> -<p> - The App requires an internet connection for the exposure logging feature, - and so that it can receive and transmit test results, so that it can - communicate with the App’s server system. -</p> -<ul> <li> - Bluetooth + Any information about the onset of symptoms </li> -</ul> -<p> - Your smartphone’s Bluetooth interface must be enabled for your smartphone - to record random IDs from other smartphones and store them in the device’s - exposure log. -</p> -<ul> <li> - Camera + Your TAN (see Section 6 b.). </li> </ul> <p> - Your smartphone requires a camera to be able to scan a QR code when - registering a test. + Your smartphone may first ask you for permission to pass your own random + IDs from the COVID-19 Exposure Notification System to the app. +</p> +<p> + Before transmitting the random IDs to the server system, the app adds a + transmission risk value and a specification of the type of diagnosis to + each of the random IDs (see also Section 6 a.). Since the app’s warning + feature can only be used for lab-confirmed diagnoses, the type of diagnosis + is the same for all users. The transmission risk value is an estimate of + how infectious you were on the day on which the respective random ID was + used. Since how infectious a person is or was depends on the duration and + course of the infection, it can be taken into account, for example, that + the more time has passed since the onset of symptoms, the lower the risk of + a person spreading the virus on the day of a possible exposure. +</p> +<p> + The requested information about the onset of symptoms is optional. However, + this information may help to calculate the transmission risk value more + accurately. If you do not provide information about your symptoms, then the + transmission risk values will be calculated assuming a typical case of + infection with coronavirus, i.e. the more time has passed since a random ID + was used, the lower the associated transmission risk value. +</p> +<p> + <u>If you have not retrieved your test result in the app:</u> +</p> +<p> + Even if you have not retrieved your positive test result via the app, you + can still warn your fellow human beings. To do this, select the “Request + TAN†procedure. The app will then prompt you to call the app hotline. A + hotline worker will then ask you a few questions to make sure that you + really have tested positive for coronavirus. This is to prevent false + warnings being transmitted, either by accident or intentionally. Once you + have answered these questions sufficiently, you will be asked for your + mobile/telephone number and your name. This is so that you can be called + back later and given what’s called a TeleTAN to enter in the app. Your + mobile/telephone number and your name will be temporarily stored for this + purpose only and deleted after an hour at the latest. Immediately after + your call, the hotline worker will generate your TeleTAN via a special + access to the server system and then call you back to tell you your + TeleTAN. A TeleTAN is only valid for one hour and will therefore be deleted + no later than one hour after it has been passed on to you. After a valid + TeleTAN is entered in the app, it is transmitted to the server system for + verification. Upon successful verification, the app receives a token from + the server system, i.e. a digital access key that is stored in the app. + Using this token, the app then requests a TAN from the server system. +</p> +<h2> + d. Using the app for information purposes only +</h2> +<p> + As long as you use the app for information purposes only, i.e. do not use + any of the features mentioned above, then processing only takes place + locally on your smartphone and the RKI will not process any personal data. + Websites linked in the app, such as www.bundesregierung.de, are + opened and displayed in your smartphone’s standard browser (Android + smartphones) or within the app (iPhones). The data processed here is + determined by the respective providers of the websites accessed. +</p> +<h1>7. How does the transnational warning system work? + +</h1> +<p> + To ensure that users are also warned by the official coronavirus apps of + other countries, the RKI, together with several official healthcare bodies + and authorities in other countries (hereinafter referred to as <strong>health + authorities</strong>) has set up a central warning server + for sharing warnings between countries (hereinafter referred to as the <strong>exchange + server</strong>). The exchange server uses the digital + infrastructure of the eHealth Network established between the Member + States. +</p> +<p> + The national server systems of the coronavirus apps connected to the + exchange server regularly transmit their own positive lists to the exchange + server and receive the positive lists of the other countries. +</p> +<p> + The server system merges the positive lists received in this way with its + own positive list, which allows the exposure logging feature to also + take into account possible exposures involving users of another coronavirus + app (see point 6 c.) The other participating countries proceed in the same + way with the positive lists provided by the RKI. +</p> +<p> + Only countries whose coronavirus apps are compatible with each other and + which guarantee a comparably high level of data protection can participate + in the joint exchange server. In particular, this requires that the + coronavirus apps of the participating countries also use the COVID-19 + Exposure Notification System, are approved by the respective national + health authorities, and respect the privacy of their users. The technical + and organisational details of this cooperation are laid down in an EU + Commission Decision (Commission Implementing Decision (EU) 2020/1023 of 15 + July 2020, which is available at + https://eur-lex.europa.eu/eli/dec_impl/2020/1023/oj ). +</p> +<p> + Together with the respective competent health authorities of the + participating countries, the RKI is a joint controller under data + protection law, meaning it is responsible for processing the information + contained in the positive lists (random IDs and, if applicable, information + about the onset of symptoms) on the exchange server in order to enable the + transnational exposure logging and warning system. +</p> +<p> + Please note that the list of participating countries is subject to change. + The current list, with details of the competent health authorities in each + case, can be found in the FAQs available at + https://www.coronawarn.app/en/faq/#interoperability_countries . +</p> +<h1> + 8. What permissions does the app require? +</h1> +<p> + The app requires access to a number of your smartphone’s features and + interfaces. For this purpose, you need to grant the app certain + permissions. The permission system depends on your operating system’s + specifications. For example, your smartphone may combine individual + permissions into permission categories, where you can only agree to the + permission category as a whole. Please note that without the permissions + requested by the app, you will not be able to use some or all of the app + features. </p> +<h2> + a. Technical requirements (all smartphones) +</h2> <ul> <li> - Background operation + The app requires an internet connection in order to exchange data with + the server system. + </li> + <li> + The Bluetooth feature must be enabled so that your smartphone can + transmit its own random IDs and record the random IDs of other + smartphones. + </li> + <li> + The app needs to be able to run in the background on your smartphone in + order to automatically identify your risk of infection and check the + status of a registered test. If you deny the app permission to run in + the background, then you must start all actions in the app itself. </li> </ul> -<p> - The App runs in the background (i.e. when you are not actively using the - App) in order to be able to automatically identify your risk and query the - status of a registered test. If you deny the App permission to run in the - background in your smartphone’s operating system, then you must start all - actions in the App itself. -</p> -<h3> +<h2> b. Android smartphones -</h3> +</h2> <p> - If you are using an Android device, the following system features must also - be enabled: + If you are using an Android smartphone, the following system features must + also be enabled: </p> <ul> <li> - COVID-19 Exposure Notifications + The Android COVID-19 exposure notification system (COVID-19 Exposure + Notifications) </li> -</ul> -<p> - The App’s exposure logging feature requires this functionality. Otherwise, - no exposure log with the random IDs of your contacts will be available. The - functionality must be enabled within the App to allow the App to access the - exposure log. -</p> -<ul> <li> - Location + If you have a smartphone running on Android version 10 or lower, + location services need to be enabled for your smartphone to search for + Bluetooth signals from other smartphones. Please note that no location + data is collected in this process. </li> -</ul> -<p> - Your smartphone’s location service must be enabled for your device to - search for Bluetooth signals from other smartphones. Please note that no - location data is collected in this process. -</p> -<ul> <li> - Notification + To be notified of changes in your risk of infection and the status of + test results, the notification feature must be enabled. The + notification feature is enabled by default in the operating system. </li> </ul> <p> - The user is notified locally of the identified risk and available test - results. The necessary notification function is already enabled in the - operating system. -</p> -<p> - The App also requires the following permissions: + The app also requires the following permissions: </p> <ul> <li> - Camera + The feature for registering your test requires access to the camera in + order to read the QR code. </li> </ul> -<p> - The App requires access to the camera to read the QR code when registering - a test. -</p> -<h3> +<h2> c. iPhones (Apple iOS) -</h3> +</h2> <p> If you are using an iPhone, the following system features must be enabled: </p> <ul> <li> - COVID-19 Exposure Logging + The iOS COVID-19 exposure notification system (Exposure Notification) </li> -</ul> -<p> - The App’s exposure logging feature requires this functionality, otherwise - no exposure log with the random IDs of your contacts will be available. The - functionality must be enabled within the App to allow the App to access the - exposure log. -</p> -<ul> <li> - Notifications + Notifications must be enabled so that you can be notified of changes in + your risk of infection and the status of test results. </li> </ul> <p> - The user is notified locally of the identified risk and available test - results. Notifications must be enabled for this. -</p> -<p> - The App also requires the following permissions: + The app also requires the following permissions: </p> <ul> <li> - Camera + The feature for registering your test requires access to the camera in + order to read the QR code. </li> </ul> +<h1> + 9. When will your data be deleted? +</h1> <p> - The App requires access to the camera to read the QR code when registering - a test. + The storage period depends on the purposes or app features for which your + data has been stored. When determining the storage period, the RKI takes + into account the latest scientific findings on the incubation period (up to + 14 days) as well as on how long there is a risk of an infected person + infecting someone else after the end of the incubation period. Unless + otherwise specified under Section 6, the following storage periods apply: </p> <h2> - 8. When will data be deleted? + a. Data on your smartphone </h2> <p> - All data stored in the App is deleted as soon as it is no longer needed for - the App features: + The retrieved positive lists are deleted from the app memory after 14 days. + The infection risk determined in the app (e.g. “low riskâ€) is deleted from + the app memory after each update, but after 14 days at the latest. If you + have registered a positive coronavirus test, the token in the app memory is + deleted as soon as you activate the warning feature. </p> -<h3> - a. Exposure Logging -</h3> -<ul> - <li> - The list of random IDs of users who have shared a positive test result - will be deleted from the App immediately, and also automatically - deleted from your smartphone’s exposure log after 14 days. - </li> - <li> - The RKI has no way of influencing the deletion of contact data in your - smartphone’s exposure log (including your own random IDs) and contact - data on other smartphones, as this functionality is provided by Apple - or Google. In this case, the deletion depends on what Apple or Google - has determined. Currently, the data is automatically deleted after 14 - days. It may also be possible, using the functionality provided by - Apple and Google, to manually delete data in your device’s system - settings. - </li> - <li> - The risk status displayed in the App will be deleted as soon as a new - risk status has been determined. A new risk status is usually - determined after the App has received a new list of random IDs. - </li> -</ul> -<h3> - b. Registering a test -</h3> -<ul> - <li> - The hashed code number will be deleted from the App’s server system - after 21 days. - </li> - <li> - In the event of a negative test result, the hashed code number and the - test result will be deleted from the test result database immediately - after the test result is retrieved; and in the event of a positive test - result, they will be deleted immediately after the copy of the TAN - stored on the server system is deleted (see below). - </li> - <li> - The token stored on the server system will be deleted after 21 days. - </li> - <li> - The token stored in the app will be deleted from the smartphone after - the App is deleted or after using the feature for sharing the test - result. - </li> -</ul> -<h3> - c. Sharing your test result -</h3> -<ul> - <li> - Your smartphone’s own random IDs which are shared in the App will be - deleted from the server system after 14 days. - </li> - <li> - The copy of the TAN stored on the server system will be deleted after - 21 days. - </li> - <li> - The TAN stored in the App will be deleted after the test result has - been shared. - </li> - <li> - The TeleTAN stored in the App will be deleted after the test result has - been shared. - </li> - <li> - The TeleTAN stored on the server system will be deleted after 21 days. - </li> - <li> - The TeleTAN sent to the hotline employee will be deleted there - immediately after it has been passed on to you by telephone. - </li> - <li> - The token stored on the server system will be deleted after 21 days. - </li> - <li> - The token stored in the App will be deleted after the test result has - been shared. - </li> -</ul> <h2> - 9. Who will receive your data? + b. Data on server systems </h2> <p> - If you share a test result to warn other users, your random IDs from the - last 14 days will be passed on to the App on other users’ smartphones. + Positive lists are deleted from all server systems (including exchange + servers) after 14 days. All other data will be deleted after 21 days at the + latest. +</p> +<h1> + 10. Who will receive your data? +</h1> +<p> + If you warn other users via the app, your random IDs from the last 14 days + as well as optional information you provide about the onset of your + symptoms will be forwarded to the competent health authorities of each of + the countries participating in the exchange server. From there, they will + be passed on to the server systems of the coronavirus apps of those + countries participating in the transnational warning system. The server + systems of the national coronavirus apps then distribute your data to their + own users as part of the positive lists. +</p> +<p> + The competent national health authorities in the participating countries + have commissioned the EU Commission, as data processor, to operate and + maintain the joint warning system. </p> <p> The RKI has commissioned T-Systems International GmbH and SAP Deutschland SE & Co. KG to operate and maintain part of the technical - infrastructure of the App (e.g. server system, hotline), meaning that these + infrastructure of the app (e.g. server system, hotline), meaning that these two companies are processors under data protection law and acting on the - RKI’s behalf (Article 28 GDPR). + RKI’s behalf. The EU Commission has also commissioned these companies, as + sub-processors, with the technical provision and management of the + participating countries’ joint warning system. </p> <p> - Otherwise, the RKI will only pass on personal data collected in connection - with your use of the App to third parties if the RKI is legally obliged to - do so or if this is necessary for legal action or criminal prosecution in - the case of attacks on the App’s technical infrastructure. In other cases, + Otherwise, the RKI will only pass on your data collected in connection with + your use of the app to third parties if the RKI is legally obliged to do so + or if this is necessary for legal action or criminal prosecution in the + case of attacks on the app’s technical infrastructure. In other cases, personal data will not generally be passed on. </p> -<h2> - 10. Is data transferred to a third country? -</h2> +<h1> + 11. Is your data transferred to countries outside the EU? +</h1> <p> - The data generated when the App is used is processed exclusively on servers - in Germany or in another EU or EEA member state. + If you activate the app’s warning feature, the coronavirus apps connected + to the shared exchange server can retrieve the current positive lists + worldwide, which means that users who are currently abroad on holiday or + business trips, for example, can also be warned. Otherwise, the data + transmitted by the app is processed exclusively on servers in Germany or in + another country in the EU (or the European Economic Area), which are + therefore subject to the strict requirements of the General Data Protection + Regulation (GDPR). </p> -<h2> - 11. Withdrawal of consent -</h2> +<h1> + 12. How can you withdraw your consent? +</h1> <p> - You have the right to withdraw any consent you granted the RKI in the App + You have the right to withdraw any consent you granted the RKI in the app at any time with effect for the future. Please note that this will not affect the lawfulness of the processing before the withdrawal. </p> +<h2> + a. Consent to exposure logging +</h2> <p> - To withdraw your consent to the exposure logging feature, you can disable - the feature using the toggle switch in the App or delete the App. If you - decide to use the exposure logging feature again, you can toggle the - feature back on or reinstall the App. -</p> -<p> - To withdraw your consent to the test registration feature, you can delete - the test registration in the App. The token for retrieving the test result - will then be deleted from your device. Neither the RKI nor the testing - laboratory can then assign the transmitted data to your App or smartphone. - If you wish to register another test, you will be asked to grant your - consent again. + To withdraw your consent, you can disable the exposure logging feature + or delete the app. If you would like to use the exposure logging feature + again, you can re-enable the feature or reinstall the app. </p> +<h2> + b. Consent to test registration +</h2> <p> - To withdraw your consent to the sharing of your test result, you must - delete the App. All of your random IDs stored in the App will then be - removed and can no longer be assigned to your smartphone. If you wish to - report another test result, you can reinstall the App and grant your - consent again. Alternatively, you may be able to delete your own random IDs - in the exposure log in your smartphone’s system settings. Please note that, - once transmitted, the RKI has no way of deleting your random IDs from the - lists and from other users’ smartphones. + To withdraw your consent, you can delete the test registration in the app. + The token for retrieving the test result will consequently be deleted from + the app memory, so that the token can no longer be assigned on the server + system. It will not be possible to register the same test again. If you + wish to register a new test, you will be asked to grant your consent again. </p> <h2> - 12. Your other rights under data protection law + c. Consent to warning feature </h2> +<p> + To withdraw your consent, you will need to delete the app. Your random IDs + already transmitted to the server system will consequently be deleted from + the app memory and can no longer be assigned. If you wish to activate the + warning feature again, you will need to reinstall the app and grant your + consent again. Once registered in the app, a test result cannot be used + again to warn others. +</p> +<p> + Once your random IDs and transmission risk values have been transmitted, + the RKI has no way of deleting them from the positive lists distributed by + the server system or from users’ smartphones. If you also wish to delete + your exposure data stored in the COVID-19 Exposure Notification System, you + may be able to manually delete it in your smartphone’s system settings. + Please also note the information in Section 5 b. +</p> +<h1> + 13. What other rights do you have under data protection law? +</h1> <p> If the RKI processes your personal data, you also have the following data protection rights: </p> <ul> <li> - the rights under Articles 15, 16, 17, 18, 20 and 21 GDPR, + The rights under Articles 15, 16, 17, 18, 20 and 21 GDPR, </li> <li> - the right to contact the official RKI data protection officer and raise - your concerns (Article 38(4) GDPR) and + the right to contact the official + RKI data protection officer + (https://www.rki.de/DE/Content/Institut/OrgEinheiten/Datenschutz/Datenschutz_node.html) + and raise your concerns (Art. 38(4) GDPR) and </li> <li> the right to lodge a complaint with a competent data protection - authority. To do so, you can either contact your local supervisory - authority or the competent authority at the RKI’s headquarters. The - competent supervisory authority for the RKI is the Federal Commissioner - for Data Protection and Freedom of Information, Graurheindorfer Straße - 153, 53117 Bonn. + supervisory authority. To do so, you can either contact your local + supervisory authority or the authority responsible for the RKI. The + supervisory authority responsible for the RKI is the Federal + Commissioner for Data Protection and Freedom of Information, + Graurheindorfer Straße 153, 53117 Bonn. </li> </ul> <p> - Please note that the RKI can only fulfil the rights mentioned above if the + In respect of the joint processing performed by the transnational exchange + server, you also have these data protection rights vis-à -vis the health + authorities responsible for data processing in the countries participating + in the exchange server (see Section 7). +</p> +<p> + Please note that the rights mentioned above can only be fulfilled if the data on which your claim is based can be clearly assigned to you. This - would only be possible if the RKI were to collect further personal data - that would allow the data mentioned above to be clearly assigned to you or - your smartphone. Since this is not necessary – and not intended – for the - purposes of the App, the RKI is not obliged to collect such additional data - (Article 11(2) GDPR). Moreover, this would run counter to the stated - objective of keeping the amount of data processed for the App as low as - possible. Against this backdrop, it will not normally be possible to - directly fulfil the above data protection rights under Articles 15, 16, 17, - 18, 20 and 21 GDPR, as doing so would require additional information about - you which is not available to the RKI. -</p> -<p> - Last amended: 12 June 2020 -</p> \ No newline at end of file + would only be possible if the app were used to collect further personal + data that would allow the data transmitted to the server system to be + clearly assigned to you or your smartphone. Since this is not necessary for + the purposes of the app, the RKI is not obliged to collect such additional + data (Art. 11(2) GDPR). Moreover, this would run counter to the stated + objective of collecting as little data as possible. For this reason, it + will generally not be possible to fulfil the above data protection rights + even if you provide additional information about your identity. +</p> +<h1> + 14. Data protection officer and contact +</h1> +<p> + If you have any questions or concerns regarding data protection, you are + welcome to send them to the RKI’s official data protection officer by post + to Robert Koch-Institut, FAO the data protection officer, Nordufer 20, + 13353 Berlin, or by emailing datenschutz@rki.de. +</p> +<p> + *** +</p> diff --git a/Corona-Warn-App/src/main/assets/privacy_tr.html b/Corona-Warn-App/src/main/assets/privacy_tr.html index c92bb2077e79d129f06a306a75f3b0e8b298dc32..55243e394d5031feef9b974a735dce3ed2b231d2 100644 --- a/Corona-Warn-App/src/main/assets/privacy_tr.html +++ b/Corona-Warn-App/src/main/assets/privacy_tr.html @@ -2,756 +2,775 @@ Veri GizliliÄŸi Beyanı </p> <p> - Corona-Warn-App + Bu Veri GizliliÄŸi Beyanında, Almanya Federal Hükümetinin resmi + Corona-Warn-App’ını kullandığınızda, verilerinizin nasıl iÅŸleneceÄŸini ve + hangi veri koruma haklarına sahip olduÄŸunuzu öğreneceksiniz. </p> <p> - Bu veri gizliliÄŸi beyanı ile Corona-Warn-App'nın kullanımı esnasında hangi - verilerin toplanacağını, bu verilerin nasıl kullanılacağını ve hangi veri - koruma haklarına sahip olduÄŸunuzu öğrenirsiniz. + Burada aÅŸağıdaki konular ele alınmaktadır: </p> <p> - Tüm kullanıcıların anlayabilmesi için bu veri gizliliÄŸi beyanını mümkün - olduÄŸu kadar teknik olmayan ve basit ÅŸekilde açıklamaya çalıştık. + 1. Corona-Warn-App’ın yayımcısı kimdir? </p> -<h2> - 1. Bu uygulamayı size kim sunuyor? -</h2> <p> - Corona-Warn-App (bundan böyle "<strong>UYGULAMA</strong>") Nordufer 20, - 13353 Berlin adresinde bulunan Robert Koch-Institut (bundan böyle "<strong>RKI</strong>") - sunuyor. + 2. Uygulamanın kullanılması isteÄŸe baÄŸlı mı? </p> <p> - RKI, veri koruma hukuku açısından da UYGULAMA kullanıcılarının kiÅŸisel - verilerinin iÅŸlenmesinden sorumludur. + 3. Verileriniz iÅŸlenmesinde hangi yasal dayanaklar söz konusudur? </p> <p> - Yukarıda anılan adres (zu Händen „Behördlicher Datenschutzbeauftragter“ - – "Resmi Veri Koruma Görevlisi" dikkatine) ve datenschutz@rki.de - e-posta adresi aracılığıyla RKI'nin veri koruma görevlisine - ulaÅŸabilirsiniz. + 4. Uygulama kimleri hedefler? </p> -<h2> - 2. UYGULAMA'nın kullanımı isteÄŸe mi baÄŸlı? -</h2> -<p> - UYGULAMA'nın kullanımı tamamen isteÄŸe baÄŸlıdır. Bu sebeple, UYGULAMA'yı - kullanıp kullanmamaya ve nasıl kullanacağınıza bizzat kendiniz karar - verirsiniz. -</p> -<p> - UYGULAMA'nın yüklenmesi ve kullanımı tamamen isteÄŸe baÄŸlı olsa da, - UYGULAMA'yı ilk açtığınızda, UYGULAMA'nın maruz kalma günlüğü için kiÅŸisel - verilerinizi iÅŸleyebilmesi için "Maruz kalma günlüğünü etkinleÅŸtir" - düğmesine tıklayarak RKI'ye onayınızı beyan etmelisiniz. UYGULAMA sizin - için bir enfeksiyon riski tespit ederse, verileriniz, saÄŸlık verilerini de - oluÅŸturur. Aksi takdirde UYGULAMA akıllı telefonunuzun temas kayıt iÅŸlevine - eriÅŸemeyeceÄŸi için, Kabul etmeniz gereklidir. Maruz kalma günlüğünü - dilediÄŸinizde UYGULAMA içerisindeki butondan devre dışı bırakabilirsiniz. - Bu durumda UYGULAMA'nın tüm iÅŸlevlerini kullanamazsınız. AÅŸağıdaki - iÅŸlevlerin veri iÅŸlemesi için özel onayınız ayrıca gereklidir: -</p> -<ul> - <li> - Test kaydetme (6 b numaralı baÅŸlığa bakınız) - </li> - <li> - Test sonucunuzu paylaÅŸma (6 c numaralı baÅŸlığa bakınız) - </li> -</ul> <p> - Bu iÅŸlevler çerçevesinde yapılan veri iÅŸleme aÅŸağıdaki bölümlerde ayrıntılı - ÅŸekilde açıklanmıştır. + 5. Hangi veriler iÅŸlenir? </p> -<h2> - 3. Verileriniz hangi hukuki dayanakla iÅŸlenir? -</h2> <p> - RKI, esas itibariyle Avrupa BirliÄŸi Genel Veri Koruma Tüzüğü (GDPR) madde 6 - paragraf 1 cümle 1 bent a ve madde 9 paragraf 2 bent a uyarınca kiÅŸisel - verilerinizi sadece verdiÄŸiniz onaya dayanarak iÅŸler. VerdiÄŸiniz onayı, - dilediÄŸinizde geri alabilirsiniz. Cayma hakkınız hakkındaki diÄŸer bilgileri - ve bu hakkı nasıl kullanacağınız hakkındaki talimatları madde 11'de - bulabilirsiniz. + 6. Verileriniz niçin iÅŸleniyor? </p> -<h2> - 4. UYGULAMA kimlere yöneliktir? -</h2> <p> - UYGULAMA, Almanya'da ikamet eden ve en az 16 yaşında olan kiÅŸilere - yöneliktir. + 7. Sınır ötesi uyarı sistemi nasıl çalışır? </p> -<h2> - 5. Hangi kiÅŸisel veriler iÅŸlenir? -</h2> <p> - UYGULAMA, mümkün olduÄŸu kadar az sayıda kiÅŸisel veri iÅŸlenecek ÅŸekilde - tasarlanmıştır. Bununla kastedilen, örneÄŸin UYGULAMA RKI ya da diÄŸer - kullanıcıların kimliÄŸinizi, saÄŸlık durumunuzu ya da konumunuzu öğrenmesine - imkan verecek bilgileri toplamadığıdır. UYGULAMA ayrıca, kullanım - davranışınızın izleme araçları (Tracking Tool) tarafından tespit ya da - analiz edilmesine imkan tanımaz. + 8. Uygulamanın hangi izinlere gerek duyar? </p> <p> - UYGULAMA tarafından iÅŸlenen veriler aÅŸağıdaki kategorilere ayrılır: + 9. Verileriniz ne zaman silinir? </p> <p> - <strong>a. EriÅŸim verileri</strong> + 10. Verileriniz kime aktarılır? </p> <p> - AÅŸağıdaki iÅŸlevleri kullanıyorsanız veya etkinleÅŸtiriyorsanız, eriÅŸim - verileri oluÅŸur: + 11. Verileriniz AB dışındaki ülkelere aktarılacak mı? + </p> -<ul> - <li> - Maruz kalma günlüğü - </li> - <li> - Test kaydetme - </li> - <li> - Test sonucunuzu paylaÅŸma - </li> -</ul> <p> - UYGULAMA'nın sunucu sisteminden her veri çağırdığınızda, IP adresiniz - (sunucular arası yükü dengeleyen Load Balancer'da) gizlenir ve sonraki - iÅŸlemlerde UYGULAMA'nın sunucu sistemleri dahilinde iÅŸlenmez. + 12. Onayınızı nasıl geri alabilirsiniz? </p> <p> - Ek olarak, aÅŸağıdaki veriler iÅŸlenir: + 13. BaÅŸka hangi veri koruma haklarına sahipsiniz? </p> -<ul> - <li> - Çağırmanın tarih ve saati (zaman kaydı) - </li> - <li> - taşınan veri miktarı (örn., paket uzunluÄŸu) - </li> - <li> - BaÅŸarılı çağırmalar hakkında bildirim - </li> -</ul> <p> - Bu eriÅŸim verileri sadece teknik alt yapının emniyeti ve korunması için - iÅŸlenir. UYGULAMA'nın kullanıcısı olarak kiÅŸisel kimliÄŸiniz belirlenmez ve - bir kullanım profili oluÅŸturulmaz. Kullanım sürecinden sonra IP adresiniz - saklanmaz. + 14. Veri koruma görevlisi ve iletiÅŸim </p> <p> - <strong>b. Maruz kalma verileri</strong> + Bu metnin tüm kullanıcılar için anlaşılabilir olması amacıyla, mümkün + olduÄŸunca basit ve teknik terimler içermeyen bir metin hazırladık. </p> +<h1> + 1. Corona-Warn-App’ın yayımcısı kimdir? +</h1> <p> - Akıllı telefonunuzda, iÅŸletim sistemindeki diÄŸer kullanıcılar için temas - kaydı iÅŸlevini etkinleÅŸtirirseniz, akıllı telefonunuz yakın çevrenizdeki - temas kaydı etkinleÅŸtirilmiÅŸ akıllı telefonlardan alınan rastgele - kimlikleri (bundan böyle: "<strong>Rastgele Kimlikler"</strong>) olarak da - anılan, sürekli rastgele oluÅŸturulan tanıtıcı numaraları Bluetooth Low - Energy aracılığıyla gönderir. Aynı ÅŸekilde, akıllı telefonunuz da diÄŸer - akıllı telefonların rastgele kimliklerini alır. DiÄŸer akıllı telefonlardan - alınan rastgele kimliklere, akıllı telefonunuzun temas kayıt iÅŸlevi ve - ayrıca aÅŸağıdaki maruz kalma verileri kaydedilir ve saklanır: + Bu Uygulama, Almanya Federal Hükümeti için Robert Koch-Institut (Robert + Koch Enstitüsü) (<strong>RKI</strong>) tarafından yayımlanmaktadır. RKI, + ayrıca verilerinizin, veri gizliliÄŸi kurallarına uygun olarak iÅŸlenmesinden + de sorumludur. </p> -<ul> - <li> - Temasın tarihi ve saati - </li> - <li> - Temasın süresi - </li> - <li> - Temasın Bluetooth sinyal gücü - </li> - <li> - ÅžifrelenmiÅŸ meta veriler (protokol sürümü ve verici gücü). - </li> -</ul> <p> - Akıllı telefonunuzun kendi rastgele kimliÄŸi ve diÄŸer akıllı telefonlardan - alınan rastgele kimlikler ve diÄŸer maruz kalma verileri (temasın tarihi ve - saati, temasın süresi, temasın sinyal gücü ve ÅŸifrelenmiÅŸ meta veriler) - akıllı telefonunuz tarafından temas kayıt iÅŸlevinin temas protokolünde - kaydedilir ve halihazırda 14 gün boyunca saklanır. + Enfekte olduysanız ve gönüllü olarak sınır ötesi bir uyarı + tetiklediÄŸinizde, katılımcı ülkelerdeki resmi Korona uygulamalarının + kullanıcılarıyla bir temas söz konusu olursa, bu kiÅŸilerin uyarılması + saÄŸlanır. Bu durumda, hem RKI, hem de sınır ötesi uyarı sistemine katılan + ülkelerin yetkili saÄŸlık kurumları, verilerin iÅŸlenmesinden müştereken + sorumlu olur. Ayrıntılar için Madde 7’ye bakın. </p> +<h1> + 2. Uygulamanın kullanılması isteÄŸe baÄŸlı mı? +</h1> <p> - Android akıllı telefonlarda bu temas kayıt iÅŸlevinin adı "COVID-19 Temas - Bildirimleri Sistemi" ve iPhone'larda "COVID-19'a Maruz Kalma Günlüğü"dür. - Bu temas kayıt iÅŸlevlerinin UYGULAMA'nın parçası olmadığını, aksine akıllı - telefonunuzun iÅŸletim sisteminin ayrılmaz bir parçası olduÄŸunu - hatırlatırız. Temas kayıt iÅŸlevi bu yüzden size Apple (iPhone) ve Google - (Android akıllı telefonlar) tarafından hazırlanır ve bu yüzden bu - iÅŸletmelerin veri koruma kurallarına tabidir. Temas kayıt iÅŸlevi - çerçevesindeki iÅŸletim sistemindeki veri iÅŸleme, RKI'nin etki alanının - dışında kalır. + Uygulamanın kullanımı isteÄŸe baÄŸlıdır; Uygulamayı yüklemeniz, Uygulamanın + hangi iÅŸlevlerini kullanmanız ve verileri diÄŸer kiÅŸilerle paylaÅŸmanız + noktasında yalnızca siz karar verirsiniz. Uygulamanın veri aktarımını + gerektiren tüm iÅŸlevleri, öncesinde sizin açık bir ÅŸekilde onay vermenizi + ister. Onay vermezseniz veya sonradan bu onayı geri alırsanız, bu durum + sizin için bir sakınca doÄŸurmaz. </p> +<h1> + 3. Verileriniz iÅŸlenmesinde hangi yasal dayanaklar söz konusudur? + +</h1> <p> - Android akıllı telefonların temas kayıt iÅŸlevine iliÅŸkin diÄŸer bilgilere ÅŸu - adresten eriÅŸebilirsiniz: - https://support.google.com/android/answer/9888358?hl=de. + Verileriniz esas itibariyle yalnızca açık bir ÅŸekilde verdiÄŸiniz onay + temelinde iÅŸlenir. Bu baÄŸlamdaki yasal dayanak, GVKT (Genel Veri Koruma + Tüzüğü) madde 6, fıkra 1, cümle 1, bent a ve saÄŸlık verileri durumundaki + yasal dayanak ise GVKT madde 9, fıkra 2, bent a’dır. VerdiÄŸiniz onayı, + istediÄŸiniz zaman geri alabilirsiniz. Onayınız geri alma hakkı ile ilgili + ayrıntılı bilgileri madde 12’de bulabilirsiniz. </p> +<h1> + 4. Uygulama kimleri hedefler? +</h1> <p> - Apple'ın temas kayıt iÅŸlevi ile ilgili diÄŸer bilgilere, iPhone'unuzun - ayarlar kısmındaki "Gizlilik" > "SaÄŸlık" > "COVID-19'a Maruz Kalma - Günlüğü" kısmından eriÅŸebilirsiniz. Lütfen dikkat ediniz: Temas kayıt - iÅŸlevini, iPhone'unuzda Sürüm 13.5 ve üstü iOS iÅŸletim sistemleri yüklüyse, - kullanabilirsiniz. + Uygulama, en az 16 yaşında olan ve Almanya’da yaÅŸayan kiÅŸilere yönelik + hazırlanmıştır. </p> +<h1> + 5. Hangi veriler iÅŸlenir? +</h1> <p> - Akıllı telefonun oluÅŸturduÄŸu ve sakladığı maruz kalma verileri UYGULAMA - tarafından, sadece maruz kalma günlüğü etkinleÅŸtirildiyse iÅŸlenir. + Uygulama, mümkün olduÄŸunca az kiÅŸisel verileri iÅŸleyecek ÅŸekilde + programlanmıştır. Bu, Uygulama, RKI’nin veya diÄŸer kullanıcıların sizin + kimliÄŸinizi, adınızı, konumunuzu veya diÄŸer kiÅŸisel bilgilerinizi + öğrenmesine olanak tanıyan verileri toplamadığı anlamına gelir. Dolayısıyla + Uygulama, analiz araçları üzerinden kullanıcı davranışınızın herhangi bir + deÄŸerlendirmesini yapmaz. </p> -<h3> - a. SaÄŸlık verileri -</h3> <p> - SaÄŸlık verileri, belirli bir kiÅŸinin saÄŸlık durumuna iliÅŸkin bilgiler - içeren tüm verilerdir. Bunlara sadece eski ve güncel hastalıklara iliÅŸkin - bilgiler deÄŸil, ayrıca bir kiÅŸinin hastalık risklerine iliÅŸkin bilgiler de - dahildir (örn. kiÅŸiye koronavirüsün bulaÅŸma riski). + Uygulama tarafından iÅŸlenen veriler aÅŸağıdaki kategorilerde + sınıflandırılabilir: </p> +<h2> + a. EriÅŸim verileri +</h2> <p> - AÅŸağıdaki durumlarda saÄŸlık verilerinin iÅŸlenmesi söz konusudur: + Uygulama, RKI’nin sunucu sistemiyle (bundan böyle: <strong> sunucu sistemi</strong>) her veri + alışveriÅŸinde, sunucu sistemi + eriÅŸim verileri olarak adlandırılan verileri iÅŸler. Bu iÅŸlem, Uygulamanın + güncel verilere (örneÄŸin uyarılar için) eriÅŸebilmesi veya akıllı telefonda + saklanan belirli verileri sunucu sistemine aktarabilmesi için gereklidir. + EriÅŸim verileri aÅŸağıdaki verilerden oluÅŸmaktadır: </p> <ul> <li> - Maruz kalma günlüğü, koronavirüs ile enfekte olan kiÅŸi ile olası - temasını olduÄŸunu tespit ettiÄŸinde. + IP adresi + </li> + <li> + EriÅŸimin tarih ve saati </li> <li> - Bir testi kaydettiÄŸinizde. + Aktarılan veri miktarı (veya paket uzunluÄŸu) </li> <li> - Pozitif test sonucu paylaÅŸtığınızda. + Veri alışveriÅŸinin baÅŸarılı olup olmadığına dair ileti </li> </ul> -<h2> - 6. UYGULAMA'nın iÅŸlevleri -</h2> -<h3> - a. Maruz kalma günlüğü -</h3> -<p> - Maruz kalma günlüğü, UYGULAMA'nın çekirdek iÅŸlevidir. UYGULAMA'nın amacı - koronavirüs ile enfekte olmuÅŸ diÄŸer kullanıcılara olası bir teması takip - etmek, bu yüzden sizin için oluÅŸan enfeksiyon riskini deÄŸerlendirmek ve - sizin için tespit edilen toplam risk puanına göre davranış ve saÄŸlık - talimatları hazırlamaktır. -</p> -<p> - Maruz kalma günlüğünü etkinleÅŸtirdiÄŸinizde, UYGULAMA arka plan iÅŸletimdeki - sunucu sistemlerinden test sonuçları pozitif çıkmış ve kendi rastgele - kimliklerini paylaÅŸmış olan diÄŸer kullanıcıların rastgele kimliklerinden - oluÅŸan listeyi günde bir kaç defa (ya da "Güncelleme" düğmesini - tıklattığınızda) çağırır. UYGULAMA, akıllı telefonunuzun temas protokolünde - saklanan rastgele kimlikleri ile karşılaÅŸtıracağı rastgele kimlikleri, - akıllı telefonunuzun temas kayıt iÅŸlevine iletir. Akıllı telefonunuzun - temas kayıt iÅŸlevi bir eÅŸleÅŸtirme belirlerse, UYGULAMA'ya maruz kalma - verilerini (tarih, süre, sinyal gücü) verir, ancak ilgili temasın rastgele - kimliÄŸini vermez. -</p> -<p> - Temas halinde, bireysel enfeksiyon riskinizi tespit etmek amacıyla temas - kayıt iÅŸlevi tarafından iletilen maruz kalma verileri UYGULAMA tarafından - analiz edilir. Maruz kalma verilerinin nasıl yorumlanması gerektiÄŸini - belirleyen (örn. temas süresinin, enfeksiyon riski üzerinde ne tür bir - etkisinin olduÄŸu) deÄŸerlendirme algoritması, sahip olunan güncel bilimsel - bilgilere dayanır. Bu yüzden yeni bilgiler edinildiÄŸinde deÄŸerlendirme - algoritmasının ayarları RKI tarafından yeniden yapılır ve deÄŸerlendirme - algoritması bu ÅŸekilde güncellenebilir. DeÄŸerlendirme algoritmasının - ayarları, enfekte olan kiÅŸilerin rastgele kimliklerinden oluÅŸan liste ile - birlikte UYGULAMA'ya iletilir. -</p> -<p> - Enfeksiyon riskinin tespiti sadece akıllı telefonunuzda lokal olarak - gerçekleÅŸir, yani veriler çevrimdışı iÅŸlenir. Tespit edilen enfeksiyon - riski de aynı ÅŸekilde sadece UYGULAMA'da saklanır ve baÅŸka alıcılara (RKI, - Apple, Google ve diÄŸer üçüncü taraflara) verilmez. -</p> -<p> - EriÅŸim verilerinizin, maruz kalma verilerinizin ve gerekirse saÄŸlık - verilerinizin (sizin için bir enfeksiyon riski tespit edilmiÅŸse) yukarıda - anıldığı gibi iÅŸlenmesinin hukuki dayanağı, maruz kalma günlüğü - etkinleÅŸtirme esnasında verdiÄŸiniz onaydır. -</p> -<h3> - b. Test kaydetme -</h3> -<p> - Koronavirüs enfeksiyonu için test olduysanız, bu testi doktorunuz ya da - test kuruluÅŸundan aldığınız QR kodunu UYGULAMA'da tarayarak, UYGULAMA'ya - kaydedebilirsiniz. UYGULAMA, laboratuvarın test sonucu çıktığında sizi - bilgilendirir. -</p> -<p> - Ancak bu durum, test laboratuvarının UYGULAMA'nın sunucu sistemine baÄŸlı - olması ve sizin de test uygulaması çerçevesinde test sonucunun laboratuvar - tarafından UYGULAMA'nın sunucu sistemine (test sonucu veri tabanı) - gönderilmesine özellikle onay vermiÅŸ olmanız ÅŸartına baÄŸlıdır. UYGULAMA'nın - sunucu sistemine baÄŸlı olmayan laboratuvarların test sonuçları UYGULAMA'da - gösterilmez. EÄŸer bir QR kodu almadıysanız, bu test laboratuvarının - sunucuya baÄŸlı olmadığı anlamına gelir. Bu durumda bu iÅŸlevi - kullanamazsınız. -</p> -<p> - <u>Test kaydı</u> -</p> -<p> - Test sonucunu UYGULAMA'da alabilmeniz için öncelikle test kaydını - UYGULAMA'da yapmalısınız. Bunun için, doktordan ya da test kuruluÅŸundan - numune alma esnasında bir QR kodu alırsınız. Bu QR kodu, QR kodu tarayıcısı - ile okunabilen bir tanıtma sayısını içerir. Test kaydı için akıllı - telefonunuzun kamerası ile QR kodunu UYGULAMA'da taramalısınız. -</p> -<p> - QR kodundan okunan tanıtma sayısı, UYGULAMA tarafından karıştırılır, daha - doÄŸrusu, tanıtma sayısı, temelinde yatan tanıtma sayısı tanınmayacak - ÅŸekilde belirli bir matematik yöntemiyle deÄŸiÅŸtirilir. Akıllı telefonunuz - internet ile baÄŸlantı kurduÄŸunda, UYGULAMA karma kod numarasını, - UYGULAMA'nın sunucu sistemlerine iletir. Bunun karşılığında, UYGULAMA, - sunucu sisteminden UYGULAMA'da saklanacak olan bir belirteç, daha doÄŸrusu - dijital eriÅŸim anahtarı alır. Belirteç, sunucu sisteminde karma kod - numarası ile birleÅŸtirilir. UYGULAMA, akıllı telefonda karma kod numarasını - siler. Sunucu sistemi her bir karma kod numarası için sadece bir defa bir - belirteç verir. Bu sayede QR kodunun, UYGULAMA'nın diÄŸer kullanıcıları - tarafından test sonuçlarının sorgulanması için kullanılmaması garantilenir. -</p> <p> - Test kaydınız böylelikle biter. + Bu eriÅŸim verileri, Uygulamanın ve sunucu sisteminin teknik açıdan + iÅŸletimini sürdürmek ve güvence altına almak için iÅŸlenmektedir. Bu süreçte + siz, Uygulamanın kullanıcısı olarak ÅŸahsen tanımlanmazsınız ve sizin için + bir kullanıcı profili oluÅŸturulmaz. IP adresi, kullanım iÅŸlemi bitiminden + sonra saklanmaz. </p> <p> - <u>Test sonuçlarının saklanması</u> -</p> -<p> - Test sonuçları çıktığında laboratuvar, RKI tarafından iÅŸletilen test sonucu - veri bankasında karma kod numarası bilgisi bildirilerek test sonucunu - bırakır. Test sonucu veri tabanı, RKI tarafından UYGULAMA'nın sunucu - sistemleri dahilinde özel bir sunucuda iÅŸletilir. Test laboratuvarı, - UYGULAMA'yı da kullanan aynı matematik yöntemini kullanarak ve verilen QR - kodunda bulunan tanıtma sayısı temel alınarak karma kod numarası oluÅŸturur. -</p> -<p> - <u>Test sonuçlarının çaÄŸrılması</u> -</p> -<p> - UYGULAMA, belirteç kullanılarak UYGULAMA'nın sunucu sisteminde kayıtlı - testin durumunu düzenli sorgular. Sunucu sistemi, belirteci, karma kod - numarasına ekler ve bunu da test sonucu veri tabanına iletir. Test sonucu - veri tabanına eklenmiÅŸse, veri tabanı test sonucunu sunucu sistemine geri - gönderir ve sunucu ise bunu içeriÄŸine bakmadan UYGULAMA'ya gönderir. -</p> -<p> - Test sonucunun pozitif olması halinde UYGULAMA, belirtecin yeniden - kullanımı ile sunucu sisteminden bir TAN (iÅŸlem numarası) ister. Sunucu - sistemi, belirteci tekrar karma kod numarasına ekler ve test sonucu veri - tabanından, karma kod numarasının pozitif bir test sonucu bulunduÄŸuna dair - bir onay ister. Test sonucu veri tabanı bunu onaylarsa, sunucu sistemi - TAN'ı oluÅŸturur ve UYGULAMA'ya iletir. TAN'ın bir kopyası sunucu sisteminde - kalır. -</p> -<p> - Pozitif bir test sonucunun iletilmesi halinde yanlış bilgilerin diÄŸer - kullanıcılar ile paylaşılmamasını saÄŸlamak için TAN gereklidir. -</p> -<p> - Anılan verilerin yukarıda açıklandığı ÅŸekilde iÅŸlenmesinin hukuki dayanağı, - "Test kaydetme" iÅŸlevine verdiÄŸiniz onaydır. -</p> -<h3> - c. Test sonucunuzu paylaÅŸma -</h3> -<p> - DiÄŸer kullanıcıları uyarmak için "Test sonucunuzu paylaÅŸma" iÅŸlevini - kullanırsanız, UYGULAMA akıllı telefonunuzda kayıtlı olan son 14 güne ait - rastgele kimliklerinizi ve TAN'ı UYGULAMA'nın sunucu sistemine iletir. - Sunucu sistemi öncelikle TAN'ın geçerli olup olmadığını kontrol eder ve - rastgele kimliklerinizi, pozitif test sonucu paylaÅŸan kullanıcıların - rastgele kimliklerinden oluÅŸan listeye taşır. Bundan böyle rastgele - kimlikleriniz, maruz kalma günlüğü çerçevesinde diÄŸer kullanıcılar - tarafından indirilebilir. -</p> -<p> - <u>Test sonucunuzu UYGULAMA'da çağırmadıysanız:</u> -</p> -<p> - Pozitif test sonucunu UYGULAMA'da çağırmadıysanız bile, diÄŸer kullanıcıları - uyarmak için test sonucunuzu UYGULAMA aracılığıyla paylaÅŸabilirsiniz. Bu - durumda, UYGULAMA sizden TAN iÅŸlevi gören bir TeleTAN girmenizi ister. -</p> -<p> - TeleTAN'ı alabilmek için +49 (0)800 7540002 numaralı telefon aracılığıyla - Corona-Warn-App yardım hattını arayabilirsiniz. Danışma hattı yetkilisi, - çaÄŸrınızın uygunluÄŸunu kontrol etmek için öncelikle size telefonda bazı - sorular soracaktır. Bu sorular, kötü niyetli enfeksiyon bildirimlerinin ve - bunlardan kaynaklanan hatalı uyarıların ve toplam risk puanının önlenmesine - yarar. Bu sorulara yeterli yanıtlar verildikten sonra sizden cep telefonu / - telefon numaranız istenir. Bu telefon numarası sizi daha sonra geri aramak - ve size uygulamaya gireceÄŸiniz TeleTAN'ı bildirmek amacıyla alınır. Cep - telefonu / telefon numaranız sadece bu amaç için geçici bir süre saklanır - ve en geç bir saat içerisinde silinir. -</p> -<p> - ÇaÄŸrınızdan sonra yardım hattı çalışanı, UYGULAMA'nın sunucu sistemine özel - eriÅŸim yetkisini kullanarak bir TeleTAN oluÅŸturur ve TeleTAN'ınızı sizinle - paylaÅŸmak için sizi arar. UYGULAMA'ya TeleTAN'ı girdiÄŸinizde, UYGULAMA, - kıyaslamak ve onaylamak için TeleTAN'ı UYGULAMA'nın sunucu sistemine geri - gönderir. Bunun karşılığında, UYGULAMA, sunucu sisteminden UYGULAMA'da - saklanacak olan bir belirteç, daha doÄŸrusu dijital eriÅŸim anahtarı alır. - UYGULAMA, sunucu sisteminden bu belirteç ile bir TAN ister. -</p> -<p> - EriÅŸim verileriniz ve saÄŸlık verilerinizin (rastgele kimlikler, test - sonucu, TAN ve TeleTAN) iÅŸlenmesinin hukuki dayanağı, "Test sonucunuzu - paylaÅŸma" iÅŸlevine verdiÄŸiniz onaydır. -</p> -<p> - <strong>d. UYGULAMA'nın bilgi amaçlı kullanımı</strong> -</p> -<p> - UYGULAMA'yı sadece bilgi amaçlı kullanıyorsanız, daha doÄŸrusu UYGULAMA'nın - yukarıda anılan hiçbir iÅŸlevini kullanmıyorsanız ve hiçbir veri - girmiyorsanız, veri iÅŸleme sadece akıllı telefonunuzda yapılır ve hiçbir - kiÅŸisel veri meydana gelmez. UYGULAMA'da baÄŸlantı kurulan: - www.bundesregierung.de gibi web sayfaları akıllı telefonunuzun standart - tarayıcısında açılır ve gösterilir. Hangi verilerin iÅŸleneceÄŸi, kullanılan - tarayıcıya, yapılandırmasına ve de çaÄŸrılan web sayfasının veri iÅŸleme - uygulamasına baÄŸlıdır. + Bir kullanım iÅŸlemi sırasında verilerinizin IP adresinize yetkisiz + atanmasını önlemek için, Uygulama, sunucu sistemine sadece özel bir giriÅŸ + sunucusu üzerinden eriÅŸir. Bunun ardından giriÅŸ sunucusu, Uygulama + tarafından talep edilen veya iletilen verileri, IP adresi olmaksızın, + yetkili sunucuya iletir, bu sayede IP adresi sunucu sisteminde iÅŸlenmez. </p> <h2> - 7. UYGULAMA hangi yetkilendirme ve iÅŸlevleri gerektirir? + b. Maruz kalma verileri </h2> <p> - UYGULAMA, akıllı telefonunuzun çeÅŸitli iÅŸlevlerine ve ara yüzlerine eriÅŸim - gerektirir. Bunun için, UYGULAMA'nın belirli yetkilendirmeleri istemesi - gereklidir. Yetkilendirmeler, çeÅŸitli üreticiler tarafından farklı - programlanır. Bu sayede, yetkilendirme kategorisini topluca kabul - edebileceÄŸiniz ÅŸekilde örn., yetkilendirme kategorilerine iliÅŸkin tekil - yetkilendirmeler toplanabilir. UYGULAMA aracılığıyla bir eriÅŸimin reddi - halinde UYGULAMA'nın hiçbir iÅŸlevini kullanamayacağınızı ya da çok az - iÅŸlevini kullanabileceÄŸinizi lütfen dikkate alın. -</p> -<h3> - a. Teknik ÅŸartlar (tüm akıllı telefonlar) -</h3> + iPhone’unuzun COVID-19 bildirim sistemini (orada “maruz kalma bildirimleri†+ olarak adlandırılır) veya Android akıllı telefonunuzun (orada “COVID-19 + temas bildirimleri†olarak adlandırılır) etkinleÅŸtirdiÄŸinizde, akıllı + telefonunuz, Bluetooth üzerinden maruz kalma verilerini göndermeye baÅŸlar + ve bu veriler yakınınızda bulunan diÄŸer akıllı telefonlar tarafından + kaydedilir. Öte yandan, kendi akıllı telefonunuz da diÄŸer akıllı + telefonlardan maruz kalma verileri alır. Gönderilen maruz kalma verileri + ÅŸunları içerir: +</p> <ul> <li> - Ä°nternet + Rastgele kimlik kodları (bundan böyle: <strong> rastgele kimlik numaraları</strong>) </li> -</ul> -<p> - UYGULAMA, UYGULAMA'nın sunucu sistemleri ile iletiÅŸim kurmak amacıyla maruz - kalma günlüğü, test sonucu alma ve test sonucu aktarma iÅŸlevleri için - internet baÄŸlantısını gerektirir. -</p> -<ul> <li> - Bluetooth + Bluetooth protokol sürümü </li> -</ul> -<p> - DiÄŸer akıllı telefonların rastgele kimliklerini alabilmesi ve bunları - cihazın temas protokolünde saklayabilmesi için akıllı telefonunuzun - Bluetooth ara yüzü etkinleÅŸtirilmelidir. -</p> -<ul> <li> - Kamera + Bluetooth iletim gücü, desibel miliwatt (dBm) olarak </li> </ul> <p> - Test kaydı amacıyla QR kodunu tarayabilmesi için akıllı telefonunuz, bir - kamera gerektirir. + Kaydedilen karşılaÅŸmalardaki maruz kalma verileri, ek olarak ÅŸunları + içerir: </p> <ul> <li> - Arka plan iÅŸletim + KarşılaÅŸmanın günü, saati ve süresi </li> -</ul> -<p> - Riski otomatik tespit etmek ve kayıtlı testlerin durumunu sorgulayabilmek - için UYGULAMA (UYGULAMA'yı aktif ÅŸekilde kullanmazsanız da) arka plan - iÅŸletimini gerektirir. Akıllı telefonunuzun iÅŸletim sisteminde arka plan - iÅŸletimini devre dışı bırakırsanız, tüm eylemleri UYGULAMA'da bizzat - baÅŸlatmalısınız. -</p> -<h3> - b. Android akıllı telefonlar -</h3> -<p> - Android cihaz kullanıyorsanız, aÅŸağıdaki sistem iÅŸlevleri ayrıca - etkinleÅŸtirilmelidir: -</p> -<ul> <li> - COVID-19 Temas Bildirimleri Sistemi + Bluetooth iletim gücü, dBm cinsinden </li> </ul> <p> - Temaslarınızın rastgele kimlikleri ile aksi takdirde hiçbir temas protokolü - sunulmadığından, maruz kalma günlüğü bu iÅŸlevi gerektirir. Ä°ÅŸlev, - UYGULAMA'nın temas protokolüne eriÅŸebilmesi için UYGULAMA dahilinde - etkinleÅŸtirilmelidir. + Rastgele kimlik numaraları düzenli olarak deÄŸiÅŸtirilir. Bu yöntem, akıllı + telefonunuzun bu rastgele kimlikler üzerinden tanımlanmasını önlemeye + yöneliktir. Akıllı telefonunuz tarafından gönderilen kendi maruz kalma + verileriniz ve temas halinde olduÄŸunuz kiÅŸilerin kayıtlı maruz kalma + verileri, akıllı telefonunuza kaydedilir ve her ikisi de 14 günlük bir + sürenin ardından silinir. Aynı ÅŸekilde gönderdiÄŸiniz maruz kalma + verileriniz, diÄŸer Uygulama kullanıcılarının akıllı telefonları tarafından + kaydedildiÄŸinde, iÅŸlenmeye baÅŸlanır. +</p> +<p> + Lütfen dikkate alın: COVID-19 bildirim sistemi, iÅŸletim sisteminizin bir + iÅŸlevidir. Dolayısıyla bu sistemin saÄŸlayıcıları ve sorumluları, Apple + (iPhone’unuz varsa) ve Google’dır (Android akıllı telefonunuz varsa). Bu + baÄŸlamda verilerin iÅŸlenmesi, bu ÅŸirketlerin veri koruma yönetmeliklerine + tabidir ve RKI’nin sorumluluk ve etki alanı dışındadır. Ä°ÅŸletim + sisteminizin sürümüne ve ayarlarına baÄŸlı olarak, fiili gösterimler, + kullanım adımları ve ayar seçenekleri, bu Veri GizliliÄŸi Beyanındaki + sunumdan farklı olabilirler. Söz konusu üreticiler, size daha ayrıntılı + bilgi saÄŸlamaktadır: </p> <ul> <li> - Konum tespiti + Android akıllı telefonlar için bu bilgileri Google’da, cihazınızdaki + “Ayarlar†> Google > COVID-19 temas bildirimleri ve “Daha fazla + bilgi†baÄŸlantısı altında bulabilirsiniz. </li> -</ul> -<p> - Cihazınızın diÄŸer akıllı telefonların Bluetooth sinyallerini araması için - akıllı telefonunuzun konum tespiti etkinleÅŸtirilmelidir. Bu arama esnasında - konum verileri toplanmaz. -</p> -<ul> <li> - Bildirim + Apple iPhone’ları için bu bilgiler, cihazınızdaki “Ayarlar†> “Maruz + kalma bildirimleri†ve “Maruz kalma bildirimleri böyle çalışır…†+ baÄŸlantısı altında bulabilirsiniz. </li> </ul> +<h2> + c. SaÄŸlık verileri +</h2> <p> - Kullanıcı, maruz kalma günlüğü ve mevcut test sonuçları hakkında lokal - olarak bilgilendirilir. Bunun için gerekli olan bildirim iÅŸlevi, iÅŸletim - sisteminde etkin haldedir. -</p> -<p> - UYGULAMA ayrıca aÅŸağıdaki yetkileri gerektirir: + SaÄŸlık verileri, bir kiÅŸinin saÄŸlığı hakkında bilgiler içeren tüm + verilerdir. Bunlar, yalnızca bir kiÅŸinin eski ve güncel hastalıklarıyla + ilgili bilgileri deÄŸil, aynı zamanda hastalık riski (örneÄŸin bir kiÅŸinin + Koronavirüs ile enfekte olma riski) ile ilgili bilgilerdir. Uygulama, + saÄŸlık verilerini aÅŸağıdaki durumlarda iÅŸler: </p> <ul> <li> - Kamera + Bir maruz kalma fark edildiÄŸinde </li> -</ul> -<p> - UYGULAMA, test kaydı esnasında QR kodunu okuyabilmek için kameraya - eriÅŸebilmelidir. -</p> -<h3> - c. iPhone (Apple iOS) -</h3> -<p> - iPhone kullanıyorsanız, aÅŸağıdaki sistem iÅŸlevleri etkinleÅŸtirilmelidir: -</p> -<ul> <li> - COVID-19'a Maruz Kalma Günlüğü + Bir test veya bir pozitif bulgu raporu kaydederseniz + </li> + <li> + Uygulama üzerinden çağırdığınız test sonucu pozitif ise + </li> + <li> + KarşılaÅŸmalarınızı, Uygulama üzerinden olası bir enfeksiyon konusunda + uyarırsanız </li> -</ul> -<p> - Temaslarınızın rastgele kimlikleri ile aksi takdirde hiçbir temas protokolü - sunulmadığından, maruz kalma günlüğü bu iÅŸlevi gerektirir. Ä°ÅŸlev, - UYGULAMA'nın temas protokolüne eriÅŸebilmesi için UYGULAMA dahilinde - etkinleÅŸtirilmelidir. -</p> -<ul> <li> - Bildirimler + Olası Korona semptomların baÅŸlangıcına iliÅŸkin beyanda bulunursanız </li> </ul> <p> - Kullanıcı, maruz kalma günlüğü ve mevcut test sonuçları hakkında lokal - olarak bilgilendirilir. Bildirimler bu yüzden etkinleÅŸtirilmelidir. + Ayrıntılar 6. Maddede açıklanmıştır. </p> +<h1> + 6. Verileriniz niçin iÅŸleniyor? +</h1> +<h2> + a. Maruz kalma günlüğü +</h2> <p> - UYGULAMA ayrıca aÅŸağıdaki yetkileri gerektirir: + Uygulamanın ana iÅŸlevlerinden biri, maruz kalma günlüğüdür. Bunun + görevleri, Korona testi pozitif çıkan kiÅŸilerle olası temaslar (maruz + kalmalar) konusunda sizi sınır ötesi ortamda da uyarmak, enfeksiyon + riskinizi hesaplamak ve size bu baÄŸlamda gerekli davranış ve saÄŸlık + bilgileri temin etmektir. +</p> +<p> + Bu amaç için Uygulama, arka planda çalışarak sunucu sisteminden, Korona + testi pozitif çıkan ve sınır ötesi uyarı sistemine katılan ülkelerin resmi + Korona uygulamaları aracılığıyla gönüllü olarak bir uyarı tetikleyen + kullanıcılardan rastgele kimlik numaraları ve varsa semptomların + baÅŸlangıcına iliÅŸkin bilgiyi içeren günlük bir liste çağırır (bundan böyle: <strong>pozitif + liste</strong>). Pozitif listedeki rastgele kimlik + numaraları, ek olarak ayrıca bir taşıma riski deÄŸeri ve tanı tipi hakkında + bilgi de içerir (bkz. Madde 6 c.). +</p> +<p> + Uygulama bu rastgele kimlik numaralarını, COVID-19 bildirim sistemine + aktarır ve bu sistem bu kodları daha önce kaydedilen rastgele kimlik + numaraları ile karşılaÅŸtırır. COVID-19 bildirim sistemi bir eÅŸleÅŸme + saptarsa, söz konusu maruz kalma için kaydedilen maruz kalma verilerini + Uygulamaya aktarır. Bu veriler ve pozitif listedeki bilgiler (taşıma riski + deÄŸeri, semptomların baÅŸlangıcına iliÅŸkin bilgiler) enfeksiyon riskinizi + belirlemek için Uygulama tarafından deÄŸerlendirmeye alınır. Bu verilerin + hesaplanmasını belirleyen deÄŸerlendirme algoritması, RKI’nin güncel + bilimsel bulgularına (örn. temas süresinin enfeksiyon riski üzerindeki + etkisi) dayanmaktadır. Yeni bulgular olması durumunda RKI, Uygulamanın + deÄŸerlendirme ayarları üzerinden deÄŸerlendirme algoritmasını + güncelleyebilir. Bu durumda, yeni deÄŸerlendirme ayarları pozitif listeyle + birlikte Uygulamaya aktarılır. +</p> +<p> + Enfeksiyon riski, yalnızca Uygulama içinde hesaplanır ve COVID-19 bildirim + sistemine veya diÄŸer alıcılara (RKI, Almanya’daki diÄŸer saÄŸlık kurumları + veya diÄŸer ülkeler, Apple, Google ve diÄŸer üçüncü taraflar da dahil olmak + üzere) aktarılmaz. +</p> +<h2> + b. Test kaydetme +</h2> +<p> + Korona testi yaptırdıysanız, testinizi Uygulamaya kaydedebilirsiniz. Test + sonucu hazır olur olmaz, Uygulama sizi bu konuda bilgilendirecektir. Ancak + bu bilgilendirme, test laboratuvarının sunucu sistemine baÄŸlı olmasını ve + sizin ayrıca, test sonuçlarınızın test süreci kapsamında laboratuvar + tarafından sunucu sistemine (test sonuçları veritabanı) aktarılmasına onay + vermenizi gerektirir. Uygulamanın sunucu sistemine baÄŸlı olmayan + laboratuvarlardan gönderilen test sonuçları görüntülenemez. Bir QR kod + almadıysanız, bu iÅŸlevi kullanamazsınız. </p> -<ul> - <li> - Kamera - </li> -</ul> <p> - UYGULAMA, test kaydı esnasında QR kodunu okuyabilmek için kameraya - eriÅŸebilmelidir. + <u>Test kaydı</u> +</p> +<p> + Test sonucunu Uygulama aracılığıyla çağırmak için, testinizi + kaydetmelisiniz. Bunun için doktorunuzdan veya testin yapıldığı tesisten + bir QR kod alırsınız. Bu QR kod, Uygulama ile okunabilen bir kod numarası + içerir. Bu testi kaydetmek için, bu QR kodu akıllı telefonunuzun + kamerasıyla Uygulamaya taramanız gerekir. Okunan kod numarası, Uygulama + tarafından karma hale getirilir. Bunun anlamı, kod numarasının spesifik bir + matematik yöntemi ile sürece yabancılaÅŸtırılması ve böylece artık tanınmaz + hale gelmesidir. Akıllı telefonunuz internete baÄŸlanır baÄŸlanmaz, Uygulama + bu karma kod numarasını sunucu sistemine iletir. Bunun karşılığında + Uygulama, sunucu sisteminden bir belirteç, yani bir dijital eriÅŸim kodu + alır ve bu da Uygulamaya kaydedilir. Belirteç, sunucu sistemindeki karma + kod numarasına baÄŸlıdır. Uygulama daha sonra akıllı telefonunuzdaki karma + kod numarasını siler. Testinizin kaydedilmesi böylece tamamlanmış olur. Her + bir karma kod numarası için sunucu sistemi yalnızca bir kez bir belirteç + verir. Bu sayede QR kodunuzun Uygulamanın diÄŸer kullanıcıları tarafından + test sonuçlarını sorgulamak için kullanılmasının önüne geçilir. +</p> +<p> + <u>Test sonucunun saklanması</u> +</p> +<p> + Test laboratuvarı test sonucunu hazırladığında, hemen bu sonucu ilgili + karma kod numarası ile birlikte RKI tarafından iÅŸletilen test sonuçları + veri tabanına kaydedilmek üzere gönderir. Test sonuçları veri tabanı, + sunucu sistemi içinde ayrı bir sunucuda bulunur. Test laboratuvarı, + Uygulamanın kullandığı matematik yönteminin aynısını kullanarak, size + verilen QR kodda yer alan kod numarası bazında karma kod numarasını + oluÅŸturur. +</p> +<p> + <u>Test sonucunun çaÄŸrılması </u> +</p> +<p> + Uygulama, düzenli olarak belirteci kullanarak sunucu sisteminden kayıtlı + testinizin durumunu sorgular. Bu baÄŸlamda sunucu sistemi, bu belirteci + karma kod numarasına atar ve bunu test sonuçları veri tabanına iletir. Veri + tabanı sistemi, bu karma kod numarası için bir test sonucunun + <br/> + yüklenip yüklenmediÄŸini denetler ve sonucu geriye bildirir. Sunucu sistemi, + daha sonra iÅŸlemin durumunu ve test sonuçları veri tabanından sorgulanan + test sonucunun kendisini (yani test sonucunuzun pozitif veya negatif + çıktığını) Uygulamaya iletir. Uygulamadaki test durumu bildirimlerini + etkinleÅŸtirdiyseniz (“Ayarlar†> “Bildirimler†altında), ilgili + bildirimi alırsınız. Uygulamayı açtığınızda, test sonucu size gösterilir. +</p> +<p> + Korona testiniz pozitif çıkmışsa, Uygulama, tekrar belirteci kullanarak + sunucu sisteminden bir TAN (iÅŸlem numarası) ister. TAN, Uygulama tarafından + tetiklenen bir uyarı durumunda, diÄŸer kullanıcılara yanlış uyarı + verilmesini önlemek için gerekli olur. Bu amaçla, sunucu sistemi belirteci + tekrar karma kod numarasına atar ve test sonuçları veri tabanından bu karma + kod numarası için gerçekten bir pozitif test sonucunun mevcudiyetini + doÄŸrulamasını ister. Ä°lgili doÄŸrulama alındığında, sunucu sistemi TAN’ı + oluÅŸturur ve bunu uygulamaya iletir. Bu TAN’ın bir kopyası sunucu + sisteminde kalır. </p> <h2> - 8. Veriler ne zaman silinir? + c. DiÄŸer insanların uyarılması </h2> <p> - UYGULAMA'da saklanan tüm veriler, UYGULAMA'nın iÅŸlevleri için ihtiyaç - kalmadığında silinir: + Korona testiniz pozitif çıkmışsa, bu Uygulamayı veya katılımcı ülkelerin + resmi Korona uygulamalarını kullanan diÄŸer kullanıcıları uyarmak için sınır + ötesi uyarı iÅŸlevini kullanabilirsiniz. Bu durumda, Uygulama ÅŸu verileri + sunucu sistemine iletir: </p> -<h3> - a. Maruz kalma günlüğü -</h3> <ul> <li> - Pozitif test sonucu paylaÅŸan kullanıcılara iliÅŸkin liste, UYGULAMA'da - derhal ve ayrıca akıllı telefonunuzun temas protokolünde de 14 gün - sonra otomatik silinir. + Son 14 gündeki kendi rastgele kimlik numaralarınız </li> <li> - Akıllı telefonunuzun temas protokolünde maruz kalma verileri (kendi - rastgele kimlikleriniz dahil) ve diÄŸer akıllı telefonlardaki maruz - kalma verilerinin silinmesine iliÅŸkin olarak RKI'nin, bu iÅŸlev Apple - veya Google tarafından hazırlandığı için hiçbir etkisi yoktur. Silme - iÅŸlemi Apple veya Google'ın kararlarına göre gerçekleÅŸir. Veriler ÅŸu - anda 14 gün sonra otomatik silinir. Ayrıca cihazınızın sistem - ayarlarında Apple ve Google tarafından sunulan fonksiyonları kullanarak - bunları manuel olarak silebilirsiniz. + Semptomların baÅŸlangıcına iliÅŸkin olası bilgi </li> <li> - Yeni toplam risk puanı tespit edildiÄŸinde UYGULAMA'da görüntülenen - toplam risk puanı silinir. Yeni toplam risk puanı kural olarak - UYGULAMA, rastgele kimliklerinden oluÅŸan listeyi aldıktan sonra tespit - edilir. + TAN’ınız (bkz. Madde 6 b.) </li> </ul> -<h3> - b. Test kaydetme -</h3> +<p> + Akıllı telefonunuz, ilk önce COVID-19 bildirim sisteminden kendi rastgele + kimlik numaralarınızı Uygulamaya aktarmak için sizden izin isteyebilir. +</p> +<p> + Rastgele kimlik numaraları sunucu sistemine iletilmeden önce, Uygulama + rastgele kimlik numaralarına ayrıca bir taşıma riski deÄŸeri ve tanı tipi + hakkında verileri ekler (bunun için Madde 6 a’ya bakın). Uygulamanın uyarı + iÅŸlevi, sadece laboratuvarda onaylanan tanıları kullanılabildiÄŸinden, tanı + tipi tüm kullanıcılar için aynıdır. Taşıma riski deÄŸeri, ilgili rastgele + kimlik numarasının kullanıldığı gündeki enfeksiyon olasılığının bir tahmini + deÄŸeridir. Enfeksiyon olasılığı, enfeksiyonun süresine ve seyrine baÄŸlı + olduÄŸundan, örneÄŸin bir maruz kalma gününde, semptomların baÅŸlangıcından bu + yana ne kadar zaman geçmiÅŸse, o gün enfeksiyon riski o kadar düşük olur. +</p> +<p> + Sorgulanan semptomların baÅŸlangıcına iliÅŸkin bilginin verilmesi, isteÄŸe + baÄŸlıdır. Ancak bu bilgi, taşıma riski deÄŸerinin daha kesin bir ÅŸekilde + hesaplanmasında yardımcı olmaktadır. Bu bilgiyi saÄŸlamadığınızda, + enfeksiyonun tipik seyri varsayılarak taşıma riski deÄŸeri hesaplanır, yani + rastgele kimlik numarası kullanımından sonra geçen süre ne kadar uzunsa, + ilgili taşıma riski deÄŸeri o kadar küçük olur. +</p> +<p> + <u>Uygulama üzerinden test sonucunuzu almadıysanız:</u> +</p> +<p> + Pozitif test sonucunuzu Uygulama üzerinden çağırmamış olsanız bile, diÄŸer + insanları uyarabilirsiniz. Bunun için, “TAN iste†prosedürünü seçin. Bunun + üzerine Uygulama sizden yardım hattını aramanızı ister. Orada bir yardım + hattı çalışanı, Korona testinizin pozitif çıktığından emin olmak için size + birkaç soru soracaktır. Bunun amacı, yanlış uyarıların istemeden veya + kasıtlı olarak tetiklenmesini önlemektir. Bu soruları doÄŸru yanıtladıktan + sonra, size cep telefonu / telefon numaranız ve adınız sorulacaktır. Bu, + daha sonra sizi telefonla arayarak, Uygulamaya girmeniz gereken ve TeleTAN + olarak adlandırılan kodu size bildirmek içindir. Cep telefonunuz / telefon + numaranız ve adınız, yalnızca bu süreçte geçici olarak kaydedilecek ve en + geç bir saat içinde silinecektir. Aramanızdan hemen sonra, yardım hattı + çalışanı, sunucu sistemindeki özel bir eriÅŸim yolu üzerinden TeleTAN’ınızı + oluÅŸturacak ve bu konuda bilgi vermek için sizi arayacaktır. Bir TeleTAN + yalnızca bir saat süreyle geçerli kalır ve dolayısıyla size iletildikten + hemen sonra, ancak en geç bir saat içinde yardım hattındaki sistemden + silinir. Uygulamaya geçerli bir TeleTAN girildikten sonra, bu kod doÄŸrulama + için sunucu sistemine iletilir. DoÄŸrulama baÅŸarılı olursa Uygulama, sunucu + sisteminden bir belirteç, yani bir dijital eriÅŸim kodu alır ve bu da + Uygulamaya kaydedilir. Uygulama daha sonra bu belirteci sunucu sisteminden + bir TAN talep etmek için kullanır. +</p> +<h2> + d. Uygulamanın bilgilenme amaçlı kullanımı +</h2> +<p> + Uygulamayı yalnızca bilgi edinme amaçlı kullanıyorsanız, yani yukarıda + belirtilen iÅŸlevlerden hiçbirini kullanmıyorsanız, veri iÅŸleme yalnızca + kendi akıllı telefonunuzda gerçekleÅŸir ve RKI tarafından hiçbir kiÅŸisel + veri iÅŸlenmez. Uygulamada, örneÄŸin www.bundesregierung.de gibi + baÄŸlantılı web siteleri açılır ve standart tarayıcıda (Android akıllı + telefonlar) veya Uygulamada (iPhone’lar) görüntülenir. Hangi verilerin + iÅŸleneceÄŸi, eriÅŸilen web sitesinin ilgili saÄŸlayıcısı tarafından + belirlenmektedir. +</p> +<h1> + 7. Sınır ötesi uyarı sistemi nasıl çalışır? +</h1> +<p> + DiÄŸer ülkelerdeki resmi Korona uygulamalarının kullanıcılarının da + uyarılmasını için RKI, bu ülkelerdeki sorumlu merciler ve kurumlar (bundan + böyle: <strong>saÄŸlık kurumları</strong>) ile birlikte uyarı mesajlarının + sınır ötesi deÄŸiÅŸimine yönelik merkezi bir uyarı sunucusu (bundan böyle: <strong>veri deÄŸiÅŸim + sunucusu</strong>) kurmuÅŸtur. Veri deÄŸiÅŸim sunucusu, + elektronik saÄŸlık hizmetleri için üye devletler arasında kurulmuÅŸ olan ağın + dijital altyapısını kullanır. +</p> +<p> + Veri deÄŸiÅŸim sunucusuna baÄŸlı Korona uygulamalarının ulusal sunucu + sistemleri, kendi pozitif listelerini düzenli olarak veri deÄŸiÅŸim + sunucusuna iletir ve ondan diÄŸer ülkelerin pozitif listelerini alır. +</p> +<p> + Sunucu sistemi, aldığı pozitif listeleri kendi pozitif listesiyle + birleÅŸtirir, bu sayede maruz kalma günlüğünde, diÄŸer Korona + uygulamalarının kullanıcılarıyla olan riskli karşılaÅŸmalar da dikkate + alınabilir (bkz. Madde 6 c.). DiÄŸer katılımcı ülkeler, RKI tarafından + saÄŸlanan pozitif listelerle aynı yöntemi kullanarak çalışmaktadır. +</p> +<p> + OrtaklaÅŸa iÅŸletilen veri deÄŸiÅŸim sunucusuna, yalnızca ulusal Korona + uygulamalarının uyumlu olduÄŸu ve aynı yüksek düzeyde veri gizliliÄŸi + güvencesi veren ülkelerin katılmasına izin verilmektedir. Bunun için, + özellikle, katılımcı ülkelerin Korona uygulamalarının da COVID-19 bildirim + sistemini kullanması, ilgili ulusal saÄŸlık kurumları tarafından onaylanmış + olması ve ayrıca kullanıcılarının gizliliÄŸinin korunması zorunludur. + Ä°ÅŸbirliÄŸinin teknik ve organizasyonel ayrıntıları AB Komisyonunun bir + kararında belirlenmiÅŸtir (15 Temmuz 2020 tarihli Uygulama Kararı (AB) + 2020/1023, bu kararı ÅŸu adresten eriÅŸebilirsiniz: + https://eur-lex.europa.eu/eli/dec_impl/2020/1023/oj ). +</p> +<p> + RKI ve katılımcı ülkelerin yetkili saÄŸlık kurumları, sınır ötesi maruz + kalma günlüğü ve uyarısı saÄŸlamak üzere veri deÄŸiÅŸim sunucusunda bulunan + pozitif listelerde yer alan verilerin (rastgele kimlik numaraları ve + semptomların baÅŸlangıcına iliÅŸkin olası bilgiler) iÅŸlenmesinden müştereken + sorumludur. +</p> +<p> + Sisteme katılımcı ülkeler listesinin deÄŸiÅŸebileceÄŸini, lütfen göz önünde + bulundurun. Sorumlu saÄŸlık kurumları hakkında bilgilerin bulunduÄŸu güncel + listenin yer aldığı sıkça sorulan sorulara + https://www.coronawarn.app/en/faq/#interoperability_countries + adresinde eriÅŸebilirsiniz. +</p> +<h1> + 8. Uygulamanın hangi izinlere gerek duyar? +</h1> +<p> + Uygulama, akıllı telefonunuzdaki çeÅŸitli iÅŸlevlere ve arabirimlere eriÅŸim + gerektirir. Bunun için, Uygulamaya belli bazı izinleri vermenizi + gereklidir. Bu yetkilendirme sistemi, iÅŸletim sisteminizin teknik + özelliklerine göre deÄŸiÅŸmektedir. ÖrneÄŸin yetkilendirmeler, akıllı + telefonunuzda yetkilendirme kategorilerinde birleÅŸtirilmiÅŸ olabilir ve + sizin yetkilendirme kategorisini bir bütün olarak kabul etmeniz + gerekebilir. Uygulama tarafından talep edilen yetkiler verilmezse, hiçbir + Uygulama iÅŸlevinin kullanılamayacağını veya yalnızca birkaçının + kullanılabileceÄŸini lütfen unutmayın. +</p> +<h2> + a. Teknik gereksinimler (tüm akıllı telefonlar) +</h2> <ul> <li> - Karma kod numarası, 21 gün sonra UYGULAMA'nın sunucu sisteminden - silinir. + Uygulama, sunucu sistemiyle veri alışveriÅŸinde bulunabilmek için + internet baÄŸlantısı gerektirir. </li> <li> - Karma kod numarası ve test sonucu veri tabanında bulunan test sonucu, - negatif test sonucu halinde test sonucunun çaÄŸrılmasından hemen sonra - ve pozitif test sonucu halinde ise sunucu sisteminde saklanan TAN - kopyasının silinmesinden hemen sonra silinir (aÅŸağıya bakınız). + Akıllı telefonunuzun kendi rastgele kimlik numaralarını gönderebilmesi + ve diÄŸer akıllı telefonlardan rastgele kimlik numaralarını + kaydedebilmesi için, Bluetooth iÅŸlevinin etkinleÅŸtirilmesi zorunludur. </li> <li> - Sunucu sisteminde saklanan belirteç, 21 gün sonra silinir. - </li> - <li> - UYGULAMA'da saklanan belirteç, UYGULAMA akıllı telefondan silindikten - sonra ya da "Test sonucunuzu paylaÅŸma" iÅŸlevi gerçekleÅŸtirildikten - sonra silinir. + Uygulama, enfeksiyon riskinizi otomatik olarak belirlemek ve bir + kayıtlı testin durumunu sorgulamak için akıllı telefonunuzda arka + planda çalışabilmelidir. Arka plan iÅŸletimini devre dışı bırakırsanız, + Uygulamanın tüm eylemlerini kendiniz baÅŸlatmanız gerekir. </li> </ul> -<h3> - c. Test sonucunuzu paylaÅŸma -</h3> +<h2> + b. Android akıllı telefonları +</h2> +<p> + Bir Android akıllı telefon kullanıyorsanız, ayrıca aÅŸağıdaki sistem + iÅŸlevlerinin de etkinleÅŸtirilmesi gerekir: +</p> <ul> <li> - UYGULAMA'da paylaşılan rastgele kimlikler, 14 gün sonra sunucu - sisteminden silinir. + Android’in COVID-19 bildirim sistemi (COVID-19 temas bildirimleri) </li> <li> - Sunucu sisteminde saklanan TAN kopyası, 21 gün sonra silinir. + Sürüm 10’a kadar olan Android sürümlerinde konum belirleme özelliÄŸi + etkinleÅŸtirilmelidir. Ancak konum verileri toplanmaz. </li> <li> - UYGULAMA'da saklanan TAN, test sonucunun paylaşılmasından sonra - silinir. - </li> - <li> - UYGULAMA'da saklanan TeleTAN, test sonucunun paylaşılmasından sonra - silinir. + Enfeksiyon riskinizin ve test sonuçlarının durumlarındaki + deÄŸiÅŸikliklerden haberdar olmak için, bildirim iÅŸlevinin + etkinleÅŸtirilmiÅŸ olmalıdır. Bildirim iÅŸlevi, iÅŸletim sisteminde + standart olarak etkinleÅŸtirilmiÅŸtir. </li> +</ul> +<p> + Bunların yanı sıra Uygulama aÅŸağıdaki yetkilere gerek duyar: +</p> +<ul> <li> - Sunucu sisteminde saklanan TeleTAN kopyası, 21 gün sonra silinir. + “Testi kaydet†iÅŸlevi, QR kodu okuyabilmek için kameraya eriÅŸim yetkisi + gerektirir. </li> +</ul> +<h2> + c. iPhone’lar (Apple iOS) +</h2> +<p> + Bir iPhone kullanıyorsanız, aÅŸağıdaki sistem iÅŸlevlerinin de + etkinleÅŸtirilmesi gerekir: +</p> +<ul> <li> - Yardım hattının çalışanlarına iletilen TeleTAN, sizinle telefon - aracılığıyla paylaşıldıktan sonra derhal silinir. + iOS’in COVID-19 bildirim sistemi (maruz kalma bildirimleri) </li> <li> - Sunucu sisteminde saklanan belirteç, 21 gün sonra silinir. + Enfeksiyon riskinizin ve test sonuçlarının durumlarındaki + deÄŸiÅŸikliklerden haberdar olmak için, bildirimler iÅŸlevi + etkinleÅŸtirilmiÅŸ olmalıdır. </li> +</ul> +<p> + Bunlara ek olarak Uygulama aÅŸağıdaki yetkilere gerek duyar: +</p> +<ul> <li> - UYGULAMA'da saklanan belirteç, test sonucunun paylaşılmasından sonra - silinir. + “Testi kaydet†iÅŸlevi, QR kodu okuyabilmek için kameraya eriÅŸim yetkisi + gerektirir. </li> </ul> +<h1> + 9. Verileriniz ne zaman silinir? +</h1> +<p> + Saklama süresi, verilerinizin kaydedildiÄŸi amaçlara veya Uygulama + iÅŸlevlerine göre deÄŸiÅŸmektedir. Verilerin saklama süresini belirlerken RKI, + inkübasyon dönemi (14 güne kadar) ve enfekte bir kiÅŸinin inkübasyon dönemi + bitiminden sonra diÄŸer insanlar için oluÅŸturduÄŸu enfeksiyon riskinin + süresine iliÅŸkin güncel bilimsel bulguları dikkate alır. Madde 6’da daha + kısa bir saklama süresi belirtilmedikçe, aÅŸağıdaki süreler geçerlidir: +</p> <h2> - 9. Verileriniz kimlere iletilir? + a. Akıllı telefonunuzdaki veriler </h2> <p> - DiÄŸer kullanıcıları uyarmak için test sonucu paylaÅŸtığınızda, son 14 güne - ait rastgele kimlikleriniz diÄŸer kullanıcıların UYGULAMA'larına iletilir. + ÇaÄŸrılan pozitif listeler 14 gün sonra Uygulama belleÄŸinden silinir. + Uygulamada hesaplanan enfeksiyon riski (örn. “düşük riskâ€), her + güncellemeden sonra, ancak en geç 14 gün sonra Uygulama belleÄŸinden + silinir. Pozitif Korona testi kaydettiyseniz, bir uyarı tetikledikten hemen + sonra belirteç, Uygulama belleÄŸinden silinir. </p> +<h2> + b. Sunucu sistemlerindeki veriler +</h2> <p> - RKI, UYGULAMA'nın teknik alt yapısının bir bölümünün iÅŸletimi ve bakımı - (örn., sunucu sistemleri, yardım hattı) için Deutsche Telekom AG ve SAP - Deutschland SE & Co. KG'yi görevlendirmiÅŸtir (AB Genel Veri Koruma - Tüzüğü madde 28) ve bu firmalar bununla ilgili olarak RKI'nin veri - iÅŸlemcisi sıfatıyla faaliyet gösterecektir. + Pozitif listeler, 14 gün sonra tüm sunucu sistemlerinden (deÄŸiÅŸim + sunucuları dahil) silinir. DiÄŸer tüm veriler en geç 21 gün sonra silinir. </p> +<h1> + 10. Verileriniz kime aktarılır? +</h1> <p> - Bundan baÅŸka, RKI, UYGULAMA'nın kullanımı ile baÄŸlantılı olarak toplanan - kiÅŸisel verileri sadece kanunen yükümlü olursa veya teknik altyapı - saldırıya uÄŸradığında gerçekleÅŸecek hukuki ya da cezai takip iÅŸlemleri için - gerekli olursa üçüncü kiÅŸilere iletebilir. Bundan baÅŸka durumlarda veriler - esas itibariyle baÅŸkalarına iletilmez. + Uygulama aracılığıyla diÄŸer kullanıcıları uyardığınızda, son 14 güne ait + rastgele kimlik numaralarınız ve semptomların baÅŸlangıcına iliÅŸkin isteÄŸe + baÄŸlı bilgiler, veri deÄŸiÅŸim sunucusuna katılan ülkelerin sorumlu saÄŸlık + kurumlarına gönderilir ve oradan da sınır ötesi uyarı sistemine katılan + resmi Korona uygulamalarının sunucu sistemlerine aktarılır. Ulusal Korona + uygulamalarının sunucu sistemleri, verilerinizi pozitif listelerin bir + ögesi olarak kendi kullanıcılarına dağıtır. </p> -<h2> - 10. Veriler üçüncü ülkelere aktarılır mı? -</h2> <p> - UYGULAMA'nın kullanımında toplanan veriler, sadece Almanya'daki sunucularda - ya da baÅŸka bir AB ya da Avrupa Ekonomik Alanı üye devletinde iÅŸlenir. + Katılımcı ülkelerin yetkili ulusal saÄŸlık kurumları, ortaklaÅŸa iÅŸletilen + uyarı sisteminin iÅŸletimi ve bakımı için AB Komisyonunu iÅŸletici kuruluÅŸ + olarak görevlendirmiÅŸtir. </p> -<h2> - 11. Onayı geri alma -</h2> <p> - UYGULAMA'da RKI'ya yönelik verdiÄŸiniz onayları dilediÄŸinizde ve gelecekte - etki etmek ÅŸartıyla geri alabilirsiniz. Ancak, geri alma anına kadarki veri - iÅŸlemenin hukuka uygunluÄŸu, bu geri almadan etkilenmez. + RKI, Uygulamanın teknik altyapısının bir bölümünün (örn. sunucu sistemleri, + yardım hattı) iÅŸletimi ve bakımı için, iÅŸletici kuruluÅŸ olarak T-Systems + International GmbH ve SAP Deutschland SE & Co. KG firmalarını + görevlendirmiÅŸtir. Bu firmalar, aynı zamanda AB Komisyonu tarafından, + katılımcı ülkelerin ortaklaÅŸa iÅŸletilen uyarı sisteminin teknik yapısının + temini ve idaresi için alt iÅŸleyici olarak görevlendirilmektedir. </p> <p> - Maruz kalma günlüğüne iliÅŸkin onayınızı geri almak için UYGULAMA - dahilindeki ayarlar aracılığıyla iÅŸlevi devre dışı bırakabilir ya da - UYGULAMA'yı silebilirsiniz. Maruz kalma günlüğünü yeniden kullanmak - isterseniz, ayarı yeniden etkinleÅŸtirebilir ya da UYGULAMA'yı yeniden - yükleyebilirsiniz. + Sözü gelmiÅŸken, RKI, Uygulamanın kullanımıyla baÄŸlantılı olarak toplanan + verilerinizi, yalnızca RKI’nin yasalar tarafından yükümlü kılınması veya + Uygulamanın teknik altyapısına bir saldırı olması durumunda bir yasal + takibat veya cezai kovuÅŸturma için ifÅŸa edilmesi gerekli olduÄŸu takdirde + üçüncü taraflara aktarır. DiÄŸer durumlarda veri aktarımı gerçekleÅŸmez. </p> +<h1> + 11. Verileriniz AB dışındaki ülkelere aktarılacak mı? +</h1> <p> - "Test kaydetme" iÅŸlevine verdiÄŸiniz onayı geri almak için UYGULAMA'daki - test kaydını silebilirsiniz. Test sonucunun çaÄŸrılması için alınan - belirteç, bundan sonra cihazınızdan silinir. RKI ve test laboravutarı, - iletilen verileri UYGULAMA'nıza ya da cihazınıza ekleyemez. BaÅŸka bir testi - kaydettirmek isterseniz sizden yeni bir onay vermeniz istenir. + Bir uyarı tetiklediÄŸinizde, ortaklaÅŸa iÅŸletilen veri deÄŸiÅŸim sunucusuna + baÄŸlı Korona uygulamaları dünya çapındaki mevcut pozitif listeleri + çağırabilir, böylece tatilde veya iÅŸ gezisinde olan kullanıcılar da + uyarılabilir. Ancak Uygulama tarafından aktarılan veriler, sadece + Almanya’daki sunucularda veya bir diÄŸer AB (veya Avrupa Ekonomik Alanı) + ülkesindeki sunucularda iÅŸlenir, dolayısıyla Genel Veri Koruma Tüzüğünün + (GVKT) katı gerekliliklerine tabidir. </p> +<h1> + 12. Onayınızı nasıl geri alabilirsiniz? +</h1> <p> - "Test sonucunuzu paylaÅŸma" iÅŸlevine verdiÄŸiniz onayı geri almak için - UYGULAMA'yı silmelisiniz. UYGULAMA'da saklanan tüm rastgele kimlikleriniz - silinir ve akıllı telefonunuzla artık iliÅŸkilendirilemez. Yeniden bir test - sonucu bildirmek isterseniz, UYGULAMA'yı yeniden yükleyebilir ve yeni bir - onay verebilirsiniz. Alternatif olarak, ÅŸayet varsa, akıllı telefonunuzun - sistem ayarlarından temas bildirim iÅŸlevi çerçevesinde rastgele - kimliklerinizi silebilirsiniz. Lütfen RKI'nin iletmiÅŸ olduÄŸunuz rastgele - kimlikleri diÄŸer kullanıcıların akıllı telefonlarından ve hazırlanan - listelerden doÄŸrudan silme imkanının olmadığını dikkate alın. + GeleceÄŸe dönük geçerli olmak üzere, Uygulamada RKI’ye verdiÄŸiniz onayı + istediÄŸiniz zaman geri alma hakkına sahipsiniz. Ancak bu, iptal iÅŸlemi + geçerli oluncaya kadar bu onay temelinde yürütülmüş olan iÅŸlemlerin + yasalara uygunluÄŸunu etkilemez. </p> <h2> - 12. DiÄŸer veri koruma haklarınız + a. Maruz kalma günlüğü onayı </h2> <p> - KiÅŸisel verileriniz, RKI tarafından iÅŸlendiÄŸi sürece aÅŸağıdaki veri koruma - haklarına da sahipsiniz: + Onayınızı geri almak için, maruz kalma günlüğünü devre dışı bırakabilir + veya Uygulamayı silebilirsiniz. Maruz kalma günlüğünü tekrar kullanmak + isterseniz, kaydırıcıyı yeniden etkinleÅŸtirebilir veya uygulamayı yeniden + yükleyebilirsiniz. +</p> +<h2> + b. Test kaydı için onay +</h2> +<p> + Onayınızı geri almak için, test kaydetmeyi devre dışı bırakabilir veya + Uygulamayı silebilirsiniz. Bunun ardından test sonucunu çağırmak için + kullanılan belirteç, Uygulama belleÄŸinden silinir, böylece belirteç artık + sunucu sisteminde atanamaz. Bu durumda aynı testi tekrar kaydetmeniz artık + mümkün olmaz. Yeni bir test kaydetmek isterseniz, sizden yeniden onay + vermeniz istenecektir. +</p> +<h2> + c. Uyarı iÅŸlevi onayı +</h2> +<p> + Onayınızı geri almak için, Uygulamayı silmeniz gerekmektedir. Sunucu + sistemine halen iletilmiÅŸ olan rastgele kimlikleriniz, Uygulama belleÄŸinden + silinecek ve artık atanamayacaktır. Daha sonra tekrar bir uyarı tetiklemek + isterseniz, Uygulamayı yeniden yüklemeniz ve tekrar onay vermeniz gerekir. + Uygulamaya kaydedilmiÅŸ olan test sonucu, baÅŸkalarını uyarmak için tekrar + kullanılamaz. +</p> +<p> + RKI, rastgele kimliklerinizi ve taşıma riski deÄŸerlerinizi, sunucu sistemi + tarafından dağıtılmış olan pozitif listelerden ve kullanıcıların akıllı + telefonlarından silme olanağına sahip deÄŸildir. Ayrıca COVID-19 bildirim + sisteminde saklanan maruz kalma verilerinizi silme iÅŸlemini, muhtemelen + akıllı telefonunuzun sistem ayarlarında manuel olarak + gerçekleÅŸtirmelisiniz. Bunun için ayrıca Madde 5 b altındaki bilgileri + dikkate alın. +</p> +<h1> + 13. BaÅŸka hangi veri koruma haklarına sahipsiniz? +</h1> +<p> + KiÅŸisel verilerinizi RKI tarafından iÅŸlendiÄŸi sürece, ek olarak aÅŸağıdaki + veri koruma haklarına da sahipsiniz: </p> <ul> <li> - AB Genel Veri Koruma Tüzüğü maddeler 15, 16, 17, 18, 20 ve 21'den - kaynaklanan haklar, + GVKT Madde 15, 16, 17, 18, 20 ve 21 kapsamındaki haklar, </li> <li> - RKI resmi veri koruma görevlisi ile iletiÅŸime geçme ve talebinizi sunma - hakkı (AB Genel Veri Koruma Tüzüğü madde 38 paragraf 4) ve + RKI’nin veri koruma görevlisi + (https://www.rki.de/DE/Content/Institut/OrgEinheiten/Datenschutz/Datenschutz_node.html) + ile iletiÅŸim geçme ve isteklerinizi dile getirme hakkı (GVKT Madde 38 + fıkra 4 uyarınca) ve </li> <li> - yetkili denetim kurumu huzurunda veri korumaya iliÅŸkin ÅŸikayette - bulunma hakkı. Bunun için, ikamet ettiÄŸiniz ya da RKI'nin ÅŸirket - merkezinin bulunduÄŸu yerdeki yetkili denetim kurumuna - baÅŸvurabilirsiniz. RKI için yetkili denetim kurumu, Graurheindorfer - Str. 153, 53117 Bonn adresinde bulunan Veri Koruma ve Bilgi Özgürlüğü - federal görevlisidir. + yetkili veri koruma denetim makamına ÅŸikayette bulunma hakkı. Bunun + için ya ikâmet yerinizdeki yetkili denetim makamı ya da RKI için + yetkili makam ile iletiÅŸime geçebilirsiniz. RKI için yetkili denetim + makamı: Bundesbeauftragte für den Datenschutz und die + Informationsfreiheit (Federal Veri Koruma ve Bilgi Özgürlüğü Komiseri) + Graurheindorfer Str. 153, 53117 Bonn. </li> </ul> <p> - RKI'nin yukarıda anılan haklarının sadece, ileri sürülen taleplerin - dayanağı verilerin açıkça ÅŸahsınıza baÄŸlanması halinde ifa edilebileceÄŸine - dikkat çekeriz. Bu da, yukarıda anılan verilerin ÅŸahsınıza ya da cihazınıza - eklenmesine izin verilen diÄŸer kiÅŸisel verilerin RKI tarafından toplanması - halinde mümkündür. Bu husus da UYGULAMA'nın amaçları için gerekli - olmadığından – ve ayrıca istenmediÄŸinden – RKI bu tür bir ek veri toplama - ile sorumlu deÄŸildir (AB Genel Veri Koruma Tüzüğü madde 11 paragraf. 2). - Ayrıca, bu husus UYGULAMA çerçevesindeki veri iÅŸlemenin mümkün olduÄŸu kadar - veri koruma tasarrufu yaparak gerçekleÅŸtirilmesi olan amaca ve de açıklanan - amaca aykırıdır. Bu yüzden, yukarıda anılan AB Genel Veri Koruma Tüzüğü - maddeler 15, 16, 17, 18, 20 ve 21'den kaynaklanan veri koruma hakları, - kural olarak derhal uygulanmaz ve RKI'ye sunulmayan, ÅŸahsınızla ilgili ek - bilgiler ile uygulanır. -</p> -<p> - Versiyon: 09.06.2020 -</p> \ No newline at end of file + Bu veri koruma hakları, ortaklaÅŸa iÅŸletilen sınır ötesi veri deÄŸiÅŸim + sunucusu ile ilgili olarak, veri deÄŸiÅŸim sunucusuna katılan ülkelerdeki + veri iÅŸlemeden sorumlu saÄŸlık kurumları tarafından da size tanınmaktadır + (Bkz. Madde 7). +</p> +<p> + Lütfen yukarıda sözü geçen veri koruma haklarının, yalnızca bu talep edilen + hakların ilgili olduÄŸu verilerin açıkça sizin ÅŸahsınıza atanabilmesi + halinde ifa edilebileceÄŸini göz önünde bulundurun. Bu yalnızca, sunucu + sistemine aktarılan verilerin, ÅŸahsınıza veya akıllı telefonunuza açık bir + ÅŸekilde atanmasını saÄŸlayan Uygulama üzerinden daha fazla kiÅŸisel verilerin + toplanmasıyla mümkün olabilmektedir. Bu iÅŸlem Uygulamanın amaçları + doÄŸrultusunda gerekli olmadığından, RKI bu tür ek verileri toplamak zorunda + deÄŸildir (GVKT Madde 11, fıkra 2). Kaldı ki, bu iÅŸlem, mümkün olduÄŸunca az + veri toplama hedefine ters düşecektir. Bu nedenle, yukarıda belirtilen veri + koruma hakları, kimliÄŸiniz hakkında vermiÅŸ olduÄŸunuz ek bilgilerle bile + genellikle yerine getirilememektedir. +</p> +<h1> + 14. Veri koruma görevlisi ve iletiÅŸim +</h1> +<p> + Veri gizliliÄŸine iliÅŸkin sorularınızı ve endiÅŸelerinizi RKI’nin resmi veri + koruma görevlisine gönderebilirsiniz: Robert Koch-Institut, z. H. des + Datenschutzbeauftragten (veri koruma görevlisi), Nordufer 20,13353 Berlin + veya e-posta yoluyla: datenschutz@rki.de. +</p> +<p> + Yayım tarihi: 17.10.2020 +</p> diff --git a/Corona-Warn-App/src/main/assets/technical_de.html b/Corona-Warn-App/src/main/assets/technical_de.html index 396367104674cc8e299ce74bfd5cf4497eab69b8..cb8322cc84be6d36cdaf9fe0731b9a6bab8317f6 100644 --- a/Corona-Warn-App/src/main/assets/technical_de.html +++ b/Corona-Warn-App/src/main/assets/technical_de.html @@ -18,10 +18,6 @@ Licensor: Joda.org Website: https://www.joda.org/joda-time/ License: Apache 2.0</p> -<p>Component: Mockito - Licensor: Mockito contributors - Website: https://site.mockito.org/ - License: MIT</p> <p>Component: MockK Licensor: github.com/mockk Website: https://github.com/mockk/mockk @@ -66,6 +62,14 @@ Licensor: Google Website: https://github.com/google/protobuf-gradle-plugin License: BSD 3-Clause</p> +<p>Component: Dagger + Licensor: Google + Website: https://github.com/google/dagger + License: Apache 2.0</p> +<p>Component: AssistedInject + Licensor: Square + Website: https://github.com/square/AssistedInject + License: Apache 2.0</p> <p>Component: Conscrypt Licensor: Conscrypt Website: https://github.com/google/conscrypt @@ -264,23 +268,6 @@ as modifying the License. </li> </ol> <p>The MIT License</p> -<p>Copyright (c) 2007 Mockito contributors</p> -<p>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:</p> -<p>The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software.</p> -<p>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.</p> -<p>The MIT License</p> <p>Copyright (c) 2010 Xtreme Labs, Pivotal Labs and Google Inc.</p> <p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Corona-Warn-App/src/main/assets/technical_en.html b/Corona-Warn-App/src/main/assets/technical_en.html index 396367104674cc8e299ce74bfd5cf4497eab69b8..cb8322cc84be6d36cdaf9fe0731b9a6bab8317f6 100644 --- a/Corona-Warn-App/src/main/assets/technical_en.html +++ b/Corona-Warn-App/src/main/assets/technical_en.html @@ -18,10 +18,6 @@ Licensor: Joda.org Website: https://www.joda.org/joda-time/ License: Apache 2.0</p> -<p>Component: Mockito - Licensor: Mockito contributors - Website: https://site.mockito.org/ - License: MIT</p> <p>Component: MockK Licensor: github.com/mockk Website: https://github.com/mockk/mockk @@ -66,6 +62,14 @@ Licensor: Google Website: https://github.com/google/protobuf-gradle-plugin License: BSD 3-Clause</p> +<p>Component: Dagger + Licensor: Google + Website: https://github.com/google/dagger + License: Apache 2.0</p> +<p>Component: AssistedInject + Licensor: Square + Website: https://github.com/square/AssistedInject + License: Apache 2.0</p> <p>Component: Conscrypt Licensor: Conscrypt Website: https://github.com/google/conscrypt @@ -264,23 +268,6 @@ as modifying the License. </li> </ol> <p>The MIT License</p> -<p>Copyright (c) 2007 Mockito contributors</p> -<p>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:</p> -<p>The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software.</p> -<p>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.</p> -<p>The MIT License</p> <p>Copyright (c) 2010 Xtreme Labs, Pivotal Labs and Google Inc.</p> <p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Corona-Warn-App/src/main/assets/technical_tr.html b/Corona-Warn-App/src/main/assets/technical_tr.html index 396367104674cc8e299ce74bfd5cf4497eab69b8..cb8322cc84be6d36cdaf9fe0731b9a6bab8317f6 100644 --- a/Corona-Warn-App/src/main/assets/technical_tr.html +++ b/Corona-Warn-App/src/main/assets/technical_tr.html @@ -18,10 +18,6 @@ Licensor: Joda.org Website: https://www.joda.org/joda-time/ License: Apache 2.0</p> -<p>Component: Mockito - Licensor: Mockito contributors - Website: https://site.mockito.org/ - License: MIT</p> <p>Component: MockK Licensor: github.com/mockk Website: https://github.com/mockk/mockk @@ -66,6 +62,14 @@ Licensor: Google Website: https://github.com/google/protobuf-gradle-plugin License: BSD 3-Clause</p> +<p>Component: Dagger + Licensor: Google + Website: https://github.com/google/dagger + License: Apache 2.0</p> +<p>Component: AssistedInject + Licensor: Square + Website: https://github.com/square/AssistedInject + License: Apache 2.0</p> <p>Component: Conscrypt Licensor: Conscrypt Website: https://github.com/google/conscrypt @@ -264,23 +268,6 @@ as modifying the License. </li> </ol> <p>The MIT License</p> -<p>Copyright (c) 2007 Mockito contributors</p> -<p>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:</p> -<p>The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software.</p> -<p>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.</p> -<p>The MIT License</p> <p>Copyright (c) 2010 Xtreme Labs, Pivotal Labs and Google Inc.</p> <p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Corona-Warn-App/src/main/assets/terms_de.html b/Corona-Warn-App/src/main/assets/terms_de.html index 28f2bf16ad0cb35e6b6393c775d0d2871533a3f2..03458bc785114d5a938ab96335998898be4184d4 100644 --- a/Corona-Warn-App/src/main/assets/terms_de.html +++ b/Corona-Warn-App/src/main/assets/terms_de.html @@ -8,7 +8,7 @@ INHALT </p> <p> - 1. Welche Funktionen hat die APP? + 1. Welche Funktionen hat die App? </p> <p> 2. Was bedeutet niedriges oder erhöhtes Risiko? @@ -60,20 +60,22 @@ </p> <p> vertreten durch den Präsidenten. Für Fragen, Beschwerden und Ansprüche im - Zusammenhang mit diesen Nutzungsbedingungen können Sie das RKI telefonisch - unter +49 30 18754-5100 und per E-Mail unter CoronaWarnApp@rki.de - erreichen. + Zusammenhang mit diesen Nutzungsbedingungen können Sie das RKI per E-Mail + unter CoronaWarnApp@rki.de erreichen. </p> <p> Bitte lesen Sie diese Nutzungsbedingungen sorgfältig. Diese - Nutzungsbedingungen regeln Ihre Nutzung der Corona Warn App einschließlich - der Nutzung zukünftiger Versionen (Patches, Updates und Upgrades) ("<strong>App</strong>") und - der Nutzung weiterer Dienste ("<strong>CWA-Dienste</strong>"), die derzeit oder - zukünftig vom RKI im Zusammenhang mit der App bereitgestellt werden. Die - separate Datenschutzerklärung (siehe - https://www.coronawarn.app/assets/documents/cwa-privacy-notice-de.pdf) ist - Bestandteil dieser Nutzungsbedingungen. Bitte lesen Sie auch die - Datenschutzerklärung sorgfältig. + Nutzungsbedingungen regeln Ihre Nutzung der Corona-Warn-App einschließlich + der Nutzung zukünftiger Versionen (Patches, Updates und Upgrades) („<strong>App</strong>“) und + der Nutzung weiterer Dienste („<a name="_Hlk41947003"><strong>CWA-Dienste</strong>“), die + derzeit oder + zukünftig vom RKI im Zusammenhang mit der App bereitgestellt werden. Sie + können diese Nutzungsbedingungen jederzeit in der App unter + „App-Informationen“ und unter https://www.coronawarn.app/assets/documents/cwa-eula-de.pdf + abrufen. Die separate Datenschutzerklärung (siehe unter „App-Informationen“ + und unter https://www.coronawarn.app/assets/documents/cwa-privacy-notice-de.pdf + ) ist nicht Bestandteil dieser Nutzungsbedingungen. Bitte lesen Sie dennoch + auch die Datenschutzerklärung sorgfältig. </p> <p> Die App ist für die Nutzung auf iOS-Geräten im Apple App Store verfügbar @@ -88,85 +90,111 @@ Nutzungsbedingungen einverstanden. Sollten Sie mit den Nutzungsbedingungen nicht einverstanden sein, dürfen Sie die App nicht installieren oder nutzen (bzw. müssen diese wieder löschen) und dürfen auch die die damit - verbundenen Dienste und Systeme nicht nutzen. Etwaige Rechte unter Open + verbundenen Dienste und Systeme nicht nutzen. Etwaige Rechte unter Open- Source-Lizenzen in Bezug auf den Quellcode der App bleiben hiervon unberührt. </p> <p> Sie sind für die Einhaltung dieser Nutzungsbedingungen auch dann - verantwortlich, wenn Sie das Endgerät, auf dem Sie die App installiert + verantwortlich, wenn Sie das Smartphone, auf dem Sie die App installiert haben, Dritten überlassen und diese die App verwenden. </p> <p> Die App richtet sich an Personen, die mindestens 16 Jahre alt sind. - Personen unter 16 Jahren dürfen die App nur mit Zustimmung ihres/ihrer - Sorgeberechtigten verwenden. </p> <p> 1. WELCHE FUNKTIONEN HAT DIE APP? </p> <p> - Ziel der Corona Warn App ist es, SARS-CoV-2-Infektionsketten frühzeitig zu + Ziel der App ist es, SARS-CoV-2-Infektionsketten frühzeitig zu durchbrechen. Personen sollen möglichst zuverlässig und schnell über Begegnungen mit infizierten Personen und damit mögliche Ãœbertragungen des Virus informiert werden, damit sie sich freiwillig isolieren können, um damit zu einer Eindämmung der SARS-CoV-2-Pandemie beizutragen. </p> +<p> + Die App nutzt das von Apple und Google bereitgestellte System für + COVID-19-Begegnungsbenachrichtigungen („<strong>COVID-19-Benachrichtigungssystem</strong>“), das + integraler + Bestandteil des Betriebssystems Ihres Smartphones ist. Der genaue Name, die + Bedienung und der Funktionsumfang des COVID-19-Benachrichtigungssystems + können je nach Hersteller und Version Ihres Betriebssystems variieren. Das + COVID-19-Benachrichtigungssystem ist kein Bestandteil der CWA-Dienste oder + der App, sondern eine Systemanforderung der App. Für die Verfügbarkeit, + Funktionsfähigkeit, Zuverlässigkeit und die Nutzungsbedingungen und + Datenverarbeitung des COVID-19-Benachrichtigungssystems ist der Anbieter + des jeweiligen Betriebssystems verantwortlich. Das RKI hat hierauf keinen + Einfluss. +</p> <p> Die wesentlichen Funktionen der App sind nachstehend beschrieben. Hierbei handelt es sich um eine Beschreibung zu Ihrer Information und nicht um eine - Beschaffenheitsvereinbarung oder die Vereinbarung bestimmter Funktionen, - bitte beachten Sie die diesbezüglichen Hinweise und Vorbehalte unter Ziffer + Beschaffenheitsvereinbarung oder die Vereinbarung bestimmter Funktionen. + Bitte beachten Sie die diesbezüglichen Hinweise und Vorbehalte unter Ziffer 10. </p> <p> - Hintergrund + Risiko-Ermittlung </p> <p> - Die App läuft auf dem Endgerät im Hintergrund und speichert automatisiert - und verschlüsselt die Zufallscodes (<em>rolling proximity identifier</em>) - anderer in der Nähe befindlicher Endgeräte. In regelmäßigen Abständen holt - sich die App über die CWA-Dienste eine Liste der Zufallscodes (<em>temporary exposure keys</em>) - der Personen, die sich freiwillig - infiziert gemeldet haben, und vergleicht diese mit den gespeicherten - Zufallscodes im Gerät, um eine Risiko-Begegnung zu ermitteln. + Nachdem Sie das COVID-19-Benachrichtigungssystem Ihres Betriebssystems und + die Risiko-Ermittlung in der App aktiviert haben, beginnt das + COVID-19-Benachrichtigungssystem mit der Aussendung von Zufalls-IDs über + die Bluetooth-Schnittstelle Ihres Geräts. Zugleich empfängt das + COVID-19-Benachrichtigungssystem die Zufalls-IDs von anderen Nutzern und + speichert diese zusammen mit den für die Bestimmung des Infektionsrisikos + relevanten technischen Informationen zur Bluetooth-Signalstärke (je stärker + das Signal, desto geringer ist in der Regel der Abstand), zum Tag und zur + Dauer der Begegnung. </p> <p> - Die App kann nur Begegnungen mit Personen registrieren, die ihrerseits ein - Endgerät mit installierter App bei sich führen und alle Voraussetzungen für - die Nutzung der App erfüllen (siehe unten Ziffer 7). Begegnungen mit - anderen Personen kann die App nicht registrieren. + In regelmäßigen Abständen holt sich die App über die CWA-Dienste eine Liste + der Zufalls-IDs der Personen, die sich in der offiziellen Corona-App eines + am länderübergreifenden Warnsystem teilnehmenden Landes infiziert gemeldet + haben, und übergibt diese an das COVID-19-Benachrichtigungssystem. Das + COVID-19-Benachrichtigungssystem vergleicht diese mit den gespeicherten + Zufalls-IDs im Gerät, um eine Risiko-Begegnung zu ermitteln. </p> <p> - Risikobenachrichtigung + Infektionsrisiko </p> <p> - Bei einer festgestellten Risiko-Begegnung zu positiv getesteten Personen - erhalten Sie eine Benachrichtigung und verhaltensbezogene Empfehlungen. - Hier kann zum Beispiel die Kontaktaufnahme mit ärztlichem Fachpersonal, mit - dem zuständigen Gesundheitsamt und/oder die freiwillige häusliche Isolation - empfohlen werden. + Bei einer vom COVID-19-Benachrichtigungssystem festgestellten + Risiko-Begegnung mit einer positiv getesteten Person informiert das + COVID-19-Benachrichtigungssystem die App und übergibt ihr die + Aufzeichnungen zur Signalstärke, zum Tag und zur Dauer des Kontakts. Die + App bewertetet diese Aufzeichnungen und informiert Sie dann über das für + Sie ermittelte Infektionsrisiko und entsprechende Handlungsempfehlungen des + RKI. Hier kann zum Beispiel die Kontaktaufnahme mit ärztlichem + Fachpersonal, mit dem zuständigen Gesundheitsamt und/oder die freiwillige + häusliche Isolation empfohlen werden. </p> <p> - Benachrichtigung über Testergebnisse + Testregistrierung </p> <p> Ab dem Zeitpunkt der Probenabgabe für einen Test auf eine SARS-CoV-2-Infektion können Sie über die App den digitalen Testinformationsprozess starten und damit über das Testergebnis - benachrichtigt werden. Die App übermittelt lediglich das vom jeweiligen - Labor mitgeteilte Testergebnis. Das RKI ist weder für die Durchführung des - Tests noch für den Inhalt des Testergebnisses verantwortlich. + benachrichtigt werden. Voraussetzung ist, dass das Testlabor an die + CWA-Dienste angeschlossen ist und Ihnen einen QR-Code oder eine TAN für die + Testregistrierung aushändigt. Die App übermittelt lediglich das vom + jeweiligen Labor mitgeteilte Testergebnis. Das RKI ist weder für die + Durchführung des Tests noch für den Inhalt des Testergebnisses + verantwortlich. </p> <p> - Infektfall + Andere warnen </p> <p> - Im Fall eines positiven SARS-CoV-2-Befunds können Sie freiwillig die in der - App gespeicherten eigenen Zufallscodes der letzten 14 Tage als - Positivkennungen (<em>diagnosis keys</em>) veröffentlichen, damit andere - Personen, die die App nutzen, auf ihrem eigenen Endgerät abgleichen können, - ob sie mit Ihnen eine Risiko-Begegnung hatten. + Im Fall eines positiven SARS-CoV-2-Befunds können Sie die im + COVID-19-Benachrichtigungssystem gespeicherten eigenen Zufalls-IDs der + letzten 14 Tage sowie optionale Angaben zum erstmaligen Auftreten von + eventuellen Krankheitssymptomen an die CWA-Dienste übermitteln, damit + andere Personen, die die offizielle Corona-App eines am + länderübergreifenden Warnsystem teilnehmenden Landes nutzen, auf ihrem + eigenen Smartphone benachrichtigt werden können, falls sie mit Ihnen eine + Risiko-Begegnung hatten. </p> <p> Technische Beschreibung der App @@ -189,10 +217,12 @@ <p> Weiterführende Informationen zur App finden Sie unter folgendem Link: https://www.coronawarn.app/de/ + (Anbieter: SAP Deutschland SE & Co. KG) </p> <p> Weiterführende Informationen zur SARS-CoV-2-Pandemie finden Sie unter folgendem Link: https://www.zusammengegencorona.de/ + (Anbieter: Bundesministerium für Gesundheit) </p> <p> Diese weiterführenden Informationen dienen lediglich der Erläuterung und @@ -202,22 +232,26 @@ 2. WAS BEDEUTET NIEDRIGES ODER ERHÖHTES RISIKO? </p> <p> - Die App berechnet auf Basis der festgestellten Begegnungen ein indikatives - individuelles Risiko. Hierbei werden Faktoren wie der Zeitraum seit der - Begegnung (<em>days since exposure</em>), die Dauer der Begegnung (<em>exposure duration</em>), - die ungefähre Nähe zur infizierten Person, - basierend auf der gemessenen Dämpfung des Bluetooth-Signals (<em>signal attenuation</em>) sowie - ggf. Ãœbertragungsrisiken (<em>transmission risk</em> berücksichtigt. Auf dieser Basis wird Ihnen - in - der App entweder ein "niedriges Risiko" oder ein "erhöhtes Risiko" - angezeigt. Es handelt sich hierbei um einen rein indikativen Wert auf der - Grundlage der erfassten Daten. + Die App berechnet auf Basis der vom COVID-19-Benachrichtigungssystem + aufgezeichneten Begegnungen ein geschätztes individuelles Risiko. Hierbei + werden Faktoren wie der Zeitraum seit der Begegnung, die Dauer der + Begegnung, die ungefähre Nähe zur Corona-positiv getesteten Person, + basierend auf der gemessenen Dämpfung des Bluetooth-Signals, sowie die Dauer + seit Symptombeginn (sofern von der Corona-positiv getesteten Person beim + Bereitstellen der Zufalls-IDs angegeben) berücksichtigt. +</p> +<p> + Auf dieser Basis wird Ihnen in der App ein „niedriges“, „erhöhtes“ oder – + wenn keine Risiko-Ermittlung durchgeführt werden kann – „unbekanntes + Risiko" angezeigt. Es handelt sich hierbei um eine Schätzung auf der + Grundlage der vom COVID-19-Benachrichtigungssystem und den CWA-Diensten + bereitgestellten Daten. <strong> Eine Aussage über das Vorliegen einer tatsächlichen Infektion mit SARS-CoV-2 ist hiermit nicht verbunden. </strong> - Auch bei der Angabe eines "niedrigen Risikos" kann eine Infektion - vorliegen, während auch bei Angabe eines "erhöhten Risikos" eine Infektion + Auch bei der Angabe eines „niedrigen Risikos“ kann eine Infektion + vorliegen, während auch bei Angabe eines „erhöhten Risikos“ eine Infektion nicht gegeben sein kann. </p> <p> @@ -234,14 +268,13 @@ 3. RISIKO-BEGEGNUNG – WAS TUN? </p> <p> - Wenn Sie über die App eine Benachrichtigung über eine festgestellte - Risiko-Begegnung mit infizierten Personen erhalten, erhalten Sie - verhaltensbezogene Empfehlungen in der Benachrichtigung. Diese Empfehlungen - sind rechtlich nicht verbindlich, ihre Befolgung wird aber vom RKI - empfohlen. Gesetzliche und vertragliche Pflichten sowie behördliche - Anordnungen für den Fall einer Risiko-Begegnung mit infizierten Personen - bleiben unberührt und müssen von Ihnen unabhängig von diesen Empfehlungen - befolgt werden. + Wenn Sie über die App über eine festgestellte Risiko-Begegnung mit + Corona-positiv getesteten Personen informiert werden, erhalten Sie + verhaltensbezogene Empfehlungen. Diese Empfehlungen sind rechtlich nicht + verbindlich, ihre Befolgung wird aber vom RKI empfohlen. Gesetzliche und + vertragliche Pflichten sowie behördliche Anordnungen für den Fall einer + Risiko-Begegnung mit infizierten Personen bleiben unberührt und müssen von + Ihnen unabhängig von diesen Empfehlungen befolgt werden. </p> <p> <strong> @@ -250,27 +283,29 @@ </p> <p> <strong> - Die Benachrichtigung bedeutet nicht, dass Sie sich mit SARS-CoV-2 - infiziert haben. + Die Information über eine Risiko-Begegnung bedeutet nicht, dass Sie + sich mit SARS-CoV-2 infiziert haben. </strong> - Sie besagt lediglich, dass sie während der letzten 14 Tage eine + Sie besagt lediglich, dass Sie während der letzten 14 Tage eine Risiko-Begegnung mit einer anderen Person hatten, bei der eine SARS-CoV-2-Infektion positiv festgestellt wurde. Hieraus ergibt sich für Sie zunächst nur eine Möglichkeit, dass Sie sich ebenfalls infiziert haben - könnten. Die Einstufung des diesbezüglichen Risikos als "niedrig" oder - "erhöht" erfolgt allein auf der Basis der ermittelten Daten und lässt keine - Aussage über das tatsächliche Vorliegen einer Infektion zu. + könnten. Die Einstufung des diesbezüglichen Risikos als „niedrig“ oder + „erhöht“ erfolgt allein auf der Basis der vom + COVID-19-Benachrichtigungssystem und den CWA-Diensten (z.B. Angaben zum + Symptombeginn) bereitgestellten Daten und lässt keine Aussage über das + tatsächliche Vorliegen einer Infektion zu. </p> <p> <strong> - Die Benachrichtigung über eine Risiko-Begegnung kann unzutreffend sein. + Die Information über eine Risiko-Begegnung kann unzutreffend sein. </strong> - Die Risiko-Begegnung kann von Ihrem Endgerät beispielsweise zu einem - Zeitpunkt registriert worden sein, zu dem Sie sich nicht in der Nähe Ihres - Endgeräts aufgehalten haben oder während eine andere Person Ihr Endgerät - verwendet hat. Die Risiko-Begegnung kann auch aufgrund bestehender Grenzen - bei der Kontaktmessung fälschlicherweise registriert worden sein (siehe - unten Ziffer 8). + Die Risiko-Begegnung kann vom COVID-19-Benachrichtigungssystem + beispielsweise zu einem Zeitpunkt aufgezeichnet worden sein, zu dem Sie + sich nicht in der Nähe Ihres Smartphones aufgehalten haben oder während eine + andere Person Ihr Smartphone verwendet hat. Die Risiko-Begegnung kann auch + aufgrund bestehender Grenzen des COVID-19-Benachrichtigungssystems + fälschlicherweise registriert worden sein (siehe unten Ziffer 8). </p> <p> 4. KEIN INFEKTIONSSCHUTZ DURCH DIE APP @@ -292,21 +327,22 @@ <li> <strong> Sie können sich auch mit SARS-CoV-2 infizieren, ohne dass die App - Sie über die Risiko-Begegnung mit der Person benachrichtigt, die - Sie infiziert hat: + Sie über die Risiko-Begegnung mit der Person informiert, die Sie + infiziert hat: </strong> </li> </ul> <p> - o Die App registriert nicht alle Ihre Begegnungen mit anderen Personen, - z.B. weil andere Personen die App nicht verwenden, Sie Ihr Endgerät nicht - immer bei sich tragen oder die App nicht immer in Betrieb haben oder weil - die Kontaktmessung gewissen Grenzen unterliegt (siehe unten Ziffer 8). + o Die App kennt nicht alle Ihre Begegnungen mit anderen Personen, z.B. weil + andere Personen die App nicht verwenden, Sie Ihr Smartphone nicht immer bei + sich tragen oder die App nicht immer in Betrieb haben oder weil die + Begegnungsaufzeichnung mit dem COVID-19-Benachrichtigungssystem gewissen + Grenzen unterliegt (siehe unten Ziffer 8). </p> <p> - o Die App informiert Sie nur über festgestellte Risiko-Begegnungen mit - infizierten Personen. Das setzt voraus, dass die App die Begegnung mit der - infizierten Person registriert hat <u>und</u> die infizierte Person eine + o Die App informiert Sie nur über vom COVID-19-Benachrichtigungssystem + festgestellte und an die App weitergegebene Risiko-Begegnungen mit + infizierten Personen. Das setzt voraus, dass die infizierte Person eine Warnung über die App auslöst. Das Auslösen der Warnung ist freiwillig und erfolgt möglicherweise nicht durch alle infizierten Personen. </p> @@ -318,12 +354,15 @@ </p> <p> www.infektionsschutz.de/coronavirus + (Anbieter: Bundeszentrale für gesundheitliche Aufklärung) </p> <p> www.zusammengegencorona.de + (Anbieter: Bundesministerium für Gesundheit) </p> <p> www.rki.de/covid-19 + (Anbieter: RKI) </p> <p> Diese weiterführenden Informationen dienen lediglich Ihrer Information und @@ -334,7 +373,7 @@ </p> <p> <strong>A</strong> - - Halten Sie mindestens 1,5m Abstand zu Ihren Mitmenschen + - Halten Sie mindestens 1,5 m Abstand zu Ihren Mitmenschen </p> <p> <strong>H</strong> @@ -366,15 +405,17 @@ 6. AUSLÖSEN EINER WARNUNG </p> <p> - Sie können über die App andere Kontaktpersonen warnen, wenn Sie mit - SARS-CoV-2 infiziert wurden. <strong>Sie dürfen diese Warnung nur auslösen, wenn - die Infektion durch einen Test in einem zugelassenen Testlabor positiv - bestätigt wurde. -</strong> + Sie können über die App andere Kontaktpersonen warnen, wenn Sie positiv auf + eine Infektion mit SARS-CoV-2 getestet wurden. <strong>Sie dürfen diese Warnung nur auslösen, + wenn </strong> + <strong> + die Infektion durch einen Test in einem zugelassenen Testlabor positiv + bestätigt wurde. + </strong> </p> <p> - Falls das zugelassene Testlabor noch nicht an die CWA-Dienste angeschlossen - ist, erfolgt eine Ãœberprüfung Ihres Infektionsstatus über eine vom RKI + Falls Ihr Testlabor noch nicht an die CWA-Dienste angeschlossen ist, + erfolgt eine Ãœberprüfung Ihres Infektionsstatus über eine vom RKI eingerichtete Verifikations-Hotline. Das Auslösen einer Warnung über die App auf der Grundlage einer bloßen Risiko-Mitteilung ist nicht zulässig. </p> @@ -383,11 +424,11 @@ </p> <p> Wenn Sie nicht sicher sind, ob Sie sich infiziert haben oder nicht, dann - kontaktieren Sie bitte Ihren Hausarzt oder das zuständige Gesundheitsamt, - bevor Sie eine Warnung auslösen. Hier erhalten Sie weitere Beratung und - können sich erforderlichenfalls auf eine Infektion testen lassen. In der - Zwischenzeit befolgen Sie die allgemein gültigen Empfehlungen für das - Verhalten bei dem Verdacht einer SARS-CoV-2-Infektion. + kontaktieren Sie bitte Ihren Hausarzt oder das zuständige Gesundheitsamt. + Hier erhalten Sie weitere Beratung und können sich erforderlichenfalls auf + eine Infektion testen lassen. In der Zwischenzeit befolgen Sie die + allgemein gültigen Empfehlungen für das Verhalten bei dem Verdacht einer + SARS-CoV-2-Infektion. </p> <p> Missbrauchsverbot @@ -398,12 +439,7 @@ schwerwiegende Konsequenzen nach sich ziehen. </strong> Insbesondere können Sie sich eventuell gegenüber anderen betroffenen - Personen schadenersatzpflichtig machen. -</p> -<p> - Das RKI behält sich vor, Sie bei Feststellung eines missbräuchlichen - Verhaltens von der weiteren Nutzung der App und der CWA-Dienste - auszuschließen. + Personen schadensersatzpflichtig machen. </p> <p> 7. VORAUSSETZUNGEN FÃœR DIE NUTZUNG DER APP @@ -418,36 +454,40 @@ <p> Bestimmte Funktionen der App setzen auf zentrale Dienste und Systeme auf, die über die CWA-Dienste zur Verfügung gestellt werden. Diese Funktionen - stehen daher nur zur Verfügung, wenn Ihr Endgerät über eine Datenverbindung + stehen daher nur zur Verfügung, wenn Ihr Smartpnone über eine Datenverbindung mit dem Internet verfügt, z.B. über UMTS, LTE oder WLAN, um hierüber auf die CWA-Dienste zugreifen zu können. Ohne Datenverbindung stehen einige oder alle Funktionen der App nicht zur Verfügung. Dies gilt auch, wenn Sie - Ihr Endgerät in den Flugmodus versetzen oder ausschalten. + Ihr Smartphone in den Flugmodus versetzen oder ausschalten. </p> <p> - Die App muss auf dem Endgerät laufen und eingeschaltet sein + Das COVID-19-Benachrichtigungssystem muss aktiviert sein </p> <p> - Die App muss auf Ihrem Endgerät im Vorder- oder Hintergrund laufen und - eingeschaltet sein. Hierzu müssen Sie die App starten. Wenn Sie die App - nicht starten, ausschalten oder beenden, speichert die App keine - Begegnungen mit anderen Personen und erzeugt keine Zufallscodes zur - Speicherung durch andere Personen. Wenn Sie das Endgerät neu starten (z.B. - nach dem Ausschalten, nachdem die Batterie leer war oder nach einem Update - des Betriebssystems), müssen Sie auch die App neu starten. + Das COVID-19-Benachrichtigungssystem Ihres Smartphones muss aktiviert und für + die Region „Deutschland“ bzw. die App freigegeben sein. </p> <p> - Einstellungen im Endgerät + <strong><em>Hintergrundaktualisierung</em></strong> +</p> +<p> + Die App muss dauerhaft im Hintergrundbetrieb laufen. Wenn Sie das Smartphone + neu starten (z.B. nach dem Ausschalten, nachdem die Batterie leer war oder + nach einem Update des Betriebssystems) oder nach einer erzwungenen + Beendigung der App müssen Sie auch die App neu starten. +</p> +<p> + Einstellungen im Smartphone </p> <p> Für die Nutzung der App müssen Sie ferner die Bluetooth (BLE)-Funktionen - auf Ihrem Endgerät aktivieren und ggf. zur Verwendung durch die App - freigegeben. + auf Ihrem Smartphone aktivieren und ggf. zur Verwendung durch die App + freigeben. </p> <p> Für die Nutzung der App empfiehlt das RKI ferner folgende Funktionen auf - Ihrem Endgerät zu aktivieren und ggf. zur Verwendung durch die App - freizugegeben, auch wenn diese nicht Voraussetzung für die Nutzung der + Ihrem Smartphone zu aktivieren und ggf. zur Verwendung durch die App + freizugeben, auch wenn diese nicht Voraussetzung für die Nutzung der grundlegenden Funktionen der App sind: </p> <ul> @@ -459,22 +499,25 @@ </li> </ul> <p> - Bitte prüfen Sie in den Einstellungen ihres Endgeräts, ob diese Funktionen + Bitte prüfen Sie in den Einstellungen Ihres Smartphones, ob diese Funktionen aktiviert und für die Verwendung der App freigegeben sind. </p> <p> Eine ausführliche Anleitung zur Einrichtung der App unter iOS und Android - finden Sie unter https://www.coronawarn.app/de/. Die Anleitung dient lediglich der - Erläuterung und ist nicht Teil dieser Nutzungsbedingungen. + finden Sie auf der Website des Open-Source-Projekts für die Corona-Warn-App + unter https://www.coronawarn.app/de/ + (Anbieter: SAP Deutschland SE & Co. KG). Die Anleitung dient lediglich + der Erläuterung und ist nicht Teil dieser Nutzungsbedingungen. </p> <p> - Sie müssen immer die aktuelle Version der App verwenden + Sie müssen immer eine aktuelle Version der App verwenden </p> <p> Das RKI wird von Zeit zu Zeit Updates der App zur Verfügung stellen. Sie - müssen diese Updates unverzüglich installieren und immer die neueste + sollten diese Updates unverzüglich installieren und immer die neueste verfügbare Version der App verwenden. Beim Verwenden älterer Versionen kann - es zu Fehlfunktionen und Störungen kommen. + es zu Fehlfunktionen und Störungen kommen. Sofern ein Update zwingend + erforderlich ist, werden Sie beim Öffnen der App darauf hingewiesen. </p> <p> <strong> @@ -482,41 +525,48 @@ </strong> </p> <p> - Die App verwendet eigens von Apple in iOS und Google in Android - implementierte Funktionen (<em>sog. Exposure Notification</em>). Diese - stehen in iOS erst ab Version 13.5 und in Android erst ab Version 6 - zur Verfügung. Die App funktioniert daher leider nicht mit früheren - Versionen der beiden Betriebssysteme. + Die App verwendet das eigens von Apple in iOS und Google in Android + implementierte COVID-19-Benachrichtigungssystem. Dieses steht in iOS erst + ab Version 13.5 und in Android erst ab Version 6 zur Verfügung. Die App + funktioniert daher leider nicht mit früheren Versionen der beiden + Betriebssysteme. </p> <p> 8. GRENZEN DER APP </p> <p> - Die App kann Sie dabei unterstützen, Risiko-Begegnungen mit Personen zu - erkennen, die später positiv getestet wurden. Die App hat aber auch - Grenzen, die berücksichtigt werden müssen. -</p> -<p> - Eine dieser Grenzen ist, dass die App zwar laufend eigene Zufallscodes (<em>Rolling Proximity - Identifiers</em>) aussendet, aber andere Zufallscodes - nur in bestimmten Intervallen empfängt. Diese Empfangsfenster liegen - derzeit noch bis zu fünf Minuten auseinander und sind nur als sehr kurz - spezifiziert. - In der App sind die Empfangsfenster vier Sekunden lang. - Diese Funktionalitäten sind Bestandteil der - Exposure Notification Frameworks von Google beziehungsweise Apple, - welche jederzeit geändert werden können. -</p> -<p> - Für die Entfernungsmessung wird die Dämpfung des Bluetooth-Signals - verwendet. Eine geringere Dämpfung bedeutet dabei grundsätzlich, dass das - andere Endgerät näher ist. Eine höhere Dämpfung kann entweder bedeuten, - dass das andere Endgerät weiter entfernt ist (also eine Entfernung von mehr - als zwei Metern) oder dass sich zwischen den beiden Endgeräten etwas - befindet, was das Signal blockiert. Das können Objekte wie eine Wand oder - eine Tasche, in der sich das Endgerät befindet, sein, aber genauso Personen - oder Tiere. + Die App kann Sie dabei unterstützen, Risiko-Begegnungen mit anderen Nutzern + zu erkennen, die später positiv getestet wurden. Die App hat aber auch + Grenzen, die berücksichtigt werden müssen, insbesondere: </p> +<ul> + <li> + Die App kann nur die vom COVID-19-Benachrichtigungssystem Ihres + Betriebssystems aufgezeichneten und an die App weitergegebenen + Risiko-Begegnungen bewerten. Die Verfügbarkeit, Vollständigkeit, + Richtigkeit und Zuverlässigkeit dieser Aufzeichnungen im + COVID-19-Benachrichtigungssystem können vom RKI nicht beeinflusst + werden. + </li> + <li> + Die App kann Sie nur vor Risiko-Begegnungen mit Corona-positiv + getesteten Nutzern einer offiziellen Corona-App eines am + länderübergreifenden Warnsystem teilnehmenden Landes warnen, die ihr + positives Testergebnis über die jeweilige Corona-App für die + länderübergreifende Warnfunktion zur Verfügung gestellt haben. + </li> + <li> + Für die Bewertung des Infektionsrisikos nutzt die App die + Aufzeichnungen zur Dämpfung des Bluetooth-Signals. Eine geringere + Dämpfung bedeutet dabei grundsätzlich, dass das andere Smartphone näher + ist. Eine höhere Dämpfung kann entweder bedeuten, dass das andere + Smartphone weiter entfernt ist (also eine Entfernung von mehr als zwei + Metern) oder dass sich zwischen den beiden Smartphones etwas befindet, + was das Signal blockiert. Das können Objekte wie eine Wand oder eine + Tasche, in der sich das Smartphone befindet, sein, aber genauso Personen + oder Tiere. + </li> +</ul> <p> 9. NUTZUNGSRECHTE </p> @@ -532,7 +582,7 @@ Die Lizenz für die iOS-Version der App umfasst die Nutzung auf jedem Apple-Gerät, an dem Sie Eigentum haben oder über das Sie Kontrolle ausüben, im Rahmen der geltenden Nutzungsbedingungen des App Stores, wobei auch über - andere Apple Accounts, die mit Ihrem Apple Account via Family Sharing oder + andere Apple-Accounts, die mit Ihrem Apple-Account via Family Sharing oder Volumenkauf verbunden sind, auf die App zugegriffen und diese genutzt werden kann. </p> @@ -544,25 +594,25 @@ <strong><em>Eigentum an der App</em></strong> </p> <p> - Die App (einschließlich des Quellcodes) ist das alleinige und - ausschließliche Eigentum von SAP SE, Dietmar Hopp Allee 16, 69190 Walldorf - („<strong>SAP</strong>“) oder deren Lizenzgebern, vorbehaltlich der Ihnen - nach Ziffer 9 eingeräumten Rechte sowie sonstiger Rechte an der App, die - SAP der Bundesrepublik Deutschland vertraglich eingeräumt hat. + Die App ist das alleinige und ausschließliche Eigentum von SAP SE, + Dietmar-Hopp-Allee 16, 69190 Walldorf („<strong>SAP</strong>“) oder deren + Lizenzgebern, vorbehaltlich der Ihnen nach Ziffer 9 eingeräumten Rechte + sowie sonstiger Rechte an der App, die SAP der Bundesrepublik Deutschland + vertraglich eingeräumt hat. </p> <p> - <strong><em>Open Source-Lizenzhinweise</em></strong> + <strong><em>Open-Source-Lizenzhinweise</em></strong> </p> <p> Information über die Verwendung von Drittkomponenten in der App und die - anwendbaren Lizenzbestimmungen finden Sie in den Open + anwendbaren Lizenzbestimmungen finden Sie in den Open- Source-Lizenzhinweisen in der App. </p> <p> - Der Quellcode der App ist unter den Lizenzbedingungen der "Apache 2.0 - License" veröffentlicht und kann unter "https://github.com/corona-warn-app" - heruntergeladen werden. Die Lizenzbedingungen der "Apache 2.0 License" sind - unter "https://www.apache.org/licenses/LICENSE-2.0" abrufbar. + Der Quellcode der App ist unter den Lizenzbedingungen der „Apache 2.0 + License“ veröffentlicht und kann unter „https://github.com/corona-warn-app“ heruntergeladen + werden. Die Lizenzbedingungen der „Apache 2.0 License“ sind unter + „https://www.apache.org/licenses/LICENSE-2.0“ abrufbar. </p> <p> Die auf den Quellcode der App sowie auf in der App enthaltene @@ -579,7 +629,7 @@ Sie dürfen die App und die Schnittstellen zu den CWA-Diensten nicht missbräuchlich verwenden. Sie dürfen die CWA-Dienste nicht für andere Zwecke nutzen als den bestimmungsgemäßen Betrieb der App auf Ihrem - Endgerät. Sie dürfen auf die CWA-Dienste ausschließlich über die App + Smartphone. Sie dürfen auf die CWA-Dienste ausschließlich über die App zugreifen. </p> <p> @@ -618,18 +668,17 @@ Änderung der Nutzungsbedingungen </p> <p> - Das RKI behält sich vor, diese Nutzungsbedingungen zu ändern. In diesem - Fall werden Sie beim Start der App aufgefordert, den geänderten - Nutzungsbedingungen zuzustimmen. Wenn Sie den geänderten - Nutzungsbedingungen nicht zustimmen, können Sie die App und die CWA- - Dienste nicht mehr nutzen und müssen die App von Ihrem Endgerät löschen. + Das RKI behält sich vor, diese Nutzungsbedingungen zu ändern. Wenn Sie den + geänderten Nutzungsbedingungen nicht zustimmen, können Sie die App und die + CWA-Dienste nicht mehr nutzen und müssen die App von Ihrem Smartphone + löschen. </p> <p> - Risk Score + Änderung der Parameter der Risikobewertung </p> <p> - Das RKI behält sich ferner vor, die im Rahmen der Risikobewertung (<em>risk score</em>) - verwendeten Parameter jederzeit zu ändern, um dadurch + Das RKI behält sich ferner vor, die im Rahmen der Bewertung des + Infektionsrisikos verwendeten Parameter jederzeit zu ändern, um dadurch jeweils aktuellen Forschungsergebnissen zur Virusübertragung zu entsprechen. Das RKI bestimmt die verwendeten Parameter jeweils nach seinem Ermessen. @@ -664,9 +713,9 @@ </li> </ul> <p> - Für die Datensicherung Ihres Endgeräts sowie ggf. damit verbundener Systeme + Für die Datensicherung Ihres Smartphones sowie ggf. damit verbundener Systeme sind Sie verantwortlich, inklusive der Datensicherung sämtlicher anderer - Apps, welche auf Ihrem Endgerät gespeichert sind. + Apps, welche auf Ihrem Smartphone gespeichert sind. </p> <p> 12. BESONDERE BEDINGUNGEN FÃœR DIE IOS-VERSION DER APP @@ -675,21 +724,6 @@ Die folgenden Bedingungen gelten für den Bezug der App über den Apple App Store und die Nutzung der App unter dem Betriebssystem iOS. </p> -<p> - Einwilligung zur Nutzung von Daten -</p> -<p> - Sie erklären sich damit einverstanden, dass das RKI technische Daten und - zugehörige Informationen – insbesondere technische Informationen über Ihr - Gerät, System und Ihre Anwendungssoftware sowie Peripheriegeräte – erheben - und nutzen darf, die in regelmäßigen Abständen erfasst werden, um die - Bereitstellung von Software-Aktualisierungen, Produkt-Support und anderen - im Zusammenhang mit der App gegenüber Ihnen erbrachten Dienstleistungen - (soweit gegeben) zu erleichtern. Das RKI darf diese Informationen nutzen, - um seine Produkte zu verbessern oder Ihnen Dienstleistungen oder - Technologien zur Verfügung zu stellen, solange dies in einer Form erfolgt, - die Ihre Identität nicht preisgibt. -</p> <p> Wartung und Support </p> @@ -729,7 +763,7 @@ </li> </ul> <p> - einschließlich im Zusammenhang mit der Nutzung der HealthKit und + einschließlich im Zusammenhang mit der Nutzung der HealthKit- und HomeKit-Frameworks. </p> <p> @@ -743,7 +777,7 @@ Schutzrechten. </p> <p> - US Embargos und Sanktionen + US-Embargos und Sanktionen </p> <p> Mit Anerkennen dieser Nutzungsbedingungen bestätigten Sie, @@ -753,12 +787,12 @@ dass Sie sich nicht in einem Land aufhalten, das einem Embargo der Regierung der Vereinigten Staaten von Amerika unterliegt oder von der Regierung der Vereinigten Staaten von Amerika als Unterstützer von - Terroristen (<em>"terrorist supporting" country</em>) designiert wurde + Terroristen (<em>„terrorist supporting“ country</em>) designiert wurde und </li> <li> dass Sie nicht auf einer Liste der Regierung der Vereinigten Staaten - von Amerika als sog. <em>Prohibited or Restricted Party</em> geführt + von Amerika als sog. <em>„Prohibited or Restricted Party“</em> geführt werden. </li> </ul> @@ -792,7 +826,7 @@ Sofern Sie im Zusammenhang mit der Nutzung der App Dienste Dritter in Anspruch nehmen, insbesondere die Dienste von Telekommunikationsdienstleistern für die Bereitstellung einer - Datenverbindung, sind Sie für damit im Zusammenhang stehenden Kosten und + Datenverbindung, sind Sie für die damit im Zusammenhang stehenden Kosten und die Einhaltung der jeweiligen Vertragsbedingungen selbst verantwortlich. </p> <p> @@ -818,4 +852,4 @@ </p> <p> * * * -</p> \ No newline at end of file +</p> diff --git a/Corona-Warn-App/src/main/assets/terms_en.html b/Corona-Warn-App/src/main/assets/terms_en.html index c304c47e96eac9fe51153ceb6c0aabfaafa1096b..270cfdec8c9458625e0c68b6b1a511ebb9486413 100644 --- a/Corona-Warn-App/src/main/assets/terms_en.html +++ b/Corona-Warn-App/src/main/assets/terms_en.html @@ -5,7 +5,7 @@ <strong>Terms of Use</strong> </p> <p> - TABLE OF CONTENTS + CONTENTS </p> <p> 1. What features does the App have? @@ -14,28 +14,29 @@ 2. What does low or elevated risk mean? </p> <p> - 3. What do I do if I have been exposed to a confirmed case? + 3. What should I do if I have been exposed to a confirmed case? </p> <p> 4. The App does not protect you against infection </p> <p> - 5. Accessing test results + 5. Retrieval of test results </p> <p> - 6. Warning feature + 6. Activating the warning feature </p> <p> - 7. Technical requirements + 7. Requirements for using the App </p> <p> 8. Limitations of the App </p> <p> - 9. User rights + 9. Rights of use </p> <p> - 10. Important information on availability and changes + 10. Important information about availability and changes + </p> <p> 11. No warranty @@ -56,202 +57,236 @@ Nordufer 20 </p> <p> - 13353 Berlin ("<strong>RKI</strong>") + 13353 Berlin (<strong>RKI</strong>), </p> <p> - represented by its President. Please call the RKI on +49 30 187 545 100 or - email us at CoronaWarnApp@rki.de if you have any questions relating to - these Terms of Use or if you wish to submit any complaints or legal claims. + which is represented by its President. Please email CoronaWarnApp@rki.de if you have any + questions, complaints or legal claims relating to these Terms of Use. </p> <p> - Please make sure that you read these Terms of Use carefully. These Terms of - Use form the basis for your use of the Corona-Warn-App ("<strong>CWA</strong>") and any future - versions thereof (patches, updates - and upgrades) ("<strong>App</strong>") and the use of any other services ("<strong>CWA - Services</strong>") which are - already available or may be made available by the RKI in connection with - the App. The separate Data Protection Declaration (see - https://www.coronawarn.app/assets/documents/cwa-privacy-notice-en.pdf) - forms an integral part of these Terms of Use. Please also read the Data - Protection Declaration carefully. + Please read these Terms of Use carefully. These Terms of Use govern your + use of the Corona-Warn-App and any future versions thereof (patches, + updates and upgrades) (the <strong>App</strong>) and the use of other + services which are currently provided or will be provided in the future by + the RKI in connection with the App (<strong>CWA Services</strong>). You can + view these Terms of Use at any time by going to “App Information†in the + App itself or by visiting https://www.coronawarn.app/assets/documents/cwa-eula-en.pdf. + The separate privacy notice (also available under “App Information†and + at https://www.coronawarn.app/assets/documents/cwa-privacy-notice-en.pdf + ) is not part of these Terms of Use. Nevertheless, you are advised to read + the privacy notice carefully. </p> <p> - The App is available from the Apple App Store for all iOS devices and from - Google Play for all Android devices. The general terms and conditions for - apps available from Apple or Google do not apply with respect to the RKI. - The RKI is solely responsible for the content and maintenance of the App - and for any legal claims you may have in respect of the App. + The App is available from the Apple App Store for use on iOS devices + and from Google Play for use on Android devices. + General terms of use for apps from Apple or Google do not apply to the RKI. + The RKI is solely responsible for the content of the App as well as its + maintenance and care and for any legal claims you may have in relation to + the App. </p> <p> - You confirm that you agree to these Terms of Use when you install and use - the App. If you do not agree to these Terms of Use, you may not install or - use the App (or you will need to uninstall it) and you will not be able to - use any of the related services or systems. This will not affect any rights - under any open source licences relating to the App's source code. + By installing and using the App, you confirm that you agree to these Terms + of Use. If you do not agree to the Terms of Use, you may not install or use + the App (or you will need to delete it) and nor may you use the associated + services and systems. This does not affect any rights under open-source + licences relating to the App’s source code. </p> <p> - You are still responsible for complying with these Terms of Use if you give - the device on which the App is installed to a third party and they use the - App. + You are responsible for compliance with these Terms of Use even if you give + the device on which you have installed the App to third parties and they + use the App. </p> <p> - The App is intended for use by anyone who is 16 or over. Anyone under 16 - may only use the App with the permission of their parent or guardian (<em>Sorgeberechtigte</em>). + The App is aimed at people who are at least 16 years of age. </p> <p> 1. WHAT FEATURES DOES THE APP HAVE? </p> <p> - The aim of the Corona Warning App is to disrupt chains of infection of - SARS-CoV-2 at an early stage. The intention is to notify people quickly and - reliably about any contact they may have had with infected individuals and - any potential exposure to the virus. This will allow people to self-isolate - and limit the spread of the SARS-CoV-2 pandemic. + The aim of the App is to break SARS-CoV-2 infection chains at an early + stage. The intention is to inform people as reliably and quickly as + possible about encounters they have had with infected individuals and thus + any potential transmission of the virus, so that they can self-isolate and + help to contain the SARS-CoV-2 pandemic. +</p> +<p> + The App uses the COVID-19 exposure notification system provided by Apple + and Google (<strong>COVID-19 Exposure Notification System</strong>), which + is an integral part of your device’s operating system. The exact name, + operation, and functionality of the COVID-19 Exposure Notification System + may vary depending on the manufacturer and version of your operating + system. The COVID-19 Exposure Notification System is not part of the CWA + Services or the App, but a system requirement of the App. The provider of + the respective operating system is responsible for the availability, + functionality, reliability and the terms of use and data processing of the + COVID-19 Exposure Notification System. The RKI has no influence on this. </p> <p> - The key features of the App are set out below. The details provided are - solely for your information. They do not constitute legally binding - specifications or any agreement that certain features must be available. - Please also consult the information and conditions contained in Section 10. + The key features of the App are set out below. The descriptions are + provided for your information. They do not constitute legally binding + specifications or any agreement concerning certain features. Please also + refer to the relevant information and reservations in Section 10. </p> <p> - Background app + Risk identification </p> <p> - The App runs in the background on your device and automatically stores and - encrypts random IDs (rolling proximity identifiers) produced by other - nearby devices. The App regularly collects a list of random IDs (temporary - exposure keys) via the CWA Services for those individuals who have - voluntarily registered themselves as being infected. It then compares these - against the random IDs already stored on the device and identifies any - situation where an infection could have been passed on. + After you have enabled your operating system’s COVID-19 Exposure + Notification System and the App’s risk identification feature, the COVID-19 + Exposure Notification System starts sending random IDs via your device’s + Bluetooth interface. At the same time, the COVID-19 Exposure Notification + System receives the random IDs of other users and stores them together with + technical information, which is relevant for determining the risk of + infection, about the Bluetooth signal strength (generally speaking: the + stronger the signal, the shorter the distance), the day and the duration of + the exposure. </p> <p> - The App is only able to identify and register encounters with other persons - if the App is equally installed on a device carried on by such person and - if such person meets all the conditions for using the App (see Section 7 - below). The App is not able to register whether the user has had contact - with other people as such. + At regular intervals, the App uses the CWA Services to retrieve a list of + the random IDs of people who have reported an infection in the official + coronavirus app of any country participating in the transnational warning + system, and transfers this list to the COVID-19 Exposure Notification + System. The COVID-19 Exposure Notification System compares these with the + random IDs stored in the device to identify a possible exposure. </p> <p> - Exposure notification + Risk of infection </p> <p> - You will receive a notification if you have had exposure to someone who has - a confirmed infection. This notification will include instructions on what - you should do next. This may include contacting a medical professional or - the local public health department (<em>Gesundheitsamt</em>) and/or - self-isolating at home. + In the event of a possible exposure involving someone who tested positive, + the COVID-19 Exposure Notification System notifies the App and provides it + with the information recorded about the signal strength, day, and duration + of the contact. The App evaluates this recorded information and then + informs you about the risk of infection identified for you, and any + corresponding recommendations from the RKI about what you should do next. + This may include contacting a medical professional or the local public + health department (<em>Gesundheitsamt</em>) and/or self-isolating at home. </p> <p> - Notification of test results + Registering a test </p> <p> - As soon as you have been tested for a SARS-CoV-2 infection, you can use the - App to start the digital test notification process. You will then receive a - notification of your test result in due course. The App is only able to - provide the test result from the relevant lab. The RKI is not responsible - for the performance of the test or the content of the test result. + As soon as you have been tested for infection with SARS-CoV-2, you can use + the App to start the digital test information process and thus be notified + of your test result. For this to work, the testing laboratory needs to be + connected to the CWA Services and provide you with a QR code or a TAN to + register your test. The App is only able to provide the test result from + the relevant lab. The RKI is not responsible for conducting the test or for + the content of the test result. </p> <p> - Positive result + Warning others </p> <p> - If your SARS-CoV-2 test is positive, you may use the App to voluntarily - publish your own random IDs registered by the App for the last 14 days as - diagnosis keys. This will enable other App users to check on their own - devices whether they may have had exposure to you during that period. + If your SARS-CoV-2 test result is positive, you can transmit your own + random IDs from the last 14 days, which are stored in the COVID-19 Exposure + Notification System, as well as optional information about the onset of any + symptoms, to the CWA Services. This will allow other people who use the + official coronavirus app of any country participating in the transnational + warning system to be notified on their own devices of any possible exposure + involving you. </p> <p> Technical specifications of the App </p> <p> - Details of the technical features of the App and the related services and - systems are available at: + Detailed descriptions of the technical features of the App and the related + services and systems are available at: </p> <p> https://github.com/Corona-Warn-App </p> <p> - These technical specifications are for information purposes only and do not - form part of these Terms of Use. They are not a legally binding agreement - regarding the quality or specifications for the App. + These technical specifications are provided for information purposes only + and do not form part of these Terms of Use. They do not constitute legally + binding App specifications. </p> <p> Further information </p> <p> - Further information on the App is available at: - https://www.coronawarn.app/en/ + Further information about the App is available at: https://www.coronawarn.app/en/ + (provider: SAP Deutschland SE & Co. KG) </p> <p> - Further information on the SARS-CoV-2 pandemic is available at: + Further information about the SARS-CoV-2 pandemic is available at: https://www.zusammengegencorona.de/ + (provider: Federal Ministry of Health) </p> <p> - The above information is for information purposes only and does not form - part of these Terms of Use. + This further information is provided for information purposes only and does + not form part of these Terms of Use. </p> <p> 2. WHAT DOES LOW OR ELEVATED RISK MEAN? </p> <p> - The App uses any confirmed exposures to calculate the user's indicative - individual risk. It uses factors such as days since exposure, exposure - duration, the proximity to a confirmed case based on the Bluetooth signal - attenuation and any transmission risk. The App will then tell your whether - you are at "low risk" or "elevated risk". This is a purely indicative - assessment based on the data collected. + The App calculates the user’s estimated individual risk based on the + exposures recorded by the COVID-19 Exposure Notification System. It + considers factors such as days since exposure, exposure duration, the + user’s rough proximity to the person who has tested positive for + coronavirus (based on the Bluetooth signal attenuation), and the time since + the onset of symptoms (if indicated by the person who tested positive when + they provided their random IDs). +</p> +<p> + The App will then show you a “lowâ€, “elevatedâ€, or – if the App is unable + to perform risk identification – “unknown†risk. This is an estimate based + on the data provided by the COVID-19 Exposure Notification System and the + CWA Services. <strong> - The App cannot tell you whether you are actually infected with - SARS-CoV-2. + This does not mean that you are actually infected with SARS-CoV-2. </strong> - You may still be infected if you are categorised as "low risk" and you may - not be infected even if you are placed in the "elevated risk" category. + You may still be infected if the App shows a “low riskâ€, and you may not be + infected if it shows an “elevated riskâ€. </p> <p> <strong> - There are a number of other factors which may affect your own personal - risk of infection. The App will not take those factors into account. + Other factors can significantly affect your own personal risk of + infection. The App does not take those factors into account. </strong> - They include your own personal circumstances, the external circumstances of - any exposure to a confirmed case, your own behaviour and any contact with - anyone who is not registered with the App. See also Section 4. + In particular, these include your own personal circumstances, the external + circumstances of any possible exposure to a person with coronavirus, your + own behaviour, and any exposure to third parties which is not recorded by + the App. See also Section 4. </p> <p> - 3. WHAT DO I DO IF I HAVE BEEN EXPOSED TO A CONFIRMED CASE? + 3. WHAT SHOULD I DO IF I HAVE BEEN EXPOSED TO A CONFIRMED CASE? </p> <p> - If the App notifies you that you have been exposed to a confirmed case, you - will also receive information on what to do next. These instructions are - not legally binding, but the RKI does recommend that you follow them. The - recommendations referred to above do not affect any applicable legal or - contractual obligations or any official requirements on what to do in the - event of any exposure to a confirmed case. You must still comply with any - such obligations or requirements. + If the App notifies you of possible exposure to a person who has tested + positive for coronavirus, it will also give you recommendations for what to + do next. These recommendations are not legally binding, but the RKI does + recommend that you follow them. They do not affect your legal or + contractual obligations or any official requirements concerning what to do + in the event of exposure to a confirmed case. You must still comply with + any such obligations or requirements. </p> <p> <strong> - The App does not and cannot be used to provide any form of medical - diagnosis. + No medical diagnosis whatsoever is performed in or using the App. </strong> </p> <p> - <strong>The notification does not mean that you have SARS-CoV-2. </strong> + <strong> + The notification of possible exposure does not mean that you have been + infected with SARS-CoV-2. + </strong> It simply means that you have been exposed to someone with a confirmed case - of SARS-CoV-2 during the last 14 days and that you may also potentially - have been infected. The classification of risk as "low" or "elevated" is - based solely on the available data and does not indicate whether you have - actually been infected. + of SARS-CoV-2 during the last 14 days. Consequently, there is only a + possibility that you could also have been infected. The classification of + the risk as “low†or “elevated†is based solely on the data provided by the + COVID-19 Exposure Notification System and the CWA Services (e.g. + information about the onset of symptoms) and does not indicate whether you + have actually been infected. </p> <p> - <strong> - You may receive an exposure notification which is not accurate. - </strong> - Your device may, for example, register an exposure at a time when you are - not close to your device or while someone else is using it. Exposures may - also be wrongly registered due to existing limitations in contact/proximity - measurement (see Section 8). + <strong>The notification of possible exposure may be inaccurate. </strong> + The COVID-19 Exposure Notification System may, for example, have recorded + the possible exposure at a time when you were not close to your device or + while someone else was using it. The possible exposure may also have been + wrongly registered due to existing limitations in the COVID-19 Exposure + Notification System (see Section 8). </p> <p> 4. THE APP DOES NOT PROTECT YOU AGAINST INFECTION @@ -267,128 +302,125 @@ </li> <li> <strong> - The App does not reduce your own personal risk of infection. + The App will not reduce your own personal risk of infection. </strong> </li> <li> <strong> - You can still catch SARS-CoV-2 without the App notifying you of the - exposure to the person who may have infected you: + You can still become infected with SARS-CoV-2 even if the App + doesn’t notify you of your exposure to the person who infected you: </strong> </li> </ul> <p> - o The App does not register all your contact with other people. This may be - because other people are not using the App, you do not always have your - device on you or you do not have the App activated at all times. There are - also certain limitations in terms of contact/proximity measurement (see - Section 8 below). + o The App does not know about all your encounters with other people. This + may be because other people do not use the App, you do not always carry + your device with you, or you do not always have the App running. The + exposure logging performed by the COVID-19 Exposure Notification System + also has certain limitations (see Section 8). </p> <p> - o The App only notifies you of potential exposures to confirmed cases. The - App needs to have registered your contact with a confirmed case <u>and</u> - the infected individual needs to have activated the App's warning feature. - Activating the warning feature is voluntary and not all infected - individuals may do so. + o The App only notifies you of any possible exposure to confirmed cases if + this has been detected by the COVID-19 Exposure Notification System and + passed on to the App. For this to happen, the infected person must have + activated their own app’s warning feature. Activating the warning feature + is voluntary and some infected persons may choose not to do this. </p> <p> - Please use the App in conjunction with the other relevant precautions and - official requirements. Reliable information on the SARS-CoV-2 pandemic and - the precautions you should take is available at: + Please also comply with all other precautions and official requirements + when using the App. Reliable sources of information about the SARS-CoV-2 + pandemic and appropriate precautions include: </p> <p> www.infektionsschutz.de/coronavirus + (provider: Federal Centre for Health Education, BZgA) </p> <p> www.zusammengegencorona.de + (provider: Federal Ministry of Health) </p> <p> www.rki.de/covid-19 + (provider: RKI) </p> <p> - The above is purely for your information and does not form part of these - Terms of Use. + This further information is provided for information purposes only and does + not form part of these Terms of Use. </p> <p> - Always follow these <strong>rules</strong>, including when you are using - the App: + Please follow the <strong>DHM rules</strong> even when using the App: </p> <p> - - Practice social distancing (at least 1.5m) + <strong>D</strong> + - Practise social distancing of at least 1.5 m. </p> <p> - - Wash your hands regularly for at least 20 seconds + <strong>H</strong> + - Wash your hands regularly for at least 20 seconds. </p> <p> - - Always wear a face mask when you go shopping and on public transport + <strong>M</strong> + - Always wear a face mask when you go shopping and on public transport. </p> <p> This is the best way to protect yourself and others against the virus. </p> <p> - 5. ACCESSING TEST RESULTS + 5. RETRIEVAL OF TEST RESULTS </p> <p> - You may only access your <u>own</u> test results via the App. + You may only access your own test results via the App. </p> <p> - If you are waiting for test results and the CWA Services are not available - or you cannot access your results via the App for any other reason, please - use alternative means to obtain your result (e.g. contact the test provider - such as your GP or the local public health department (<em>Gesundheitsamt</em>). Do not wait - until the App is available again. + If you are awaiting test results and the CWA Services are not available or + you cannot retrieve your test results via the App for any other reason, + please use alternative means to obtain your result (e.g. contact the test + provider, such as your GP or the local public health department (<em>Gesundheitsamt</em>)). Do + not wait until the App is available again. </p> <p> - 6. WARNING FEATURE + 6. ACTIVATING THE WARNING FEATURE </p> <p> - You can use the App to warn other people you have had contact with that you + You can use the App to warn other people whom you have encountered that you have tested positive for SARS-CoV-2. <strong> You may only activate the warning feature if your positive test result - came from an approved testing lab. + came from an approved testing laboratory. </strong> </p> <p> - If the approved test lab is not linked to the CWA Services, your infection - status will be verified via a verification hotline set up by the RKI. You - may not activate the warning feature on the basis of a reporting of - positive test result only. + If your testing laboratory is not linked to the CWA Services, your + infection status will be verified via a verification hotline set up by the + RKI. You may not activate the warning feature on the basis of merely having + been notified of a possible exposure. </p> <p> - In cases of doubt, get in touch with your GP or the local public health + In cases of doubt, first contact your GP or the local public health department (Gesundheitsamt) </p> <p> - If you are not sure whether or not you have been infected, contact your GP - or the local public health department (<em>Gesundheitsamt</em>) before - activating the warning feature. They will be able to advise you what to do - and you may be able to get yourself tested if necessary. In the meantime, - make sure you follow the general recommendations for what to do in the - event that you think you may be infected with SARS-CoV-2. + If you are not sure whether you have been infected, please contact your GP + or the local public health department (<em>Gesundheitsamt</em>). There you + will receive further advice and can be tested if necessary. In the + meantime, make sure you follow the general recommendations for what to do + in suspected cases of infection with SARS-CoV-2. </p> <p> - Use of the warning feature without good reason + Improper use </p> <p> <strong> - You may not activate the warning feature without good reason and doing - so may have serious consequences. + Improperly activating the warning feature is prohibited and may result + in serious consequences. </strong> - You may, for example, be liable for damages towards any other affected - individuals. + You may, for example, be liable for damages towards anyone affected. </p> <p> - In the event of any use of the App which is not in line with these Terms of - Use, the RKI reserves the right to ban users from accessing the App and the - CWA Services. + 7. REQUIREMENTS FOR USING THE APP </p> <p> - 7. TECHNICAL REQUIREMENTS -</p> -<p> - The following technical requirements need to be met in order to use the - App: + The following technical requirements must be met in order to use the App: </p> <p> You will need a data connection @@ -397,101 +429,117 @@ Certain features of the App are based on central services and systems provided via the CWA Services. These features are therefore only available if your device has an internet data connection, e.g. via UMTS, LTE or WiFi, - enabling access to the CWA Services. Some or all of the features of the App - will not be available if you do not have a data connection. The same will - apply when your device is turned off or in flight mode. + enabling access to the CWA Services. Without a data connection, some or all + of the features of the App will not be available. The same will apply when + your device is turned off, or in flight mode. </p> <p> - The App must be running and activated + The COVID-19 Exposure Notification System must be enabled </p> <p> - The App muss must be running on your device (in the foreground or - background) and must be activated. You will need to launch the App for - this. If you fail to launch the App, or deactivate or quit the App, it will - not register any encounters with other people and will not generate any - random IDs which can be stored by other devices. You will need to relaunch - the App if you restart your device (e.g. after turning it off, when the - battery runs out or following an operating system update). + Your device’s COVID-19 Exposure Notification System must be enabled and + have the necessary permission for the region “Germany†/ for the App. +</p> +<p> + <strong><em>Background updates</em></strong> +</p> +<p> + The App needs to run permanently in the background. You will also need to + restart the App if you restart your device (e.g. after switching it off, + after the battery has run out or after an operating system update) or if + the App has been forced to close. </p> <p> Settings on your device </p> <p> - You will also need to activate the Bluetooth (BLE) functions on your device - and allow the App to access them. + To use the App, you will also need to enable the Bluetooth (BLE) + functionality on your device and allow the App to access it if requested. </p> <p> - The RKI also recommends activating the following functions on your device - and allowing the App to access them, although you will still be able to use - the basic features of the App without them: + The RKI also recommends enabling the following features on your device and + allowing the App to access them if requested, although you will still be + able to use the basic features of the App without them: </p> <ul> <li> - notifications + Notifications </li> <li> - camera + Camera </li> </ul> <p> - Please check the settings on your device to see whether these functions are - activated and may be accessed by the App. + Please check your device settings to see whether these features are enabled + and whether the App has permission to use them. </p> <p> - Detailed instructions on how to set up the App for iOS and Android are - available at https://www.coronawarn.app/en/. These instructions are for - information purposes only and do not form part of these Terms of Use. + Detailed instructions on how to set up the App on iOS and Android are + available on the website of the open-source project for the Corona-Warn-App + at https://www.coronawarn.app/en/ + (provider: SAP Deutschland SE & Co. KG). These instructions are + provided for information purposes only and do not form part of these Terms + of Use. </p> <p> - You will need to ensure that you are using the latest version of the App + You will need to use a current version of the App </p> <p> - The RKI will publish occasional updates for the App. You will need to - install these updates as soon as possible and ensure that you are always - using the newest version of the App. Using older versions of the App may - lead to technical issues or disruptions. + The RKI will occasionally publish updates for the App. You should install + these updates as soon as possible and ensure that you are always using the + latest version of the App. Using older versions of the App may lead to + malfunctions and disruptions. If an update is absolutely necessary, you + will be notified of this when you open the App. </p> <p> - <strong> - <em>You will need to have the latest versions of iOS or Android</em> - </strong> + <strong><em>You will need a current version of iOS or Android</em></strong> </p> <p> - The App uses functions implemented specifically by Apple on iOS and Google - on Android ("exposure notification"). These are only available on iOS - version 13.5 and upwards and Android version 6 and upwards. Unfortunately - the App does not work with earlier versions of those operating systems. + The App uses the COVID-19 Exposure Notification System implemented by Apple + in iOS and Google in Android. This is only available in iOS version 13.5 + and upwards and in Android version 6 and upwards. Unfortunately, the App + does not work on earlier versions of the two operating systems. </p> <p> 8. LIMITATIONS OF THE APP </p> <p> - The App is designed to help you identify exposures you have had to people - who subsequently received a positive test result. But you should always - remember that the App has certain limitations. -</p> -<p> - One of these is that, while the App is constantly sending out random IDs - (rolling proximity identifiers), it only receives random IDs from other - devices at specific intervals. The windows for receiving data in the App - are currently up to five minutes apart and are only very short.. All these - functionalities are based on the underlying Exposure Notification Framework - from Apple and Google and can be changed by these companies at any time. -</p> -<p> - The Bluetooth signal attenuation is used for the proximity measurement. A - lower signal attenuation essentially means that the other device is closer. - A higher signal attenuation means that either the other device is further - away (i.e. a distance of more than two metres) or there is something - between the two devices blocking the signal. This might include something - like a wall or a bag containing the device, but could just as easily be - people or animals. + The App is designed to help you identify a possible exposure you have had + to another user who subsequently tested positive for coronavirus. However, + it is important to know that the App has certain limitations, especially: </p> +<ul> + <li> + A possible exposure can only be assessed by the App if that possible + exposure has been recorded by your operating system’s COVID-19 Exposure + Notification System and passed on to the App. The RKI has no way of + influencing the availability, completeness, correctness and reliability + of these records in the COVID-19 Exposure Notification System. + </li> + <li> + The App can warn you of a possible exposure to infected users of the + official coronavirus app of any country participating in the + transnational warning system. To do so, however, those users must have + provided their positive test result via the respective coronavirus app, + making this information available for the transnational warning + feature. + </li> + <li> + To assess the risk of infection, the App uses the information recorded + about the Bluetooth signal attenuation. In principle, the lower the + signal attenuation, the closer the device. A higher signal attenuation + can either mean that the other device was further away (i.e. a distance + of more than two metres) or that there was something between the two + devices which blocked the signal. This may be an object such as a wall + or a bag in which the device was being carried, but also people or + animals. + </li> +</ul> <p> - 9. USER RIGHTS + 9. RIGHTS OF USE </p> <p> - <strong><em>Simple user right</em></strong> + <strong><em>Simple right of use</em></strong> </p> <p> You are hereby granted a limited, non-exclusive, non-transferable and @@ -499,202 +547,187 @@ own personal, non-commercial purposes. </p> <p> - The licence for the iOS version der App covers use on any Apple device + The licence for the iOS version of the App covers use on any Apple device owned or controlled by you, subject to the applicable terms and conditions of the App Store. You may also access and use the App via other Apple - accounts linked to your own Apple account via Family Sharing or the - purchase of bulk licences. + accounts linked to your own Apple account via Family Sharing or volume + purchasing. </p> <p> - You are entitled to make copies of the App for your own backup purposes. - You are not entitled to any other rights in respect of the App. + You may make copies of the App for backup purposes. You are not granted any + further rights to the App. </p> <p> <strong><em>Ownership of the App</em></strong> </p> <p> - The App (including the source code) is the sole, exclusive property of SAP - SE, Dietmar Hopp Allee 16, 69190 Walldorf, Germany ("<strong>SAP</strong>") - or its licensors, subject to the rights granted to you under Section 9 and - any other rights to the App which have been contractually granted to the - Federal Republic of Germany by SAP. + The App is the sole and exclusive property of SAP SE, Dietmar-Hopp-Allee + 16, 69190 Walldorf (<strong>SAP</strong>) or its licensors, subject to the + rights granted to you under Section 9 and any other rights to the App which + SAP has contractually granted to the Federal Republic of Germany. </p> <p> - <strong><em>Open source licensing notes</em></strong> + <strong><em>Open-source licensing notes</em></strong> </p> <p> Information on the use of third-party components contained in the App and - the applicable licensing provisions can be found in the open source - licensing notes in the App. + the applicable licence terms can be found in the open-source licensing + notes in the App. </p> <p> - The source code for the App is published under the "Apache 2.0 Licence" - licence conditions and may be downloaded at - "https://github.com/corona-warn-app". The licence conditions for the - "Apache 2.0 Licence" are available at - "https://www.apache.org/licenses/LICENSE-2.0". + The App’s source code is published under the terms of the “Apache 2.0 + License†and can be downloaded at + https://github.com/corona-warn-app . + The terms of the “Apache 2.0 License†are available at + https://www.apache.org/licenses/LICENSE-2.0 . </p> <p> - The licensing provisions which apply to the source code for the App and the - third-party components contained in the App are not affected by the rights - granted under this Section 9. + The licence terms which apply to the App’s source code as well as to + third-party components contained in the App are not affected by the + granting of rights under this Section 9. </p> <p> - <strong><em>What you are not allowed to do</em></strong> + <strong><em>What is not allowed</em></strong> </p> <p> You may not manipulate or change the App. </p> <p> - You may not use the App or the interfaces to the CWA Services for any - purpose which is not in line with these Terms of Use. You may not use the - CWA Services for any purpose other than the intended use of the App on your - device. You may only access the CWA Services via the App. + You may not use the App or the interfaces to the CWA Services for improper + purposes. You may not use the CWA Services for any purpose other than the + intended use of the App on your device. You may only access the CWA + Services via the App. </p> <p> - 10. IMPORTANT INFORMATION ON AVAILABILITY AND CHANGES + 10. IMPORTANT INFORMATION ABOUT AVAILABILITY AND CHANGES </p> <p> - No claim to a specific functionality + No legal claim to specific functionality </p> <p> The App is made available to you in the form in which it is published by - the RKI. The RKI does not accept any responsibility for the operability of - the App or the CWA Services and does not agree any specific properties or - qualities with you. You are not entitled to any claim to a specific - functionality or constitution of the App or the CWA Services. The RKI is - entitled to make changes to the App at any time and to remove entire - features or parts thereof or to add extra features to the App. + the RKI. The RKI accepts no responsibility for the operability of the App + or the CWA Services and does not agree any specific properties or qualities + with you. You have no legal claim to specific functionality or any other + quality of the App or the CWA Services. The RKI is entitled to make changes + to the App at any time and to remove entire features or parts thereof or to + add extra features to the App. </p> <p> No guarantee of availability </p> <p> The RKI may restrict or suspend the operation of the App and the CWA - Services at any time. You do not have any claim to the continued - availability of the App or any of the associated services and systems, - including the CWA Services, either as regards individual features or the - system as a whole. + Services at any time. You have no legal claim to the continued availability + of the App or any of the associated services and systems, including the CWA + Services, as regards either individual features or the system as a whole. </p> <p> The RKI does not guarantee the availability or performance of the CWA - Services. The CWA Services may be temporarily unavailable due to - maintenance or a fault. This may last for some time in certain cases. The - functionality of the App will be restricted or completely unavailable - during such periods. + Services. These may be temporarily unavailable due to maintenance or + disruptions and may also be unavailable for longer periods of time. In such + cases, the functionality of the App will be partially or completely + restricted. </p> <p> Changes to these Terms of Use </p> <p> - The RKI reserves the right to make changes to these Terms of Use. You will - be asked to agree to any such changes when you launch the App. If you do - not agree to the changes, you will no longer be able to use the App and the - CWA Services and you will need to uninstall the App from your device. + The RKI reserves the right to make changes to these Terms of Use. If you do + not agree to the changed Terms of Use, you will no longer be able to use + the App and the CWA Services and you will need to uninstall the App from + your device. </p> <p> - Risk score + Changes to risk assessment parameters </p> <p> - The RKI also reserves the right to change the parameters used to determine - the risk score at any time to take account of the latest research findings - relating to the transmission and spread of the virus. The RKI may determine - these parameters at its own discretion. + The RKI also reserves the right to change the parameters used to assess the + risk of infection at any time, in order to take into account the latest + research findings on how the virus is spread. The RKI determines the + parameters used at its own discretion. </p> <p> 11. NO WARRANTY </p> <p> The RKI determines both the features and the design of the App and the CWA - Services. In this respect, the RKI does not agree any specific properties - or qualities with you and you have no right to the incorporation of - specific features in the App or to these being designed in a specific way. - The App is provided in the condition and with the features implemented by - the RKI when it was published in the Apple App Store or Google Play. + Services. The RKI does not agree any specific quality with you and you have + no legal claim to the incorporation of certain features in the App or to + these being designed in a certain way. The App is provided in the condition + and with the features as implemented by the RKI when the App is published + in the Apple App Store or on Google Play. </p> <p> - The RKI will exercise reasonable care in providing the App and the CWA - Services. The RKI does not make any other promises or assurances regarding - the App or the CWA Services and, in particular, does not warrant that: + The RKI will exercise reasonable care when providing the App and running + the CWA Services. The RKI makes no other promises or assurances with regard + to the App or the CWA Services. In particular, it does not warrant that: </p> <ul> <li> you will be able to use the App or the CWA Services without any - interruption or that these will be free from errors, + interruption or errors, </li> <li> the App and the CWA Services will not be subject to any losses, corruption, attacks, viruses, interference, hacking or other - security-related issues. + security-related disruptions. </li> </ul> <p> - You have sole responsibility for data security on your device and any - systems connected to it, including the data security of all other apps - installed on your device. + You are responsible for backing up your device and any systems connected to + it, including all other apps stored on your device. </p> <p> 12. SPECIAL TERMS FOR THE IOS VERSION OF THE APP </p> <p> The following terms apply if you obtain the App from the Apple App Store - and use it with the iOS operating system. -</p> -<p> - Consent to data usage -</p> -<p> - You consent to the RKI collecting and using technical data and associated - information (particularly technical information on your device, system and - application software and your peripherals) at regular intervals in order to - facilitate the provision of software updates, product support and any other - services provided to you in connection with the App. The RKI may use this - information to improve its products or offer you services or technology, - provided this is done without disclosing your identity. + and use it on the iOS operating system. </p> <p> Maintenance and support </p> <p> - As publisher of the App, the RKI has sole responsibility for maintenance - and support services for the App in line with these Terms of Use. Apple - assumes no obligation whatsoever to provide any maintenance or support - services in respect of the App. + As the publisher of the App, the RKI is solely responsible for the App’s + maintenance and support in line with these Terms of Use. Apple assumes no + obligation to provide any maintenance or support services in respect of the + App. </p> <p> - Apple not liable for service interruptions + Apple not liable for disruptions </p> <p> - You may notify Apple in the event of service interruptions affecting the - App. To the extent legally permissible, Apple has no further obligations in - the event of such service interruptions. + You may notify Apple in the event of disruptions affecting the App. To the + extent legally permissible, Apple has no further obligations in the event + of such disruptions. </p> <p> Product liability </p> <p> - Apple is not liable for any claims by you or third parties in relation to - the App or to the use or possession of the App. This includes + Apple is not liable for any legal claims by you or third parties in + relation to the App or to the use or possession of the App, including </p> <ul> <li> - product liability claims + product liability claims, </li> <li> claims based on the App not meeting statutory or regulatory - requirements and + requirements, and </li> <li> - claims under consumer protection and data protection or any similar + claims under consumer protection and data protection laws or similar laws, </li> </ul> <p> - including claims in connection with use of the HealthKit and HomeKit + including claims in connection with the use of the HealthKit and HomeKit frameworks. </p> <p> - Infringement of third-party IP rights + Infringement of third-party intellectual property rights </p> <p> In the event that third parties assert claims due to the infringement of @@ -713,32 +746,32 @@ <li> you are not in a country subject to an embargo by the government of the United States of America or deemed by the government of the United - States of America to be a terrorist supporting country and + States of America to be a terrorist-supporting country and </li> <li> - you have not been place on a list of prohibited or restricted parties + you have not been placed on a list of prohibited or restricted parties kept by the government of the United States of America. </li> </ul> <p> - Apple's rights as a third-party beneficiary + Apple’s right as a third-party beneficiary </p> <p> You acknowledge and accept that Apple is a third-party beneficiary under these Terms of Use and that Apple can therefore enforce these Terms of Use - against you. The contracting parties retain the right to modify or - terminate these Terms of Use, including Apple's rights. This does not - require Apple's consent. + against you. The contracting parties retain the right to make changes to or + cancel these Terms of Use, including Apple’s rights. This shall not require + Apple’s consent. </p> <p> 13. FINAL PROVISIONS </p> <p> - Proper use of the App / blocking users in the event of misuse + Intended use; blocking in cases of improper use </p> <p> You may use the App and the CWA Services only in line with their intended - used. In the event of misuse of the App or the CWA Services, the RKI + used. In the event of improper use of the App or the CWA Services, the RKI reserves the right to ban users from accessing the App and the CWA Services. </p> @@ -746,10 +779,10 @@ Third-party services </p> <p> - If you use third-party services in connection with accessing the App, - including telecoms services to obtain a data connection, you are - responsible for covering the associated costs and complying with the - relevant terms and conditions. + If you use third-party services in connection with using the App, in + particular those of telecommunication service providers for the provision + of a data connection, you are responsible for the associated costs and + complying with the relevant terms and conditions. </p> <p> Applicable law @@ -759,18 +792,18 @@ Germany. The United Nations Convention on Contracts for the International Sale of Goods is excluded. This does not affect the statutory provisions on restriction of the choice of law and on the applicability of mandatory - provisions, including those in the country in which you as a consumer are - resident. + provisions, in particular those in the country in which you as a consumer + are ordinarily resident. </p> <p> Severability </p> <p> - Should any of these Terms of Use be or become legally invalid, this will + Should any of these Terms of Use be or become legally invalid, this shall not affect the remaining provisions. The invalid provisions shall be - replaced by any applicable statutory provisions. If this would constitute - unreasonable hardship for one of the parties, the entire Terms of Use shall - be cease to be valid. + replaced by any applicable statutory provisions. However, if this would + constitute unreasonable hardship for one of the parties, the entire Terms + of Use shall cease to be valid. </p> <p> * * * diff --git a/Corona-Warn-App/src/main/assets/terms_tr.html b/Corona-Warn-App/src/main/assets/terms_tr.html index d0e57459d7b39e29a276b2e590c765978ea12353..e05c5ad422f54a35f6d0c065005810bcb0bf58eb 100644 --- a/Corona-Warn-App/src/main/assets/terms_tr.html +++ b/Corona-Warn-App/src/main/assets/terms_tr.html @@ -2,430 +2,472 @@ <strong>Corona-Warn-App</strong> </p> <p> - <strong>Kullanım koÅŸulları</strong> + <strong>Kullanım KoÅŸulları</strong> </p> <p> İÇERÄ°K </p> <p> - 1. UYGULAMA'da hangi iÅŸlevler bulunur? + 1. Uygulamanın iÅŸlevleri nelerdir? </p> <p> - 2. Düşük ya da daha yüksek risk ne anlama gelir? + 2. Düşük risk veya daha yüksek risk, ne anlama gelir? </p> <p> - 3. Maruz kalma - ne yapmalıyım? + 3. Riske maruz kalınca - ne yapmalıyız? </p> <p> - 4. UYGULAMA, enfeksiyona karşı koruma saÄŸlamaz + 4. Uygulama, enfeksiyondan korunma saÄŸlamaz </p> <p> - 5. Test sonuçlarını isteme + 5. Test sonuçlarının çaÄŸrılması </p> <p> - 6. Uyarıda bulunma + 6. Bir uyarının tetiklenmesi </p> <p> - 7. UYGULAMA'yı kullanım ÅŸartları + 7. Uygulamanın kullanım gereksinimleri </p> <p> - 8. UYGULAMA'nın sınırları + 8. Uygulamanın sınırları +</p> +<p>9. Kullanım hakları </p> <p> - 9. Kullanım hakları + 10. KullanılabilirliÄŸe ve deÄŸiÅŸikliklere iliÅŸkin önemli bilgiler </p> <p> - 10. Kullanılabilirlik ve deÄŸiÅŸiklikler hakkında önemli talimatlar + 11. Garanti yok </p> <p> - 11. Garanti yoktur + 12. Uygulamanın iOS sürümü için özel koÅŸulları </p> <p> - 12. UYGULAMA'nın iOS sürümü için özel koÅŸullar + 13. Sonuç hükümleri </p> <p> - 13. Son hükümler + Uygulamanın yayımcısı: </p> <p> - Bu uygulamanın yayımcısı, + Robert Koch-Institut ( Robert Koch Enstitüsü) </p> <p> - baÅŸkanı tarafından temsil edilen ve + Nordufer 20 </p> <p> - Nordufer 20, + 13353 Berlin ("<strong>RKI</strong>") </p> <p> - 13353 Berlin adresinde bulunan + Bu Kullanım KoÅŸulları ile ilgili sorularınız, ÅŸikayetleriniz ve talepleriniz için, + CoronaWarnApp@rki.de adresinden e-posta yoluyla RKI ile iletiÅŸime geçebilirsiniz. </p> <p> - Robert Koch-Institut'tür ("<strong>RKI</strong>"). Bu kullanım koÅŸulları - ile ilgili soru, ÅŸikayet ya da istekleriniz için +49 30 18754-5100 numaralı - telefon ve CoronaWarnApp@rki.de e-posta adresi aracılığıyla RKI'ye - ulaÅŸabilirsiniz. + Lütfen bu kullanım koÅŸullarını dikkatlice okuyunuz. Bu Kullanım KoÅŸulları, + gelecekteki sürümler (yamalar, güncellemeler ve yükseltmeler) ve RKI + tarafından ÅŸu sıralar sunulan veya gelecekte sunulacak olan ilgili diÄŸer + hizmetlerin (“<strong>CWA hizmetleri</strong>â€) kullanımı da dahil olmak üzere, + Corona-Warn-App’ı (“<strong>Uygulama</strong>â€) kullanımınızı düzenler. Bu Kullanım + KoÅŸullarını, istediÄŸiniz zaman Uygulamadaki “Uygulama bilgileri†ve “ + https://www.coronawarn.app/assets/documents/cwa-eula-tr.pdf + üzerinden eriÅŸebilirsiniz. Ayrı olarak sunulan Veri GizliliÄŸi Beyanı (Bkz. + “Uygulama bilgileri†ve + https://www.coronawarn.app/assets/documents/cwa-privacy-notice-tr.pdf + ), bu Kullanım KoÅŸullarının bir parçası deÄŸildir. Ancak, yine de Veri + GizliliÄŸi Beyanını dikkatlice okuyunuz. </p> <p> - Lütfen bu kullanım koÅŸullarını dikkatlice okuyun. Bu kullanım koÅŸulları, - Corona-Warn-App kullanımınızı ve gelecekteki hizmetlerin (yamalar, - güncellemeler ve yükseltmeler) ("<strong>UYGULAMA</strong>") kullanımını ve - ÅŸu anda ya da gelecekte RKI tarafından UYGULAMA ile baÄŸlantılı olarak - hazırlanacak, diÄŸer hizmetleri ("<strong>CWA Hizmetleri</strong>") kullanımınızı - düzenler. Bu kullanım koÅŸullarından ayrı bir belge olan veri gizliliÄŸi - beyanı (bakınız: <strong>[<em>Link</em>]</strong>), bu kullanım - koÅŸullarının bir parçasıdır. Veri gizliliÄŸi beyanını da dikkatlice okuyun. + Uygulama, iOS cihazlar için Apple AppStore’dan ve Android cihazlar Google + Play’den temin edilebilir. Apple veya Google’dan gelen uygulamaların genel + kullanım koÅŸulları, RKI ile ilgili olarak geçerli deÄŸildir. RKI, + Uygulamanın içeriÄŸinden, bakım ve servis çalışmalarından ve Uygulamayla + ilgili olabilecek hak taleplerinden yegane sorumludur. </p> <p> - UYGULAMA'ya, iOS cihazlarda kullanım için Apple App Store ve Android - cihazlarda kullanım için Google Play aracılığıyla eriÅŸebilirsiniz. Apple ya - da Google uygulamalarının genel kullanım koÅŸulları, RKI uygulamalarına - uygulanmaz. RKI, UYGULAMA'nın içeriklerinden ve de bunların bakım ve - korumasından ve UYGULAMA'ya iliÅŸkin taleplerinizden tek başına sorumludur. + Uygulamayı yüklediÄŸinizde ve kullandığınızda, bu Kullanım KoÅŸullarını kabul + etmiÅŸ olursunuz. Kullanım KoÅŸullarını kabul etmiyorsanız, Uygulamayı + yükleyemez veya kullanamazsınız (ve tekrar silmeniz gerekir) ve Uygulama + ile iliÅŸkili hizmetleri ve sistemleri de kullanamazsınız. Açık kaynak + lisansları kapsamındaki olası haklar, Uygulamanın kaynak koduyla ilgili + olarak saklı kalır. </p> <p> - UYGULAMA'yı yükleyerek ve kullanarak, bu kullanım koÅŸullarını kabul - ettiÄŸinizi açıklarsınız. Bu kullanım koÅŸullarını kabul etmiyorsanız, - UYGULAMA'yı yükleyemez ya da kullanamazsınız (ve bunları silmelisiniz) ve - bu UYGULAMA ile baÄŸlantılı hizmet ve sistemleri kullanamazsınız. - UYGULAMA'nın kaynak koduna iliÅŸkin açık kaynak lisansları çerçevesindeki - olası haklar saklıdır. + Uygulamayı yüklediÄŸiniz cihazı, üçüncü kiÅŸilere verirseniz ve onlar + Uygulamayı kullansalar bile bu Kullanım KoÅŸullarına yerine getirilmesinden + siz sorumlu olursunuz. </p> <p> - UYGULAMA'yı yüklediÄŸiniz cihazı, üçüncü kiÅŸilere devretmeniz ve bu - kiÅŸilerin UYGULAMA'yı kullanması halinde de kullanım koÅŸullarına - uyulmasından siz sorumlu olursunuz. + Uygulama, en az 16 yaşında olan kiÅŸilere yönelik hazırlanmıştır. </p> <p> - UYGULAMA, en az 16 yaşında olan kiÅŸiler içindir. 16 yaşın altındaki - kiÅŸiler, UYGULAMA'yı velilerinin onayı ile kullanabilir. + 1. UYGULAMANIN Ä°ÅžLEVLERÄ° NELERDÄ°R? </p> <p> - 1. UYGULAMA'DA HANGÄ° Ä°ÅžLEVLER BULUNUR? + Uygulamanın amacı, SARS-CoV-2 enfeksiyon zincirini erken aÅŸamada kesmektir. + Bu baÄŸlamda kullanıcıların, SARS-CoV-2 pandemisinin kontrol altına + alınmasına katkıda bulunmak ve kendilerini gönüllü olarak izole + edebilmeleri için, enfekte insanlarla karşılaÅŸma (maruz kalma) durumları ve + dolayısıyla olası virüs taşımaya iliÅŸkin mümkün olduÄŸunca hızlı ve + güvenilir bir ÅŸekilde bilgilendirilmeleri amaçlanmaktadır. </p> <p> - Corona-Warn-App ile, SARS-CoV-2 enfeksiyon zincirlerinin erken kırılması - amaçlanır. SARS-CoV-2 pandemisinin engellenmesine katkı amacıyla - kendilerini izole edebilmeleri için insanlar, enfekte olan kiÅŸiler ile - yaÅŸadıkları karşılaÅŸmalar ve olası virüs taşıma hakkında mümkün olan en - güvenilir ve hızlı ÅŸekilde bilgilendirilmelidir. + Uygulama, Apple ve Google tarafından saÄŸlanan ve cihazınızın iÅŸletim + sisteminin ayrılmaz bir parçası olan COVID-19 maruz kalma bildirimleri (“<strong>COVID-19 + bildirim sistemini</strong>â€) kullanır. COVID-19 bildirim + sisteminin tam adı, çalışması ve iÅŸlevselliÄŸi, kullandığınız iÅŸletim + sisteminin üreticisine ve sürümüne baÄŸlı olarak deÄŸiÅŸebilmektedir. COVID-19 + bildirim sistemi, CWA hizmetlerinin veya Uygulamanın bir parçası deÄŸil, + aksine Uygulamanın öngördüğü bir sistem gereksinimidir. COVID-19 bildirim + sisteminin kullanılabilirliÄŸi, iÅŸlevselliÄŸi, güvenilirliÄŸi ve kullanım + koÅŸulları ve veri iÅŸlemesinden, ilgili iÅŸletim sisteminin saÄŸlayıcısı + sorumludur. RKI’nin bu baÄŸlamda herhangi bir etkisi bulunmamaktadır. </p> <p> - UYGULAMA'nın temel iÅŸlevleri aÅŸağıda açıklanmıştır. Burada amaçlanan, - nitelik sözleÅŸmesi ya da belirli iÅŸlevlerin kararlaÅŸtırılması olmayıp, sizi - bilgilendirmek için açıklama yapılmasıdır. Lütfen 10 numaralı baÅŸlıktaki - ilgili talimat ve koÅŸulları dikkate alın. + Uygulamanın temel iÅŸlevleri aÅŸağıda açıklanmıştır. Bunlar, bilgilerinize + yönelik açıklamalardır ve Uygulamanın kalitesine iliÅŸkin bir anlaÅŸma veya + spesifik iÅŸlevlere iliÅŸkin bir anlaÅŸma deÄŸildir, lütfen bu baÄŸlamda Madde + 10 altındaki bilgileri ve çekinceleri dikkate alın. </p> <p> - Arka plan + Risk deÄŸerlendirmesi </p> <p> - UYGULAMA cihazda arka planda çalışır ve yakında bulunan cihazların rastgele - kimliklerini otomatik kaydeder ve ÅŸifreler (<em>rolling proximity identifier</em>). UYGULAMA, - enfekte olduklarını - bildiren kiÅŸilerin rastgele kimliklerinin bir listesini (<em>temporary exposure keys</em>) CWA - hizmetleri aracılığıyla ve düzenli - aralıklarla alır ve maruz kalmayı tespit etmek için bu rastgele kodları, - cihazda kayıtlı rastgele kimlikler ile karşılaÅŸtırır. + Ä°ÅŸletim sisteminizde COVID-19 bildirim sistemini etkinleÅŸtirdikten ve + Uygulamadaki risk deÄŸerlendirmesini etkinleÅŸtirdikten sonra, COVID-19 + bildirim sistemi, cihazınızın Bluetooth arayüzü üzerinden rastgele kimlik + numaralarını göndermeye baÅŸlar. Öte yandan, COVID-19 bildirim sisteminin + diÄŸer kullanıcılarından rastgele kimlik no’ları alır ve bunları enfeksiyon + riskini belirlemek üzere Bluetooth sinyal gücü ile ilgili teknik bilgiler, + ilgili gün ve karşılaÅŸmanın süresi ile birlikte kaydeder (sinyal ne kadar + güçlü ise, mesafe genellikle o kadar kısadır). </p> <p> - UYGULAMA sadece UYGULAMA'nın yüklü olduÄŸu bir cihazı üzerinde bulunduran ve - UYGULAMA kullanımı için tüm ÅŸartları yerine getiren kiÅŸiler ile - karşılaÅŸmaları kaydedebilir (7 numaralı baÅŸlığa bakınız). UYGULAMA diÄŸer - insanlar ile karşılaÅŸmaları kaydedemez. + Uygulama ayrıca, CWA hizmetleri aracılığıyla sınır ötesi uyarı sistemine + katılan ülkelerin resmi Korona uygulamalarına enfekte olduklarını bildiren + kiÅŸilerin rastgele kimlik numaralarının bir listesini düzenli aralıklarla + alır ve bunu COVID-19 bildirim sistemine aktarır. COVID-19 bildirim + sistemi, bir riske maruz kalmayı belirlemek için, bunları cihazda saklanan + rastgele kimlik numaraları ile karşılaÅŸtırır. </p> <p> - Maruz kalma bildirimi + Enfeksiyon riski </p> <p> - Testleri pozitif kiÅŸiler ile yapıldığı belirlenen maruz kalma durumunda bir - bildirim ve nasıl davranmanız gerektiÄŸiyle ilgili tavsiyeler alırsınız. - ÖrneÄŸin, tıbbi uzman personel ya da kamu saÄŸlığı yetkilisi ile iletiÅŸime - geçmeniz ve/veya evde izolasyon tavsiye edilebilir. + COVID-19 bildirim sisteminin, test sonucu pozitif çıkan bir kiÅŸiyle bir + riskli karşılaÅŸma tespit ettiÄŸinde, COVID-19 bildirim sistemi, Uygulamaya + bununla ilgili olarak bir ileti gönderir ve temasın sinyal gücü, günü ve + süresinin kayıtlarını saÄŸlar. Uygulama bu kayıtları deÄŸerlendirir ve + ardından sizin için saptadığı enfeksiyon riski ve ayrıca RKI’nin bu + konudaki eylem önerileri hakkında sizi bilgilendirir. Bu öneriler örneÄŸin, + tıp uzmanına, sorumlu saÄŸlık kurumuna danışma ve/veya gönüllü ev izolasyonu + olabilir. </p> <p> - Test sonuçlarının bildirilmesi + Test kaydı </p> <p> - SARS-CoV-2 enfeksiyonu testi için numune verildiÄŸi andan itibaren UYGULAMA - üzerinden test hakkında dijital bilgi sürecini baÅŸlatabilir ve bu sayede - test sonucu hakkında bildirim alabilirsiniz. UYGULAMA sadece ilgili - laboratuvar tarafından iletilen test sonucunu iletir. RKI, testin yapılması - ya da test sonucunun içeriÄŸinden sorumlu deÄŸildir. + SARS-CoV-2 enfeksiyon testi için numune verildiÄŸi andan itibaren, Uygulama + aracılığıyla dijital test bilgilendirme sürecini baÅŸlatabilir ve söz konusu + test sonucunu alabilirsiniz. Bunun için ön koÅŸul, test laboratuvarının CWA + hizmetlerine baÄŸlanmış olması ve size test kaydı için bir QR kod veya TAN + (iÅŸlem numarası) vermesidir. Uygulama, yalnızca ilgili laboratuvar + tarafından kendisine gönderilen test sonucunu aktarır. RKI, ne testin + gerçekleÅŸtirilmesinden, ne de test sonucunun içeriÄŸinden sorumludur. </p> <p> - Enfeksiyon durumu + DiÄŸer insanların uyarılması </p> <p> - Pozitif SARS-CoV-2 bulgusu halinde ve bu UYGULAMA'yı kullanan diÄŸer - kiÅŸilerin sizinle maruz kalma yaÅŸayıp yaÅŸamadıklarını kendi cihazlarında - karşılaÅŸtırabilmeleri için UYGULAMA'da son 14 günün kayıtlı rastgele - kimliklerini, tanı anahtarı (<em>diagnosis keys</em>) olarak - yayınlayabilirsiniz. + SARS-CoV-2 bulgusu pozitif çıkması durumunda, son 14 gün boyunca COVID-19 + bildirim sisteminde saklanan kendi rastgele kimlik numaralarınız ve ayrıca + hastalığın olası bir semptomunun ilk ortaya çıkışıyla ilgili verileri, + gönüllü olarak CWA hizmetlerine aktarabilirsiniz, böylece sınır ötesi uyarı + sistemine katılan ülkelerin resmi Korona uygulamaları, sizinle bir riskli + karşılaÅŸma olması durumunda kendi cihazlarında ilgili bildirimi alabilir. </p> <p> - UYGULAMA'nın teknik tanımı + Uygulamanın teknik açıklaması </p> <p> - UYGULAMA'nın ve de UYGULAMA ile baÄŸlantılı hizmet ile sistemlerin teknik - fonksiyonları, aÅŸağıdaki baÄŸlantıda ayrıntılı bir ÅŸekilde tanımlanmıştır: + Uygulamanın teknik iÅŸlevleri ve iliÅŸkili hizmetler ve sistemler aÅŸağıdaki + linkte ayrıntılı olarak açıklanmaktadır: </p> <p> https://github.com/Corona-Warn-App </p> <p> - Bu teknik tanım, sadece aydınlatma amacı taşır ve bu kullanım koÅŸullarının - bir parçası deÄŸildir. UYGULAMA ile ilgili bir nitelik sözleÅŸmesi - oluÅŸturmaz. + Bu teknik açıklamalar, yalnızca bilgilendirme amaçlıdır ve bu Kullanım + KoÅŸullarının bir parçası deÄŸildir. Ve Uygulamanın kalitesine iliÅŸkin bir + anlaÅŸma da teÅŸkil etmez. </p> <p> - Ek bilgiler + Ayrıntılı bilgiler </p> <p> - UYGULAMA'ya iliÅŸkin ek bilgileri aÅŸağıdaki baÄŸlantıda bulabilirsiniz: - <strong>[<em>Link</em>]</strong> + Uygulama ile ilgili ayrıntılı bilgileri aÅŸağıdaki linkte bulabilirsiniz: + https://www.coronawarn.app/de/ + (SaÄŸlayan kurum: SAP Deutschland SE & Co. KG) </p> <p> - SARS-CoV-2 pandemisine iliÅŸkin ek bilgileri aÅŸağıdaki baÄŸlantıda + SARS-CoV-2 pandemisi ilgili ayrıntılı bilgileri aÅŸağıdaki linkte bulabilirsiniz: https://www.zusammengegencorona.de/ + (SaÄŸlayan kurum: Bundesministerium für Gesundheit/Federal SaÄŸlık Bakanlığı) +</p> +<p> + Bu ek bilgiler, yalnızca açıklama amaçlıdır ve bu Kullanım KoÅŸullarının bir + parçası deÄŸildir. </p> <p> - Bu ek bilgiler, sadece aydınlatma amacı taşır ve bu kullanım koÅŸullarının - bir parçası deÄŸildir. + 2. DÜŞÜK RÄ°SK VEYA DAHA YÃœKSEK RÄ°SK, NE ANLAMA GELÄ°R? </p> <p> - 2. DÜŞÜK YA DA DAHA YÃœKSEK RÄ°SK NE ANLAMA GELÄ°R? + Uygulama, COVID-19 bildirim sistemi tarafından kaydedilen riskli + karşılaÅŸmalara göre tahmini bir bireysel risk hesaplar. Bu baÄŸlamda, riskli + karşılaÅŸmadan bu yana geçen zaman aralığı, riskli karşılaÅŸma süresi, + Bluetooth sinyal gücünün ölçülen zayıflamasına göre Korona testi pozitif + çıkan kiÅŸiye olan yaklaşık mesafe ve semptomların baÅŸlangıcından bu yana + geçen süre (Korona testi pozitif çıkan kiÅŸi tarafından saÄŸlanmışsa) gibi + faktörler göz önüne alınır. </p> <p> - UYGULAMA, tespit edilen karşılaÅŸmaları temel alarak, belirtici bireysel - riski hesaplar. Bluetooth sinyallerinin zayıflaması ölçülerek (<em>signal attenuation</em>) - karşılaÅŸmadan itibaren geçen zaman (<em>days since exposure</em>), karşılaÅŸmanın süresi ( <em>exposure - duration</em>), enfekte olan kiÅŸiye tahmini mesafe gibi - faktörler ve de taşıma riskleri (<em>transmission risk</em>) dikkate - alınır. Buna dayanarak, UYGULAMA size "düşük risk" ya da "daha yüksek risk" - olarak bildirimde bulunur. Bu durumda, kaydedilen veriler temel alınarak - salt belirtici bir deÄŸer elde edilir. + Bu faktörler temelinde, Uygulamada "düşük", "daha yüksek" veya risk + deÄŸerlendirmesi yapılamıyorsa “bilinmeyen risk†görüntülenir. Bu veri, + COVID-19 bildirim sisteminden ve CWA hizmetlerinden saÄŸlanan verileri baz + alan bir tahmindir. <strong> - Bu durumda, gerçek bir SARS-CoV-2 enfeksiyonun mevcudiyetine iliÅŸkin - bir bildirim söz konusu deÄŸildir. + Bir SARS-CoV-2 enfeksiyonun gerçekten varlığına iliÅŸkin bir ifade + deÄŸildir. </strong> - "Düşük risk" halinde de bir enfeksiyon söz konusu olabileceÄŸi gibi "daha - yüksek risk" halinde de bir enfeksiyon söz konusu olmayabilir. + ÖrneÄŸin “düşük risk†hesaplandığında bir enfeksiyon söz konusu olabilirken, + “daha yüksek risk†hesaplandığında bile mutlaka bir enfeksiyon olması + zorunda deÄŸildir. </p> <p> <strong> - DiÄŸer faktörler bireysel enfeksiyon riskinizi önemli ölçüde - etkileyebilir. UYGULAMA bu faktörleri göz önüne almaz. + BaÅŸka faktörler, sizin kiÅŸisel enfeksiyon riskinizi önemli ölçüde + etkileyebilmektedir. Bu faktörler, Uygulama tarafından dikkate alınmaz. </strong> - Bu faktörler özellikle bireysel ÅŸartlarınız, enfekte olan kiÅŸi ile maruz - kalmalanın çevresel ÅŸartları, bireysel davranışlarınız ve de üçüncü kiÅŸiler - ile yaÅŸadığınız, ancak UYGULAMA'nın kapsamadığı karşılaÅŸmalardır. Lütfen 4 - numaralı baÅŸlıktaki talimatları dikkate alın. + Bunlar, özellikle sizin kiÅŸisel koÅŸullarınız, virüs bulaÅŸmış bir kiÅŸiyle + karşılaÅŸma riskinin harici koÅŸulları, kiÅŸisel tutumunuz ve Uygulama + tarafından kaydedilmeyen üçüncü kiÅŸilerle olan karşılaÅŸmalarınızdır. Lütfen + Madde 4‘teki bilgilere dikkat ediniz. </p> <p> - 3. MARUZ KALMA - NE YAPMALIYIM? + 3. RÄ°SKE MARUZ KALINCA - NE YAPMALIYIZ? </p> <p> - Enfekte olan kiÅŸiler ile yaÅŸadığınız maruz kalma durumunda UYGULAMA size - bildirimde bulunursa, bu bildirimde nasıl davranmanız gerektiÄŸiyle ilgili - tavsiyeler alırsınız. Bu tavsiyeler hukuken baÄŸlayıcı deÄŸildir, ancak RKI - bunlara uymanızı tavsiye eder. Enfekte olan kiÅŸiler ile yaÅŸadığınız maruz - kalmaya yönelik kanunlardan ve sözleÅŸmelerden ve de resmi makamların - talimatlarından doÄŸan yükümlülükler saklı kalır ve bu yükümlülüklere söz - konusu tavsiyelerden bağımsız olarak uymak zorundasınız. + Korona testi pozitif çıkan kiÅŸilerle bir riskli karşılaÅŸma hakkında + Uygulama tarafından bilgilendirildiÄŸinizde, ayrıca bu konuyla ilgili tutum + önerileri de alırsınız. Bu öneriler yasal olarak baÄŸlayıcı deÄŸildir, ancak + RKI bu önerilere uyulmasını önerir. Enfekte kiÅŸilerle bir maruz kalma + durumunda geçerli olan yasal ve sözleÅŸmeden doÄŸan yükümlülükler ve ayrıca + resmi düzenlemeler, bu baÄŸlamda etkilenmeksizin geçerliliÄŸini korurlar ve + bu önerilerden bağımsız olarak riayet edilmelidirler. </p> <p> <strong> - UYGULAMA içerisinde ya da UYGULAMA aracılığıyla hiçbir tıbbi tanı - koyulmaz. + Uygulama içinde veya aracılığıyla herhangi bir tıbbi tanı konmaz. </strong> </p> <p> <strong> - Bildirim, SARS-CoV-2 virüsüyle enfekte olduÄŸunuz anlamına gelmez. + Bir maruz kalma ile ilgili yapılan bilgilendirme, sizin SARS-CoV-2 ile + enfekte olduÄŸunuz anlamına gelmez. </strong> - Bildirim, sadece SARS-CoV-2 enfeksiyonu pozitif belirlenen bir kiÅŸi ile son - 14 günde maruz kalma yaÅŸadığınızı bildirir. Bu durumdan, öncelikle sizin de - enfekte olmuÅŸ olma ihtimaliniz doÄŸar. Buna iliÅŸkin riskin "düşük" ya da - "daha yüksek" olarak sınıflandırılması, sadece iletilen verilere dayanır ve - gerçek bir enfeksiyona iliÅŸkin bildirim deÄŸildir. + Bu bilgilendirme sadece, son 14 gün içinde SARS-CoV-2 enfeksiyon testi + pozitif olduÄŸu tespit edilen bir kiÅŸiyle bir riskli karşılaÅŸma yaÅŸadığınızı + gösterir. Burada öncelikle, sizin de aynı ÅŸekilde enfeksiyon kapmış + olabileceÄŸinize dair bir olasılık söz konusudur. Bu baÄŸlamda sadece, + COVID-19 bildirim sistemi ve CWA hizmetleri tarafından saÄŸlanan veriler + (örneÄŸin semptomların baÅŸlangıcına iliÅŸkin veriler) temelinde “düşük†veya + “daha yüksek†olarak bir risk sınıflandırması yapılır ve enfeksiyonun + gerçekten var olmasına dair herhangi bir ifade sunulmaz. </p> <p> - <strong>Maruz kalmaya iliÅŸkin bildirim doÄŸru olmayabilir. </strong> - Cihazınız maruz kalmayı, örneÄŸin, cihazınızın yakınında bulunmadığınız ya - da baÅŸka bir kiÅŸinin cihazınızı kullandığı esnada kaydetmiÅŸ olabilir. Maruz - kalma, temas ölçümü esnasında mevcut sınırlar sebebiyle yanlışlıkla - kaydedilmiÅŸ olabilir (aÅŸağıda yer alan 8 numaralı baÅŸlığa bakınız). + <strong>Bir maruz kalma hakkındaki bilgi yanlış olabilir.</strong> + Maruz kalma verisi, COVID-19 bildirim sistemi tarafından, örneÄŸin + cihazınızın yanınızda olmadığı bir durumda veya baÅŸka bir kiÅŸi cihazınızı + kullanırken kaydedilmiÅŸ olabilir. Maruz kalma, COVID-19 bildirim sisteminin + mevcut sınırları nedeniyle yanlış kaydedilmiÅŸ olabilir (Bkz. aÅŸağıdaki + Madde 8). </p> <p> - 4. UYGULAMA, ENFEKSÄ°YONA KARÅžI KORUMA SAÄžLAMAZ + 4. UYGULAMA, ENFEKSÄ°YONDAN KORUNMA SAÄžLAMAZ </p> <p> - UYGULAMA, enfeksiyon zincirlerinin kırılmasını saÄŸlar. + Uygulamanın amacı enfeksiyon zincirini kesmektir. </p> <ul> <li> - <strong>UYGULAMA sizi SARS-CoV-2 enfeksiyonuna karşı korumaz.</strong> + <strong>Uygulama, sizi SARS-CoV-2 enfeksiyonundan korumaz.</strong> </li> <li> - <strong>UYGULAMA, kiÅŸisel enfeksiyon riskinizi azaltmaz.</strong> + <strong>Uygulama, sizin kiÅŸisel enfeksiyon riskinizi azaltmaz.</strong> </li> <li> <strong> - Sizi enfekte eden kiÅŸi ile maruz kalmanız hakkında UYGULAMA size - bildirim göndermemiÅŸ olmasına raÄŸmen SARS-CoV-2 virüsüyle enfekte - olabilirsiniz: + Bir kiÅŸi ile maruz kalma durumu yaÅŸarsanız, Uygulama size bu konuda + bir uyarı vermeden de, SARS-CoV-2 ile enfekte olabilirsiniz: </strong> </li> </ul> <p> - o UYGULAMA, örneÄŸin; diÄŸer kiÅŸiler UYGULAMA'yı kullanmadığı için, - cihazınızı her zaman yanınızda taşımadığınız için ya da UYGULAMA hep - çalışır durumda olmadığı için ya da temas ölçümü bazı sınırlara tabi olduÄŸu - için diÄŸer kiÅŸiler ile tüm karşılaÅŸmalarınızı kaydetmez (aÅŸağıda yer alan 8 - numaralı baÅŸlığa bakınız). + o Uygulama, diÄŸer insanlarla olan tüm karşılaÅŸmalarınızı bilemez, çünkü + örneÄŸin Uygulamayı kullanmayan diÄŸer insanlarla karşılaÅŸabilirsiniz, + cihazınızı her zaman yanınızda taşımıyor veya Uygulamayı her zaman çalışır + durumda tutmuyorsunuzdur veya karşılaÅŸmaların kaydedilmesi COVID-19 + bildirim sisteminde belirli bazı sınırlara tabidir (Bkz. aÅŸağıdaki Madde + 8). </p> <p> - o UYGULAMA size sadece enfekte olan kiÅŸiler ile yaÅŸadığınız maruz kalmaları - bildirir. Bu durum, UYGULAMA'nın enfekte olan kiÅŸiler ile yaÅŸadığınız - karşılaÅŸmayı kaydetmiÅŸ olmasına <u>ve</u> enfekte olan kiÅŸinin UYGULAMA - aracılığıyla uyarıda bulunması ÅŸartına baÄŸlıdır. Uyarıda bulunma isteÄŸe - baÄŸlıdır ve muhtemelen tüm enfekte olan kiÅŸiler uyarıda bulunmaz. + o Uygulama, sizi yalnızca COVID-19 bildirim sistemi tarafından saptanan ve + Uygulamaya aktarılan enfekte insanlarla karşılaÅŸma durumundaki riskler + hakkında bilgilendirir. Bu ise enfekte olmuÅŸ kiÅŸinin Uygulama aracılığıyla + bir uyarı tetiklemesini gerektirir. Ancak uyarı tetiklemek isteÄŸe baÄŸlıdır + ve tüm enfekte kiÅŸiler tarafından yapılmayabilir. </p> <p> - Lütfen UYGULAMA'nın kullanımı esnasında diÄŸer tedbir önlemlerine ve resmi - talimatlara uyun. SARS-CoV-2 pandemisi ve tedbir önlemlerine iliÅŸkin - güvenilir bilgilere aÅŸağıdaki baÄŸlantılardan da ulaÅŸabilirsiniz: + Dolayısıyla Uygulamayı kullanırken, lütfen diÄŸer tedbirleri ve resmi + düzenlemeleri de dikkate alınız. SARS-CoV-2 pandemisi ve ilgili tedbirler + hakkında güvenilir bilgileri ÅŸu adreste bulabilirsiniz: </p> <p> www.infektionsschutz.de/coronavirus + (SaÄŸlayan kurum: Bundeszentrale für gesundheitliche Aufklärung/Federal + SaÄŸlık Bilgilendirme Merkezi) </p> <p> www.zusammengegencorona.de + (SaÄŸlayan kurum: Bundesministerium für Gesundheit/Federal SaÄŸlık Bakanlığı) </p> <p> www.rki.de/covid-19 + (SaÄŸlayan kurum: RKI) </p> <p> - Bu ek bilgiler sadece sizi bilgilendirme amacı taşır ve bu kullanım - koÅŸullarının bir parçası deÄŸildir. + Bu ek bilgiler, yalnızca açıklama amaçlıdır ve bu Kullanım KoÅŸullarının bir + parçası deÄŸildir. </p> <p> - UYGULAMA'yı kullanırken <strong>MEM kurallarına da uyun:</strong> + Uygulamayı kullanırken <strong>AHA kurallarına</strong> uyun: </p> <p> - <strong>M</strong> - - Yanınızdaki kiÅŸiler ile aranızda en az 1,5 metre mesafe olmasına dikkat - edin + <strong>A</strong> + - DiÄŸer insanlarla aranıza en azından 1,5 m mesafe bırakın </p> <p> - <strong>E</strong> - - Ellerinizi düzenli olarak en az 20 saniye boyunca yıkayın + <strong>H</strong> + - Ellerinizi düzenli olarak en azından 20 saniye boyunca yıkayın </p> <p> - <strong>M</strong> - - AlışveriÅŸ esnasında ve toplu taşıma araçlarında maske kullanın + <strong>A</strong> + - AlışveriÅŸte ve toplu taşıma araçlarında günlük maske takın </p> <p> - Ancak bu ÅŸekilde kendinizi ve diÄŸer kiÅŸileri virüse karşı korursunuz. + Böylece hem kendinizi, hem de baÅŸkalarını virüsten korursunuz. </p> <p> - 5. TEST SONUÇLARINI Ä°STEME + 5. TEST SONUÇLARININ ÇAÄžRILMASI </p> <p> - UYGULAMA aracılığıyla sadece kendi test sonuçlarınızı isteyebilirsiniz. + Uygulamayı, sadece kendi test sonuçlarınıza eriÅŸmek amacıyla da + kullanabilirsiniz. </p> <p> - Test sonuçlarını bekliyorsanız ve CWA hizmetleri hazır deÄŸilse ya da test - sonuçlarını baÅŸka sebeplerle UYGULAMA üzerinden isteyemiyorsanız, lütfen - örneÄŸin, aile doktorunuz ya da yerel kamu saÄŸlığı yetkilisi gibi ilgili - test noktasından diÄŸer iletiÅŸim yolları aracılığıyla test sonucu hakkında - bilgi edinin. UYGULAMA'nın tekrar kullanıma sunulmasını beklemeyin. + Test sonucunuzu bekliyorsanız, ancak CWA hizmetleri kullanılamıyorsa veya + test sonuçlarının Uygulama aracılığıyla alınması diÄŸer nedenlerden ötürü + çalışmıyorsa, lütfen test sonucunuz hakkında bilgiyi, aile doktorunuz veya + yerel saÄŸlık kurumundaki bir test merkezi gibi diÄŸer iletiÅŸim kanalları + üzerinden saÄŸlayın. Uygulamanın tekrar kullanılabilir duruma gelmesini + beklemeyin. </p> <p> - 6. UYARIDA BULUNMA + 6. BÄ°R UYARININ TETÄ°KLENMESÄ° </p> <p> - SARS-CoV-2 virüsüyle enfekte olursanız, UYGULAMA aracılığıyla diÄŸer - iletiÅŸim kiÅŸilerini uyarabilirsiniz. + SARS-CoV-2 enfeksiyonu testiniz pozitif çıkmışsa, temas edebileceÄŸiniz + diÄŸer insanları uyarmak için Uygulamayı kullanabilirsiniz. <strong> - Yetkili bir test laboratuvarında yapılan test sonucunda enfeksiyonun - pozitif çıkması halinde bu uyarıda bulunabilirsiniz. + Böyle bir uyarıyı yalnızca, onaylı bir test laboratuvarında yapılan bir + enfeksiyon testi pozitif olarak belirlendiÄŸi takdirde tetiklemenize + izin verilir. </strong> </p> <p> - Yetkili test laboratuvarı, CWA hizmetlerinde yer almıyorsa, RKI'nin - düzenlediÄŸi DoÄŸrulama Yardım Hattı aracılığıyla enfeksiyon durumunuz - kontrol edilir. Sadece pozitif risk sonucunu bildirmeye dayanarak UYGULAMA - aracılığıyla uyarıda bulunamazsınız. + Test yaptırdığınız laboratuvar, henüz CWA hizmetlerine baÄŸlanmadıysa, + enfeksiyon durumunuz RKI tarafından kurulan bir doÄŸrulama yardım hattı + aracılığıyla kontrol edilecektir. Yalnızca bir risk bildirimi yapmak için, + Uygulama aracılığıyla uyarı tetiklenmesine izin verilmez. </p> <p> - Belirsizlik halinde: önce aile doktorunuzla ya da kamu saÄŸlığı yetkilisi - ile iletiÅŸime geçin + Belirsizlik halinde: Önce aile doktorunuza veya bir saÄŸlık kurumuna + baÅŸvurun </p> <p> - Enfekte olup olmadığınızdan emin deÄŸilseniz, bir uyarıda bulunmadan önce - aile doktorunuzla ya da kamu saÄŸlığı yetkilisi ile iletiÅŸime geçin. Aile - doktoru ya da yetkili saÄŸlık birimi size ek tavsiyelerde bulunur ve gerekli - olursa enfeksiyon testi yaptırabilirsiniz. Bu esnada, SARS-CoV-2 virüsü - enfeksiyonu şüphesi halinde nasıl davranmanız gerektiÄŸiyle ilgili genel - olarak geçerli tavsiyelere uyarsınız. + Enfekte olup olmadığınızdan emin deÄŸilseniz, lütfen aile doktorunuz veya + yetkili saÄŸlık kurumu ile iletiÅŸime geçin. Orada ayrıntılı danışmanlık + hizmeti alabilir ve gerekirse enfeksiyon testi yaptırabilirsiniz. Bu + süreçte, bir SARS-CoV-2 enfeksiyonundan şüpheleniyorsanız, yapmanız + gerekenler konusunda genel geçerli önerileri uygulayın. </p> <p> - Kötüye kullanım yasağı + Suistimal yasağı </p> <p> <strong> - Kötü niyetli uyarıda bulunamazsınız ve kötü niyetli uyarıda bulunmanız - ağır sonuçlara yol açabilir. + Bir uyarının kötü niyetli olarak tetiklenmesi, yasaktır ve ciddi + sonuçlar doÄŸurabilir. </strong> - Özellikle, maÄŸdur olan diÄŸer kiÅŸilerin zararlarını karşılamakla sorumlu - tutulabilirsiniz. + Özellikle, olumsuz etkilenen diÄŸer insanlara zarar tazminatı ödemekle + yükümlü kılınabilirsiniz. </p> <p> - Kötü niyetli davranışın tespiti halinde RKI, UYGULAMA ve CWA hizmetlerini - kullanmaya devam etmenizi engelleme hakkını saklı tutar. + 7. UYGULAMANIN KULLANIM GEREKSÄ°NÄ°MLERÄ° </p> <p> - 7. UYGULAMA'YI KULLANIM ÅžARTLARI + Uygulamayı kullanmak için aÅŸağıdaki teknik gereksinimler zorunludur: </p> <p> - AÅŸağıdaki teknik ÅŸartlar UYGULAMA'nın kullanımı için gereklidir: + Bir veri baÄŸlantısına ihtiyacınız var </p> <p> - Veri baÄŸlantınız olmalıdır + Uygulamanın belirli bazı iÅŸlevleri, CWA hizmetleri üzerinden kullanıma + sunulan merkezi hizmetlere ve sistemlere dayanmaktadır. Dolayısıyla bu + iÅŸlevler, yalnızca cihazınızın internete veri baÄŸlantısı varsa + kullanılabilmektedir, örneÄŸin, CWA hizmetlerine eriÅŸebilmek için UMTS, LTE + veya WLAN gibi aÄŸ teknolojilerinden yararlanılmaktadır. Veri baÄŸlantısı + olmadan, Uygulamanın iÅŸlevlerinden bazıları veya tamamı kullanılamaz. Bu, + cihazınızı uçuÅŸ moduna geçirdiÄŸinizde veya kapattığınızda da söz konusudur. </p> <p> - UYGULAMA'nın belirli iÅŸlevleri, CWA hizmetleri aracılığıyla sunulan merkezi - hizmet ve sistemleri gerektirir. Bu yüzden, bu iÅŸlevler CWA hizmetlerine - eriÅŸim için cihazınızın örneÄŸin, UMTS, LTE ya da WLAN aracılığıyla internet - ile veri baÄŸlantısı olduÄŸunda sunulur. Veri baÄŸlantısı olmadan UYGULAMA'nın - tüm ya da bir kısım özellikleri çalışmaz. Bu durum, cihazınızı uçak moduna - aldığınızda ya da kapattığınızda da geçerlidir. + COVID-19 bildirim sistemi etkinleÅŸtirilmiÅŸ olmalıdır </p> <p> - UYGULAMA, cihazda çalışmalı ve açık olmalıdır + Cihazınızdaki COVID-19 bildirim sistemi, etkinleÅŸtirilmiÅŸ ve “Almanya†+ bölgesi ve Uygulama için kullanıma açılmış olmalıdır. </p> <p> - UYGULAMA, cihazınızda ön ya da arka planda çalışmalı ve açık olmalıdır. - Bunun için UYGULAMA'yı baÅŸlatmalısınız. UYGULAMA'yı baÅŸlatmaz, kapatır ya - da sonlandırırsanız, UYGULAMA diÄŸer kiÅŸiler ile karşılaÅŸmaları kaydetmez ve - diÄŸer kiÅŸiler aracılığıyla kayıt amaçlı rastgele kimlikler üretmez. Cihazı - yeniden baÅŸlatırsanız, (örneÄŸin, kapattıktan, pil bittikten ya da iÅŸletim - sisteminin güncelledikten sonra) UYGULAMA'yı da yeniden baÅŸlatmalısınız. + <strong><em>Arka plan güncellemesi</em></strong> </p> <p> - Cihaz ayarları + Uygulama, arka planda sürekli çalışmalıdır. Cihazınızı yeniden + baÅŸlatırsanız (örn. cihazınızı kapattıktan, bataryası bittikten veya + iÅŸletim sistemi güncellemesinden sonra) veya Uygulamanın zorunlu olarak + sonlandırılmasından sonra, Uygulamayı yeniden baÅŸlatmanız gerekir. </p> <p> - UYGULAMA'yı kullanmak için cihazınızdaki Bluetooth (BLE) iÅŸlevlerini - etkinleÅŸtirmeli ve gerekirse UYGULAMA tarafından kullanıma izin - vermelisiniz. + Cihazdaki ayarlar </p> <p> - UYGULAMA'nın temel iÅŸlevlerinin kullanımı için ÅŸart olmasa da, RKI, - UYGULAMA'nın kullanımı için aÅŸağıdaki iÅŸlevleri cihazınızda - etkinleÅŸtirmenizi ve gerekirse UYGULAMA tarafından kullanıma izin vermenizi - önerir: + Uygulamayı kullanmak için cihazınızdaki Bluetooth (BLE) iÅŸlevlerini de + etkinleÅŸtirmeli ve gerekirse Uygulama tarafından kullanılmak üzere + onaylamalısınız. +</p> +<p> + Uygulamayı kullanmanız için RKI ayrıca, cihazınızda aÅŸağıdaki iÅŸlevleri + etkinleÅŸtirmenizi ve gerekirse, bir ön koÅŸul olmasa bile, Uygulamanın temel + iÅŸlevlerini kullanmak için bunların Uygulama tarafından kullanılmasını + onaylamanızı önerir: </p> <ul> <li> @@ -436,344 +478,352 @@ </li> </ul> <p> - Lütfen bu iÅŸlevlerin etkinleÅŸtirildiÄŸini ve UYGULAMA'nın kullanımı için - bunlara izin verildiÄŸini cihazınızın ayarlar kısmından kontrol edin. + Lütfen cihazınızın ayarlarında, bu iÅŸlevlerin etkinleÅŸtirildiÄŸini ve + Uygulamanın kullanımı için onaylandığından emin olun. </p> <p> - iOS ve Android uyarınca UYGULAMA'nın ayarlanması ile ilgili ayrıntılı - talimatı https://www.coronawarn.app/en/ bulabilirsiniz. Kılavuz sadece aydınlatma amacı - taşır ve bu kullanım koÅŸullarının bir parçası deÄŸildir. + Uygulamanın iOS ve Android sistemlerinde nasıl kurulacağına dair ayrıntılı + kılavuzu, açık kaynak projesinin web sitesinde Corona-Warn-App bölümünde + bulabilirsiniz: https://www.coronawarn.app/de/ + (SaÄŸlayan kurum: SAP Deutschland SE & Co. KG). Sözü geçen kılavuz, + yalnızca bilgilendirme amaçlıdır ve bu Kullanım KoÅŸullarının bir parçası + deÄŸildir. </p> <p> - Her zaman UYGULAMA'nın güncel sürümünü kullanmalısınız + Uygulamanın daima güncel bir sürümünü kullanmalısınız. </p> <p> - RKI, muhtelif zamanlarda UYGULAMA'nın güncellemelerini sunar. Bu - güncellemeleri derhal yüklemeli ve her zaman UYGULAMA'nın en son sürümünü - kullanmalısınız. Eski sürümlerin kullanılması, hatalar ve arızalar ile - sonuçlanabilir. + RKI, ara sıra Uygulamanın güncellemelerini saÄŸlayacaktır. Bu + güncellemeleri, cihazınıza hemen yüklemeli ve Uygulamanın daima mevcut en + son sürümünü kullanmalısınız. Daha eski sürümlerin kullanılması, hatalı + çalışmalara ve arızalara neden olabilir. Bir güncelleme zorunlu olarak + gerekliyse, Uygulamayı açtığınızda bu konuda bilgilendirileceksiniz. </p> <p> - <strong><em>iOS veya Android'in en son sürümleri gereklidir</em></strong> -</p> -<p> - UYGULAMA, sadece iOS'ta Apple ve Android'de Google tarafından uygulanan - iÅŸlevleri (<em>Exposure Notification olarak anılır</em>) kullanır. Bu - iÅŸlevler, iOS'ta sürüm 13.5 ve Android'de sürüm 6 ile sunulmuÅŸtur. - UYGULAMA, maalesef bu yüzden her iki iÅŸletim sisteminin önceki sürümlerinde - mevcut deÄŸildir. -</p> -<p> - 8. UYGULAMA'NIN SINIRLARI + <strong> + <em>iOS veya Android sistemlerinin en son sürümleri gereklidir</em> + </strong> </p> <p> - UYGULAMA, test sonuçları sonradan pozitif çıkan kiÅŸilere maruz kalmaları - görmeniz için size yardımcı olur. UYGULAMA'nın dikkate alınması gereken - sınırları vardır. + Uygulama, Apple tarafından iOS’te ve Google tarafından Android’de sunulan + COVID-19 bildirim sistemini kullanır. Bu ise sadece, iOS sürümü 13.5’ten ve + Android’de sürüm 6’dan itibaren mevcuttur. Uygulama, ne yazık ki iki + iÅŸletim sisteminin daha önceki sürümlerinde çalışmamaktadır. </p> <p> - UYGULAMA'nın bazı rastgele kimlikleri (<em>Rolling Proximity Identifiers</em>) sürekli - göndermesi, ancak diÄŸer - rastgele kimlikleri sadece belirli aralıklarla göndermesi bu sınırlardan - biridir. Bu süre aralığı ÅŸu anda beÅŸ dakikadadır ve çok kısa olarak - belirtilmiÅŸtir. Bu iÅŸlevsellikler, Google ve Apple'ın muhtelif zamanlarda - deÄŸiÅŸtirilebilecek olan Exposure Notification Frameworks'ün bir parçasıdır. + 8. UYGULAMANIN SINIRLARI </p> <p> - Mesafe ölçümü için Bluetooth sinyallerindeki zayıflama kullanılır. - Zayıflamanın azalması baÅŸka bir cihazın yakınlarda olduÄŸunu gösterir. - Zayıflamanın artması baÅŸka bir cihazın uzakta olduÄŸunu (iki metreden fazla - mesafe) ya da her iki cihazın arasında sinyali engelleyen bir nesnenin - olduÄŸunu gösterir. Cihazın içinde bulunduÄŸu bir çanta ya da duvar gibi - nesneler ya da aynı ÅŸekilde insan ya da hayvanlar olabilir. + Uygulama, testi pozitif çıkan diÄŸer kullanıcılarla riskli karşılaÅŸmaları + belirlemenize yardımcı olabilir. Ancak Uygulamanın dikkate alınması gereken + sınırları da vardır, özellikle: </p> +<ul> + <li> + Uygulama, sadece iÅŸletim sisteminizdeki COVID-19 bildirim sistemi + tarafından kaydedilen ve Uygulamaya aktarılan maruz kalmaları + deÄŸerlendirebilir. Bu kayıtların COVID-19 bildirim sistemindeki + mevcudiyeti, eksiksizliÄŸi, doÄŸruluÄŸu ve güvenilirliÄŸi üzerinde RKI’nin + bir etkisi yoktur. + </li> + <li> + Uygulama yalnızca, sınır ötesi uyarı sistemine katılan ülkelerin resmi + Korona uygulamalarının Korona pozitif kullanıcılarının, pozitif test + sonuçlarını ilgili Korona uygulaması aracılığıyla sınır ötesi uyarı + iÅŸlevi için kullanıma sunmaları ve siz bu kullanıcılarla bir riskli + karşılaÅŸma yaÅŸamanız halinde sizi uyarabilir. + </li> + <li> + Enfeksiyon riskini deÄŸerlendirmek için, Uygulama, ölçülen Bluetooth + sinyal gücünün zayıflamasını kullanır. Sinyal gücünün zayıflaması daha + az ise, diÄŸer cihaz daha yakın demektir. Zayıflama artıyorsa, diÄŸer + cihazın daha uzakta olduÄŸu (yani mesafe iki metreden daha fazla) veya + sinyali engelleyen iki cihaz arasında baÅŸka bir ÅŸeyin olduÄŸu anlamına + gelir. Bu, bir engel, bir duvar veya cihazın bulunduÄŸu bir cep gibi + nesneler olabileceÄŸi gibi, insanlar veya hayvanlar da olabilir. + </li> +</ul> <p> - 9. KULLANIM HAKLARI + 9. KULLANIM HAKLARI </p> <p> <strong><em>Basit kullanım hakkı</em></strong> </p> <p> - Ä°ÅŸbu belgeyle UYGULAMA'nın ticari olmayan ve kiÅŸisel amaçlar ile kullanımı - için size sınırlı, gayri münhasır, devredilemez, iptal edilebilir bir - lisans verilmektedir. + Uygulamayı kendi kiÅŸisel ve ticari olmayan amaçlarınıza yönelik kullanmanız + için, size sınırlı, münhasır olmayan, devredilemez, alt lisans olarak + verilemez, geri alınabilir bir lisans verilmektedir. </p> <p> - UYGULAMA'nın iOS sürümünün lisansı, mülkiyetiniz ya da kontrolünüzdeki her - bir Apple cihazında geçerli App Store kullanım koÅŸulları çerçevesindeki - kullanımı kapsar ve aile paylaşımı ya da eÄŸitime yönelik Volume Purchase - programı aracılığıyla Apple hesabınız ile baÄŸlantılı diÄŸer Apple hesapları - aracılığıyla UYGULAMA'ya eriÅŸebilir ve UYGULAMA'yı kullanabilirsiniz. + Uygulamanın iOS sürümü lisansı, AppStore’ın geçerli kullanım koÅŸullarına + tabi olarak sahip olduÄŸunuz veya kontrol ettiÄŸiniz herhangi bir Apple + cihazında kullanımı içerir. Uygulamaya ayrıca aile içi paylaşımı veya toplu + satın alma yoluyla Apple hesabınıza baÄŸlanan diÄŸer Apple hesapları + aracılığıyla da eriÅŸilebilir ve kullanabilirsiniz. </p> <p> - Yedekleme amacıyla UYGULAMA'nın kopyalarını oluÅŸturabilirsiniz. Size, - UYGULAMA'ya iliÅŸkin baÅŸkaca hiçbir hak tanınmaz. + Yedekleme amaçlı olarak Uygulamanın kopyalarını oluÅŸturmanıza izin verilir. + Bu belirtilenlerin dışında Uygulama için baÅŸka haklara sahip deÄŸilsiniz. </p> <p> - <strong><em>UYGULAMA'nın mülkiyeti</em></strong> + <strong><em>Uygulamada mülkiyet kavramı</em></strong> </p> <p> - 9 numaralı baÅŸlık çerçevesinde size tanınan haklar ve de SAP tarafından - Almanya Federal Cumhuriyeti'ne sözleÅŸme ile saÄŸlanan, UYGULAMA'ya iliÅŸkin - diÄŸer haklar saklı kalmak kaydıyla, UYGULAMA'nın (kaynak kodlarının dahil) - mülkiyeti yalnızca ve münhasıran Dietmar Hopp Allee 16, 69190 Walldorf - adresinde bulunan SAP SE ("<strong>SAP</strong>") ya da lisans verenlerine - aittir. + Uygulamanın tek ve münhasır mülkiyeti, merkezi Dietmar-Hopp-Allee 16, 69190 + Walldorf’ta bulunan SAP SE’ye (“<strong>SAP</strong>â€) veya lisans + verenlerine aittir; bu baÄŸlamda Madde 9 uyarınca size tanınan haklar ve + SAP’nin sözleÅŸmeyle Federal Almanya Cumhuriyetine verdiÄŸi uygulamaya + iliÅŸkin diÄŸer haklar hariç tutulur. </p> <p> - <strong><em>Açık kaynak lisans talimatları</em></strong> + <strong><em>Açık kaynak lisans bilgileri</em></strong> </p> <p> - UYGULAMA'da bulunan üçüncü taraf bileÅŸenlerinin kullanımı ve geçerli lisans - koÅŸulları hakkında bilgiye, UYGULAMA'daki Açık Kaynak Lisans - Talimatlarından eriÅŸebilirsiniz. + Uygulamada kullanılan üçüncü taraf bileÅŸenleri ve geçerli lisans koÅŸulları + hakkında bilgiler, Uygulamadaki açık kaynak lisans bilgilerinde yer + almaktadır. </p> <p> - UYGULAMA'nın kaynak kodu, "Apache 2.0 License" lisans koÅŸullarında - yayınlanmıştır ve "https://github.com/corona-warn-app" adresinden indirebilirsiniz. - "Apache 2.0 License" lisans koÅŸullarına "https://www.apache.org/licenses/LICENSE-2.0" - adresinden eriÅŸebilirsiniz. + Uygulamanın kaynak kodu, "Apache 2.0 License" lisans koÅŸulları altında + yayınlanmakta olup, “ + https://github.com/corona-warn-app + †adresinden indirilebilir. “Apache 2.0 License†lisans koÅŸullarına “ + https://www.apache.org/licenses/LICENSE-2.0 + †adresinden eriÅŸebilirsiniz. </p> <p> - UYGULAMA'daki kaynak koduna ve de UYGULAMA'da bulunan üçüncü taraf - bileÅŸenlerine uygulanan lisans koÅŸulları, 9 numaralı baÅŸlık uyarınca - tanınan haklardan etkilenmez. + Uygulamanın kaynak kodunun yanı sıra Uygulamada kullanılan üçüncü taraf + bileÅŸenleri için geçerli lisans koÅŸulları, Madde 9’da deÄŸinilen hakların + verilmesinden bağımsızdır. </p> <p> - <strong><em>Yasak iÅŸlemler</em></strong> + <strong><em>Neye izin verilmez</em></strong> </p> <p> - UYGULAMA'yı manipüle edemez ya da deÄŸiÅŸtiremezsiniz. + Uygulamayı manipüle etmenize veya deÄŸiÅŸtirmenize izin verilmez. </p> <p> - UYGULAMA'yı ya da CWA hizmetlerinin ara yüzlerini kötüye kullanamazsınız. - CWA hizmetlerini, cihazınızdaki UYGULAMA'nın amaca uygun kullanımından - baÅŸka bir amaçla kullanamazsınız. CWA hizmetlerine sadece UYGULAMA - aracılığıyla ulaÅŸabilirsiniz. + Uygulamayı ve CWA hizmetlerinin arayüzlerini kötü amaçlı kullanamazsınız. + CWA hizmetlerini, Uygulamanın cihazınızda amaçlanan çalışması dışındaki + amaçlar doÄŸrultusunda kullanamazsınız. CWA hizmetlerine yalnızca Uygulama + üzerinden eriÅŸmenize izin verilir. </p> <p> - 10. KULLANILABÄ°LÄ°RLÄ°K VE DEĞİŞİKLÄ°KLER HAKKINDA ÖNEMLÄ° TALÄ°MATLAR + 10. KULLANILABÄ°LÄ°RLÄ°ÄžE VE DEĞİŞİKLÄ°KLERE Ä°LÄ°ÅžKÄ°N ÖNEMLÄ° BÄ°LGÄ°LER </p> <p> - Belirli iÅŸlevlere yönelik talepte bulunulamaz + Belirli bir iÅŸlevsellik talebi kabul edilmez </p> <p> - UYGULAMA, RKI tarafından yayınlandığı ÅŸekliyle hizmetinize sunulur. RKI, - UYGULAMA ve CWA hizmetlerinin iÅŸlevleri hakkında hiçbir garantide bulunmaz - ve size belirli nitelikleri taahhüt etmez. UYGULAMA ya da CWA hizmetlerinin - belirli bir iÅŸlev ya da baÅŸka bir niteliÄŸe sahip olması gerektiÄŸi talebinde - bulunamazsınız. RKI, UYGULAMA'yı dilediÄŸinde deÄŸiÅŸtirebilir ve iÅŸlevleri - tamamen ya da kısmen kaldırabilir ya da UYGULAMA'ya ek iÅŸlevler ile - geniÅŸletebilir. + Uygulama, RKI tarafından yayımlandığı haliyle kullanımınıza sunulur. RKI, + Uygulamanın veya CWA hizmetlerinin iÅŸlevselliÄŸini garanti etmez ve sizinle + spesifik bir kaliteye iliÅŸkin bir anlaÅŸma yapmamaktadır. Uygulamanın veya + CWA hizmetlerinin belli bir iÅŸlevselliÄŸine veya kalite seviyesine yönelik + hak talebinde bulunamazsınız. RKI, istediÄŸi zaman Uygulamayı deÄŸiÅŸtirebilir + ve iÅŸlevlerini tamamen veya kısmen kaldırabilir veya Uygulamayı ek iÅŸlevler + ile geniÅŸletebilir. </p> <p> - Kullanılabilirlik taahhüt edilmez + Kullanılabilirlik taahhüdü yok </p> <p> - RKI, UYGULAMA ve CWA hizmetlerinin iÅŸleyiÅŸini dilediÄŸinde sınırlayabilir ya - da durdurabilir. Tek bir iÅŸlev ya da tüm sisteme iliÅŸkin olarak - UYGULAMA'nın ya da CWA hizmetleri dahil UYGULAMA ile baÄŸlantılı hizmetler - ile sistemlerin çalışmaya devam etmesi talebinde bulunamazsınız. + RKI, istediÄŸi zaman Uygulamanın ve CWA hizmetlerinin iÅŸletimini + kısıtlayabilir veya durdurabilir. CWA hizmetleri dahil olmak üzere, + Uygulamanın veya iliÅŸkili hizmetlerin ve sistemlerin herhangi bir iÅŸlevinin + veya bir bütün olarak sistemin tamamının sürekli kullanıma sunulmasına + yönelik bir hak talebinde bulunamazsınız. </p> <p> - RKI, CWA hizmetlerinin kullanılabilirlik ya da performansı hakkında hiçbir - taahhütte bulunmaz. KUU hizmetleri, bakım çalışmaları ya da arızalar - sebebiyle geçici olarak ve gerekirse daha uzun süreler boyunca - çalışmayabilir. Bu durumlarda, UYGULAMA'nın iÅŸlevselliÄŸi tamamen ya da - kısmen sınırlanır. + RKI, CWA hizmetlerinin kullanıma sunulmasına veya performansına iliÅŸkin + herhangi bir taahhütte bulunmaz. Bunlar, bakım çalışmaları veya arızalar + nedeniyle geçici olarak ve gerekirse daha uzun süreler için kullanıma + sunulmayabilir. Bu durumlarda, Uygulamanın iÅŸlevselliÄŸi kısmen veya tamamen + kısıtlanır. </p> <p> - Kullanım koÅŸullarının deÄŸiÅŸtirilmesi + Kullanım KoÅŸullarının deÄŸiÅŸtirilmesi </p> <p> - RKI, bu kullanım koÅŸullarını deÄŸiÅŸtirme hakkını saklı tutar. Böyle bir - durumda, UYGULAMA'yı baÅŸlatırken deÄŸiÅŸtirilen kullanım koÅŸullarını kabul - etmeniz istenir. DeÄŸiÅŸtirilen kullanım koÅŸullarını kabul etmiyorsanız - UYGULAMA ve CWA hizmetlerini kullanamazsınız ve UYGULAMA'yı cihazınızdan - silmelisiniz. + RKI, bu Kullanım KoÅŸullarını istediÄŸi zaman deÄŸiÅŸtirme hakkını saklı tutar. + DeÄŸiÅŸtirilen Kullanım KoÅŸullarını kabul etmezseniz, artık Uygulamayı ve CWA + hizmetlerini kullanamazsınız ve Uygulamayı cihazınızdan silmeniz gerekir. </p> <p> - Risk Puanı + Risk deÄŸerlendirme parametrelerinin deÄŸiÅŸtirilmesi </p> <p> - Virüs taşımaya iliÅŸkin güncel araÅŸtırma sonuçlarına uyum saÄŸlamak için RKI, - risk puanında (<em>risk score</em>) kullanılan parametreleri dilediÄŸinde - deÄŸiÅŸtirme hakkını saklı tutar. RKI, kullanılan parametreleri kendi - takdiriyle belirler. + RKI ayrıca, virüs taşıma ile ilgili en son araÅŸtırma sonuçlarına + adaptasyonu saÄŸlamak adına, enfeksiyon riskinin deÄŸerlendirilmesinde + kullanılan parametreleri istediÄŸi zaman deÄŸiÅŸtirme hakkını saklı tutar. + RKI, bu kapsamda kullanılan parametreleri kendi takdirine göre belirler. </p> <p> - 11. GARANTÄ° YOKTUR + 11. GARANTÄ° YOK </p> <p> - RKI, UYGULAMA'nın ve CWA hizmetlerinin iÅŸlevlerini ve de bunların yapısını - belirler. RKI, UYGULAMA'nın belirli niteliklere sahip olduÄŸunu taahhüt - etmez ve siz de UYGULAMA'nın belirli iÅŸlevlere sahip olması ya da bunların - belirli bir yöntemle ÅŸekillendirilmesi talebinde bulunamazsınız. UYGULAMA, - RKI'nin UYGULAMA'yı Apple App Store'da ya da Google Play'de sunduÄŸu - ÅŸekliyle aynı durumda ve aynı iÅŸlevler ile sunulur. + RKI, Uygulamanın ve CWA hizmetlerinin iÅŸlevlerini ve bunların tasarımını + belirler. RKI, sizinle spesifik bir kalite seviyesi anlaÅŸması yapmaz ve + siz, Uygulamanın belirli iÅŸlevlere sahip olmasına veya bunların tasarım + ÅŸekline yönelik hak talebinde bulunamazsınız. Uygulama, RKI tarafından + programlandığı ÅŸekliyle ve iÅŸlevlerle Apple AppStore’da veya Google Play’de + kullanıma sunulur. </p> <p> - RKI, UYGULAMA'yı makul özen ile sunar ve CWA hizmetlerine de makul özen - uygulanır. RKI, UYGULAMA ya da CWA hizmetlerine iliÅŸkin baÅŸkaca hiçbir - taahhüt ya da güvencede bulunmaz ve özellikle de aÅŸağıdakiler kesinlikle - garanti etmez: + RKI, uygulamayı gereken özenle kullanıma sunacak ve CWA hizmetleriyle + ilgili olarak da gereken özeni gösterecektir. RKI, Uygulamaya veya CWA + hizmetlerine iliÅŸkin baÅŸka herhangi bir vaatte bulunmaz veya güvence vermez + ve özellikle ÅŸunları garanti etmez: </p> <ul> <li> - UYGULAMA ya da CWA hizmetlerini kullanımınızın kesintisiz ya da hatasız - olacağını, + Sizin Uygulamayı veya CWA hizmetlerini kullanımınızın kesintisiz veya + hatasız saÄŸlanması, </li> <li> - UYGULAMA ya da CWA hizmetlerinin kayıp, yolsuzluk, saldırı, virüs, - müdahale, bilgisayar korsanlığı ya da diÄŸer güvenlik hatalarından muaf - olacağını, + Uygulamada veya CWA hizmetlerinde, kayıp, yolsuzluk, saldırı, virüsler, + izinsiz müdahale, bilgisayar korsanlığı veya güvenlikle ilgili diÄŸer + kesintilerin olmaması. </li> </ul> <p> - Cihazınızdaki verilerin ve icabında bununla baÄŸlantılı sistemlerin - yedeklenmesinden siz sorumlusunuz, bunlara cihazınızda kayıtlı olan diÄŸer - tüm uygulamaların yedeklenmesi de dahildir. -</p> -<p> - 12. UYGULAMA'NIN Ä°OS SÃœRÃœMÃœ İÇİN ÖZEL KOÅžULLAR + · + <br/> + <br/> </p> <p> - AÅŸağıdaki koÅŸullar, UYGULAMA'nın Apple App Store aracılığıyla satın - alınması ve iOS iÅŸletim sistemi ile kullanımı için geçerlidir. + Cihazınızda saklanan diÄŸer tüm uygulamaların yedeklenmesi de dahil olmak + üzere, cihazınızdaki verileri ve cihazınıza baÄŸlı tüm sistemleri + yedeklemekten siz sorumlusunuz. </p> <p> - Veri kullanımının onaylanması + 12. UYGULAMANIN Ä°OS SÃœRÃœMÃœ İÇİN ÖZEL KOÅžULLARI </p> <p> - RKI'nin yazılım güncellemeleri, ürün destek ve UYGULAMA ile baÄŸlantılı - olarak size sunulan hizmetlerin hazırlanmasını kolaylaÅŸtırmak için düzenli - aralıklarla toplanan teknik veri ve bunlara iliÅŸkin bilgileri - özellikle - cihaz, sistem ve uygulama yazılımınız ve de donanım birimleri hakkındaki - teknik bilgileri - toplayacağını ve kullanacağını kabul edersiniz. RKI, bu - bilgileri ürünlerini geliÅŸtirmek ya da size hizmet ve teknolojiler sunmak - amacıyla ve de kimliÄŸinizi ifÅŸa etmeyecek ÅŸekilde kullanabilir. + AÅŸağıdaki koÅŸullar, Uygulamanın Apple AppStore’dan indirilmesi ve iOS + iÅŸletim sisteminde kullanımı için geçerlidir. </p> <p> - Bakım ve Destek + Bakım ve destek </p> <p> - UYGULAMA'nın yayımcısı olarak RKI, bu kullanım koÅŸullarına göre - UYGULAMA'nın bakım ve desteÄŸinden tek başına sorumludur. Apple, UYGULAMA - ile ilgili olarak bakım ve destek hizmetlerinin saÄŸlanmasından kesinlikle - sorumlu deÄŸildir. + Uygulamanın bu Kullanım KoÅŸullarına uygun olarak, bakımından ve + desteklenmesinden yalnızca Uygulamanın yayımcısı olarak RKI sorumludur. + Apple, Uygulamaya iliÅŸkin herhangi bir bakım veya destek hizmeti saÄŸlama + yükümlülüğü üstlenmez. </p> <p> - Apple, arızalar sebebiyle sorumlu deÄŸildir + Apple, arızalar nedeniyle sorumluluk üstlenmez </p> <p> - UYGULAMA'nın arızalanması halinde bu konuda Apple'i bilgilendirebilirsiniz. - Kanun tarafından öngörülen haller hariç, Apple'ın UYGULAMA arızaları - sebebiyle sorumluluÄŸu yoktur. + Uygulama arızalanırsa, bunu Apple’a bildirmekte serbestsiniz. Yasaların + izin verdiÄŸi ölçüde, Apple’ın Uygulamanın kesintiye uÄŸramasına iliÅŸkin + herhangi bir yükümlülüğü yoktur. </p> <p> Ãœrün sorumluluÄŸu </p> <p> - Apple, ürün sorumluluÄŸundan doÄŸan talepler, + Apple, sizin veya bir üçüncü tarafın Uygulamaya iliÅŸkin, aÅŸağıdakiler de + dahil olmak üzere, mülkiyet veya kullanımına yönelik bir hak talebinden + sorumlu deÄŸildir: </p> <ul> <li> - UYGULAMA'nın yasa ya da yönetmelikten doÄŸan geçerli gereksinimleri - yerine getirmediÄŸi yönündeki talepler ve + Ãœrün sorumluluÄŸuna iliÅŸkin hak talepleri, </li> <li> - HealthKit ve HomeKit Frameworks kullanımları ile baÄŸlantılı olanlar - dahil tüketiciyi koruma ve veri koruma yasaları ya da benzer yasalar - çerçevesindeki talepler dahil + Uygulamanın geçerli yasal veya düzenleyici gereklilikleri yerine + getirmemesine yönelik hak talepleri ve </li> <li> - UYGULAMA ya da UYGULAMA'yı elinde bulundurma yada UYGULAMA'nın - kullanımı ile ilgili olarak sizin ya da üçüncü tarafların + Tüketici koruma ve veri gizliliÄŸi yasaları veya benzeri yasalar + kapsamındaki hak talepleri, </li> </ul> <p> - benzer taleplerinden sorumlu deÄŸildir. + HealthKit ve HomeKit Framework’leri kullanımıyla baÄŸlantılı olanlar. </p> <p> - Üçüncü kiÅŸilerin korunma haklarını ihlal + Üçüncü taraf mülkiyet haklarının ihlali </p> <p> - Üçüncü kiÅŸilerin UYGULAMA aracılığıyla ya da UYGULAMA'nın kullanımı ya da - UYGULAMA'yı elinizde bulundurmanız sebebiyle korunma haklarının ihlaline - iliÅŸkin talepte bulunması halinde, Apple, korunma haklarının ihlalinden - ötürü bu tür taleplerin araÅŸtırılması, savunulması, uzlaÅŸtırılması ya da - ifasından sorumlu olmaz. + Üçüncü tarafların, Uygulamanın kendi mülkiyet haklarını ihlal ettiÄŸine veya + sizin Uygulamayı bulundurmanız veya kullanmanız nedeniyle mülkiyet + haklarının ihlal edildiÄŸine yönelik hak taleplerinde bulunması durumunda, + Apple, bu konuyu soruÅŸturmak, savunmak, karara baÄŸlamak veya gereÄŸini ifa + etmekten sorumlu deÄŸildir. </p> <p> - A.B.D. ambargoları ve yaptırımları + ABD ambargoları ve yaptırımları </p> <p> - Bu kullanım koÅŸullarını kabul ederek, + Bu Kullanım KoÅŸullarını kabul ederek, </p> <ul> <li> - Amerika BirleÅŸik Devletleri hükümeti ambargosuna tabi bir ülkede ya da - Amerika BirleÅŸik Devletleri hükümeti tarafından terörist destekçisi (<em>"terrorist - supporting" country</em>) olarak öngörülen bir ülkede - ikamet etmediÄŸinizi ve + Amerika BirleÅŸik Devletleri Hükümeti tarafından ambargoya tabi tutulan + veya Amerika BirleÅŸik Devletleri Hükümeti tarafından “Teröre Destek + Veren Ãœlke†(<em>terrorist supporting country</em>) olarak tanımlanmış + bir ülkede olmadığınızı ve </li> <li> - Amerika BirleÅŸik Devletleri hükümetinin <em>Prohibited or Restricted Party</em> olarak - bilinen listesinde yer - almadığınızı onaylarsınız. + Amerika BirleÅŸik Devletleri Hükümetinin “Yasaklı veya Kısıtlanmış + Taraf†(<em>Prohibited or Restricted Party</em>) olarak adlandırdığı + kiÅŸi ve kurumlar listesinde yer almadığınızı onaylamış olursunuz. </li> </ul> <p> - Apple'ın lehtarlığı + Apple’ın üçüncü taraf lehtar hakları </p> <p> - Apple'ın bu kullanım koÅŸulları uyarınca lehtar olduÄŸunu ve bu sebeple, bu - kullanım koÅŸullarını size karşı uygulayabileceÄŸini kabul eder ve - onaylarsınız. Bu kullanım koÅŸulları ve Apple'ın bu kullanım koÅŸulları - çerçevesindeki haklarına iliÅŸkin yapılacak deÄŸiÅŸiklik ve iptal hakkı - taraflara aittir ve Apple'ın onayını gerektirmez. + Bu Kullanım KoÅŸulları baÄŸlamında, Apple için üçüncü taraf lehtar hakları + oluÅŸtuÄŸunu ve bu nedenle Apple’ın bu Kullanım KoÅŸullarını size karşı + uygulayabileceÄŸini onaylar ve kabul edersiniz. Apple’ın bu kapsamdaki + hakları da dahil olmak üzere, bu Kullanım KoÅŸullarında yapılan + deÄŸiÅŸiklikler ve iptaller, sözleÅŸme taraflarına saklı kalır ve Apple’ın + onayını gerektirmez. </p> <p> - 13. SON HÃœKÃœMLER + 13. SONUÇ HÃœKÃœMLERÄ° </p> <p> - Amaca uygun kullanım / kötüye kullanım halinde engelleme + Amaca uygun kullanım / suistimal halinde eriÅŸime kapatma </p> <p> - UYGULAMA ve CWA hizmetlerini sadece amaca uygun olarak kullanabilirsiniz. - UYGULAMA’nın kötüye kullanımı ya da CWA hizmetlerine amaca uygun olmayan - ÅŸekilde eriÅŸim halinde RKI, UYGULAMA ve CWA hizmetlerini devre dışı bırakma - hakkını saklı tutar. + Uygulamayı ve CWA hizmetlerini, yalnızca amacına uygun kullanabilirsiniz. + RKI, Uygulamanın suistimali veya CWA hizmetlerine kötü niyetli eriÅŸim + durumunda, sizin Uygulamaya ve CWA hizmetlerine eriÅŸiminizi kapatma hakkını + saklı tutar. </p> <p> - Üçüncü tarafların hizmetleri + Üçüncü taraf hizmetleri </p> <p> - UYGULAMA'nın kullanımı ile baÄŸlantılı olarak özellikle telekomünikasyon - hizmet saÄŸlayıcılarının hizmet baÄŸlantısı sunma hizmetleri gibi üçüncü - tarafların hizmetlerinden yararlanırsanız, ilgili sözleÅŸme koÅŸullarına - uygun davranmakla ve bu baÄŸlamda meydana gelen masraflardan bizzat - sorumlusunuz. + Uygulamanın kullanımıyla baÄŸlantılı olarak üçüncü tarafların hizmetlerini, + özellikle de bir veri baÄŸlantısının saÄŸlanması için telekomünikasyon hizmet + saÄŸlayıcılarının hizmetlerinden yararlandığınızda, oluÅŸan masraflardan ve + ilgili sözleÅŸme koÅŸullarına uymaktan siz sorumlu olursunuz. </p> <p> - Tabi olunan hukuk + Uygulanacak hukuk </p> <p> - Bu kullanım koÅŸulları, Almanya Federal Cumhuriyeti kanunlarına tabidir. - Milletlerarası Mal Satımına iliÅŸkin SözleÅŸmeler hakkında BirleÅŸmiÅŸ - Milletler AnlaÅŸması hükümleri uygulanmaz. Özellikle tüketici olarak ikamet - ettiÄŸiniz ülkenin zorunlu kanun hükümlerinin uygulanması ve hukuk seçiminin - kısıtlanması ile ilgili yasal hükümler saklıdır. + Bu Kullanım KoÅŸulları, Almanya Federal Cumhuriyeti yasalarına tabidir. + Uluslararası Mal Satış SözleÅŸmelerine iliÅŸkin BirleÅŸmiÅŸ Milletler + Konvansiyonu geçerli deÄŸildir. Özellikle sizin tüketici olarak olaÄŸan + ikamet yerinizin bulunduÄŸu ülke, yargı yeri seçimini kısıtlayan ve zorunlu + hükümlerin uygulanabilirliÄŸine iliÅŸkin yasal hükümler, bu baÄŸlamda + etkilenmeksizin geçerliliÄŸini korurlar. </p> <p> Kısmi geçersizlik </p> <p> - Bu kullanım koÅŸullarının bir kısmı hukuken geçersiz olsa dahi, kalan - kısımlar geçerli olmaya devam eder. Geçersiz kısımların yerine kanuni - hükümler uygulanır. Kullanım koÅŸulları, bu durumun sözleÅŸmenin - taraflarından biri için kabul edilemez bir zorluÄŸa yol açtığı ölçüde - tamamen geçersiz olur. + Bu Kullanım KoÅŸulları, münferit maddelerin hukuken geçersiz olması + durumunda bile, geri kalan kısımlarında baÄŸlayıcı kalır Hukuken geçersiz + olan maddeler yerine, varsa yasal hükümler uygulanır. Bu durum, sözleÅŸme + taraflarından biri için kabul edilemez bir zorluk teÅŸkil ederse, Kullanım + KoÅŸulları bir bütün olarak geçersiz hale gelecektir. </p> <p> * * * diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt index 21ce0efd119bd9ce90a2fbf92abec58bca23f94b..c59011fb5a237823925049893146dbe6656ffb14 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt @@ -1,192 +1,139 @@ package de.rki.coronawarnapp -import android.annotation.SuppressLint import android.app.Activity import android.app.Application import android.content.Context import android.content.IntentFilter -import android.content.pm.ActivityInfo -import android.net.wifi.WifiManager import android.os.Bundle -import android.os.PowerManager import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.ProcessLifecycleOwner -import androidx.lifecycle.lifecycleScope import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Configuration import androidx.work.WorkManager +import dagger.android.AndroidInjector +import dagger.android.DispatchingAndroidInjector +import dagger.android.HasAndroidInjector import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver import de.rki.coronawarnapp.exception.reporting.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL import de.rki.coronawarnapp.notification.NotificationHelper -import de.rki.coronawarnapp.storage.LocalData -import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction -import de.rki.coronawarnapp.util.ConnectivityHelper -import de.rki.coronawarnapp.util.debug.FileLogger +import de.rki.coronawarnapp.util.CWADebug +import de.rki.coronawarnapp.util.WatchdogService +import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.di.ApplicationComponent import de.rki.coronawarnapp.worker.BackgroundWorkHelper -import de.rki.coronawarnapp.worker.BackgroundWorkScheduler -import kotlinx.coroutines.launch import org.conscrypt.Conscrypt import timber.log.Timber import java.security.Security -import java.util.UUID +import javax.inject.Inject -class CoronaWarnApplication : Application(), LifecycleObserver, - Application.ActivityLifecycleCallbacks { +class CoronaWarnApplication : Application(), HasAndroidInjector { - companion object { - val TAG: String? = CoronaWarnApplication::class.simpleName - private lateinit var instance: CoronaWarnApplication - - /* describes if the app is in foreground - * Initialized to false, because app could also be started by a background job. - * For the cases where the app is started via the launcher icon, the onAppForegrounded - * event will be called, setting it to true - */ - var isAppInForeground = false + @Inject lateinit var component: ApplicationComponent - fun getAppContext(): Context = - instance.applicationContext + @Inject lateinit var androidInjector: DispatchingAndroidInjector<Any> + override fun androidInjector(): AndroidInjector<Any> = androidInjector - const val TEN_MINUTE_TIMEOUT_IN_MS = 10 * 60 * 1000L - var fileLogger: FileLogger? = null - } - - private lateinit var errorReceiver: ErrorReportReceiver + @Inject lateinit var watchdogService: WatchdogService override fun onCreate() { - super.onCreate() instance = this + super.onCreate() + CWADebug.init(this) + + Timber.v("onCreate(): Initializing Dagger") + AppInjector.init(this) - val configuration = Configuration.Builder() - .setMinimumLoggingLevel(android.util.Log.DEBUG) - .build() - WorkManager.initialize(this, configuration) + Timber.v("onCreate(): Initializing WorkManager") + Configuration.Builder() + .apply { setMinimumLoggingLevel(android.util.Log.DEBUG) }.build() + .let { WorkManager.initialize(this, it) } NotificationHelper.createNotificationChannel() + // Enable Conscrypt for TLS1.3 Support below API Level 29 Security.insertProviderAt(Conscrypt.newProvider(), 1) - ProcessLifecycleOwner.get().lifecycle.addObserver(this) - registerActivityLifecycleCallbacks(this) - if (BuildConfig.DEBUG) { - Timber.plant(Timber.DebugTree()) - } - if ((BuildConfig.FLAVOR == "deviceForTesters" || BuildConfig.DEBUG)) { - fileLogger = FileLogger(this) - } + ProcessLifecycleOwner.get().lifecycle.addObserver(foregroundStateUpdater) + registerActivityLifecycleCallbacks(activityLifecycleCallback) - // notification to test the WakeUpService from Google when the app - // was force stopped + // notification to test the WakeUpService from Google when the app was force stopped BackgroundWorkHelper.sendDebugNotification( "Application onCreate", "App was woken up" ) - // Only do this if the background jobs are enabled - if (ConnectivityHelper.autoModeEnabled(applicationContext)) { - ProcessLifecycleOwner.get().lifecycleScope.launch { - // we want a wakelock as the OS does not handle this for us like in the background - // job execution - val wakeLock = createWakeLock() - // we keep a wifi lock to wake up the wifi connection in case the device is dozing - val wifiLock = createWifiLock() - try { - BackgroundWorkHelper.sendDebugNotification( - "Automatic mode is on", "Check if we have downloaded keys already today" - ) - RetrieveDiagnosisKeysTransaction.startWithConstraints() - } catch (e: Exception) { - BackgroundWorkHelper.sendDebugNotification( - "RetrieveDiagnosisKeysTransaction failed", - (e.localizedMessage - ?: "Unknown exception occurred in onCreate") + "\n\n" + (e.cause - ?: "Cause is unknown").toString() - ) - // retry the key retrieval in case of an error with a scheduled work - BackgroundWorkScheduler.scheduleDiagnosisKeyOneTimeWork() - } - - if (wifiLock.isHeld) wifiLock.release() - if (wakeLock.isHeld) wakeLock.release() - } + watchdogService.launch() + } + + private val foregroundStateUpdater = object : LifecycleObserver { + @OnLifecycleEvent(Lifecycle.Event.ON_START) + fun onAppForegrounded() { + isAppInForeground = true + Timber.v("App is in the foreground") + } - // if the user is onboarded we will schedule period background jobs - // in case the app was force stopped and woken up again by the Google WakeUpService - if (LocalData.onboardingCompletedTimestamp() != null) BackgroundWorkScheduler.startWorkScheduler() + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + fun onAppBackgrounded() { + isAppInForeground = false + Timber.v("App is in the background") } } - private fun createWakeLock(): PowerManager.WakeLock = - (getSystemService(Context.POWER_SERVICE) as PowerManager) - .run { - newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, - TAG + "-WAKE-" + UUID.randomUUID().toString() - ).apply { - acquire(TEN_MINUTE_TIMEOUT_IN_MS) - } - } + private val activityLifecycleCallback = object : ActivityLifecycleCallbacks { + private val localBM by lazy { + LocalBroadcastManager.getInstance(this@CoronaWarnApplication) + } + private var errorReceiver: ErrorReportReceiver? = null - private fun createWifiLock(): WifiManager.WifiLock = - (getSystemService(Context.WIFI_SERVICE) as WifiManager) - .run { - createWifiLock( - WifiManager.WIFI_MODE_FULL_HIGH_PERF, - TAG + "-WIFI-" + UUID.randomUUID().toString() - ).apply { - acquire() - } + override fun onActivityPaused(activity: Activity) { + errorReceiver?.let { + localBM.unregisterReceiver(it) + errorReceiver = null } + } - /** - * Callback when the app is open but backgrounded - */ - @OnLifecycleEvent(Lifecycle.Event.ON_STOP) - fun onAppBackgrounded() { - isAppInForeground = false - Timber.v("App backgrounded") - } + override fun onActivityStarted(activity: Activity) { + // NOOP + } - /** - * Callback when the app is foregrounded - */ - @OnLifecycleEvent(Lifecycle.Event.ON_START) - fun onAppForegrounded() { - isAppInForeground = true - Timber.v("App foregrounded") - } + override fun onActivityDestroyed(activity: Activity) { + // NOOP + } - override fun onActivityPaused(activity: Activity) { - // unregisters error receiver - LocalBroadcastManager.getInstance(this).unregisterReceiver(errorReceiver) - } + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { + // NOOP + } - override fun onActivityStarted(activity: Activity) { - // does not override function. Empty on intention - } + override fun onActivityStopped(activity: Activity) { + // NOOP + } - override fun onActivityDestroyed(activity: Activity) { - // does not override function. Empty on intention - } + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + // NOOP + } - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { - // does not override function. Empty on intention - } + override fun onActivityResumed(activity: Activity) { + errorReceiver?.let { + localBM.unregisterReceiver(it) + errorReceiver = null + } - override fun onActivityStopped(activity: Activity) { - // does not override function. Empty on intention + errorReceiver = ErrorReportReceiver(activity).also { + localBM.registerReceiver(it, IntentFilter(ERROR_REPORT_LOCAL_BROADCAST_CHANNEL)) + } + } } - @SuppressLint("SourceLockedOrientationActivity") - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { - // set screen orientation to portrait - activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT - } + companion object { + private lateinit var instance: CoronaWarnApplication + + /* describes if the app is in foreground + * Initialized to false, because app could also be started by a background job. + * For the cases where the app is started via the launcher icon, the onAppForegrounded + * event will be called, setting it to true + */ + var isAppInForeground = false - override fun onActivityResumed(activity: Activity) { - errorReceiver = - ErrorReportReceiver(activity) - LocalBroadcastManager.getInstance(this) - .registerReceiver(errorReceiver, IntentFilter(ERROR_REPORT_LOCAL_BROADCAST_CHANNEL)) + fun getAppContext(): Context = instance.applicationContext } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigApiV1.kt new file mode 100644 index 0000000000000000000000000000000000000000..ae8898f1aabacd8f602ffc16065bcefe7040fb6a --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigApiV1.kt @@ -0,0 +1,13 @@ +package de.rki.coronawarnapp.appconfig + +import okhttp3.ResponseBody +import retrofit2.http.GET +import retrofit2.http.Path + +interface AppConfigApiV1 { + + @GET("/version/v1/configuration/country/{country}/app_config") + suspend fun getApplicationConfiguration( + @Path("country") country: String + ): ResponseBody +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..aa295a3523210e13dec27ad6f9338ed67c3efe6e --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigModule.kt @@ -0,0 +1,52 @@ +package de.rki.coronawarnapp.appconfig + +import android.content.Context +import dagger.Module +import dagger.Provides +import de.rki.coronawarnapp.environment.download.DownloadCDNHttpClient +import de.rki.coronawarnapp.environment.download.DownloadCDNServerUrl +import okhttp3.Cache +import okhttp3.OkHttpClient +import org.joda.time.Duration +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.io.File +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +@Module +class AppConfigModule { + + @Singleton + @Provides + fun provideAppConfigApi( + context: Context, + @DownloadCDNHttpClient client: OkHttpClient, + @DownloadCDNServerUrl url: String, + gsonConverterFactory: GsonConverterFactory + ): AppConfigApiV1 { + val cacheSize = 1 * 1024 * 1024L // 1MB + + val cacheDir = File(context.cacheDir, "http_app-config") + val cache = Cache(cacheDir, cacheSize) + + val cachingClient = client.newBuilder().apply { + cache(cache) + connectTimeout(HTTP_TIMEOUT_APPCONFIG.millis, TimeUnit.MILLISECONDS) + readTimeout(HTTP_TIMEOUT_APPCONFIG.millis, TimeUnit.MILLISECONDS) + writeTimeout(HTTP_TIMEOUT_APPCONFIG.millis, TimeUnit.MILLISECONDS) + callTimeout(HTTP_TIMEOUT_APPCONFIG.millis, TimeUnit.MILLISECONDS) + }.build() + + return Retrofit.Builder() + .client(cachingClient) + .baseUrl(url) + .addConverterFactory(gsonConverterFactory) + .build() + .create(AppConfigApiV1::class.java) + } + + companion object { + private val HTTP_TIMEOUT_APPCONFIG = Duration.standardSeconds(10) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..8ee5e894584a3a07e051c950e946ca9ebbf5b548 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigProvider.kt @@ -0,0 +1,131 @@ +package de.rki.coronawarnapp.appconfig + +import androidx.annotation.VisibleForTesting +import dagger.Lazy +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.environment.download.DownloadCDNHomeCountry +import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration +import de.rki.coronawarnapp.util.ZipHelper.unzip +import de.rki.coronawarnapp.util.security.VerificationKeys +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AppConfigProvider @Inject constructor( + private val appConfigAPI: Lazy<AppConfigApiV1>, + private val verificationKeys: VerificationKeys, + @DownloadCDNHomeCountry private val homeCountry: LocationCode, + private val configStorage: AppConfigStorage +) { + + private val configApi: AppConfigApiV1 + get() = appConfigAPI.get() + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal suspend fun downloadAppConfig(): ByteArray? { + Timber.tag(TAG).d("Fetching app config.") + var exportBinary: ByteArray? = null + var exportSignature: ByteArray? = null + configApi.getApplicationConfiguration(homeCountry.identifier).byteStream() + .unzip { entry, entryContent -> + if (entry.name == EXPORT_BINARY_FILE_NAME) exportBinary = + entryContent.copyOf() + if (entry.name == EXPORT_SIGNATURE_FILE_NAME) exportSignature = + entryContent.copyOf() + } + if (exportBinary == null || exportSignature == null) { + throw ApplicationConfigurationInvalidException() + } + + if (verificationKeys.hasInvalidSignature(exportBinary, exportSignature)) { + throw ApplicationConfigurationCorruptException() + } + + return exportBinary!! + } + + private fun tryParseConfig(byteArray: ByteArray?): ApplicationConfiguration? { + Timber.v("Parsing config (size=%dB)", byteArray?.size) + if (byteArray == null) return null + return ApplicationConfiguration.parseFrom(byteArray) + } + + private suspend fun getNewAppConfig(): ApplicationConfiguration? { + val newConfigRaw = try { + downloadAppConfig() + } catch (e: Exception) { + Timber.w(e, "Failed to download latest AppConfig.") + if (configStorage.isAppConfigAvailable) { + null + } else { + Timber.e("No fallback available, rethrowing!") + throw e + } + } + + val newConfigParsed = try { + tryParseConfig(newConfigRaw) + } catch (e: Exception) { + Timber.w(e, "Failed to parse latest AppConfig.") + null + } + + return newConfigParsed?.also { + Timber.d("Saving new valid config.") + Timber.v("New Config.supportedCountries: %s", it.supportedCountriesList) + configStorage.appConfigRaw = newConfigRaw + } + } + + private fun getFallback(): ApplicationConfiguration { + val lastValidConfig = tryParseConfig(configStorage.appConfigRaw) + return if (lastValidConfig != null) { + Timber.d("Using fallback AppConfig.") + lastValidConfig + } else { + Timber.e("No valid fallback AppConfig available.") + throw ApplicationConfigurationInvalidException() + } + } + + suspend fun getAppConfig(): ApplicationConfiguration = withContext(Dispatchers.IO) { + val newAppConfig = getNewAppConfig() + + return@withContext if (newAppConfig != null) { + newAppConfig + } else { + Timber.w("No new config available, using last valid.") + getFallback() + } + }.performSanityChecks() + + private fun ApplicationConfiguration.performSanityChecks(): ApplicationConfiguration { + var sanityChecked = this + + if (sanityChecked.supportedCountriesList == null) { + sanityChecked = sanityChecked.toNewConfig { + clearSupportedCountries() + addAllSupportedCountries(emptyList<String>()) + } + } + + val countryCheck = sanityChecked.supportedCountriesList + if (countryCheck.size == 1 && !VALID_CC.matches(countryCheck.single())) { + Timber.w("Invalid country data, clearing. (%s)", this.supportedCountriesList) + sanityChecked = sanityChecked.toNewConfig { + clearSupportedCountries() + } + } + return sanityChecked + } + + companion object { + private val VALID_CC = "^([A-Z]{2,3})$".toRegex() + private const val EXPORT_BINARY_FILE_NAME = "export.bin" + private const val EXPORT_SIGNATURE_FILE_NAME = "export.sig" + private val TAG = AppConfigProvider::class.java.simpleName + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigStorage.kt new file mode 100644 index 0000000000000000000000000000000000000000..44edccd9c44b9163bcb367cd070e64fe7c4e38fb --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigStorage.kt @@ -0,0 +1,47 @@ +package de.rki.coronawarnapp.appconfig + +import android.content.Context +import timber.log.Timber +import java.io.File +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AppConfigStorage @Inject constructor( + context: Context +) { + private val configDir = File(context.filesDir, "appconfig_storage") + private val configFile = File(configDir, "appconfig") + + val isAppConfigAvailable: Boolean + get() = configFile.exists() && configFile.length() > MIN_VALID_CONFIG_BYTES + + var appConfigRaw: ByteArray? + get() { + Timber.v("get() AppConfig") + if (!configFile.exists()) return null + + val value = configFile.readBytes() + Timber.v("Read AppConfig of size %s and date %s", value.size, configFile.lastModified()) + return value + } + set(value) { + Timber.v("set(...) AppConfig: %dB", value?.size) + + if (configDir.mkdirs()) Timber.v("Parent folder created.") + + if (configFile.exists()) { + Timber.v("Overwriting %d from %s", configFile.length(), configFile.lastModified()) + } + if (value != null) { + configFile.writeBytes(value) + } else { + configFile.delete() + } + } + + companion object { + // The normal config is ~512B+, we just need to check for a non 0 value, 128 is fine. + private const val MIN_VALID_CONFIG_BYTES = 128 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ApplicationConfigurationCorruptException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationCorruptException.kt similarity index 88% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ApplicationConfigurationCorruptException.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationCorruptException.kt index 5cb36f06630e270566e5d94289868c60dadcdec4..51c5dfb8933f457956bf161cd29acc5defef8c94 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ApplicationConfigurationCorruptException.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationCorruptException.kt @@ -1,4 +1,4 @@ -package de.rki.coronawarnapp.exception +package de.rki.coronawarnapp.appconfig import de.rki.coronawarnapp.exception.reporting.ErrorCodes import de.rki.coronawarnapp.exception.reporting.ReportedException diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..48423b587ce0079e958f1d01b16700370ed79a7d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationExtensions.kt @@ -0,0 +1,11 @@ +package de.rki.coronawarnapp.appconfig + +import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration + +fun ApplicationConfiguration.toNewConfig( + action: ApplicationConfiguration.Builder.() -> Unit +): ApplicationConfiguration { + val builder = this.toBuilder() + action(builder) + return builder.build() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ApplicationConfigurationInvalidException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationInvalidException.kt similarity index 88% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ApplicationConfigurationInvalidException.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationInvalidException.kt index eb71a47e24b1bbe53d1cc6c641bed6eb118127c8..153435397fcff0fa237e32723413fd5aae3f9c30 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/ApplicationConfigurationInvalidException.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationInvalidException.kt @@ -1,4 +1,4 @@ -package de.rki.coronawarnapp.exception +package de.rki.coronawarnapp.appconfig import de.rki.coronawarnapp.exception.reporting.ErrorCodes import de.rki.coronawarnapp.exception.reporting.ReportedException diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/DiagnosisKeysModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/DiagnosisKeysModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..213c479c350ccd82d1d66325577d4db521362772 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/DiagnosisKeysModule.kt @@ -0,0 +1,37 @@ +package de.rki.coronawarnapp.diagnosiskeys + +import android.content.Context +import dagger.Module +import dagger.Provides +import de.rki.coronawarnapp.diagnosiskeys.server.DiagnosisKeyApiV1 +import de.rki.coronawarnapp.diagnosiskeys.storage.legacy.KeyCacheLegacyDao +import de.rki.coronawarnapp.environment.download.DownloadCDNHttpClient +import de.rki.coronawarnapp.environment.download.DownloadCDNServerUrl +import de.rki.coronawarnapp.storage.AppDatabase +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Singleton + +@Module +class DiagnosisKeysModule { + + @Singleton + @Provides + fun provideDiagnosisKeyApi( + @DownloadCDNHttpClient client: OkHttpClient, + @DownloadCDNServerUrl url: String, + gsonConverterFactory: GsonConverterFactory + ): DiagnosisKeyApiV1 = Retrofit.Builder() + .client(client) + .baseUrl(url) + .addConverterFactory(gsonConverterFactory) + .build() + .create(DiagnosisKeyApiV1::class.java) + + @Singleton + @Provides + fun legacyKeyCacheDao(context: Context): KeyCacheLegacyDao { + return AppDatabase.getInstance(context).dateDao() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/CountryData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/CountryData.kt new file mode 100644 index 0000000000000000000000000000000000000000..6f58466cae1dd86d5200f342fb2793e6b31d7c4b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/CountryData.kt @@ -0,0 +1,88 @@ +package de.rki.coronawarnapp.diagnosiskeys.download + +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo +import org.joda.time.LocalDate +import org.joda.time.LocalTime + +sealed class CountryData { + + abstract val country: LocationCode + + abstract val approximateSizeInBytes: Long +} + +internal data class CountryDays( + override val country: LocationCode, + val dayData: Collection<LocalDate> +) : CountryData() { + + override val approximateSizeInBytes: Long by lazy { + dayData.size * APPROX_DAY_SIZE + } + + /** + * Return a filtered list that contains all dates which are part of this wrapper, but not in the parameter. + */ + fun getMissingDays(cachedKeys: List<CachedKeyInfo>): Collection<LocalDate>? { + val cachedCountryDates = cachedKeys + .filter { it.location == country } + .map { it.day } + + return dayData.filter { date -> + !cachedCountryDates.contains(date) + } + } + + /** + * Create a new country object that only contains those elements, + * that are part of this wrapper, but not in the cache. + */ + fun toMissingDays(cachedKeys: List<CachedKeyInfo>): CountryDays? { + val missingDays = this.getMissingDays(cachedKeys) + if (missingDays == null || missingDays.isEmpty()) return null + + return CountryDays(this.country, missingDays) + } + + companion object { + // ~512KB + private const val APPROX_DAY_SIZE = 512 * 1024L + } +} + +internal data class CountryHours( + override val country: LocationCode, + val hourData: Map<LocalDate, List<LocalTime>> +) : CountryData() { + + override val approximateSizeInBytes: Long by lazy { + hourData.values.fold(0L) { acc, hoursForDay -> + acc + hoursForDay.size * APPROX_HOUR_SIZE + } + } + + fun getMissingHours(cachedKeys: List<CachedKeyInfo>): Map<LocalDate, List<LocalTime>>? { + val cachedHours = cachedKeys + .filter { it.location == country } + + return hourData.mapNotNull { (day, dayHours) -> + val missingHours = dayHours.filter { hour -> + cachedHours.none { it.day == day && it.hour == hour } + } + if (missingHours.isEmpty()) null else day to missingHours + }.toMap() + } + + fun toMissingHours(cachedKeys: List<CachedKeyInfo>): CountryHours? { + val missingHours = this.getMissingHours(cachedKeys) + if (missingHours == null || missingHours.isEmpty()) return null + + return CountryHours(this.country, missingHours) + } + + companion object { + // ~22KB + private const val APPROX_HOUR_SIZE = 22 * 1024L + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloader.kt new file mode 100644 index 0000000000000000000000000000000000000000..9b8830415e665a016293cb2ca33afb28f726e609 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloader.kt @@ -0,0 +1,347 @@ +package de.rki.coronawarnapp.diagnosiskeys.download + +import dagger.Reusable +import de.rki.coronawarnapp.diagnosiskeys.server.DiagnosisKeyServer +import de.rki.coronawarnapp.diagnosiskeys.server.DownloadInfo +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo +import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.diagnosiskeys.storage.legacy.LegacyKeyCacheMigration +import de.rki.coronawarnapp.risk.TimeVariables +import de.rki.coronawarnapp.storage.AppSettings +import de.rki.coronawarnapp.storage.DeviceStorage +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.withContext +import org.joda.time.LocalTime +import timber.log.Timber +import java.io.File +import javax.inject.Inject + +/** + * Downloads new or missing key files from the CDN + */ +@Reusable +class KeyFileDownloader @Inject constructor( + private val deviceStorage: DeviceStorage, + private val keyServer: DiagnosisKeyServer, + private val keyCache: KeyCacheRepository, + private val legacyKeyCache: LegacyKeyCacheMigration, + private val settings: AppSettings +) { + + private suspend fun requireStorageSpace(data: List<CountryData>): DeviceStorage.CheckResult { + val requiredBytes = data.fold(0L) { acc, item -> + acc + item.approximateSizeInBytes + } + Timber.d("%dB are required for %s", requiredBytes, data) + return deviceStorage.requireSpacePrivateStorage(requiredBytes).also { + Timber.tag(TAG).d("Storage check result: %s", it) + } + } + + private suspend fun getCompletedKeyFiles(type: CachedKeyInfo.Type): List<CachedKeyInfo> { + return keyCache + .getEntriesForType(type) + .filter { (keyInfo, file) -> + val complete = keyInfo.isDownloadComplete + val exists = file.exists() + if (complete && !exists) { + Timber.tag(TAG).v("Incomplete download, will overwrite: %s", keyInfo) + } + // We overwrite not completed ones + complete && exists + } + .map { it.first } + } + + /** + * Fetches all necessary Files from the Cached KeyFile Entries out of the [KeyCacheRepository] and + * adds to that all open Files currently available from the Server. + * + * Assumptions made about the implementation: + * - the app initializes with an empty cache and draws in every available data set in the beginning + * - the difference can only work properly if the date from the device is synchronized through the net + * - the difference in timezone is taken into account by using UTC in the Conversion from the Date to Server format + * + * @return list of all files from both the cache and the diff query + */ + suspend fun asyncFetchKeyFiles(wantedCountries: List<LocationCode>): List<File> = + withContext(Dispatchers.IO) { + val availableCountries = keyServer.getCountryIndex() + val filteredCountries = availableCountries.filter { wantedCountries.contains(it) } + Timber.tag(TAG).v( + "Available=%s; Wanted=%s; Intersect=%s", + availableCountries, wantedCountries, filteredCountries + ) + + val availableKeys = + if (settings.isLast3HourModeEnabled) { + syncMissing3Hours(filteredCountries, DEBUG_HOUR_LIMIT) + keyCache.getEntriesForType(CachedKeyInfo.Type.COUNTRY_HOUR) + } else { + syncMissingDays(filteredCountries) + keyCache.getEntriesForType(CachedKeyInfo.Type.COUNTRY_DAY) + } + + return@withContext availableKeys + .filter { it.first.isDownloadComplete && it.second.exists() } + .mapNotNull { (keyInfo, path) -> + if (!path.exists()) { + Timber.tag(TAG).w("Missing keyfile for : %s", keyInfo) + null + } else { + Timber.tag(TAG).v("Providing available key: %s", keyInfo) + path + } + } + .also { Timber.tag(TAG).d("Returning %d available keyfiles", it.size) } + } + + private suspend fun determineMissingDays(availableCountries: List<LocationCode>): List<CountryDays> { + val availableDays = availableCountries.map { + val days = keyServer.getDayIndex(it) + CountryDays(it, days) + } + + val cachedDays = getCompletedKeyFiles(CachedKeyInfo.Type.COUNTRY_DAY) + + val staleDays = getStale(cachedDays, availableDays) + + if (staleDays.isNotEmpty()) { + Timber.tag(TAG).v("Deleting stale days: %s", staleDays) + keyCache.delete(staleDays) + } + + val nonStaleDays = cachedDays.minus(staleDays) + + // The missing days + return availableDays.mapNotNull { it.toMissingDays(nonStaleDays) } + } + + /** + * Fetches files given by serverDates by respecting countries + * @param availableCountries pair of dates per country code + */ + private suspend fun syncMissingDays( + availableCountries: List<LocationCode> + ) = withContext(Dispatchers.IO) { + val countriesWithMissingDays = determineMissingDays(availableCountries) + + requireStorageSpace(countriesWithMissingDays) + + Timber.tag(TAG).d("Downloading missing days: %s", countriesWithMissingDays) + val batchDownloadStart = System.currentTimeMillis() + val dayDownloads = countriesWithMissingDays + .flatMap { country -> + country.dayData.map { dayDate -> country to dayDate } + } + .map { (countryWrapper, dayDate) -> + async { + val (keyInfo, path) = keyCache.createCacheEntry( + location = countryWrapper.country, + dayIdentifier = dayDate, + hourIdentifier = null, + type = CachedKeyInfo.Type.COUNTRY_DAY + ) + + return@async downloadKeyFile(keyInfo, path) + } + } + + Timber.tag(TAG).d("Waiting for %d missing day downloads.", dayDownloads.size) + // execute the query plan + val downloadedDays = dayDownloads.awaitAll().filterNotNull() + + Timber.tag(TAG).d( + "Batch download (%d files) finished in %dms", + dayDownloads.size, + (System.currentTimeMillis() - batchDownloadStart) + ) + + downloadedDays.map { (keyInfo, path) -> + Timber.tag(TAG).v("Downloaded keyfile: %s to %s", keyInfo, path) + path + } + + return@withContext + } + + private suspend fun determineMissingHours( + availableCountries: List<LocationCode>, + itemLimit: Int + ): List<CountryHours> { + val availableHours = availableCountries.flatMap { location -> + var remainingItems = itemLimit + // Descending because we go backwards newest -> oldest + val indexWithToday = keyServer.getDayIndex(location).let { + val lastDayInIndex = it.maxOrNull() + Timber.tag(TAG).v("Last day in index: %s", lastDayInIndex) + if (lastDayInIndex != null) { + it.plus(lastDayInIndex.plusDays(1)) + } else { + it + } + } + Timber.tag(TAG).v("Day index with (fake) today entry: %s", indexWithToday) + + indexWithToday.sortedDescending().mapNotNull { day -> + // Limit reached, return null (filtered out) instead of new CountryHours object + if (remainingItems <= 0) return@mapNotNull null + + val hoursForDate = mutableListOf<LocalTime>() + for (hour in keyServer.getHourIndex(location, day).sortedDescending()) { + if (remainingItems <= 0) break + remainingItems-- + hoursForDate.add(hour) + } + + CountryHours(location, mapOf(day to hoursForDate)) + } + } + + val cachedHours = getCompletedKeyFiles(CachedKeyInfo.Type.COUNTRY_HOUR) + + val staleHours = getStale(cachedHours, availableHours) + + if (staleHours.isNotEmpty()) { + Timber.tag(TAG).v("Deleting stale hours: %s", staleHours) + keyCache.delete(staleHours) + } + + val nonStaleHours = cachedHours.minus(staleHours) + + // The missing hours + return availableHours.mapNotNull { it.toMissingHours(nonStaleHours) } + } + + // All cached files that are no longer on the server are considered stale + private fun getStale( + cachedKeys: List<CachedKeyInfo>, + availableData: List<CountryData> + ): List<CachedKeyInfo> = cachedKeys.filter { cachedKey -> + val availableCountry = availableData + .filter { it.country == cachedKey.location } + .singleOrNull { + when (cachedKey.type) { + CachedKeyInfo.Type.COUNTRY_DAY -> true + CachedKeyInfo.Type.COUNTRY_HOUR -> { + it as CountryHours + it.hourData.containsKey(cachedKey.day) + } + } + } + if (availableCountry == null) { + Timber.w("Unknown location %s, assuming stale hour.", cachedKey.location) + return@filter true // It's stale + } + + when (cachedKey.type) { + CachedKeyInfo.Type.COUNTRY_DAY -> { + availableCountry as CountryDays + availableCountry.dayData.none { date -> + cachedKey.day == date + } + } + CachedKeyInfo.Type.COUNTRY_HOUR -> { + availableCountry as CountryHours + val availableDay = availableCountry.hourData[cachedKey.day] + if (availableDay == null) { + Timber.d("Unknown day %s, assuming stale hour.", cachedKey.location) + return@filter true // It's stale + } + + availableDay.none { time -> + cachedKey.hour == time + } + } + } + } + + /** + * Fetches files given by serverDates by respecting countries + * @param availableCountries pair of dates per country code + * @param hourItemLimit how many hours to go back + */ + private suspend fun syncMissing3Hours( + availableCountries: List<LocationCode>, + hourItemLimit: Int + ) = withContext(Dispatchers.IO) { + Timber.tag(TAG).v( + "asyncHandleLast3HoursFilesFetch(availableCountries=%s, hourLimit=%d)", + availableCountries, hourItemLimit + ) + val missingHours = determineMissingHours(availableCountries, hourItemLimit) + Timber.tag(TAG).d("Downloading missing hours: %s", missingHours) + + requireStorageSpace(missingHours) + + val hourDownloads = missingHours.flatMap { country -> + country.hourData.flatMap { (day, missingHours) -> + missingHours.map { missingHour -> + async { + val (keyInfo, path) = keyCache.createCacheEntry( + location = country.country, + dayIdentifier = day, + hourIdentifier = missingHour, + type = CachedKeyInfo.Type.COUNTRY_HOUR + ) + + return@async downloadKeyFile(keyInfo, path) + } + } + } + } + + Timber.tag(TAG).d("Waiting for %d missing hour downloads.", hourDownloads.size) + val downloadedHours = hourDownloads.awaitAll().filterNotNull() + + downloadedHours.map { (keyInfo, path) -> + Timber.tag(TAG).d("Downloaded keyfile: %s to %s", keyInfo, path) + path + } + + return@withContext + } + + private suspend fun downloadKeyFile( + keyInfo: CachedKeyInfo, + saveTo: File + ): Pair<CachedKeyInfo, File>? = try { + val preconditionHook: suspend (DownloadInfo) -> Boolean = + { downloadInfo -> + val continueDownload = !legacyKeyCache.tryMigration( + downloadInfo.serverMD5, saveTo + ) + continueDownload // Continue download if no migration happened + } + + val dlInfo = keyServer.downloadKeyFile( + locationCode = keyInfo.location, + day = keyInfo.day, + hour = keyInfo.hour, + saveTo = saveTo, + precondition = preconditionHook + ) + + Timber.tag(TAG).v("Dowwnload finished: %s -> %s", keyInfo, saveTo) + + keyCache.markKeyComplete(keyInfo, dlInfo.serverMD5 ?: dlInfo.localMD5!!) + keyInfo to saveTo + } catch (e: Exception) { + Timber.tag(TAG).e(e, "Download failed: %s", keyInfo) + keyCache.delete(listOf(keyInfo)) + null + } + + companion object { + private val TAG: String? = KeyFileDownloader::class.simpleName + private const val DEBUG_HOUR_LIMIT = 3 + + // Daymode: ~512KB per day, ~14 days + // Hourmode: ~20KB per hour, 24 hours, also ~512KB + private val EXPECTED_STORAGE_PER_COUNTRY = + TimeVariables.getDefaultRetentionPeriodInDays() * 512 * 1024L + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyApiV1.kt new file mode 100644 index 0000000000000000000000000000000000000000..258321c44c01b54b1c139d2c56700bc94942f2ec --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyApiV1.kt @@ -0,0 +1,41 @@ +package de.rki.coronawarnapp.diagnosiskeys.server + +import okhttp3.ResponseBody +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Streaming + +interface DiagnosisKeyApiV1 { + // TODO Let retrofit format this to CountryCode + @GET("/version/v1/diagnosis-keys/country") + suspend fun getCountryIndex(): List<String> + + // TODO Let retrofit format this to LocalDate + @GET("/version/v1/diagnosis-keys/country/{country}/date") + suspend fun getDayIndex( + @Path("country") country: String + ): List<String> + + // TODO Let retrofit format this to LocalTime + @GET("/version/v1/diagnosis-keys/country/{country}/date/{day}/hour") + suspend fun getHourIndex( + @Path("country") country: String, + @Path("day") day: String + ): List<String> + + @Streaming + @GET("/version/v1/diagnosis-keys/country/{country}/date/{day}") + suspend fun downloadKeyFileForDay( + @Path("country") country: String, + @Path("day") day: String + ): Response<ResponseBody> + + @Streaming + @GET("/version/v1/diagnosis-keys/country/{country}/date/{day}/hour/{hour}") + suspend fun downloadKeyFileForHour( + @Path("country") country: String, + @Path("day") day: String, + @Path("hour") hour: String + ): Response<ResponseBody> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServer.kt new file mode 100644 index 0000000000000000000000000000000000000000..decf192f7e4e028a4e4845efcc6bd19ea0c09d31 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServer.kt @@ -0,0 +1,115 @@ +package de.rki.coronawarnapp.diagnosiskeys.server + +import dagger.Lazy +import de.rki.coronawarnapp.environment.download.DownloadCDNHomeCountry +import de.rki.coronawarnapp.util.HashExtensions.hashToMD5 +import de.rki.coronawarnapp.util.debug.measureTimeMillisWithResult +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.joda.time.format.DateTimeFormat +import retrofit2.HttpException +import timber.log.Timber +import java.io.File +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class DiagnosisKeyServer @Inject constructor( + private val diagnosisKeyAPI: Lazy<DiagnosisKeyApiV1>, + @DownloadCDNHomeCountry private val homeCountry: LocationCode +) { + + private val keyApi: DiagnosisKeyApiV1 + get() = diagnosisKeyAPI.get() + + suspend fun getCountryIndex(): List<LocationCode> = withContext(Dispatchers.IO) { + keyApi + .getCountryIndex() + .map { LocationCode(it) } + } + + suspend fun getDayIndex(location: LocationCode): List<LocalDate> = withContext(Dispatchers.IO) { + keyApi + .getDayIndex(location.identifier) + .map { dayString -> + // 2020-08-19 + LocalDate.parse(dayString, DAY_FORMATTER) + } + } + + suspend fun getHourIndex(location: LocationCode, day: LocalDate): List<LocalTime> = + withContext(Dispatchers.IO) { + keyApi + .getHourIndex(location.identifier, day.toString(DAY_FORMATTER)) + .map { hourString -> LocalTime.parse(hourString, HOUR_FORMATTER) } + } + + /** + * Retrieves Key Files from the Server + * Leave **[hour]** null to download a day package + */ + suspend fun downloadKeyFile( + locationCode: LocationCode, + day: LocalDate, + hour: LocalTime? = null, + saveTo: File, + precondition: suspend (DownloadInfo) -> Boolean = { true } + ): DownloadInfo = withContext(Dispatchers.IO) { + Timber.tag(TAG).v( + "Starting download: country=%s, day=%s, hour=%s -> %s.", + locationCode, day, hour, saveTo + ) + + if (saveTo.exists()) { + Timber.tag(TAG).w("File existed, overwriting: %s", saveTo) + if (saveTo.delete()) { + Timber.tag(TAG).e("%s exists, but can't be deleted.", saveTo) + } + } + + val response = if (hour != null) { + keyApi.downloadKeyFileForHour( + locationCode.identifier, + day.toString(DAY_FORMATTER), + hour.toString(HOUR_FORMATTER) + ) + } else { + keyApi.downloadKeyFileForDay( + locationCode.identifier, + day.toString(DAY_FORMATTER) + ) + } + + var downloadInfo = DownloadInfo(response.headers()) + + if (!precondition(downloadInfo)) { + Timber.tag(TAG).d("Precondition is not met, aborting.") + return@withContext downloadInfo + } + if (response.isSuccessful) { + saveTo.outputStream().use { target -> + response.body()!!.byteStream().use { source -> + source.copyTo(target, DEFAULT_BUFFER_SIZE) + } + } + + val (localMD5, duration) = measureTimeMillisWithResult { saveTo.hashToMD5() } + Timber.v("Hashed to MD5 in %dms: %s", duration, saveTo) + + downloadInfo = downloadInfo.copy(localMD5 = localMD5) + Timber.tag(TAG).v("Key file download successful: %s", downloadInfo) + + return@withContext downloadInfo + } else { + throw HttpException(response) + } + } + + companion object { + private val TAG = DiagnosisKeyServer::class.java.simpleName + private val DAY_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd") + private val HOUR_FORMATTER = DateTimeFormat.forPattern("H") + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DownloadInfo.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DownloadInfo.kt new file mode 100644 index 0000000000000000000000000000000000000000..fb1dcbeebc0c6e027f36f3f2189a820e75ca2943 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/DownloadInfo.kt @@ -0,0 +1,25 @@ +package de.rki.coronawarnapp.diagnosiskeys.server + +import okhttp3.Headers + +data class DownloadInfo( + val headers: Headers, + val localMD5: String? = null +) { + + val serverMD5 by lazy { headers.getPayloadChecksumMD5() } + + private fun Headers.getPayloadChecksumMD5(): String? { + + val fileMD5 = values("ETag").singleOrNull() +// TODO EXPOSUREBACK-178 +// var fileMD5 = headers.values("x-amz-meta-cwa-hash-md5").singleOrNull() +// if (fileMD5 == null) { +// headers.values("x-amz-meta-cwa-hash").singleOrNull() +// } +// if (fileMD5 == null) { // Fallback +// fileMD5 = headers.values("ETag").singleOrNull() +// } + return fileMD5?.removePrefix("\"")?.removeSuffix("\"") + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/LocationCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/LocationCode.kt new file mode 100644 index 0000000000000000000000000000000000000000..8201571a46b14ca53b35d2146dae940a663014e0 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/server/LocationCode.kt @@ -0,0 +1,10 @@ +package de.rki.coronawarnapp.diagnosiskeys.server + +import java.util.Locale + +data class LocationCode( + private val rawIdentifier: String +) { + @Transient + val identifier: String = rawIdentifier.toUpperCase(Locale.ROOT) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyInfo.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyInfo.kt new file mode 100644 index 0000000000000000000000000000000000000000..b77f11c7be3f1f58959c1c7b19ba50414ea19724 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyInfo.kt @@ -0,0 +1,84 @@ +package de.rki.coronawarnapp.diagnosiskeys.storage + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.TypeConverter +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.util.HashExtensions.toSHA1 +import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.LocalTime + +@Entity(tableName = "keyfiles") +data class CachedKeyInfo( + @PrimaryKey @ColumnInfo(name = "id") val id: String, + @ColumnInfo(name = "type") val type: Type, + @ColumnInfo(name = "location") val location: LocationCode, // i.e. "DE" + @ColumnInfo(name = "day") val day: LocalDate, // i.e. 2020-08-23 + @ColumnInfo(name = "hour") val hour: LocalTime?, // i.e. 23 + @ColumnInfo(name = "createdAt") val createdAt: Instant, + @ColumnInfo(name = "checksumMD5") val checksumMD5: String?, + @ColumnInfo(name = "completed") val isDownloadComplete: Boolean +) { + + constructor( + type: Type, + location: LocationCode, + day: LocalDate, + hour: LocalTime?, + createdAt: Instant + ) : this( + id = calcluateId(location, day, hour, type), + location = location, + day = day, + hour = hour, + type = type, + createdAt = createdAt, + checksumMD5 = null, + isDownloadComplete = false + ) + + @Transient + val fileName: String = "$id.zip" + + fun toDownloadUpdate(checksumMD5: String?): DownloadUpdate = DownloadUpdate( + id = id, + checksumMD5 = checksumMD5, + isDownloadComplete = checksumMD5 != null + ) + + companion object { + fun calcluateId( + location: LocationCode, + day: LocalDate, + hour: LocalTime?, + type: Type + ): String { + var rawId = "${location.identifier}.${type.typeValue}.$day" + hour?.let { rawId += ".$hour" } + return rawId.toSHA1() + } + } + + enum class Type constructor(internal val typeValue: String) { + COUNTRY_DAY("country_day"), + COUNTRY_HOUR("country_hour"); + + class Converter { + @TypeConverter + fun toType(value: String?): Type? = + value?.let { values().single { it.typeValue == value } } + + @TypeConverter + fun fromType(type: Type?): String? = type?.typeValue + } + } + + @Entity + data class DownloadUpdate( + @PrimaryKey @ColumnInfo(name = "id") val id: String, + @ColumnInfo(name = "checksumMD5") val checksumMD5: String?, + @ColumnInfo(name = "completed") val isDownloadComplete: Boolean + ) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheDatabase.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheDatabase.kt new file mode 100644 index 0000000000000000000000000000000000000000..e4be6ba47007ae858c1065509d49f6469bd71e11 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheDatabase.kt @@ -0,0 +1,62 @@ +package de.rki.coronawarnapp.diagnosiskeys.storage + +import android.content.Context +import androidx.room.Dao +import androidx.room.Database +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import androidx.room.Update +import de.rki.coronawarnapp.util.database.CommonConverters +import javax.inject.Inject + +@Database( + entities = [CachedKeyInfo::class], + version = 1, + exportSchema = true +) +@TypeConverters(CommonConverters::class, CachedKeyInfo.Type.Converter::class) +abstract class KeyCacheDatabase : RoomDatabase() { + + abstract fun cachedKeyFiles(): CachedKeyFileDao + + @Dao + interface CachedKeyFileDao { + @Query("SELECT * FROM keyfiles") + suspend fun getAllEntries(): List<CachedKeyInfo> + + @Query("SELECT * FROM keyfiles WHERE type = :type") + suspend fun getEntriesForType(type: String): List<CachedKeyInfo> + + @Query("DELETE FROM keyfiles") + suspend fun clear() + + @Insert(onConflict = OnConflictStrategy.ABORT) + suspend fun insertEntry(cachedKeyInfo: CachedKeyInfo) + + @Delete + suspend fun deleteEntry(cachedKeyInfo: CachedKeyInfo) + + @Update(entity = CachedKeyInfo::class) + suspend fun updateDownloadState(update: CachedKeyInfo.DownloadUpdate) + } + + class Factory @Inject constructor(private val context: Context) { + /** + * The fallback behavior is to reset the app as we only store exposure summaries + * and cached references that are non-critical to app operation. + */ + fun create(): KeyCacheDatabase = Room + .databaseBuilder(context, KeyCacheDatabase::class.java, DATABASE_NAME) + .fallbackToDestructiveMigrationFrom() + .build() + } + + companion object { + private const val DATABASE_NAME = "keycache.db" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..4336c7ac87ff9de1ee0ef0052e0150a673a83f69 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheRepository.kt @@ -0,0 +1,153 @@ +/****************************************************************************** + * Corona-Warn-App * + * * + * SAP SE and all other contributors / * + * copyright owners license this file to you under the Apache * + * License, Version 2.0 (the "License"); you may not use this * + * file except in compliance with the License. * + * You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ******************************************************************************/ + +package de.rki.coronawarnapp.diagnosiskeys.storage + +import android.content.Context +import android.database.sqlite.SQLiteConstraintException +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.util.TimeStamper +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import timber.log.Timber +import java.io.File +import java.io.IOException +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class KeyCacheRepository @Inject constructor( + private val context: Context, + private val databaseFactory: KeyCacheDatabase.Factory, + private val timeStamper: TimeStamper +) { + + private val storageDir by lazy { + File(context.cacheDir, "diagnosis_keys").apply { + if (!exists()) { + if (mkdirs()) { + Timber.d("KeyCache directory created: %s", this) + } else { + throw IOException("KeyCache directory creation failed: $this") + } + } + } + } + + private val database by lazy { databaseFactory.create() } + + private var isInitDone = false + private val initMutex = Mutex() + + private suspend fun getDao(): KeyCacheDatabase.CachedKeyFileDao { + val dao = database.cachedKeyFiles() + + if (!isInitDone) { + initMutex.withLock { + if (isInitDone) return@withLock + isInitDone = true + + doHouseKeeping() + } + } + + return dao + } + + private suspend fun doHouseKeeping() { + val dirtyInfos = getDao().getAllEntries().filter { + it.isDownloadComplete && !getPathForKey(it).exists() + } + Timber.v("HouseKeeping, deleting: %s", dirtyInfos) + delete(dirtyInfos) + } + + fun getPathForKey(cachedKeyInfo: CachedKeyInfo): File { + return File(storageDir, cachedKeyInfo.fileName) + } + + suspend fun getAllCachedKeys(): List<Pair<CachedKeyInfo, File>> { + return getDao().getAllEntries().map { it to getPathForKey(it) } + } + + suspend fun getEntriesForType(type: CachedKeyInfo.Type): List<Pair<CachedKeyInfo, File>> { + return getDao().getEntriesForType(type.typeValue).map { it to getPathForKey(it) } + } + + suspend fun createCacheEntry( + type: CachedKeyInfo.Type, + location: LocationCode, + dayIdentifier: LocalDate, + hourIdentifier: LocalTime? + ): Pair<CachedKeyInfo, File> { + val newKeyFile = CachedKeyInfo( + type = type, + location = location, + day = dayIdentifier, + hour = hourIdentifier, + createdAt = timeStamper.nowUTC + ) + + val targetFile = getPathForKey(newKeyFile) + + try { + getDao().insertEntry(newKeyFile) + if (targetFile.exists()) { + Timber.w("Target path despite no collision exists, deleting: %s", targetFile) + } + } catch (e: SQLiteConstraintException) { + Timber.e(e, "Insertion collision? Overwriting for %s", newKeyFile) + delete(listOf(newKeyFile)) + + Timber.d(e, "Retrying insertion for %s", newKeyFile) + getDao().insertEntry(newKeyFile) + } + + // This can't be null unless our cache dir is root `/` + val targetParent = targetFile.parentFile!! + if (!targetParent.exists()) { + Timber.w("Parent folder doesn't exist, cache cleared? %s", targetParent) + targetParent.mkdirs() + } + + return newKeyFile to targetFile + } + + suspend fun markKeyComplete(cachedKeyInfo: CachedKeyInfo, checksumMD5: String) { + val update = cachedKeyInfo.toDownloadUpdate(checksumMD5) + getDao().updateDownloadState(update) + } + + suspend fun delete(keyInfos: Collection<CachedKeyInfo>) { + Timber.d("delete(keyFiles=%s)", keyInfos) + keyInfos.forEach { key -> + getDao().deleteEntry(key) + Timber.v("Deleted %s", key) + val path = getPathForKey(key) + if (path.delete()) Timber.v("Deleted cache key file at %s", path) + } + } + + suspend fun clear() { + Timber.i("clear()") + delete(getDao().getAllEntries()) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/Converters.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheLegacyDao.kt similarity index 75% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/Converters.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheLegacyDao.kt index 7b5c36d39378e073345839cee683ab40bd7a7d77..3418ebd0cbeb0c4b81fd43ed1be1cd1c97595fa3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/Converters.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheLegacyDao.kt @@ -17,23 +17,13 @@ * under the License. * ******************************************************************************/ -package de.rki.coronawarnapp.util +package de.rki.coronawarnapp.diagnosiskeys.storage.legacy -import androidx.room.TypeConverter -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken +import androidx.room.Dao +import androidx.room.Query -class Converters { - private val gson = Gson() - - @TypeConverter - fun fromString(value: String?): List<Int> { - val listType = object : TypeToken<List<Int?>?>() {}.type - return gson.fromJson(value, listType) - } - - @TypeConverter - fun fromArrayList(list: List<Int?>?): String { - return gson.toJson(list) - } +@Dao +interface KeyCacheLegacyDao { + @Query("DELETE FROM date") + suspend fun clear() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheEntity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheLegacyEntity.kt similarity index 95% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheEntity.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheLegacyEntity.kt index 8bd2ac55df388512c458b045f3f44c1194524ed6..0a8593c004eaa9d9475f57cef05aed5f11745346 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheEntity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheLegacyEntity.kt @@ -17,7 +17,7 @@ * under the License. * ******************************************************************************/ -package de.rki.coronawarnapp.storage.keycache +package de.rki.coronawarnapp.diagnosiskeys.storage.legacy import androidx.room.Entity import androidx.room.Index @@ -27,7 +27,7 @@ import androidx.room.PrimaryKey tableName = "date", indices = [Index("id")] ) -class KeyCacheEntity { +class KeyCacheLegacyEntity { @PrimaryKey var id: String = "" diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/LegacyKeyCacheMigration.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/LegacyKeyCacheMigration.kt new file mode 100644 index 0000000000000000000000000000000000000000..ca2cf95867b371a37bf8875325410289009ed0bd --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/LegacyKeyCacheMigration.kt @@ -0,0 +1,103 @@ +package de.rki.coronawarnapp.diagnosiskeys.storage.legacy + +import android.content.Context +import dagger.Lazy +import de.rki.coronawarnapp.risk.TimeVariables +import de.rki.coronawarnapp.util.HashExtensions.hashToMD5 +import de.rki.coronawarnapp.util.TimeStamper +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import org.joda.time.Duration +import org.joda.time.Instant +import timber.log.Timber +import java.io.File +import javax.inject.Inject + +class LegacyKeyCacheMigration @Inject constructor( + private val context: Context, + private val legacyDao: Lazy<KeyCacheLegacyDao>, + private val timeStamper: TimeStamper +) { + + private val cacheDir by lazy { + File(context.cacheDir, "key-export") + } + + private val workMutex = Mutex() + private var isInit = false + private val legacyCacheMap = mutableMapOf<String, File>() + + private suspend fun tryInit() { + if (isInit) return + isInit = true + + if (!cacheDir.exists()) { + Timber.tag(TAG).v("Legacy cache dir doesn't exist, we are done.") + return + } + + try { + legacyDao.get().clear() + } catch (e: Exception) { + // Not good, but not a problem, we don't need the actual entities for migration. + Timber.tag(TAG).w(e, "Failed to clear legacy key cache from db.") + } + + try { + cacheDir.listFiles()?.forEach { file -> + val isExpired = Duration( + Instant.ofEpochMilli(file.lastModified()), + timeStamper.nowUTC + ).standardDays > TimeVariables.getDefaultRetentionPeriodInDays() + + if (isExpired) { + Timber.tag(TAG).d("Deleting expired file: %s", file) + file.delete() + } else { + val md5 = file.hashToMD5() + Timber.tag(TAG).v("MD5 %s for %s", md5, file) + legacyCacheMap[md5] = file + } + } + } catch (e: Exception) { + Timber.tag(TAG).e(e, "Reading legacy cached failed. Clearing.") + cacheDir.deleteRecursively() + } + + if (cacheDir.exists() && cacheDir.listFiles()?.isNullOrEmpty() == true) { + Timber.tag(TAG).v("Legacy cache dir is empty, deleting.") + cacheDir.delete() + } + } + + suspend fun tryMigration(fileMD5: String?, targetPath: File): Boolean = workMutex.withLock { + if (fileMD5 == null) return false + tryInit() + + val legacyFile = legacyCacheMap[fileMD5] ?: return false + Timber.tag(TAG).i("Migrating legacy file for %s to %s", fileMD5, targetPath) + + return try { + legacyFile.inputStream().use { from -> + targetPath.outputStream().use { to -> + from.copyTo(to, DEFAULT_BUFFER_SIZE) + } + } + true + } catch (e: Exception) { + Timber.tag(TAG).e(e, "Failed to migrate %s", legacyFile) + false + } finally { + try { + val removedFile = legacyCacheMap.remove(fileMD5) + if (removedFile?.delete() == true) Timber.tag(TAG).d("Deleted %s", removedFile) + } catch (e: Exception) { + Timber.tag(TAG).e(e, "Failed to delete %s", legacyFile) + } + } + } + + companion object { + private val TAG = this::class.java.simpleName + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/BaseEnvironmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/BaseEnvironmentModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..77576c6c01ae1399b455a8b72c900ff93d11032f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/BaseEnvironmentModule.kt @@ -0,0 +1,10 @@ +package de.rki.coronawarnapp.environment + +open class BaseEnvironmentModule { + fun requireValidUrl(url: String): String { + if (!url.startsWith("https://")) { + throw IllegalArgumentException("HTTPS url required: $url") + } + return url + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/BuildConfigWrap.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/BuildConfigWrap.kt new file mode 100644 index 0000000000000000000000000000000000000000..8fc88e77f9cb9b5ce3f49404a59b1d16a5386d04 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/BuildConfigWrap.kt @@ -0,0 +1,11 @@ +package de.rki.coronawarnapp.environment + +import de.rki.coronawarnapp.BuildConfig + +// Can't be const because that prevents them from being mocked in tests +@Suppress("MayBeConstant") +object BuildConfigWrap { + + val ENVIRONMENT_JSONDATA = BuildConfig.ENVIRONMENT_JSONDATA + val ENVIRONMENT_TYPE_DEFAULT = BuildConfig.ENVIRONMENT_TYPE_DEFAULT +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..46b56b1e1072217c8844a63cce40b42ab27c654e --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt @@ -0,0 +1,15 @@ +package de.rki.coronawarnapp.environment + +import dagger.Module +import de.rki.coronawarnapp.environment.download.DownloadCDNModule +import de.rki.coronawarnapp.environment.submission.SubmissionCDNModule +import de.rki.coronawarnapp.environment.verification.VerificationCDNModule + +@Module( + includes = [ + DownloadCDNModule::class, + SubmissionCDNModule::class, + VerificationCDNModule::class + ] +) +class EnvironmentModule diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt new file mode 100644 index 0000000000000000000000000000000000000000..ea54dfb6d1bdb8cafc9683885ac6eb6e6001fd10 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt @@ -0,0 +1,111 @@ +package de.rki.coronawarnapp.environment + +import android.content.Context +import androidx.core.content.edit +import com.google.gson.GsonBuilder +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.DOWNLOAD +import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.SUBMISSION +import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.USE_EUR_KEY_PKGS +import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.VERIFICATION +import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.VERIFICATION_KEYS +import de.rki.coronawarnapp.environment.EnvironmentSetup.Type.Companion.toEnvironmentType +import de.rki.coronawarnapp.util.CWADebug +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class EnvironmentSetup @Inject constructor( + private val context: Context +) { + + enum class EnvKey(val rawKey: String) { + USE_EUR_KEY_PKGS("USE_EUR_KEY_PKGS"), + SUBMISSION("SUBMISSION_CDN_URL"), + VERIFICATION("VERIFICATION_CDN_URL"), + DOWNLOAD("DOWNLOAD_CDN_URL"), + VERIFICATION_KEYS("PUB_KEYS_SIGNATURE_VERIFICATION") + } + + enum class Type(val rawKey: String) { + PRODUCTION("PROD"), + INT("INT"), + INT_FED("INT-FED"), + DEV("DEV"), + WRU("WRU"), + WRU_XA("WRU-XA"), // (aka ACME) + WRU_XD("WRU-XD"); // (aka Germany) + + companion object { + internal fun String.toEnvironmentType(): Type = values().single { + it.rawKey == this + } + } + } + + private val prefs by lazy { + context.getSharedPreferences("environment_setup", Context.MODE_PRIVATE) + } + + private val environmentJson: JsonObject by lazy { + val gson = GsonBuilder().create() + gson.fromJson(BuildConfigWrap.ENVIRONMENT_JSONDATA, JsonObject::class.java).also { + Timber.d("Parsed test environment: %s", it) + } + } + + val defaultEnvironment: Type + get() = BuildConfigWrap.ENVIRONMENT_TYPE_DEFAULT.toEnvironmentType() + + var currentEnvironment: Type + get() { + return prefs + .getString(PKEY_CURRENT_ENVINROMENT, null) + ?.toEnvironmentType() ?: defaultEnvironment + } + set(value) { + if (CWADebug.buildFlavor == CWADebug.BuildFlavor.DEVICE_FOR_TESTERS) { + prefs.edit { + putString(PKEY_CURRENT_ENVINROMENT, value.rawKey) + } + } else { + Timber.w("Tried to change currentEnvironment in PRODUCTION mode.") + } + } + + private fun getEnvironmentValue(variableKey: EnvKey): JsonPrimitive = run { + try { + val targetEnvKey = if (environmentJson.has(currentEnvironment.rawKey)) { + currentEnvironment.rawKey + } else { + Timber.e("Tried to use unavailable environment: $variableKey on $currentEnvironment") + Type.PRODUCTION.rawKey + } + environmentJson + .getAsJsonObject(targetEnvKey) + .getAsJsonPrimitive(variableKey.rawKey) + } catch (e: Exception) { + Timber.e(e, "Failed to retrieve endpoint URL for $currentEnvironment:$variableKey") + throw IllegalStateException("Failed to setup test environment", e) + } + }.also { Timber.v("getEndpointUrl(endpoint=%s): %s", variableKey, it) } + + val submissionCdnUrl: String + get() = getEnvironmentValue(SUBMISSION).asString + val verificationCdnUrl: String + get() = getEnvironmentValue(VERIFICATION).asString + val downloadCdnUrl: String + get() = getEnvironmentValue(DOWNLOAD).asString + + val appConfigVerificationKey: String + get() = getEnvironmentValue(VERIFICATION_KEYS).asString + + val useEuropeKeyPackageFiles: Boolean + get() = getEnvironmentValue(USE_EUR_KEY_PKGS).asBoolean + + companion object { + private const val PKEY_CURRENT_ENVINROMENT = "environment.current" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNHomeCountry.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNHomeCountry.kt new file mode 100644 index 0000000000000000000000000000000000000000..9ee43e7cfe5b27187091a41b246f8dbcd41f5a58 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNHomeCountry.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.environment.download + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class DownloadCDNHomeCountry diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNHttpClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNHttpClient.kt new file mode 100644 index 0000000000000000000000000000000000000000..fd70111781f925eae773e09b888d34f9a00cb31a --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNHttpClient.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.environment.download + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class DownloadCDNHttpClient diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..33e73063f351b507720111a201f25864438dbafd --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNModule.kt @@ -0,0 +1,50 @@ +package de.rki.coronawarnapp.environment.download + +import dagger.Module +import dagger.Provides +import dagger.Reusable +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.environment.BaseEnvironmentModule +import de.rki.coronawarnapp.environment.EnvironmentSetup +import de.rki.coronawarnapp.http.HttpClientDefault +import okhttp3.ConnectionSpec +import okhttp3.OkHttpClient +import okhttp3.TlsVersion +import javax.inject.Singleton + +@Module +class DownloadCDNModule : BaseEnvironmentModule() { + + @Reusable + @DownloadCDNHttpClient + @Provides + fun cdnHttpClient(@HttpClientDefault defaultHttpClient: OkHttpClient): OkHttpClient = + defaultHttpClient.newBuilder().connectionSpecs(DOWNLOAD_CDN_CONNECTION_SPECS).build() + + @Singleton + @DownloadCDNServerUrl + @Provides + fun provideDownloadServerUrl(environment: EnvironmentSetup): String { + val url = environment.downloadCdnUrl + return requireValidUrl(url) + } + + @Singleton + @DownloadCDNHomeCountry + @Provides + fun provideDiagnosisHomeCountry(): LocationCode = LocationCode("DE") + + companion object { + private val DOWNLOAD_CDN_CONNECTION_SPECS = ConnectionSpec + .Builder(ConnectionSpec.COMPATIBLE_TLS) + .tlsVersions( + TlsVersion.TLS_1_0, + TlsVersion.TLS_1_1, + TlsVersion.TLS_1_2, + TlsVersion.TLS_1_3 + ) + .allEnabledCipherSuites() + .build() + .let { listOf(it) } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNServerUrl.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNServerUrl.kt new file mode 100644 index 0000000000000000000000000000000000000000..03af297dbc986dd04e1ab9a5bc6f2ca57461dd54 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/download/DownloadCDNServerUrl.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.environment.download + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class DownloadCDNServerUrl diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..0c351eb814d49070e64ddb932ec2cfe81960149d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNModule.kt @@ -0,0 +1,19 @@ +package de.rki.coronawarnapp.environment.submission + +import dagger.Module +import dagger.Provides +import de.rki.coronawarnapp.environment.BaseEnvironmentModule +import de.rki.coronawarnapp.environment.EnvironmentSetup +import javax.inject.Singleton + +@Module +class SubmissionCDNModule : BaseEnvironmentModule() { + + @Singleton + @SubmissionCDNServerUrl + @Provides + fun provideSubmissionUrl(environment: EnvironmentSetup): String { + val url = environment.submissionCdnUrl + return requireValidUrl(url) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNServerUrl.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNServerUrl.kt new file mode 100644 index 0000000000000000000000000000000000000000..96fe0060d8452122defe3ff38dc97670773bf2f6 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNServerUrl.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.environment.submission + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class SubmissionCDNServerUrl diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/verification/VerificationCDNModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/verification/VerificationCDNModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..dd278f67e92d4c5325a0ca946ab9587b37fb5ee4 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/verification/VerificationCDNModule.kt @@ -0,0 +1,19 @@ +package de.rki.coronawarnapp.environment.verification + +import dagger.Module +import dagger.Provides +import de.rki.coronawarnapp.environment.BaseEnvironmentModule +import de.rki.coronawarnapp.environment.EnvironmentSetup +import javax.inject.Singleton + +@Module +class VerificationCDNModule : BaseEnvironmentModule() { + + @Singleton + @VerificationCDNServerUrl + @Provides + fun provideVerificationUrl(environment: EnvironmentSetup): String { + val url = environment.verificationCdnUrl + return requireValidUrl(url) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/verification/VerificationCDNServerUrl.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/verification/VerificationCDNServerUrl.kt new file mode 100644 index 0000000000000000000000000000000000000000..dd1f927917402d2146b7b46fe0d4cc6698bdc5d8 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/verification/VerificationCDNServerUrl.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.environment.verification + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class VerificationCDNServerUrl diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/http/CwaWebException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/http/CwaWebException.kt index 4925705a4bb88a784f162ff47f1b165072208820..4fa8b6effbc3f77ca7a780ac791cd07eb93f8ffc 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/http/CwaWebException.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/http/CwaWebException.kt @@ -3,29 +3,29 @@ package de.rki.coronawarnapp.exception.http import de.rki.coronawarnapp.exception.reporting.ErrorCodes import de.rki.coronawarnapp.exception.reporting.ReportedIOException -open class CwaWebException(statusCode: Int) : ReportedIOException( +open class CwaWebException(val statusCode: Int) : ReportedIOException( ErrorCodes.CWA_WEB_REQUEST_PROBLEM.code, "error during web request, http status $statusCode" ) -open class CwaServerError(val statusCode: Int) : CwaWebException(statusCode) { +open class CwaServerError(statusCode: Int) : CwaWebException(statusCode) { init { if (statusCode !in 500..599) throw IllegalArgumentException("a server error has to have code 5xx") } } -open class CwaClientError(val statusCode: Int) : CwaWebException(statusCode) { +open class CwaClientError(statusCode: Int) : CwaWebException(statusCode) { init { if (statusCode !in 400..499) throw IllegalArgumentException("a client error has to have code 4xx") } } -open class CwaSuccessResponseWithCodeMismatchNotSupportedError(val statusCode: Int) : +open class CwaSuccessResponseWithCodeMismatchNotSupportedError(statusCode: Int) : CwaWebException(statusCode) -open class CwaInformationalNotSupportedError(val statusCode: Int) : CwaWebException(statusCode) -open class CwaRedirectNotSupportedError(val statusCode: Int) : CwaWebException(statusCode) +open class CwaInformationalNotSupportedError(statusCode: Int) : CwaWebException(statusCode) +open class CwaRedirectNotSupportedError(statusCode: Int) : CwaWebException(statusCode) class CwaUnknownHostException : CwaWebException(901) class BadRequestException : CwaClientError(400) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorReportReceiver.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorReportReceiver.kt index 0a3b9d44532039c17c95455fa644159fecb7d854..8aafc6246c568100c2aa7b5eaaeb8942323d3c8e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorReportReceiver.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ErrorReportReceiver.kt @@ -49,7 +49,7 @@ class ErrorReportReceiver(private val activity: Activity) : BroadcastReceiver() ErrorCodes.REPORTED_EXCEPTION_UNKNOWN_PROBLEM.code ) - message += " ($apiStatusCode)" + message += "#$apiStatusCode" } val errorTitle = context.resources.getString(R.string.errors_generic_details_headline) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt index d18d4e2ce9437dea46fd596f21e6a754e25bd863..a29ddabf3f4b86efdebbae8310fae5952be4600e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/exception/reporting/ExceptionReporter.kt @@ -9,6 +9,7 @@ import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.ReportingConstants.STATUS_CODE_GOOGLE_API_FAIL import de.rki.coronawarnapp.exception.reporting.ReportingConstants.STATUS_CODE_GOOGLE_UPDATE_NEEDED import de.rki.coronawarnapp.exception.reporting.ReportingConstants.STATUS_CODE_REACHED_REQUEST_LIMIT +import de.rki.coronawarnapp.util.tryFormattedError import java.io.PrintWriter import java.io.StringWriter @@ -20,11 +21,13 @@ fun Throwable.report( prefix: String?, suffix: String? ) { + val context = CoronaWarnApplication.getAppContext() + val intent = Intent(ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL) intent.putExtra(ReportingConstants.ERROR_REPORT_CATEGORY_EXTRA, exceptionCategory.name) intent.putExtra(ReportingConstants.ERROR_REPORT_PREFIX_EXTRA, prefix) intent.putExtra(ReportingConstants.ERROR_REPORT_SUFFIX_EXTRA, suffix) - intent.putExtra(ReportingConstants.ERROR_REPORT_MESSAGE_EXTRA, this.message) + intent.putExtra(ReportingConstants.ERROR_REPORT_MESSAGE_EXTRA, this.tryFormattedError(context)) if (this is ReportedExceptionInterface) { intent.putExtra(ReportingConstants.ERROR_REPORT_CODE_EXTRA, this.code) @@ -62,7 +65,7 @@ fun Throwable.report( } intent.putExtra(ReportingConstants.ERROR_REPORT_STACK_EXTRA, stackExtra) - LocalBroadcastManager.getInstance(CoronaWarnApplication.getAppContext()).sendBroadcast(intent) + LocalBroadcastManager.getInstance(context).sendBroadcast(intent) } fun reportGeneric( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpClientDefault.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpClientDefault.kt new file mode 100644 index 0000000000000000000000000000000000000000..dca6b3f7826139d902b63c41a4fe71a7492502dc --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpClientDefault.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.http + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class HttpClientDefault diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt index dec2043075ebf8241f0f91301c1905b0bc1ab6b2..bc347abb919fbbeff9ada2c2d768b3ef679334ff 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpErrorParser.kt @@ -27,30 +27,31 @@ import de.rki.coronawarnapp.exception.http.UnsupportedMediaTypeException import okhttp3.Interceptor import okhttp3.Response import java.net.UnknownHostException +import javax.net.ssl.HttpsURLConnection class HttpErrorParser : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { try { val response = chain.proceed(chain.request()) return when (val code = response.code) { - 200 -> response - 201 -> response - 202 -> response - 204 -> response - 400 -> throw BadRequestException() - 401 -> throw UnauthorizedException() - 403 -> throw ForbiddenException() - 404 -> throw NotFoundException() - 409 -> throw ConflictException() - 410 -> throw GoneException() - 415 -> throw UnsupportedMediaTypeException() + HttpsURLConnection.HTTP_OK -> response + HttpsURLConnection.HTTP_CREATED -> response + HttpsURLConnection.HTTP_ACCEPTED -> response + HttpsURLConnection.HTTP_NO_CONTENT -> response + HttpsURLConnection.HTTP_BAD_REQUEST -> throw BadRequestException() + HttpsURLConnection.HTTP_UNAUTHORIZED -> throw UnauthorizedException() + HttpsURLConnection.HTTP_FORBIDDEN -> throw ForbiddenException() + HttpsURLConnection.HTTP_NOT_FOUND -> throw NotFoundException() + HttpsURLConnection.HTTP_CONFLICT -> throw ConflictException() + HttpsURLConnection.HTTP_GONE -> throw GoneException() + HttpsURLConnection.HTTP_UNSUPPORTED_TYPE -> throw UnsupportedMediaTypeException() 429 -> throw TooManyRequestsException() - 500 -> throw InternalServerErrorException() - 501 -> throw NotImplementedException() - 502 -> throw BadGatewayException() - 503 -> throw ServiceUnavailableException() - 504 -> throw GatewayTimeoutException() - 505 -> throw HTTPVersionNotSupported() + HttpsURLConnection.HTTP_INTERNAL_ERROR -> throw InternalServerErrorException() + HttpsURLConnection.HTTP_NOT_IMPLEMENTED -> throw NotImplementedException() + HttpsURLConnection.HTTP_BAD_GATEWAY -> throw BadGatewayException() + HttpsURLConnection.HTTP_UNAVAILABLE -> throw ServiceUnavailableException() + HttpsURLConnection.HTTP_GATEWAY_TIMEOUT -> throw GatewayTimeoutException() + HttpsURLConnection.HTTP_VERSION -> throw HTTPVersionNotSupported() 511 -> throw NetworkAuthenticationRequiredException() 598 -> throw NetworkReadTimeoutException() 599 -> throw NetworkConnectTimeoutException() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..a921a828fdc1e36ebdeb51188ed4553e94a64cfd --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/HttpModule.kt @@ -0,0 +1,94 @@ +package de.rki.coronawarnapp.http + +import dagger.Module +import dagger.Provides +import dagger.Reusable +import de.rki.coronawarnapp.BuildConfig +import de.rki.coronawarnapp.http.config.HTTPVariables +import de.rki.coronawarnapp.http.interceptor.RetryInterceptor +import de.rki.coronawarnapp.http.interceptor.WebSecurityVerificationInterceptor +import de.rki.coronawarnapp.risk.TimeVariables +import okhttp3.CipherSuite +import okhttp3.ConnectionSpec +import okhttp3.Interceptor +import okhttp3.OkHttpClient +import okhttp3.TlsVersion +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.converter.protobuf.ProtoConverterFactory +import timber.log.Timber +import java.util.concurrent.TimeUnit + +@Module +class HttpModule { + + @Reusable + @HttpClientDefault + @Provides + fun defaultHttpClient(): OkHttpClient { + val interceptors: List<Interceptor> = listOf( + WebSecurityVerificationInterceptor(), + HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger { + override fun log(message: String) { + Timber.tag("OkHttp").v(message) + } + }).apply { + if (BuildConfig.DEBUG) setLevel(HttpLoggingInterceptor.Level.BODY) + }, + RetryInterceptor(), + HttpErrorParser() + ) + + return OkHttpClient.Builder().apply { + connectTimeout(HTTPVariables.getHTTPConnectionTimeout(), TimeUnit.MILLISECONDS) + readTimeout(HTTPVariables.getHTTPReadTimeout(), TimeUnit.MILLISECONDS) + writeTimeout(HTTPVariables.getHTTPWriteTimeout(), TimeUnit.MILLISECONDS) + callTimeout(TimeVariables.getTransactionTimeout(), TimeUnit.MILLISECONDS) + + interceptors.forEach { addInterceptor(it) } + }.build() + } + + @Reusable + @Provides + fun provideGSONConverter(): GsonConverterFactory = GsonConverterFactory.create() + + @Reusable + @Provides + fun provideProtoConverter(): ProtoConverterFactory = ProtoConverterFactory.create() + + @Reusable + @RestrictedConnectionSpecs + @Provides + fun restrictedConnectionSpecs(): List<ConnectionSpec> = ConnectionSpec + .Builder(ConnectionSpec.RESTRICTED_TLS) + .tlsVersions( + TlsVersion.TLS_1_2, + TlsVersion.TLS_1_3 + ) + .cipherSuites( + // TLS 1.2 with Perfect Forward Secrecy (BSI TR-02102-2) + CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, + CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + // TLS 1.3 (BSI TR-02102-2) + CipherSuite.TLS_AES_128_GCM_SHA256, + CipherSuite.TLS_AES_256_GCM_SHA384, + CipherSuite.TLS_AES_128_CCM_SHA256 + ) + .build() + .let { listOf(it) } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/RestrictedConnectionSpecs.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/RestrictedConnectionSpecs.kt new file mode 100644 index 0000000000000000000000000000000000000000..396eb9a39d0cc47c463a2e8e67369d9eaf019b74 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/RestrictedConnectionSpecs.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.http + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class RestrictedConnectionSpecs diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt deleted file mode 100644 index ae9366bfd235e4fc438ce84ee7b80cf3a8815800..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/ServiceFactory.kt +++ /dev/null @@ -1,203 +0,0 @@ -package de.rki.coronawarnapp.http - -import android.webkit.URLUtil -import de.rki.coronawarnapp.BuildConfig -import de.rki.coronawarnapp.CoronaWarnApplication -import de.rki.coronawarnapp.exception.http.ServiceFactoryException -import de.rki.coronawarnapp.http.config.HTTPVariables -import de.rki.coronawarnapp.http.interceptor.RetryInterceptor -import de.rki.coronawarnapp.http.interceptor.WebSecurityVerificationInterceptor -import de.rki.coronawarnapp.http.service.DistributionService -import de.rki.coronawarnapp.http.service.SubmissionService -import de.rki.coronawarnapp.http.service.VerificationService -import de.rki.coronawarnapp.risk.TimeVariables -import okhttp3.Cache -import okhttp3.CipherSuite -import okhttp3.ConnectionPool -import okhttp3.ConnectionSpec -import okhttp3.Interceptor -import okhttp3.OkHttpClient -import okhttp3.TlsVersion -import okhttp3.logging.HttpLoggingInterceptor -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import retrofit2.converter.protobuf.ProtoConverterFactory -import java.io.File -import java.util.concurrent.TimeUnit - -class ServiceFactory { - companion object { - /** - * 10 MiB - */ - private const val HTTP_CACHE_SIZE = 10L * 1024L * 1024L - - /** - * Cache file name - */ - private const val HTTP_CACHE_NAME = "http_cache" - } - - /** - * List of interceptors, e.g. logging - */ - private val mInterceptors: List<Interceptor> = listOf( - WebSecurityVerificationInterceptor(), - HttpLoggingInterceptor().also { - if (BuildConfig.DEBUG) it.setLevel(HttpLoggingInterceptor.Level.BODY) - }, - RetryInterceptor(), - HttpErrorParser() - ) - - /** - * connection pool held in-memory, especially useful for key retrieval - */ - private val conPool = ConnectionPool() - - /** - * Basic disk cache backed by LRU - */ - private val cache = Cache( - directory = File(CoronaWarnApplication.getAppContext().cacheDir, HTTP_CACHE_NAME), - maxSize = HTTP_CACHE_SIZE - ) - - private val gsonConverterFactory = GsonConverterFactory.create() - private val protoConverterFactory = ProtoConverterFactory.create() - - private val okHttpClient by lazy { - val clientBuilder = OkHttpClient.Builder() - - clientBuilder.connectTimeout( - HTTPVariables.getHTTPConnectionTimeout(), - TimeUnit.MILLISECONDS - ) - clientBuilder.readTimeout( - HTTPVariables.getHTTPReadTimeout(), - TimeUnit.MILLISECONDS - ) - clientBuilder.writeTimeout( - HTTPVariables.getHTTPWriteTimeout(), - TimeUnit.MILLISECONDS - ) - clientBuilder.callTimeout( - TimeVariables.getTransactionTimeout(), - TimeUnit.MILLISECONDS - ) - - clientBuilder.connectionPool(conPool) - - cache.evictAll() - clientBuilder.cache(cache) - - mInterceptors.forEach { clientBuilder.addInterceptor(it) } - - clientBuilder.build() - } - - /** - * For the CDN we want to ensure maximum Compatibility. - */ - private fun getCDNSpecs(): List<ConnectionSpec> = listOf( - ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS) - .tlsVersions( - TlsVersion.TLS_1_0, - TlsVersion.TLS_1_1, - TlsVersion.TLS_1_2, - TlsVersion.TLS_1_3 - ) - .allEnabledCipherSuites() - .build() - ) - - /** - * For Submission and Verification we want to limit our specifications for TLS. - */ - private fun getRestrictedSpecs(): List<ConnectionSpec> = listOf( - ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS) - .tlsVersions( - TlsVersion.TLS_1_2, - TlsVersion.TLS_1_3 - ) - .cipherSuites( - // TLS 1.2 with Perfect Forward Secrecy (BSI TR-02102-2) - CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, - CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, - CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, - CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, - CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, - CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, - CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, - CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, - // TLS 1.3 (BSI TR-02102-2) - CipherSuite.TLS_AES_128_GCM_SHA256, - CipherSuite.TLS_AES_256_GCM_SHA384, - CipherSuite.TLS_AES_128_CCM_SHA256 - ) - .build() - ) - - /** - * Helper function to create a new client from an existent Client with New Specs. - * - * @param specs - */ - private fun OkHttpClient.buildClientWithNewSpecs(specs: List<ConnectionSpec>) = - this.newBuilder().connectionSpecs(specs).build() - - private val downloadCdnUrl - get() = getValidUrl(BuildConfig.DOWNLOAD_CDN_URL) - - fun distributionService(): DistributionService = distributionService - private val distributionService by lazy { - Retrofit.Builder() - .client(okHttpClient.buildClientWithNewSpecs(getCDNSpecs())) - .baseUrl(downloadCdnUrl) - .addConverterFactory(gsonConverterFactory) - .build() - .create(DistributionService::class.java) - } - - private val verificationCdnUrl - get() = getValidUrl(BuildConfig.VERIFICATION_CDN_URL) - - fun verificationService(): VerificationService = verificationService - private val verificationService by lazy { - Retrofit.Builder() - .client(okHttpClient.buildClientWithNewSpecs(getRestrictedSpecs())) - .baseUrl(verificationCdnUrl) - .addConverterFactory(gsonConverterFactory) - .build() - .create(VerificationService::class.java) - } - - private val submissionCdnUrl - get() = getValidUrl(BuildConfig.SUBMISSION_CDN_URL) - - fun submissionService(): SubmissionService = submissionService - private val submissionService by lazy { - Retrofit.Builder() - .client(okHttpClient.buildClientWithNewSpecs(getRestrictedSpecs())) - .baseUrl(submissionCdnUrl) - .addConverterFactory(protoConverterFactory) - .addConverterFactory(gsonConverterFactory) - .build() - .create(SubmissionService::class.java) - } - - private fun getValidUrl(url: String): String { - if (!URLUtil.isHttpsUrl(url)) { - throw ServiceFactoryException(IllegalArgumentException("the url is invalid")) - } - return url - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt deleted file mode 100644 index 906b6b44c1dc7bbaa96e76d87349e68fd9e67411..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/WebRequestBuilder.kt +++ /dev/null @@ -1,258 +0,0 @@ -/****************************************************************************** - * Corona-Warn-App * - * * - * SAP SE and all other contributors / * - * copyright owners license this file to you under the Apache * - * License, Version 2.0 (the "License"); you may not use this * - * file except in compliance with the License. * - * You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ******************************************************************************/ - -package de.rki.coronawarnapp.http - -import KeyExportFormat -import com.google.protobuf.ByteString -import com.google.protobuf.InvalidProtocolBufferException -import de.rki.coronawarnapp.exception.ApplicationConfigurationCorruptException -import de.rki.coronawarnapp.exception.ApplicationConfigurationInvalidException -import de.rki.coronawarnapp.http.requests.RegistrationRequest -import de.rki.coronawarnapp.http.requests.RegistrationTokenRequest -import de.rki.coronawarnapp.http.requests.TanRequestBody -import de.rki.coronawarnapp.http.service.DistributionService -import de.rki.coronawarnapp.http.service.SubmissionService -import de.rki.coronawarnapp.http.service.VerificationService -import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration -import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants -import de.rki.coronawarnapp.service.submission.KeyType -import de.rki.coronawarnapp.service.submission.SubmissionConstants -import de.rki.coronawarnapp.storage.FileStorageHelper -import de.rki.coronawarnapp.util.TimeAndDateExtensions.toServerFormat -import de.rki.coronawarnapp.util.ZipHelper.unzip -import de.rki.coronawarnapp.util.security.HashHelper -import de.rki.coronawarnapp.util.security.VerificationKeys -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import timber.log.Timber -import java.io.File -import java.util.Date -import java.util.UUID -import kotlin.math.max - -class WebRequestBuilder( - private val distributionService: DistributionService, - private val verificationService: VerificationService, - private val submissionService: SubmissionService, - private val verificationKeys: VerificationKeys -) { - companion object { - private val TAG: String? = WebRequestBuilder::class.simpleName - private const val EXPORT_BINARY_FILE_NAME = "export.bin" - private const val EXPORT_SIGNATURE_FILE_NAME = "export.sig" - - @Volatile - private var instance: WebRequestBuilder? = null - - fun getInstance(): WebRequestBuilder { - return instance ?: synchronized(this) { - instance ?: buildWebRequestBuilder().also { instance = it } - } - } - - private fun buildWebRequestBuilder(): WebRequestBuilder { - val serviceFactory = ServiceFactory() - return WebRequestBuilder( - serviceFactory.distributionService(), - serviceFactory.verificationService(), - serviceFactory.submissionService(), - VerificationKeys() - ) - } - } - - suspend fun asyncGetDateIndex(): List<String> = withContext(Dispatchers.IO) { - return@withContext distributionService - .getDateIndex(DiagnosisKeyConstants.AVAILABLE_DATES_URL).toList() - } - - suspend fun asyncGetHourIndex(day: Date): List<String> = withContext(Dispatchers.IO) { - return@withContext distributionService - .getHourIndex( - DiagnosisKeyConstants.AVAILABLE_DATES_URL + - "/${day.toServerFormat()}/${DiagnosisKeyConstants.HOUR}" - ) - .toList() - } - - /** - * Retrieves Key Files from the Server based on a URL - * - * @param url the given URL - */ - suspend fun asyncGetKeyFilesFromServer( - url: String - ): File = withContext(Dispatchers.IO) { - val fileName = "${UUID.nameUUIDFromBytes(url.toByteArray())}.zip" - val file = File(FileStorageHelper.keyExportDirectory, fileName) - if (file.exists()) file.delete() - file.outputStream().use { fos -> - Timber.v("Added $url to queue.") - distributionService.getKeyFiles(url).byteStream().use { - it.copyTo(fos, DEFAULT_BUFFER_SIZE) - } - Timber.v("key file request successful.") - } - return@withContext file - } - - suspend fun asyncGetApplicationConfigurationFromServer(): ApplicationConfiguration = - withContext(Dispatchers.IO) { - var exportBinary: ByteArray? = null - var exportSignature: ByteArray? = null - - distributionService.getApplicationConfiguration( - DiagnosisKeyConstants.COUNTRY_APPCONFIG_DOWNLOAD_URL - ).byteStream().unzip { entry, entryContent -> - if (entry.name == EXPORT_BINARY_FILE_NAME) exportBinary = entryContent.copyOf() - if (entry.name == EXPORT_SIGNATURE_FILE_NAME) exportSignature = - entryContent.copyOf() - } - if (exportBinary == null || exportSignature == null) { - throw ApplicationConfigurationInvalidException() - } - - if (verificationKeys.hasInvalidSignature(exportBinary, exportSignature)) { - throw ApplicationConfigurationCorruptException() - } - - try { - return@withContext ApplicationConfiguration.parseFrom(exportBinary) - } catch (e: InvalidProtocolBufferException) { - throw ApplicationConfigurationInvalidException() - } - } - - suspend fun asyncGetRegistrationToken( - key: String, - keyType: KeyType - ): String = withContext(Dispatchers.IO) { - val keyStr = if (keyType == KeyType.GUID) { - HashHelper.hash256(key) - } else { - key - } - - val paddingLength = when (keyType) { - KeyType.GUID -> SubmissionConstants.PADDING_LENGTH_BODY_REGISTRATION_TOKEN_GUID - KeyType.TELETAN -> SubmissionConstants.PADDING_LENGTH_BODY_REGISTRATION_TOKEN_TELETAN - } - - verificationService.getRegistrationToken( - SubmissionConstants.REGISTRATION_TOKEN_URL, - "0", - requestPadding(SubmissionConstants.PADDING_LENGTH_HEADER_REGISTRATION_TOKEN), - RegistrationTokenRequest(keyType.name, keyStr, requestPadding(paddingLength)) - ).registrationToken - } - - suspend fun asyncGetTestResult( - registrationToken: String - ): Int = withContext(Dispatchers.IO) { - verificationService.getTestResult( - SubmissionConstants.TEST_RESULT_URL, - "0", - requestPadding(SubmissionConstants.PADDING_LENGTH_HEADER_TEST_RESULT), - RegistrationRequest( - registrationToken, - requestPadding(SubmissionConstants.PADDING_LENGTH_BODY_TEST_RESULT) - ) - ).testResult - } - - suspend fun asyncGetTan( - registrationToken: String - ): String = withContext(Dispatchers.IO) { - verificationService.getTAN( - SubmissionConstants.TAN_REQUEST_URL, - "0", - requestPadding(SubmissionConstants.PADDING_LENGTH_HEADER_TAN), - TanRequestBody( - registrationToken, - requestPadding(SubmissionConstants.PADDING_LENGTH_BODY_TAN) - ) - ).tan - } - - suspend fun asyncFakeVerification() = withContext(Dispatchers.IO) { - verificationService.getTAN( - SubmissionConstants.TAN_REQUEST_URL, - "1", - requestPadding(SubmissionConstants.PADDING_LENGTH_HEADER_TAN), - TanRequestBody( - registrationToken = SubmissionConstants.DUMMY_REGISTRATION_TOKEN, - requestPadding = requestPadding(SubmissionConstants.PADDING_LENGTH_BODY_TAN_FAKE) - ) - ) - } - - suspend fun asyncSubmitKeysToServer( - authCode: String, - keyList: List<KeyExportFormat.TemporaryExposureKey> - ) = withContext(Dispatchers.IO) { - Timber.d("Writing ${keyList.size} Keys to the Submission Payload.") - - val randomAdditions = 0 // prepare for random addition of keys - val fakeKeyCount = - max(SubmissionConstants.minKeyCountForSubmission + randomAdditions - keyList.size, 0) - val fakeKeyPadding = requestPadding(SubmissionConstants.fakeKeySize * fakeKeyCount) - - val submissionPayload = KeyExportFormat.SubmissionPayload.newBuilder() - .addAllKeys(keyList) - .setPadding(ByteString.copyFromUtf8(fakeKeyPadding)) - .build() - submissionService.submitKeys( - DiagnosisKeyConstants.DIAGNOSIS_KEYS_SUBMISSION_URL, - authCode, - "0", - SubmissionConstants.EMPTY_HEADER, - submissionPayload - ) - return@withContext - } - - suspend fun asyncFakeSubmission() = withContext(Dispatchers.IO) { - - val randomAdditions = 0 // prepare for random addition of keys - val fakeKeyCount = SubmissionConstants.minKeyCountForSubmission + randomAdditions - - val fakeKeyPadding = - requestPadding(SubmissionConstants.fakeKeySize * fakeKeyCount) - - val submissionPayload = KeyExportFormat.SubmissionPayload.newBuilder() - .setPadding(ByteString.copyFromUtf8(fakeKeyPadding)) - .build() - - submissionService.submitKeys( - DiagnosisKeyConstants.DIAGNOSIS_KEYS_SUBMISSION_URL, - SubmissionConstants.EMPTY_HEADER, - "1", - requestPadding(SubmissionConstants.PADDING_LENGTH_HEADER_SUBMISSION_FAKE), - submissionPayload - ) - } - - private fun requestPadding(length: Int): String { - val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9') - return (1..length) - .map { allowedChars.random() } - .joinToString("") - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/HTTPVariables.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/HTTPVariables.kt index 4939bf675565a6365f9eee6316b1506dbd356a3f..72a3dad134fc7e3dba2eac9e60e1abf9db97dcf0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/HTTPVariables.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/config/HTTPVariables.kt @@ -5,7 +5,7 @@ object HTTPVariables { * The maximal runtime of a transaction * In milliseconds */ - private const val HTTP_CONNECTION_TIMEOUT = 10000L + private const val HTTP_CONNECTION_TIMEOUT = 20000L /** * Getter function for [HTTP_CONNECTION_TIMEOUT] @@ -19,7 +19,7 @@ object HTTPVariables { * The maximal runtime of a transaction * In milliseconds */ - private const val HTTP_READ_TIMEOUT = 10000L + private const val HTTP_READ_TIMEOUT = 20000L /** * Getter function for [HTTP_READ_TIMEOUT] @@ -33,7 +33,7 @@ object HTTPVariables { * The maximal runtime of a transaction * In milliseconds */ - private const val HTTP_WRITE_TIMEOUT = 10000L + private const val HTTP_WRITE_TIMEOUT = 20000L /** * Getter function for [HTTP_WRITE_TIMEOUT] diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/PlaybookImpl.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/PlaybookImpl.kt deleted file mode 100644 index 3012a11394711c4d974fc4613431790e217c13de..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/PlaybookImpl.kt +++ /dev/null @@ -1,143 +0,0 @@ -package de.rki.coronawarnapp.http.playbook - -import KeyExportFormat -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.service.submission.KeyType -import de.rki.coronawarnapp.service.submission.SubmissionConstants -import de.rki.coronawarnapp.util.formatter.TestResult -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import timber.log.Timber -import java.util.UUID -import java.util.concurrent.TimeUnit - -class PlaybookImpl( - private val webRequestBuilder: WebRequestBuilder -) : Playbook { - - private val uid = UUID.randomUUID().toString() - private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.IO) - - override suspend fun initialRegistration(key: String, keyType: KeyType): String { - Timber.i("[$uid] New Initial Registration Playbook") - - // real registration - val (registrationToken, exception) = - executeCapturingExceptions { webRequestBuilder.asyncGetRegistrationToken(key, keyType) } - - // fake verification - ignoreExceptions { webRequestBuilder.asyncFakeVerification() } - - // fake submission - ignoreExceptions { webRequestBuilder.asyncFakeSubmission() } - - coroutineScope.launch { followUpPlaybooks() } - - return registrationToken ?: propagateException(exception) - } - - override suspend fun testResult(registrationToken: String): TestResult { - Timber.i("[$uid] New Test Result Playbook") - - // real test result - val (testResult, exception) = - executeCapturingExceptions { webRequestBuilder.asyncGetTestResult(registrationToken) } - - // fake verification - ignoreExceptions { webRequestBuilder.asyncFakeVerification() } - - // fake submission - ignoreExceptions { webRequestBuilder.asyncFakeSubmission() } - - coroutineScope.launch { followUpPlaybooks() } - - return testResult?.let { TestResult.fromInt(it) } - ?: propagateException(exception) - } - - override suspend fun submission( - registrationToken: String, - keys: List<KeyExportFormat.TemporaryExposureKey> - ) { - Timber.i("[$uid] New Submission Playbook") - - // real auth code - val (authCode, exception) = executeCapturingExceptions { - webRequestBuilder.asyncGetTan( - registrationToken - ) - } - - // fake verification - ignoreExceptions { webRequestBuilder.asyncFakeVerification() } - - // real submission - if (authCode != null) { - webRequestBuilder.asyncSubmitKeysToServer(authCode, keys) - coroutineScope.launch { followUpPlaybooks() } - } else { - webRequestBuilder.asyncFakeSubmission() - coroutineScope.launch { followUpPlaybooks() } - propagateException(exception) - } - } - - private suspend fun dummy(launchFollowUp: Boolean) { - // fake verification - ignoreExceptions { webRequestBuilder.asyncFakeVerification() } - - // fake verification - ignoreExceptions { webRequestBuilder.asyncFakeVerification() } - - // fake submission - ignoreExceptions { webRequestBuilder.asyncFakeSubmission() } - - if (launchFollowUp) - coroutineScope.launch { followUpPlaybooks() } - } - - override suspend fun dummy() = dummy(true) - - private suspend fun followUpPlaybooks() { - val runsToExecute = IntRange( - SubmissionConstants.minNumberOfSequentialPlaybooks - 1 /* one was already executed */, - SubmissionConstants.maxNumberOfSequentialPlaybooks - 1 /* one was already executed */ - ).random() - Timber.i("[$uid] Follow Up: launching $runsToExecute follow up playbooks") - - repeat(runsToExecute) { - val executionDelay = IntRange( - SubmissionConstants.minDelayBetweenSequentialPlaybooks, - SubmissionConstants.maxDelayBetweenSequentialPlaybooks - ).random() - Timber.i("[$uid] Follow Up: (${it + 1}/$runsToExecute) waiting $executionDelay[s]...") - delay(TimeUnit.SECONDS.toMillis(executionDelay.toLong())) - - dummy(false) - } - Timber.i("[$uid] Follow Up: finished") - } - - private suspend fun ignoreExceptions(body: suspend () -> Unit) { - try { - body.invoke() - } catch (e: Exception) { - Timber.d(e, "Ignoring dummy request exception") - } - } - - private suspend fun <T> executeCapturingExceptions(body: suspend () -> T): Pair<T?, Exception?> { - return try { - val result = body.invoke() - result to null - } catch (e: Exception) { - null to e - } - } - - private fun propagateException(exception: Exception?): Nothing { - throw exception ?: IllegalStateException() - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/RegistrationRequest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/RegistrationRequest.kt deleted file mode 100644 index 6a20e507c21ae3e0dc1c0358dc78e781af9620d2..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/RegistrationRequest.kt +++ /dev/null @@ -1,10 +0,0 @@ -package de.rki.coronawarnapp.http.requests - -import com.google.gson.annotations.SerializedName - -data class RegistrationRequest( - @SerializedName("registrationToken") - val registrationToken: String? = null, - @SerializedName("requestPadding") - val requestPadding: String? = null -) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/RegistrationTokenRequest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/RegistrationTokenRequest.kt deleted file mode 100644 index 9667101c70a328c36fe9d6edbca5e0737d4dc1d6..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/RegistrationTokenRequest.kt +++ /dev/null @@ -1,12 +0,0 @@ -package de.rki.coronawarnapp.http.requests - -import com.google.gson.annotations.SerializedName - -data class RegistrationTokenRequest( - @SerializedName("keyType") - val keyType: String? = null, - @SerializedName("key") - val key: String? = null, - @SerializedName("requestPadding") - val requestPadding: String? = null -) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/TanRequestBody.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/TanRequestBody.kt deleted file mode 100644 index ce6c123551516d2c56975f877b451737e8aa2bea..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/requests/TanRequestBody.kt +++ /dev/null @@ -1,10 +0,0 @@ -package de.rki.coronawarnapp.http.requests - -import com.google.gson.annotations.SerializedName - -data class TanRequestBody( - @SerializedName("registrationToken") - val registrationToken: String? = null, - @SerializedName("requestPadding") - val requestPadding: String? = null -) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/RegistrationTokenResponse.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/RegistrationTokenResponse.kt deleted file mode 100644 index 4ec189715dc431a32c64e0a490815cc2abd4d90a..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/RegistrationTokenResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package de.rki.coronawarnapp.http.responses - -import com.google.gson.annotations.SerializedName - -data class RegistrationTokenResponse( - @SerializedName("registrationToken") - val registrationToken: String -) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/TanResponse.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/TanResponse.kt deleted file mode 100644 index 91f1ea9b7c00ab4230b442127f84e61edd0e9796..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/TanResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package de.rki.coronawarnapp.http.responses - -import com.google.gson.annotations.SerializedName - -data class TanResponse( - @SerializedName("tan") - val tan: String -) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/TestResultResponse.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/TestResultResponse.kt deleted file mode 100644 index 065a2356f20f1ae6eaa09cd935f07f3bdbd7bfe3..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/responses/TestResultResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package de.rki.coronawarnapp.http.responses - -import com.google.gson.annotations.SerializedName - -data class TestResultResponse( - @SerializedName("testResult") - val testResult: Int -) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/DistributionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/DistributionService.kt deleted file mode 100644 index 1571fc4b66c822f47299fbc97347429dc4af9c4e..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/DistributionService.kt +++ /dev/null @@ -1,22 +0,0 @@ -package de.rki.coronawarnapp.http.service - -import okhttp3.ResponseBody -import retrofit2.http.GET -import retrofit2.http.Streaming -import retrofit2.http.Url - -interface DistributionService { - - @GET - suspend fun getDateIndex(@Url url: String): List<String> - - @GET - suspend fun getHourIndex(@Url url: String): List<String> - - @Streaming - @GET - suspend fun getKeyFiles(@Url url: String): ResponseBody - - @GET - suspend fun getApplicationConfiguration(@Url url: String): ResponseBody -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/VerificationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/VerificationService.kt deleted file mode 100644 index 9974fe50fa5666111dace01e73ff0f98e14d5016..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/VerificationService.kt +++ /dev/null @@ -1,39 +0,0 @@ -package de.rki.coronawarnapp.http.service - -import de.rki.coronawarnapp.http.requests.RegistrationTokenRequest -import de.rki.coronawarnapp.http.requests.RegistrationRequest -import de.rki.coronawarnapp.http.requests.TanRequestBody -import de.rki.coronawarnapp.http.responses.RegistrationTokenResponse -import de.rki.coronawarnapp.http.responses.TanResponse -import de.rki.coronawarnapp.http.responses.TestResultResponse -import retrofit2.http.Body -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.Url - -interface VerificationService { - - @POST - suspend fun getRegistrationToken( - @Url url: String, - @Header("cwa-fake") fake: String, - @Header("cwa-header-padding") headerPadding: String?, - @Body requestBody: RegistrationTokenRequest - ): RegistrationTokenResponse - - @POST - suspend fun getTestResult( - @Url url: String, - @Header("cwa-fake") fake: String, - @Header("cwa-header-padding") headerPadding: String?, - @Body request: RegistrationRequest - ): TestResultResponse - - @POST - suspend fun getTAN( - @Url url: String, - @Header("cwa-fake") fake: String, - @Header("cwa-header-padding") headerPadding: String?, - @Body requestBody: TanRequestBody - ): TanResponse -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt new file mode 100644 index 0000000000000000000000000000000000000000..526b5e05270bad8de02da844dbda29a1292a1ff1 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClient.kt @@ -0,0 +1,35 @@ +@file:Suppress("DEPRECATION") + +package de.rki.coronawarnapp.nearby + +import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider +import timber.log.Timber +import java.io.File +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ENFClient @Inject constructor( + private val googleENFClient: ExposureNotificationClient, + private val diagnosisKeyProvider: DiagnosisKeyProvider +) : DiagnosisKeyProvider { + + // TODO Remove this once we no longer need direct access to the ENF Client, + // i.e. in **[InternalExposureNotificationClient]** + internal val internalClient: ExposureNotificationClient + get() = googleENFClient + + override suspend fun provideDiagnosisKeys( + keyFiles: Collection<File>, + configuration: ExposureConfiguration?, + token: String + ): Boolean { + Timber.d( + "asyncProvideDiagnosisKeys(keyFiles=%s, configuration=%s, token=%s)", + keyFiles, configuration, token + ) + return diagnosisKeyProvider.provideDiagnosisKeys(keyFiles, configuration, token) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClientLocalData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClientLocalData.kt new file mode 100644 index 0000000000000000000000000000000000000000..26564ab4af748c81731269262f78141e6b43c7de --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFClientLocalData.kt @@ -0,0 +1,34 @@ +package de.rki.coronawarnapp.nearby + +import android.content.Context +import androidx.core.content.edit +import org.joda.time.Instant +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ENFClientLocalData @Inject constructor( + private val context: Context +) { + + private val prefs by lazy { + context.getSharedPreferences("enfclient_localdata", Context.MODE_PRIVATE) + } + + var lastQuotaResetAt: Instant + get() = Instant.ofEpochMilli(prefs.getLong(PKEY_QUOTA_LAST_RESET, 0L)) + set(value) = prefs.edit(true) { + putLong(PKEY_QUOTA_LAST_RESET, value.millis) + } + + var currentQuota: Int + get() = prefs.getInt(PKEY_QUOTA_CURRENT, 0) + set(value) = prefs.edit(true) { + putInt(PKEY_QUOTA_CURRENT, value) + } + + companion object { + private const val PKEY_QUOTA_LAST_RESET = "enfclient.quota.lastreset" + private const val PKEY_QUOTA_CURRENT = "enfclient.quota.current" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..4b7094c8f709b45f7765061d8078771d5a0ec118 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/ENFModule.kt @@ -0,0 +1,24 @@ +package de.rki.coronawarnapp.nearby + +import android.content.Context +import com.google.android.gms.nearby.Nearby +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import dagger.Module +import dagger.Provides +import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DefaultDiagnosisKeyProvider +import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider +import javax.inject.Singleton + +@Module +class ENFModule { + + @Singleton + @Provides + fun exposureNotificationClient(context: Context): ExposureNotificationClient = + Nearby.getExposureNotificationClient(context) + + @Singleton + @Provides + fun diagnosisKeySubmitter(submitter: DefaultDiagnosisKeyProvider): DiagnosisKeyProvider = + submitter +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt index efa21ac87851bb24c84cfb90e7683f4f5c859f3e..06b33b5503e44f33c4c7127f993fece9d6df485d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationClient.kt @@ -1,8 +1,5 @@ package de.rki.coronawarnapp.nearby -import com.google.android.gms.nearby.Nearby -import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration -import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration.ExposureConfigurationBuilder import com.google.android.gms.nearby.exposurenotification.ExposureSummary import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import de.rki.coronawarnapp.CoronaWarnApplication @@ -10,7 +7,7 @@ import de.rki.coronawarnapp.risk.TimeVariables import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository import de.rki.coronawarnapp.util.TimeAndDateExtensions.millisecondsToSeconds -import java.io.File +import de.rki.coronawarnapp.util.di.AppInjector import java.util.Date import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -24,7 +21,7 @@ object InternalExposureNotificationClient { // reference to the client from the Google framework with the given application context private val exposureNotificationClient by lazy { - Nearby.getExposureNotificationClient(CoronaWarnApplication.getAppContext()) + AppInjector.component.enfClient.internalClient } /**************************************************** @@ -92,29 +89,8 @@ object InternalExposureNotificationClient { } } - /** - * Takes an ExposureConfiguration object. Inserts a list of files that contain key - * information into the on-device database. Provide the keys of confirmed cases retrieved - * from your internet-accessible server to the Google Play service once requested from the - * API. Information about the file format is in the Exposure Key Export File Format and - * Verification document that is linked from google.com/covid19/exposurenotifications. - * - * @param keyFiles - * @param configuration - * @param token - * @return - */ - suspend fun asyncProvideDiagnosisKeys( - keyFiles: Collection<File>, - configuration: ExposureConfiguration?, - token: String - ): Void = suspendCoroutine { cont -> - val exposureConfiguration = configuration ?: ExposureConfigurationBuilder().build() - exposureNotificationClient.provideDiagnosisKeys( - keyFiles.toList(), - exposureConfiguration, - token - ) + suspend fun getVersion(): Long = suspendCoroutine { cont -> + exposureNotificationClient.version .addOnSuccessListener { cont.resume(it) }.addOnFailureListener { @@ -160,4 +136,11 @@ object InternalExposureNotificationClient { cont.resumeWithException(it) } } + + /** + * Indicates if device supports scanning without location service + * + * @return + */ + fun deviceSupportsLocationlessScanning() = exposureNotificationClient.deviceSupportsLocationlessScanning() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/NearbyModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/NearbyModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..e35491eafaf8d414ee359c84ba80a7567db619bb --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/NearbyModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.nearby + +import android.content.Context +import com.google.android.gms.nearby.Nearby +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import dagger.Module +import dagger.Provides +import dagger.Reusable + +@Module +class NearbyModule { + + @Reusable + @Provides + fun provideENF(context: Context): ExposureNotificationClient { + return Nearby.getExposureNotificationClient(context) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..bca8dfdd48723b685774623dfcd72733203aec66 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt @@ -0,0 +1,106 @@ +@file:Suppress("DEPRECATION") + +package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider + +import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import de.rki.coronawarnapp.util.GoogleAPIVersion +import timber.log.Timber +import java.io.File +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +@Singleton +class DefaultDiagnosisKeyProvider @Inject constructor( + private val googleAPIVersion: GoogleAPIVersion, + private val submissionQuota: SubmissionQuota, + private val enfClient: ExposureNotificationClient +) : DiagnosisKeyProvider { + + override suspend fun provideDiagnosisKeys( + keyFiles: Collection<File>, + configuration: ExposureConfiguration?, + token: String + ): Boolean { + return try { + if (keyFiles.isEmpty()) { + Timber.d("No key files submitted, returning early.") + return true + } + + val usedConfiguration = if (configuration == null) { + Timber.w("Passed configuration was NULL, creating fallback.") + ExposureConfiguration.ExposureConfigurationBuilder().build() + } else { + configuration + } + + if (googleAPIVersion.isAtLeast(GoogleAPIVersion.V16)) { + provideKeys(keyFiles, usedConfiguration, token) + } else { + provideKeysLegacy(keyFiles, usedConfiguration, token) + } + } catch (e: Exception) { + Timber.e( + e, "Error during provideDiagnosisKeys(keyFiles=%s, configuration=%s, token=%s)", + keyFiles, configuration, token + ) + throw e + } + } + + private suspend fun provideKeys( + files: Collection<File>, + configuration: ExposureConfiguration, + token: String + ): Boolean { + Timber.d("Using non-legacy key provision.") + + if (!submissionQuota.consumeQuota(1)) { + Timber.w("Not enough quota available.") + // TODO Currently only logging, we'll be more strict in a future release + // return false + } + + performSubmission(files, configuration, token) + return true + } + + /** + * We use Batch Size 1 and thus submit multiple times to the API. + * This means that instead of directly submitting all files at once, we have to split up + * our file list as this equals a different batch for Google every time. + */ + private suspend fun provideKeysLegacy( + keyFiles: Collection<File>, + configuration: ExposureConfiguration, + token: String + ): Boolean { + Timber.d("Using LEGACY key provision.") + + if (!submissionQuota.consumeQuota(keyFiles.size)) { + Timber.w("Not enough quota available.") + // TODO What about proceeding with partial submission? + // TODO Currently only logging, we'll be more strict in a future release + // return false + } + + keyFiles.forEach { performSubmission(listOf(it), configuration, token) } + return true + } + + private suspend fun performSubmission( + keyFiles: Collection<File>, + configuration: ExposureConfiguration, + token: String + ): Void = suspendCoroutine { cont -> + Timber.d("Performing key submission.") + enfClient + .provideDiagnosisKeys(keyFiles.toList(), configuration, token) + .addOnSuccessListener { cont.resume(it) } + .addOnFailureListener { cont.resumeWithException(it) } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..accedeed05ba0a7be5e2259326da4960db3ab3b7 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DiagnosisKeyProvider.kt @@ -0,0 +1,25 @@ +package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider + +import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration +import java.io.File + +interface DiagnosisKeyProvider { + + /** + * Takes an ExposureConfiguration object. Inserts a list of files that contain key + * information into the on-device database. Provide the keys of confirmed cases retrieved + * from your internet-accessible server to the Google Play service once requested from the + * API. Information about the file format is in the Exposure Key Export File Format and + * Verification document that is linked from google.com/covid19/exposurenotifications. + * + * @param keyFiles + * @param configuration + * @param token + * @return + */ + suspend fun provideDiagnosisKeys( + keyFiles: Collection<File>, + configuration: ExposureConfiguration?, + token: String + ): Boolean +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt new file mode 100644 index 0000000000000000000000000000000000000000..d9bd53506983a3d65e700bd694c21e6ca8d2a618 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuota.kt @@ -0,0 +1,91 @@ +package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider + +import androidx.annotation.VisibleForTesting +import de.rki.coronawarnapp.nearby.ENFClientLocalData +import de.rki.coronawarnapp.util.TimeStamper +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import org.joda.time.DateTimeZone +import org.joda.time.Duration +import org.joda.time.Instant +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class SubmissionQuota @Inject constructor( + private val enfData: ENFClientLocalData, + private val timeStamper: TimeStamper +) { + + private var currentQuota: Int + get() = enfData.currentQuota + set(value) { + enfData.currentQuota = value + } + + private var lastQuotaReset: Instant + get() = enfData.lastQuotaResetAt + set(value) { + enfData.lastQuotaResetAt = value + } + + private val mutex = Mutex() + + /** + * Attempts to consume quota, and returns true if enough quota was available. + */ + suspend fun consumeQuota(wanted: Int): Boolean = mutex.withLock { + attemptQuotaReset() + + if (currentQuota < wanted) { + Timber.d("Not enough quota: want=%d, have=%d", wanted, currentQuota) + return false + } + + run { + val oldQuota = currentQuota + val newQuota = currentQuota - wanted + Timber.d("Consuming quota: old=%d, new=%d", oldQuota, newQuota) + currentQuota = newQuota + } + return true + } + + /** + * Attempts to reset the quota + * On initial launch, the lastQuotaReset is set to Instant.EPOCH, + * thus the quota will be immediately set to 20. + */ + private fun attemptQuotaReset() { + val oldQuota = currentQuota + val oldQuotaReset = lastQuotaReset + + val now = timeStamper.nowUTC + + val nextQuotaReset = lastQuotaReset + .toDateTime(DateTimeZone.UTC) + .withTimeAtStartOfDay() + .plus(Duration.standardDays(1)) + + if (now.isAfter(nextQuotaReset)) { + currentQuota = DEFAULT_QUOTA + lastQuotaReset = now + + Timber.i( + "Quota reset: oldQuota=%d, lastReset=%s -> newQuota=%d, thisReset=%s", + oldQuota, oldQuotaReset, currentQuota, now + ) + } else { + Timber.d( + "No new quota available (now=%s, availableAt=%s)", + now, nextQuotaReset + ) + } + } + + companion object { + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal const val DEFAULT_QUOTA = 20 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/NotificationHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/NotificationHelper.kt index c09cb0746f727e887d75b6e64156cf63e2d922ed..1fd3465f14562f241e5e9ecdd1c1707ce5d05c2f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/NotificationHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/notification/NotificationHelper.kt @@ -178,7 +178,7 @@ object NotificationHelper { */ fun sendNotification(content: String, visibility: Int) { if (!CoronaWarnApplication.isAppInForeground) { - sendNotification("", content, visibility) + sendNotification("", content, visibility, true) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/BackgroundNoise.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/BackgroundNoise.kt similarity index 72% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/BackgroundNoise.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/BackgroundNoise.kt index ea1005d3def6baeec8456de12c4bb9547a421d37..55b7fb55382c84c07c34b7b4279b3e7672cebeef 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/BackgroundNoise.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/BackgroundNoise.kt @@ -1,8 +1,7 @@ -package de.rki.coronawarnapp.http.playbook +package de.rki.coronawarnapp.playbook -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.service.submission.SubmissionConstants import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.worker.BackgroundConstants import de.rki.coronawarnapp.worker.BackgroundWorkScheduler import kotlin.random.Random @@ -21,6 +20,9 @@ class BackgroundNoise { } } + private val playbook: Playbook + get() = AppInjector.component.playbook + fun scheduleDummyPattern() { if (BackgroundConstants.NUMBER_OF_DAYS_TO_RUN_PLAYBOOK > 0) BackgroundWorkScheduler.scheduleBackgroundNoisePeriodicWork() @@ -29,9 +31,8 @@ class BackgroundNoise { suspend fun foregroundScheduleCheck() { if (LocalData.isAllowedToSubmitDiagnosisKeys() == true) { val chance = Random.nextFloat() * 100 - if (chance < SubmissionConstants.probabilityToExecutePlaybookWhenOpenApp) { - PlaybookImpl(WebRequestBuilder.getInstance()) - .dummy() + if (chance < DefaultPlaybook.PROBABILITY_TO_EXECUTE_PLAYBOOK_ON_APP_OPEN) { + playbook.dummy() } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/DefaultPlaybook.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/DefaultPlaybook.kt new file mode 100644 index 0000000000000000000000000000000000000000..338a63f34b8fa33fd08ed609aa6e6a41044ae11c --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/DefaultPlaybook.kt @@ -0,0 +1,174 @@ +package de.rki.coronawarnapp.playbook + +import de.rki.coronawarnapp.submission.server.SubmissionServer +import de.rki.coronawarnapp.util.formatter.TestResult +import de.rki.coronawarnapp.verification.server.VerificationKeyType +import de.rki.coronawarnapp.verification.server.VerificationServer +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import timber.log.Timber +import java.util.UUID +import java.util.concurrent.TimeUnit +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class DefaultPlaybook @Inject constructor( + private val verificationServer: VerificationServer, + private val submissionServer: SubmissionServer +) : Playbook { + + private val uid = UUID.randomUUID().toString() + private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.IO) + + override suspend fun initialRegistration( + key: String, + keyType: VerificationKeyType + ): Pair<String, TestResult> { + Timber.i("[$uid] New Initial Registration Playbook") + + // real registration + val (registrationToken, registrationException) = + executeCapturingExceptions { + verificationServer.retrieveRegistrationToken( + key, + keyType + ) + } + + // if the registration succeeded continue with the real test result retrieval + // if it failed, execute a dummy request to satisfy the required playbook pattern + val (testResult, testResultException) = if (registrationToken != null) { + executeCapturingExceptions { verificationServer.retrieveTestResults(registrationToken) } + } else { + ignoreExceptions { verificationServer.retrieveTanFake() } + null to null + } + + // fake submission + ignoreExceptions { submissionServer.submitKeysToServerFake() } + + coroutineScope.launch { followUpPlaybooks() } + + // if registration and test result retrieval succeeded, return the result + if (registrationToken != null && testResult != null) + return registrationToken to TestResult.fromInt(testResult) + + // else propagate the exception of either the first or the second step + propagateException(registrationException, testResultException) + } + + override suspend fun testResult(registrationToken: String): TestResult { + Timber.i("[$uid] New Test Result Playbook") + + // real test result + val (testResult, exception) = + executeCapturingExceptions { verificationServer.retrieveTestResults(registrationToken) } + + // fake verification + ignoreExceptions { verificationServer.retrieveTanFake() } + + // fake submission + ignoreExceptions { submissionServer.submitKeysToServerFake() } + + coroutineScope.launch { followUpPlaybooks() } + + return testResult?.let { TestResult.fromInt(it) } ?: propagateException(exception) + } + + override suspend fun submission( + data: Playbook.SubmissionData + ) { + Timber.i("[$uid] New Submission Playbook") + // real auth code + val (authCode, exception) = executeCapturingExceptions { + verificationServer.retrieveTan(data.registrationToken) + } + + // fake verification + ignoreExceptions { verificationServer.retrieveTanFake() } + + // real submission + if (authCode != null) { + val serverSubmissionData = SubmissionServer.SubmissionData( + authCode = authCode, + keyList = data.temporaryExposureKeys, + consentToFederation = data.consentToFederation, + visistedCountries = data.visistedCountries + ) + submissionServer.submitKeysToServer(serverSubmissionData) + coroutineScope.launch { followUpPlaybooks() } + } else { + submissionServer.submitKeysToServerFake() + coroutineScope.launch { followUpPlaybooks() } + propagateException(exception) + } + } + + private suspend fun dummy(launchFollowUp: Boolean) { + // fake verification + ignoreExceptions { verificationServer.retrieveTanFake() } + + // fake verification + ignoreExceptions { verificationServer.retrieveTanFake() } + + // fake submission + ignoreExceptions { submissionServer.submitKeysToServerFake() } + + if (launchFollowUp) + coroutineScope.launch { followUpPlaybooks() } + } + + override suspend fun dummy() = dummy(true) + + private suspend fun followUpPlaybooks() { + val runsToExecute = IntRange( + MIN_NUMBER_OF_SEQUENTIAL_PLAYBOOKS - 1 /* one was already executed */, + MAX_NUMBER_OF_SEQUENTIAL_PLAYBOOKS - 1 /* one was already executed */ + ).random() + Timber.i("[$uid] Follow Up: launching $runsToExecute follow up playbooks") + + repeat(runsToExecute) { + val executionDelay = IntRange( + MIN_DELAY_BETWEEN_SEQUENTIAL_PLAYBOOKS, + MAX_DELAY_BETWEEN_SEQUENTIAL_PLAYBOOKS + ).random() + Timber.i("[$uid] Follow Up: (${it + 1}/$runsToExecute) waiting $executionDelay[s]...") + delay(TimeUnit.SECONDS.toMillis(executionDelay.toLong())) + + dummy(false) + } + Timber.i("[$uid] Follow Up: finished") + } + + private suspend fun ignoreExceptions(body: suspend () -> Unit) { + try { + body.invoke() + } catch (e: Exception) { + Timber.d(e, "Ignoring dummy request exception") + } + } + + private suspend fun <T> executeCapturingExceptions(body: suspend () -> T): Pair<T?, Exception?> { + return try { + val result = body.invoke() + result to null + } catch (e: Exception) { + null to e + } + } + + private fun propagateException(vararg exceptions: Exception?): Nothing { + throw exceptions.filterNotNull().firstOrNull() ?: IllegalStateException() + } + + companion object { + const val PROBABILITY_TO_EXECUTE_PLAYBOOK_ON_APP_OPEN = 0f + const val MIN_NUMBER_OF_SEQUENTIAL_PLAYBOOKS = 1 + const val MAX_NUMBER_OF_SEQUENTIAL_PLAYBOOKS = 1 + const val MIN_DELAY_BETWEEN_SEQUENTIAL_PLAYBOOKS = 0 + const val MAX_DELAY_BETWEEN_SEQUENTIAL_PLAYBOOKS = 0 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/Playbook.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/Playbook.kt similarity index 58% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/Playbook.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/Playbook.kt index 66ab1f957b9edcb3af994ca120a3aba2276ecc19..6babf297d09784ef6d8c4d7c2087ea48e238996a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/playbook/Playbook.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/Playbook.kt @@ -1,8 +1,8 @@ -package de.rki.coronawarnapp.http.playbook +package de.rki.coronawarnapp.playbook -import KeyExportFormat -import de.rki.coronawarnapp.service.submission.KeyType +import de.rki.coronawarnapp.server.protocols.KeyExportFormat import de.rki.coronawarnapp.util.formatter.TestResult +import de.rki.coronawarnapp.verification.server.VerificationKeyType /** * The concept of Plausible Deniability aims to hide the existence of a positive test result by always using a defined “playbook pattern†of requests to the Verification Server and CWA Backend so it is impossible for an attacker to identify which communication was done. @@ -13,17 +13,19 @@ interface Playbook { suspend fun initialRegistration( key: String, - keyType: KeyType - ): String /* registration token */ + keyType: VerificationKeyType + ): Pair<String, TestResult> /* registration token & test result*/ - suspend fun testResult( - registrationToken: String - ): TestResult + suspend fun testResult(registrationToken: String): TestResult - suspend fun submission( - registrationToken: String, - keys: List<KeyExportFormat.TemporaryExposureKey> + data class SubmissionData( + val registrationToken: String, + val temporaryExposureKeys: List<KeyExportFormat.TemporaryExposureKey>, + val consentToFederation: Boolean, + val visistedCountries: List<String> ) + suspend fun submission(data: SubmissionData) + suspend fun dummy() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/PlaybookModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/PlaybookModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..d76e5654c2f1548d459db8cceb3db829bacda8d2 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/playbook/PlaybookModule.kt @@ -0,0 +1,13 @@ +package de.rki.coronawarnapp.playbook + +import dagger.Module +import dagger.Provides +import javax.inject.Singleton + +@Module +class PlaybookModule { + + @Singleton + @Provides + fun providePlaybook(defaultPlayBook: DefaultPlaybook): Playbook = defaultPlayBook +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ReceiverBinder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ReceiverBinder.kt new file mode 100644 index 0000000000000000000000000000000000000000..8d8cf82f4db376f5af6b7469e86100982645a05a --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/receiver/ReceiverBinder.kt @@ -0,0 +1,6 @@ +package de.rki.coronawarnapp.receiver + +import dagger.Module + +@Module +internal abstract class ReceiverBinder diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskLevelCalculation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskLevelCalculation.kt new file mode 100644 index 0000000000000000000000000000000000000000..1418cdea0b034b8bb268803ec61697ac7f8e4012 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskLevelCalculation.kt @@ -0,0 +1,66 @@ +package de.rki.coronawarnapp.risk + +import com.google.android.gms.nearby.exposurenotification.ExposureSummary +import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.round + +@Singleton +class DefaultRiskLevelCalculation @Inject constructor() : RiskLevelCalculation { + + companion object { + + private var TAG = DefaultRiskLevelCalculation::class.simpleName + + private const val DECIMAL_MULTIPLIER = 100 + } + + override fun calculateRiskScore( + attenuationParameters: ApplicationConfigurationOuterClass.AttenuationDuration, + exposureSummary: ExposureSummary + ): Double { + + /** all attenuation values are capped to [TimeVariables.MAX_ATTENUATION_DURATION] */ + val weightedAttenuationLow = + attenuationParameters.weights.low + .times(exposureSummary.attenuationDurationsInMinutes[0].capped()) + val weightedAttenuationMid = + attenuationParameters.weights.mid + .times(exposureSummary.attenuationDurationsInMinutes[1].capped()) + val weightedAttenuationHigh = + attenuationParameters.weights.high + .times(exposureSummary.attenuationDurationsInMinutes[2].capped()) + + val maximumRiskScore = exposureSummary.maximumRiskScore.toDouble() + + val defaultBucketOffset = attenuationParameters.defaultBucketOffset.toDouble() + val normalizationDivisor = attenuationParameters.riskScoreNormalizationDivisor.toDouble() + + val attenuationStrings = + "Weighted Attenuation: ($weightedAttenuationLow + $weightedAttenuationMid + " + + "$weightedAttenuationHigh + $defaultBucketOffset)" + Timber.v(attenuationStrings) + + val weightedAttenuationDuration = + weightedAttenuationLow + .plus(weightedAttenuationMid) + .plus(weightedAttenuationHigh) + .plus(defaultBucketOffset) + + Timber.v("Formula used: ($maximumRiskScore / $normalizationDivisor) * $weightedAttenuationDuration") + + val riskScore = (maximumRiskScore / normalizationDivisor) * weightedAttenuationDuration + + return round(riskScore.times(DECIMAL_MULTIPLIER)).div(DECIMAL_MULTIPLIER) + } + + private fun Int.capped(): Int { + return if (this > TimeVariables.getMaxAttenuationDuration()) { + TimeVariables.getMaxAttenuationDuration() + } else { + this + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskScoreAnalysis.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskScoreAnalysis.kt new file mode 100644 index 0000000000000000000000000000000000000000..eb8c7c04337432a01315e29b97216c62515cc411 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskScoreAnalysis.kt @@ -0,0 +1,11 @@ +package de.rki.coronawarnapp.risk + +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class DefaultRiskScoreAnalysis @Inject constructor() : RiskScoreAnalysis { + + override fun withinDefinedLevelThreshold(riskScore: Double, min: Int, max: Int) = + riskScore >= min && riskScore <= max +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelCalculation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelCalculation.kt index 10547f52aa6de3e406c3fe72459c15421e9cb301..6d876e68529432312d3ec7af786d040bef56f462 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelCalculation.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevelCalculation.kt @@ -2,58 +2,11 @@ package de.rki.coronawarnapp.risk import com.google.android.gms.nearby.exposurenotification.ExposureSummary import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass -import timber.log.Timber -import kotlin.math.round -object RiskLevelCalculation { - private var TAG = RiskLevelCalculation::class.simpleName - - private const val DECIMAL_MULTIPLIER = 100 +interface RiskLevelCalculation { fun calculateRiskScore( attenuationParameters: ApplicationConfigurationOuterClass.AttenuationDuration, exposureSummary: ExposureSummary - ): Double { - - /** all attenuation values are capped to [TimeVariables.MAX_ATTENUATION_DURATION] */ - val weightedAttenuationLow = - attenuationParameters.weights.low - .times(exposureSummary.attenuationDurationsInMinutes[0].capped()) - val weightedAttenuationMid = - attenuationParameters.weights.mid - .times(exposureSummary.attenuationDurationsInMinutes[1].capped()) - val weightedAttenuationHigh = - attenuationParameters.weights.high - .times(exposureSummary.attenuationDurationsInMinutes[2].capped()) - - val maximumRiskScore = exposureSummary.maximumRiskScore.toDouble() - - val defaultBucketOffset = attenuationParameters.defaultBucketOffset.toDouble() - val normalizationDivisor = attenuationParameters.riskScoreNormalizationDivisor.toDouble() - - val attenuationStrings = - "Weighted Attenuation: ($weightedAttenuationLow + $weightedAttenuationMid + " + - "$weightedAttenuationHigh + $defaultBucketOffset)" - Timber.v(attenuationStrings) - - val weightedAttenuationDuration = - weightedAttenuationLow - .plus(weightedAttenuationMid) - .plus(weightedAttenuationHigh) - .plus(defaultBucketOffset) - - Timber.v("Formula used: ($maximumRiskScore / $normalizationDivisor) * $weightedAttenuationDuration") - - val riskScore = (maximumRiskScore / normalizationDivisor) * weightedAttenuationDuration - - return round(riskScore.times(DECIMAL_MULTIPLIER)).div(DECIMAL_MULTIPLIER) - } - - private fun Int.capped(): Int { - return if (this > TimeVariables.getMaxAttenuationDuration()) { - TimeVariables.getMaxAttenuationDuration() - } else { - this - } - } + ): Double } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..7b69bc7eb52fc57ef2012a402fd1081b1c6aff35 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskModule.kt @@ -0,0 +1,21 @@ +package de.rki.coronawarnapp.risk + +import dagger.Binds +import dagger.Module +import javax.inject.Singleton + +@Module +abstract class RiskModule { + + @Binds + @Singleton + abstract fun bindRiskLevelCalculation( + riskLevelCalculation: DefaultRiskLevelCalculation + ): RiskLevelCalculation + + @Binds + @Singleton + abstract fun bindRiskScoreAnalysis( + riskScoreAnalysis: DefaultRiskScoreAnalysis + ): RiskScoreAnalysis +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskScoreAnalysis.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskScoreAnalysis.kt new file mode 100644 index 0000000000000000000000000000000000000000..10bb47c25f7ebc0038e0a830f54f35710d1d21b0 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskScoreAnalysis.kt @@ -0,0 +1,10 @@ +package de.rki.coronawarnapp.risk + +interface RiskScoreAnalysis { + + fun withinDefinedLevelThreshold( + riskScore: Double, + min: Int, + max: Int + ): Boolean +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/TimeVariables.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/TimeVariables.kt index c518230d7a1a0f59dab7b17da660454efd018fb2..99a10696c70e8c606c401de795f3b686418ce689 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/TimeVariables.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/TimeVariables.kt @@ -1,13 +1,13 @@ package de.rki.coronawarnapp.risk import com.google.android.gms.common.api.ApiException -import de.rki.coronawarnapp.BuildConfig import de.rki.coronawarnapp.CoronaWarnApplication import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository +import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.TimeAndDateExtensions.daysToMilliseconds import de.rki.coronawarnapp.util.TimeAndDateExtensions.roundUpMsToDays @@ -34,7 +34,7 @@ object TimeVariables { * The maximal runtime of a transaction * In milliseconds */ - private const val TRANSACTION_TIMEOUT = 60000L + private const val TRANSACTION_TIMEOUT = 180000L /** * Getter function for [TRANSACTION_TIMEOUT] @@ -99,21 +99,16 @@ object TimeVariables { * Delay in milliseconds for manual key retrieval process * Value for testing: 1 min = 1000 * 60 * 1 * Value: 24 hours = 1000 * 60 * 60 * 24 milliseconds + * + * @return delay of key retrieval in milliseconds */ - private val MANUAL_KEY_RETRIEVAL_DELAY = - if (BuildConfig.FLAVOR == "deviceForTesters") { + fun getManualKeyRetrievalDelay() = + if (CWADebug.buildFlavor == CWADebug.BuildFlavor.DEVICE_FOR_TESTERS) { MILISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTES } else { MILISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTES * MINUTES_IN_AN_HOUR * HOURS_IN_AN_DAY } - /** - * Getter function for [MANUAL_KEY_RETRIEVAL_DELAY] - * - * @return delay of key retrieval in milliseconds - */ - fun getManualKeyRetrievalDelay() = MANUAL_KEY_RETRIEVAL_DELAY - /** * This is the maximum attenuation duration value for the risk level calculation * in minutes @@ -175,19 +170,23 @@ object TimeVariables { * @return in milliseconds */ fun getTimeActiveTracingDuration(): Long = System.currentTimeMillis() - - (getInitialExposureTracingActivationTimestamp() ?: 0L) - - LocalData.totalNonActiveTracing() + (getInitialExposureTracingActivationTimestamp() ?: 0L) - + LocalData.totalNonActiveTracing() suspend fun getActiveTracingDaysInRetentionPeriod(): Long { // the active tracing time during the retention period - all non active tracing times val tracingActiveMS = getTimeRangeFromRetentionPeriod() + val retentionPeriodInMS = getDefaultRetentionPeriodInMS() + val lastNonActiveTracingTimestamp = LocalData.lastNonActiveTracingTimestamp() + val current = System.currentTimeMillis() + val retentionTimestamp = current - retentionPeriodInMS val inactiveTracingIntervals = TracingIntervalRepository .getDateRepository(CoronaWarnApplication.getAppContext()) .getIntervals() .toMutableList() // by default the tracing is assumed to be activated - // if the API is reachable we set the value accordingly + // if the API is reachable we set the value accordingly val enIsDisabled = try { !InternalExposureNotificationClient.asyncIsEnabled() } catch (e: ApiException) { @@ -195,21 +194,23 @@ object TimeVariables { false } - if (enIsDisabled) { - val current = System.currentTimeMillis() - val lastTimeTracingWasNotActivated = minOf( - LocalData.lastNonActiveTracingTimestamp() ?: current, - current - tracingActiveMS - ) - + // lastNonActiveTracingTimestamp could be null when en is disabled + // it only gets updated when you turn the en back on + // if en is disabled and lastNonActiveTracingTimestamp != null, only then we add a pair to + // the inactive intervals list to account for the time of inactivity between the last time + // en was not active and now. + if (enIsDisabled && lastNonActiveTracingTimestamp != null) { + val lastTimeTracingWasNotActivated = + LocalData.lastNonActiveTracingTimestamp() ?: current inactiveTracingIntervals.add(Pair(lastTimeTracingWasNotActivated, current)) } - - val finalTracingMS = tracingActiveMS - inactiveTracingIntervals - .map { it.second - it.first } + val inactiveTracingMS = inactiveTracingIntervals + .map { it.second - maxOf(it.first, retentionTimestamp) } .sum() - return finalTracingMS.roundUpMsToDays() + // because we delete periods that are past 14 days but tracingActiveMS counts from first + // ever activation, there are edge cases where tracingActiveMS gets to be > 14 days + return (minOf(tracingActiveMS, retentionPeriodInMS) - inactiveTracingMS).roundUpMsToDays() } /**************************************************** diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/ServiceBinder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/ServiceBinder.kt new file mode 100644 index 0000000000000000000000000000000000000000..d53e08964ff8828c969cd0a3fb508053c7a2463b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/ServiceBinder.kt @@ -0,0 +1,6 @@ +package de.rki.coronawarnapp.service + +import dagger.Module + +@Module +internal abstract class ServiceBinder diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt index 790beb9c0da5aed08d6478f66b9b245d83a278cf..e82f912b257d2afee323163116b35937e82bf209 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt @@ -1,12 +1,12 @@ package de.rki.coronawarnapp.service.applicationconfiguration import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration -import de.rki.coronawarnapp.http.WebRequestBuilder import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration +import de.rki.coronawarnapp.util.di.AppInjector object ApplicationConfigurationService { suspend fun asyncRetrieveApplicationConfiguration(): ApplicationConfiguration { - return WebRequestBuilder.getInstance().asyncGetApplicationConfigurationFromServer() + return AppInjector.component.appConfigProvider.getAppConfig() } suspend fun asyncRetrieveExposureConfiguration(): ExposureConfiguration = diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyConstants.kt deleted file mode 100644 index c9010f1086dd00ee23a1f129b09ec083e5d242fa..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyConstants.kt +++ /dev/null @@ -1,81 +0,0 @@ -/****************************************************************************** - * Corona-Warn-App * - * * - * SAP SE and all other contributors / * - * copyright owners license this file to you under the Apache * - * License, Version 2.0 (the "License"); you may not use this * - * file except in compliance with the License. * - * You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ******************************************************************************/ - -package de.rki.coronawarnapp.service.diagnosiskey - -/** - * The Diagnosis Key constants - */ -object DiagnosisKeyConstants { - /** version resource variable for REST-like Service Calls */ - private const val VERSION = "version" - - /** parameter resource variable for REST-like Service Calls */ - private const val PARAMETERS = "parameters" - private const val APPCONFIG = "configuration" - - /** diagnosis keys resource variable for REST-like Service Calls */ - private const val DIAGNOSIS_KEYS = "diagnosis-keys" - - /** country resource variable for REST-like Service Calls */ - private const val COUNTRY = "country" - - /** date resource variable for REST-like Service Calls */ - private const val DATE = "date" - - /** hour resource variable for REST-like Service Calls */ - const val HOUR = "hour" - - private const val INDEX_FILE_NAME = "index.txt" - - /** resource variables but non-static context */ - private var CURRENT_VERSION = "v1" - private var CURRENT_COUNTRY = "DE" - - /** Distribution URL built from CDN URL's and REST resources */ - private var VERSIONED_DISTRIBUTION_CDN_URL = "$VERSION/$CURRENT_VERSION" - - /** Submission URL built from CDN URL's and REST resources */ - private var VERSIONED_SUBMISSION_CDN_URL = "$VERSION/$CURRENT_VERSION" - - /** Parameter Download URL built from CDN URL's and REST resources */ - private val PARAMETERS_DOWNLOAD_URL = "$VERSIONED_DISTRIBUTION_CDN_URL/$PARAMETERS" - private val APPCONFIG_DOWNLOAD_URL = "$VERSIONED_DISTRIBUTION_CDN_URL/$APPCONFIG" - - /** Index Download URL built from CDN URL's and REST resources */ - val INDEX_DOWNLOAD_URL = "$VERSIONED_DISTRIBUTION_CDN_URL/$INDEX_FILE_NAME" - - /** Diagnosis key Download URL built from CDN URL's and REST resources */ - val DIAGNOSIS_KEYS_DOWNLOAD_URL = "$VERSIONED_DISTRIBUTION_CDN_URL/$DIAGNOSIS_KEYS" - - /** Diagnosis key Submission URL built from CDN URL's and REST resources */ - val DIAGNOSIS_KEYS_SUBMISSION_URL = "$VERSIONED_SUBMISSION_CDN_URL/$DIAGNOSIS_KEYS" - - /** Country-Specific Parameter URL built from CDN URL's and REST resources */ - val PARAMETERS_COUNTRY_DOWNLOAD_URL = "$PARAMETERS_DOWNLOAD_URL/$COUNTRY" - val APPCONFIG_COUNTRY_DOWNLOAD_URL = "$APPCONFIG_DOWNLOAD_URL/$COUNTRY" - - val COUNTRY_APPCONFIG_DOWNLOAD_URL = - "$APPCONFIG_COUNTRY_DOWNLOAD_URL/$CURRENT_COUNTRY/app_config" - - /** Available Dates URL built from CDN URL's and REST resources */ - val AVAILABLE_DATES_URL = "$DIAGNOSIS_KEYS_DOWNLOAD_URL/$COUNTRY/$CURRENT_COUNTRY/$DATE" - - const val SERVER_ERROR_CODE_403 = 403 -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/QRScanResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/QRScanResult.kt new file mode 100644 index 0000000000000000000000000000000000000000..783ec13a29ac5895765b53c0de7e47b19843807b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/QRScanResult.kt @@ -0,0 +1,32 @@ +package de.rki.coronawarnapp.service.submission + +import java.util.regex.Pattern + +data class QRScanResult(val rawResult: String) { + + val isValid: Boolean + get() = guid != null + val guid: String? by lazy { extractGUID(rawResult) } + + private fun extractGUID(rawResult: String): String? { + if (rawResult.length > MAX_QR_CODE_LENGTH) return null + if (rawResult.count { it == GUID_SEPARATOR } != 1) return null + if (!QR_CODE_REGEX.toRegex().matches(rawResult)) return null + + val potentialGUID = rawResult.substringAfterLast(GUID_SEPARATOR, "") + if (potentialGUID.isBlank() || potentialGUID.length > MAX_GUID_LENGTH) return null + + return potentialGUID + } + + companion object { + // regex pattern for scanned QR code URL + val QR_CODE_REGEX: Pattern = Pattern.compile( + "^((^https:\\/{2}localhost)(\\/\\?)[A-Fa-f0-9]{6}" + + "[-][A-Fa-f0-9]{8}[-][A-Fa-f0-9]{4}[-][A-Fa-f0-9]{4}[-][A-Fa-f0-9]{4}[-][A-Fa-f0-9]{12})\$" + ) + const val GUID_SEPARATOR = '?' + const val MAX_QR_CODE_LENGTH = 150 + const val MAX_GUID_LENGTH = 80 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt deleted file mode 100644 index 4ab4045084e1622f85f212ac4909f25a604ae984..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt +++ /dev/null @@ -1,56 +0,0 @@ -package de.rki.coronawarnapp.service.submission - -object SubmissionConstants { - private const val VERSION = "version" - private const val REGISTRATION_TOKEN = "registrationToken" - private const val TEST_RESULT = "testresult" - private const val TAN = "tan" - - private var CURRENT_VERSION = "v1" - - private val VERSIONED_VERIFICATION_CDN_URL = "$VERSION/$CURRENT_VERSION" - - val REGISTRATION_TOKEN_URL = "$VERSIONED_VERIFICATION_CDN_URL/$REGISTRATION_TOKEN" - val TEST_RESULT_URL = "$VERSIONED_VERIFICATION_CDN_URL/$TEST_RESULT" - val TAN_REQUEST_URL = "$VERSIONED_VERIFICATION_CDN_URL/$TAN" - - const val MAX_QR_CODE_LENGTH = 150 - const val MAX_GUID_LENGTH = 80 - const val GUID_SEPARATOR = '?' - - const val SERVER_ERROR_CODE_400 = 400 - - const val EMPTY_HEADER = "" - - // padding registration token - private const val VERIFICATION_BODY_FILL = 139 - - const val PADDING_LENGTH_HEADER_REGISTRATION_TOKEN = 0 - const val PADDING_LENGTH_BODY_REGISTRATION_TOKEN_TELETAN = 51 + VERIFICATION_BODY_FILL - const val PADDING_LENGTH_BODY_REGISTRATION_TOKEN_GUID = 0 + VERIFICATION_BODY_FILL - - // padding test result - const val PADDING_LENGTH_HEADER_TEST_RESULT = 7 - const val PADDING_LENGTH_BODY_TEST_RESULT = 31 + VERIFICATION_BODY_FILL - - // padding tan - const val PADDING_LENGTH_HEADER_TAN = 14 - const val PADDING_LENGTH_BODY_TAN = 31 + VERIFICATION_BODY_FILL - const val PADDING_LENGTH_BODY_TAN_FAKE = 31 + VERIFICATION_BODY_FILL - const val DUMMY_REGISTRATION_TOKEN = "11111111-2222-4444-8888-161616161616" - - const val PADDING_LENGTH_HEADER_SUBMISSION_FAKE = 36 - - const val probabilityToExecutePlaybookWhenOpenApp = 0f - const val minNumberOfSequentialPlaybooks = 1 - const val maxNumberOfSequentialPlaybooks = 1 - const val minDelayBetweenSequentialPlaybooks = 0 - const val maxDelayBetweenSequentialPlaybooks = 0 - - const val minKeyCountForSubmission = 14 - const val fakeKeySize = (1 * 16 /* key data*/) + (3 * 4 /* 3x int32*/) -} - -enum class KeyType { - GUID, TELETAN; -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt index 10dc0ec346f03304eb595d526ccbc11c328d0402..be711b0ae28bdf4ac9b2d804691e45c80bd4cd8c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt @@ -3,16 +3,22 @@ package de.rki.coronawarnapp.service.submission import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import de.rki.coronawarnapp.exception.NoGUIDOrTANSetException import de.rki.coronawarnapp.exception.NoRegistrationTokenSetException -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.http.playbook.BackgroundNoise -import de.rki.coronawarnapp.http.playbook.PlaybookImpl +import de.rki.coronawarnapp.playbook.BackgroundNoise +import de.rki.coronawarnapp.playbook.Playbook import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.submission.Symptoms import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction +import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.util.formatter.TestResult +import de.rki.coronawarnapp.verification.server.VerificationKeyType import de.rki.coronawarnapp.worker.BackgroundWorkScheduler object SubmissionService { + private val playbook: Playbook + get() = AppInjector.component.playbook + suspend fun asyncRegisterDevice() { val testGUID = LocalData.testGUID() val testTAN = LocalData.teletan() @@ -27,54 +33,47 @@ object SubmissionService { } private suspend fun asyncRegisterDeviceViaGUID(guid: String) { - val registrationToken = - PlaybookImpl(WebRequestBuilder.getInstance()).initialRegistration( + val (registrationToken, testResult) = + playbook.initialRegistration( guid, - KeyType.GUID + VerificationKeyType.GUID ) LocalData.registrationToken(registrationToken) deleteTestGUID() + SubmissionRepository.updateTestResult(testResult) } private suspend fun asyncRegisterDeviceViaTAN(tan: String) { - val registrationToken = - PlaybookImpl(WebRequestBuilder.getInstance()).initialRegistration( + val (registrationToken, testResult) = + playbook.initialRegistration( tan, - KeyType.TELETAN + VerificationKeyType.TELETAN ) LocalData.registrationToken(registrationToken) deleteTeleTAN() + SubmissionRepository.updateTestResult(testResult) } - suspend fun asyncSubmitExposureKeys(keys: List<TemporaryExposureKey>) { + suspend fun asyncSubmitExposureKeys(keys: List<TemporaryExposureKey>, symptoms: Symptoms) { val registrationToken = LocalData.registrationToken() ?: throw NoRegistrationTokenSetException() - SubmitDiagnosisKeysTransaction.start(registrationToken, keys) + SubmitDiagnosisKeysTransaction.start(registrationToken, keys, symptoms) } suspend fun asyncRequestTestResult(): TestResult { val registrationToken = LocalData.registrationToken() ?: throw NoRegistrationTokenSetException() - return PlaybookImpl(WebRequestBuilder.getInstance()).testResult(registrationToken) + return playbook.testResult(registrationToken) } fun containsValidGUID(scanResult: String): Boolean { - if (scanResult.length > SubmissionConstants.MAX_QR_CODE_LENGTH || - scanResult.count { it == SubmissionConstants.GUID_SEPARATOR } != 1 - ) - return false - - val potentialGUID = extractGUID(scanResult) - - return !(potentialGUID.isEmpty() || potentialGUID.length > SubmissionConstants.MAX_GUID_LENGTH) + val scanResult = QRScanResult(scanResult) + return scanResult.isValid } - fun extractGUID(scanResult: String): String = - scanResult.substringAfterLast(SubmissionConstants.GUID_SEPARATOR, "") - fun storeTestGUID(guid: String) = LocalData.testGUID(guid) fun deleteTestGUID() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppDatabase.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppDatabase.kt index ce4640c15db065cd1bde1485ebaf723f3c43ab3d..454055162dc1c14c57945c1ae1b3e3b97f177631 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppDatabase.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppDatabase.kt @@ -7,27 +7,28 @@ import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.TypeConverters -import de.rki.coronawarnapp.storage.keycache.KeyCacheDao -import de.rki.coronawarnapp.storage.keycache.KeyCacheEntity -import de.rki.coronawarnapp.storage.keycache.KeyCacheRepository +import de.rki.coronawarnapp.diagnosiskeys.storage.legacy.KeyCacheLegacyDao +import de.rki.coronawarnapp.diagnosiskeys.storage.legacy.KeyCacheLegacyEntity import de.rki.coronawarnapp.storage.tracing.TracingIntervalDao import de.rki.coronawarnapp.storage.tracing.TracingIntervalEntity import de.rki.coronawarnapp.storage.tracing.TracingIntervalRepository -import de.rki.coronawarnapp.util.Converters +import de.rki.coronawarnapp.util.database.CommonConverters +import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.util.security.SecurityHelper +import kotlinx.coroutines.runBlocking import net.sqlcipher.database.SupportFactory import java.io.File @Database( - entities = [ExposureSummaryEntity::class, KeyCacheEntity::class, TracingIntervalEntity::class], + entities = [ExposureSummaryEntity::class, KeyCacheLegacyEntity::class, TracingIntervalEntity::class], version = 1, exportSchema = true ) -@TypeConverters(Converters::class) +@TypeConverters(CommonConverters::class) abstract class AppDatabase : RoomDatabase() { abstract fun exposureSummaryDao(): ExposureSummaryDao - abstract fun dateDao(): KeyCacheDao + abstract fun dateDao(): KeyCacheLegacyDao abstract fun tracingIntervalDao(): TracingIntervalDao companion object { @@ -54,7 +55,8 @@ abstract class AppDatabase : RoomDatabase() { resetInstance() // reset also the repo instances - KeyCacheRepository.resetInstance() + val keyRepository = AppInjector.component.keyCacheRepository + runBlocking { keyRepository.clear() } // TODO this is not nice TracingIntervalRepository.resetInstance() ExposureSummaryRepository.resetInstance() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppSettings.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppSettings.kt new file mode 100644 index 0000000000000000000000000000000000000000..c89378bffdc07c8cb218c5b1bbdbe884f8f3daff --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/AppSettings.kt @@ -0,0 +1,12 @@ +package de.rki.coronawarnapp.storage + +import de.rki.coronawarnapp.util.CWADebug +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AppSettings @Inject constructor() { + + val isLast3HourModeEnabled: Boolean + get() = LocalData.last3HoursMode() && CWADebug.isDebugBuildOrMode +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/DeviceStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/DeviceStorage.kt new file mode 100644 index 0000000000000000000000000000000000000000..412d5900f12b40b7dfff4b50163f5ef2351c03a6 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/DeviceStorage.kt @@ -0,0 +1,145 @@ +package de.rki.coronawarnapp.storage + +import android.annotation.TargetApi +import android.app.usage.StorageStatsManager +import android.content.Context +import android.os.Build +import android.os.storage.StorageManager +import android.text.format.Formatter +import dagger.Reusable +import de.rki.coronawarnapp.util.ApiLevel +import de.rki.coronawarnapp.util.storage.StatsFsProvider +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import timber.log.Timber +import java.io.File +import java.io.IOException +import java.util.UUID +import javax.inject.Inject + +@Reusable +class DeviceStorage @Inject constructor( + private val context: Context, + private val apiLevel: ApiLevel, + private val statsFsProvider: StatsFsProvider +) { + + private val privateStorage = context.filesDir + private val storageManager by lazy { context.getSystemService(Context.STORAGE_SERVICE) as StorageManager } + + @TargetApi(Build.VERSION_CODES.O) + private fun requestStorageAPI26Plus(targetPath: File, requiredBytes: Long = -1L): CheckResult { + Timber.tag(TAG).v( + "requestStorageAPI26Plus(path=%s, requiredBytes=%d)", targetPath, requiredBytes + + ) + val statsManager = + context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager + + val storageUUID: UUID = storageManager.getUuidForPath(targetPath) + + val totalBytes = statsManager.getTotalBytes(storageUUID) + var availableBytes = statsManager.getFreeBytes(storageUUID) + + if (availableBytes < requiredBytes) { + val allocatableBytes = storageManager.getAllocatableBytes(storageUUID) + if (allocatableBytes + availableBytes >= requiredBytes) { + val toAllocate = requiredBytes - availableBytes + Timber.tag(TAG).v( + "Not enough free space, allocating %d on %s.", requiredBytes, targetPath + ) + storageManager.allocateBytes(storageUUID, toAllocate) + availableBytes += toAllocate + } + } + + return CheckResult( + path = targetPath, + isSpaceAvailable = availableBytes >= requiredBytes || requiredBytes == -1L, + requiredBytes = requiredBytes, + freeBytes = availableBytes, + totalBytes = totalBytes + ) + } + + private fun requestStorageLegacy(targetPath: File, requiredBytes: Long = -1L): CheckResult { + Timber.tag(TAG).v( + "requestStorageAPI26Plus(path=%s, requiredBytes=%d)", targetPath, requiredBytes + ) + + val stats = statsFsProvider.createStats(targetPath) + + return CheckResult( + path = targetPath, + isSpaceAvailable = stats.availableBytes >= requiredBytes || requiredBytes == -1L, + requiredBytes = requiredBytes, + freeBytes = stats.availableBytes, + totalBytes = stats.totalBytes + ) + } + + private suspend fun checkSpace( + path: File, + requiredBytes: Long = -1L + ): CheckResult = withContext(Dispatchers.IO) { + try { + Timber.tag(TAG).v("checkSpace(path=%s, requiredBytes=%d)", path, requiredBytes) + val result: CheckResult = if (apiLevel.hasAPILevel(Build.VERSION_CODES.O)) { + try { + requestStorageAPI26Plus(path, requiredBytes) + } catch (e: Exception) { + Timber.tag(TAG).e(e, "requestStorageAPI26Plus() failed") + requestStorageLegacy(path, requiredBytes) + } + } else { + requestStorageLegacy(path, requiredBytes) + } + + Timber.tag(TAG).d("Requested %d from %s: %s", requiredBytes, path, result) + return@withContext result + } catch (e: Exception) { + throw IOException("checkSpace(path=$path, requiredBytes=$requiredBytes) FAILED", e) + .also { Timber.tag(TAG).e(it) } + } + } + + /** + * Returns an **[CheckResult]** telling you how much private storage is available to us + * Pass **[requiredBytes]** if we should attempt to free space if not enough is available. + * This may cause the system to delete caches to free space. + * + * Don't call this on the UI thread as the operation may block due to IO. + * + * @throws IOException if storage check or allocation fails. + */ + suspend fun checkSpacePrivateStorage(requiredBytes: Long = -1L): CheckResult = + checkSpace(privateStorage, requiredBytes) + + /** + * Like **[checkSpacePrivateStorage]** but throws **[InsufficientStorageException]** + * if not enough is available + */ + suspend fun requireSpacePrivateStorage(requiredBytes: Long = -1L): CheckResult = + checkSpace(privateStorage, requiredBytes).apply { + if (!isSpaceAvailable) throw InsufficientStorageException(this) + } + + data class CheckResult( + val path: File, + val isSpaceAvailable: Boolean, + val requiredBytes: Long = -1L, + val freeBytes: Long, + val totalBytes: Long + ) { + + fun getFormattedFreeSpace(context: Context): String = + Formatter.formatShortFileSize(context, freeBytes) + + fun getFormattedTotalSpace(context: Context): String = + Formatter.formatShortFileSize(context, totalBytes) + } + + companion object { + val TAG = DeviceStorage::class.java.simpleName + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageConstants.kt deleted file mode 100644 index 9571157bb5f46f21dc511ebe3f7d96ad0a779fec..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageConstants.kt +++ /dev/null @@ -1,18 +0,0 @@ -package de.rki.coronawarnapp.storage - -/** - * The File Storage constants are used inside the FileStorageHelper - * - * @see FileStorageHelper - */ -object FileStorageConstants { - - /** Days to keep data in internal storage */ - const val DAYS_TO_KEEP: Long = 14 - - /** Size (Mb) threshold for free space check */ - const val FREE_SPACE_THRESHOLD = 15 - - /** Key export directory name in internal storage */ - const val KEY_EXPORT_DIRECTORY_NAME = "key-export" -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageHelper.kt deleted file mode 100644 index 44442e9e61db22babad2aeb451523e1d5e897292..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/FileStorageHelper.kt +++ /dev/null @@ -1,90 +0,0 @@ -package de.rki.coronawarnapp.storage - -import android.content.Context -import android.os.Build -import android.os.storage.StorageManager -import de.rki.coronawarnapp.CoronaWarnApplication -import de.rki.coronawarnapp.exception.NotEnoughSpaceOnDiskException -import timber.log.Timber -import java.io.File -import java.util.UUID -import java.util.concurrent.TimeUnit - -/** - * A helper class for file storage manipulation - * The helper uses externalised constants for readability. - * - * @see FileStorageConstants - */ -object FileStorageHelper { - - private val TAG: String? = FileStorageHelper::class.simpleName - private val TIME_TO_KEEP = TimeUnit.DAYS.toMillis(FileStorageConstants.DAYS_TO_KEEP) - private const val BYTES = 1048576 - - /** - * create the needed key export directory (recursively) - * - */ - fun initializeExportSubDirectory() = keyExportDirectory.mkdirs() - - /** - * Get key files export directory used to store all export files for the transaction - * Uses FileStorageConstants.KEY_EXPORT_DIRECTORY_NAME constant - * - * @return File of key export directory - */ - val keyExportDirectory = File( - CoronaWarnApplication.getAppContext().cacheDir, - FileStorageConstants.KEY_EXPORT_DIRECTORY_NAME - ) - - /** - * Checks if internal store has free memory. - * Threshold: FileStorageConstants.FREE_SPACE_THRESHOLD - * Bound to .usableSpace due to API level restrictions (minimum required level - 23) - */ - fun checkFileStorageFreeSpace() { - val availableSpace = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val storageManager = CoronaWarnApplication.getAppContext() - .getSystemService(Context.STORAGE_SERVICE) as StorageManager - val storageVolume = storageManager.primaryStorageVolume - val storageUUID = - UUID.fromString(storageVolume.uuid ?: StorageManager.UUID_DEFAULT.toString()) - storageManager.getAllocatableBytes(storageUUID) / BYTES - } else { - keyExportDirectory.usableSpace / BYTES - } - if (availableSpace < FileStorageConstants.FREE_SPACE_THRESHOLD) { - throw NotEnoughSpaceOnDiskException() - } - } - - fun getAllFilesInKeyExportDirectory(): List<File> { - return keyExportDirectory - .walk(FileWalkDirection.BOTTOM_UP) - .filter(File::isFile) - .toList() - } - - fun File.isOutdated(): Boolean = - (System.currentTimeMillis() - lastModified() > TIME_TO_KEEP) - - private fun File.checkAndRemove(): Boolean { - return if (exists() && isDirectory) { - deleteRecursively() - } else { - false - } - } - - // LOGGING - private fun logFileRemovalResult(fileName: String, result: Boolean) = - Timber.d("File $fileName was deleted: $result") - - private fun logAvailableSpace(availableSpace: Long) = - Timber.d("Available space: $availableSpace") - - private fun logInsufficientSpace(availableSpace: Long) = - Timber.e("Not enough free space! Required: ${FileStorageConstants.FREE_SPACE_THRESHOLD} Has: $availableSpace") -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/InsufficientStorageException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/InsufficientStorageException.kt new file mode 100644 index 0000000000000000000000000000000000000000..bb38a584438e3e1078078684667e7fa96da905d2 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/InsufficientStorageException.kt @@ -0,0 +1,20 @@ +package de.rki.coronawarnapp.storage + +import android.content.Context +import android.text.format.Formatter +import de.rki.coronawarnapp.util.FormattedError +import java.io.IOException + +class InsufficientStorageException( + val result: DeviceStorage.CheckResult +) : IOException( + "Not enough free space: ${result.requiredBytes}B are required and only ${result.freeBytes}B are available." +), FormattedError { + + override fun getFormattedError(context: Context): String { + val formattedRequired = Formatter.formatShortFileSize(context, result.requiredBytes) + val formattedFree = Formatter.formatShortFileSize(context, result.freeBytes) + // TODO Replace with localized message when the exception is logged via new error tracking. + return "Not enough free space: $formattedRequired are required and only $formattedFree are available." + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt index 889ab566942df188a9780255f3301afafc45daa3..30e0c58f6ea6006f10774524888d2b8c56795fc0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt @@ -18,6 +18,9 @@ object LocalData { private val TAG: String? = LocalData::class.simpleName + private const val PREFERENCE_INTEROPERABILITY_IS_USED_AT_LEAST_ONCE = + "preference_interoperability_is_used_at_least_once" + /**************************************************** * ONBOARDING DATA ****************************************************/ @@ -710,4 +713,21 @@ object LocalData { ****************************************************/ fun getSharedPreferenceInstance(): SharedPreferences = globalEncryptedSharedPreferencesInstance + + /**************************************************** + * INTEROPERABILITY + ****************************************************/ + + var isInteroperabilityShownAtLeastOnce: Boolean + get() { + return getSharedPreferenceInstance().getBoolean( + PREFERENCE_INTEROPERABILITY_IS_USED_AT_LEAST_ONCE, + false + ) + } + set(value) { + getSharedPreferenceInstance().edit { + putBoolean(PREFERENCE_INTEROPERABILITY_IS_USED_AT_LEAST_ONCE, value) + } + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SettingsRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SettingsRepository.kt index d556fb829201288fcb745ae453f6bc8cb84d8e4d..54c2f41509a6404770d42a4d3aad856622cd4570 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SettingsRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SettingsRepository.kt @@ -3,8 +3,10 @@ package de.rki.coronawarnapp.storage import android.content.Context import androidx.core.app.NotificationManagerCompat import androidx.lifecycle.MutableLiveData +import de.rki.coronawarnapp.util.BackgroundPrioritization import de.rki.coronawarnapp.util.ConnectivityHelper -import de.rki.coronawarnapp.util.PowerManagementHelper +import javax.inject.Inject +import javax.inject.Singleton /** * The Settings Repository maps all setting states from different sources to MutableLiveData. @@ -14,9 +16,11 @@ import de.rki.coronawarnapp.util.PowerManagementHelper * * @see LocalData */ -object SettingsRepository { - - private val TAG: String? = SettingsRepository::class.simpleName +@Singleton +class SettingsRepository @Inject constructor( + private val context: Context, + private val backgroundPrioritization: BackgroundPrioritization +) { // public mutable live data val isNotificationsEnabled = MutableLiveData(true) @@ -35,7 +39,7 @@ object SettingsRepository { * * @see LocalData */ - fun refreshNotificationsEnabled(context: Context) { + fun refreshNotificationsEnabled() { isNotificationsEnabled.value = NotificationManagerCompat.from(context).areNotificationsEnabled() } @@ -131,8 +135,7 @@ object SettingsRepository { /** * Refresh the current background priority state. */ - fun refreshBackgroundPriorityEnabled(context: Context) { - isBackgroundPriorityEnabled.value = - PowerManagementHelper.isIgnoringBatteryOptimizations(context) + fun refreshBackgroundPriorityEnabled() { + isBackgroundPriorityEnabled.value = backgroundPrioritization.isBackgroundActivityPrioritized } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SubmissionRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SubmissionRepository.kt index eb969441593d73076b13fb71e42a27490959829e..e241304e6a6a5bbeaca97ae517faf5ed3d4ae7a7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SubmissionRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/SubmissionRepository.kt @@ -13,8 +13,9 @@ object SubmissionRepository { val testResultReceivedDate = MutableLiveData(Date()) val deviceUIState = MutableLiveData(DeviceUIState.UNPAIRED) + private val testResult = MutableLiveData<TestResult?>(null) - suspend fun refreshUIState() { + suspend fun refreshUIState(refreshTestResult: Boolean) { var uiState = DeviceUIState.UNPAIRED if (LocalData.numberOfSuccessfulSubmissions() == 1) { @@ -25,7 +26,10 @@ object SubmissionRepository { LocalData.isAllowedToSubmitDiagnosisKeys() == true -> { DeviceUIState.PAIRED_POSITIVE } - else -> fetchTestResult() + refreshTestResult -> fetchTestResult() + else -> { + deriveUiState(testResult.value) + } } } } @@ -35,32 +39,42 @@ object SubmissionRepository { private suspend fun fetchTestResult(): DeviceUIState { try { val testResult = SubmissionService.asyncRequestTestResult() - if (testResult == TestResult.POSITIVE) { - LocalData.isAllowedToSubmitDiagnosisKeys(true) - } + updateTestResult(testResult) + return deriveUiState(testResult) + } catch (err: NoRegistrationTokenSetException) { + return DeviceUIState.UNPAIRED + } + } - val initialTestResultReceivedTimestamp = LocalData.initialTestResultReceivedTimestamp() + fun updateTestResult(testResult: TestResult) { + this.testResult.value = testResult - if (initialTestResultReceivedTimestamp == null) { - val currentTime = System.currentTimeMillis() - LocalData.initialTestResultReceivedTimestamp(currentTime) - testResultReceivedDate.value = Date(currentTime) - if (testResult == TestResult.PENDING) { - BackgroundWorkScheduler.startWorkScheduler() - } - } else { - testResultReceivedDate.value = Date(initialTestResultReceivedTimestamp) - } + if (testResult == TestResult.POSITIVE) { + LocalData.isAllowedToSubmitDiagnosisKeys(true) + } + + val initialTestResultReceivedTimestamp = LocalData.initialTestResultReceivedTimestamp() - return when (testResult) { - TestResult.NEGATIVE -> DeviceUIState.PAIRED_NEGATIVE - TestResult.POSITIVE -> DeviceUIState.PAIRED_POSITIVE - TestResult.PENDING -> DeviceUIState.PAIRED_NO_RESULT - TestResult.INVALID -> DeviceUIState.PAIRED_ERROR - TestResult.REDEEMED -> DeviceUIState.PAIRED_REDEEMED + if (initialTestResultReceivedTimestamp == null) { + val currentTime = System.currentTimeMillis() + LocalData.initialTestResultReceivedTimestamp(currentTime) + testResultReceivedDate.value = Date(currentTime) + if (testResult == TestResult.PENDING) { + BackgroundWorkScheduler.startWorkScheduler() } - } catch (err: NoRegistrationTokenSetException) { - return DeviceUIState.UNPAIRED + } else { + testResultReceivedDate.value = Date(initialTestResultReceivedTimestamp) + } + } + + private fun deriveUiState(testResult: TestResult?): DeviceUIState { + return when (testResult) { + TestResult.NEGATIVE -> DeviceUIState.PAIRED_NEGATIVE + TestResult.POSITIVE -> DeviceUIState.PAIRED_POSITIVE + TestResult.PENDING -> DeviceUIState.PAIRED_NO_RESULT + TestResult.REDEEMED -> DeviceUIState.PAIRED_REDEEMED + TestResult.INVALID -> DeviceUIState.PAIRED_ERROR + null -> DeviceUIState.UNPAIRED } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/interoperability/InteroperabilityRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/interoperability/InteroperabilityRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..90768259c610867b8e66e7a53e00bb9e25bb501f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/interoperability/InteroperabilityRepository.kt @@ -0,0 +1,55 @@ +package de.rki.coronawarnapp.storage.interoperability + +import android.text.TextUtils +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Transformations +import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.ui.Country +import kotlinx.coroutines.runBlocking +import timber.log.Timber +import java.util.Locale +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class InteroperabilityRepository @Inject constructor( + private val appConfigProvider: AppConfigProvider +) { + + fun saveInteroperabilityUsed() { + LocalData.isInteroperabilityShownAtLeastOnce = true + } + + private val _countryList: MutableLiveData<List<Country>> = MutableLiveData(listOf()) + val countryList = Transformations.distinctUntilChanged(_countryList) + + init { + getAllCountries() + } + + /** + * Gets all countries from @see ApplicationConfigurationService.asyncRetrieveApplicationConfiguration + * Also changes every country code to lower case + */ + fun getAllCountries() { + runBlocking { + try { + val countries = appConfigProvider.getAppConfig() + .supportedCountriesList + .mapNotNull { rawCode -> + val countryCode = rawCode.toLowerCase(Locale.ROOT) + + val mappedCountry = Country.values().singleOrNull { it.code == countryCode } + if (mappedCountry == null) Timber.e("Unknown countrycode: %s", rawCode) + mappedCountry + } + _countryList.postValue(countries) + Timber.d("Country list: ${TextUtils.join(System.lineSeparator(), countries)}") + } catch (e: Exception) { + Timber.e(e) + _countryList.postValue(listOf()) + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheDao.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheDao.kt deleted file mode 100644 index 0e6cbeadb1b6f5e2f6b5c06b6668ad3a80fab963..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheDao.kt +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * Corona-Warn-App * - * * - * SAP SE and all other contributors / * - * copyright owners license this file to you under the Apache * - * License, Version 2.0 (the "License"); you may not use this * - * file except in compliance with the License. * - * You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ******************************************************************************/ - -package de.rki.coronawarnapp.storage.keycache - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.Query - -@Dao -interface KeyCacheDao { - @Query("SELECT * FROM date WHERE type=0") - suspend fun getDates(): List<KeyCacheEntity> - - @Query("SELECT * FROM date WHERE type=1") - suspend fun getHours(): List<KeyCacheEntity> - - @Query("SELECT * FROM date") - suspend fun getAllEntries(): List<KeyCacheEntity> - - @Query("SELECT * FROM date WHERE id IN (:idList)") - suspend fun getAllEntries(idList: List<String>): List<KeyCacheEntity> - - @Query("DELETE FROM date") - suspend fun clear() - - @Query("DELETE FROM date WHERE type=1") - suspend fun clearHours() - - @Delete - suspend fun deleteEntry(entity: KeyCacheEntity) - - @Delete - suspend fun deleteEntries(entities: List<KeyCacheEntity>) - - @Insert - suspend fun insertEntry(keyCacheEntity: KeyCacheEntity): Long -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheRepository.kt deleted file mode 100644 index dd6b6425d39da8b125aac2b520d3e9f5f3ee7d5b..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/keycache/KeyCacheRepository.kt +++ /dev/null @@ -1,103 +0,0 @@ -/****************************************************************************** - * Corona-Warn-App * - * * - * SAP SE and all other contributors / * - * copyright owners license this file to you under the Apache * - * License, Version 2.0 (the "License"); you may not use this * - * file except in compliance with the License. * - * You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ******************************************************************************/ - -package de.rki.coronawarnapp.storage.keycache - -import android.content.Context -import de.rki.coronawarnapp.storage.AppDatabase -import timber.log.Timber -import java.io.File -import java.net.URI - -class KeyCacheRepository(private val keyCacheDao: KeyCacheDao) { - companion object { - @Volatile - private var instance: KeyCacheRepository? = null - - private fun getInstance(keyCacheDao: KeyCacheDao) = - instance ?: synchronized(this) { - instance - ?: KeyCacheRepository(keyCacheDao) - .also { instance = it } - } - - fun resetInstance() = synchronized(this) { - instance = null - } - - fun getDateRepository(context: Context): KeyCacheRepository { - return getInstance( - AppDatabase.getInstance(context.applicationContext) - .dateDao() - ) - } - } - - enum class DateEntryType { - DAY, - HOUR - } - - suspend fun createEntry(key: String, uri: URI, type: DateEntryType) = keyCacheDao.insertEntry( - KeyCacheEntity().apply { - this.id = key - this.path = uri.rawPath - this.type = type.ordinal - } - ) - - suspend fun deleteOutdatedEntries(validEntries: List<String>) = - keyCacheDao.getAllEntries().forEach { - Timber.v("valid entries for cache from server: $validEntries") - val file = File(it.path) - if (!validEntries.contains(it.id) || !file.exists()) { - Timber.w("${it.id} will be deleted from the cache") - deleteFileForEntry(it) - keyCacheDao.deleteEntry(it) - } - } - - private fun deleteFileForEntry(entry: KeyCacheEntity) = File(entry.path).delete() - - suspend fun getDates() = keyCacheDao.getDates() - suspend fun getHours() = keyCacheDao.getHours() - - suspend fun clearHours() { - getHours().forEach { deleteFileForEntry(it) } - keyCacheDao.clearHours() - } - - suspend fun clear() { - keyCacheDao.getAllEntries().forEach { deleteFileForEntry(it) } - keyCacheDao.clear() - } - - suspend fun clear(idList: List<String>) { - if (idList.isNotEmpty()) { - val entries = keyCacheDao.getAllEntries(idList) - entries.forEach { deleteFileForEntry(it) } - keyCacheDao.deleteEntries(entries) - } - } - - suspend fun getFilesFromEntries() = keyCacheDao - .getAllEntries() - .map { File(it.path) } - .filter { it.exists() } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/tracing/TracingIntervalRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/tracing/TracingIntervalRepository.kt index 0f34787c36abdac94c4c5dccce2270b19895c83a..2daf3d847bed99a233c2292a0672f90b281b1c78 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/tracing/TracingIntervalRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/tracing/TracingIntervalRepository.kt @@ -66,7 +66,7 @@ class TracingIntervalRepository(private val tracingIntervalDao: TracingIntervalD return tracingIntervalDao .getAllIntervals() - .map { Pair(maxOf(it.from, retentionTimestamp), it.to) } + .map { Pair(it.from, it.to) } .also { Timber.d("Intervals: $it") } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVector.kt new file mode 100644 index 0000000000000000000000000000000000000000..825fa48362bd491d325a78e16a2ff61723c62726 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVector.kt @@ -0,0 +1,3 @@ +package de.rki.coronawarnapp.submission + +typealias DaysSinceOnsetOfSymptomsVector = IntArray diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVectorDeterminator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVectorDeterminator.kt new file mode 100644 index 0000000000000000000000000000000000000000..e7a6c4179315a9f031c59ae5d97094ed5f7894b4 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVectorDeterminator.kt @@ -0,0 +1,59 @@ +package de.rki.coronawarnapp.submission + +import dagger.Reusable +import de.rki.coronawarnapp.util.TimeAndDateExtensions.ageInDays +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDate +import de.rki.coronawarnapp.util.TimeStamper +import javax.inject.Inject + +/** + * The determination of the values for days since onset of symptoms follows the documentation + * described in great detail in this tech spec: + * https://github.com/corona-warn-app/cwa-app-tech-spec/blob/master/docs/spec/days-since-onset-of-symptoms.md + */ +@Reusable +class DaysSinceOnsetOfSymptomsVectorDeterminator @Inject constructor( + private val timeStamper: TimeStamper +) { + + @Suppress("MagicNumber") + internal fun determine(symptoms: Symptoms): DaysSinceOnsetOfSymptomsVector { + return when (symptoms.symptomIndication) { + Symptoms.Indication.POSITIVE -> + determinePositiveIndication(symptoms) + Symptoms.Indication.NO_INFORMATION -> + createDaysSinceOnsetOfSymptomsVectorWith(4000) + Symptoms.Indication.NEGATIVE -> + createDaysSinceOnsetOfSymptomsVectorWith(3000) + } + } + + @Suppress("MagicNumber") + private fun determinePositiveIndication(symptoms: Symptoms): DaysSinceOnsetOfSymptomsVector { + return when (symptoms.startOfSymptoms) { + is Symptoms.StartOf.Date -> + createDaysSinceOnsetOfSymptomsVectorWith( + symptoms.startOfSymptoms.date.ageInDays(timeStamper.nowUTC.toLocalDate()) + ) + is Symptoms.StartOf.LastSevenDays -> + createDaysSinceOnsetOfSymptomsVectorWith(701) + is Symptoms.StartOf.OneToTwoWeeksAgo -> + createDaysSinceOnsetOfSymptomsVectorWith(708) + is Symptoms.StartOf.MoreThanTwoWeeks -> + createDaysSinceOnsetOfSymptomsVectorWith(715) + else -> + createDaysSinceOnsetOfSymptomsVectorWith(2000) + } + } + + private fun createDaysSinceOnsetOfSymptomsVectorWith( + submissionDayValue: Int, + size: Int = VECTOR_LENGTH + ): DaysSinceOnsetOfSymptomsVector { + return (submissionDayValue downTo (submissionDayValue - size + 1)).toList().toIntArray() + } + + companion object { + private const val VECTOR_LENGTH = 15 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DefaultKeyConverter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DefaultKeyConverter.kt new file mode 100644 index 0000000000000000000000000000000000000000..cd1cb36f8fc7da563e9bcc79706a3c34af26f657 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/DefaultKeyConverter.kt @@ -0,0 +1,23 @@ +package de.rki.coronawarnapp.submission + +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import com.google.protobuf.ByteString +import de.rki.coronawarnapp.server.protocols.KeyExportFormat +import dagger.Reusable +import javax.inject.Inject + +@Reusable +class DefaultKeyConverter @Inject constructor() : KeyConverter { + override fun toExternalFormat( + key: TemporaryExposureKey, + riskValue: Int, + daysSinceOnsetOfSymptoms: Int + ) = + KeyExportFormat.TemporaryExposureKey.newBuilder() + .setKeyData(ByteString.readFrom(key.keyData.inputStream())) + .setRollingStartIntervalNumber(key.rollingStartIntervalNumber) + .setRollingPeriod(key.rollingPeriod) + .setTransmissionRiskLevel(riskValue) + .setDaysSinceOnsetOfSymptoms(daysSinceOnsetOfSymptoms) + .build() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculations.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculations.kt new file mode 100644 index 0000000000000000000000000000000000000000..86a03c65231fea54767c35b374ebd6042e692b26 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculations.kt @@ -0,0 +1,74 @@ +package de.rki.coronawarnapp.submission + +import androidx.annotation.VisibleForTesting +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.server.protocols.KeyExportFormat +import de.rki.coronawarnapp.util.TimeAndDateExtensions.ageInDays +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDate +import de.rki.coronawarnapp.util.TimeStamper +import org.joda.time.Duration +import org.joda.time.Instant +import org.joda.time.LocalDate +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ExposureKeyHistoryCalculations @Inject constructor( + private val transmissionRiskVectorDeterminator: TransmissionRiskVectorDeterminator, + private val daysSinceOnsetOfSymptomsVectorDeterminator: DaysSinceOnsetOfSymptomsVectorDeterminator, + private val keyConverter: KeyConverter, + private val timeStamper: TimeStamper +) { + + fun transformToKeyHistoryInExternalFormat( + keys: List<TemporaryExposureKey>, + symptoms: Symptoms + ) = toExternalFormat( + removeOldKeys(sortWithRecentKeyFirst(keys)), + transmissionRiskVectorDeterminator.determine(symptoms), + daysSinceOnsetOfSymptomsVectorDeterminator.determine(symptoms) + ) + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun removeOldKeys( + keys: List<TemporaryExposureKey>, + now: LocalDate = timeStamper.nowUTC.toLocalDate() + ) = keys.filter { it.ageInDays(now) in 0..MAX_AGE_IN_DAYS } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun toExternalFormat( + keys: List<TemporaryExposureKey>, + transmissionRiskVector: TransmissionRiskVector, + daysSinceOnsetOfSymptomsVector: DaysSinceOnsetOfSymptomsVector, + now: LocalDate = timeStamper.nowUTC.toLocalDate() + ): List<KeyExportFormat.TemporaryExposureKey> { + val result = mutableListOf<KeyExportFormat.TemporaryExposureKey>() + keys.groupBy { it.ageInDays(now) }.forEach { entry -> + val ageInDays = entry.key + entry.value.forEach { + result.add( + keyConverter.toExternalFormat( + it, + transmissionRiskVector[ageInDays], + daysSinceOnsetOfSymptomsVector[ageInDays] + ) + ) + } + } + return result.toList() + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun sortWithRecentKeyFirst(keys: List<TemporaryExposureKey>) = + keys.sortedWith(compareByDescending { it.rollingStartIntervalNumber }) + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun TemporaryExposureKey.ageInDays(now: LocalDate): Int = + Instant.ofEpochMilli(rollingStartIntervalNumber * TEN_MINUTES_IN_MILLIS) + .toLocalDate().ageInDays(now) + + companion object { + const val MAX_AGE_IN_DAYS = 14 + val TEN_MINUTES_IN_MILLIS = Duration.standardMinutes(10).millis + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/KeyConverter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/KeyConverter.kt new file mode 100644 index 0000000000000000000000000000000000000000..d30b291d409022b8af2ca1f61087c2c5deaf34c4 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/KeyConverter.kt @@ -0,0 +1,13 @@ +package de.rki.coronawarnapp.submission + +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.server.protocols.KeyExportFormat + +interface KeyConverter { + + fun toExternalFormat( + key: TemporaryExposureKey, + riskValue: Int, + daysSinceOnsetOfSymptoms: Int + ): KeyExportFormat.TemporaryExposureKey +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..437d565d657aa7035b039d102e247bff779f6ee8 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionModule.kt @@ -0,0 +1,65 @@ +package de.rki.coronawarnapp.submission + +import android.content.Context +import dagger.Module +import dagger.Provides +import dagger.Reusable +import de.rki.coronawarnapp.environment.submission.SubmissionCDNServerUrl +import de.rki.coronawarnapp.http.HttpClientDefault +import de.rki.coronawarnapp.http.RestrictedConnectionSpecs +import de.rki.coronawarnapp.submission.server.SubmissionApiV1 +import de.rki.coronawarnapp.submission.server.SubmissionHttpClient +import okhttp3.Cache +import okhttp3.ConnectionSpec +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.converter.protobuf.ProtoConverterFactory +import java.io.File +import javax.inject.Singleton + +@Module +class SubmissionModule { + + @Reusable + @SubmissionHttpClient + @Provides + fun cdnHttpClient( + @HttpClientDefault defaultHttpClient: OkHttpClient, + @RestrictedConnectionSpecs connectionSpecs: List<ConnectionSpec> + ): OkHttpClient = + defaultHttpClient.newBuilder().connectionSpecs(connectionSpecs).build() + + @Singleton + @Provides + fun provideSubmissionApi( + context: Context, + @SubmissionHttpClient client: OkHttpClient, + @SubmissionCDNServerUrl url: String, + protoConverterFactory: ProtoConverterFactory, + gsonConverterFactory: GsonConverterFactory + ): SubmissionApiV1 { + val cache = Cache(File(context.cacheDir, "http_submission"), DEFAULT_CACHE_SIZE) + + val cachingClient = client.newBuilder().apply { + cache(cache) + }.build() + + return Retrofit.Builder() + .client(cachingClient) + .baseUrl(url) + .addConverterFactory(protoConverterFactory) + .addConverterFactory(gsonConverterFactory) + .build() + .create(SubmissionApiV1::class.java) + } + + @Singleton + @Provides + fun provideKeyConverter(defaultKeyConverter: DefaultKeyConverter): KeyConverter = + defaultKeyConverter + + companion object { + private const val DEFAULT_CACHE_SIZE = 5 * 1024 * 1024L // 5MB + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt new file mode 100644 index 0000000000000000000000000000000000000000..13e80e20a5f75dd4014b4f7597914124338ed71f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/Symptoms.kt @@ -0,0 +1,23 @@ +package de.rki.coronawarnapp.submission + +import org.joda.time.LocalDate + +data class Symptoms( + val startOfSymptoms: StartOf?, + val symptomIndication: Indication +) { + sealed class StartOf { + + data class Date(val date: LocalDate) : StartOf() + object LastSevenDays : StartOf() + object OneToTwoWeeksAgo : StartOf() + object MoreThanTwoWeeks : StartOf() + object NoInformation : StartOf() + } + + enum class Indication { + POSITIVE, + NEGATIVE, + NO_INFORMATION + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVector.kt new file mode 100644 index 0000000000000000000000000000000000000000..f3a09fff76bdb0ce63e4207ba388050b7cfe795a --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVector.kt @@ -0,0 +1,14 @@ +package de.rki.coronawarnapp.submission + +class TransmissionRiskVector(private val values: IntArray) { + + val raw: IntArray + get() = values + + operator fun get(index: Int) = + if (index < values.size) values[index] else DEFAULT_TRANSMISSION_RISK_LEVEL + + companion object { + private const val DEFAULT_TRANSMISSION_RISK_LEVEL = 1 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminator.kt new file mode 100644 index 0000000000000000000000000000000000000000..fc87a8785cf97ffd3adbe18d82e4a04aa626d3ee --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminator.kt @@ -0,0 +1,56 @@ +package de.rki.coronawarnapp.submission + +import dagger.Reusable +import de.rki.coronawarnapp.submission.Symptoms.Indication +import de.rki.coronawarnapp.submission.Symptoms.StartOf +import de.rki.coronawarnapp.util.TimeAndDateExtensions.ageInDays +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDate +import de.rki.coronawarnapp.util.TimeStamper +import org.joda.time.LocalDate +import javax.inject.Inject + +@Reusable +class TransmissionRiskVectorDeterminator @Inject constructor( + private val timeStamper: TimeStamper +) { + + @Suppress("MagicNumber") + fun determine(symptoms: Symptoms, now: LocalDate = timeStamper.nowUTC.toLocalDate()) = TransmissionRiskVector( + when (symptoms.symptomIndication) { + Indication.POSITIVE -> when (symptoms.startOfSymptoms) { + is StartOf.Date -> { + when (symptoms.startOfSymptoms.date.ageInDays(now)) { + 0 -> intArrayOf(8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1) + 1 -> intArrayOf(8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1) + 2 -> intArrayOf(6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1, 1) + 3 -> intArrayOf(5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1) + 4 -> intArrayOf(3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1) + 5 -> intArrayOf(2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1) + 6 -> intArrayOf(2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1) + 7 -> intArrayOf(1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1) + 8 -> intArrayOf(1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1) + 9 -> intArrayOf(1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2) + 10 -> intArrayOf(1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6, 4) + 11 -> intArrayOf(1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7, 6) + 12 -> intArrayOf(1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8, 7) + 13 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8, 8) + 14 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8, 8) + 15 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6, 8) + 16 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 6) + 17 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5) + 18 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3) + 19 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2) + 20 -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2) + else -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) + } + } + is StartOf.LastSevenDays -> intArrayOf(4, 5, 6, 7, 7, 7, 6, 5, 4, 3, 2, 1, 1, 1, 1) + is StartOf.MoreThanTwoWeeks -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5) + is StartOf.NoInformation -> intArrayOf(5, 6, 8, 8, 8, 7, 5, 3, 2, 1, 1, 1, 1, 1, 1) + is StartOf.OneToTwoWeeksAgo -> intArrayOf(1, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 6, 6, 4) + else -> intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) + } + Indication.NEGATIVE -> intArrayOf(4, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) + Indication.NO_INFORMATION -> intArrayOf(5, 6, 7, 7, 7, 6, 4, 3, 2, 1, 1, 1, 1, 1, 1) + }) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/SubmissionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionApiV1.kt similarity index 62% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/SubmissionService.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionApiV1.kt index a2092edea1a5456b5f8949d1ae7afdd8ad595eda..ebb23fe4e97e91070e49d64f3d792f48ad076c1a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/http/service/SubmissionService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionApiV1.kt @@ -1,19 +1,17 @@ -package de.rki.coronawarnapp.http.service +package de.rki.coronawarnapp.submission.server -import KeyExportFormat -import okhttp3.ResponseBody +import de.rki.coronawarnapp.server.protocols.KeyExportFormat import retrofit2.http.Body import retrofit2.http.Header import retrofit2.http.POST -import retrofit2.http.Url -interface SubmissionService { - @POST +interface SubmissionApiV1 { + + @POST("version/v1/diagnosis-keys") suspend fun submitKeys( - @Url url: String, @Header("cwa-authorization") authCode: String?, @Header("cwa-fake") fake: String, @Header("cwa-header-padding") headerPadding: String?, @Body requestBody: KeyExportFormat.SubmissionPayload - ): ResponseBody + ) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionHttpClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionHttpClient.kt new file mode 100644 index 0000000000000000000000000000000000000000..d7c83b129573eff9c62d5f602826fa1eea68ca79 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionHttpClient.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.submission.server + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class SubmissionHttpClient diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionServer.kt new file mode 100644 index 0000000000000000000000000000000000000000..a8c41429d38285a4d8f479905c4db7a610a31443 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/server/SubmissionServer.kt @@ -0,0 +1,85 @@ +package de.rki.coronawarnapp.submission.server + +import com.google.protobuf.ByteString +import dagger.Lazy +import de.rki.coronawarnapp.server.protocols.KeyExportFormat +import de.rki.coronawarnapp.util.PaddingTool.requestPadding +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.max + +@Singleton +class SubmissionServer @Inject constructor( + private val submissionApi: Lazy<SubmissionApiV1> +) { + + private val api: SubmissionApiV1 + get() = submissionApi.get() + + data class SubmissionData( + val authCode: String, + val keyList: List<KeyExportFormat.TemporaryExposureKey>, + val consentToFederation: Boolean, + val visistedCountries: List<String> + ) + + suspend fun submitKeysToServer( + data: SubmissionData + ) = withContext(Dispatchers.IO) { + Timber.d("submitKeysToServer()") + val authCode = data.authCode + val keyList = data.keyList + Timber.d("Writing ${keyList.size} Keys to the Submission Payload.") + + val randomAdditions = 0 // prepare for random addition of keys + val fakeKeyCount = max( + MIN_KEY_COUNT_FOR_SUBMISSION + randomAdditions - keyList.size, + 0 + ) + val fakeKeyPadding = requestPadding(FAKE_KEY_SIZE * fakeKeyCount) + + val submissionPayload = KeyExportFormat.SubmissionPayload.newBuilder() + .addAllKeys(keyList) + .setPadding(ByteString.copyFromUtf8(fakeKeyPadding)) + .setConsentToFederation(data.consentToFederation) + .addAllVisitedCountries(data.visistedCountries) + .build() + + api.submitKeys( + authCode = authCode, + fake = "0", + headerPadding = EMPTY_HEADER, + requestBody = submissionPayload + ) + } + + suspend fun submitKeysToServerFake() = withContext(Dispatchers.IO) { + Timber.d("submitKeysToServerFake()") + + val randomAdditions = 0 // prepare for random addition of keys + val fakeKeyCount = MIN_KEY_COUNT_FOR_SUBMISSION + randomAdditions + + val fakeKeyPadding = requestPadding(FAKE_KEY_SIZE * fakeKeyCount) + + val submissionPayload = KeyExportFormat.SubmissionPayload.newBuilder() + .setPadding(ByteString.copyFromUtf8(fakeKeyPadding)) + .build() + + api.submitKeys( + authCode = EMPTY_HEADER, + fake = "1", + headerPadding = requestPadding(PADDING_LENGTH_HEADER_SUBMISSION_FAKE), + requestBody = submissionPayload + ) + } + + companion object { + const val EMPTY_HEADER = "" + const val PADDING_LENGTH_HEADER_SUBMISSION_FAKE = 36 + const val MIN_KEY_COUNT_FOR_SUBMISSION = 14 + const val FAKE_KEY_SIZE = (1 * 16 /* key data*/) + (3 * 4 /* 3x int32*/) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/timer/TimerHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/timer/TimerHelper.kt index 6212810fa0b875c2866ac84c76d96e013cdea90e..96c90c0f6beb744030269b9f6268694af52c425c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/timer/TimerHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/timer/TimerHelper.kt @@ -4,6 +4,7 @@ import de.rki.coronawarnapp.BuildConfig import de.rki.coronawarnapp.risk.TimeVariables import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.SettingsRepository +import de.rki.coronawarnapp.util.di.AppInjector import org.joda.time.DateTime import org.joda.time.DateTimeZone import org.joda.time.Instant @@ -48,6 +49,10 @@ object TimerHelper { */ private const val INITIAL_TIMER_DELAY = 0L + private val settingsRepository by lazy { + AppInjector.component.settingsRepository + } + /** * Get cooldown time left between last time update button was triggered and current time * @@ -103,7 +108,7 @@ object TimerHelper { } } if (!isManualKeyRetrievalOnTimer.get()) { - SettingsRepository.updateManualKeyRetrievalEnabled(true) + settingsRepository.updateManualKeyRetrievalEnabled(true) } } @@ -115,13 +120,12 @@ object TimerHelper { * @see getManualKeyRetrievalTimeLeft * @see SettingsRepository.updateManualKeyRetrievalEnabled * @see SettingsRepository.updateManualKeyRetrievalTime - * @see de.rki.coronawarnapp.util.TimeAndDateExtensions.millisecondsToHMS */ private fun onManualKeyRetrievalTimerTick() { val timeDifference = getManualKeyRetrievalTimeLeft() val result = timeDifference <= 0 - SettingsRepository.updateManualKeyRetrievalEnabled(result) - SettingsRepository.updateManualKeyRetrievalTime(timeDifference) + settingsRepository.updateManualKeyRetrievalEnabled(result) + settingsRepository.updateManualKeyRetrievalTime(timeDifference) if (result) stopManualKeyRetrievalTimer() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisInjectionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisInjectionHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..5d118d7e7e252f580cd9d87ebd0dfb642f9364e7 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisInjectionHelper.kt @@ -0,0 +1,16 @@ +package de.rki.coronawarnapp.transaction + +import de.rki.coronawarnapp.environment.EnvironmentSetup +import de.rki.coronawarnapp.nearby.ENFClient +import de.rki.coronawarnapp.util.GoogleAPIVersion +import javax.inject.Inject +import javax.inject.Singleton + +// TODO Remove once we have refactored the transaction and it's no longer a singleton +@Singleton +data class RetrieveDiagnosisInjectionHelper @Inject constructor( + val transactionScope: TransactionCoroutineScope, + val googleAPIVersion: GoogleAPIVersion, + val cwaEnfClient: ENFClient, + val environmentSetup: EnvironmentSetup +) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransaction.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransaction.kt index 247d9f74272866d32ee703e1877092a5e8607d10..036905b788a065b9b14684da8811ad8b42bd32f4 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransaction.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransaction.kt @@ -20,9 +20,13 @@ package de.rki.coronawarnapp.transaction import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration +import de.rki.coronawarnapp.diagnosiskeys.download.KeyFileDownloader +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.environment.EnvironmentSetup +import de.rki.coronawarnapp.nearby.ENFClient import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService -import de.rki.coronawarnapp.storage.FileStorageHelper import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.API_SUBMISSION import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.CLOSE @@ -33,7 +37,8 @@ import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.Retriev import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.RetrieveDiagnosisKeysTransactionState.TOKEN import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.rollback import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.start -import de.rki.coronawarnapp.util.CachedKeyFileHolder +import de.rki.coronawarnapp.util.CWADebug +import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.worker.BackgroundWorkHelper import org.joda.time.DateTime import org.joda.time.DateTimeZone @@ -116,6 +121,28 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { /** atomic reference for the rollback value for created files during the transaction */ private val exportFilesForRollback = AtomicReference<List<File>>() + private val transactionScope: TransactionCoroutineScope by lazy { + AppInjector.component.transRetrieveKeysInjection.transactionScope + } + private val keyCacheRepository: KeyCacheRepository by lazy { + AppInjector.component.keyCacheRepository + } + private val keyFileDownloader: KeyFileDownloader by lazy { + AppInjector.component.keyFileDownloader + } + + var onApiSubmissionStarted: (() -> Unit)? = null + var onApiSubmissionFinished: (() -> Unit)? = null + + var onKeyFilesDownloadStarted: (() -> Unit)? = null + var onKeyFilesDownloadFinished: ((keyCount: Int, fileSize: Long) -> Unit)? = null + + private val enfClient: ENFClient + get() = AppInjector.component.transRetrieveKeysInjection.cwaEnfClient + + private val environmentSetup: EnvironmentSetup + get() = AppInjector.component.transRetrieveKeysInjection.environmentSetup + suspend fun startWithConstraints() { val currentDate = DateTime(Instant.now(), DateTimeZone.UTC) val lastFetch = DateTime( @@ -125,6 +152,7 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { if (LocalData.lastTimeDiagnosisKeysFromServerFetch() == null || currentDate.withTimeAtStartOfDay() != lastFetch.withTimeAtStartOfDay() ) { + Timber.tag(TAG).d("No keys fetched today yet (last=%s, now=%s)", lastFetch, currentDate) BackgroundWorkHelper.sendDebugNotification( "Start RetrieveDiagnosisKeysTransaction", "No keys fetched today yet \n${DateTime.now()}\nUTC: $currentDate" @@ -133,17 +161,23 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { } } - /** initiates the transaction. This suspend function guarantees a successful transaction once completed. */ - suspend fun start() = lockAndExecuteUnique { + /** initiates the transaction. This suspend function guarantees a successful transaction once completed. + * @param requestedCountries defines which countries (country codes) should be used. If not filled the + * country codes will be loaded from the ApplicationConfigurationService + */ + suspend fun start( + requestedCountries: List<String>? = null + ) = lockAndExecute(unique = true, scope = transactionScope) { + /** * Handles the case when the ENClient got disabled but the Transaction is still scheduled * in a background job. Also it acts as a failure catch in case the orchestration code did * not check in before. */ if (!InternalExposureNotificationClient.asyncIsEnabled()) { - Timber.w("EN is not enabled, skipping RetrieveDiagnosisKeys") + Timber.tag(TAG).w("EN is not enabled, skipping RetrieveDiagnosisKeys") executeClose() - return@lockAndExecuteUnique + return@lockAndExecute } /**************************************************** * INIT TRANSACTION @@ -155,34 +189,61 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { ****************************************************/ val token = executeToken() - /**************************************************** - * RETRIEVE RISK SCORE PARAMETERS - ****************************************************/ + // RETRIEVE RISK SCORE PARAMETERS val exposureConfiguration = executeRetrieveRiskScoreParams() - /**************************************************** - * FILES FROM WEB REQUESTS - ****************************************************/ - val keyFiles = executeFetchKeyFilesFromServer(currentDate) - - if (keyFiles.isNotEmpty()) { - /**************************************************** - * SUBMIT FILES TO API - ****************************************************/ - executeAPISubmission(token, keyFiles, exposureConfiguration) + val countries = if (environmentSetup.useEuropeKeyPackageFiles) { + listOf("EUR") } else { - Timber.w("no key files, skipping submission to internal API.") + requestedCountries ?: ApplicationConfigurationService + .asyncRetrieveApplicationConfiguration() + .supportedCountriesList } - /**************************************************** - * Fetch Date Update - ****************************************************/ - executeFetchDateUpdate(currentDate) - /**************************************************** - * CLOSE TRANSACTION - ****************************************************/ + invokeSubmissionStartedInDebugOrBuildMode() + + val availableKeyFiles = executeFetchKeyFilesFromServer(countries) + + if (availableKeyFiles.isEmpty()) { + Timber.tag(TAG).w("No keyfiles were available!") + } + + if (CWADebug.isDebugBuildOrMode) { + val totalFileSize = availableKeyFiles.fold(0L, { acc, file -> + file.length() + acc + }) + + onKeyFilesDownloadFinished?.invoke(availableKeyFiles.size, totalFileSize) + onKeyFilesDownloadFinished = null + invokeSubmissionStartedInDebugOrBuildMode() + } + + val isSubmissionSuccessful = executeAPISubmission( + exportFiles = availableKeyFiles, + exposureConfiguration = exposureConfiguration, + token = token + ) + + invokeSubmissionFinishedInDebugOrBuildMode() + + if (isSubmissionSuccessful) executeFetchDateUpdate(currentDate) + executeClose() } + private fun invokeSubmissionStartedInDebugOrBuildMode() { + if (CWADebug.isDebugBuildOrMode) { + onApiSubmissionStarted?.invoke() + onApiSubmissionStarted = null + } + } + + private fun invokeSubmissionFinishedInDebugOrBuildMode() { + if (CWADebug.isDebugBuildOrMode) { + onApiSubmissionFinished?.invoke() + onApiSubmissionFinished = null + } + } + override suspend fun rollback() { super.rollback() try { @@ -200,12 +261,12 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { } private fun rollbackSetup() { - Timber.v("rollback $SETUP") + Timber.tag(TAG).v("rollback $SETUP") LocalData.lastTimeDiagnosisKeysFromServerFetch(lastFetchDateForRollback.get()) } private fun rollbackToken() { - Timber.v("rollback $TOKEN") + Timber.tag(TAG).v("rollback $TOKEN") LocalData.googleApiToken(googleAPITokenForRollback.get()) } @@ -215,7 +276,7 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { private suspend fun executeSetup() = executeState(SETUP) { lastFetchDateForRollback.set(LocalData.lastTimeDiagnosisKeysFromServerFetch()) val currentDate = Date(System.currentTimeMillis()) - Timber.d("using $currentDate as current date in Transaction.") + Timber.tag(TAG).d("using $currentDate as current date in Transaction.") currentDate } @@ -241,32 +302,25 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { * Executes the WEB_REQUESTS Transaction State */ private suspend fun executeFetchKeyFilesFromServer( - currentDate: Date + countries: List<String> ) = executeState(FILES_FROM_WEB_REQUESTS) { - FileStorageHelper.initializeExportSubDirectory() - CachedKeyFileHolder.asyncFetchFiles(currentDate) + val locationCodes = countries.map { LocationCode(it) } + keyFileDownloader.asyncFetchKeyFiles(locationCodes) } - /** - * Executes the API_SUBMISSION Transaction State - * - * We currently use Batch Size 1 and thus submit multiple times to the API. - * This means that instead of directly submitting all files at once, we have to split up - * our file list as this equals a different batch for Google every time. - */ private suspend fun executeAPISubmission( token: String, exportFiles: Collection<File>, exposureConfiguration: ExposureConfiguration? - ) = executeState(API_SUBMISSION) { - exportFiles.forEach { batch -> - InternalExposureNotificationClient.asyncProvideDiagnosisKeys( - listOf(batch), - exposureConfiguration, - token - ) - } - Timber.d("Diagnosis Keys provided successfully, Token: $token") + ): Boolean = executeState(API_SUBMISSION) { + Timber.tag(TAG).d("Attempting submission to ENF") + val success = enfClient.provideDiagnosisKeys( + keyFiles = exportFiles, + configuration = exposureConfiguration, + token = token + ) + Timber.tag(TAG).d("Diagnosis Keys provided (success=%s, token=%s)", success, token) + return@executeState success } /** @@ -275,6 +329,7 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { private suspend fun executeFetchDateUpdate( currentDate: Date ) = executeState(FETCH_DATE_UPDATE) { + Timber.tag(TAG).d("executeFetchDateUpdate(currentDate=%s)", currentDate) LocalData.lastTimeDiagnosisKeysFromServerFetch(currentDate) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelInjectionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelInjectionHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..f5e6689c6319a39c2dd5d9eb59ad0a12c6919d2c --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelInjectionHelper.kt @@ -0,0 +1,10 @@ +package de.rki.coronawarnapp.transaction + +import javax.inject.Inject +import javax.inject.Singleton + +// TODO Remove once we have refactored the transaction and it's no longer a singleton +@Singleton +data class RiskLevelInjectionHelper @Inject constructor( + val transactionScope: TransactionCoroutineScope +) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt index fd019cbe9215bfd06b6a859e29fc3626c4674f07..e11e39327da89cf50b63ec56ca872a211aeba5e6 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/RiskLevelTransaction.kt @@ -7,6 +7,8 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.exception.RiskLevelCalculationException import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.notification.NotificationHelper +import de.rki.coronawarnapp.risk.DefaultRiskLevelCalculation +import de.rki.coronawarnapp.risk.DefaultRiskScoreAnalysis import de.rki.coronawarnapp.risk.RiskLevel import de.rki.coronawarnapp.risk.RiskLevel.INCREASED_RISK import de.rki.coronawarnapp.risk.RiskLevel.LOW_LEVEL_RISK @@ -16,6 +18,7 @@ import de.rki.coronawarnapp.risk.RiskLevel.UNKNOWN_RISK_INITIAL import de.rki.coronawarnapp.risk.RiskLevel.UNKNOWN_RISK_OUTDATED_RESULTS import de.rki.coronawarnapp.risk.RiskLevel.UNKNOWN_RISK_OUTDATED_RESULTS_MANUAL import de.rki.coronawarnapp.risk.RiskLevelCalculation +import de.rki.coronawarnapp.risk.RiskScoreAnalysis import de.rki.coronawarnapp.risk.TimeVariables import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService @@ -34,6 +37,7 @@ import de.rki.coronawarnapp.transaction.RiskLevelTransaction.RiskLevelTransactio import de.rki.coronawarnapp.transaction.RiskLevelTransaction.RiskLevelTransactionState.UPDATE_RISK_LEVEL import de.rki.coronawarnapp.util.ConnectivityHelper import de.rki.coronawarnapp.util.TimeAndDateExtensions.millisecondsToHours +import de.rki.coronawarnapp.util.di.AppInjector import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber @@ -126,6 +130,22 @@ object RiskLevelTransaction : Transaction() { override val TAG: String? = RiskLevelTransaction::class.simpleName + // @Inject lateinit var riskLevelCalculation: RiskLevelCalculation + // TODO pass instance of this to constructor as soon as RiskLevelTransaction is converted to a class + // Injecting here will break Test + private val riskLevelCalculation: RiskLevelCalculation = DefaultRiskLevelCalculation() + + /** + * The maximal runtime of the Risk Level transaction + * In milliseconds + */ + private const val RISK_LEVEL_TRANSACTION_TIMEOUT = 480 * 1000L + + // @Inject lateinit var riskScoreAnalysis: RiskScoreAnalysis + // TODO pass instance of this to constructor as soon as RiskLevelTransaction is converted to a class + // Injecting here will break Test + private val riskScoreAnalysis: RiskScoreAnalysis = DefaultRiskScoreAnalysis() + /** possible transaction states */ private enum class RiskLevelTransactionState : TransactionState { /** Check the conditions for the [NO_CALCULATION_POSSIBLE_TRACING_OFF] score */ @@ -171,8 +191,15 @@ object RiskLevelTransaction : Transaction() { /** atomic reference for the rollback value for date of last risk level calculation */ private val lastCalculatedRiskLevelDate = AtomicReference<Long>() + private val transactionScope: TransactionCoroutineScope by lazy { + AppInjector.component.transRiskLevelInjection.transactionScope + } + /** initiates the transaction. This suspend function guarantees a successful transaction once completed. */ - suspend fun start() = lockAndExecute { + suspend fun start() = lockAndExecute( + scope = transactionScope, + timeout = RISK_LEVEL_TRANSACTION_TIMEOUT + ) { /**************************************************** * CHECK [NO_CALCULATION_POSSIBLE_TRACING_OFF] CONDITIONS ****************************************************/ @@ -261,7 +288,7 @@ object RiskLevelTransaction : Transaction() { val isTracingEnabled = InternalExposureNotificationClient.asyncIsEnabled() if (!isTracingEnabled) return@executeState NO_CALCULATION_POSSIBLE_TRACING_OFF - Timber.v("$transactionId - TRACING_NOT_ACTIVE_RISK not applicable") + Timber.tag(TAG).v("$transactionId - TRACING_NOT_ACTIVE_RISK not applicable") return@executeState UNDETERMINED } @@ -274,10 +301,12 @@ object RiskLevelTransaction : Transaction() { // if there was no key retrieval before, we return no calculation state TimeVariables.getLastTimeDiagnosisKeysFromServerFetch() ?: return@executeState UNKNOWN_RISK_INITIAL.also { - Timber.v("$transactionId - no last time diagnosis keys from server fetch timestamp was found") + Timber.tag(TAG).v( + "$transactionId - no last time diagnosis keys from server fetch timestamp was found" + ) } - Timber.v("$transactionId - CHECK_UNKNOWN_RISK_INITIAL_NO_KEYS not applicable") + Timber.tag(TAG).v("$transactionId - CHECK_UNKNOWN_RISK_INITIAL_NO_KEYS not applicable") return@executeState UNDETERMINED } @@ -301,18 +330,22 @@ object RiskLevelTransaction : Transaction() { ) { if (ConnectivityHelper.autoModeEnabled(CoronaWarnApplication.getAppContext())) { return@executeState UNKNOWN_RISK_OUTDATED_RESULTS.also { - Timber.v("diagnosis keys outdated and active tracing time is above threshold") - Timber.v("manual mode not active (background jobs enabled)") + Timber.tag(TAG).v( + "diagnosis keys outdated and active tracing time is above threshold" + ) + Timber.tag(TAG).v("manual mode not active (background jobs enabled)") } } else { return@executeState UNKNOWN_RISK_OUTDATED_RESULTS_MANUAL.also { - Timber.v("diagnosis keys outdated and active tracing time is above threshold") - Timber.v("manual mode active (background jobs disabled)") + Timber.tag(TAG).v( + "diagnosis keys outdated and active tracing time is above threshold" + ) + Timber.tag(TAG).v("manual mode active (background jobs disabled)") } } } - Timber.v("$transactionId - CHECK_UNKNOWN_RISK_OUTDATED not applicable") + Timber.tag(TAG).v("$transactionId - CHECK_UNKNOWN_RISK_OUTDATED not applicable") return@executeState UNDETERMINED } @@ -345,7 +378,7 @@ object RiskLevelTransaction : Transaction() { executeState(RETRIEVE_APPLICATION_CONFIG) { return@executeState getApplicationConfiguration() .also { - Timber.v(TAG, "$transactionId - retrieved configuration from backend") + Timber.tag(TAG).v("$transactionId - retrieved configuration from backend") } } @@ -357,7 +390,9 @@ object RiskLevelTransaction : Transaction() { val exposureSummary = getNewExposureSummary() return@executeState exposureSummary.also { - Timber.v(TAG, "$transactionId - get the exposure summary for further calculation") + Timber.tag(TAG).v( + "$transactionId - get the exposure summary for further calculation" + ) } } @@ -374,38 +409,59 @@ object RiskLevelTransaction : Transaction() { // values provided by the Google API val attenuationParameters = appConfig.attenuationDuration - // calculate the risk score based on the values collected by the Google EN API and - // the backend configuration - val riskScore = RiskLevelCalculation.calculateRiskScore( - attenuationParameters, - exposureSummary - ).also { - Timber.v(TAG, "calculated risk with the given config: $it") - } - // these are the defined risk classes. They will divide the calculated // risk score into the low and increased risk val riskScoreClassification = appConfig.riskScoreClasses - // get the high risk score class - val highRiskScoreClass = - riskScoreClassification.riskClassesList.find { it.label == "HIGH" } - ?: throw RiskLevelCalculationException(IllegalStateException("no high risk score class found")) - - // if the calculated risk score is above the defined level threshold we return the high level risk score - if (riskScore >= highRiskScoreClass.min && riskScore <= highRiskScoreClass.max) { - Timber.v("$riskScore is above the defined min value ${highRiskScoreClass.min}") - return@executeState INCREASED_RISK - } else if (riskScore > highRiskScoreClass.max) { - throw RiskLevelCalculationException( - IllegalStateException("risk score is above the max threshold for score class") - ) - } + return@executeState getRiskLevel( + riskLevelCalculation, + riskScoreAnalysis, + attenuationParameters, + exposureSummary, + riskScoreClassification + ) + } - Timber.v("$transactionId - INCREASED_RISK not applicable") - return@executeState UNDETERMINED + fun getRiskLevel( + riskLevelCalculation: RiskLevelCalculation, + riskScoreAnalysis: RiskScoreAnalysis, + attenuationParameters: ApplicationConfigurationOuterClass.AttenuationDuration, + exposureSummary: ExposureSummary, + riskScoreClassification: ApplicationConfigurationOuterClass.RiskScoreClassification + ): RiskLevel { + // calculate the risk score based on the values collected by the Google EN API and + // the backend configuration + val riskScore = riskLevelCalculation.calculateRiskScore( + attenuationParameters, + exposureSummary + ).also { + Timber.tag(TAG).v("calculated risk with the given config: $it") } + // get the high risk score class + val highRiskScoreClass = + riskScoreClassification.riskClassesList.find { it.label == "HIGH" } + ?: throw RiskLevelCalculationException(IllegalStateException("no high risk score class found")) + + // if the calculated risk score is above the defined level threshold we return the high level risk score + if (riskScoreAnalysis.withinDefinedLevelThreshold( + riskScore, + highRiskScoreClass.min, + highRiskScoreClass.max + ) + ) { + Timber.tag(TAG).v("$riskScore is above the defined min value ${highRiskScoreClass.min}") + return INCREASED_RISK + } else if (riskScore > highRiskScoreClass.max) { + throw RiskLevelCalculationException( + IllegalStateException("risk score is above the max threshold for score class") + ) + } + + Timber.tag(TAG).v("$transactionId - INCREASED_RISK not applicable") + return UNDETERMINED + } + /** * Executes the [CHECK_UNKNOWN_RISK_INITIAL_TRACING_DURATION] Transaction State */ @@ -414,11 +470,11 @@ object RiskLevelTransaction : Transaction() { ) { // if the active tracing duration is not above the defined threshold we return no calculation state if (!isActiveTracingTimeAboveThreshold()) { - Timber.v("$transactionId - active tracing time is not enough") + Timber.tag(TAG).v("$transactionId - active tracing time is not enough") return@executeState UNKNOWN_RISK_INITIAL } - Timber.v("$transactionId - UNKNOWN_RISK_INITIAL not applicable") + Timber.tag(TAG).v("$transactionId - UNKNOWN_RISK_INITIAL not applicable") return@executeState UNDETERMINED } @@ -427,7 +483,7 @@ object RiskLevelTransaction : Transaction() { */ private suspend fun executeUpdateRiskLevelScore(riskLevel: RiskLevel) = executeState(UPDATE_RISK_LEVEL) { - Timber.v("$transactionId - update the risk level with $riskLevel") + Timber.tag(TAG).v("$transactionId - update the risk level with $riskLevel") updateRiskLevelScore(riskLevel) } @@ -435,7 +491,7 @@ object RiskLevelTransaction : Transaction() { * Executes the [CLOSE] Transaction State */ private suspend fun executeClose() = executeState(CLOSE) { - Timber.v("$transactionId - transaction will close") + Timber.tag(TAG).v("$transactionId - transaction will close") lastCalculatedRiskLevelScoreForRollback.set(null) lastCalculatedRiskLevelDate.set(null) } @@ -454,7 +510,9 @@ object RiskLevelTransaction : Transaction() { */ private suspend fun isValidResult(riskLevel: RiskLevel): Boolean { if (riskLevel != UNDETERMINED) { - Timber.v("$transactionId - $riskLevel was determined by the transaction. UPDATE and CLOSE will be called") + Timber.tag(TAG).d( + "$transactionId - $riskLevel was determined by the transaction. UPDATE and CLOSE will be called" + ) lastCalculatedRiskLevelScoreForRollback.set(RiskLevelRepository.getLastCalculatedScore()) executeUpdateRiskLevelScore(riskLevel) lastCalculatedRiskLevelDate.set(LocalData.lastTimeRiskLevelCalculation()) @@ -473,7 +531,7 @@ object RiskLevelTransaction : Transaction() { private suspend fun getApplicationConfiguration(): ApplicationConfigurationOuterClass.ApplicationConfiguration = withContext(Dispatchers.Default) { return@withContext ApplicationConfigurationService.asyncRetrieveApplicationConfiguration() - .also { Timber.v("configuration from backend: $it") } + .also { Timber.tag(TAG).d("configuration from backend: $it") } } /** @@ -489,7 +547,7 @@ object RiskLevelTransaction : Transaction() { val activeTracingDurationInHours = durationTracingIsActive.millisecondsToHours() return (activeTracingDurationInHours >= durationTracingIsActiveThreshold).also { - Timber.v( + Timber.tag(TAG).v( "active tracing time ($activeTracingDurationInHours h) is above threshold " + "($durationTracingIsActiveThreshold h): $it" ) @@ -526,7 +584,7 @@ object RiskLevelTransaction : Transaction() { InternalExposureNotificationClient.asyncGetExposureSummary(googleToken) return exposureSummary.also { - Timber.v("$transactionId - generated new exposure summary with $googleToken") + Timber.tag(TAG).v("$transactionId - generated new exposure summary with $googleToken") } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisInjectionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisInjectionHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..7203a78381ac141fa61c139c50cd76810f6848d6 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisInjectionHelper.kt @@ -0,0 +1,16 @@ +package de.rki.coronawarnapp.transaction + +import de.rki.coronawarnapp.submission.ExposureKeyHistoryCalculations +import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.playbook.Playbook +import javax.inject.Inject +import javax.inject.Singleton + +// TODO Remove once we have refactored the transaction and it's no longer a singleton +@Singleton +data class SubmitDiagnosisInjectionHelper @Inject constructor( + val transactionScope: TransactionCoroutineScope, + val playbook: Playbook, + val appConfigProvider: AppConfigProvider, + val exposureKeyHistoryCalculations: ExposureKeyHistoryCalculations +) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransaction.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransaction.kt index 326cffe113fbaf6494681cca328f29885de533d7..9b969b2615d2df27db150678da544d0dfa98b69d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransaction.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransaction.kt @@ -1,15 +1,19 @@ package de.rki.coronawarnapp.transaction import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.http.playbook.PlaybookImpl +import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.appconfig.toNewConfig +import de.rki.coronawarnapp.playbook.Playbook +import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration import de.rki.coronawarnapp.service.submission.SubmissionService +import de.rki.coronawarnapp.submission.ExposureKeyHistoryCalculations +import de.rki.coronawarnapp.submission.Symptoms import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction.SubmitDiagnosisKeysTransactionState.CLOSE import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction.SubmitDiagnosisKeysTransactionState.RETRIEVE_TAN_AND_SUBMIT_KEYS import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction.SubmitDiagnosisKeysTransactionState.RETRIEVE_TEMPORARY_EXPOSURE_KEY_HISTORY import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction.SubmitDiagnosisKeysTransactionState.STORE_SUCCESS -import de.rki.coronawarnapp.util.ProtoFormatConverterExtensions.limitKeyCount -import de.rki.coronawarnapp.util.ProtoFormatConverterExtensions.transformKeyHistoryToExternalFormat +import de.rki.coronawarnapp.util.di.AppInjector +import timber.log.Timber /** * The SubmitDiagnosisKeysTransaction is used to define an atomic Transaction for Key Reports. Its states allow an @@ -36,6 +40,7 @@ import de.rki.coronawarnapp.util.ProtoFormatConverterExtensions.transformKeyHist */ object SubmitDiagnosisKeysTransaction : Transaction() { + private const val FALLBACK_COUNTRY = "DE" override val TAG: String? = SubmitDiagnosisKeysTransaction::class.simpleName /** possible transaction states */ @@ -47,36 +52,60 @@ object SubmitDiagnosisKeysTransaction : Transaction() { CLOSE } + private val transactionScope: TransactionCoroutineScope by lazy { + AppInjector.component.transSubmitDiagnosisInjection.transactionScope + } + + private val playbook: Playbook + get() = AppInjector.component.transSubmitDiagnosisInjection.playbook + + private val appConfigProvider: AppConfigProvider + get() = AppInjector.component.transSubmitDiagnosisInjection.appConfigProvider + + private val exposureKeyHistoryCalculations: ExposureKeyHistoryCalculations + get() = AppInjector.component.transSubmitDiagnosisInjection.exposureKeyHistoryCalculations + /** initiates the transaction. This suspend function guarantees a successful transaction once completed. */ suspend fun start( registrationToken: String, - keys: List<TemporaryExposureKey> - ) = lockAndExecuteUnique { - /**************************************************** - * RETRIEVE TEMPORARY EXPOSURE KEY HISTORY - ****************************************************/ + keys: List<TemporaryExposureKey>, + symptoms: Symptoms + ) = lockAndExecute(unique = true, scope = transactionScope) { + val temporaryExposureKeyList = executeState(RETRIEVE_TEMPORARY_EXPOSURE_KEY_HISTORY) { - keys.limitKeyCount() - .transformKeyHistoryToExternalFormat() + exposureKeyHistoryCalculations.transformToKeyHistoryInExternalFormat(keys, symptoms) } - /**************************************************** - * RETRIEVE TAN & SUBMIT KEYS - ****************************************************/ + + val visistedCountries = + appConfigProvider.getAppConfig().performSanityChecks().supportedCountriesList + executeState(RETRIEVE_TAN_AND_SUBMIT_KEYS) { - PlaybookImpl(WebRequestBuilder.getInstance()).submission( - registrationToken, - temporaryExposureKeyList + val submissionData = Playbook.SubmissionData( + registrationToken = registrationToken, + temporaryExposureKeys = temporaryExposureKeyList, + consentToFederation = true, + visistedCountries = visistedCountries ) + playbook.submission(submissionData) } - /**************************************************** - * STORE SUCCESS - ****************************************************/ + executeState(STORE_SUCCESS) { SubmissionService.submissionSuccessful() } - /**************************************************** - * CLOSE TRANSACTION - ****************************************************/ + executeState(CLOSE) {} } + + private fun ApplicationConfiguration.performSanityChecks(): ApplicationConfiguration { + var sanityChecked = this + + if (sanityChecked.supportedCountriesList.isEmpty()) { + sanityChecked = sanityChecked.toNewConfig { + addSupportedCountries(FALLBACK_COUNTRY) + } + Timber.w("Country list was empty, corrected: %s", sanityChecked.supportedCountriesList) + } + + return sanityChecked + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/Transaction.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/Transaction.kt index f43dfd36aa2f6bbcf762165c6a0bae9c62061649..e206e1a2a8b7148c6ae6306fb392e9556571a456 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/Transaction.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/Transaction.kt @@ -26,6 +26,7 @@ import de.rki.coronawarnapp.risk.TimeVariables import de.rki.coronawarnapp.transaction.Transaction.InternalTransactionStates.INIT import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext @@ -48,16 +49,7 @@ import kotlin.system.measureTimeMillis */ abstract class Transaction { - companion object { - /** - * Transaction Timeout in Milliseconds, used to cancel any Transactions that run into never ending execution - * (e.g. due to a coroutine not being cancelled properly or an exception leading to unchecked behavior) - */ - private val TRANSACTION_TIMEOUT_MS = - TimeVariables.getTransactionTimeout() - } - - @Suppress("VariableNaming") // Done as the Convention is TAG for every class + @Suppress("VariableNaming", "PropertyName") // Done as the Convention is TAG for every class abstract val TAG: String? /** @@ -91,7 +83,7 @@ abstract class Transaction { private fun setState(state: TransactionState) = currentTransactionState.set(state) .also { - Timber.d("$transactionId - STATE CHANGE: ${currentTransactionState.get()}") + Timber.tag(TAG).d("$transactionId - STATE CHANGE: ${currentTransactionState.get()}") } /** @@ -173,26 +165,6 @@ abstract class Transaction { ): T = executeState(Dispatchers.Default, state, block) - /** - * Executes the transaction as Unique. This results in the next execution being omitted in case of a race towards - * the lock. Please see [lockAndExecute] for more details - * - * @param T Optional Return Type in case the Transaction should return a value from the coroutine. - * @param block the suspending function that should be used to execute the transaction. - */ - protected suspend fun <T> lockAndExecuteUnique(block: suspend CoroutineScope.() -> T) = - lockAndExecute(true, block) - - /** - * Executes the transaction as non-unique. This results in the next execution being queued in case of a race towards - * the lock. Please see [lockAndExecute] for more details - * - * @param T Optional Return Type in case the Transaction should return a value from the coroutine. - * @param block the suspending function that should be used to execute the transaction. - */ - protected suspend fun <T> lockAndExecute(block: suspend CoroutineScope.() -> T) = - lockAndExecute(false, block) - /** * Attempts to go into the internal lock context (mutual exclusion coroutine) and executes the given suspending * function. Standard Logging is executed to inform about the transaction status. @@ -206,37 +178,54 @@ abstract class Transaction { * * In an error scenario, during the handling of the transaction error, a rollback will be executed on best-effort basis. * - * @param T Optional Return Type in case the Transaction should return a value from the coroutine. + * @param unique Executes the transaction as Unique. This results in the next execution being omitted in case of a race towards the lock. * @param block the suspending function that should be used to execute the transaction. + * @param timeout the timeout for the transcation (in milliseconds) * @throws TransactionException the exception that wraps around any error that occurs inside the lock. * * @see executeState * @see executedStatesStack */ - private suspend fun <T> lockAndExecute(unique: Boolean, block: suspend CoroutineScope.() -> T) { + suspend fun lockAndExecute( + unique: Boolean = false, + scope: CoroutineScope, + timeout: Long = TimeVariables.getTransactionTimeout(), + block: suspend CoroutineScope.() -> Unit + ) { + if (unique && internalMutualExclusionLock.isLocked) { - val runningString = "TRANSACTION WITH ID $transactionId ALREADY RUNNING " + - "($currentTransactionState) AS UNIQUE, SKIPPING EXECUTION." - Timber.w(runningString) + Timber.tag(TAG).w( + "TRANSACTION WITH ID %s ALREADY RUNNING (%s) AS UNIQUE, SKIPPING EXECUTION.", + transactionId, currentTransactionState + ) return } - try { - return internalMutualExclusionLock.withLock { + + val deferred = scope.async { + internalMutualExclusionLock.withLock { executeState(INIT) { transactionId.set(UUID.randomUUID()) } - measureTimeMillis { - withTimeout(TRANSACTION_TIMEOUT_MS) { + + val duration = measureTimeMillis { + withTimeout(timeout) { block.invoke(this) } - }.also { - val completedString = - "TRANSACTION $transactionId COMPLETED (${System.currentTimeMillis()}) " + - "in $it ms, STATES EXECUTED: ${getExecutedStates()}" - Timber.i(completedString) } + + Timber.tag(TAG).i( + "TRANSACTION %s COMPLETED (%d) in %d ms, STATES EXECUTED: %s", + transactionId, System.currentTimeMillis(), duration, getExecutedStates() + ) + resetExecutedStateStack() } - } catch (e: Exception) { - handleTransactionError(e) + } + + withContext(scope.coroutineContext) { + try { + deferred.await() + } catch (e: Exception) { + handleTransactionError(e) + } } } @@ -253,14 +242,18 @@ abstract class Transaction { * @param error the error that lead to an error case in the transaction that cannot be handled inside the * transaction but has to be caught from the exception caller */ - protected open suspend fun handleTransactionError(error: Throwable?): Nothing { - rollback() - resetExecutedStateStack() - throw TransactionException( + protected open suspend fun handleTransactionError(error: Throwable): Nothing { + val wrap = TransactionException( transactionId.get(), currentTransactionState.toString(), error ) + Timber.tag(TAG).e(wrap) + + rollback() + resetExecutedStateStack() + + throw wrap } /** @@ -274,7 +267,7 @@ abstract class Transaction { * @throws RollbackException throws a rollback exception when handleRollbackError() is called */ protected open suspend fun rollback() { - if (BuildConfig.DEBUG) Timber.d("Initiate Rollback") + if (BuildConfig.DEBUG) Timber.tag(TAG).d("Initiate Rollback") } /** @@ -285,10 +278,12 @@ abstract class Transaction { * @param error the error that lead to an error case in the rollback */ protected open fun handleRollbackError(error: Throwable?): Nothing { - throw RollbackException( + val wrap = RollbackException( transactionId.get(), currentTransactionState.toString(), error ) + Timber.tag(TAG).e(wrap) + throw wrap } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/TransactionCoroutineScope.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/TransactionCoroutineScope.kt new file mode 100644 index 0000000000000000000000000000000000000000..0e27712b8af6d356585d87e67c6576dec91421ff --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/transaction/TransactionCoroutineScope.kt @@ -0,0 +1,13 @@ +package de.rki.coronawarnapp.transaction + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.coroutines.CoroutineContext + +@Singleton +class TransactionCoroutineScope @Inject constructor() : CoroutineScope { + override val coroutineContext: CoroutineContext = SupervisorJob() + Dispatchers.Default +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/ActivityBinder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/ActivityBinder.kt new file mode 100644 index 0000000000000000000000000000000000000000..011e464a4139ce61ae3d27277f58feee268fd9ef --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/ActivityBinder.kt @@ -0,0 +1,21 @@ +package de.rki.coronawarnapp.ui + +import dagger.Module +import dagger.android.ContributesAndroidInjector +import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.ui.main.MainActivityModule +import de.rki.coronawarnapp.ui.main.MainActivityTestModule +import de.rki.coronawarnapp.ui.onboarding.OnboardingActivity +import de.rki.coronawarnapp.ui.onboarding.OnboardingActivityModule + +@Module +abstract class ActivityBinder { + @ContributesAndroidInjector(modules = [MainActivityModule::class, MainActivityTestModule::class]) + abstract fun mainActivity(): MainActivity + + @ContributesAndroidInjector + abstract fun launcherActivity(): LauncherActivity + + @ContributesAndroidInjector(modules = [OnboardingActivityModule::class]) + abstract fun onboardingActivity(): OnboardingActivity +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/Country.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/Country.kt new file mode 100644 index 0000000000000000000000000000000000000000..2c22c8b002551f81783c5690ba7636e090db55c7 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/Country.kt @@ -0,0 +1,44 @@ +package de.rki.coronawarnapp.ui + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import de.rki.coronawarnapp.R + +enum class Country( + val code: String, + @StringRes val labelRes: Int, + @DrawableRes val iconRes: Int +) { + AT("at", R.string.country_name_at, R.drawable.ic_country_at), + BE("be", R.string.country_name_be, R.drawable.ic_country_be), + BG("bg", R.string.country_name_bg, R.drawable.ic_country_bg), + CH("ch", R.string.country_name_ch, R.drawable.ic_country_ch), + CY("cy", R.string.country_name_cy, R.drawable.ic_country_cy), + CZ("cz", R.string.country_name_cz, R.drawable.ic_country_cz), + DE("de", R.string.country_name_de, R.drawable.ic_country_de), + DK("dk", R.string.country_name_dk, R.drawable.ic_country_dk), + EE("ee", R.string.country_name_ee, R.drawable.ic_country_ee), + ES("es", R.string.country_name_es, R.drawable.ic_country_es), + FI("fi", R.string.country_name_fi, R.drawable.ic_country_fi), + FR("fr", R.string.country_name_fr, R.drawable.ic_country_fr), + UK("uk", R.string.country_name_uk, R.drawable.ic_country_uk), + GR("gr", R.string.country_name_gr, R.drawable.ic_country_gr), + HR("hr", R.string.country_name_hr, R.drawable.ic_country_hr), + HU("hu", R.string.country_name_hu, R.drawable.ic_country_hu), + IE("ie", R.string.country_name_ie, R.drawable.ic_country_ie), + IS("is", R.string.country_name_is, R.drawable.ic_country_is), + IT("it", R.string.country_name_it, R.drawable.ic_country_it), + LI("li", R.string.country_name_li, R.drawable.ic_country_li), + LT("lt", R.string.country_name_lt, R.drawable.ic_country_lt), + LU("lu", R.string.country_name_lu, R.drawable.ic_country_lu), + LV("lv", R.string.country_name_lv, R.drawable.ic_country_lv), + MT("mt", R.string.country_name_mt, R.drawable.ic_country_mt), + NL("nl", R.string.country_name_nl, R.drawable.ic_country_nl), + NO("no", R.string.country_name_no, R.drawable.ic_country_no), + PL("pl", R.string.country_name_pl, R.drawable.ic_country_pl), + PT("pt", R.string.country_name_pt, R.drawable.ic_country_pt), + RO("ro", R.string.country_name_ro, R.drawable.ic_country_ro), + SE("se", R.string.country_name_se, R.drawable.ic_country_se), + SI("si", R.string.country_name_si, R.drawable.ic_country_si), + SK("sk", R.string.country_name_sk, R.drawable.ic_country_sk) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/LauncherActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/LauncherActivity.kt index 9e4820952921bc9f6418eac2b7b79d7830a80eb5..1f55312ecea5c8dd259a6445f235aca801693e86 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/LauncherActivity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/LauncherActivity.kt @@ -1,11 +1,13 @@ package de.rki.coronawarnapp.ui +import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.onboarding.OnboardingActivity import de.rki.coronawarnapp.update.UpdateChecker +import de.rki.coronawarnapp.util.di.AppInjector import kotlinx.coroutines.launch class LauncherActivity : AppCompatActivity() { @@ -15,6 +17,11 @@ class LauncherActivity : AppCompatActivity() { private lateinit var updateChecker: UpdateChecker + override fun onCreate(savedInstanceState: Bundle?) { + AppInjector.setup(this) + super.onCreate(savedInstanceState) + } + override fun onResume() { super.onResume() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/SingleLiveEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/SingleLiveEvent.kt new file mode 100644 index 0000000000000000000000000000000000000000..03fff86ccbc7ad804151e68875e07b093837d956 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/SingleLiveEvent.kt @@ -0,0 +1,67 @@ + +package de.rki.coronawarnapp.ui + +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import androidx.annotation.MainThread +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer +import timber.log.Timber +import java.util.concurrent.atomic.AtomicBoolean + +/** + * A lifecycle-aware observable that sends only new updates after subscription, used for events like + * navigation and Snackbar messages. + * + * + * This avoids a common problem with events: on configuration change (like rotation) an update + * can be emitted if the observer is active. This LiveData only calls the observable if there's an + * explicit call to setValue() or call(). + * + * + * Note that only one observer is going to be notified of changes. + */ +class SingleLiveEvent<T> : MutableLiveData<T>() { + private val pending = AtomicBoolean(false) + @MainThread + override fun observe(owner: LifecycleOwner, observer: Observer<in T>) { + if (hasActiveObservers()) { + Timber + .w("Multiple observers registered but only one will be notified of changes.") + } + // Observe the internal MutableLiveData + super.observe(owner, Observer { t -> + if (pending.compareAndSet(true, false)) { + observer.onChanged(t) + } + }) + } + + @MainThread + override fun setValue(t: T?) { + pending.set(true) + super.setValue(t) + } + /** + * Used for cases where T is Void, to make calls cleaner. + */ + @MainThread + fun call() { + value = null + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/base/ActivityExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/base/ActivityExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..83d7f1b7115b4a15cb921dc12c899e85b908e25b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/base/ActivityExtensions.kt @@ -0,0 +1,20 @@ +package de.rki.coronawarnapp.ui.base + +import android.app.Activity +import android.content.Intent +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.ExternalActionException +import de.rki.coronawarnapp.exception.reporting.report + +fun Activity.startActivitySafely( + intent: Intent, + handler: (Exception) -> Unit = { + ExternalActionException(it).report(ExceptionCategory.UI) + } +) { + try { + startActivity(intent) + } catch (exception: Exception) { + handler.invoke(exception) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..f9346c71339d9a40efa65926622fb2b837bca970 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarAdapter.kt @@ -0,0 +1,78 @@ +package de.rki.coronawarnapp.ui.calendar + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import de.rki.coronawarnapp.R +import org.joda.time.LocalDate + +/** + * Calendar adapter for recycler view + * + * @param clickListener (Day) -> Unit - on item click event listener + */ +class CalendarAdapter(private val clickListener: (Day) -> Unit) : + RecyclerView.Adapter<CalendarDayViewHolder>() { + + /** + * Mutable list of days + * + * @see Day + */ + private val data = mutableListOf<Day>() + + init { + setHasStableIds(true) + } + + /** + * Create new calendar day view holders + * + * @see CalendarDayViewHolder + */ + override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): CalendarDayViewHolder { + // Create a new view. + val v = LayoutInflater.from(viewGroup.context) + .inflate(R.layout.fragment_calendar_day, viewGroup, false) + + return CalendarDayViewHolder(v) + } + + /** + * Update calendar day view holders + * + * @see CalendarDayViewHolder.bind + */ + override fun onBindViewHolder(viewHolder: CalendarDayViewHolder, position: Int) { + viewHolder.bind(data[position], clickListener) + } + + /** + * Update days list and notify that data set was changed + * + * @see CalendarDayViewHolder.bind + */ + fun update(days: List<Day>) { + data.clear() + data.addAll(days) + notifyDataSetChanged() + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun getItemCount(): Int { + return data.size + } + + /** + * Data class for calendar day + * + * @param date LocalDate + * @param isSelected Boolean + * + * @see LocalDate + */ + data class Day(val date: LocalDate, val isSelected: Boolean = false) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculation.kt new file mode 100644 index 0000000000000000000000000000000000000000..a78f20525bdfb4c195b4115250264cbb3c27e248 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculation.kt @@ -0,0 +1,121 @@ +package de.rki.coronawarnapp.ui.calendar + +import dagger.Reusable +import org.joda.time.DateTime +import org.joda.time.DateTimeZone +import org.joda.time.Instant +import org.joda.time.LocalDate +import java.util.Locale +import javax.inject.Inject + +@Reusable +class CalendarCalculation @Inject constructor() { + + /** + * Get month text view text + * + * Algorithm: + * Case 1: + * first date month != last date month + * first date year == last date year + * Result: September - October 2020 + * + * Case 2: + * first date month != last date month + * first date year != last date year + * Result: December 2020 - January 2021 + * + * Case 3: + * first date month == last date month + * Result: September 2020 + * + * NOTE: This algorithm does not cover same month, but different year - calendar has + * strict constant of 28 days to display, so this case would never happen. + * + * @param firstDate LocalDate - first displayed date + * @param lastDate LocalDate - last displayed date + * + * @return String + * + * @see StringBuilder + */ + fun getMonthText(firstDate: LocalDate, lastDate: LocalDate): String { + val monthText = StringBuilder() + // Append first date month as it would always be displayed + monthText.append(firstDate.monthOfYear().getAsText(Locale.getDefault())) + if (firstDate.monthOfYear() != lastDate.monthOfYear()) { + // Different month + if (firstDate.year() == lastDate.year()) { + // Same year (Case 1) + monthText.append(" - ") + .append(lastDate.monthOfYear().getAsText(Locale.getDefault())) + } else { + // Different year (Case 2) + monthText.append(" ") + .append(firstDate.year().get()) + .append(" - ") + .append(lastDate.monthOfYear().getAsText(Locale.getDefault())) + } + // Append last date year + monthText.append(" ") + .append(lastDate.year().get()) + } else { + // Same month + monthText.append(" ") + .append(firstDate.year().get()) + } + return monthText.toString() + } + + /** + * Calculate dates for calendar + * Input constants: + * - 4 Weeks (TotalWeeks) + * - 7 Days (DaysInWeekCount) + * - Current week - last row + * - Week starts from Monday + * + * Algorithm: + * Goal: calculate days to add with JodaTime lib to current date + * + * Input: Today = 9 September (Wednesday) + * + * Step 1: Define day shift in the week + * |_M_|_T_|_W_|_T_|_F_|_S_|_S_| + * | -2| -1| 9 | +1| +2| +3| +4| <- Current Week (4th row) + * Code: (CurrentDayOfTheWeek * -1) + dayId + * + * Step 2: Apply week shift + * |_M_|_T_|_W_|_T_|_F_|_S_|_S_| + * | -9| -8| -7| -6| -5| -4| -3| <- Previous Week (3d row) + * | -2| -1| 9 | +1| +2| +3| +4| <- Current Week (4th row) + * Code: (DaysInWeekCount * (TotalWeeks - weekId)) * -1 + */ + fun getDates(currentDate: DateTime = DateTime(Instant.now(), DateTimeZone.UTC)): List<CalendarAdapter.Day> { + // Create mutable list of DateTime as a result + val result = mutableListOf<CalendarAdapter.Day>() + // Get current day of the week (where 1 = Monday, 7 = Sunday) + val currentDayOfTheWeek = currentDate.dayOfWeek().get() + // Week count + val weeksCount = WEEKS_COUNT - 1 + for (weekId in 0..weeksCount) { + for (dayId in 1..DAYS_IN_WEEK) { + val daysDiff = (currentDayOfTheWeek * -1) + dayId - (DAYS_IN_WEEK * (weeksCount - weekId)) + result.add(CalendarAdapter.Day(currentDate.plusDays(daysDiff).toLocalDate())) + } + } + return result + } + + companion object { + /** + * Total days in week + */ + const val DAYS_IN_WEEK = 7 + + /** + * Weeks count + */ + private const val WEEKS_COUNT = 4 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarDayViewHolder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarDayViewHolder.kt new file mode 100644 index 0000000000000000000000000000000000000000..393f585c04f71bb7fabbd91de19db2fbf6fd05bb --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarDayViewHolder.kt @@ -0,0 +1,70 @@ +package de.rki.coronawarnapp.ui.calendar + +import android.view.View +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import de.rki.coronawarnapp.R +import org.joda.time.LocalDate +import org.joda.time.format.DateTimeFormat + +/** + * Calendar day view holder + * + * @param v View - view for holder + */ +class CalendarDayViewHolder(v: View) : RecyclerView.ViewHolder(v) { + + /** + * Day text view + */ + private val textView: TextView = v.findViewById(R.id.dayText) + + /** + * Accessibility talk back date format + */ + private val talkBackDateFormat = DateTimeFormat.forPattern("EEEE d MMMMM") + + /** + * Bind data to view + */ + fun bind(day: CalendarAdapter.Day, clickListener: (CalendarAdapter.Day) -> Unit) { + val context = textView.context + val today = LocalDate.now() + + // Set day text + textView.text = day.date.dayOfMonth.toString() + + // Set day content description for talk back + textView.contentDescription = day.date.toString(talkBackDateFormat) + + // If date is after today - then disable click listener + if (!day.date.isAfter(today)) { + textView.setOnClickListener { clickListener(day) } + } + + // Update visuals + when { + // Selected + day.isSelected -> { + textView.setBackgroundResource(R.drawable.calendar_selected_day_back) + textView.setTextColor(ContextCompat.getColor(context, R.color.colorTextEmphasizedButton)) + } + // Today + day.date.isEqual(today) -> { + textView.setBackgroundResource(R.drawable.calendar_today_back) + textView.setTextColor(ContextCompat.getColor(context, R.color.colorCalendarTodayText)) + } + // Future + day.date.isAfter(today) -> { + textView.setBackgroundResource(0) + textView.setTextColor(ContextCompat.getColor(context, R.color.colorTextPrimary3)) + } + // Past + day.date.isBefore(today) -> { + textView.setBackgroundResource(0) + textView.setTextColor(ContextCompat.getColor(context, R.color.colorTextPrimary1)) + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarView.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarView.kt new file mode 100644 index 0000000000000000000000000000000000000000..cb545f2fe2f7b6602553e5c2bbb9fb0023b4eff6 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarView.kt @@ -0,0 +1,196 @@ +package de.rki.coronawarnapp.ui.calendar + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import de.rki.coronawarnapp.R +import org.joda.time.DateTime +import org.joda.time.Instant +import org.joda.time.LocalDate +import java.util.Locale + +/** + * Custom calendar view with rules: + * - 4 Weeks + * - 7 Days + * - Current week - last row + * - Week starts from Monday + */ +class CalendarView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + /** + * Calendar layout + */ + private var calendarLayout: LinearLayout + + /** + * Calendar header + */ + private var headerTextView: TextView + + /** + * Recycler view for dates + * + * @see RecyclerView + */ + private var recyclerView: RecyclerView + + /** + * Layout manager for recycler view + * + * @see RecyclerView.LayoutManager + */ + private var layoutManager: RecyclerView.LayoutManager + + /** + * Mutable list of Day + * + * @see CalendarAdapter.Day + */ + private val days = mutableListOf<CalendarAdapter.Day>() + + /** + * Recycler view adapter + * + * @see CalendarAdapter + */ + private lateinit var adapter: CalendarAdapter + + /** + * Fragment click listener + */ + private var listener: ((LocalDate?) -> Unit)? = null + + /** + * On item click event listener + * + * @see CalendarAdapter.update + * @see updateSelection + */ + private val onItemClickListener: (CalendarAdapter.Day) -> Unit = { selectedDay -> + // Update data set + val updateData = days.map { oldDay -> oldDay.copy(isSelected = selectedDay == oldDay) } + // Update selection + updateSelection(updateData.any { it.isSelected }) + + adapter.update(updateData) + + // Invoke fragment on click + listener?.invoke(updateData.find { it.isSelected }?.date) + } + + /** + * Unset selection of each date shown + * + * @see CalendarAdapter.update + */ + fun unsetSelection() { + val updateData = days.map { oldDay -> oldDay.copy(isSelected = false) } + updateSelection(false) + adapter.update(updateData) + } + + init { + LayoutInflater.from(context) + .inflate(R.layout.fragment_calendar, this, true) + + // Get linear layout + calendarLayout = findViewById<LinearLayout>(R.id.calendar_layout) + + // Get header view + headerTextView = findViewById<TextView>(R.id.calendar_header) + + // Get recycler view + recyclerView = findViewById<RecyclerView>(R.id.calendar_recycler_view) + + // Create layout manager + layoutManager = LinearLayoutManager(context) + // Set to grid layout + layoutManager = GridLayoutManager(context, CalendarCalculation.DAYS_IN_WEEK) + + with(recyclerView) { + layoutManager = this@CalendarView.layoutManager + scrollToPosition(0) + } + + // Calculate dates to display + days.addAll(CalendarCalculation().getDates()) + + // Set calendar adapter as adapter for recycler view + adapter = CalendarAdapter(onItemClickListener) + adapter.update(days) + + recyclerView.adapter = adapter + + // Setup day legend + setUpDayLegend() + + // Setup month + setUpMonthTextView() + } + + /** + * Set fragment click listener + * + * @see listener + */ + fun setDateSelectedListener(listener: (LocalDate?) -> Unit) { + this.listener = listener + } + + /** + * Update header and top level layout background + */ + private fun updateSelection(isSelected: Boolean) { + calendarLayout.isSelected = isSelected + headerTextView.isSelected = isSelected + } + + /** + * SetUp day legend (week day) + * + * NOTE: DaysOfWeek is impossible to use due to API 23 + */ + private fun setUpDayLegend() { + // Get day legend layout + val dayLegendLayout = findViewById<LinearLayout>(R.id.calendar_day_legend) + // Get current week day + val date = LocalDate() + val currentWeekDay = DateTime(Instant.now()).dayOfWeek().get() + for (dayId in 1..CalendarCalculation.DAYS_IN_WEEK) { + val dayOfWeek = CalendarWeekDayView(context) + val weekDay = date.withDayOfWeek(dayId).dayOfWeek() + // weekDay.getAsText returns in either "Fri" or "Friday" format, substring first latter + dayOfWeek.setUp( + weekDay.getAsText(Locale.getDefault()).take(1), + weekDay.get() == currentWeekDay + ) + dayLegendLayout.addView(dayOfWeek) + } + } + + /** + * SetUp month text view + * + * @see CalendarCalculation.getMonthText + */ + private fun setUpMonthTextView() { + // Get month text view + val monthTextView = findViewById<TextView>(R.id.calendar_month) + + // Get first and last days + val firstDate = days.first().date + val lastDate = days.last().date + + monthTextView.text = CalendarCalculation().getMonthText(firstDate, lastDate) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt new file mode 100644 index 0000000000000000000000000000000000000000..52ff504e3d219e5fee43e5c51e86c5dea38a4afe --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt @@ -0,0 +1,51 @@ +package de.rki.coronawarnapp.ui.calendar + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import android.widget.TextView +import de.rki.coronawarnapp.R + +/** + * Week day custom view + */ +class CalendarWeekDayView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + private val textView: TextView + + /** + * Initialize the view + * + * Get TextView for day setup + * SetUp layout params + */ + init { + LayoutInflater.from(context) + .inflate(R.layout.fragment_calendar_day, this, true) + textView = findViewById(R.id.dayText) + + layoutParams = LayoutParams( + 0, + LayoutParams.WRAP_CONTENT, + 1.0f + ) + } + + /** + * SetUp the view from CalendarFragment + */ + fun setUp(text: String, isSelected: Boolean = false) { + textView.text = text + + if (isSelected) { + textView.setTextAppearance(R.style.calendarWeekDaySelected) + } else { + textView.setTextAppearance(R.style.calendarWeekDayNormal) + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt index 52153ca9f15cdb0e8590aa7fe3aa58cec6abe6b9..e0e7143283072ad7e0f69c958fd67cbe954f78e1 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt @@ -1,39 +1,22 @@ package de.rki.coronawarnapp.ui.information +import android.content.Intent +import android.net.Uri import android.os.Bundle -import android.text.method.LinkMovementMethod -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationAboutBinding import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * Basic Fragment which only displays static content. */ -class InformationAboutFragment : Fragment() { - companion object { - private val TAG: String? = InformationAboutFragment::class.simpleName - } - - private var _binding: FragmentInformationAboutBinding? = null - private val binding: FragmentInformationAboutBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentInformationAboutBinding.inflate(inflater) - return binding.root - } +class InformationAboutFragment : Fragment(R.layout.fragment_information_about) { - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentInformationAboutBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -43,7 +26,11 @@ class InformationAboutFragment : Fragment() { private fun setLinks() { binding.informationAboutEasyLanguage - .movementMethod = LinkMovementMethod.getInstance() + .setOnClickListener { + val browserIntent = Intent(Intent.ACTION_VIEW, + Uri.parse(getString(R.string.onboarding_tracing_easy_language_explanation_url))) + startActivity(browserIntent) + } } override fun onResume() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt index 6b351030c0f2712e25a9b14be40911e267cebcd8..61f6ff9699e927de917d74d06715ba2ae978f1b0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt @@ -1,40 +1,21 @@ package de.rki.coronawarnapp.ui.information import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationContactBinding import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.util.ExternalActionHelper +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * Basic Fragment which only displays static content. */ -class InformationContactFragment : Fragment() { - companion object { - private val TAG: String? = InformationContactFragment::class.simpleName - } - - private var _binding: FragmentInformationContactBinding? = null - private val binding: FragmentInformationContactBinding get() = _binding!! +class InformationContactFragment : Fragment(R.layout.fragment_information_contact) { - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentInformationContactBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentInformationContactBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt index 9a6bd0b92f067cf0371595d1674c799776c4c921..e6b1683ce430f4073e569959a96785f79ae6eec2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt @@ -1,9 +1,7 @@ package de.rki.coronawarnapp.ui.information import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo import androidx.fragment.app.Fragment @@ -13,31 +11,14 @@ import de.rki.coronawarnapp.databinding.FragmentInformationBinding import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.util.ExternalActionHelper +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * Basic Fragment which links to static and web content. */ -class InformationFragment : Fragment() { - companion object { - private val TAG: String? = InformationFragment::class.simpleName - } - - private var _binding: FragmentInformationBinding? = null - private val binding: FragmentInformationBinding get() = _binding!! +class InformationFragment : Fragment(R.layout.fragment_information) { - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentInformationBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentInformationBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt index 4d5b127d03617c4bdde3b3a61994e9cf11464d4f..560b64eb7029a5b307952a82fcac44b6d9fce725 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt @@ -2,38 +2,21 @@ package de.rki.coronawarnapp.ui.information import android.os.Bundle import android.text.method.LinkMovementMethod -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationLegalBinding import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.util.convertToHyperlink +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * Basic Fragment which only displays static content. */ -class InformationLegalFragment : Fragment() { - companion object { - private val TAG: String? = InformationLegalFragment::class.simpleName - } - - private var _binding: FragmentInformationLegalBinding? = null - private val binding: FragmentInformationLegalBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentInformationLegalBinding.inflate(inflater) - return binding.root - } +class InformationLegalFragment : Fragment(R.layout.fragment_information_legal) { - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentInformationLegalBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -42,11 +25,11 @@ class InformationLegalFragment : Fragment() { } /** - * Make the links clickable + * Make the links clickable and convert to hyperlink */ private fun setUpContactFormLinks() { binding.informationLegalContactForm.informationLegalContactForm - .movementMethod = LinkMovementMethod.getInstance() + .convertToHyperlink(getString(R.string.information_legal_subtitle_contact_url)) binding.informationLegalContactForm.informationLegalContactFormNonEnDe .movementMethod = LinkMovementMethod.getInstance() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalPresentation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalPresentation.kt new file mode 100644 index 0000000000000000000000000000000000000000..21b0cfef5c8a4b119bd5a305d830ca67bce404e5 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalPresentation.kt @@ -0,0 +1,15 @@ +package de.rki.coronawarnapp.ui.information + +import de.rki.coronawarnapp.util.device.SystemInfoProvider +import java.util.Locale +import javax.inject.Inject + +class InformationLegalPresentation @Inject constructor(private val systemInfoProvider: SystemInfoProvider) { + + val showBackupLinkToContactForm: Boolean + get() { + systemInfoProvider.locale.apply { + return language != Locale.ENGLISH.language && language != Locale.GERMAN.language + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt index c445f900f1539bfd1ef4e31ae4b9c10138a99311..41c3cde335afb3b4368409540c49c09ba11a3233 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt @@ -1,38 +1,19 @@ package de.rki.coronawarnapp.ui.information import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationPrivacyBinding import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * Basic Fragment which only displays static content. */ -class InformationPrivacyFragment : Fragment() { - companion object { - private val TAG: String? = InformationPrivacyFragment::class.simpleName - } - - private var _binding: FragmentInformationPrivacyBinding? = null - private val binding: FragmentInformationPrivacyBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentInformationPrivacyBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } +class InformationPrivacyFragment : Fragment(R.layout.fragment_information_privacy) { + private val binding: FragmentInformationPrivacyBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt index a4ee7576532e3928a945d24b1704b46eefab41e9..0a98ff88bfbcd7352f9b0d3260b3116e8f069b5d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt @@ -1,38 +1,23 @@ package de.rki.coronawarnapp.ui.information import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationTechnicalBinding import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * Basic Fragment which only displays static content. */ -class InformationTechnicalFragment : Fragment() { +class InformationTechnicalFragment : Fragment(R.layout.fragment_information_technical) { companion object { private val TAG: String? = InformationTechnicalFragment::class.simpleName } - private var _binding: FragmentInformationTechnicalBinding? = null - private val binding: FragmentInformationTechnicalBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentInformationTechnicalBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentInformationTechnicalBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt index 98a4079e6a084554861912d4f0ad375ba5fc4531..5c0046ebea1ee3ed37a93482be699babbc0955c9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt @@ -1,38 +1,20 @@ package de.rki.coronawarnapp.ui.information import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationTermsBinding import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * Basic Fragment which only displays static content. */ -class InformationTermsFragment : Fragment() { - companion object { - private val TAG: String? = InformationTermsFragment::class.simpleName - } - - private var _binding: FragmentInformationTermsBinding? = null - private val binding: FragmentInformationTermsBinding get() = _binding!! +class InformationTermsFragment : Fragment(R.layout.fragment_information_terms) { - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentInformationTermsBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentInformationTermsBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..be8e13c919927fcf9ea8da8c30100b8b8fadfd82 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt @@ -0,0 +1,101 @@ +package de.rki.coronawarnapp.ui.interoperability + +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.provider.Settings +import android.view.View +import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.CoronaWarnApplication +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentInteroperabilityConfigurationBinding +import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.util.ConnectivityHelper +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModels +import javax.inject.Inject + +class InteroperabilityConfigurationFragment : + Fragment(R.layout.fragment_interoperability_configuration), AutoInject { + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val vm: InteroperabilityConfigurationFragmentViewModel by cwaViewModels { viewModelFactory } + + private val binding: FragmentInteroperabilityConfigurationBinding by viewBindingLazy() + + private var isNetworkCallbackRegistered = false + private val networkCallback = object : ConnectivityHelper.NetworkCallback() { + override fun onNetworkAvailable() { + vm.getAllCountries() + } + + override fun onNetworkUnavailable() { + // NOOP + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + vm.countryList.observe2(this) { + binding.countryData = it + } + + if (ConnectivityHelper.isNetworkEnabled(CoronaWarnApplication.getAppContext())) { + registerNetworkCallback() + } + + vm.saveInteroperabilityUsed() + + binding.interoperabilityConfigurationHeader.headerButtonBack.buttonIcon.setOnClickListener { + vm.onBackPressed() + } + + vm.navigateBack.observe2(this) { + if (it) { + (requireActivity() as MainActivity).goBack() + } + } + + binding.interoperabilityConfigurationCountryList + .noCountriesRiskdetailsInfoview.riskDetailsOpenSettingsButton.setOnClickListener { + val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY) + } else { + Intent(Settings.ACTION_SETTINGS) + } + startActivity(intent) + } + } + + private fun registerNetworkCallback() { + context?.let { + ConnectivityHelper.registerNetworkStatusCallback(it, networkCallback) + isNetworkCallbackRegistered = true + } + } + + private fun unregisterNetworkCallback() { + if (isNetworkCallbackRegistered) { + context?.let { + ConnectivityHelper.unregisterNetworkStatusCallback(it, networkCallback) + isNetworkCallbackRegistered = false + } + } + } + + override fun onDestroy() { + super.onDestroy() + unregisterNetworkCallback() + } + + override fun onResume() { + super.onResume() + if (ConnectivityHelper.isNetworkEnabled(CoronaWarnApplication.getAppContext())) { + registerNetworkCallback() + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..caa2f41b1891c773674a1b293da29a01b552efa3 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.ui.interoperability + +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey + +@Module +abstract class InteroperabilityConfigurationFragmentModule { + @Binds + @IntoMap + @CWAViewModelKey(InteroperabilityConfigurationFragmentViewModel::class) + abstract fun testRiskLevelFragment( + factory: InteroperabilityConfigurationFragmentViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..4d73e11f99f4b63f41033b114b6a7081812167ae --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModel.kt @@ -0,0 +1,30 @@ +package de.rki.coronawarnapp.ui.interoperability + +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository +import de.rki.coronawarnapp.util.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory + +class InteroperabilityConfigurationFragmentViewModel @AssistedInject constructor( + private val interoperabilityRepository: InteroperabilityRepository +) : CWAViewModel() { + + val countryList = interoperabilityRepository.countryList + val navigateBack = SingleLiveEvent<Boolean>() + + fun onBackPressed() { + navigateBack.postValue(true) + } + + fun saveInteroperabilityUsed() { + interoperabilityRepository.saveInteroperabilityUsed() + } + + fun getAllCountries() { + interoperabilityRepository.getAllCountries() + } + + @AssistedInject.Factory + interface Factory : SimpleCWAViewModelFactory<InteroperabilityConfigurationFragmentViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/lists/BaseAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/lists/BaseAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..8cad45f7db98cddcafe6cd29c6955ab3f54e1d96 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/lists/BaseAdapter.kt @@ -0,0 +1,32 @@ +package de.rki.coronawarnapp.ui.lists + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.CallSuper +import androidx.annotation.LayoutRes +import androidx.recyclerview.widget.RecyclerView + +abstract class BaseAdapter<T : BaseAdapter.VH> : RecyclerView.Adapter<T>() { + + @CallSuper + final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): T { + return onCreateBaseVH(parent, viewType) + } + + abstract fun onCreateBaseVH(parent: ViewGroup, viewType: Int): T + + @CallSuper + final override fun onBindViewHolder(holder: T, position: Int) { + onBindBaseVH(holder, position) + } + + abstract fun onBindBaseVH(holder: T, position: Int) + + abstract class VH(@LayoutRes layoutRes: Int, parent: ViewGroup) : RecyclerView.ViewHolder( + LayoutInflater.from(parent.context).inflate(layoutRes, parent, false) + ) { + + val context: Context = parent.context + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt index fd3d3941807a6a45dd8caf5fcac14a110ffcc052..9f468c223fbd4ddbd7788bf9de503b8d5a92787a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt @@ -10,16 +10,24 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.lifecycleScope +import dagger.android.AndroidInjector +import dagger.android.DispatchingAndroidInjector +import dagger.android.HasAndroidInjector import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient +import de.rki.coronawarnapp.playbook.BackgroundNoise import de.rki.coronawarnapp.storage.LocalData -import de.rki.coronawarnapp.http.playbook.BackgroundNoise +import de.rki.coronawarnapp.ui.base.startActivitySafely import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel +import de.rki.coronawarnapp.util.BackgroundPrioritization import de.rki.coronawarnapp.util.ConnectivityHelper import de.rki.coronawarnapp.util.DialogHelper -import de.rki.coronawarnapp.util.ExternalActionHelper -import de.rki.coronawarnapp.util.PowerManagementHelper +import de.rki.coronawarnapp.util.device.PowerManagement +import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.worker.BackgroundWorkScheduler import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject /** * This activity holds all the fragments (except onboarding) and also registers a listener for @@ -29,7 +37,7 @@ import kotlinx.coroutines.launch * @see ConnectivityHelper * @see BackgroundWorkScheduler */ -class MainActivity : AppCompatActivity() { +class MainActivity : AppCompatActivity(), HasAndroidInjector { companion object { private val TAG: String? = MainActivity::class.simpleName @@ -38,11 +46,20 @@ class MainActivity : AppCompatActivity() { } } + @Inject lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any> + override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector + private val FragmentManager.currentNavigationFragment: Fragment? get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first() private lateinit var settingsViewModel: SettingsViewModel + @Inject + lateinit var backgroundPrioritization: BackgroundPrioritization + + @Inject + lateinit var powerManagement: PowerManagement + /** * Register connection callback. */ @@ -78,11 +95,15 @@ class MainActivity : AppCompatActivity() { } override fun onLocationUnavailable() { - settingsViewModel.updateLocationEnabled(false) + val canIgnoreLocationEnabled = + InternalExposureNotificationClient.deviceSupportsLocationlessScanning() + settingsViewModel.updateLocationEnabled(canIgnoreLocationEnabled) + Timber.d("Location unavailable but can be ignored? $canIgnoreLocationEnabled") } } override fun onCreate(savedInstanceState: Bundle?) { + AppInjector.setup(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) settingsViewModel = ViewModelProviders.of(this).get(SettingsViewModel::class.java) @@ -117,7 +138,7 @@ class MainActivity : AppCompatActivity() { R.string.onboarding_energy_optimized_dialog_button_negative, false, { // go to battery optimization - ExternalActionHelper.disableBatteryOptimizations(this) + startActivitySafely(powerManagement.disableBatteryOptimizationsIntent) }, { // keep battery optimization enabled showManualCheckingRequiredDialog() @@ -126,7 +147,7 @@ class MainActivity : AppCompatActivity() { } private fun checkForEnergyOptimizedEnabled() { - if (!PowerManagementHelper.isIgnoringBatteryOptimizations(this)) { + if (!backgroundPrioritization.isBackgroundActivityPrioritized) { showEnergyOptimizedEnabledForBackground() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..689223bc1972be310d9440d3bc6653e299602c28 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivityModule.kt @@ -0,0 +1,20 @@ +package de.rki.coronawarnapp.ui.main + +import dagger.Module +import dagger.android.ContributesAndroidInjector +import de.rki.coronawarnapp.ui.interoperability.InteroperabilityConfigurationFragment +import de.rki.coronawarnapp.ui.interoperability.InteroperabilityConfigurationFragmentModule +import de.rki.coronawarnapp.ui.onboarding.OnboardingDeltaInteroperabilityModule + +@Module(includes = [OnboardingDeltaInteroperabilityModule::class]) +abstract class MainActivityModule { + + // activity specific injection module for future dependencies + + // example: + // @ContributesAndroidInjector + // abstract fun mainFragment(): MainFragment + + @ContributesAndroidInjector(modules = [InteroperabilityConfigurationFragmentModule::class]) + abstract fun intertopConfigScreen(): InteroperabilityConfigurationFragment +} diff --git a/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt similarity index 80% rename from Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt index ec73b7aa81b7d70e37e0512d2da936a714f5453d..db82cafc9c5b7084710bd046145f62b75eb560dd 100644 --- a/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainFragment.kt @@ -1,9 +1,7 @@ package de.rki.coronawarnapp.ui.main import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import android.widget.PopupMenu import androidx.fragment.app.Fragment @@ -19,8 +17,12 @@ import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel +import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.ExternalActionHelper +import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.errors.RecoveryByResetDialogFactory +import de.rki.coronawarnapp.util.ui.viewBindingLazy import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -35,44 +37,42 @@ import kotlinx.coroutines.withContext * @see submissionViewModel * @see PopupMenu */ -class MainFragment : Fragment() { - - companion object { - private val TAG: String? = MainFragment::class.simpleName - } +class MainFragment : Fragment(R.layout.fragment_main) { private val tracingViewModel: TracingViewModel by activityViewModels() private val settingsViewModel: SettingsViewModel by activityViewModels() private val submissionViewModel: SubmissionViewModel by activityViewModels() - private var _binding: FragmentMainBinding? = null - private val binding: FragmentMainBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentMainBinding.inflate(inflater) - binding.tracingViewModel = tracingViewModel - binding.settingsViewModel = settingsViewModel - binding.submissionViewModel = submissionViewModel - binding.lifecycleOwner = this - return binding.root - } + private val binding: FragmentMainBinding by viewBindingLazy() - override fun onDestroyView() { - super.onDestroyView() - _binding = null + private val errorResetTool by lazy { + AppInjector.component.errorResetTool } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.tracingViewModel = tracingViewModel + binding.settingsViewModel = settingsViewModel + binding.submissionViewModel = submissionViewModel + setButtonOnClickListener() setContentDescription() - + checkShouldInteroperabilityBeOpened() showOneTimeTracingExplanationDialog() } + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + if (errorResetTool.isResetNoticeToBeShown) { + RecoveryByResetDialogFactory(this).showDialog( + detailsLink = R.string.errors_generic_text_catastrophic_error_encryption_failure, + onDismiss = { + errorResetTool.isResetNoticeToBeShown = false + } + ) + } + } + override fun onResume() { super.onResume() // refresh required data @@ -88,12 +88,10 @@ class MainFragment : Fragment() { } private fun setContentDescription() { - val shareButtonString: String = getString(R.string.button_share) - val menuButtonString: String = getString(R.string.button_menu) - val mainCardString: String = getString(R.string.hint_external_webpage) - binding.mainHeaderShare.buttonIcon.contentDescription = shareButtonString - binding.mainHeaderOptionsMenu.buttonIcon.contentDescription = menuButtonString - binding.mainAbout.mainCard.contentDescription = mainCardString + binding.mainHeaderShare.buttonIcon.contentDescription = getString(R.string.button_share) + binding.mainHeaderOptionsMenu.buttonIcon.contentDescription = + getString(R.string.button_menu) + binding.mainAbout.mainCard.contentDescription = getString(R.string.hint_external_webpage) } private fun setButtonOnClickListener() { @@ -156,10 +154,10 @@ class MainFragment : Fragment() { ) } - private fun showPopup(view: View) { - val popup = PopupMenu(requireContext(), view) - popup.inflate(R.menu.menu_main) - popup.setOnMenuItemClickListener { + private fun showPopup(view: View) = PopupMenu(requireContext(), view).apply { + inflate(R.menu.menu_main) + menu.findItem(R.id.menu_test).isVisible = CWADebug.isDeviceForTestersBuild + setOnMenuItemClickListener { return@setOnMenuItemClickListener when (it.itemId) { R.id.menu_help -> { findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToMainOverviewFragment()) @@ -173,10 +171,25 @@ class MainFragment : Fragment() { findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToSettingsFragment()) true } + R.id.menu_test -> { + findNavController().doNavigate(MainFragmentDirections.actionMainFragmentToTestNavGraph()) + true + } else -> super.onOptionsItemSelected(it) } } - popup.show() + }.show() + + private fun checkShouldInteroperabilityBeOpened() { + if (!LocalData.isInteroperabilityShownAtLeastOnce) { + navigateToInteroperabilityFeature() + } + } + + private fun navigateToInteroperabilityFeature() { + findNavController().doNavigate( + MainFragmentDirections.actionMainFragmentToOnboardingDeltaInteroperabilityFragment() + ) } private fun showOneTimeTracingExplanationDialog() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainOverviewFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainOverviewFragment.kt index 67b6ebbe80b2cfc72150ad78ee1b68f853d17c61..c99a5dba307a8486871d86d3fd8929817ed8fb26 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainOverviewFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainOverviewFragment.kt @@ -1,12 +1,12 @@ package de.rki.coronawarnapp.ui.main import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentMainOverviewBinding +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * The fragment displays static informative content to the user @@ -15,28 +15,9 @@ import de.rki.coronawarnapp.databinding.FragmentMainOverviewBinding * */ -class MainOverviewFragment : Fragment() { +class MainOverviewFragment : Fragment(R.layout.fragment_main_overview) { - companion object { - private val TAG: String? = MainOverviewFragment::class.simpleName - } - - private var _binding: FragmentMainOverviewBinding? = null - private val binding: FragmentMainOverviewBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentMainOverviewBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentMainOverviewBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainShareFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainShareFragment.kt index 52c0e3df59de90639ce0c92aec3f62300e00934d..a82e0c320d3edbd0dd6bc5dae69918206681f5c4 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainShareFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainShareFragment.kt @@ -1,9 +1,7 @@ package de.rki.coronawarnapp.ui.main import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -11,40 +9,21 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentMainShareBinding import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.util.ExternalActionHelper +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * This fragment informs the user about what he is going to share and how he is going to help everybody with this :) * * @see TracingViewModel */ -class MainShareFragment : Fragment() { - - companion object { - private val TAG: String? = MainShareFragment::class.simpleName - } +class MainShareFragment : Fragment(R.layout.fragment_main_share) { private val tracingViewModel: TracingViewModel by activityViewModels() - private var _binding: FragmentMainShareBinding? = null - private val binding: FragmentMainShareBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentMainShareBinding.inflate(inflater) - binding.tracingViewModel = tracingViewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentMainShareBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.tracingViewModel = tracingViewModel setButtonOnClickListener() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt index 4da93c88dbf3f80e4bfbd951c00f84e0bdf8e1c1..6bf286800370e70f60b0f12b70a68b3c59f87d31 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt @@ -7,16 +7,21 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.LifecycleObserver +import dagger.android.AndroidInjector +import dagger.android.DispatchingAndroidInjector +import dagger.android.HasAndroidInjector import de.rki.coronawarnapp.R import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.util.di.AppInjector +import javax.inject.Inject /** * This activity holds all the onboarding fragments and isn't used after a successful onboarding flow. * * @see LocalData */ -class OnboardingActivity : AppCompatActivity(), LifecycleObserver { +class OnboardingActivity : AppCompatActivity(), LifecycleObserver, HasAndroidInjector { companion object { private val TAG: String? = OnboardingActivity::class.simpleName @@ -26,10 +31,14 @@ class OnboardingActivity : AppCompatActivity(), LifecycleObserver { } } + @Inject lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any> + override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector + private val FragmentManager.currentNavigationFragment: Fragment? get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first() override fun onCreate(savedInstanceState: Bundle?) { + AppInjector.setup(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_onboarding) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivityModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivityModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..f72ee0245bdc8735ee29d179214ccd1d86864531 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivityModule.kt @@ -0,0 +1,17 @@ +package de.rki.coronawarnapp.ui.onboarding + +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module +internal abstract class OnboardingActivityModule { + + // activity specific injection module for future dependencies + + // example: + // @ContributesAndroidInjector + // abstract fun onboardingFragment(): OnboardingFragment + + @ContributesAndroidInjector(modules = [OnboardingTracingModule::class]) + abstract fun onboardingScreen(): OnboardingTracingFragment +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..d9cd64f18641c3648a5004b7e2aaaee790fd651f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragment.kt @@ -0,0 +1,58 @@ +package de.rki.coronawarnapp.ui.onboarding + +import android.os.Bundle +import android.text.method.LinkMovementMethod +import android.view.View +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentOnboardingDeltaInteroperabilityBinding +import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.util.convertToHyperlink +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModels +import javax.inject.Inject + +class OnboardingDeltaInteroperabilityFragment : + Fragment(R.layout.fragment_onboarding_delta_interoperability), AutoInject { + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val vm: OnboardingDeltaInteroperabilityFragmentViewModel by cwaViewModels { viewModelFactory } + + private val binding: FragmentOnboardingDeltaInteroperabilityBinding by viewBindingLazy() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + vm.countryList.observe2(this) { + binding.countryData = it + } + vm.saveInteroperabilityUsed() + + binding.onboardingInclude.onboardingDeltaExpandedTermsTextLink + .convertToHyperlink(getString(R.string.information_terms_html_path)) + binding.onboardingInclude.onboardingDeltaExpandedTermsTextLink + .movementMethod = LinkMovementMethod.getInstance() + + binding.onboardingInclude.onboardingDeltaExpandedTermsTextLink.setOnClickListener { + findNavController().doNavigate(OnboardingDeltaInteroperabilityFragmentDirections + .actionOnboardingDeltaInteroperabilityFragmentToInformationTermsFragment()) + } + + binding.onboardingButtonBack.buttonIcon.setOnClickListener { + vm.onBackPressed() + } + binding.onboardingButtonNext.setOnClickListener { + vm.onBackPressed() + } + + vm.navigateBack.observe2(this) { + if (it) { + (requireActivity() as MainActivity).goBack() + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragmentViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..d817af9e90e91a55f57f2c9fb5cdadfea1847041 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragmentViewModel.kt @@ -0,0 +1,26 @@ +package de.rki.coronawarnapp.ui.onboarding + +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository +import de.rki.coronawarnapp.util.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory + +class OnboardingDeltaInteroperabilityFragmentViewModel @AssistedInject constructor( + private val interoperabilityRepository: InteroperabilityRepository +) : CWAViewModel() { + + val countryList = interoperabilityRepository.countryList + val navigateBack = SingleLiveEvent<Boolean>() + + fun onBackPressed() { + navigateBack.postValue(true) + } + + fun saveInteroperabilityUsed() { + interoperabilityRepository.saveInteroperabilityUsed() + } + + @AssistedInject.Factory + interface Factory : SimpleCWAViewModelFactory<OnboardingDeltaInteroperabilityFragmentViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..035c4f1bbeb6e6b8b069ec7564302b734384a0ab --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityModule.kt @@ -0,0 +1,23 @@ +package de.rki.coronawarnapp.ui.onboarding + +import dagger.Binds +import dagger.Module +import dagger.android.ContributesAndroidInjector +import dagger.multibindings.IntoMap +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey + +@Module +abstract class OnboardingDeltaInteroperabilityModule { + + @Binds + @IntoMap + @CWAViewModelKey(OnboardingDeltaInteroperabilityFragmentViewModel::class) + abstract fun interopOnBoardingDeltaScreenVM( + factory: OnboardingDeltaInteroperabilityFragmentViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> + + @ContributesAndroidInjector + abstract fun interopOnBoardingDeltaScreen(): OnboardingDeltaInteroperabilityFragment +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragment.kt index e01dac101a8a7ac0070713df131b8f141a3bacf3..df4b0d3f6735f76ff3e8f1f778ef88774802449a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragment.kt @@ -1,40 +1,23 @@ package de.rki.coronawarnapp.ui.onboarding +import android.content.Intent +import android.net.Uri import android.os.Bundle -import android.text.method.LinkMovementMethod -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentOnboardingBinding import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * Onboarding starting point. */ -class OnboardingFragment : Fragment() { - companion object { - private val TAG: String? = OnboardingFragment::class.simpleName - } - - private var _binding: FragmentOnboardingBinding? = null - private val binding: FragmentOnboardingBinding get() = _binding!! +class OnboardingFragment : Fragment(R.layout.fragment_onboarding) { - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentOnboardingBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentOnboardingBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -48,7 +31,13 @@ class OnboardingFragment : Fragment() { private fun setLinks() { binding.onboardingInclude.onboardingEasyLanguage - .movementMethod = LinkMovementMethod.getInstance() + .setOnClickListener { + val browserIntent = Intent( + Intent.ACTION_VIEW, + Uri.parse(getString(R.string.onboarding_tracing_easy_language_explanation_url)) + ) + startActivity(browserIntent) + } } override fun onResume() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt index c6768a15f48d752bc6b7ce8ba8022a4eee645790..7ebb2b1d16e1886134c81ebae426795184b9e380 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt @@ -1,14 +1,14 @@ package de.rki.coronawarnapp.ui.onboarding import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.appcompat.app.AlertDialog import androidx.core.app.NotificationManagerCompat import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentOnboardingNotificationsBinding +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * This fragment ask the user if he wants to get notifications and finishes the onboarding afterwards. @@ -16,27 +16,9 @@ import de.rki.coronawarnapp.databinding.FragmentOnboardingNotificationsBinding * @see NotificationManagerCompat * @see AlertDialog */ -class OnboardingNotificationsFragment : Fragment() { - companion object { - private val TAG: String? = OnboardingNotificationsFragment::class.simpleName - } - - private var _binding: FragmentOnboardingNotificationsBinding? = null - private val binding: FragmentOnboardingNotificationsBinding get() = _binding!! +class OnboardingNotificationsFragment : Fragment(R.layout.fragment_onboarding_notifications) { - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentOnboardingNotificationsBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentOnboardingNotificationsBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingPrivacyFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingPrivacyFragment.kt index f15cbfbde6c084c29ee22e40add187f5ef94f49a..010b629c714a490b2f1e40d4f31123a46726c6c8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingPrivacyFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingPrivacyFragment.kt @@ -1,39 +1,21 @@ package de.rki.coronawarnapp.ui.onboarding import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentOnboardingPrivacyBinding import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * This fragment informs the user regarding privacy. */ -class OnboardingPrivacyFragment : Fragment() { - companion object { - private val TAG: String? = OnboardingPrivacyFragment::class.simpleName - } - - private var _binding: FragmentOnboardingPrivacyBinding? = null - private val binding: FragmentOnboardingPrivacyBinding get() = _binding!! +class OnboardingPrivacyFragment : Fragment(R.layout.fragment_onboarding_privacy) { - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentOnboardingPrivacyBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentOnboardingPrivacyBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTestFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTestFragment.kt index 2923d9ea0f06dbc570783d41a99d0b24b6b9b5f6..a66ac14e56298884c776a73c3e6395f7a0dab7c0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTestFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTestFragment.kt @@ -1,39 +1,20 @@ package de.rki.coronawarnapp.ui.onboarding import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentOnboardingTestBinding import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * This fragment informs the user about test results. */ -class OnboardingTestFragment : Fragment() { - companion object { - private val TAG: String? = OnboardingTestFragment::class.simpleName - } - - private var _binding: FragmentOnboardingTestBinding? = null - private val binding: FragmentOnboardingTestBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentOnboardingTestBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } +class OnboardingTestFragment : Fragment(R.layout.fragment_onboarding_test) { + private val binding: FragmentOnboardingTestBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt index 23f302095ecfca1dc2fc645a8751af08b5535140..2b2698e0b6fabbc0fbc11fb0fd84b741d01e8bdd 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt @@ -2,24 +2,22 @@ package de.rki.coronawarnapp.ui.onboarding import android.content.Intent import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment -import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentOnboardingTracingBinding -import de.rki.coronawarnapp.exception.ExceptionCategory -import de.rki.coronawarnapp.exception.reporting.report -import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper -import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.util.DialogHelper -import kotlinx.coroutines.launch +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider +import de.rki.coronawarnapp.util.viewmodel.cwaViewModels +import javax.inject.Inject /** * This fragment ask the user if he wants to enable tracing. @@ -27,16 +25,14 @@ import kotlinx.coroutines.launch * @see InternalExposureNotificationPermissionHelper * @see AlertDialog */ -class OnboardingTracingFragment : Fragment(), - InternalExposureNotificationPermissionHelper.Callback { - - companion object { - private val TAG: String? = OnboardingTracingFragment::class.simpleName - } +class OnboardingTracingFragment : Fragment(R.layout.fragment_onboarding_tracing), + InternalExposureNotificationPermissionHelper.Callback, AutoInject { private lateinit var internalExposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper - private var _binding: FragmentOnboardingTracingBinding? = null - private val binding: FragmentOnboardingTracingBinding get() = _binding!! + private val binding: FragmentOnboardingTracingBinding by viewBindingLazy() + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val vm: OnboardingTracingFragmentViewModel by cwaViewModels { viewModelFactory } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { internalExposureNotificationPermissionHelper.onResolutionComplete( @@ -51,29 +47,19 @@ class OnboardingTracingFragment : Fragment(), InternalExposureNotificationPermissionHelper(this, this) } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentOnboardingTracingBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setButtonOnClickListener() + vm.countryList.observe2(this) { + binding.countryData = it + } + vm.saveInteroperabilityUsed() } override fun onResume() { super.onResume() binding.onboardingTracingContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) - resetTracing() + vm.resetTracing() } private fun setButtonOnClickListener() { @@ -84,7 +70,7 @@ class OnboardingTracingFragment : Fragment(), showCancelDialog() } binding.onboardingButtonBack.buttonIcon.setOnClickListener { - (activity as OnboardingActivity).goBack() + (requireActivity() as OnboardingActivity).goBack() } } @@ -115,23 +101,4 @@ class OnboardingTracingFragment : Fragment(), OnboardingTracingFragmentDirections.actionOnboardingTracingFragmentToOnboardingTestFragment() ) } - - private fun resetTracing() { - // Reset tracing state in onboarding - lifecycleScope.launch { - try { - if (InternalExposureNotificationClient.asyncIsEnabled()) { - InternalExposureNotificationClient.asyncStop() - // Reset initial activation timestamp - LocalData.initialTracingActivationTimestamp(0L) - } - } catch (exception: Exception) { - exception.report( - ExceptionCategory.EXPOSURENOTIFICATION, - OnboardingTracingFragment.TAG, - null - ) - } - } - } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragmentViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..ed3c9bcf05fb84c88eefac276a7e5f63d8c8ad29 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragmentViewModel.kt @@ -0,0 +1,49 @@ +package de.rki.coronawarnapp.ui.onboarding + +import androidx.lifecycle.viewModelScope +import com.squareup.inject.assisted.AssistedInject +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient +import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory +import kotlinx.coroutines.launch + +class OnboardingTracingFragmentViewModel @AssistedInject constructor( + private val interoperabilityRepository: InteroperabilityRepository +) : CWAViewModel() { + + val countryList = interoperabilityRepository.countryList + + fun saveInteroperabilityUsed() { + interoperabilityRepository.saveInteroperabilityUsed() + } + + // Reset tracing state in onboarding + fun resetTracing() { + viewModelScope.launch { + try { + if (InternalExposureNotificationClient.asyncIsEnabled()) { + InternalExposureNotificationClient.asyncStop() + // Reset initial activation timestamp + LocalData.initialTracingActivationTimestamp(0L) + } + } catch (exception: Exception) { + exception.report( + ExceptionCategory.EXPOSURENOTIFICATION, + TAG, + null + ) + } + } + } + + @AssistedInject.Factory + interface Factory : SimpleCWAViewModelFactory<OnboardingTracingFragmentViewModel> + + companion object { + private val TAG: String? = OnboardingTracingFragmentViewModel::class.simpleName + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..078a969a21856150d43932533eb7fa68b5aeb06d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingModule.kt @@ -0,0 +1,23 @@ +package de.rki.coronawarnapp.ui.onboarding + +import dagger.Binds +import dagger.Module +import dagger.android.ContributesAndroidInjector +import dagger.multibindings.IntoMap +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey + +@Module +abstract class OnboardingTracingModule { + + @Binds + @IntoMap + @CWAViewModelKey(OnboardingTracingFragmentViewModel::class) + abstract fun onboardingScreenVM( + factory: OnboardingTracingFragmentViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> + + @ContributesAndroidInjector + abstract fun onboardingScreen(): OnboardingFragment +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/riskdetails/RiskDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/riskdetails/RiskDetailsFragment.kt index d816080e0948d03eebb3399b908dfaf873ba0529..b3846cbb98c8f33c0c9619151881a6f599fbade5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/riskdetails/RiskDetailsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/riskdetails/RiskDetailsFragment.kt @@ -1,19 +1,20 @@ package de.rki.coronawarnapp.ui.riskdetails import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentRiskDetailsBinding import de.rki.coronawarnapp.timer.TimerHelper import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.convertToHyperlink /** * This is the detail view of the risk card if additional information for the user. @@ -21,37 +22,18 @@ import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel * @see TracingViewModel * @see SettingsViewModel */ -class RiskDetailsFragment : Fragment() { - - companion object { - private val TAG: String? = RiskDetailsFragment::class.simpleName - } +class RiskDetailsFragment : Fragment(R.layout.fragment_risk_details) { private val tracingViewModel: TracingViewModel by activityViewModels() private val settingsViewModel: SettingsViewModel by activityViewModels() - private var _binding: FragmentRiskDetailsBinding? = null - private val binding: FragmentRiskDetailsBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentRiskDetailsBinding.inflate(inflater) - binding.tracingViewModel = tracingViewModel - binding.settingsViewModel = settingsViewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentRiskDetailsBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.tracingViewModel = tracingViewModel + binding.settingsViewModel = settingsViewModel setButtonOnClickListeners() + setUpWebLinks() } override fun onResume() { @@ -65,6 +47,14 @@ class RiskDetailsFragment : Fragment() { binding.riskDetailsContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) } + /** + * Make the links clickable and convert to hyperlink + */ + private fun setUpWebLinks() { + binding.riskDetailsInformationLowriskBodyUrl + .convertToHyperlink(getString(R.string.risk_details_explanation_faq_body_with_link)) + } + private fun setButtonOnClickListeners() { binding.riskDetailsHeaderButtonBack.setOnClickListener { (activity as MainActivity).goBack() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsBackgroundPriorityFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsBackgroundPriorityFragment.kt index b5d465e9fbd0954d9ac49bb405d88c1ccf4239a7..57db3b076f914cd0d6c72fe88b423a9e67f1d5ae 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsBackgroundPriorityFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsBackgroundPriorityFragment.kt @@ -1,17 +1,17 @@ package de.rki.coronawarnapp.ui.settings import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSettingsBackgroundPriorityBinding +import de.rki.coronawarnapp.ui.base.startActivitySafely import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel -import de.rki.coronawarnapp.util.ExternalActionHelper +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * This is the setting background priority page. Here the user sees the background priority setting status. @@ -20,33 +20,15 @@ import de.rki.coronawarnapp.util.ExternalActionHelper * @see TracingViewModel * @see SettingsViewModel */ -class SettingsBackgroundPriorityFragment : Fragment() { - companion object { - private val TAG: String? = SettingsBackgroundPriorityFragment::class.simpleName - } +class SettingsBackgroundPriorityFragment : + Fragment(R.layout.fragment_settings_background_priority) { private val settingsViewModel: SettingsViewModel by activityViewModels() - private var _binding: FragmentSettingsBackgroundPriorityBinding? = null - private val binding: FragmentSettingsBackgroundPriorityBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentSettingsBackgroundPriorityBinding.inflate(inflater) - binding.settingsViewModel = settingsViewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSettingsBackgroundPriorityBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.settingsViewModel = settingsViewModel setButtonOnClickListener() } @@ -54,7 +36,7 @@ class SettingsBackgroundPriorityFragment : Fragment() { super.onResume() binding.settingsBackgroundPriorityContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) // refresh required data - settingsViewModel.refreshBackgroundPriorityEnabled(requireContext()) + settingsViewModel.refreshBackgroundPriorityEnabled() } private fun setButtonOnClickListener() { @@ -66,14 +48,19 @@ class SettingsBackgroundPriorityFragment : Fragment() { it.setOnClickListener { val isPriorityEnabled = settingsViewModel.isBackgroundPriorityEnabled.value == true - if (!isPriorityEnabled) - ExternalActionHelper.disableBatteryOptimizations(requireContext()) + if (!isPriorityEnabled) { + (requireActivity() as MainActivity).apply { + startActivitySafely(powerManagement.disableBatteryOptimizationsIntent) + } + } } } // explanatory card binding.settingsTracingStatusConnection.tracingStatusCardButton.setOnClickListener { - ExternalActionHelper.toBatteryOptimizationSettings(requireContext()) + (requireActivity() as MainActivity).apply { + startActivity(powerManagement.toBatteryOptimizationSettingsIntent) + } } // back navigation diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsFragment.kt index 258db57c53ac5fe4b0c60817f9f36ad815783419..ab2dd1d05f46a23bf02313e24ad9cc9a59f47011 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsFragment.kt @@ -1,18 +1,18 @@ package de.rki.coronawarnapp.ui.settings import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSettingsBinding import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * This is the setting overview page. @@ -20,36 +20,16 @@ import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel * @see TracingViewModel * @see SettingsViewModel */ -class SettingsFragment : Fragment() { - - companion object { - private val TAG: String? = SettingsFragment::class.simpleName - } +class SettingsFragment : Fragment(R.layout.fragment_settings) { private val tracingViewModel: TracingViewModel by activityViewModels() private val settingsViewModel: SettingsViewModel by activityViewModels() - private var _binding: FragmentSettingsBinding? = null - private val binding: FragmentSettingsBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentSettingsBinding.inflate(inflater) - binding.tracingViewModel = tracingViewModel - binding.settingsViewModel = settingsViewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSettingsBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.tracingViewModel = tracingViewModel + binding.settingsViewModel = settingsViewModel setButtonOnClickListener() } @@ -57,10 +37,10 @@ class SettingsFragment : Fragment() { super.onResume() // refresh required data tracingViewModel.refreshIsTracingEnabled() - settingsViewModel.refreshNotificationsEnabled(requireContext()) + settingsViewModel.refreshNotificationsEnabled() settingsViewModel.refreshNotificationsRiskEnabled() settingsViewModel.refreshNotificationsTestEnabled() - settingsViewModel.refreshBackgroundPriorityEnabled(requireContext()) + settingsViewModel.refreshBackgroundPriorityEnabled() binding.settingsContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsNotificationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsNotificationFragment.kt index 48445dcc8c8f20b2e7a4045733b53bf9bcbe29ca..5cba2de2b865b10ae138723a20ea626852ed598b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsNotificationFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsNotificationFragment.kt @@ -1,18 +1,17 @@ package de.rki.coronawarnapp.ui.settings import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSettingsNotificationsBinding import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.util.ExternalActionHelper -import de.rki.coronawarnapp.util.IGNORE_CHANGE_TAG +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * This is the setting notification page. Here the user sees his os notifications settings status. @@ -22,33 +21,14 @@ import de.rki.coronawarnapp.util.IGNORE_CHANGE_TAG * @see TracingViewModel * @see SettingsViewModel */ -class SettingsNotificationFragment : Fragment() { - companion object { - private val TAG: String? = SettingsNotificationFragment::class.simpleName - } +class SettingsNotificationFragment : Fragment(R.layout.fragment_settings_notifications) { private val settingsViewModel: SettingsViewModel by activityViewModels() - private var _binding: FragmentSettingsNotificationsBinding? = null - private val binding: FragmentSettingsNotificationsBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentSettingsNotificationsBinding.inflate(inflater) - binding.settingsViewModel = settingsViewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSettingsNotificationsBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.settingsViewModel = settingsViewModel setButtonOnClickListener() } @@ -56,7 +36,7 @@ class SettingsNotificationFragment : Fragment() { super.onResume() binding.settingsNotificationsContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) // refresh required data - settingsViewModel.refreshNotificationsEnabled(requireContext()) + settingsViewModel.refreshNotificationsEnabled() settingsViewModel.refreshNotificationsRiskEnabled() settingsViewModel.refreshNotificationsTestEnabled() } @@ -79,9 +59,9 @@ class SettingsNotificationFragment : Fragment() { val goBack = binding.settingsNotificationsHeader.headerButtonBack.buttonIcon // Update Risk - updateRiskNotificationSwitch.setOnCheckedChangeListener { _, _ -> + updateRiskNotificationSwitch.setOnCheckedChangeListener { view, _ -> // Make sure that listener is called by user interaction - if (updateRiskNotificationSwitch.tag != IGNORE_CHANGE_TAG) { + if (view.isPressed) { settingsViewModel.toggleNotificationsRiskEnabled() } } @@ -90,9 +70,9 @@ class SettingsNotificationFragment : Fragment() { if (updateRiskNotificationRow.isEnabled) settingsViewModel.toggleNotificationsRiskEnabled() } // Update Test - updateTestNotificationSwitch.setOnCheckedChangeListener { _, _ -> + updateTestNotificationSwitch.setOnCheckedChangeListener { view, _ -> // Make sure that listener is called by user interaction - if (updateTestNotificationSwitch.tag != IGNORE_CHANGE_TAG) { + if (view.isPressed) { settingsViewModel.toggleNotificationsTestEnabled() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt index 77b7043444bbbb633a7dd539eb5e0ff7bbd88cd8..74bf4859462a9971738756c3583c3ad76a96a30c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt @@ -2,9 +2,7 @@ package de.rki.coronawarnapp.ui.settings import android.app.AlertDialog import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope @@ -18,6 +16,7 @@ import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.onboarding.OnboardingActivity import de.rki.coronawarnapp.util.DataRetentionHelper import de.rki.coronawarnapp.util.DialogHelper +import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.worker.BackgroundWorkScheduler import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -27,28 +26,13 @@ import kotlinx.coroutines.withContext * The user is informed what a reset means and he can perform it. * */ -class SettingsResetFragment : Fragment() { +class SettingsResetFragment : Fragment(R.layout.fragment_settings_reset) { companion object { private val TAG: String? = SettingsResetFragment::class.simpleName } - private var _binding: FragmentSettingsResetBinding? = null - private val binding: FragmentSettingsResetBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentSettingsResetBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSettingsResetBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt index b954f326c491df28203987fc6a0a5becc08b14f0..7f496e7d23977b22ce93e18b1feecdfa7b676150 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsTracingFragment.kt @@ -2,13 +2,12 @@ package de.rki.coronawarnapp.ui.settings import android.content.Intent import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSettingsTracingBinding import de.rki.coronawarnapp.exception.ExceptionCategory @@ -16,14 +15,15 @@ import de.rki.coronawarnapp.exception.reporting.report import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.ExternalActionHelper -import de.rki.coronawarnapp.util.IGNORE_CHANGE_TAG -import de.rki.coronawarnapp.util.PowerManagementHelper import de.rki.coronawarnapp.util.formatter.formatTracingSwitchEnabled +import de.rki.coronawarnapp.util.ui.observe2 +import de.rki.coronawarnapp.util.ui.viewBindingLazy import de.rki.coronawarnapp.worker.BackgroundWorkScheduler import kotlinx.coroutines.launch @@ -35,7 +35,7 @@ import kotlinx.coroutines.launch * @see InternalExposureNotificationClient * @see InternalExposureNotificationPermissionHelper */ -class SettingsTracingFragment : Fragment(), +class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), InternalExposureNotificationPermissionHelper.Callback { companion object { @@ -44,30 +44,21 @@ class SettingsTracingFragment : Fragment(), private val tracingViewModel: TracingViewModel by activityViewModels() private val settingsViewModel: SettingsViewModel by activityViewModels() - private var _binding: FragmentSettingsTracingBinding? = null - private val binding: FragmentSettingsTracingBinding get() = _binding!! + private val binding: FragmentSettingsTracingBinding by viewBindingLazy() private lateinit var internalExposureNotificationPermissionHelper: InternalExposureNotificationPermissionHelper - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentSettingsTracingBinding.inflate(inflater) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) binding.tracingViewModel = tracingViewModel binding.settingsViewModel = settingsViewModel - binding.lifecycleOwner = this - return binding.root - } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + tracingViewModel.navigateToInteroperability.observe2(this) { + if (it) { + navigateToInteroperability() + } + } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) setButtonOnClickListener() } @@ -99,13 +90,15 @@ class SettingsTracingFragment : Fragment(), val switch = binding.settingsTracingSwitchRow.settingsSwitchRowSwitch val back = binding.settingsTracingHeader.headerButtonBack.buttonIcon val bluetooth = binding.settingsTracingStatusBluetooth.tracingStatusCardButton - val connection = binding.settingsTracingStatusConnection.tracingStatusCardButton val location = binding.settingsTracingStatusLocation.tracingStatusCardButton + val interoperability = binding.settingsInteroperabilityRow.settingsPlainRow + internalExposureNotificationPermissionHelper = InternalExposureNotificationPermissionHelper(this, this) - switch.setOnCheckedChangeListener { _, _ -> + switch.setOnCheckedChangeListener { view, _ -> + // Make sure that listener is called by user interaction - if (switch.tag != IGNORE_CHANGE_TAG) { + if (view.isPressed) { startStopTracing() // Focus on the body text after to announce the tracing status for accessibility reasons binding.settingsTracingSwitchRow.settingsSwitchRowHeaderBody @@ -117,15 +110,12 @@ class SettingsTracingFragment : Fragment(), tracingViewModel.isTracingEnabled.value ?: throw IllegalArgumentException() val isBluetoothEnabled = settingsViewModel.isBluetoothEnabled.value ?: throw IllegalArgumentException() - val isConnectionEnabled = - settingsViewModel.isConnectionEnabled.value ?: throw IllegalArgumentException() val isLocationEnabled = settingsViewModel.isLocationEnabled.value ?: throw IllegalArgumentException() // check if the row is clickable, this adds the switch behaviour val isEnabled = formatTracingSwitchEnabled( isTracingEnabled, isBluetoothEnabled, - isConnectionEnabled, isLocationEnabled ) if (isEnabled) startStopTracing() @@ -139,11 +129,19 @@ class SettingsTracingFragment : Fragment(), location.setOnClickListener { ExternalActionHelper.toMainSettings(requireContext()) } - connection.setOnClickListener { - ExternalActionHelper.toConnections(requireContext()) + interoperability.setOnClickListener { + tracingViewModel.onInteroperabilitySettingPressed() } } + private fun navigateToInteroperability() { + findNavController() + .doNavigate( + SettingsTracingFragmentDirections + .actionSettingsTracingFragmentToInteropCountryConfigurationFragment() + ) + } + private fun startStopTracing() { // if tracing is enabled when listener is activated it should be disabled lifecycleScope.launch { @@ -162,7 +160,8 @@ class SettingsTracingFragment : Fragment(), // activated during onboarding showConsentDialog() // check if background processing is switched off, if it is, show the manual calculation dialog explanation before turning on. - if (!PowerManagementHelper.isIgnoringBatteryOptimizations(requireActivity())) { + val activity = requireActivity() as MainActivity + if (!activity.backgroundPrioritization.isBackgroundActivityPrioritized) { showManualCheckingRequiredDialog() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionCountry.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionCountry.kt new file mode 100644 index 0000000000000000000000000000000000000000..b4d661288920edd94ffb8c76c7949cc3849fcdb7 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionCountry.kt @@ -0,0 +1,3 @@ +package de.rki.coronawarnapp.ui.submission + +data class SubmissionCountry(val countryCode: String, var selected: Boolean = false) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..cc4cc4b727fe926c05916149d053dcaa33a93e5b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragment.kt @@ -0,0 +1,154 @@ +package de.rki.coronawarnapp.ui.submission + +import android.content.res.ColorStateList +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Observer +import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentSubmissionSymptomCalendarBinding +import de.rki.coronawarnapp.submission.Symptoms +import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel +import de.rki.coronawarnapp.util.formatter.formatCalendarBackgroundButtonStyleByState +import de.rki.coronawarnapp.util.formatter.formatCalendarButtonStyleByState +import de.rki.coronawarnapp.util.formatter.isEnableSymptomCalendarButtonByState + +class SubmissionSymptomCalendarFragment : Fragment() { + + private var _binding: FragmentSubmissionSymptomCalendarBinding? = null + private val binding: FragmentSubmissionSymptomCalendarBinding get() = _binding!! + private val submissionViewModel: SubmissionViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentSubmissionSymptomCalendarBinding.inflate(inflater) + binding.submissionViewModel = submissionViewModel + binding.lifecycleOwner = this + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setButtonOnClickListener() + + binding.symptomCalendarContainer.setDateSelectedListener(submissionViewModel::onDateSelected) + + submissionViewModel.symptomCalendarEvent.observe(viewLifecycleOwner, Observer { + when (it) { + is SymptomCalendarEvent.NavigateToNext -> navigateToSymptomFinish() + is SymptomCalendarEvent.NavigateToPrevious -> navigateToPreviousScreen() + } + }) + + submissionViewModel.symptomStart.observe(viewLifecycleOwner, Observer { + updateButtons(it) + if (it !is Symptoms.StartOf.Date) { + binding.symptomCalendarContainer.unsetSelection() + } + }) + + submissionViewModel.initSymptomStart() + } + + private fun updateButtons(symptomStart: Symptoms.StartOf?) { + binding.symptomCalendarChoiceSelection.calendarButtonSevenDays + .findViewById<Button>(R.id.calendar_button_seven_days) + .setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.LastSevenDays)) + binding.symptomCalendarChoiceSelection.targetLayout + .findViewById<Button>(R.id.calendar_button_seven_days).backgroundTintList = + ColorStateList.valueOf( + formatCalendarBackgroundButtonStyleByState( + symptomStart, Symptoms.StartOf.LastSevenDays + ) + ) + + binding.symptomCalendarChoiceSelection.targetLayout + .findViewById<Button>(R.id.calendar_button_one_two_weeks) + .setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.OneToTwoWeeksAgo)) + binding.symptomCalendarChoiceSelection.targetLayout + .findViewById<Button>(R.id.calendar_button_one_two_weeks).backgroundTintList = + ColorStateList.valueOf( + formatCalendarBackgroundButtonStyleByState( + symptomStart, Symptoms.StartOf.OneToTwoWeeksAgo + ) + ) + + binding.symptomCalendarChoiceSelection.targetLayout + .findViewById<Button>(R.id.calendar_button_more_than_two_weeks) + .setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.MoreThanTwoWeeks)) + binding.symptomCalendarChoiceSelection.targetLayout + .findViewById<Button>(R.id.calendar_button_more_than_two_weeks).backgroundTintList = + ColorStateList.valueOf( + formatCalendarBackgroundButtonStyleByState( + symptomStart, Symptoms.StartOf.MoreThanTwoWeeks + ) + ) + + binding.symptomCalendarChoiceSelection.targetLayout + .findViewById<Button>(R.id.target_button_verify) + .setTextColor(formatCalendarButtonStyleByState(symptomStart, Symptoms.StartOf.NoInformation)) + binding.symptomCalendarChoiceSelection.targetLayout + .findViewById<Button>(R.id.target_button_verify).backgroundTintList = + ColorStateList.valueOf( + formatCalendarBackgroundButtonStyleByState( + symptomStart, Symptoms.StartOf.NoInformation + ) + ) + + binding + .symptomButtonNext.findViewById<Button>(R.id.symptom_button_next).isEnabled = + isEnableSymptomCalendarButtonByState( + symptomStart + ) + } + + private fun navigateToSymptomFinish() { + findNavController().doNavigate(SubmissionSymptomCalendarFragmentDirections + .actionSubmissionSymptomCalendarFragmentToSubmissionResultPositiveOtherWarningFragment()) + } + + private fun navigateToPreviousScreen() { + findNavController().doNavigate(SubmissionSymptomCalendarFragmentDirections + .actionSubmissionCalendarFragmentToSubmissionSymptomIntroductionFragment()) + } + + private fun setButtonOnClickListener() { + binding + .submissionSymptomCalendarHeader.headerButtonBack.buttonIcon + .setOnClickListener { submissionViewModel.onCalendarPreviousClicked() } + + binding + .symptomButtonNext + .setOnClickListener { submissionViewModel.onCalendarNextClicked() } + + binding.symptomCalendarChoiceSelection + .calendarButtonSevenDays + .setOnClickListener { submissionViewModel.onLastSevenDaysStart() } + + binding.symptomCalendarChoiceSelection + .calendarButtonOneTwoWeeks + .setOnClickListener { submissionViewModel.onOneToTwoWeeksAgoStart() } + + binding.symptomCalendarChoiceSelection + .calendarButtonMoreThanTwoWeeks + .setOnClickListener { submissionViewModel.onMoreThanTwoWeeksStart() } + + binding.symptomCalendarChoiceSelection + .targetButtonVerify + .setOnClickListener { submissionViewModel.onNoInformationStart() } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroductionFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroductionFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..1af4a2ede61fc5ff6dd311ea8c05f81048ff77fe --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomIntroductionFragment.kt @@ -0,0 +1,175 @@ +package de.rki.coronawarnapp.ui.submission + +import android.content.res.ColorStateList +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentSubmissionSymptomIntroBinding +import de.rki.coronawarnapp.submission.Symptoms +import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel +import de.rki.coronawarnapp.util.DialogHelper +import de.rki.coronawarnapp.util.formatter.formatBackgroundButtonStyleByState +import de.rki.coronawarnapp.util.formatter.formatButtonStyleByState +import de.rki.coronawarnapp.util.formatter.isEnableSymptomIntroButtonByState + +class SubmissionSymptomIntroductionFragment : Fragment() { + + private var _binding: FragmentSubmissionSymptomIntroBinding? = null + private val binding: FragmentSubmissionSymptomIntroBinding get() = _binding!! + private val submissionViewModel: SubmissionViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentSubmissionSymptomIntroBinding.inflate(inflater) + binding.submissionViewModel = submissionViewModel + binding.lifecycleOwner = this + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setButtonOnClickListener() + + submissionViewModel.symptomIntroductionEvent.observe(viewLifecycleOwner, { + when (it) { + is SymptomIntroductionEvent.NavigateToSymptomCalendar -> navigateToNext() + is SymptomIntroductionEvent.NavigateToPreviousScreen -> handleSubmissionCancellation() + } + }) + + submissionViewModel.symptomIndication.observe(viewLifecycleOwner, { + updateButtons(it) + }) + + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) + + submissionViewModel.initSymptoms() + } + + private val backCallback: OnBackPressedCallback = + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + submissionViewModel.onPreviousClicked() + } + } + + private fun updateButtons(symptomIndication: Symptoms.Indication?) { + binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_apply) + .setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.POSITIVE)) + binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_apply).backgroundTintList = + ColorStateList.valueOf( + formatBackgroundButtonStyleByState( + symptomIndication, + Symptoms.Indication.POSITIVE + ) + ) + binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_reject) + .setTextColor(formatButtonStyleByState(symptomIndication, Symptoms.Indication.NEGATIVE)) + binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_reject).backgroundTintList = + ColorStateList.valueOf( + formatBackgroundButtonStyleByState( + symptomIndication, + Symptoms.Indication.NEGATIVE + ) + ) + binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_verify) + .setTextColor( + formatButtonStyleByState( + symptomIndication, + Symptoms.Indication.NO_INFORMATION + ) + ) + binding.submissionSymptomContainer.findViewById<Button>(R.id.target_button_verify).backgroundTintList = + ColorStateList.valueOf( + formatBackgroundButtonStyleByState( + symptomIndication, + Symptoms.Indication.NO_INFORMATION + ) + ) + binding + .symptomButtonNext.findViewById<Button>(R.id.symptom_button_next).isEnabled = + isEnableSymptomIntroButtonByState( + symptomIndication + ) + } + + private fun navigateToNext() { + + if (submissionViewModel.symptomIndication.value!! == Symptoms.Indication.POSITIVE) { + findNavController().doNavigate( + SubmissionSymptomIntroductionFragmentDirections + .actionSubmissionSymptomIntroductionFragmentToSubmissionSymptomCalendarFragment() + ) + } else { + findNavController().doNavigate( + SubmissionSymptomIntroductionFragmentDirections + .actionSubmissionSymptomIntroductionFragmentToSubmissionResultPositiveOtherWarningFragment() + ) + } + } + + /** + * Opens a Dialog that warns user + * when they're about to cancel the submission flow + * @see DialogHelper + * @see navigateToPreviousScreen + */ + private fun handleSubmissionCancellation() { + DialogHelper.showDialog( + DialogHelper.DialogInstance( + requireActivity(), + R.string.submission_error_dialog_confirm_cancellation_title, + R.string.submission_error_dialog_confirm_cancellation_body, + R.string.submission_error_dialog_confirm_cancellation_button_positive, + R.string.submission_error_dialog_confirm_cancellation_button_negative, + true, + ::navigateToPreviousScreen + ) + ) + } + + private fun navigateToPreviousScreen() { + findNavController().doNavigate( + SubmissionSymptomIntroductionFragmentDirections + .actionSubmissionSymptomIntroductionFragmentToSubmissionResultFragment() + ) + } + + private fun setButtonOnClickListener() { + binding + .submissionSymptomHeader.headerButtonBack.buttonIcon + .setOnClickListener { submissionViewModel.onPreviousClicked() } + + binding + .symptomButtonNext + .setOnClickListener { submissionViewModel.onNextClicked() } + + binding + .symptomChoiceSelection.targetButtonApply + .setOnClickListener { submissionViewModel.onPositiveSymptomIndication() } + + binding + .symptomChoiceSelection.targetButtonReject + .setOnClickListener { submissionViewModel.onNegativeSymptomIndication() } + + binding + .symptomChoiceSelection.targetButtonVerify + .setOnClickListener { submissionViewModel.onNoInformationSymptomIndication() } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomCalendarEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomCalendarEvent.kt new file mode 100644 index 0000000000000000000000000000000000000000..922d0ff4c44846e25266eb7093fa67b3f843422d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomCalendarEvent.kt @@ -0,0 +1,6 @@ +package de.rki.coronawarnapp.ui.submission + +sealed class SymptomCalendarEvent { + object NavigateToNext : SymptomCalendarEvent() + object NavigateToPrevious : SymptomCalendarEvent() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomIntroductionEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomIntroductionEvent.kt new file mode 100644 index 0000000000000000000000000000000000000000..96eb49ef2e3e6ba19beee220f6276b51c5ad7a73 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SymptomIntroductionEvent.kt @@ -0,0 +1,6 @@ +package de.rki.coronawarnapp.ui.submission + +sealed class SymptomIntroductionEvent { + object NavigateToSymptomCalendar : SymptomIntroductionEvent() + object NavigateToPreviousScreen : SymptomIntroductionEvent() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/adapter/SubmissionCountrySelectionAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/adapter/SubmissionCountrySelectionAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..8ad1c4eef9f482eeb04b697e483b99d90b19ebe1 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/adapter/SubmissionCountrySelectionAdapter.kt @@ -0,0 +1,55 @@ +package de.rki.coronawarnapp.ui.submission.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import de.rki.coronawarnapp.databinding.IncludeSubmissionCountryItemBinding +import de.rki.coronawarnapp.ui.submission.SubmissionCountry + +class SubmissionCountrySelectionAdapter(private val onCountrySelectionListener: (SubmissionCountry) -> Unit) : + RecyclerView.Adapter<SubmissionCountrySelectionAdapter.SubmissionCountryHolder>() { + private var _countries = emptyList<SubmissionCountry>() + + fun setCountries(countries: List<SubmissionCountry>) { + _countries = countries + notifyDataSetChanged() + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubmissionCountryHolder { + val inflater = LayoutInflater.from(parent.context) + return SubmissionCountryHolder( + IncludeSubmissionCountryItemBinding.inflate( + inflater, + parent, + false + ) + ) + } + + override fun getItemCount() = _countries.size + + override fun onBindViewHolder(holder: SubmissionCountryHolder, position: Int) { + holder.bind(_countries[position], onCountrySelectionListener) + } + + class SubmissionCountryHolder(private val viewDataBinding: IncludeSubmissionCountryItemBinding) : + RecyclerView.ViewHolder(viewDataBinding.root) { + fun bind( + country: SubmissionCountry, + onCountrySelectionListener: (SubmissionCountry) -> Unit + ) { + viewDataBinding.submissionCountry = country + viewDataBinding.executePendingBindings() + + viewDataBinding.submissionCountrySelectorCountryBody.setOnClickListener { + country.selected = !country.selected + onCountrySelectionListener(country) + } + + viewDataBinding.submissionCountrySelectorCountryRadiobutton.setOnCheckedChangeListener { _, isChecked -> + country.selected = isChecked + onCountrySelectionListener(country) + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionContactFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionContactFragment.kt similarity index 68% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionContactFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionContactFragment.kt index de00ac35c343d7861c46fd7b122d75b4affb023a..8c7c568a1a509b17902e3ae5c3eddbdf2ff2e960 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionContactFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionContactFragment.kt @@ -1,9 +1,7 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.fragment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController @@ -12,29 +10,14 @@ import de.rki.coronawarnapp.databinding.FragmentSubmissionContactBinding import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.util.ExternalActionHelper +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * The [SubmissionContactFragment] allows requesting a teletan via phone */ -class SubmissionContactFragment : Fragment() { +class SubmissionContactFragment : Fragment(R.layout.fragment_submission_contact) { - private var _binding: FragmentSubmissionContactBinding? = null - private val binding: FragmentSubmissionContactBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // get the binding reference by inflating it with the current layout - _binding = FragmentSubmissionContactBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSubmissionContactBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -53,6 +36,9 @@ class SubmissionContactFragment : Fragment() { binding.submissionContactButtonCall.setOnClickListener { dial() } + binding.includeSubmissionContact.submissionContactStep1Number.setOnClickListener { + dial() + } binding.submissionContactButtonEnter.setOnClickListener { findNavController().doNavigate( SubmissionContactFragmentDirections.actionSubmissionContactFragmentToSubmissionTanFragment() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionCountrySelectionFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionCountrySelectionFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..c3a9a3130e34369ebae1e1ad2bb48881bcf2bc9c --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionCountrySelectionFragment.kt @@ -0,0 +1,63 @@ +package de.rki.coronawarnapp.ui.submission.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import de.rki.coronawarnapp.databinding.FragmentSubmissionCountrySelectionBinding +import de.rki.coronawarnapp.ui.submission.adapter.SubmissionCountrySelectionAdapter +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionCountrySelectViewModel + +class SubmissionCountrySelectionFragment : Fragment() { + + companion object { + private val TAG: String? = SubmissionCountrySelectionFragment::class.simpleName + } + + private val viewModel: SubmissionCountrySelectViewModel by viewModels() + private var _binding: FragmentSubmissionCountrySelectionBinding? = null + private val binding: FragmentSubmissionCountrySelectionBinding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentSubmissionCountrySelectionBinding.inflate(inflater) + binding.submissionCountrySelectViewModel = viewModel + binding.lifecycleOwner = this + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val adapter = SubmissionCountrySelectionAdapter { + viewModel.updateCountryCheckedState(it) + } + + viewModel.countries.observe(viewLifecycleOwner, Observer { + adapter.setCountries(it) + }) + + binding.submissionCountrySelectionSelector.submissionCountrySelectorRecyclerview.adapter = + adapter + + binding.submissionCountrySelectionSelector.submissionCountrySelectorRecyclerview.layoutManager = + LinearLayoutManager(context) + + binding.submissionCountrySelectionNoSelection.submissionCountryNoSelectionContainer.setOnClickListener { + viewModel.noInfoClick() + } + + viewModel.fetchCountries() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDispatcherFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDispatcherFragment.kt similarity index 64% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDispatcherFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDispatcherFragment.kt index 0ae9e32603cac3dedd9e3797f9cd3a05c80fe1ea..128285d437cf68c4bb4fa31752120117d040fcec 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDispatcherFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDispatcherFragment.kt @@ -1,9 +1,7 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.fragment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController @@ -12,30 +10,11 @@ import de.rki.coronawarnapp.databinding.FragmentSubmissionDispatcherBinding import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.util.DialogHelper +import de.rki.coronawarnapp.util.ui.viewBindingLazy -class SubmissionDispatcherFragment : Fragment() { +class SubmissionDispatcherFragment : Fragment(R.layout.fragment_submission_dispatcher) { - companion object { - private val TAG: String? = SubmissionDispatcherFragment::class.simpleName - } - - private var _binding: FragmentSubmissionDispatcherBinding? = null - private val binding: FragmentSubmissionDispatcherBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentSubmissionDispatcherBinding.inflate(inflater) - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSubmissionDispatcherBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -56,14 +35,12 @@ class SubmissionDispatcherFragment : Fragment() { } binding.submissionDispatcherContent.submissionDispatcherTanCode.dispatcherCard.setOnClickListener { findNavController().doNavigate( - SubmissionDispatcherFragmentDirections - .actionSubmissionDispatcherFragmentToSubmissionTanFragment() + SubmissionDispatcherFragmentDirections.actionSubmissionDispatcherFragmentToSubmissionTanFragment() ) } binding.submissionDispatcherContent.submissionDispatcherTanTele.dispatcherCard.setOnClickListener { findNavController().doNavigate( - SubmissionDispatcherFragmentDirections - .actionSubmissionDispatcherFragmentToSubmissionContactFragment() + SubmissionDispatcherFragmentDirections.actionSubmissionDispatcherFragmentToSubmissionContactFragment() ) } } @@ -86,8 +63,7 @@ class SubmissionDispatcherFragment : Fragment() { private fun privacyPermissionIsGranted() { findNavController().doNavigate( - SubmissionDispatcherFragmentDirections - .actionSubmissionDispatcherFragmentToSubmissionQRCodeScanFragment() + SubmissionDispatcherFragmentDirections.actionSubmissionDispatcherFragmentToSubmissionQRCodeScanFragment() ) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDoneFragment.kt similarity index 64% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDoneFragment.kt index 5efab5ef21f2333b8737bb6d5b80140614a996ba..c8ebbb8a02ebd71d66e335427000101c60fb6184 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDoneFragment.kt @@ -1,37 +1,21 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.fragment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionDoneBinding import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * The [SubmissionDoneFragment] displays information to a user that submitted his exposure keys */ -class SubmissionDoneFragment : Fragment() { +class SubmissionDoneFragment : Fragment(R.layout.fragment_submission_done) { - private var _binding: FragmentSubmissionDoneBinding? = null - private val binding: FragmentSubmissionDoneBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // get the binding reference by inflating it with the current layout - _binding = FragmentSubmissionDoneBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSubmissionDoneBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionIntroFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionIntroFragment.kt similarity index 64% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionIntroFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionIntroFragment.kt index 3ad69bd6b9a2b6883013917664c96e2646d5ab02..cf00793bd02a96a8d4449a7a8df96af0a69a040d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionIntroFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionIntroFragment.kt @@ -1,37 +1,21 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.fragment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionIntroBinding import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * The [SubmissionIntroFragment] displays information about how the corona warning system works */ -class SubmissionIntroFragment : Fragment() { +class SubmissionIntroFragment : Fragment(R.layout.fragment_submission_intro) { - private var _binding: FragmentSubmissionIntroBinding? = null - private val binding: FragmentSubmissionIntroBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // get the binding reference by inflating it with the current layout - _binding = FragmentSubmissionIntroBinding.inflate(inflater) - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSubmissionIntroBinding by viewBindingLazy() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionQRCodeScanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionQRCodeScanFragment.kt similarity index 81% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionQRCodeScanFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionQRCodeScanFragment.kt index c6492216c45e12e6fd8676543ecf564a9038540e..9216658159f461c879eb6e90f3411dcdd76f65db 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionQRCodeScanFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionQRCodeScanFragment.kt @@ -1,11 +1,9 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.fragment import android.Manifest import android.content.pm.PackageManager import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -21,36 +19,27 @@ import de.rki.coronawarnapp.exception.http.CwaServerError import de.rki.coronawarnapp.exception.http.CwaWebException import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.ui.submission.ApiRequestState +import de.rki.coronawarnapp.ui.submission.ScanStatus import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel import de.rki.coronawarnapp.util.CameraPermissionHelper import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.observeEvent +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * A simple [Fragment] subclass. */ -class SubmissionQRCodeScanFragment : Fragment() { +class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_code_scan) { companion object { private const val REQUEST_CAMERA_PERMISSION_CODE = 1 - private val TAG: String? = SubmissionQRCodeScanFragment::class.simpleName } private val viewModel: SubmissionViewModel by activityViewModels() - private var _binding: FragmentSubmissionQrCodeScanBinding? = null - private val binding: FragmentSubmissionQrCodeScanBinding get() = _binding!! + private val binding: FragmentSubmissionQrCodeScanBinding by viewBindingLazy() private var showsPermissionDialog = false - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentSubmissionQrCodeScanBinding.inflate(inflater) - binding.lifecycleOwner = this - return binding.root - } - private fun decodeCallback(result: BarcodeResult) { viewModel.validateAndStoreTestGUID(result.text) } @@ -59,35 +48,19 @@ class SubmissionQRCodeScanFragment : Fragment() { binding.submissionQrCodeScanPreview.decodeSingle { decodeCallback(it) } } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance { return when (exception) { is BadRequestException -> DialogHelper.DialogInstance( requireActivity(), - R.string.submission_error_dialog_web_test_paired_title, - R.string.submission_error_dialog_web_test_paired_body, - R.string.submission_error_dialog_web_test_paired_button_positive, - null, - true, - ::navigateToDispatchScreen - ) - is CwaServerError -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - getString( - R.string.submission_error_dialog_web_generic_network_error_body, - exception.statusCode - ), - R.string.submission_error_dialog_web_generic_error_button_positive, - null, + R.string.submission_qr_code_scan_invalid_dialog_headline, + R.string.submission_qr_code_scan_invalid_dialog_body, + R.string.submission_qr_code_scan_invalid_dialog_button_positive, + R.string.submission_qr_code_scan_invalid_dialog_button_negative, true, + { startDecode() }, ::navigateToDispatchScreen ) - is CwaClientError -> DialogHelper.DialogInstance( + is CwaClientError, is CwaServerError -> DialogHelper.DialogInstance( requireActivity(), R.string.submission_error_dialog_web_generic_error_title, getString( @@ -183,17 +156,15 @@ class SubmissionQRCodeScanFragment : Fragment() { permissions: Array<String>, grantResults: IntArray ) { - if (requestCode == REQUEST_CAMERA_PERMISSION_CODE) { - - // permission was denied - if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_DENIED)) { + // if permission was denied + if (requestCode == REQUEST_CAMERA_PERMISSION_CODE && + (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_DENIED)) { if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { showCameraPermissionRationaleDialog() } else { // user permanently denied access to the camera showCameraPermissionDeniedDialog() } - } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionResultPositiveOtherWarningFragment.kt similarity index 79% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionResultPositiveOtherWarningFragment.kt index 471d9f48c22b05b97bd0e5b4c81f7b58dfc437c2..6c06f446b8aca66d191ab39339b8ae21a81333bf 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionResultPositiveOtherWarningFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionResultPositiveOtherWarningFragment.kt @@ -1,14 +1,11 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.fragment import android.content.Intent import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey import de.rki.coronawarnapp.R @@ -16,28 +13,27 @@ import de.rki.coronawarnapp.databinding.FragmentSubmissionPositiveOtherWarningBi import de.rki.coronawarnapp.exception.http.BadRequestException import de.rki.coronawarnapp.exception.http.CwaClientError import de.rki.coronawarnapp.exception.http.CwaServerError +import de.rki.coronawarnapp.exception.http.CwaWebException import de.rki.coronawarnapp.exception.http.ForbiddenException import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper import de.rki.coronawarnapp.ui.doNavigate +import de.rki.coronawarnapp.ui.submission.ApiRequestState import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.observeEvent +import de.rki.coronawarnapp.util.ui.viewBindingLazy -class SubmissionResultPositiveOtherWarningFragment : Fragment(), +class SubmissionResultPositiveOtherWarningFragment : + Fragment(R.layout.fragment_submission_positive_other_warning), InternalExposureNotificationPermissionHelper.Callback { - companion object { - private val TAG: String? = SubmissionResultPositiveOtherWarningFragment::class.simpleName - } - private val submissionViewModel: SubmissionViewModel by activityViewModels() private val tracingViewModel: TracingViewModel by activityViewModels() - private var _binding: FragmentSubmissionPositiveOtherWarningBinding? = null - private val binding: FragmentSubmissionPositiveOtherWarningBinding get() = _binding!! + private val binding: FragmentSubmissionPositiveOtherWarningBinding by viewBindingLazy() private lateinit var internalExposureNotificationPermissionHelper: - InternalExposureNotificationPermissionHelper + InternalExposureNotificationPermissionHelper override fun onResume() { super.onResume() @@ -45,25 +41,7 @@ class SubmissionResultPositiveOtherWarningFragment : Fragment(), tracingViewModel.refreshIsTracingEnabled() } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - internalExposureNotificationPermissionHelper = - InternalExposureNotificationPermissionHelper(this, this) - _binding = FragmentSubmissionPositiveOtherWarningBinding.inflate(inflater) - binding.submissionViewModel = submissionViewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - private fun buildErrorDialog(exception: Exception): DialogHelper.DialogInstance { + private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance { return when (exception) { is BadRequestException -> DialogHelper.DialogInstance( requireActivity(), @@ -83,19 +61,7 @@ class SubmissionResultPositiveOtherWarningFragment : Fragment(), true, ::navigateToSubmissionResultFragment ) - is CwaServerError -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - getString( - R.string.submission_error_dialog_web_generic_network_error_body, - exception.statusCode - ), - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::navigateToSubmissionResultFragment - ) - is CwaClientError -> DialogHelper.DialogInstance( + is CwaServerError, is CwaClientError -> DialogHelper.DialogInstance( requireActivity(), R.string.submission_error_dialog_web_generic_error_title, getString( @@ -121,13 +87,18 @@ class SubmissionResultPositiveOtherWarningFragment : Fragment(), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.submissionViewModel = submissionViewModel + + internalExposureNotificationPermissionHelper = + InternalExposureNotificationPermissionHelper(this, this) + setButtonOnClickListener() submissionViewModel.submissionError.observeEvent(viewLifecycleOwner) { DialogHelper.showDialog(buildErrorDialog(it)) } - submissionViewModel.submissionState.observe(viewLifecycleOwner, Observer { + submissionViewModel.submissionState.observe(viewLifecycleOwner, { if (it == ApiRequestState.SUCCESS) { navigateToSubmissionDoneFragment() } @@ -139,7 +110,7 @@ class SubmissionResultPositiveOtherWarningFragment : Fragment(), initiateWarningOthers() } binding.submissionPositiveOtherWarningHeader.headerButtonBack.buttonIcon.setOnClickListener { - navigateToSubmissionResultFragment() + findNavController().popBackStack() } } @@ -192,5 +163,6 @@ class SubmissionResultPositiveOtherWarningFragment : Fragment(), } override fun onFailure(exception: Exception?) { + // NOOP } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTanFragment.kt similarity index 75% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTanFragment.kt index f648b300568a229f76ca96bcc8995f2ae499e1bf..1244e7f44441379473f8bdda0d8dc3d2acfd641d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTanFragment.kt @@ -1,9 +1,7 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.fragment import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -17,64 +15,37 @@ import de.rki.coronawarnapp.exception.http.CwaServerError import de.rki.coronawarnapp.exception.http.CwaWebException import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.ui.main.MainActivity +import de.rki.coronawarnapp.ui.submission.ApiRequestState +import de.rki.coronawarnapp.ui.submission.TanConstants +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionTanViewModel import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.TanHelper import de.rki.coronawarnapp.util.observeEvent -import kotlinx.android.synthetic.main.include_submission_tan.submission_tan_error -import kotlinx.android.synthetic.main.include_submission_tan.submission_tan_character_error +import de.rki.coronawarnapp.util.ui.viewBindingLazy +import kotlinx.android.synthetic.main.include_submission_tan.* /** * Fragment for TAN entry */ -class SubmissionTanFragment : Fragment() { +class SubmissionTanFragment : Fragment(R.layout.fragment_submission_tan) { private val viewModel: SubmissionTanViewModel by viewModels() private val submissionViewModel: SubmissionViewModel by activityViewModels() - private var _binding: FragmentSubmissionTanBinding? = null - private val binding: FragmentSubmissionTanBinding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // get the binding reference by inflating it with the current layout - _binding = FragmentSubmissionTanBinding.inflate(inflater) - binding.viewmodel = viewModel - binding.lifecycleOwner = this - return binding.root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + private val binding: FragmentSubmissionTanBinding by viewBindingLazy() private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance { return when (exception) { is BadRequestException -> DialogHelper.DialogInstance( requireActivity(), - R.string.submission_error_dialog_web_test_paired_title, - R.string.submission_error_dialog_web_test_paired_body, + R.string.submission_error_dialog_web_test_paired_title_tan, + R.string.submission_error_dialog_web_test_paired_body_tan, R.string.submission_error_dialog_web_test_paired_button_positive, null, true, ::goBack ) - is CwaServerError -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - getString( - R.string.submission_error_dialog_web_generic_network_error_body, - exception.statusCode - ), - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::goBack - ) - is CwaClientError -> DialogHelper.DialogInstance( + is CwaClientError, is CwaServerError -> DialogHelper.DialogInstance( requireActivity(), R.string.submission_error_dialog_web_generic_error_title, getString( @@ -100,6 +71,7 @@ class SubmissionTanFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.viewmodel = viewModel binding.submissionTanContent.submissionTanInput.listener = { tan -> resetError() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTestResultFragment.kt similarity index 77% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTestResultFragment.kt index 03aecc8b20e2803224d0dcdb03772e76f2a3c42d..98187e8c82d96ff9ab1192ad11216098d854e56f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionTestResultFragment.kt @@ -1,15 +1,12 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.fragment import android.app.AlertDialog import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultBinding @@ -22,20 +19,19 @@ import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.util.DeviceUIState import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.observeEvent +import de.rki.coronawarnapp.util.ui.viewBindingLazy /** * A simple [Fragment] subclass. */ -class SubmissionTestResultFragment : Fragment() { - companion object { - private val TAG: String? = SubmissionTanFragment::class.simpleName - } +class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_result) { private val submissionViewModel: SubmissionViewModel by activityViewModels() private val tracingViewModel: TracingViewModel by activityViewModels() - private var _binding: FragmentSubmissionTestResultBinding? = null - private val binding: FragmentSubmissionTestResultBinding get() = _binding!! + private val binding: FragmentSubmissionTestResultBinding by viewBindingLazy() + + private var skipInitialTestResultRefresh = false // Overrides default back behaviour private val backCallback: OnBackPressedCallback = @@ -47,21 +43,6 @@ class SubmissionTestResultFragment : Fragment() { } } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // get the binding reference by inflating it with the current layout - _binding = FragmentSubmissionTestResultBinding.inflate(inflater) - binding.submissionViewModel = submissionViewModel - binding.lifecycleOwner = this - // registers callback when the os level back is pressed - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) - // Inflate the layout for this fragment - return binding.root - } - private fun navigateToMainScreen() = findNavController().doNavigate( SubmissionTestResultFragmentDirections.actionSubmissionResultFragmentToMainFragment() @@ -69,19 +50,7 @@ class SubmissionTestResultFragment : Fragment() { private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance { return when (exception) { - is CwaServerError -> DialogHelper.DialogInstance( - requireActivity(), - R.string.submission_error_dialog_web_generic_error_title, - getString( - R.string.submission_error_dialog_web_generic_network_error_body, - exception.statusCode - ), - R.string.submission_error_dialog_web_generic_error_button_positive, - null, - true, - ::navigateToMainScreen - ) - is CwaClientError -> DialogHelper.DialogInstance( + is CwaClientError, is CwaServerError -> DialogHelper.DialogInstance( requireActivity(), R.string.submission_error_dialog_web_generic_error_title, getString( @@ -105,20 +74,22 @@ class SubmissionTestResultFragment : Fragment() { } } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.submissionViewModel = submissionViewModel + // registers callback when the os level back is pressed + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backCallback) + + skipInitialTestResultRefresh = + arguments?.getBoolean("skipInitialTestResultRefresh") ?: false + setButtonOnClickListener() submissionViewModel.uiStateError.observeEvent(viewLifecycleOwner) { DialogHelper.showDialog(buildErrorDialog(it)) } - submissionViewModel.deviceUiState.observe(viewLifecycleOwner, Observer { uiState -> + submissionViewModel.deviceUiState.observe(viewLifecycleOwner, { uiState -> if (uiState == DeviceUIState.PAIRED_REDEEMED) { showRedeemedTokenWarningDialog() } @@ -139,8 +110,10 @@ class SubmissionTestResultFragment : Fragment() { override fun onResume() { super.onResume() binding.submissionTestResultContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) - submissionViewModel.refreshDeviceUIState() + submissionViewModel.refreshDeviceUIState(refreshTestResult = !skipInitialTestResultRefresh) tracingViewModel.refreshIsTracingEnabled() + + skipInitialTestResultRefresh = false } private fun setButtonOnClickListener() { @@ -159,7 +132,12 @@ class SubmissionTestResultFragment : Fragment() { } binding.submissionTestResultButtonPositiveContinue.setOnClickListener { - continueIfTracingEnabled() + continueIfTracingEnabled(false) + } + + binding.submissionTestResultButtonPositiveContinueWithoutSymptoms.setOnClickListener { + submissionViewModel.onNoInformationSymptomIndication() + continueIfTracingEnabled(true) } binding.submissionTestResultButtonInvalidRemoveTest.setOnClickListener { @@ -173,7 +151,7 @@ class SubmissionTestResultFragment : Fragment() { } } - private fun continueIfTracingEnabled() { + private fun continueIfTracingEnabled(skipSymptomSubmission: Boolean) { if (tracingViewModel.isTracingEnabled.value != true) { val tracingRequiredDialog = DialogHelper.DialogInstance( requireActivity(), @@ -185,10 +163,17 @@ class SubmissionTestResultFragment : Fragment() { return } - findNavController().doNavigate( - SubmissionTestResultFragmentDirections - .actionSubmissionResultFragmentToSubmissionResultPositiveOtherWarningFragment() - ) + if (skipSymptomSubmission) { + findNavController().doNavigate( + SubmissionTestResultFragmentDirections + .actionSubmissionResultFragmentToSubmissionResultPositiveOtherWarningFragment() + ) + } else { + findNavController().doNavigate( + SubmissionTestResultFragmentDirections + .actionSubmissionResultFragmentToSubmissionSymptomIntroductionFragment() + ) + } } private fun removeTestAfterConfirmation() { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionCountrySelectViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionCountrySelectViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..72bf21e7d243f014fa9b423e809afbbfe4917542 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionCountrySelectViewModel.kt @@ -0,0 +1,73 @@ +package de.rki.coronawarnapp.ui.submission.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import de.rki.coronawarnapp.ui.submission.SubmissionCountry + +class SubmissionCountrySelectViewModel : ViewModel() { + private val _countries = MutableLiveData<List<SubmissionCountry>>(listOf()) + private val _countriesActive = MediatorLiveData<Boolean>() + private val _noInfoActive = MediatorLiveData<Boolean>() + private val _nextActive = MediatorLiveData<Boolean>() + + val countries: LiveData<List<SubmissionCountry>> = _countries + val countriesActive: LiveData<Boolean> = _countriesActive + val noInfoActive: LiveData<Boolean> = _noInfoActive + val nextActive: LiveData<Boolean> = _nextActive + + init { + _countriesActive.addSource(countries) { countries -> + _countriesActive.value = countries.any { it.selected } + } + + _noInfoActive.addSource(countriesActive) { + if (it) { + _noInfoActive.value = false + } + } + + _nextActive.addSource(countriesActive) { + if (it) { + _nextActive.value = true + } + if (!it && noInfoActive.value == false) { + _nextActive.value = false + } + } + _nextActive.addSource(noInfoActive) { + if (it) { + _nextActive.value = true + } + } + } + + fun noInfoClick() { + _countries.value?.let { currentCountries -> + _countries.postValue(currentCountries.map { it.apply { selected = false } }) + } + + _noInfoActive.postValue(true) + } + + fun fetchCountries() { + _countries.postValue( + listOf( + SubmissionCountry("IT"), + SubmissionCountry("ES") + ) + ) + } + + fun updateCountryCheckedState(country: SubmissionCountry) { + val newCountries = _countries.value?.map { + if (it.countryCode == country.countryCode) it.apply { + selected = country.selected + } else it + } + if (newCountries != null) { + _countries.postValue(newCountries) + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionTanViewModel.kt similarity index 88% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionTanViewModel.kt index 849aebddf36ed17417e72c4ad8c73c1506ca0fc0..44cf0d79752998da10f5812a48af0a51437425f2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionTanViewModel.kt @@ -1,9 +1,10 @@ -package de.rki.coronawarnapp.ui.submission +package de.rki.coronawarnapp.ui.submission.viewmodel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.ui.submission.TanConstants import de.rki.coronawarnapp.util.TanHelper import timber.log.Timber diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CountryList.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CountryList.kt new file mode 100644 index 0000000000000000000000000000000000000000..a97986690a52f7aa4223a34e29d7a7c3f33adfb0 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CountryList.kt @@ -0,0 +1,48 @@ +package de.rki.coronawarnapp.ui.view + +import android.content.Context +import android.util.AttributeSet +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.ui.Country +import java.text.Collator + +class CountryList(context: Context, attrs: AttributeSet) : + LinearLayout(context, attrs) { + + private var _list: List<Country>? = null + var list: List<Country>? + get() = _list + set(value) { + _list = value + buildList() + } + + init { + orientation = VERTICAL + } + + /** + * Cleans the view and rebuilds the list of countries. Presets already selected countries + */ + private fun buildList() { + this.removeAllViews() + list + ?.map { country -> + context.getString(country.labelRes) to country.iconRes + } + ?.sortedWith { a, b -> + Collator.getInstance().compare(a.first, b.first) + } + ?.forEachIndexed { index, (label, iconRes) -> + inflate(context, R.layout.view_country_list_entry, this) + val child = this.getChildAt(index) + child.apply { + findViewById<ImageView>(R.id.country_list_entry_image).setImageResource(iconRes) + findViewById<TextView>(R.id.country_list_entry_label).text = label + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/LocationTracingStatusCardBodyTextView.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/LocationTracingStatusCardBodyTextView.kt new file mode 100644 index 0000000000000000000000000000000000000000..cf71bbc226196247918ebbada091a5a8887791b4 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/LocationTracingStatusCardBodyTextView.kt @@ -0,0 +1,34 @@ +package de.rki.coronawarnapp.ui.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.util.setUrl + +class LocationTracingStatusCardBodyTextView : AppCompatTextView { + + constructor(context: Context?) : super(context) { + setUrl() + } + + constructor(context: Context?, attrs: AttributeSet) : super(context, attrs) { + setUrl() + } + + constructor( + context: Context?, + attrs: AttributeSet, + defStyleAttr: Int + ) : super(context, attrs, defStyleAttr) { + setUrl() + } + + private fun setUrl() { + setUrl( + R.string.settings_tracing_status_location_body, + "FAQ", + context.getString(R.string.settings_tracing_status_location_body_url) + ) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SettingsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SettingsViewModel.kt index 486954f1ac74cc6912e24ec6619ba8cf616092c9..fa6bde7ffd0c4200c7799a8d23b45f2dd0321fd8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SettingsViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SettingsViewModel.kt @@ -1,9 +1,9 @@ package de.rki.coronawarnapp.ui.viewmodel -import android.content.Context import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import de.rki.coronawarnapp.storage.SettingsRepository +import de.rki.coronawarnapp.util.di.AppInjector /** * ViewModel for everything settings related. @@ -12,23 +12,24 @@ import de.rki.coronawarnapp.storage.SettingsRepository */ class SettingsViewModel : ViewModel() { - val isNotificationsEnabled: LiveData<Boolean> = SettingsRepository.isNotificationsEnabled + private val settingsRepository by lazy { + AppInjector.component.settingsRepository + } + + val isNotificationsEnabled: LiveData<Boolean> = settingsRepository.isNotificationsEnabled val isNotificationsRiskEnabled: LiveData<Boolean> = - SettingsRepository.isNotificationsRiskEnabled + settingsRepository.isNotificationsRiskEnabled val isNotificationsTestEnabled: LiveData<Boolean> = - SettingsRepository.isNotificationsTestEnabled - val isConnectionEnabled: LiveData<Boolean> = - SettingsRepository.isConnectionEnabled - val isBluetoothEnabled: LiveData<Boolean> = - SettingsRepository.isBluetoothEnabled - val isLocationEnabled: LiveData<Boolean> = - SettingsRepository.isLocationEnabled + settingsRepository.isNotificationsTestEnabled + val isConnectionEnabled: LiveData<Boolean> = settingsRepository.isConnectionEnabled + val isBluetoothEnabled: LiveData<Boolean> = settingsRepository.isBluetoothEnabled + val isLocationEnabled: LiveData<Boolean> = settingsRepository.isLocationEnabled // Will impact UI if background activity is not permitted, persistent storing is not necessary - val isBackgroundJobEnabled: LiveData<Boolean> = SettingsRepository.isBackgroundJobEnabled + val isBackgroundJobEnabled: LiveData<Boolean> = settingsRepository.isBackgroundJobEnabled val isBackgroundPriorityEnabled: LiveData<Boolean> = - SettingsRepository.isBackgroundPriorityEnabled + settingsRepository.isBackgroundPriorityEnabled /** * Is manual key retrieval enabled @@ -37,14 +38,14 @@ class SettingsViewModel : ViewModel() { * @see SettingsRepository.isManualKeyRetrievalEnabled */ val isManualKeyRetrievalEnabled: LiveData<Boolean> = - SettingsRepository.isManualKeyRetrievalEnabled + settingsRepository.isManualKeyRetrievalEnabled /** * Manual update button timer value * * @see SettingsRepository.manualKeyRetrievalTime */ - val manualKeyRetrievalTime: LiveData<Long> = SettingsRepository.manualKeyRetrievalTime + val manualKeyRetrievalTime: LiveData<Long> = settingsRepository.manualKeyRetrievalTime /** * Refresher and toggles for settings @@ -56,32 +57,32 @@ class SettingsViewModel : ViewModel() { * - Connectivity * - Background activity * - * @see SettingsRepository + * @see settingsRepository */ - fun refreshNotificationsEnabled(context: Context) { - SettingsRepository.refreshNotificationsEnabled(context) + fun refreshNotificationsEnabled() { + settingsRepository.refreshNotificationsEnabled() } /** * Refresh & toggle risk notifications */ fun refreshNotificationsRiskEnabled() { - SettingsRepository.refreshNotificationsRiskEnabled() + settingsRepository.refreshNotificationsRiskEnabled() } fun toggleNotificationsRiskEnabled() { - SettingsRepository.toggleNotificationsRiskEnabled() + settingsRepository.toggleNotificationsRiskEnabled() } /** * Refresh & toggle test notifications */ fun refreshNotificationsTestEnabled() { - SettingsRepository.refreshNotificationsTestEnabled() + settingsRepository.refreshNotificationsTestEnabled() } fun toggleNotificationsTestEnabled() { - SettingsRepository.toggleNotificationsTestEnabled() + settingsRepository.toggleNotificationsTestEnabled() } /** @@ -90,7 +91,7 @@ class SettingsViewModel : ViewModel() { * @param value */ fun updateConnectionEnabled(value: Boolean) { - SettingsRepository.updateConnectionEnabled(value) + settingsRepository.updateConnectionEnabled(value) } /** @@ -99,7 +100,7 @@ class SettingsViewModel : ViewModel() { * @param value */ fun updateBluetoothEnabled(value: Boolean) { - SettingsRepository.updateBluetoothEnabled(value) + settingsRepository.updateBluetoothEnabled(value) } /** @@ -108,7 +109,7 @@ class SettingsViewModel : ViewModel() { * @param value */ fun updateLocationEnabled(value: Boolean) { - SettingsRepository.updateLocationEnabled(value) + settingsRepository.updateLocationEnabled(value) } /** @@ -117,7 +118,7 @@ class SettingsViewModel : ViewModel() { * @param value */ fun updateBackgroundJobEnabled(value: Boolean) { - SettingsRepository.updateBackgroundJobEnabled(value) + settingsRepository.updateBackgroundJobEnabled(value) } /** @@ -126,10 +127,10 @@ class SettingsViewModel : ViewModel() { * @param value */ fun updateManualKeyRetrievalEnabled(value: Boolean) { - SettingsRepository.updateManualKeyRetrievalEnabled(value) + settingsRepository.updateManualKeyRetrievalEnabled(value) } - fun refreshBackgroundPriorityEnabled(context: Context) { - SettingsRepository.refreshBackgroundPriorityEnabled(context) + fun refreshBackgroundPriorityEnabled() { + settingsRepository.refreshBackgroundPriorityEnabled() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt index 1964d9169bbf3fd3f9448ce09bd2992c5972155a..5f2c6cbdaa6a8bde5fc4b1fbba7b8e0766eccde5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt @@ -9,14 +9,23 @@ import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.TransactionException import de.rki.coronawarnapp.exception.http.CwaWebException import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.service.submission.QRScanResult import de.rki.coronawarnapp.service.submission.SubmissionService import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository +import de.rki.coronawarnapp.submission.Symptoms +import de.rki.coronawarnapp.ui.SingleLiveEvent import de.rki.coronawarnapp.ui.submission.ApiRequestState import de.rki.coronawarnapp.ui.submission.ScanStatus +import de.rki.coronawarnapp.ui.submission.SymptomCalendarEvent +import de.rki.coronawarnapp.ui.submission.SymptomIntroductionEvent import de.rki.coronawarnapp.util.DeviceUIState import de.rki.coronawarnapp.util.Event +import de.rki.coronawarnapp.util.di.AppInjector import kotlinx.coroutines.launch +import org.joda.time.LocalDate +import timber.log.Timber import java.util.Date class SubmissionViewModel : ViewModel() { @@ -30,9 +39,14 @@ class SubmissionViewModel : ViewModel() { private val _submissionState = MutableLiveData(ApiRequestState.IDLE) private val _submissionError = MutableLiveData<Event<CwaWebException>>(null) + private val interoperabilityRepository: InteroperabilityRepository + get() = AppInjector.component.interoperabilityRepository val scanStatus: LiveData<Event<ScanStatus>> = _scanStatus + val symptomIntroductionEvent: SingleLiveEvent<SymptomIntroductionEvent> = SingleLiveEvent() + val symptomCalendarEvent: SingleLiveEvent<SymptomCalendarEvent> = SingleLiveEvent() + val registrationState: LiveData<Event<ApiRequestState>> = _registrationState val registrationError: LiveData<Event<CwaWebException>> = _registrationError @@ -49,24 +63,48 @@ class SubmissionViewModel : ViewModel() { val deviceUiState: LiveData<DeviceUIState> = SubmissionRepository.deviceUIState - fun submitDiagnosisKeys(keys: List<TemporaryExposureKey>) = viewModelScope.launch { - try { - _submissionState.value = ApiRequestState.STARTED - SubmissionService.asyncSubmitExposureKeys(keys) - _submissionState.value = ApiRequestState.SUCCESS - } catch (err: CwaWebException) { - _submissionError.value = Event(err) - _submissionState.value = ApiRequestState.FAILED - } catch (err: TransactionException) { - if (err.cause is CwaWebException) { - _submissionError.value = Event(err.cause) - } else { - err.report(ExceptionCategory.INTERNAL) + val symptomIndication = MutableLiveData<Symptoms.Indication?>() + val symptomStart = MutableLiveData<Symptoms.StartOf?>() + + val countryList by lazy { + MutableLiveData(interoperabilityRepository.countryList) + } + + fun initSymptoms() { + symptomIndication.postValue(null) + } + + fun initSymptomStart() { + symptomStart.postValue(null) + } + + fun submitDiagnosisKeys(keys: List<TemporaryExposureKey>) { + val indication = symptomIndication.value + if (indication == null) { + Timber.w("symptoms indicator is null") + return + } + Symptoms(symptomStart.value, indication).also { + viewModelScope.launch { + try { + _submissionState.value = ApiRequestState.STARTED + SubmissionService.asyncSubmitExposureKeys(keys, it) + _submissionState.value = ApiRequestState.SUCCESS + } catch (err: CwaWebException) { + _submissionError.value = Event(err) + _submissionState.value = ApiRequestState.FAILED + } catch (err: TransactionException) { + if (err.cause is CwaWebException) { + _submissionError.value = Event(err.cause) + } else { + err.report(ExceptionCategory.INTERNAL) + } + _submissionState.value = ApiRequestState.FAILED + } catch (err: Exception) { + _submissionState.value = ApiRequestState.FAILED + err.report(ExceptionCategory.INTERNAL) + } } - _submissionState.value = ApiRequestState.FAILED - } catch (err: Exception) { - _submissionState.value = ApiRequestState.FAILED - err.report(ExceptionCategory.INTERNAL) } } @@ -91,17 +129,26 @@ class SubmissionViewModel : ViewModel() { } } - fun refreshDeviceUIState() = + fun refreshDeviceUIState(refreshTestResult: Boolean = true) { + var refresh = refreshTestResult + + deviceUiState.value?.let { + if (it != DeviceUIState.PAIRED_NO_RESULT && it != DeviceUIState.UNPAIRED) { + refresh = false + Timber.d("refreshDeviceUIState: Change refresh, state ${it.name} doesn't require refresh") + } + } executeRequestWithState( - SubmissionRepository::refreshUIState, + { SubmissionRepository.refreshUIState(refresh) }, _uiStateState, _uiStateError ) + } - fun validateAndStoreTestGUID(scanResult: String) { - if (SubmissionService.containsValidGUID(scanResult)) { - val guid = SubmissionService.extractGUID(scanResult) - SubmissionService.storeTestGUID(guid) + fun validateAndStoreTestGUID(rawResult: String) { + val scanResult = QRScanResult(rawResult) + if (scanResult.isValid) { + SubmissionService.storeTestGUID(scanResult.guid!!) _scanStatus.value = Event(ScanStatus.SUCCESS) } else { _scanStatus.value = Event(ScanStatus.INVALID) @@ -141,4 +188,52 @@ class SubmissionViewModel : ViewModel() { } } } + + fun onNextClicked() { + symptomIntroductionEvent.postValue(SymptomIntroductionEvent.NavigateToSymptomCalendar) + } + + fun onPreviousClicked() { + symptomIntroductionEvent.postValue(SymptomIntroductionEvent.NavigateToPreviousScreen) + } + + fun onCalendarNextClicked() { + symptomCalendarEvent.postValue(SymptomCalendarEvent.NavigateToNext) + } + + fun onCalendarPreviousClicked() { + symptomCalendarEvent.postValue(SymptomCalendarEvent.NavigateToPrevious) + } + + fun onPositiveSymptomIndication() { + symptomIndication.postValue(Symptoms.Indication.POSITIVE) + } + + fun onNegativeSymptomIndication() { + symptomIndication.postValue(Symptoms.Indication.NEGATIVE) + } + + fun onNoInformationSymptomIndication() { + symptomIndication.postValue(Symptoms.Indication.NO_INFORMATION) + } + + fun onLastSevenDaysStart() { + symptomStart.postValue(Symptoms.StartOf.LastSevenDays) + } + + fun onOneToTwoWeeksAgoStart() { + symptomStart.postValue(Symptoms.StartOf.OneToTwoWeeksAgo) + } + + fun onMoreThanTwoWeeksStart() { + symptomStart.postValue(Symptoms.StartOf.MoreThanTwoWeeks) + } + + fun onNoInformationStart() { + symptomStart.postValue(Symptoms.StartOf.NoInformation) + } + + fun onDateSelected(localDate: LocalDate?) { + symptomStart.postValue(if (localDate == null) null else Symptoms.StartOf.Date(localDate)) + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/TracingViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/TracingViewModel.kt index 2d94bf11de0709c02724cfa33f0960eddeece327..06e3b51238b1d34940eb2c3dbdb8b8253c12ea01 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/TracingViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/TracingViewModel.kt @@ -19,6 +19,7 @@ import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction import de.rki.coronawarnapp.transaction.RiskLevelTransaction import de.rki.coronawarnapp.ui.riskdetails.DefaultRiskDetailPresenter import de.rki.coronawarnapp.util.ConnectivityHelper +import de.rki.coronawarnapp.util.ui.SingleLiveEvent import kotlinx.coroutines.launch import org.joda.time.DateTime import org.joda.time.DateTimeZone @@ -62,6 +63,9 @@ class TracingViewModel : ViewModel() { val additionalInformationVisibility = MediatorLiveData<Int>() val informationBodyNoticeVisibility = MediatorLiveData<Int>() + // event for interoperability navigation + val navigateToInteroperability = SingleLiveEvent<Boolean>() + init { additionalInformationVisibility.addSource(riskLevel) { additionalInformationVisibility.value = @@ -125,7 +129,7 @@ class TracingViewModel : ViewModel() { // check if the keys were not already retrieved today val keysWereNotRetrievedToday = LocalData.lastTimeDiagnosisKeysFromServerFetch() == null || - currentDate.withTimeAtStartOfDay() != lastFetch.withTimeAtStartOfDay() + currentDate.withTimeAtStartOfDay() != lastFetch.withTimeAtStartOfDay() // check if the network is enabled to make the server fetch val isNetworkEnabled = @@ -136,9 +140,9 @@ class TracingViewModel : ViewModel() { val isBackgroundJobEnabled = ConnectivityHelper.autoModeEnabled(CoronaWarnApplication.getAppContext()) - Timber.v("Keys were not retrieved today $keysWereNotRetrievedToday") - Timber.v("Network is enabled $isNetworkEnabled") - Timber.v("Background jobs are enabled $isBackgroundJobEnabled") + Timber.tag(TAG).v("Keys were not retrieved today $keysWereNotRetrievedToday") + Timber.tag(TAG).v("Network is enabled $isNetworkEnabled") + Timber.tag(TAG).v("Background jobs are enabled $isBackgroundJobEnabled") if (keysWereNotRetrievedToday && isNetworkEnabled && isBackgroundJobEnabled) { TracingRepository.isRefreshing.value = true @@ -215,7 +219,7 @@ class TracingViewModel : ViewModel() { ExposureSummaryRepository.getExposureSummaryRepository() .getLatestExposureSummary(token) } - Timber.v("retrieved latest exposure summary from db") + Timber.tag(TAG).v("retrieved latest exposure summary from db") } catch (e: Exception) { e.report( de.rki.coronawarnapp.exception.ExceptionCategory.EXPOSURENOTIFICATION, @@ -240,4 +244,8 @@ class TracingViewModel : ViewModel() { fun refreshLastSuccessfullyCalculatedScore() { RiskLevelRepository.refreshLastSuccessfullyCalculatedScore() } + + fun onInteroperabilitySettingPressed() { + navigateToInteroperability.postValue(true) + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/update/UpdateChecker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/update/UpdateChecker.kt index bf416407dec31fa4f9fba7f3b98ba87061fec81a..b08ae1e74690a5bb2b599403166793bf7cfd835f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/update/UpdateChecker.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/update/UpdateChecker.kt @@ -6,7 +6,7 @@ import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat.startActivity import de.rki.coronawarnapp.BuildConfig import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.exception.ApplicationConfigurationCorruptException +import de.rki.coronawarnapp.appconfig.ApplicationConfigurationCorruptException import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService import de.rki.coronawarnapp.ui.LauncherActivity diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ApiLevel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ApiLevel.kt new file mode 100644 index 0000000000000000000000000000000000000000..0d7a8afd327eabd799769ebb9a7d97734c37e388 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ApiLevel.kt @@ -0,0 +1,14 @@ +package de.rki.coronawarnapp.util + +import android.os.Build +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ApiLevel constructor(val currentLevel: Int = Build.VERSION.SDK_INT) { + + @Inject + constructor() : this(Build.VERSION.SDK_INT) + + fun hasAPILevel(level: Int): Boolean = currentLevel >= level +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/BackgroundPrioritization.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/BackgroundPrioritization.kt new file mode 100644 index 0000000000000000000000000000000000000000..75934dc836964e21806d40754e6cc3600e1b4c40 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/BackgroundPrioritization.kt @@ -0,0 +1,6 @@ +package de.rki.coronawarnapp.util + +interface BackgroundPrioritization { + + val isBackgroundActivityPrioritized: Boolean +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt new file mode 100644 index 0000000000000000000000000000000000000000..8efb6c14888cb3fb0193da546f7ea5f9cf7566d4 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CWADebug.kt @@ -0,0 +1,34 @@ +package de.rki.coronawarnapp.util + +import android.app.Application +import de.rki.coronawarnapp.BuildConfig +import de.rki.coronawarnapp.util.debug.FileLogger +import timber.log.Timber + +object CWADebug { + var fileLogger: FileLogger? = null + + fun init(application: Application) { + if (isDebugBuildOrMode) System.setProperty("kotlinx.coroutines.debug", "on") + + if (BuildConfig.DEBUG) { + Timber.plant(Timber.DebugTree()) + } + if ((buildFlavor == BuildFlavor.DEVICE_FOR_TESTERS || BuildConfig.DEBUG)) { + fileLogger = FileLogger(application) + } + } + + val isDebugBuildOrMode: Boolean + get() = BuildConfig.DEBUG || buildFlavor == BuildFlavor.DEVICE_FOR_TESTERS + + val buildFlavor: BuildFlavor + get() = BuildFlavor.values().single { it.rawValue == BuildConfig.FLAVOR } + + val isDeviceForTestersBuild: Boolean = buildFlavor == BuildFlavor.DEVICE_FOR_TESTERS + + enum class BuildFlavor(val rawValue: String) { + DEVICE("device"), + DEVICE_FOR_TESTERS("deviceForTesters") + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt deleted file mode 100644 index bd7a7158e751f49f5711566856405186c1617b80..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/CachedKeyFileHolder.kt +++ /dev/null @@ -1,224 +0,0 @@ -/****************************************************************************** - * Corona-Warn-App * - * * - * SAP SE and all other contributors / * - * copyright owners license this file to you under the Apache * - * License, Version 2.0 (the "License"); you may not use this * - * file except in compliance with the License. * - * You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ******************************************************************************/ - -package de.rki.coronawarnapp.util - -import de.rki.coronawarnapp.BuildConfig -import de.rki.coronawarnapp.CoronaWarnApplication -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants -import de.rki.coronawarnapp.storage.FileStorageHelper -import de.rki.coronawarnapp.storage.LocalData -import de.rki.coronawarnapp.storage.keycache.KeyCacheEntity -import de.rki.coronawarnapp.storage.keycache.KeyCacheRepository -import de.rki.coronawarnapp.storage.keycache.KeyCacheRepository.DateEntryType.DAY -import de.rki.coronawarnapp.util.CachedKeyFileHolder.asyncFetchFiles -import de.rki.coronawarnapp.util.TimeAndDateExtensions.toServerFormat -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.withContext -import timber.log.Timber -import java.io.File -import java.io.IOException -import java.util.Collections -import java.util.Date -import java.util.UUID - -/** - * Singleton used for accessing key files via combining cached entries from existing files and new requests. - * made explicitly with [asyncFetchFiles] in mind - */ -object CachedKeyFileHolder { - private val TAG: String? = CachedKeyFileHolder::class.simpleName - - /** - * the key cache instance used to store queried dates and hours - */ - private val keyCache = - KeyCacheRepository.getDateRepository(CoronaWarnApplication.getAppContext()) - - /** - * Fetches all necessary Files from the Cached KeyFile Entries out of the [KeyCacheRepository] and - * adds to that all open Files currently available from the Server. - * - * Assumptions made about the implementation: - * - the app initializes with an empty cache and draws in every available data set in the beginning - * - the difference can only work properly if the date from the device is synchronized through the net - * - the difference in timezone is taken into account by using UTC in the Conversion from the Date to Server format - * - the missing days and hours are stored in one table as the actual stored data amount is low - * - the underlying repository from the database has no error and is reliable as source of truth - * - * @param currentDate the current date - if this is adjusted by the calendar, the cache is affected. - * @return list of all files from both the cache and the diff query - */ - suspend fun asyncFetchFiles(currentDate: Date): List<File> = withContext(Dispatchers.IO) { - checkForFreeSpace() - val serverDates = getDatesFromServer() - // TODO remove last3HourFetch before Release - if (BuildConfig.FLAVOR != "device" && isLast3HourFetchEnabled()) { - Timber.v("Last 3 Hours will be Fetched. Only use for Debugging!") - val currentDateServerFormat = currentDate.toServerFormat() - // just fetch the hours if the date is available - if (serverDates.contains(currentDateServerFormat)) { - return@withContext getLast3Hours(currentDate) - .map { getURLForHour(currentDate.toServerFormat(), it) } - .map { url -> - async { - return@async WebRequestBuilder.getInstance() - .asyncGetKeyFilesFromServer(url) - } - }.awaitAll() - } else { - throw IllegalStateException( - "you cannot use the last 3 hour mode if the date index " + - "does not contain any data for today" - ) - } - } else { - val uuidListFromServer = serverDates - .map { getURLForDay(it).generateCacheKeyFromString() } - // queries will be executed after the "query plan" was set - val deferredQueries: MutableCollection<Deferred<Any>> = mutableListOf() - keyCache.deleteOutdatedEntries(uuidListFromServer) - val missingDays = getMissingDaysFromDiff(serverDates) - val failedEntryCacheKeys = Collections.synchronizedList(mutableListOf<String>()) - if (missingDays.isNotEmpty()) { - // we have a date difference - deferredQueries.addAll( - missingDays - .map { getURLForDay(it) } - .map { url -> - val cacheKey = url.generateCacheKeyFromString() - async { - try { - url.createDayEntryForUrl(cacheKey) - } catch (e: Exception) { - Timber.v("failed entry: $cacheKey") - failedEntryCacheKeys.add(cacheKey) - } - } - } - ) - } - // execute the query plan - deferredQueries.awaitAll() - Timber.v("${failedEntryCacheKeys.size} failed entries ") - // For an error we clear the cache to try again - if (failedEntryCacheKeys.isNotEmpty()) { - keyCache.clear(failedEntryCacheKeys) - throw IOException("failed to download all key files, at least one failing request.") - } - keyCache.getFilesFromEntries() - .also { it.forEach { file -> Timber.v("cached file:${file.path}") } } - } - } - - private fun checkForFreeSpace() = FileStorageHelper.checkFileStorageFreeSpace() - - /** - * Calculates the missing days based on current missing entries in the cache - */ - private suspend fun getMissingDaysFromDiff(datesFromServer: Collection<String>): List<String> { - val cacheEntries = keyCache.getDates() - return datesFromServer - .also { Timber.d("${it.size} days from server") } - .filter { it.dateEntryCacheMiss(cacheEntries) } - .toList() - .also { Timber.d("${it.size} missing days") } - } - - /** - * TODO remove before Release - */ - private const val LATEST_HOURS_NEEDED = 3 - - /** - * Calculates the last 3 hours - * TODO remove before Release - */ - private suspend fun getLast3Hours(day: Date): List<String> = getHoursFromServer(day) - .also { Timber.v("${it.size} hours from server, but only latest 3 hours needed") } - .filter { TimeAndDateExtensions.getCurrentHourUTC() - LATEST_HOURS_NEEDED <= it.toInt() } - .toList() - .also { Timber.d("${it.size} missing hours") } - - /** - * Determines whether a given String has an existing date cache entry under a unique name - * given from the URL that is based on this String - * - * @param cache the given cache entries - */ - private fun String.dateEntryCacheMiss(cache: List<KeyCacheEntity>) = !cache - .map { date -> date.id } - .contains(getURLForDay(this).generateCacheKeyFromString()) - - /** - * Creates a date entry in the Key Cache for a given String with a unique Key Name derived from the URL - * and the URI of the downloaded File for that given key - */ - private suspend fun String.createDayEntryForUrl(cacheKey: String) = keyCache.createEntry( - cacheKey, - WebRequestBuilder.getInstance().asyncGetKeyFilesFromServer(this).toURI(), - DAY - ) - - /** - * Generates a unique key name (UUIDv3) for the cache entry based out of a string (e.g. an url) - */ - private fun String.generateCacheKeyFromString() = - "${UUID.nameUUIDFromBytes(this.toByteArray())}".also { - Timber.v("$this mapped to cache entry $it") - } - - /** - * Gets the correct URL String for querying an hour bucket - * - * @param formattedDate the formatted date for the hour bucket request - * @param formattedHour the formatted hour - */ - private fun getURLForHour(formattedDate: String, formattedHour: String) = - "${getURLForDay(formattedDate)}/${DiagnosisKeyConstants.HOUR}/$formattedHour" - - /** - * Gets the correct URL String for querying a day bucket - * - * @param formattedDate the formatted date - */ - private fun getURLForDay(formattedDate: String) = - "${DiagnosisKeyConstants.AVAILABLE_DATES_URL}/$formattedDate" - - /** - * Get all dates from server based as formatted dates - */ - private suspend fun getDatesFromServer() = - WebRequestBuilder.getInstance().asyncGetDateIndex() - - /** - * Get all hours from server based as formatted dates - */ - private suspend fun getHoursFromServer(day: Date) = - WebRequestBuilder.getInstance().asyncGetHourIndex(day) - - /** - * TODO remove before release - */ - private fun isLast3HourFetchEnabled(): Boolean = LocalData.last3HoursMode() -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt index 7771bd45d1d11cf11d1535bb352036c5d7c64b05..079c5f2a46e0bb0149ae5d20b85979a39e58b0ea 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt @@ -15,6 +15,7 @@ import android.os.Build import androidx.core.location.LocationManagerCompat import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.util.di.AppInjector import timber.log.Timber /** @@ -23,6 +24,10 @@ import timber.log.Timber object ConnectivityHelper { private val TAG: String? = ConnectivityHelper::class.simpleName + private val backgroundPrioritization by lazy { + AppInjector.component.connectivityHelperInjection.backgroundPrioritization + } + /** * Register bluetooth state change listener. * @@ -81,30 +86,30 @@ object ConnectivityHelper { * */ fun registerLocationStatusCallback(context: Context, callback: LocationCallback) { - val receiver = object : BroadcastReceiver() { - var isGpsEnabled: Boolean = false - var isNetworkEnabled: Boolean = false + val receiver = object : BroadcastReceiver() { + var isGpsEnabled: Boolean = false + var isNetworkEnabled: Boolean = false - override fun onReceive(context: Context, intent: Intent) { - intent.action?.let { act -> - if (act.matches("android.location.PROVIDERS_CHANGED".toRegex())) { - val locationManager = - context.getSystemService(Context.LOCATION_SERVICE) as LocationManager - isGpsEnabled = - locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) - isNetworkEnabled = - locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) + override fun onReceive(context: Context, intent: Intent) { + intent.action?.let { act -> + if (act.matches("android.location.PROVIDERS_CHANGED".toRegex())) { + val locationManager = + context.getSystemService(Context.LOCATION_SERVICE) as LocationManager + isGpsEnabled = + locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) + isNetworkEnabled = + locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) - if (isGpsEnabled || isNetworkEnabled) { - callback.onLocationAvailable() - Timber.d("Location enabled") - } else { - callback.onLocationUnavailable() - Timber.d("Location disabled") - } + if (isGpsEnabled || isNetworkEnabled) { + callback.onLocationAvailable() + Timber.d("Location enabled") + } else { + callback.onLocationUnavailable() + Timber.d("Location disabled") } } } + } } callback.recevier = receiver context.registerReceiver( @@ -200,7 +205,7 @@ object ConnectivityHelper { } /** - * Background jobs are enabled only if the battery optimization is enabled and + * Background jobs are enabled only if the background activity prioritization is enabled and * the background activity is not restricted * * @param context the context @@ -210,7 +215,7 @@ object ConnectivityHelper { * @see isBackgroundRestricted */ fun autoModeEnabled(context: Context): Boolean { - return !isBackgroundRestricted(context) || PowerManagementHelper.isIgnoringBatteryOptimizations(context) + return !isBackgroundRestricted(context) || backgroundPrioritization.isBackgroundActivityPrioritized } /** @@ -290,6 +295,7 @@ object ConnectivityHelper { */ abstract fun onLocationUnavailable() } + /** * Abstract network state change callback. * diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelperInjection.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelperInjection.kt new file mode 100644 index 0000000000000000000000000000000000000000..e7f7b9f58a3137d6f3ac40d1a61a7815e9ece671 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelperInjection.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.util + +import javax.inject.Inject + +// TODO Wrapper that can be removed once **[ConnectivityHelper]** is no longer a singleton +data class ConnectivityHelperInjection @Inject constructor( + val backgroundPrioritization: BackgroundPrioritization +) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataRetentionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataRetentionHelper.kt index 46343586783c5c9f28c5b71d5bb6825aa0d14ef4..1ce93fc10fafda64feb5c1adc377f8eaa848e38a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataRetentionHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataRetentionHelper.kt @@ -22,9 +22,10 @@ package de.rki.coronawarnapp.util import android.annotation.SuppressLint import android.content.Context import de.rki.coronawarnapp.storage.AppDatabase -import de.rki.coronawarnapp.storage.FileStorageHelper import de.rki.coronawarnapp.storage.RiskLevelRepository +import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.util.security.SecurityHelper +import kotlinx.coroutines.runBlocking import timber.log.Timber /** @@ -47,7 +48,8 @@ object DataRetentionHelper { // Reset the current risk level stored in LiveData RiskLevelRepository.reset() // Export File Reset - FileStorageHelper.getAllFilesInKeyExportDirectory().forEach { it.delete() } + // TODO runBlocking, but also all of the above is BLOCKING and should be called more nicely + runBlocking { AppInjector.component.keyCacheRepository.clear() } Timber.w("CWA LOCAL DATA DELETION COMPLETED.") } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DefaultBackgroundPrioritization.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DefaultBackgroundPrioritization.kt new file mode 100644 index 0000000000000000000000000000000000000000..7cfd0d07b2c5fbbc01e76b1002709c5bc06b92ca --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DefaultBackgroundPrioritization.kt @@ -0,0 +1,12 @@ +package de.rki.coronawarnapp.util + +import de.rki.coronawarnapp.util.device.PowerManagement +import javax.inject.Inject + +class DefaultBackgroundPrioritization @Inject constructor( + private val powerManagement: PowerManagement +) : BackgroundPrioritization { + + override val isBackgroundActivityPrioritized + get() = powerManagement.isIgnoringBatteryOptimizations +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ExternalActionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ExternalActionHelper.kt index 0883265034c19739c9fbf29f92d0ef99ebaa3827..e200dadb0909c7054ad0986a34cbbea311043a5a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ExternalActionHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ExternalActionHelper.kt @@ -155,46 +155,4 @@ object ExternalActionHelper { ) } } - - fun disableBatteryOptimizations(context: Context) { - try { - val intent = Intent( - Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - Uri.parse("package:" + context.packageName) - ) - context.startActivity(intent) - } catch (exception: Exception) { - // catch generic exception on settings navigation - // most likely due to device / rom specific intent issue - ExternalActionException(exception).report( - ExceptionCategory.UI - ) - } - } - - fun toBatteryOptimizationSettings(context: Context) { - try { - val intent = Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS) - context.startActivity(intent) - } catch (exception: Exception) { - // catch generic exception on settings navigation - // most likely due to device / rom specific intent issue - ExternalActionException(exception).report( - ExceptionCategory.UI - ) - } - } - - fun toBatterySaverSettings(context: Context) { - try { - val intent = Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS) - context.startActivity(intent) - } catch (exception: Exception) { - // catch generic exception on settings navigation - // most likely due to device / rom specific intent issue - ExternalActionException(exception).report( - ExceptionCategory.UI - ) - } - } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/FormattedError.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/FormattedError.kt new file mode 100644 index 0000000000000000000000000000000000000000..0639465cec8c0a42e1af49781100ac85ccba1f01 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/FormattedError.kt @@ -0,0 +1,12 @@ +package de.rki.coronawarnapp.util + +import android.content.Context + +interface FormattedError { + fun getFormattedError(context: Context): String +} + +fun Throwable.tryFormattedError(context: Context): String = when (this) { + is FormattedError -> this.getFormattedError(context) + else -> (localizedMessage ?: this.message) ?: this.toString() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleAPIVersion.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleAPIVersion.kt new file mode 100644 index 0000000000000000000000000000000000000000..6af00068b370a93acc562d74cf16b23d8819617c --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/GoogleAPIVersion.kt @@ -0,0 +1,40 @@ +package de.rki.coronawarnapp.util + +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.CommonStatusCodes +import dagger.Reusable +import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient +import javax.inject.Inject +import kotlin.math.abs + +@Reusable +class GoogleAPIVersion @Inject constructor() { + /** + * Indicates if the client runs above a certain version + * + * @return isAboveVersion, if connected to an old unsupported version, return false + */ + suspend fun isAtLeast(compareVersion: Long): Boolean { + if (!compareVersion.isCorrectVersionLength) { + throw IllegalArgumentException("given version has incorrect length") + } + return try { + val currentVersion = InternalExposureNotificationClient.getVersion() + currentVersion >= compareVersion + } catch (apiException: ApiException) { + if (apiException.statusCode != CommonStatusCodes.API_NOT_CONNECTED) { + throw apiException + } + return false + } + } + + // check if a raw long has the correct length to be considered an API version + private val Long.isCorrectVersionLength + get(): Boolean = abs(this).toString().length == GOOGLE_API_VERSION_FIELD_LENGTH + + companion object { + private const val GOOGLE_API_VERSION_FIELD_LENGTH = 8 + const val V16 = 16000000L + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/HashExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/HashExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..b99b9f2ccd8768f361e697298f185bb96511e5dc --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/HashExtensions.kt @@ -0,0 +1,39 @@ +package de.rki.coronawarnapp.util + +import java.io.File +import java.security.MessageDigest +import java.util.Locale + +internal object HashExtensions { + + fun String.toSHA256() = this.hashString("SHA-256") + + fun String.toSHA1() = this.hashString("SHA-1") + + fun String.toMD5() = this.hashString("MD5") + + private fun ByteArray.formatHash(): String = this + .joinToString(separator = "") { String.format("%02X", it) } + .toLowerCase(Locale.ROOT) + + private fun String.hashString(type: String): String = MessageDigest + .getInstance(type) + .digest(this.toByteArray()) + .formatHash() + + fun File.hashToMD5(): String = this.hashTo("MD5") + + private fun File.hashTo(type: String): String = MessageDigest + .getInstance(type) + .let { md -> + inputStream().use { stream -> + val buffer = ByteArray(8192) + var read: Int + while (stream.read(buffer).also { read = it } > 0) { + md.update(buffer, 0, read) + } + } + md.digest() + } + .formatHash() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/KeyFileHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/KeyFileHelper.kt index 4bf7807abee209bac0fc52aec92a80eb1e7078cc..ce325afe3e8f462095e4c5aea34647b76896a2de 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/KeyFileHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/KeyFileHelper.kt @@ -1,10 +1,9 @@ package de.rki.coronawarnapp.util -import KeyExportFormat -import KeyExportFormat.TEKSignatureList -import KeyExportFormat.TEKSignatureList.newBuilder -import KeyExportFormat.TemporaryExposureKeyExport import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange +import de.rki.coronawarnapp.server.protocols.KeyExportFormat.TEKSignature +import de.rki.coronawarnapp.server.protocols.KeyExportFormat.TEKSignatureList +import de.rki.coronawarnapp.server.protocols.KeyExportFormat.TemporaryExposureKeyExport import de.rki.coronawarnapp.util.ProtoFormatConverterExtensions.convertToGoogleKey import de.rki.coronawarnapp.util.TimeAndDateExtensions.logUTCFormat import kotlinx.coroutines.Dispatchers @@ -12,10 +11,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.withContext import timber.log.Timber -import java.io.BufferedWriter import java.io.File -import java.io.FileOutputStream -import java.io.OutputStreamWriter import java.nio.charset.Charset import java.util.Date import java.util.UUID @@ -54,7 +50,7 @@ object KeyFileHelper { .setStartTimestamp(file.header.startTimestamp) .setEndTimestamp(file.header.endTimestamp) .build(), - KeyExportFormat.TEKSignature.newBuilder() + TEKSignature.newBuilder() .setBatchNum(file.header.batchNum) .setBatchSize(file.header.batchSize) .setSignatureInfo(SignatureHelper.clientSig) @@ -78,7 +74,7 @@ object KeyFileHelper { private suspend fun createBinaryFile( storageDirectory: File?, zipFileName: String, - sourceWithTEKSignature: Pair<TemporaryExposureKeyExport, KeyExportFormat.TEKSignature> + sourceWithTEKSignature: Pair<TemporaryExposureKeyExport, TEKSignature> ): File { return withContext(Dispatchers.IO) { val exportFile = async { @@ -91,7 +87,9 @@ object KeyFileHelper { val exportSignatureFile = async { generateSignatureFile( storageDirectory, - newBuilder().addAllSignatures(listOf(sourceWithTEKSignature.second)).build() + TEKSignatureList.newBuilder() + .addAllSignatures(listOf(sourceWithTEKSignature.second)) + .build() ) } @@ -126,7 +124,7 @@ object KeyFileHelper { private fun TEKSignatureList.writeToFile( file: File - ) = FileOutputStream(file).use { stream -> + ) = file.outputStream().use { stream -> this.writeTo(stream) } @@ -144,9 +142,9 @@ object KeyFileHelper { private fun getExportBinaryFileName(): String = "key-export-binary-${UUID.randomUUID()}.bin" - private fun File.appendBinaryHeader() = FileOutputStream(this).use { fos -> - OutputStreamWriter(fos, Charset.forName(EXPORT_FILE_HEADER_CHARSET)).use { osw -> - BufferedWriter(osw).use { bw -> + private fun File.appendBinaryHeader() = outputStream().use { fos -> + fos.writer(Charset.forName(EXPORT_FILE_HEADER_CHARSET)).use { osw -> + osw.buffered().use { bw -> bw.write(EXPORT_FILE_HEADER) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PaddingTool.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PaddingTool.kt new file mode 100644 index 0000000000000000000000000000000000000000..1e80679aacc286e5e594eb53dba9917f5c5d77fb --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PaddingTool.kt @@ -0,0 +1,9 @@ +package de.rki.coronawarnapp.util + +object PaddingTool { + fun requestPadding(length: Int): String = (1..length) + .map { PADDING_ITEMS.random() } + .joinToString("") + + private val PADDING_ITEMS = ('A'..'Z') + ('a'..'z') + ('0'..'9') +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PowerManagementHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PowerManagementHelper.kt deleted file mode 100644 index a7c14291470c03b346044d284241a384ffb06099..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/PowerManagementHelper.kt +++ /dev/null @@ -1,14 +0,0 @@ -package de.rki.coronawarnapp.util - -import android.content.Context -import android.os.PowerManager - -object PowerManagementHelper { - /** - * Checks if app is excluded from battery optimizations - */ - fun isIgnoringBatteryOptimizations(context: Context): Boolean { - val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager - return powerManager.isIgnoringBatteryOptimizations(context.packageName) - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensions.kt index b7597b2cafa3faa737ac5786c8aed84aaf0deedb..975d4f17f3e0e7261b2ccc3ea0fdc840c0d66dd9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensions.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensions.kt @@ -1,55 +1,10 @@ package de.rki.coronawarnapp.util -import KeyExportFormat -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import com.google.protobuf.ByteString import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange +import de.rki.coronawarnapp.server.protocols.KeyExportFormat object ProtoFormatConverterExtensions { - private const val ROLLING_PERIOD = 144 - private const val DEFAULT_TRANSMISSION_RISK_LEVEL = 1 - private const val TRANSMISSION_RISK_DAY_0 = 5 - private const val TRANSMISSION_RISK_DAY_1 = 6 - private const val TRANSMISSION_RISK_DAY_2 = 8 - private const val TRANSMISSION_RISK_DAY_3 = 8 - private const val TRANSMISSION_RISK_DAY_4 = 8 - private const val TRANSMISSION_RISK_DAY_5 = 5 - private const val TRANSMISSION_RISK_DAY_6 = 3 - private const val TRANSMISSION_RISK_DAY_7 = 1 - private val DEFAULT_TRANSMISSION_RISK_VECTOR = intArrayOf( - TRANSMISSION_RISK_DAY_0, - TRANSMISSION_RISK_DAY_1, - TRANSMISSION_RISK_DAY_2, - TRANSMISSION_RISK_DAY_3, - TRANSMISSION_RISK_DAY_4, - TRANSMISSION_RISK_DAY_5, - TRANSMISSION_RISK_DAY_6, - TRANSMISSION_RISK_DAY_7 - ) - private const val MAXIMUM_KEYS = 14 - - fun List<TemporaryExposureKey>.limitKeyCount() = - this.sortedWith(compareByDescending { it.rollingStartIntervalNumber }).take(MAXIMUM_KEYS) - - fun List<TemporaryExposureKey>.transformKeyHistoryToExternalFormat() = - this.sortedWith(compareByDescending { it.rollingStartIntervalNumber }) - .mapIndexed { index, it -> - // The latest key we receive is from yesterday (i.e. 1 day ago), - // thus we need use index+1 - val riskValue = - if (index + 1 <= DEFAULT_TRANSMISSION_RISK_VECTOR.lastIndex) - DEFAULT_TRANSMISSION_RISK_VECTOR[index + 1] - else - DEFAULT_TRANSMISSION_RISK_LEVEL - KeyExportFormat.TemporaryExposureKey.newBuilder() - .setKeyData(ByteString.readFrom(it.keyData.inputStream())) - .setRollingStartIntervalNumber(it.rollingStartIntervalNumber) - .setRollingPeriod(ROLLING_PERIOD) - .setTransmissionRiskLevel(riskValue) - .build() - } - fun AppleLegacyKeyExchange.Key.convertToGoogleKey(): KeyExportFormat.TemporaryExposureKey = KeyExportFormat.TemporaryExposureKey.newBuilder() .setKeyData(this.keyData) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/RetryMechanism.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/RetryMechanism.kt new file mode 100644 index 0000000000000000000000000000000000000000..ba2a372b51a99e49b2fdd04881f0d47d2b99f2c6 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/RetryMechanism.kt @@ -0,0 +1,77 @@ +package de.rki.coronawarnapp.util + +import timber.log.Timber +import kotlin.math.pow +import kotlin.math.roundToLong + +object RetryMechanism { + + fun <T> retryWithBackOff( + delayCalculator: (Attempt) -> Long? = createDelayCalculator(), + delayOperation: (Long) -> Unit = { Thread.sleep(it) }, + retryCondition: (Attempt) -> Boolean = { true }, + action: () -> T + ): T { + var current = Attempt() + while (true) { + Timber.v("Executing attempt: %s", current) + try { + return action() + } catch (e: Exception) { + current = current.copy(exception = e) + } + + if (!retryCondition(current)) throw current.exception!! + + val newDelay = delayCalculator(current) + + if (newDelay == null) { + Timber.w("Retrycondition exceeded: %s", current) + throw current.exception!! + } else { + delayOperation(newDelay) + } + + current = current.copy( + count = current.count + 1, + lastDelay = newDelay, + totalDelay = current.totalDelay + newDelay + ) + } + } + + private const val DEFAULT_TOTAL_MAX_RETRY = 15 * 1000L // 15 seconds total delay + private const val DEFAULT_MAX_DELAY = 3 * 1000L // 3 seconds max between retries + private const val DEFAULT_MIN_DELAY = 25L // Almost immediate retry + private const val DEFAULT_RETRY_MULTIPLIER = 1.5 + + fun createDelayCalculator( + maxTotalDelay: Long = DEFAULT_TOTAL_MAX_RETRY, + maxDelay: Long = DEFAULT_MAX_DELAY, + minDelay: Long = DEFAULT_MIN_DELAY, + multiplier: Double = DEFAULT_RETRY_MULTIPLIER + ): (Attempt) -> Long? = { attempt -> + if (attempt.totalDelay > maxTotalDelay) { + Timber.w("Max retry duration exceeded.") + null + } else { + val exp = 2.0.pow(attempt.count.toDouble()) + val calculatedDelay = (multiplier * exp).roundToLong() + + val newDelay = if (calculatedDelay > attempt.lastDelay) { + (attempt.lastDelay..calculatedDelay).random() + } else { + (calculatedDelay..attempt.lastDelay).random() + } + + newDelay.coerceAtMost(maxDelay).coerceAtLeast(minDelay) + } + } + + data class Attempt( + val count: Int = 1, + val totalDelay: Long = 0L, + val lastDelay: Long = 0L, + val exception: Exception? = null + ) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/SignatureHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/SignatureHelper.kt index 9ad36fcbdea6b43f843e95679895a7a122b8fa65..9ffa457377cdb14a04ba855e86d6020f2eb1a72f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/SignatureHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/SignatureHelper.kt @@ -1,9 +1,9 @@ package de.rki.coronawarnapp.util -import KeyExportFormat.SignatureInfo +import de.rki.coronawarnapp.server.protocols.KeyExportFormat object SignatureHelper { - val clientSig: SignatureInfo = SignatureInfo.newBuilder() + val clientSig: KeyExportFormat.SignatureInfo = KeyExportFormat.SignatureInfo.newBuilder() .setAndroidPackage("de.rki.coronawarnapp") .setAppBundleId("de.rki.coronawarnapp") .setSignatureAlgorithm("ECDSA") diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt index 46a40294cfe76948dfdc652426747ae8dafddddc..665a94a67bfb156af56fbc7fcb75757bc349f4a3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt @@ -4,7 +4,9 @@ import android.content.Context import com.google.common.math.DoubleMath.roundToLong import org.joda.time.DateTime import org.joda.time.DateTimeZone +import org.joda.time.Days import org.joda.time.Instant +import org.joda.time.LocalDate import org.joda.time.chrono.GJChronology import org.joda.time.format.DateTimeFormat import timber.log.Timber @@ -75,4 +77,8 @@ object TimeAndDateExtensions { val millionSeconds = secondDate - firstDate return TimeUnit.MILLISECONDS.toDays(millionSeconds) } + + fun LocalDate.ageInDays(now: LocalDate) = Days.daysBetween(this, now).days + + fun Instant.toLocalDate() = this.toDateTime(DateTimeZone.UTC).toLocalDate() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeStamper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeStamper.kt new file mode 100644 index 0000000000000000000000000000000000000000..fcbfc75d6000520c026cb3db85f3f7ba7389386d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeStamper.kt @@ -0,0 +1,12 @@ +package de.rki.coronawarnapp.util + +import org.joda.time.Instant +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class TimeStamper @Inject constructor() { + + val nowUTC: Instant + get() = Instant.now() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/UtilModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/UtilModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..79bc71b5d57157184b444befa641bd3b8ca559be --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/UtilModule.kt @@ -0,0 +1,23 @@ +package de.rki.coronawarnapp.util + +import dagger.Binds +import dagger.Module +import de.rki.coronawarnapp.util.device.DefaultPowerManagement +import de.rki.coronawarnapp.util.device.PowerManagement +import javax.inject.Singleton + +@Module +abstract class UtilModule { + + @Binds + @Singleton + abstract fun bindPowerManagement( + powerManagement: DefaultPowerManagement + ): PowerManagement + + @Binds + @Singleton + abstract fun bindBackgroundPrioritization( + backgroundPrioritization: DefaultBackgroundPrioritization + ): BackgroundPrioritization +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/Views.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/Views.kt new file mode 100644 index 0000000000000000000000000000000000000000..0b70bf717794ab09bbd35bc899e5e24cdd24b24f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/Views.kt @@ -0,0 +1,56 @@ +package de.rki.coronawarnapp.util + +import android.text.SpannableString +import android.text.Spanned +import android.text.method.LinkMovementMethod +import android.text.style.URLSpan +import android.widget.TextView +import androidx.annotation.StringRes + +fun TextView.convertToHyperlink(url: String) { + setText( + SpannableString(text).apply { setSpan(URLSpan(url), 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) }, + TextView.BufferType.SPANNABLE + ) + movementMethod = LinkMovementMethod.getInstance() +} + +fun TextView.setUrlText(@StringRes textRes: Int, url: String) { + context.getString(textRes, url).also { + val indexOf = it.indexOf(url) + setText( + SpannableString(it).apply { + setSpan( + URLSpan(url), + indexOf, + indexOf + url.length, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + }, + TextView.BufferType.SPANNABLE + ) + movementMethod = LinkMovementMethod.getInstance() + } +} + +fun TextView.setUrl(@StringRes textRes: Int, label: String, url: String) { + context.getString(textRes).also { + val indexOf = it.indexOf(label) + if (indexOf > 0) { + setText( + SpannableString(it).apply { + setSpan( + URLSpan(url), + indexOf, + indexOf + label.length, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + }, + TextView.BufferType.SPANNABLE + ) + movementMethod = LinkMovementMethod.getInstance() + } else { + text = it + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt new file mode 100644 index 0000000000000000000000000000000000000000..d2e5aa97c9fc787f2874d65145e9c203a8457d9b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/WatchdogService.kt @@ -0,0 +1,77 @@ +package de.rki.coronawarnapp.util + +import android.content.Context +import android.net.wifi.WifiManager +import android.os.PowerManager +import androidx.lifecycle.ProcessLifecycleOwner +import androidx.lifecycle.lifecycleScope +import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction +import de.rki.coronawarnapp.worker.BackgroundWorkHelper +import de.rki.coronawarnapp.worker.BackgroundWorkScheduler +import kotlinx.coroutines.launch +import timber.log.Timber +import java.util.UUID +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class WatchdogService @Inject constructor(private val context: Context) { + + private val powerManager by lazy { + context.getSystemService(Context.POWER_SERVICE) as PowerManager + } + private val wifiManager by lazy { + context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + } + + fun launch() { + // Only do this if the background jobs are enabled + if (!ConnectivityHelper.autoModeEnabled(context)) { + Timber.d("Background jobs are not enabled, aborting.") + return + } + + Timber.v("Acquiring wakelocks for watchdog routine.") + ProcessLifecycleOwner.get().lifecycleScope.launch { + // A wakelock as the OS does not handle this for us like in the background job execution + val wakeLock = createWakeLock() + // A wifi lock to wake up the wifi connection in case the device is dozing + val wifiLock = createWifiLock() + try { + BackgroundWorkHelper.sendDebugNotification( + "Automatic mode is on", "Check if we have downloaded keys already today" + ) + RetrieveDiagnosisKeysTransaction.startWithConstraints() + } catch (e: Exception) { + BackgroundWorkHelper.sendDebugNotification( + "RetrieveDiagnosisKeysTransaction failed", + (e.localizedMessage + ?: "Unknown exception occurred in onCreate") + "\n\n" + (e.cause + ?: "Cause is unknown").toString() + ) + // retry the key retrieval in case of an error with a scheduled work + BackgroundWorkScheduler.scheduleDiagnosisKeyOneTimeWork() + } + + if (wifiLock.isHeld) wifiLock.release() + if (wakeLock.isHeld) wakeLock.release() + } + + // if the user is onboarded we will schedule period background jobs + // in case the app was force stopped and woken up again by the Google WakeUpService + if (LocalData.onboardingCompletedTimestamp() != null) BackgroundWorkScheduler.startWorkScheduler() + } + + private fun createWakeLock(): PowerManager.WakeLock = powerManager + .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CWA-WAKE-${UUID.randomUUID()}") + .apply { acquire(TEN_MINUTE_TIMEOUT_IN_MS) } + + private fun createWifiLock(): WifiManager.WifiLock = wifiManager + .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "CWA-WIFI-${UUID.randomUUID()}") + .apply { acquire() } + + companion object { + private const val TEN_MINUTE_TIMEOUT_IN_MS = 10 * 60 * 1000L + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ZipHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ZipHelper.kt index 22d10b8c0a7f2d6d35e8b78d0da4b9623b465fa6..b296cced9c324d4a7499b2512b716e069a38abc0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ZipHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ZipHelper.kt @@ -22,7 +22,6 @@ package de.rki.coronawarnapp.util import timber.log.Timber import java.io.File import java.io.FileInputStream -import java.io.FileOutputStream import java.io.InputStream import java.util.zip.ZipEntry import java.util.zip.ZipInputStream @@ -44,7 +43,7 @@ object ZipHelper { } outputFile.createNewFile() - FileOutputStream(outputFile).use { fileOutputStream -> + outputFile.outputStream().use { fileOutputStream -> ZipOutputStream(fileOutputStream).use { zipOutputStream -> writeToZip( nameOfOutputFile, diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/database/CommonConverters.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/database/CommonConverters.kt new file mode 100644 index 0000000000000000000000000000000000000000..cbbf8366f3d47ce6b05c2917b8a471ab7e685d91 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/database/CommonConverters.kt @@ -0,0 +1,81 @@ +/****************************************************************************** + * Corona-Warn-App * + * * + * SAP SE and all other contributors / * + * copyright owners license this file to you under the Apache * + * License, Version 2.0 (the "License"); you may not use this * + * file except in compliance with the License. * + * You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ******************************************************************************/ + +package de.rki.coronawarnapp.util.database + +import androidx.room.TypeConverter +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import java.io.File +import java.util.UUID + +class CommonConverters { + private val gson = Gson() + + @TypeConverter + fun toIntList(value: String?): List<Int> { + val listType = object : TypeToken<List<Int?>?>() {}.type + return gson.fromJson(value, listType) + } + + @TypeConverter + fun fromIntList(list: List<Int?>?): String { + return gson.toJson(list) + } + + @TypeConverter + fun toUUID(value: String?): UUID? = value?.let { UUID.fromString(it) } + + @TypeConverter + fun fromUUID(uuid: UUID?): String? = uuid?.toString() + + @TypeConverter + fun toPath(value: String?): File? = value?.let { File(it) } + + @TypeConverter + fun fromPath(path: File?): String? = path?.path + + @TypeConverter + fun toLocalDate(value: String?): LocalDate? = value?.let { LocalDate.parse(it) } + + @TypeConverter + fun fromLocalDate(date: LocalDate?): String? = date?.toString() + + @TypeConverter + fun toLocalTime(value: String?): LocalTime? = value?.let { LocalTime.parse(it) } + + @TypeConverter + fun fromLocalTime(date: LocalTime?): String? = date?.toString() + + @TypeConverter + fun toInstant(value: String?): Instant? = value?.let { Instant.parse(it) } + + @TypeConverter + fun fromInstant(date: Instant?): String? = date?.toString() + + @TypeConverter + fun toLocationCode(value: String?): LocationCode? = value?.let { LocationCode(it) } + + @TypeConverter + fun fromLocationCode(code: LocationCode?): String? = code?.identifier +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/TimeMeasurement.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/TimeMeasurement.kt new file mode 100644 index 0000000000000000000000000000000000000000..58c06b520ba0b45fca3b1c93f53b1bc966b73111 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/debug/TimeMeasurement.kt @@ -0,0 +1,7 @@ +package de.rki.coronawarnapp.util.debug + +inline fun <T> measureTimeMillisWithResult(block: () -> T): Pair<T, Long> { + val start = System.currentTimeMillis() + val result = block() + return result to (System.currentTimeMillis() - start) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DefaultPowerManagement.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DefaultPowerManagement.kt new file mode 100644 index 0000000000000000000000000000000000000000..12475b33358693e19786dc76b8099e245c7d8f64 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DefaultPowerManagement.kt @@ -0,0 +1,29 @@ +package de.rki.coronawarnapp.util.device + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.PowerManager +import android.provider.Settings +import javax.inject.Inject + +class DefaultPowerManagement @Inject constructor( + private val context: Context +) : PowerManagement { + + private val powerManager by lazy { + context.getSystemService(Context.POWER_SERVICE) as PowerManager + } + + override val isIgnoringBatteryOptimizations + get() = powerManager.isIgnoringBatteryOptimizations(context.packageName) + + override val toBatteryOptimizationSettingsIntent = + Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS) + + override val disableBatteryOptimizationsIntent = + Intent( + Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, + Uri.parse("package:${context.packageName}") + ) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DefaultSystemInfoProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DefaultSystemInfoProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..5a8fccf5f9f309fadafdfb33c012833a41e394ad --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DefaultSystemInfoProvider.kt @@ -0,0 +1,19 @@ +package de.rki.coronawarnapp.util.device + +import android.content.Context +import android.content.res.Resources +import android.os.Build +import java.util.Locale +import javax.inject.Inject + +class DefaultSystemInfoProvider @Inject constructor(context: Context) : SystemInfoProvider { + + override val locale: Locale + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + @Suppress("NewApi") + Resources.getSystem().configuration.locales[0] + } else { + @Suppress("DEPRECATION") + Resources.getSystem().configuration.locale + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DeviceModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DeviceModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..460aee0335c0fe2968ae44c72b37370be37e6eb0 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/DeviceModule.kt @@ -0,0 +1,15 @@ +package de.rki.coronawarnapp.util.device + +import dagger.Binds +import dagger.Module +import javax.inject.Singleton + +@Module +abstract class DeviceModule { + + @Binds + @Singleton + abstract fun bindSystemInfoProvider( + systemInfoProvider: DefaultSystemInfoProvider + ): SystemInfoProvider +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/PowerManagement.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/PowerManagement.kt new file mode 100644 index 0000000000000000000000000000000000000000..d0cd90a3025c22ef83240852e9352e39d6e6194e --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/PowerManagement.kt @@ -0,0 +1,15 @@ +package de.rki.coronawarnapp.util.device + +import android.content.Intent + +interface PowerManagement { + + /** + * Checks if app is excluded from battery optimizations + */ + val isIgnoringBatteryOptimizations: Boolean + + val toBatteryOptimizationSettingsIntent: Intent + + val disableBatteryOptimizationsIntent: Intent +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/SystemInfoProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/SystemInfoProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..a3d2ba8935cca8f0ff3a5cd5b588839456b87894 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/SystemInfoProvider.kt @@ -0,0 +1,11 @@ +package de.rki.coronawarnapp.util.device + +import java.util.Locale + +interface SystemInfoProvider { + + /** + * the device Locale + */ + val locale: Locale +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AndroidModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AndroidModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..15b4f6a3962f4e95b126bf2eb92a07ff3b3a263d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AndroidModule.kt @@ -0,0 +1,20 @@ +package de.rki.coronawarnapp.util.di + +import android.app.Application +import android.content.Context +import dagger.Module +import dagger.Provides +import de.rki.coronawarnapp.CoronaWarnApplication +import javax.inject.Singleton + +@Module +class AndroidModule { + + @Provides + @Singleton + fun application(app: CoronaWarnApplication): Application = app + + @Provides + @Singleton + fun context(app: Application): Context = app.applicationContext +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AppInjector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AppInjector.kt new file mode 100644 index 0000000000000000000000000000000000000000..6026460d18eb05d467d670825a6ccad8e9d531b7 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AppInjector.kt @@ -0,0 +1,48 @@ +package de.rki.coronawarnapp.util.di + +import android.app.Activity +import android.content.Context +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.fragment.app.FragmentManager +import dagger.android.AndroidInjection +import dagger.android.support.AndroidSupportInjection +import de.rki.coronawarnapp.CoronaWarnApplication +import timber.log.Timber + +object AppInjector { + lateinit var component: ApplicationComponent + + fun init(app: CoronaWarnApplication) { + component = DaggerApplicationComponent.factory().create(app) + component.inject(app) + } + + fun setup(activity: Activity) { + Timber.tag(TAG).d("Injecting %s", activity) + + // Using lifecycle callbacks would be even more awesome, + // but Activity.onPreCreate isn't available for our minAPI + AndroidInjection.inject(activity) + + if (activity is FragmentActivity) { + activity.supportFragmentManager + .registerFragmentLifecycleCallbacks(object : + FragmentManager.FragmentLifecycleCallbacks() { + override fun onFragmentPreAttached( + fm: FragmentManager, + f: Fragment, + context: Context + ) { + if (f is AutoInject) { + Timber.tag(TAG).d("Injecting %s", f) + AndroidSupportInjection.inject(f) + } + super.onFragmentPreAttached(fm, f, context) + } + }, true) + } + } + + private val TAG = AppInjector::class.java.simpleName +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..ff04498335e1bdcdf5e2839730798a2d68e86534 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt @@ -0,0 +1,88 @@ +package de.rki.coronawarnapp.util.di + +import dagger.BindsInstance +import dagger.Component +import dagger.android.AndroidInjector +import dagger.android.support.AndroidSupportInjectionModule +import de.rki.coronawarnapp.CoronaWarnApplication +import de.rki.coronawarnapp.appconfig.AppConfigModule +import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule +import de.rki.coronawarnapp.diagnosiskeys.download.KeyFileDownloader +import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.environment.EnvironmentModule +import de.rki.coronawarnapp.http.HttpModule +import de.rki.coronawarnapp.nearby.ENFClient +import de.rki.coronawarnapp.nearby.ENFModule +import de.rki.coronawarnapp.playbook.Playbook +import de.rki.coronawarnapp.playbook.PlaybookModule +import de.rki.coronawarnapp.receiver.ReceiverBinder +import de.rki.coronawarnapp.risk.RiskModule +import de.rki.coronawarnapp.service.ServiceBinder +import de.rki.coronawarnapp.storage.SettingsRepository +import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository +import de.rki.coronawarnapp.submission.SubmissionModule +import de.rki.coronawarnapp.transaction.RetrieveDiagnosisInjectionHelper +import de.rki.coronawarnapp.transaction.RiskLevelInjectionHelper +import de.rki.coronawarnapp.transaction.SubmitDiagnosisInjectionHelper +import de.rki.coronawarnapp.ui.ActivityBinder +import de.rki.coronawarnapp.util.ConnectivityHelperInjection +import de.rki.coronawarnapp.util.UtilModule +import de.rki.coronawarnapp.util.device.DeviceModule +import de.rki.coronawarnapp.util.security.EncryptedPreferencesFactory +import de.rki.coronawarnapp.util.security.EncryptionErrorResetTool +import de.rki.coronawarnapp.verification.VerificationModule +import javax.inject.Singleton + +@Singleton +@Component( + modules = [ + AndroidSupportInjectionModule::class, + AssistedInjectModule::class, + AndroidModule::class, + ReceiverBinder::class, + ServiceBinder::class, + ActivityBinder::class, + RiskModule::class, + UtilModule::class, + DeviceModule::class, + ENFModule::class, + HttpModule::class, + EnvironmentModule::class, + DiagnosisKeysModule::class, + AppConfigModule::class, + SubmissionModule::class, + VerificationModule::class, + PlaybookModule::class + ] +) +interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> { + + // TODO Remove once Singletons are gone + val transRetrieveKeysInjection: RetrieveDiagnosisInjectionHelper + val transRiskLevelInjection: RiskLevelInjectionHelper + val transSubmitDiagnosisInjection: SubmitDiagnosisInjectionHelper + + val connectivityHelperInjection: ConnectivityHelperInjection + + val settingsRepository: SettingsRepository + + val keyCacheRepository: KeyCacheRepository + val keyFileDownloader: KeyFileDownloader + + val appConfigProvider: AppConfigProvider + + val enfClient: ENFClient + + val encryptedPreferencesFactory: EncryptedPreferencesFactory + val errorResetTool: EncryptionErrorResetTool + + val playbook: Playbook + + val interoperabilityRepository: InteroperabilityRepository + + @Component.Factory + interface Factory { + fun create(@BindsInstance app: CoronaWarnApplication): ApplicationComponent + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AssistedInjectModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AssistedInjectModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..88cab114e805f64f0e01a1ab919de97c38232a83 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AssistedInjectModule.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.util.di + +import com.squareup.inject.assisted.dagger2.AssistedModule +import dagger.Module + +@AssistedModule +@Module(includes = [AssistedInject_AssistedInjectModule::class]) +interface AssistedInjectModule diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AutoInject.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AutoInject.kt new file mode 100644 index 0000000000000000000000000000000000000000..aea8f758de59fbee0f287d24bb6c27f0909e6f87 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/AutoInject.kt @@ -0,0 +1,4 @@ +package de.rki.coronawarnapp.util.di + +// Annotating an Activity, Fragment marks it for injection via **[AppInjector]** +interface AutoInject diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/errors/ExceptionExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/errors/ExceptionExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..f2d986507e3a6bd8f88acbdfc5ef125fe8835ee1 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/errors/ExceptionExtensions.kt @@ -0,0 +1,11 @@ +package de.rki.coronawarnapp.util.errors + +fun Throwable.causes(): Sequence<Throwable> = sequence { + var error = this@causes + + while (true) { + yield(error) + + error = error.cause ?: break + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/errors/RecoveryByResetDialogFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/errors/RecoveryByResetDialogFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..da52bb3e6e5ceb049fee5dc6cdd0eec93fed6c8b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/errors/RecoveryByResetDialogFactory.kt @@ -0,0 +1,30 @@ +package de.rki.coronawarnapp.util.errors + +import android.content.Context +import androidx.annotation.StringRes +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.Fragment +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.util.ExternalActionHelper + +class RecoveryByResetDialogFactory(private val fragment: Fragment) { + + private val context: Context + get() = fragment.requireContext() + + fun showDialog( + @StringRes detailsLink: Int, + onDismiss: () -> Unit + ) { + AlertDialog.Builder(context) + .setTitle(R.string.errors_generic_headline) + .setMessage(R.string.errors_generic_text_catastrophic_error_recovery_via_reset) + .setCancelable(false) + .setOnDismissListener { onDismiss() } + .setNeutralButton(R.string.errors_generic_button_negative) { _, _ -> + ExternalActionHelper.openUrl(fragment, context.getString(detailsLink)) + } + .setPositiveButton(R.string.errors_generic_button_positive) { _, _ -> } + .show() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterInformationLegalHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterInformationLegalHelper.kt index 37d044477804d4b497eb449f1c12a9659aae53e2..a7097681ebde17b1e9320dcc50066f7e93a8eefa 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterInformationLegalHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterInformationLegalHelper.kt @@ -1,34 +1,30 @@ @file:JvmName("FormatterInformationLegalHelper") package de.rki.coronawarnapp.util.formatter + import android.view.View -import java.util.Locale +import de.rki.coronawarnapp.CoronaWarnApplication +import de.rki.coronawarnapp.ui.information.InformationLegalPresentation +import de.rki.coronawarnapp.util.device.DefaultSystemInfoProvider /** * Language based format visibility * - * @param defaultLanguageEnglishOrGerman * @param isContactFormView * @return */ -fun formatVisibilityLanguageBased(defaultLanguageEnglishOrGerman: Boolean, isContactFormView: Boolean?): Int { - if (defaultLanguageEnglishOrGerman) { - return if (isContactFormView == true) { + +fun formatVisibilityLanguageBased( + isContactFormView: Boolean? +): Int { + InformationLegalPresentation(DefaultSystemInfoProvider(CoronaWarnApplication.getAppContext())).apply { + if (!showBackupLinkToContactForm) { + return if (isContactFormView == true) { + View.VISIBLE + } else View.GONE + } + return if (isContactFormView == false) { View.VISIBLE } else View.GONE } - return if (isContactFormView == false) { - View.VISIBLE - } else View.GONE } - -/** - * checks the default language of the device and formats the visibility - * Returns visibility value - * - * @param isContactFormView - * @return - */ -fun formatContactForm(isContactFormView: Boolean?): Int = - formatVisibilityLanguageBased(Locale.getDefault().language == Locale.ENGLISH.language || - Locale.getDefault().language == Locale.GERMAN.language, isContactFormView) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt index 37730c60a2c346ef7cfd3d994713f395beb65efd..bf158e8962fb69e8b6bd7524ad3b456760ba06d5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt @@ -329,35 +329,6 @@ fun formatNextUpdate( } } -/** - * Formats the risk card content description of time when diagnosis keys will be updated - * from server again when applicable but appends the word button at the end for screen reader accessibility reasons - * - * @param riskLevelScore - * @param isBackgroundJobEnabled - * @return - */ -fun formatNextUpdateContentDescription( - riskLevelScore: Int?, - isBackgroundJobEnabled: Boolean? -): String { - val appContext = CoronaWarnApplication.getAppContext() - return if (isBackgroundJobEnabled != true) { - "" - } else { - return when (riskLevelScore) { - RiskLevelConstants.UNKNOWN_RISK_INITIAL, - RiskLevelConstants.LOW_LEVEL_RISK, - RiskLevelConstants.INCREASED_RISK -> appContext.getString( - R.string.risk_card_body_next_update - ) + " " + appContext.getString( - R.string.accessibility_button - ) - else -> "" - } - } -} - /** * Formats the risk details text display for each risk level * @@ -612,6 +583,16 @@ fun formatVisibilityBehavior(riskLevelScore: Int?): Int = fun formatVisibilityBehaviorIncreasedRisk(riskLevelScore: Int?): Int = formatVisibility(riskLevelScore == RiskLevelConstants.INCREASED_RISK) +/** + * Format the risk details include display for suggested behavior depending on risk level + * Only applied in special case for low level risk + * + * @param riskLevelScore + * @return + */ +fun formatVisibilityBehaviorLowLevelRisk(riskLevelScore: Int?): Int = + formatVisibility(riskLevelScore == RiskLevelConstants.LOW_LEVEL_RISK) + /** * Format the risk details period logged card display depending on risk level * applied in case of low and high risk levels diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelper.kt index 9ab4d7e7054a343d2c69b9dc88b36cff95a1166e..3b0b0c565500ff97170c2a180065f06b114388f0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelper.kt @@ -71,14 +71,13 @@ fun formatNotificationIllustrationText(notifications: Boolean): String = * * @param tracing * @param bluetooth - * @param connection * @param location * @return String */ -fun formatTracingStatusText(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): String { +fun formatTracingStatusText(tracing: Boolean, bluetooth: Boolean, location: Boolean): String { val appContext = CoronaWarnApplication.getAppContext() - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { - TracingStatusHelper.CONNECTION, TracingStatusHelper.BLUETOOTH -> + return when (tracingStatusHelper(tracing, bluetooth, location)) { + TracingStatusHelper.BLUETOOTH -> appContext.getString(R.string.settings_tracing_status_restricted) TracingStatusHelper.TRACING_ACTIVE -> appContext.getString(R.string.settings_tracing_status_active) @@ -102,15 +101,12 @@ fun formatSwitchContentDescription(subtitle: String, status: String): String = " * * @param tracing * @param bluetooth - * @param connection * @param location * @return String */ -fun formatTracingDescription(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): String { +fun formatTracingDescription(tracing: Boolean, bluetooth: Boolean, location: Boolean): String { val appContext = CoronaWarnApplication.getAppContext() - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { - TracingStatusHelper.CONNECTION -> - appContext.getString(R.string.settings_tracing_body_connection_inactive) + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.BLUETOOTH -> appContext.getString(R.string.settings_tracing_body_bluetooth_inactive) TracingStatusHelper.LOCATION -> @@ -129,21 +125,16 @@ fun formatTracingDescription(tracing: Boolean, bluetooth: Boolean, connection: B * * @param tracing * @param bluetooth - * @param connection * @param location * @return String */ fun formatTracingContentDescription( tracing: Boolean, bluetooth: Boolean, - connection: Boolean, location: Boolean ): String { val appContext = CoronaWarnApplication.getAppContext() - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { - TracingStatusHelper.CONNECTION -> - appContext.getString(R.string.settings_tracing_body_connection_inactive) + - " " + appContext.getString(R.string.accessibility_button) + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.BLUETOOTH -> appContext.getString(R.string.settings_tracing_body_bluetooth_inactive) + " " + appContext.getString(R.string.accessibility_button) @@ -179,20 +170,16 @@ fun formatTracingStatusBody(activeTracingDaysInRetentionPeriod: Long): String { * * @param tracing * @param bluetooth - * @param connection * @param location * @return String */ fun formatTracingIllustrationText( tracing: Boolean, bluetooth: Boolean, - connection: Boolean, location: Boolean ): String { val appContext = CoronaWarnApplication.getAppContext() - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { - TracingStatusHelper.CONNECTION -> - appContext.getString(R.string.settings_tracing_connection_illustration_description_inactive) + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.BLUETOOTH -> appContext.getString(R.string.settings_tracing_bluetooth_illustration_description_inactive) TracingStatusHelper.LOCATION -> @@ -271,14 +258,13 @@ fun formatNotificationImage(notifications: Boolean): Drawable? = * * @param tracing * @param bluetooth - * @param connection * @param location * @return */ -fun formatSettingsTracingIconColor(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): Int { +fun formatSettingsTracingIconColor(tracing: Boolean, bluetooth: Boolean, location: Boolean): Int { val appContext = CoronaWarnApplication.getAppContext() - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { - TracingStatusHelper.CONNECTION, TracingStatusHelper.BLUETOOTH -> + return when (tracingStatusHelper(tracing, bluetooth, location)) { + TracingStatusHelper.BLUETOOTH -> appContext.getColor(R.color.colorTextPrimary3) TracingStatusHelper.TRACING_ACTIVE -> appContext.getColor(R.color.colorAccentTintIcon) @@ -293,19 +279,16 @@ fun formatSettingsTracingIconColor(tracing: Boolean, bluetooth: Boolean, connect * * @param tracing * @param bluetooth - * @param connection * @param location * @return */ fun formatSettingsTracingIcon( tracing: Boolean, bluetooth: Boolean, - connection: Boolean, location: Boolean ): Drawable? { val appContext = CoronaWarnApplication.getAppContext() - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { - TracingStatusHelper.CONNECTION, + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.BLUETOOTH, TracingStatusHelper.TRACING_ACTIVE -> appContext.getDrawable(R.drawable.ic_settings_tracing_active_small) @@ -345,12 +328,11 @@ fun formatSettingsBackgroundPriorityIconColor( * * @param tracing * @param bluetooth - * @param connection * @param location * @return Boolean */ -fun formatTracingSwitch(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): Boolean { - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { +fun formatTracingSwitch(tracing: Boolean, bluetooth: Boolean, location: Boolean): Boolean { + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.TRACING_ACTIVE -> true else -> false } @@ -361,12 +343,11 @@ fun formatTracingSwitch(tracing: Boolean, bluetooth: Boolean, connection: Boolea * * @param tracing * @param bluetooth - * @param connection * @param location * @return Boolean */ -fun formatTracingSwitchEnabled(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): Boolean { - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { +fun formatTracingSwitchEnabled(tracing: Boolean, bluetooth: Boolean, location: Boolean): Boolean { + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.TRACING_ACTIVE, TracingStatusHelper.TRACING_INACTIVE -> true else -> false } @@ -377,14 +358,12 @@ fun formatTracingSwitchEnabled(tracing: Boolean, bluetooth: Boolean, connection: * * @param tracing * @param bluetooth - * @param connection * @param location * @return Drawable */ -fun formatTracingIcon(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): Int? { - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { +fun formatTracingIcon(tracing: Boolean, bluetooth: Boolean, location: Boolean): Int? { + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.BLUETOOTH -> R.drawable.ic_settings_tracing_bluetooth_inactive - TracingStatusHelper.CONNECTION -> R.drawable.ic_settings_tracing_connection_inactive TracingStatusHelper.LOCATION -> R.drawable.ic_settings_location_inactive_small TracingStatusHelper.TRACING_ACTIVE -> R.raw.ic_settings_tracing_animated else -> R.drawable.ic_settings_tracing_inactive @@ -396,13 +375,12 @@ fun formatTracingIcon(tracing: Boolean, bluetooth: Boolean, connection: Boolean, * * @param tracing * @param bluetooth - * @param connection * @param location * @return Int */ -fun formatTracingIconColor(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): Int { +fun formatTracingIconColor(tracing: Boolean, bluetooth: Boolean, location: Boolean): Int { val appContext = CoronaWarnApplication.getAppContext() - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.TRACING_ACTIVE -> appContext.getColor(R.color.colorAccentTintIcon) else -> @@ -415,17 +393,14 @@ fun formatTracingIconColor(tracing: Boolean, bluetooth: Boolean, connection: Boo * * @param tracing * @param bluetooth - * @param connection * @param location * @return Drawable */ -fun formatTracingStatusImage(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): Drawable? { +fun formatTracingStatusImage(tracing: Boolean, bluetooth: Boolean, location: Boolean): Drawable? { val appContext = CoronaWarnApplication.getAppContext() - return when (tracingStatusHelper(tracing, bluetooth, connection, location)) { + return when (tracingStatusHelper(tracing, bluetooth, location)) { TracingStatusHelper.BLUETOOTH -> appContext.getDrawable(R.drawable.ic_settings_illustration_bluetooth_off) - TracingStatusHelper.CONNECTION -> - appContext.getDrawable(R.drawable.ic_settings_illustration_connection_off) TracingStatusHelper.LOCATION -> appContext.getDrawable(R.drawable.ic_settings_illustration_location_off) TracingStatusHelper.TRACING_ACTIVE -> @@ -435,45 +410,23 @@ fun formatTracingStatusImage(tracing: Boolean, bluetooth: Boolean, connection: B } } -/** - * Change the visibility of the connection card based on the tracing status. - * - * @param tracing - * @param bluetooth - * @param connection - * @param location - * @return Int - */ -fun formatTracingStatusConnection(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): Int = - formatVisibility( - tracingStatusHelper( - tracing, - bluetooth, - connection, - location - ) == TracingStatusHelper.CONNECTION - ) - /** * Change the visibility of the bluetooth card based on the tracing status. * * @param tracing * @param bluetooth - * @param connection * @param location * @return Int */ fun formatTracingStatusVisibilityBluetooth( tracing: Boolean, bluetooth: Boolean, - connection: Boolean, location: Boolean ): Int = formatVisibility( tracingStatusHelper( tracing, bluetooth, - connection, location ) == TracingStatusHelper.BLUETOOTH ) @@ -483,21 +436,18 @@ fun formatTracingStatusVisibilityBluetooth( * * @param tracing * @param bluetooth - * @param connection * @param location * @return Int */ fun formatTracingStatusVisibilityLocation( tracing: Boolean, bluetooth: Boolean, - connection: Boolean, location: Boolean ): Int = formatVisibility( tracingStatusHelper( tracing, bluetooth, - connection, location ) == TracingStatusHelper.LOCATION ) @@ -507,17 +457,15 @@ fun formatTracingStatusVisibilityLocation( * * @param tracing * @param bluetooth - * @param connection * @param location * @return Int */ fun formatTracingStatusVisibilityTracing( tracing: Boolean, bluetooth: Boolean, - connection: Boolean, location: Boolean ): Int { - val tracingStatus = tracingStatusHelper(tracing, bluetooth, connection, location) + val tracingStatus = tracingStatusHelper(tracing, bluetooth, location) return formatVisibility( tracingStatus == TracingStatusHelper.TRACING_ACTIVE || tracingStatus == TracingStatusHelper.TRACING_INACTIVE diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt index fb6de1ec97bf660e2481d4512f269fd44966a962..ea0ea81e282531d04ad27e41a0d6bf0288c40854 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSubmissionHelper.kt @@ -2,6 +2,7 @@ package de.rki.coronawarnapp.util.formatter +import android.content.Context import android.graphics.drawable.Drawable import android.text.Spannable import android.text.SpannableString @@ -10,10 +11,44 @@ import android.text.style.ForegroundColorSpan import android.view.View import de.rki.coronawarnapp.CoronaWarnApplication import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.submission.Symptoms import de.rki.coronawarnapp.ui.submission.ApiRequestState import de.rki.coronawarnapp.util.DeviceUIState import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUIFormat import java.util.Date +import java.util.Locale + +fun formatButtonStyleByState( + currentState: Symptoms.Indication?, + state: Symptoms.Indication? +): Int = + formatColor(currentState == state, R.color.colorTextSixteenWhite, R.color.colorTextPrimary1) + +fun formatBackgroundButtonStyleByState( + currentState: Symptoms.Indication?, + state: Symptoms.Indication? +): Int = + formatColor(currentState == state, R.color.colorTextSemanticNeutral, R.color.colorSurface2) + +fun formatCalendarButtonStyleByState( + currentState: Symptoms.StartOf?, + state: Symptoms.StartOf? +): Int = + formatColor(currentState == state, R.color.colorTextSixteenWhite, R.color.colorTextPrimary1) + +fun formatCalendarBackgroundButtonStyleByState( + currentState: Symptoms.StartOf?, + state: Symptoms.StartOf? +): Int = + formatColor(currentState == state, R.color.colorTextSemanticNeutral, R.color.colorSurface2) + +fun isEnableSymptomIntroButtonByState(currentState: Symptoms.Indication?): Boolean { + return currentState != null +} + +fun isEnableSymptomCalendarButtonByState(currentState: Symptoms.StartOf?): Boolean { + return currentState != null +} fun formatTestResultSpinnerVisible(uiStateState: ApiRequestState?): Int = formatVisibility(uiStateState != ApiRequestState.SUCCESS) @@ -207,3 +242,36 @@ fun formatShowRiskStatusCard(deviceUiState: DeviceUIState?): Int = deviceUiState != DeviceUIState.PAIRED_POSITIVE_TELETAN && deviceUiState != DeviceUIState.SUBMITTED_FINAL ) + +fun formatCountryIsoTagToLocalizedName(isoTag: String?): String { + val country = if (isoTag != null) Locale("", isoTag).displayCountry else "" + return country +} + +private fun resolveNameToDrawableId(drawableName: String, ctx: Context): Int? { + val drawableId = + ctx.resources.getIdentifier(drawableName, "drawable", ctx.packageName) + return if (drawableId == 0) null else drawableId +} + +fun formatCountryIsoTagToFlagDrawable(isoTag: String?): Drawable? { + val appContext = CoronaWarnApplication.getAppContext() + + val countryName = isoTag?.let { + Locale("", it).getDisplayCountry(Locale.ENGLISH).toLowerCase(Locale.ENGLISH) + } + + val countryId = + countryName?.let { resolveNameToDrawableId("ic_submission_country_flag_$it", appContext) } + + return if (countryId != null) + appContext.getDrawable(countryId) + else + appContext.getDrawable(R.drawable.ic_submission_country_flag_ireland) +} + +fun formatCountrySelectCardColor(isActive: Boolean?): Int = + formatColor(isActive == true, R.color.colorTextSemanticNeutral, R.color.card_dark) + +fun formatCountrySelectCardTextColor(isActive: Boolean?): Int = + formatColor(isActive == true, R.color.colorTextEmphasizedButton, R.color.colorTextPrimary1) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/TracingStatusHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/TracingStatusHelper.kt index 4ddd30e243be66ea623a648508eaf0cf8da76de9..3b9f6d16b89269bdd4014874f068478782446922 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/TracingStatusHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/TracingStatusHelper.kt @@ -8,8 +8,7 @@ object TracingStatusHelper { const val TRACING_ACTIVE = 0 const val TRACING_INACTIVE = 1 const val BLUETOOTH = 2 - const val CONNECTION = 3 - const val LOCATION = 4 + const val LOCATION = 3 } /** @@ -18,19 +17,16 @@ object TracingStatusHelper { * * @param tracing * @param bluetooth - * @param connection * @param location * @return Int */ -fun tracingStatusHelper(tracing: Boolean, bluetooth: Boolean, connection: Boolean, location: Boolean): Int { +fun tracingStatusHelper(tracing: Boolean, bluetooth: Boolean, location: Boolean): Int { return if (!tracing) { TracingStatusHelper.TRACING_INACTIVE } else if (!location) { TracingStatusHelper.LOCATION } else if (!bluetooth) { TracingStatusHelper.BLUETOOTH - } else if (!connection) { - TracingStatusHelper.CONNECTION } else { TracingStatusHelper.TRACING_ACTIVE } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..34bd1d355880e860bc2c6ce525ffe0d26f62e75b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactory.kt @@ -0,0 +1,40 @@ +package de.rki.coronawarnapp.util.security + +import android.content.Context +import android.content.SharedPreferences +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKeys +import de.rki.coronawarnapp.util.RetryMechanism +import timber.log.Timber +import java.security.KeyException +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class EncryptedPreferencesFactory @Inject constructor( + private val context: Context +) { + + private val masterKeyAlias by lazy { + MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) + } + + private fun createInstance(fileName: String) = EncryptedSharedPreferences.create( + fileName, + masterKeyAlias, + context, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ) + + fun create(fileName: String): SharedPreferences = try { + RetryMechanism.retryWithBackOff { + Timber.d("Creating EncryptedSharedPreferences instance.") + createInstance(fileName).also { + Timber.d("Instance created, %d entries.", it.all.size) + } + } + } catch (e: Exception) { + throw KeyException("Permantly failed to instantiate encrypted preferences", e) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptionErrorResetTool.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptionErrorResetTool.kt new file mode 100644 index 0000000000000000000000000000000000000000..de29ea8f6815868e084d7e29fc6da8f74729620f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/EncryptionErrorResetTool.kt @@ -0,0 +1,135 @@ +package de.rki.coronawarnapp.util.security + +import android.content.Context +import android.content.SharedPreferences +import androidx.core.content.edit +import de.rki.coronawarnapp.storage.DATABASE_NAME +import de.rki.coronawarnapp.util.errors.causes +import org.joda.time.Instant +import timber.log.Timber +import java.io.File +import java.security.GeneralSecurityException +import javax.inject.Inject +import javax.inject.Singleton + +/** + * This tool determines the narrow scope for which we will recovery from an encryption error + * by resetting our encrypted data. + * This will allow users currently affected by it, that update the app, to keep using it without + * requiring any manual actions from their side. + * + * https://github.com/corona-warn-app/cwa-app-android/issues/642 + */ +@Singleton +class EncryptionErrorResetTool @Inject constructor( + private val context: Context +) { + // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ContextImpl.java;drc=3b8e8d76315f6718a982d5e6a019b3aa4f634bcd;l=626 + private val encryptedPreferencesFile by lazy { + val appbaseDir = context.filesDir.parentFile!! + val sharedPrefsDir = File(appbaseDir, "shared_prefs") + File(sharedPrefsDir, "${SecurityConstants.ENCRYPTED_SHARED_PREFERENCES_FILE}.xml") + } + private val encryptedDatabaseFile by lazy { + context.getDatabasePath(DATABASE_NAME) + } + private val prefs: SharedPreferences by lazy { + context.getSharedPreferences("encryption_error_reset_tool", Context.MODE_PRIVATE) + } + + private var isResetWindowConsumed: Boolean + get() = prefs.getBoolean(PKEY_EA1851_WAS_WINDOW_CONSUMED, false) + set(value) = prefs.edit { + putBoolean(PKEY_EA1851_WAS_WINDOW_CONSUMED, value) + } + + private var resetPerformedAt: Instant? + get() = prefs.getLong(PKEY_EA1851_RESET_PERFORMED_AT, -1).let { + if (it == -1L) null else Instant.ofEpochMilli(it) + } + set(value) = prefs.edit { + if (value != null) { + putLong(PKEY_EA1851_RESET_PERFORMED_AT, value.millis) + } else { + remove(PKEY_EA1851_RESET_PERFORMED_AT) + } + } + + var isResetNoticeToBeShown: Boolean + get() = prefs.getBoolean(PKEY_EA1851_SHOW_RESET_NOTICE, false) + set(value) = prefs.edit { + putBoolean(PKEY_EA1851_SHOW_RESET_NOTICE, value) + } + + fun tryResetIfNecessary(error: Throwable): Boolean { + Timber.w(error, "isRecoveryWarranted()") + + // We only reset for the first error encountered after upgrading to 1.4.0+ + if (isResetWindowConsumed) { + Timber.v("Reset window has been consumed -> no reset.") + return false + } + isResetWindowConsumed = true + + val keyException = error.causes().singleOrNull { it is GeneralSecurityException } + if (keyException == null) { + Timber.v("Error has no GeneralSecurityException as cause -> no reset.") + return false + } + + // https://github.com/google/tink/blob/a8ec74d083068cd5e1ebed86fd8254630617b592/java_src/src/main/java/com/google/crypto/tink/aead/AeadWrapper.java#L83 + if (keyException.message?.trim()?.equals("decryption failed") != true) { + Timber.v("Not the GeneralSecurityException we are looking for -> no reset.") + return false + } + + if (!encryptedPreferencesFile.exists()) { + // The error we are looking for can only happen if there already is an encrypted preferences file + Timber.w( + "Error fits, but where is the existing preference file (%s)? -> no reset.", + encryptedPreferencesFile + ) + return false + } + + // So we have a GeneralSecurityException("decryption failed") and existing preferences + // And this is the first error we encountered after upgrading to 1.4.0, let's do this! + + return try { + performReset() + } catch (e: Exception) { + // If anything goes wrong, we return false, so that our caller can rethrow the original error. + Timber.e(e, "Error while performing the reset.") + false + } + } + + private fun performReset(): Boolean { + // Delete encrypted shared preferences file + if (!encryptedPreferencesFile.delete()) { + Timber.w("Couldn't delete %s", encryptedPreferencesFile) + // The encrypted preferences are a prerequisite for this error case + // If we can't delete that, we have to assume our reset approach failed. + return false + } + + // The user may have encountered the error even before a database was created. + if (encryptedDatabaseFile.exists() && !encryptedDatabaseFile.delete()) { + Timber.w("Couldn't delete %s", encryptedDatabaseFile) + // There was a database, but we couldn't delete it + // The database is inaccessible without the matching preferences (which we just deleted). + return false + } + + resetPerformedAt = Instant.now() + isResetNoticeToBeShown = true + + return true + } + + companion object { + private const val PKEY_EA1851_RESET_PERFORMED_AT = "ea1851.reset.performedAt" + private const val PKEY_EA1851_WAS_WINDOW_CONSUMED = "ea1851.reset.windowconsumed" + private const val PKEY_EA1851_SHOW_RESET_NOTICE = "ea1851.reset.shownotice" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/SecurityHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/SecurityHelper.kt index 57617a039fa614edb8e55de95dc972fbd5e085de..370ab58fd4ce02e2358bc1dd9f66557020403546 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/SecurityHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/SecurityHelper.kt @@ -20,45 +20,46 @@ package de.rki.coronawarnapp.util.security import android.annotation.SuppressLint -import android.content.Context import android.content.SharedPreferences import android.os.Build import android.util.Base64 -import androidx.security.crypto.EncryptedSharedPreferences -import androidx.security.crypto.MasterKeys -import de.rki.coronawarnapp.CoronaWarnApplication +import androidx.annotation.VisibleForTesting import de.rki.coronawarnapp.exception.CwaSecurityException +import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.di.ApplicationComponent import de.rki.coronawarnapp.util.security.SecurityConstants.CWA_APP_SQLITE_DB_PW import de.rki.coronawarnapp.util.security.SecurityConstants.DB_PASSWORD_MAX_LENGTH import de.rki.coronawarnapp.util.security.SecurityConstants.DB_PASSWORD_MIN_LENGTH import de.rki.coronawarnapp.util.security.SecurityConstants.ENCRYPTED_SHARED_PREFERENCES_FILE +import timber.log.Timber import java.security.SecureRandom /** * Key Store and Password Access */ object SecurityHelper { - private val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC - private val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec) - val globalEncryptedSharedPreferencesInstance: SharedPreferences by lazy { + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal val encryptedPreferencesProvider: (ApplicationComponent) -> SharedPreferences = { + val factory = it.encryptedPreferencesFactory + val encryptionErrorResetTool = it.errorResetTool withSecurityCatch { - CoronaWarnApplication.getAppContext() - .getEncryptedSharedPrefs(ENCRYPTED_SHARED_PREFERENCES_FILE) + try { + factory.create(ENCRYPTED_SHARED_PREFERENCES_FILE) + } catch (e: Exception) { + if (encryptionErrorResetTool.tryResetIfNecessary(e)) { + Timber.w("We could recovery from this error via reset. Now retrying.") + factory.create(ENCRYPTED_SHARED_PREFERENCES_FILE) + } else { + throw e + } + } } } - /** - * Initializes the private encrypted key store - */ - private fun Context.getEncryptedSharedPrefs(fileName: String) = EncryptedSharedPreferences - .create( - fileName, - masterKeyAlias, - this, - EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, - EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM - ) + val globalEncryptedSharedPreferencesInstance: SharedPreferences by lazy { + encryptedPreferencesProvider(AppInjector.component) + } private val String.toPreservedByteArray: ByteArray get() = Base64.decode(this, Base64.NO_WRAP) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/VerificationKeys.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/VerificationKeys.kt index b70af82ba6d6a329d41de23d4bddc5778e4ffaa5..35ac654628a44f338b4c982bd3ae413cdcdb3507 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/VerificationKeys.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/security/VerificationKeys.kt @@ -1,17 +1,23 @@ package de.rki.coronawarnapp.util.security -import KeyExportFormat import android.security.keystore.KeyProperties import android.util.Base64 -import de.rki.coronawarnapp.BuildConfig +import de.rki.coronawarnapp.environment.EnvironmentSetup +import de.rki.coronawarnapp.server.protocols.KeyExportFormat import timber.log.Timber import java.security.KeyFactory import java.security.Signature import java.security.spec.X509EncodedKeySpec +import javax.inject.Inject +import javax.inject.Singleton -class VerificationKeys { +@Singleton +class VerificationKeys @Inject constructor( + private val environmentSetup: EnvironmentSetup +) { companion object { private const val KEY_DELIMITER = "," + private val TAG = VerificationKeys::class.java.simpleName } private val keyFactory = KeyFactory.getInstance(KeyProperties.KEY_ALGORITHM_EC) @@ -25,8 +31,8 @@ class VerificationKeys { signature.getValidSignaturesForExport(export, signatureListBinary) .isEmpty() .also { - if (it) Timber.d("export is invalid") - else Timber.d("export is valid") + if (it) Timber.tag(TAG).d("export is invalid") + else Timber.tag(TAG).d("export is valid") } } @@ -43,20 +49,20 @@ class VerificationKeys { } verified } - .also { Timber.v("${it.size} valid signatures found") } + .also { Timber.tag(TAG).v("${it.size} valid signatures found") } private fun getKeysForSignatureVerificationFilteredByEnvironment() = - BuildConfig.PUB_KEYS_SIGNATURE_VERIFICATION.split(KEY_DELIMITER) + environmentSetup.appConfigVerificationKey.split(KEY_DELIMITER) .mapNotNull { delimitedString -> Base64.decode(delimitedString, Base64.DEFAULT) }.map { binaryPublicKey -> - keyFactory.generatePublic( - X509EncodedKeySpec( - binaryPublicKey + keyFactory.generatePublic( + X509EncodedKeySpec( + binaryPublicKey + ) ) - ) - } - .onEach { Timber.v("$it") } + } + .onEach { Timber.tag(TAG).v("$it") } private fun getTEKSignaturesForEnvironment( signatureListBinary: ByteArray? @@ -64,6 +70,6 @@ class VerificationKeys { .parseFrom(signatureListBinary) .signaturesList .asSequence() - .onEach { Timber.v(it.toString()) } + .onEach { Timber.tag(TAG).v(it.toString()) } .mapNotNull { it.signature.toByteArray() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/storage/StatsFsProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/storage/StatsFsProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..161993d8572c6617e4f4ef7f4e6b124a5532a707 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/storage/StatsFsProvider.kt @@ -0,0 +1,20 @@ +package de.rki.coronawarnapp.util.storage + +import android.os.StatFs +import dagger.Reusable +import timber.log.Timber +import java.io.File +import javax.inject.Inject + +@Reusable +class StatsFsProvider @Inject constructor() { + + fun createStats(path: File): StatFs { + Timber.tag(TAG).v("createStats(path=%s)", path) + return StatFs(path.path) + } + + companion object { + val TAG = StatsFsProvider::class.java.simpleName + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/LiveDataExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/LiveDataExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..99471c8af0e066c09ec73a50c8a73d13efe918e1 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/LiveDataExtensions.kt @@ -0,0 +1,29 @@ +package de.rki.coronawarnapp.util.ui + +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer + +fun <T> LiveData<T>.observe2(fragment: Fragment, callback: (T) -> Unit) { + observe(fragment.viewLifecycleOwner, Observer { callback.invoke(it) }) +} + +fun <T> LiveData<T>.observe2(activity: AppCompatActivity, callback: (T) -> Unit) { + observe(activity, Observer { callback.invoke(it) }) +} + +fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner? = null, observer: Observer<T>) { + val internalObserver = object : Observer<T> { + override fun onChanged(t: T?) { + observer.onChanged(t) + removeObserver(this) + } + } + if (lifecycleOwner == null) { + observeForever(internalObserver) + } else { + observe(lifecycleOwner, internalObserver) + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/SingleLiveEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/SingleLiveEvent.kt new file mode 100644 index 0000000000000000000000000000000000000000..44809a1831ffe97fb8615ace28f1d692c173a421 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/SingleLiveEvent.kt @@ -0,0 +1,71 @@ +package de.rki.coronawarnapp.util.ui + +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import androidx.annotation.MainThread +import androidx.annotation.Nullable +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer +import timber.log.Timber +import java.util.concurrent.atomic.AtomicBoolean + +/** + * A lifecycle-aware observable that sends only new updates after subscription, used for events like + * navigation and Snackbar messages. + * + * + * This avoids a common problem with events: on configuration change (like rotation) an update + * can be emitted if the observer is active. This LiveData only calls the observable if there's an + * explicit call to setValue() or call(). + * + * + * Note that only one observer is going to be notified of changes. + * https://github.com/android/architecture-samples/blob/166ca3a93ad14c6e224a3ea9bfcbd773eb048fb0/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java + */ +class SingleLiveEvent<T> : MutableLiveData<T>() { + + private val pending = AtomicBoolean(false) + + @MainThread + override fun observe(owner: LifecycleOwner, observer: Observer<in T>) { + if (hasActiveObservers()) { + Timber.w("Multiple observers registered but only one will be notified of changes.") + } + + // Observe the internal MutableLiveData + super.observe(owner, Observer<T> { t -> + if (pending.compareAndSet(true, false)) { + observer.onChanged(t) + } + }) + } + + @MainThread + override fun setValue(@Nullable t: T?) { + pending.set(true) + super.setValue(t) + } + + /** + * Used for cases where T is Void, to make calls cleaner. + */ + @MainThread + fun call() { + value = null + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/SmartLiveData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/SmartLiveData.kt new file mode 100644 index 0000000000000000000000000000000000000000..cdd903d6510f3e194b270797433d9661285dca25 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/SmartLiveData.kt @@ -0,0 +1,53 @@ +package de.rki.coronawarnapp.util.ui + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +fun <T : Any> ViewModel.smartLiveData( + dispatcher: CoroutineDispatcher = Dispatchers.Default, + initAction: suspend () -> T +) = SmartLiveDataProperty(dispatcher, initAction) + +class SmartLiveDataProperty<T : Any>( + private val dispatcher: CoroutineDispatcher = Dispatchers.Default, + private val initialValueProvider: suspend () -> T +) : ReadOnlyProperty<ViewModel, SmartLiveData<T>> { + + private var liveData: SmartLiveData<T>? = null + + override fun getValue( + thisRef: ViewModel, + property: KProperty<*> + ): SmartLiveData<T> { + liveData?.let { + return@getValue it + } + + return SmartLiveData<T>(thisRef, dispatcher).also { + liveData = it + thisRef.viewModelScope.launch(context = dispatcher) { + it.postValue(initialValueProvider()) + } + } + } +} + +class SmartLiveData<T : Any>( + private val viewModel: ViewModel, + private val dispatcher: CoroutineDispatcher +) : MutableLiveData<T>() { + + fun update(updateAction: (T) -> T) { + observeOnce { + viewModel.viewModelScope.launch(context = dispatcher) { + postValue(updateAction(it)) + } + } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..9af1ba94624597a7855b79651324471215add2c2 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt @@ -0,0 +1,68 @@ +package de.rki.coronawarnapp.util.ui + +import android.os.Handler +import android.os.Looper +import android.view.View +import androidx.annotation.MainThread +import androidx.databinding.ViewDataBinding +import androidx.fragment.app.Fragment +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.viewbinding.ViewBinding +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +inline fun <FragmentT : Fragment, reified BindingT : ViewBinding> FragmentT.viewBindingLazy() = + this.viewBindingLazy( + bindingProvider = { + val bindingMethod = BindingT::class.java.getMethod("bind", View::class.java) + val binding = bindingMethod(null, requireView()) as BindingT + if (binding is ViewDataBinding) { + binding.lifecycleOwner = this.viewLifecycleOwner + } + binding + }, + lifecycleOwnerProvider = { viewLifecycleOwner } + ) + +@Suppress("unused") +fun <FragmentT : Fragment, BindingT : ViewBinding> FragmentT.viewBindingLazy( + bindingProvider: FragmentT.() -> BindingT, + lifecycleOwnerProvider: FragmentT.() -> LifecycleOwner +) = ViewBindingProperty(bindingProvider, lifecycleOwnerProvider) + +class ViewBindingProperty<ComponentT : LifecycleOwner, BindingT : ViewBinding>( + private val bindingProvider: (ComponentT) -> BindingT, + private val lifecycleOwnerProvider: ComponentT.() -> LifecycleOwner +) : ReadOnlyProperty<ComponentT, BindingT> { + + private val uiHandler = Handler(Looper.getMainLooper()) + private var localRef: ComponentT? = null + private var viewBinding: BindingT? = null + + private val onDestroyObserver = object : DefaultLifecycleObserver { + // Called right before Fragment.onDestroyView + override fun onDestroy(owner: LifecycleOwner) { + val ref = localRef ?: return + ref.lifecycle.removeObserver(this) + localRef = null + // Otherwise the binding is null before Fragment.onDestroyView + uiHandler.post { viewBinding = null } + } + } + + @MainThread + override fun getValue(thisRef: ComponentT, property: KProperty<*>): BindingT { + viewBinding?.let { + // Only accessible from within the same component + require(localRef === thisRef) + return@getValue it + } + + localRef = thisRef + + lifecycleOwnerProvider(thisRef).lifecycle.addObserver(onDestroyObserver) + + return bindingProvider(thisRef).also { viewBinding = it } + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..b5be612335123304ec35db0e87d0f3de55a4badc --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewExtensions.kt @@ -0,0 +1,11 @@ +package de.rki.coronawarnapp.util.ui + +import android.view.View + +fun View.setGone(gone: Boolean) { + visibility = if (gone) View.GONE else View.VISIBLE +} + +fun View.setInvisible(invisible: Boolean) { + visibility = if (invisible) View.INVISIBLE else View.VISIBLE +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..deaf4368cafc84eafcd3c6e4a6a5daf4150d93ad --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModel.kt @@ -0,0 +1,22 @@ +package de.rki.coronawarnapp.util.viewmodel + +import androidx.annotation.CallSuper +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import timber.log.Timber + +abstract class CWAViewModel : ViewModel() { + + init { + Timber.v("Initialized") + } + + @CallSuper + override fun onCleared() { + viewModelScope.launch(context = Dispatchers.Default) { } + Timber.v("onCleared()") + super.onCleared() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..4ff5fa783d48b544b7b8974ca766e113e78c4495 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelExtensions.kt @@ -0,0 +1,58 @@ +package de.rki.coronawarnapp.util.viewmodel + +import androidx.activity.ComponentActivity +import androidx.annotation.MainThread +import androidx.fragment.app.Fragment +import androidx.lifecycle.SavedStateHandle + +@MainThread +inline fun <reified VM : CWAViewModel> Fragment.cwaViewModels( + noinline factoryProducer: (() -> CWAViewModelFactoryProvider.Factory) +) = this.cwaViewModels<VM>(null, factoryProducer) + +@MainThread +inline fun <reified VM : CWAViewModel> Fragment.cwaViewModels( + noinline keyProducer: (() -> String)? = null, + noinline factoryProducer: (() -> CWAViewModelFactoryProvider.Factory) +) = viewModelsKeyed<VM>(keyProducer) { factoryProducer.invoke().create(this, arguments) } + +@MainThread +inline fun <reified VM : CWAViewModel> Fragment.cwaViewModelsAssisted( + noinline factoryProducer: (() -> CWAViewModelFactoryProvider.Factory), + noinline constructorCall: ((CWAViewModelFactory<out CWAViewModel>, SavedStateHandle) -> CWAViewModel) +) = this.cwaViewModelsAssisted<VM>(null, factoryProducer, constructorCall) + +@MainThread +inline fun <reified VM : CWAViewModel> Fragment.cwaViewModelsAssisted( + noinline keyProducer: (() -> String)? = null, + noinline factoryProducer: (() -> CWAViewModelFactoryProvider.Factory), + noinline constructorCall: ((CWAViewModelFactory<out CWAViewModel>, SavedStateHandle) -> CWAViewModel) +) = viewModelsKeyed<VM>(keyProducer) { + factoryProducer.invoke().create(this, arguments, constructorCall) +} + +@MainThread +inline fun <reified VM : CWAViewModel> ComponentActivity.cwaViewModels( + noinline factoryProducer: (() -> CWAViewModelFactoryProvider.Factory) +) = this.cwaViewModels<VM>(null, factoryProducer) + +@MainThread +inline fun <reified VM : CWAViewModel> ComponentActivity.cwaViewModels( + noinline keyProducer: (() -> String)? = null, + noinline factoryProducer: (() -> CWAViewModelFactoryProvider.Factory) +) = viewModelsKeyed<VM>(keyProducer) { factoryProducer.invoke().create(this, intent.extras) } + +@MainThread +inline fun <reified VM : CWAViewModel> ComponentActivity.cwaViewModelsAssisted( + noinline factoryProducer: (() -> CWAViewModelFactoryProvider.Factory), + noinline constructorCall: ((CWAViewModelFactory<out CWAViewModel>, SavedStateHandle) -> CWAViewModel) +) = this.cwaViewModelsAssisted<VM>(null, factoryProducer, constructorCall) + +@MainThread +inline fun <reified VM : CWAViewModel> ComponentActivity.cwaViewModelsAssisted( + noinline keyProducer: (() -> String)? = null, + noinline factoryProducer: (() -> CWAViewModelFactoryProvider.Factory), + noinline constructorCall: ((CWAViewModelFactory<out CWAViewModel>, SavedStateHandle) -> CWAViewModel) +) = viewModelsKeyed<VM>(keyProducer) { + factoryProducer.invoke().create(this, intent.extras, constructorCall) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..bc2241b0f0f24e060a6b5dbed45255c566cf345f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelFactory.kt @@ -0,0 +1,3 @@ +package de.rki.coronawarnapp.util.viewmodel + +interface CWAViewModelFactory<T : CWAViewModel> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelFactoryProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelFactoryProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..836fe2688145ef18cd97a9a24894d686e1ce0a86 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelFactoryProvider.kt @@ -0,0 +1,80 @@ +package de.rki.coronawarnapp.util.viewmodel + +import android.os.Bundle +import androidx.lifecycle.AbstractSavedStateViewModelFactory +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.savedstate.SavedStateRegistryOwner +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject + +/** + * Using fragments as example: + * + * Step 1: Inject CWAViewModelSource.Factory into Fragment + * + * Step 2: Use assisted inject `CWAViewModelSource.Factory.create(...)` to create an instance of + * CWAViewModelSource that has access to the fragments `savedStateOwner` + * + * Step 3: On first access (like "by lazy") to the viewModel the extension function, + * i.e. `ourViewModel.onActionClicked`, + * `cwaViewModelsAssisted` (or one of it's variants) checks the fragments viewmodel store + * + * Step 4: If no viewmodel was available, this factory is tasked with creating a new viewmodel + * + * Step 5: `CWAViewModelSource.create` is called as part of that flow and returns a new viewmodel + * + * Step 6: The new viewmodel is cached and returned + * + * Step 7: Finally whatever called `ourViewModel.onActionClicked` can execute. + */ +class CWAViewModelFactoryProvider @AssistedInject constructor( + private val creators: @JvmSuppressWildcards Map<Class<out CWAViewModel>, CWAViewModelFactory<out CWAViewModel>>, + @Assisted savedStateOwner: SavedStateRegistryOwner, + @Assisted defaultSavedState: Bundle?, + @Assisted private val assistAction: ((CWAViewModelFactory<out CWAViewModel>, SavedStateHandle) -> CWAViewModel)? +) : AbstractSavedStateViewModelFactory(savedStateOwner, defaultSavedState) { + + /** + * Called indirectly (lazy) when the viewModel is accessed in a Fragment/Activity + **/ + override fun <T : ViewModel?> create( + key: String, + modelClass: Class<T>, + handle: SavedStateHandle + ): T { + // Find the right factory for our ViewModel + val factory = creators.entries.find { modelClass.isAssignableFrom(it.key) }?.value + if (factory == null) throw IllegalStateException("Unknown ViewModel factory: $modelClass") + + // If an `assistAction` was passed from `cwaViewModels` use that to create the ViewModel + @Suppress("UNCHECKED_CAST") + var vm: T? = assistAction?.invoke(factory, handle) as? T + + // If no `assistAction` was passed, try one of the defaults + // The Fragment or Activity may have used one of them to reduce boilerplate code. + @Suppress("UNCHECKED_CAST") + if (vm == null) { + vm = when (factory) { + is SavedStateCWAViewModelFactory<*> -> factory.create(handle) as? T + is SimpleCWAViewModelFactory<*> -> factory.create() as? T + else -> throw IllegalStateException("Unknown factory: $factory") + } + } + + return vm ?: throw IllegalStateException("$factory didn't return a ViewModel") + } + + /** + * Injected into fragments/activities + * Uses assisted injection to get access to the fragments/activities SavedStateRegistryOwner + */ + @AssistedInject.Factory + interface Factory { + fun create( + savedStateOwner: SavedStateRegistryOwner, + defaultSavedState: Bundle?, + assistAction: ((CWAViewModelFactory<out CWAViewModel>, SavedStateHandle) -> CWAViewModel)? = null + ): CWAViewModelFactoryProvider + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelKey.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelKey.kt new file mode 100644 index 0000000000000000000000000000000000000000..f50cc6ccbcb44c789e5dd55d9f486c57603460b3 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/CWAViewModelKey.kt @@ -0,0 +1,9 @@ +package de.rki.coronawarnapp.util.viewmodel + +import dagger.MapKey +import kotlin.reflect.KClass + +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +@MapKey +internal annotation class CWAViewModelKey(val value: KClass<out CWAViewModel>) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/SavedStateCWAViewModelFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/SavedStateCWAViewModelFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..add9ff8d2412d2d54fa37b00a6ded86c6ce9372f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/SavedStateCWAViewModelFactory.kt @@ -0,0 +1,7 @@ +package de.rki.coronawarnapp.util.viewmodel + +import androidx.lifecycle.SavedStateHandle + +interface SavedStateCWAViewModelFactory<T : CWAViewModel> : CWAViewModelFactory<T> { + fun create(handle: SavedStateHandle): T +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/SimpleCWAViewModelFactory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/SimpleCWAViewModelFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..2998e5edd04a08fb06946934e3e12e3992e428ea --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/SimpleCWAViewModelFactory.kt @@ -0,0 +1,5 @@ +package de.rki.coronawarnapp.util.viewmodel + +interface SimpleCWAViewModelFactory<T : CWAViewModel> : CWAViewModelFactory<T> { + fun create(): T +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/ViewModelLazyKeyed.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/ViewModelLazyKeyed.kt new file mode 100644 index 0000000000000000000000000000000000000000..11ea914bd437aa39d411728545bdc2e9000e825b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/viewmodel/ViewModelLazyKeyed.kt @@ -0,0 +1,184 @@ +package de.rki.coronawarnapp.util.viewmodel + +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import androidx.activity.ComponentActivity +import androidx.annotation.MainThread +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelLazy +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelStore +import androidx.lifecycle.ViewModelStoreOwner +import kotlin.reflect.KClass + +/** + * This is a fork of the standard ViewModel code that allows to optionally provide + * alternative keys for ViewModels, to allow for more freedom when using multiple viewModels. + * Note the `keyProducer` argument. + */ + +/** + * An implementation of [Lazy] used by [androidx.fragment.app.Fragment.viewModels] and + * [androidx.activity.ComponentActivity.viewmodels]. + * + * [storeProducer] is a lambda that will be called during initialization, [VM] will be created + * in the scope of returned [ViewModelStore]. + * + * [factoryProducer] is a lambda that will be called during initialization, + * returned [ViewModelProvider.Factory] will be used for creation of [VM] + */ +class ViewModelLazyKeyed<VM : ViewModel>( + private val viewModelClass: KClass<VM>, + private val keyProducer: (() -> String)? = null, + private val storeProducer: () -> ViewModelStore, + private val factoryProducer: () -> ViewModelProvider.Factory +) : Lazy<VM> { + private var cached: VM? = null + + override val value: VM + get() { + val viewModel = cached + return if (viewModel == null) { + val factory = factoryProducer() + val store = storeProducer() + val key = keyProducer?.invoke() ?: "androidx.lifecycle.ViewModelProvider.DefaultKey" + ViewModelProvider(store, factory).get( + key + ":" + viewModelClass.java.canonicalName, + viewModelClass.java + ).also { + cached = it + } + } else { + viewModel + } + } + + override fun isInitialized() = cached != null +} + +/** + * Returns a property delegate to access [ViewModel] by **default** scoped to this [Fragment]: + * ``` + * class MyFragment : Fragment() { + * val viewmodel: NYViewModel by viewmodels() + * } + * ``` + * + * Custom [ViewModelProvider.Factory] can be defined via [factoryProducer] parameter, + * factory returned by it will be used to create [ViewModel]: + * ``` + * class MyFragment : Fragment() { + * val viewmodel: MYViewModel by viewmodels { myFactory } + * } + * ``` + * + * Default scope may be overridden with parameter [ownerProducer]: + * ``` + * class MyFragment : Fragment() { + * val viewmodel: MYViewModel by viewmodels ({requireParentFragment()}) + * } + * ``` + * + * This property can be accessed only after this Fragment is attached i.e., after + * [Fragment.onAttach()], and access prior to that will result in IllegalArgumentException. + */ +@MainThread +inline fun <reified VM : ViewModel> Fragment.viewModelsKeyed( + noinline keyProducer: (() -> String)? = null, + noinline ownerProducer: () -> ViewModelStoreOwner = { this }, + noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null +) = createViewModelLazyKeyed( + VM::class, + keyProducer, + { ownerProducer().viewModelStore }, + factoryProducer +) + +/** + * Returns a property delegate to access parent activity's [ViewModel], + * if [factoryProducer] is specified then [ViewModelProvider.Factory] + * returned by it will be used to create [ViewModel] first time. + * + * ``` + * class MyFragment : Fragment() { + * val viewmodel: MyViewModel by activityViewModels() + * } + * ``` + * + * This property can be accessed only after this Fragment is attached i.e., after + * [Fragment.onAttach()], and access prior to that will result in IllegalArgumentException. + */ +@MainThread +inline fun <reified VM : ViewModel> Fragment.activityViewModelsKeyed( + noinline keyProducer: (() -> String)? = null, + noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null +) = createViewModelLazyKeyed( + VM::class, + keyProducer, + { requireActivity().viewModelStore }, + factoryProducer +) + +/** + * Helper method for creation of [ViewModelLazy], that resolves `null` passed as [factoryProducer] + * to default factory. + */ +@MainThread +fun <VM : ViewModel> Fragment.createViewModelLazyKeyed( + viewModelClass: KClass<VM>, + keyProducer: (() -> String)? = null, + storeProducer: () -> ViewModelStore, + factoryProducer: (() -> ViewModelProvider.Factory)? = null +): Lazy<VM> { + val factoryPromise = factoryProducer ?: { + val application = activity?.application ?: throw IllegalStateException( + "ViewModel can be accessed only when Fragment is attached" + ) + ViewModelProvider.AndroidViewModelFactory.getInstance(application) + } + return ViewModelLazyKeyed(viewModelClass, keyProducer, storeProducer, factoryPromise) +} + +/** + * Returns a [Lazy] delegate to access the ComponentActivity's ViewModel, if [factoryProducer] + * is specified then [ViewModelProvider.Factory] returned by it will be used + * to create [ViewModel] first time. + * + * ``` + * class MyComponentActivity : ComponentActivity() { + * val viewmodel: MyViewModel by viewmodels() + * } + * ``` + * + * This property can be accessed only after the Activity is attached to the Application, + * and access prior to that will result in IllegalArgumentException. + */ +@MainThread +inline fun <reified VM : ViewModel> ComponentActivity.viewModelsKeyed( + noinline keyProducer: (() -> String)? = null, + noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null +): Lazy<VM> { + val factoryPromise = factoryProducer ?: { + val application = application ?: throw IllegalArgumentException( + "ViewModel can be accessed only when Activity is attached" + ) + ViewModelProvider.AndroidViewModelFactory.getInstance(application) + } + + return ViewModelLazyKeyed(VM::class, keyProducer, { viewModelStore }, factoryPromise) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/VerificationModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/VerificationModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..8bd41f974462a36ff85a6d1d3e3b0560960aa85f --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/VerificationModule.kt @@ -0,0 +1,57 @@ +package de.rki.coronawarnapp.verification + +import android.content.Context +import dagger.Module +import dagger.Provides +import dagger.Reusable +import de.rki.coronawarnapp.environment.verification.VerificationCDNServerUrl +import de.rki.coronawarnapp.http.HttpClientDefault +import de.rki.coronawarnapp.http.RestrictedConnectionSpecs +import de.rki.coronawarnapp.verification.server.VerificationApiV1 +import de.rki.coronawarnapp.verification.server.VerificationHttpClient +import okhttp3.Cache +import okhttp3.ConnectionSpec +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.io.File +import javax.inject.Singleton + +@Module +class VerificationModule { + + @Reusable + @VerificationHttpClient + @Provides + fun cdnHttpClient( + @HttpClientDefault defaultHttpClient: OkHttpClient, + @RestrictedConnectionSpecs connectionSpecs: List<ConnectionSpec> + ): OkHttpClient = + defaultHttpClient.newBuilder().connectionSpecs(connectionSpecs).build() + + @Singleton + @Provides + fun provideVerificationApi( + context: Context, + @VerificationHttpClient client: OkHttpClient, + @VerificationCDNServerUrl url: String, + gsonConverterFactory: GsonConverterFactory + ): VerificationApiV1 { + val cache = Cache(File(context.cacheDir, "http_verification"), DEFAULT_CACHE_SIZE) + + val cachingClient = client.newBuilder().apply { + cache(cache) + }.build() + + return Retrofit.Builder() + .client(cachingClient) + .baseUrl(url) + .addConverterFactory(gsonConverterFactory) + .build() + .create(VerificationApiV1::class.java) + } + + companion object { + private const val DEFAULT_CACHE_SIZE = 5 * 1024 * 1024L // 5MB + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationApiV1.kt new file mode 100644 index 0000000000000000000000000000000000000000..a45f6617de515e732f22c1e769bc37a788d7e301 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationApiV1.kt @@ -0,0 +1,58 @@ +package de.rki.coronawarnapp.verification.server + +import com.google.gson.annotations.SerializedName +import retrofit2.http.Body +import retrofit2.http.Header +import retrofit2.http.POST + +interface VerificationApiV1 { + + data class RegistrationTokenRequest( + @SerializedName("keyType") val keyType: String? = null, + @SerializedName("key") val key: String? = null, + @SerializedName("requestPadding") val requestPadding: String? = null + ) + + data class RegistrationTokenResponse( + @SerializedName("registrationToken") val registrationToken: String + ) + + @POST("version/v1/registrationToken") + suspend fun getRegistrationToken( + @Header("cwa-fake") fake: String, + @Header("cwa-header-padding") headerPadding: String?, + @Body requestBody: RegistrationTokenRequest + ): RegistrationTokenResponse + + data class RegistrationRequest( + @SerializedName("registrationToken") val registrationToken: String? = null, + @SerializedName("requestPadding") val requestPadding: String? = null + ) + + data class TestResultResponse( + @SerializedName("testResult") val testResult: Int + ) + + @POST("version/v1/testresult") + suspend fun getTestResult( + @Header("cwa-fake") fake: String, + @Header("cwa-header-padding") headerPadding: String?, + @Body request: RegistrationRequest + ): TestResultResponse + + data class TanRequestBody( + @SerializedName("registrationToken") val registrationToken: String? = null, + @SerializedName("requestPadding") val requestPadding: String? = null + ) + + data class TanResponse( + @SerializedName("tan") val tan: String + ) + + @POST("version/v1/tan") + suspend fun getTAN( + @Header("cwa-fake") fake: String, + @Header("cwa-header-padding") headerPadding: String?, + @Body requestBody: TanRequestBody + ): TanResponse +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationHttpClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationHttpClient.kt new file mode 100644 index 0000000000000000000000000000000000000000..1c244ae61732a1e8ab53ca6acc6ec5303c5b203b --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationHttpClient.kt @@ -0,0 +1,8 @@ +package de.rki.coronawarnapp.verification.server + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class VerificationHttpClient diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationKeyType.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationKeyType.kt new file mode 100644 index 0000000000000000000000000000000000000000..f8112264c1a6c5491e6c5f0c7483c02044582f38 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationKeyType.kt @@ -0,0 +1,5 @@ +package de.rki.coronawarnapp.verification.server + +enum class VerificationKeyType { + GUID, TELETAN; +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationServer.kt new file mode 100644 index 0000000000000000000000000000000000000000..1411ca60db6ce02dcdbfb997bbe617345ee3b568 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/verification/server/VerificationServer.kt @@ -0,0 +1,100 @@ +package de.rki.coronawarnapp.verification.server + +import dagger.Lazy +import de.rki.coronawarnapp.util.PaddingTool.requestPadding +import de.rki.coronawarnapp.util.security.HashHelper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class VerificationServer @Inject constructor( + private val verificationAPI: Lazy<VerificationApiV1> +) { + + private val api: VerificationApiV1 + get() = verificationAPI.get() + + suspend fun retrieveRegistrationToken( + key: String, + keyType: VerificationKeyType + ): String = withContext(Dispatchers.IO) { + val keyStr = if (keyType == VerificationKeyType.GUID) { + HashHelper.hash256(key) + } else { + key + } + + val paddingLength = when (keyType) { + VerificationKeyType.GUID -> PADDING_LENGTH_BODY_REGISTRATION_TOKEN_GUID + VerificationKeyType.TELETAN -> PADDING_LENGTH_BODY_REGISTRATION_TOKEN_TELETAN + } + + api.getRegistrationToken( + fake = "0", + headerPadding = requestPadding(PADDING_LENGTH_HEADER_REGISTRATION_TOKEN), + requestBody = VerificationApiV1.RegistrationTokenRequest( + keyType = keyType.name, + key = keyStr, + requestPadding = requestPadding(paddingLength) + ) + ).registrationToken + } + + suspend fun retrieveTestResults( + registrationToken: String + ): Int = withContext(Dispatchers.IO) { + api.getTestResult( + fake = "0", + headerPadding = requestPadding(PADDING_LENGTH_HEADER_TEST_RESULT), + request = VerificationApiV1.RegistrationRequest( + registrationToken, + requestPadding(PADDING_LENGTH_BODY_TEST_RESULT) + ) + ).testResult + } + + suspend fun retrieveTan( + registrationToken: String + ): String = withContext(Dispatchers.IO) { + api.getTAN( + fake = "0", + headerPadding = requestPadding(PADDING_LENGTH_HEADER_TAN), + requestBody = VerificationApiV1.TanRequestBody( + registrationToken, + requestPadding(PADDING_LENGTH_BODY_TAN) + ) + ).tan + } + + suspend fun retrieveTanFake() = withContext(Dispatchers.IO) { + api.getTAN( + fake = "1", + headerPadding = requestPadding(PADDING_LENGTH_HEADER_TAN), + requestBody = VerificationApiV1.TanRequestBody( + registrationToken = DUMMY_REGISTRATION_TOKEN, + requestPadding = requestPadding(PADDING_LENGTH_BODY_TAN_FAKE) + ) + ) + } + + companion object { + // padding registration token + private const val VERIFICATION_BODY_FILL = 139 + + const val PADDING_LENGTH_HEADER_REGISTRATION_TOKEN = 0 + const val PADDING_LENGTH_BODY_REGISTRATION_TOKEN_TELETAN = 51 + VERIFICATION_BODY_FILL + const val PADDING_LENGTH_BODY_REGISTRATION_TOKEN_GUID = 0 + VERIFICATION_BODY_FILL + + // padding test result + const val PADDING_LENGTH_HEADER_TEST_RESULT = 7 + const val PADDING_LENGTH_BODY_TEST_RESULT = 31 + VERIFICATION_BODY_FILL + + // padding tan + const val PADDING_LENGTH_HEADER_TAN = 14 + const val PADDING_LENGTH_BODY_TAN = 31 + VERIFICATION_BODY_FILL + const val PADDING_LENGTH_BODY_TAN_FAKE = 31 + VERIFICATION_BODY_FILL + const val DUMMY_REGISTRATION_TOKEN = "11111111-2222-4444-8888-161616161616" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundNoiseOneTimeWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundNoiseOneTimeWorker.kt index 87e9a8c551721e4ac8c1dec420ed2803dd313744..724ac760cf52bd1843702506d759ca4f1616620d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundNoiseOneTimeWorker.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/BackgroundNoiseOneTimeWorker.kt @@ -3,8 +3,8 @@ package de.rki.coronawarnapp.worker import android.content.Context import androidx.work.CoroutineWorker import androidx.work.WorkerParameters -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.http.playbook.PlaybookImpl +import de.rki.coronawarnapp.playbook.Playbook +import de.rki.coronawarnapp.util.di.AppInjector /** * One time background noise worker @@ -17,9 +17,8 @@ class BackgroundNoiseOneTimeWorker( ) : CoroutineWorker(context, workerParams) { - companion object { - private val TAG: String? = BackgroundNoiseOneTimeWorker::class.simpleName - } + private val playbook: Playbook + get() = AppInjector.component.playbook /** * Work execution @@ -30,8 +29,7 @@ class BackgroundNoiseOneTimeWorker( var result = Result.success() try { - PlaybookImpl(WebRequestBuilder.getInstance()) - .dummy() + playbook.dummy() } catch (e: Exception) { // TODO: Should we even retry here? result = if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt index c404b59e4dc9ad722c6d87f9e50fc51a453c48b0..95cf66a25bc91be467412f2b161929af7e1d7594 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalOneTimeWorker.kt @@ -15,10 +15,6 @@ import timber.log.Timber class DiagnosisKeyRetrievalOneTimeWorker(val context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) { - companion object { - private val TAG: String? = DiagnosisKeyRetrievalOneTimeWorker::class.simpleName - } - /** * Work execution * @@ -27,7 +23,7 @@ class DiagnosisKeyRetrievalOneTimeWorker(val context: Context, workerParams: Wor * @see RetrieveDiagnosisKeysTransaction */ override suspend fun doWork(): Result { - Timber.tag(TAG).d("$id: doWork() started. Run attempt: $runAttemptCount") + Timber.d("$id: doWork() started. Run attempt: $runAttemptCount") BackgroundWorkHelper.sendDebugNotification( "KeyOneTime Executing: Start", "KeyOneTime started. Run attempt: $runAttemptCount " @@ -37,12 +33,12 @@ class DiagnosisKeyRetrievalOneTimeWorker(val context: Context, workerParams: Wor try { RetrieveDiagnosisKeysTransaction.startWithConstraints() } catch (e: Exception) { - Timber.tag(TAG).w( + Timber.w( e, "$id: Error during RetrieveDiagnosisKeysTransaction.startWithConstraints()." ) if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) { - Timber.tag(TAG).w(e, "$id: Retry attempts exceeded.") + Timber.w(e, "$id: Retry attempts exceeded.") BackgroundWorkHelper.sendDebugNotification( "KeyOneTime Executing: Failure", @@ -51,7 +47,7 @@ class DiagnosisKeyRetrievalOneTimeWorker(val context: Context, workerParams: Wor return Result.failure() } else { - Timber.tag(TAG).d(e, "$id: Retrying.") + Timber.d(e, "$id: Retrying.") result = Result.retry() } } @@ -60,7 +56,7 @@ class DiagnosisKeyRetrievalOneTimeWorker(val context: Context, workerParams: Wor "KeyOneTime Executing: End", "KeyOneTime result: $result " ) - Timber.tag(TAG).d("$id: doWork() finished with %s", result) + Timber.d("$id: doWork() finished with %s", result) return result } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalPeriodicWorker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalPeriodicWorker.kt index 03417c1999a69c6477206a408485c837ab503f7f..f7baa0f0855e09a3fef92a67d03b125b25452a42 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalPeriodicWorker.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/worker/DiagnosisKeyRetrievalPeriodicWorker.kt @@ -15,10 +15,6 @@ import timber.log.Timber class DiagnosisKeyRetrievalPeriodicWorker(val context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) { - companion object { - private val TAG: String? = DiagnosisKeyRetrievalPeriodicWorker::class.simpleName - } - /** * Work execution * @@ -28,7 +24,7 @@ class DiagnosisKeyRetrievalPeriodicWorker(val context: Context, workerParams: Wo * @see BackgroundWorkScheduler.scheduleDiagnosisKeyOneTimeWork() */ override suspend fun doWork(): Result { - Timber.tag(TAG).d("$id: doWork() started. Run attempt: $runAttemptCount") + Timber.d("$id: doWork() started. Run attempt: $runAttemptCount") BackgroundWorkHelper.sendDebugNotification( "KeyPeriodic Executing: Start", "KeyPeriodic started. Run attempt: $runAttemptCount" @@ -38,12 +34,12 @@ class DiagnosisKeyRetrievalPeriodicWorker(val context: Context, workerParams: Wo try { BackgroundWorkScheduler.scheduleDiagnosisKeyOneTimeWork() } catch (e: Exception) { - Timber.tag(TAG).w( + Timber.w( e, "$id: Error during BackgroundWorkScheduler.scheduleDiagnosisKeyOneTimeWork()." ) if (runAttemptCount > BackgroundConstants.WORKER_RETRY_COUNT_THRESHOLD) { - Timber.tag(TAG).w(e, "$id: Retry attempts exceeded.") + Timber.w(e, "$id: Retry attempts exceeded.") BackgroundWorkHelper.sendDebugNotification( "KeyPeriodic Executing: Failure", @@ -52,7 +48,7 @@ class DiagnosisKeyRetrievalPeriodicWorker(val context: Context, workerParams: Wo return Result.failure() } else { - Timber.tag(TAG).d(e, "$id: Retrying.") + Timber.d(e, "$id: Retrying.") result = Result.retry() } } @@ -61,7 +57,7 @@ class DiagnosisKeyRetrievalPeriodicWorker(val context: Context, workerParams: Wo "KeyPeriodic Executing: End", "KeyPeriodic result: $result " ) - Timber.tag(TAG).d("$id: doWork() finished with %s", result) + Timber.d("$id: doWork() finished with %s", result) return result } } diff --git a/Corona-Warn-App/src/main/res/color/calendar_header.xml b/Corona-Warn-App/src/main/res/color/calendar_header.xml new file mode 100644 index 0000000000000000000000000000000000000000..727593c505031885cbff514ce8ff43b1c55a430a --- /dev/null +++ b/Corona-Warn-App/src/main/res/color/calendar_header.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true" android:color="@color/colorTextEmphasizedButton"/> + <item android:color="@color/colorTextPrimary1"/> +</selector> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_header_background.xml b/Corona-Warn-App/src/main/res/drawable/calendar_header_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..50e670c9803c7983d2edb9f1a72d94970c76ad7d --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/calendar_header_background.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/calendar_header_background_focus_on" android:state_selected="true" /> + <item android:drawable="@drawable/calendar_header_background_focus_off" /> +</selector> diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_off.xml b/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_off.xml new file mode 100644 index 0000000000000000000000000000000000000000..c147a5441c7c653875066a2975624234f89f59c1 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_off.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:radius="@dimen/calendar_header_initial_radius" + android:bottomLeftRadius="@dimen/calendar_header_bottom_radius" + android:bottomRightRadius="@dimen/calendar_header_bottom_radius" + android:topLeftRadius="@dimen/calendar_header_top_radius" + android:topRightRadius="@dimen/calendar_header_top_radius" /> + <solid android:color="@color/colorSurface2" /> +</shape> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_on.xml b/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_on.xml new file mode 100644 index 0000000000000000000000000000000000000000..9eebae7774300955c275ad819b2f61d40c548160 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/calendar_header_background_focus_on.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners + android:radius="@dimen/calendar_header_initial_radius" + android:bottomLeftRadius="@dimen/calendar_header_bottom_radius" + android:bottomRightRadius="@dimen/calendar_header_bottom_radius" + android:topLeftRadius="@dimen/calendar_header_top_radius" + android:topRightRadius="@dimen/calendar_header_top_radius" /> + <solid android:color="@color/colorCalendarLayoutFocusOn" /> +</shape> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_layout_background.xml b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..806443454d9218c4a8b8634703edd42d45767652 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/calendar_layout_background_focus_on" android:state_selected="true" /> + <item android:drawable="@drawable/calendar_layout_background_focus_off" /> +</selector> diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_off.xml b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_off.xml new file mode 100644 index 0000000000000000000000000000000000000000..10c1626fc85807bc3080af27a816cfbf9424fb67 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_off.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners android:radius="@dimen/radius_card" /> + <stroke + android:width="@dimen/calendar_layout_stroke" + android:color="@color/colorSurface2" /> +</shape> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_on.xml b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_on.xml new file mode 100644 index 0000000000000000000000000000000000000000..39ecfa7c0532579cd21e7f158b1693e377ef0c57 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/calendar_layout_background_focus_on.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners android:radius="@dimen/radius_card" /> + <stroke + android:width="@dimen/calendar_layout_stroke" + android:color="@color/colorCalendarLayoutFocusOn" /> +</shape> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_selected_day_back.xml b/Corona-Warn-App/src/main/res/drawable/calendar_selected_day_back.xml new file mode 100644 index 0000000000000000000000000000000000000000..a76b8d017908dd7a02e2c7fcb3dce47f87d76ec7 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/calendar_selected_day_back.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid android:color="@color/colorCalendarSelectedDayBackground" /> +</shape> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/calendar_today_back.xml b/Corona-Warn-App/src/main/res/drawable/calendar_today_back.xml new file mode 100644 index 0000000000000000000000000000000000000000..874c81cd881e26340720b8352be966257dbda8f8 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/calendar_today_back.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid android:color="@android:color/transparent" /> + <stroke + android:width="1dp" + android:color="@color/colorCalendarTodayBorder" /> +</shape> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_at.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_at.xml new file mode 100644 index 0000000000000000000000000000000000000000..028f4bce528ca468d128f9afe097f065a8a2ec8c --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_at.xml @@ -0,0 +1,22 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.4545l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_be.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_be.xml new file mode 100644 index 0000000000000000000000000000000000000000..58e34fc7783cfd92b9efc76e3fb9ca75c1f9c4e6 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_be.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M8.1818,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#FFC107" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M15.8182,0l8.1818,0l0,16l-8.1818,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M-0,0l8.1818,0l0,16l-8.1818,0z" + android:strokeWidth="1" + android:fillColor="#424242" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_bg.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_bg.xml new file mode 100644 index 0000000000000000000000000000000000000000..c6e11f13d9a73afb9a46b2af1fe5e9e2b1ffc5c6 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_bg.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,10.6667l24,0l0,5.3333l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.3333l24,0l0,5.3333l-24,0z" + android:strokeWidth="1" + android:fillColor="#43A047" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,-0l24,0l0,5.3333l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_ch.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_ch.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a3ac8aac8d33378c6e98ad263e034787cda35f2 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_ch.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="16dp" + android:viewportWidth="16" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h16v16h-16z"/> + <path + android:pathData="M0,0l16,0l0,16l-16,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.3636,3.2727l3.2727,0l0,9.8182l-3.2727,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.0909,6.5455l9.8182,0l0,3.2727l-9.8182,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_cy.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_cy.xml new file mode 100644 index 0000000000000000000000000000000000000000..2541d70822e21b1b0cd55cd4d863ec1308aa98b5 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_cy.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l23.9776,0l0,16l-23.9776,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M19.6372,2C19.4938,2.0284 19.2679,2.0987 19.161,2.1538C19.0928,2.1887 19.1207,2.2531 19.0187,2.2831C18.8943,2.3202 18.7939,2.3164 18.6794,2.3507C18.333,2.4538 18.1574,2.6862 17.8628,2.8373C17.6359,2.9535 17.3288,2.912 17.1936,2.9889C17.0032,3.0969 16.8723,3.2873 16.6661,3.3991C16.4048,3.5409 16.1599,3.6751 15.8763,3.7711C15.5768,3.8725 15.3232,3.9347 15.0167,3.9565C14.6659,3.9811 14.4652,4.2233 14.1396,4.2985C14.1074,4.1802 13.3056,4.3967 13.1545,4.4136C12.7514,4.4595 12.3347,4.406 11.9539,4.3607C11.6185,4.3209 11.2525,4.2445 10.9165,4.2549C10.7316,4.2609 10.6121,4.2827 10.4256,4.2211C10.2292,4.1562 10.0388,4.0067 9.8294,3.9533C9.9216,4.4071 10.0148,4.8762 9.813,5.342C9.5479,5.9556 9.1503,5.6671 8.7036,5.5149C8.3523,5.3955 8.1527,5.4358 7.8538,5.5547C7.8227,5.5673 7.7507,5.5667 7.7338,5.5738C7.6476,5.612 7.6972,5.5902 7.605,5.6704C7.4147,5.8362 7.3803,6.0855 7.1883,6.2551C6.9538,6.4624 6.7018,6.5087 6.4312,6.3495C6.2398,6.2365 6.0668,5.8716 6.0047,6.2322C5.9676,6.4487 6.1623,6.5595 6.219,6.7509C6.2474,6.8469 6.1972,6.9713 6.2092,7.0204C6.231,7.1093 6.2938,7.2135 6.3227,7.3002C6.3456,7.37 6.291,7.3995 6.3325,7.5004C6.3788,7.6133 6.4879,7.6493 6.5403,7.7093C6.6685,7.856 6.6914,7.91 6.7563,8.144C6.8141,8.3507 6.8288,8.3704 7.011,8.4876C7.0852,8.5351 7.1845,8.624 7.2745,8.6671C7.3656,8.7107 7.359,8.6502 7.4474,8.6742C7.8118,8.7735 8.1968,9.0909 8.5918,9.0909C8.7963,9.0909 8.943,9.0145 9.111,8.9785C9.3461,8.9284 9.5392,8.9551 9.7487,9.0587C9.7612,9.2278 10.0399,9.4444 9.9314,9.6369C10.0612,9.6222 10.1741,9.6031 10.2974,9.5971C10.5887,9.5829 10.4556,9.7067 10.3912,9.4509C10.2941,9.0647 10.5396,8.8656 10.9083,8.7331C11.3256,8.5831 11.7919,8.7096 12.1607,8.6098C12.5108,8.5149 12.9118,8.3202 13.2385,8.1805C13.3607,8.1282 13.4512,7.9776 13.5799,7.9405C13.749,7.892 13.7801,7.9591 13.8952,7.874C13.953,7.8315 14.0408,7.6465 14.061,7.5838C14.1292,7.37 14.0152,7.1442 14.2296,6.9762C14.3659,6.8687 14.5547,6.8802 14.7216,6.8867C14.8285,6.8911 14.9507,6.8835 15.0527,6.9233C15.1356,6.956 15.2228,7.0831 15.2932,7.0984C15.4688,7.136 15.4825,7.0264 15.6156,6.9582C15.8905,6.8175 16.1485,6.7264 16.4332,6.8098C16.5718,6.8507 16.6748,6.9707 16.7359,6.8693C16.7354,6.8704 16.5385,6.5104 16.4665,6.4269C16.3154,6.2518 16.1185,6.2098 15.9723,6.0271C15.8741,5.9038 15.741,5.6458 15.5796,5.6191C15.6843,5.5504 15.5948,5.3404 15.6134,5.2013C15.6363,5.03 15.7492,4.7693 15.8883,4.6558C16.0754,4.5031 16.173,4.6313 16.3776,4.5822C16.5958,4.5298 16.5439,4.4556 16.6498,4.2789C16.9339,3.8049 17.4919,3.7438 17.9087,3.4553C18.0958,3.326 18.3548,3.1509 18.5196,3.0004C18.6521,2.8793 18.6565,2.7522 18.8218,2.6431C18.9881,2.5329 19.3956,2.4789 19.5101,2.3551C19.5848,2.2733 19.5668,2.0878 19.6372,2Z" + android:strokeWidth="1" + android:fillColor="#F57F17" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.4172,12.8464C11.4085,12.8524 11.2083,12.992 10.917,12.992L10.917,12.9925L10.9165,12.992C10.7245,12.992 10.5423,12.9271 10.3803,12.8311C10.5892,12.4809 11.1548,12.7133 11.4172,12.8464ZM9.9925,12.5616C9.9734,12.7973 10.1578,12.7973 10.1578,12.7973C10.2194,12.7973 10.2194,12.5584 9.9925,12.5616ZM11.5181,12.632L11.5181,12.632L11.5181,12.632C11.3523,12.2905 11.1412,11.9011 10.6978,11.9524L10.6972,11.9524C10.6748,12.3876 11.1516,12.5758 11.5181,12.632ZM10.5592,12.5327L10.5592,12.5327C10.6623,12.5327 10.7676,12.5224 10.8701,12.5082C10.6601,12.2944 10.3007,12.0936 9.9919,12.2453C10.0154,12.4885 10.3748,12.5327 10.5592,12.5327ZM8.9114,12.2305C9.0816,12.4095 9.3467,12.4929 9.5921,12.4929L9.5921,12.4935C9.8174,12.5104 9.891,12.4258 9.7481,12.2676C9.5779,12.0789 9.1132,12.1793 8.9114,12.2305ZM8.805,11.9049C8.7952,11.9731 8.8165,12.1176 8.9092,12.1176L8.9092,12.1176C8.991,12.0805 8.9256,11.8438 8.805,11.9049ZM10.4861,12.0795L10.4861,12.0795C10.5881,12.0205 10.5063,11.7675 10.353,11.8362C10.347,11.9224 10.3421,12.0205 10.4861,12.0795ZM8.8263,11.5673L8.8263,11.5673C8.9016,11.9316 9.4083,12.0336 9.7181,12.0451L9.7181,12.0451C9.4678,11.732 9.1754,11.4827 8.8263,11.5673ZM10.1785,11.9998L10.1785,11.9998L10.1785,11.9998C10.0852,11.7009 9.7863,11.2885 9.4018,11.4135C9.4874,11.7462 9.8561,11.9475 10.1785,11.9998ZM7.7888,11.5056C7.7588,11.7718 8.2667,11.8247 8.4276,11.8247L8.4276,11.8247C8.5383,11.8247 8.6479,11.8116 8.7543,11.7838C8.5399,11.4778 8.1368,11.4129 7.7888,11.5056ZM9.219,11.5165L9.219,11.5165C9.2976,11.4233 9.2392,11.2051 9.0859,11.2744C9.0521,11.4233 9.219,11.5165 9.219,11.5165ZM7.947,10.7349C7.7714,10.9373 8.4778,11.3911 8.6239,11.4287C8.5754,11.3125 8.1647,10.4851 7.947,10.7349ZM9.0139,11.414C8.9419,11.1658 8.7172,10.4175 8.3076,10.5653C8.4336,10.8876 8.6736,11.2662 9.0128,11.414C9.0128,11.414 9.0134,11.414 9.0139,11.414ZM7.803,11.1669C7.7927,11.2885 7.8854,11.3916 8.0054,11.3824C8.2536,11.3633 7.9858,11.1178 7.803,11.1669ZM7.8456,10.9885C7.833,10.6678 7.4032,10.5838 7.1534,10.574C7.1932,10.9062 7.3956,10.994 7.7179,10.994L7.7179,10.994C7.7605,10.9935 7.803,10.9918 7.8456,10.9885ZM8.0905,10.5953L8.0905,10.5953C8.1118,10.3449 8.1887,9.9718 7.887,9.854L7.8865,9.854C7.9219,10.1289 7.9132,10.3635 8.0905,10.5953L8.0905,10.5953ZM7.8123,10.5745C7.8123,10.5745 7.8854,10.5865 7.8854,10.4671C7.8854,10.3476 7.5783,9.6304 7.0923,9.6364C7.0868,9.9893 7.3405,10.5745 7.8123,10.5745ZM12.5845,12.8464C12.5932,12.8524 12.7934,12.992 13.0847,12.992L13.0847,12.9925L13.0852,12.992C13.2772,12.992 13.4594,12.9271 13.6214,12.8311C13.4125,12.4809 12.8468,12.7133 12.5845,12.8464ZM13.8439,12.7973C13.8439,12.7973 14.0283,12.7973 14.0092,12.5616C13.7823,12.5584 13.7823,12.7973 13.8439,12.7973ZM12.4836,12.632C12.8501,12.5758 13.3263,12.3876 13.3039,11.9524L13.3034,11.9524C12.861,11.9011 12.6494,12.29 12.4836,12.632L12.4836,12.632L12.4836,12.632ZM13.1316,12.5082C13.2341,12.5224 13.3388,12.5322 13.4425,12.5322L13.4425,12.5322C13.6268,12.5322 13.9868,12.4885 14.0098,12.2453C13.701,12.0936 13.3416,12.2944 13.1316,12.5082ZM14.2536,12.2676C14.1107,12.4258 14.1843,12.5104 14.4096,12.4935L14.4096,12.4929C14.655,12.4929 14.9201,12.4095 15.0903,12.2305C14.8885,12.1793 14.4238,12.0789 14.2536,12.2676ZM15.0919,12.1176L15.0919,12.1176C15.1852,12.1176 15.2065,11.9731 15.1961,11.9049C15.0761,11.8438 15.0107,12.0805 15.0919,12.1176ZM13.5156,12.0795C13.6596,12.0205 13.6547,11.9218 13.6487,11.8362C13.4954,11.7675 13.4136,12.0205 13.5156,12.0795L13.5156,12.0795ZM14.2836,12.0456L14.2836,12.0456C14.5934,12.0342 15.1001,11.9322 15.1759,11.5678L15.1754,11.5678C14.8263,11.4827 14.5339,11.732 14.2836,12.0456ZM14.5999,11.4135C14.2154,11.2885 13.9159,11.7009 13.8232,11.9993L13.8232,11.9993L13.8232,11.9993C14.1456,11.9475 14.5143,11.7462 14.5999,11.4135ZM15.2474,11.7833C15.3538,11.8111 15.4639,11.8242 15.5741,11.8242L15.5741,11.8242C15.735,11.8242 16.2434,11.7718 16.2128,11.5051C15.8648,11.4129 15.4618,11.4778 15.2474,11.7833ZM14.7827,11.5165C14.7827,11.5165 14.9496,11.4233 14.9158,11.2744C14.7619,11.2051 14.7036,11.4233 14.7827,11.5165L14.7827,11.5165ZM16.0547,10.7349C15.8376,10.4851 15.4263,11.3125 15.3778,11.4287C15.5234,11.3911 16.2303,10.9373 16.0547,10.7349ZM14.9878,11.414C14.9883,11.414 14.9883,11.414 14.9888,11.4135C15.3281,11.2656 15.5681,10.8871 15.6941,10.5647C15.285,10.4175 15.0598,11.1658 14.9878,11.414ZM15.9963,11.3824C16.1163,11.3916 16.209,11.2885 16.1987,11.1669C16.0159,11.1178 15.7481,11.3633 15.9963,11.3824ZM16.1561,10.9885C16.1987,10.9924 16.2412,10.994 16.2843,10.994L16.2843,10.994C16.6061,10.994 16.8085,10.9062 16.8488,10.574C16.5985,10.5838 16.1687,10.6678 16.1561,10.9885ZM15.9112,10.5953L15.9112,10.5953C16.0879,10.3635 16.0792,10.1289 16.1152,9.854L16.1147,9.854C15.8136,9.9718 15.8905,10.3449 15.9112,10.5953L15.9112,10.5953ZM16.1894,10.5745C16.6612,10.5745 16.9148,9.9893 16.9094,9.6364C16.4234,9.6304 16.1163,10.3476 16.1163,10.4671C16.1163,10.5865 16.1894,10.5745 16.1894,10.5745ZM12.1907,12.9064L12.3788,12.8305C12.2987,12.6762 12.1143,12.7509 12.0167,12.8611L12.0008,12.8649L12.0008,12.866L11.9845,12.8622C11.8868,12.752 11.703,12.6778 11.6228,12.8322L11.811,12.9075L11.8083,12.908L11.4216,13.2124C11.4903,13.2735 11.571,13.3351 11.6479,13.4545L11.6485,13.4545C11.7914,13.3815 11.9065,13.1436 12.0008,13.0024L12.0008,13.0018C12.0958,13.1431 12.2103,13.3809 12.3538,13.4545L12.3543,13.4545C12.4312,13.3351 12.5119,13.2735 12.5807,13.2124L12.1939,12.9075L12.1907,12.9064Z" + android:strokeWidth="1" + android:fillColor="#33691E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_cz.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_cz.xml new file mode 100644 index 0000000000000000000000000000000000000000..758f5fbc4f772ee9c57004ff37be8d3d58f1d97b --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_cz.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,8l24,0l0,8l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0l24,0l0,8l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0l0,16l12.5455,-7.9989z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_de.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_de.xml new file mode 100644 index 0000000000000000000000000000000000000000..d47f4299d446e9529719e292eaf6730d2f839b41 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_de.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,10.6667l24,0l0,5.3333l-24,0z" + android:strokeWidth="1" + android:fillColor="#FFC107" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.3333l24,0l0,5.3333l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,-0l24,0l0,5.3333l-24,0z" + android:strokeWidth="1" + android:fillColor="#424242" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_dk.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_dk.xml new file mode 100644 index 0000000000000000000000000000000000000000..a1ea40b27066e5fdb6e0e0493e18d1822aac4b7e --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_dk.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,6.5455l24,0l0,3.2727l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6364,0l3.2727,0l0,16.3636l-3.2727,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_ee.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_ee.xml new file mode 100644 index 0000000000000000000000000000000000000000..d6bfddc90a2927f30fde5c115a794408f7dc3366 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_ee.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,10.9091l24,0l0,5l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.4545l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:fillColor="#424242" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:fillColor="#2196F3" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_es.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_es.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd4a1ae813fbcd7151baea4e1f0f1e70e7ccf55b --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_es.xml @@ -0,0 +1,3412 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#DD2C00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,4.2667l24,0l0,7.4667l-24,0z" + android:strokeWidth="1" + android:fillColor="#FFC107" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1493,7.0603C4.1493,7.0603 4.1317,7.0603 4.1227,7.0555C4.1131,7.0496 4.0853,7.0219 4.0853,7.0219L4.0613,7.0064L4.0405,6.9781C4.0405,6.9781 4.0165,6.9387 4.0267,6.9061C4.0379,6.8768 4.0565,6.8656 4.0752,6.856C4.0912,6.8453 4.1285,6.8352 4.1285,6.8352C4.1285,6.8352 4.1563,6.8229 4.1659,6.8197C4.1749,6.8197 4.2096,6.8101 4.2096,6.8101C4.2096,6.8101 4.2192,6.8053 4.2283,6.8027C4.2384,6.7973 4.2517,6.7973 4.2597,6.7941C4.2672,6.7941 4.2869,6.7888 4.2976,6.7877C4.3163,6.7867 4.344,6.7899 4.3536,6.7899C4.3627,6.7899 4.3957,6.7925 4.4096,6.7925C4.4219,6.7925 4.4693,6.7899 4.4837,6.7899C4.4971,6.7899 4.5061,6.7867 4.5221,6.7899C4.5376,6.7899 4.5632,6.7995 4.5723,6.8021C4.5787,6.8064 4.6251,6.8219 4.6421,6.8272C4.6597,6.8315 4.7013,6.8395 4.7205,6.8501C4.7397,6.8576 4.7509,6.8741 4.7605,6.8875C4.7707,6.8997 4.7723,6.9147 4.7755,6.9216C4.7792,6.9312 4.7797,6.952 4.7755,6.9589C4.7717,6.9685 4.7595,6.9883 4.7595,6.9883L4.7371,7.0208L4.7104,7.0427C4.7104,7.0427 4.6907,7.0613 4.6763,7.0592C4.6608,7.056 4.5061,7.0299 4.4059,7.0299C4.3072,7.0315 4.1488,7.0603 4.1493,7.0603" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6784,7.0656C4.6784,7.0656 4.6773,7.0656 4.6757,7.0656C4.6731,7.0656 4.6661,7.0645 4.6539,7.0613C4.6037,7.0528 4.4875,7.0352 4.4064,7.0352C4.3125,7.0352 4.16,7.0635 4.1504,7.0656C4.1504,7.0656 4.1499,7.0656 4.1493,7.0656L4.1493,7.0656C4.1488,7.0656 4.1483,7.0656 4.1483,7.0656C4.1429,7.0656 4.1291,7.0656 4.12,7.0571C4.1104,7.0528 4.0821,7.0277 4.0821,7.0267L4.0587,7.0085C4.0581,7.0085 4.0576,7.0075 4.0571,7.0075L4.0368,6.9797C4.0352,6.9781 4.0101,6.9387 4.0224,6.9056C4.0347,6.8736 4.0539,6.8624 4.0725,6.8528C4.0901,6.8427 4.1253,6.832 4.1269,6.832C4.128,6.8309 4.1563,6.8187 4.1664,6.8171C4.1744,6.8155 4.2037,6.8069 4.2091,6.8059C4.2107,6.8053 4.2192,6.8016 4.2283,6.7963C4.2352,6.7941 4.2416,6.7941 4.2485,6.7931C4.2533,6.7925 4.2571,6.7925 4.2597,6.7915C4.2608,6.7899 4.2635,6.7899 4.2667,6.7899C4.2757,6.7867 4.2891,6.7813 4.2981,6.7813C4.3104,6.7813 4.3259,6.7813 4.3376,6.7835C4.3445,6.7845 4.3509,6.7856 4.3541,6.7856C4.3584,6.7856 4.3675,6.7861 4.3781,6.7867C4.3893,6.7877 4.4021,6.7888 4.4107,6.7888C4.4171,6.7888 4.4325,6.7867 4.4469,6.7856C4.4629,6.7835 4.4773,6.7824 4.4848,6.7824C4.4885,6.7824 4.4928,6.7824 4.4971,6.7813C4.5056,6.7813 4.5136,6.7813 4.5232,6.7824C4.5387,6.7856 4.5669,6.7936 4.5739,6.7989C4.5824,6.8021 4.6267,6.8176 4.6448,6.824C4.6507,6.8272 4.6592,6.8272 4.6693,6.8304C4.6885,6.8336 4.7109,6.84 4.7232,6.8437C4.7445,6.8549 4.7568,6.8709 4.7653,6.8832C4.7733,6.8939 4.776,6.9035 4.7781,6.9125C4.7792,6.9147 4.7792,6.9179 4.7808,6.9189C4.7851,6.9301 4.7851,6.9525 4.7808,6.9616C4.776,6.9691 4.7627,6.9899 4.7627,6.9899L4.7408,7.024C4.7408,7.0251 4.7408,7.0261 4.7408,7.0261L4.7131,7.0459C4.7125,7.048 4.6955,7.0656 4.6784,7.0656L4.6784,7.0656ZM4.4064,7.0283C4.4875,7.0283 4.6059,7.0448 4.656,7.0533C4.6667,7.0549 4.6747,7.0565 4.6773,7.0565C4.6784,7.0565 4.6784,7.0565 4.6784,7.0565C4.6896,7.0565 4.7035,7.0453 4.7077,7.0411L4.7344,7.0203L4.7552,6.9861C4.7557,6.9861 4.7685,6.968 4.7723,6.9579C4.7749,6.9525 4.7749,6.9328 4.7723,6.9253C4.7712,6.9211 4.7696,6.9189 4.7691,6.9157C4.7664,6.9072 4.7632,6.8981 4.7573,6.8907C4.7483,6.8784 4.7381,6.8645 4.7195,6.8549C4.7072,6.8491 4.6853,6.8437 4.6667,6.8411C4.6571,6.8379 4.648,6.8347 4.6416,6.8325C4.6256,6.8283 4.5792,6.8117 4.5696,6.8075C4.5632,6.8032 4.536,6.7952 4.5221,6.7941C4.5131,6.7925 4.5051,6.7936 4.4971,6.7936C4.4928,6.7936 4.488,6.7941 4.4843,6.7941C4.4773,6.7941 4.4619,6.7952 4.4469,6.7952C4.4315,6.7952 4.4165,6.7963 4.4101,6.7963C4.4016,6.7963 4.3888,6.7952 4.3771,6.7952C4.3669,6.7952 4.3579,6.7952 4.3536,6.7952C4.3504,6.7952 4.344,6.7952 4.3355,6.7941C4.3243,6.7936 4.3099,6.7909 4.2976,6.7925C4.2907,6.7925 4.2773,6.7952 4.2688,6.7984C4.2661,6.8 4.2624,6.8005 4.2603,6.8016C4.2571,6.8027 4.2533,6.8037 4.2496,6.8037C4.2432,6.8037 4.2357,6.8037 4.2309,6.8069C4.2219,6.8091 4.2123,6.8165 4.2123,6.8165C4.2123,6.8165 4.2117,6.8165 4.2112,6.8165C4.2096,6.8165 4.176,6.8251 4.1664,6.8277C4.1595,6.8288 4.1376,6.8373 4.1291,6.8411C4.1285,6.8411 4.0939,6.8523 4.0757,6.8597C4.0565,6.8704 4.0405,6.8811 4.0309,6.9077C4.0197,6.9371 4.0432,6.9755 4.0432,6.9755L4.0635,7.0037L4.0859,7.0192C4.0939,7.0288 4.1157,7.0464 4.1237,7.0533C4.1307,7.056 4.1419,7.0565 4.1477,7.0565C4.1541,7.0555 4.3088,7.0283 4.4064,7.0283Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.3621,6.8395C4.3621,6.792 4.3824,6.7531 4.4085,6.7531C4.4347,6.7531 4.4549,6.792 4.4549,6.8395C4.4549,6.8843 4.4347,6.9227 4.4085,6.9227C4.3824,6.9227 4.3621,6.8843 4.3621,6.8395" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4085,6.928C4.3792,6.928 4.3568,6.8896 4.3568,6.8395C4.3568,6.7904 4.3792,6.7499 4.4085,6.7499C4.4379,6.7499 4.4597,6.7904 4.4597,6.8395C4.4597,6.8896 4.4379,6.928 4.4085,6.928ZM4.4085,6.7573C4.3851,6.7573 4.3659,6.7947 4.3659,6.8395C4.3659,6.8821 4.3845,6.9184 4.4085,6.9184C4.4315,6.9184 4.4501,6.8821 4.4501,6.8395C4.4501,6.7947 4.4315,6.7573 4.4085,6.7573Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.3877,6.8395C4.3877,6.7947 4.3973,6.7605 4.4101,6.7605C4.4219,6.7605 4.4315,6.7947 4.4315,6.8395C4.4315,6.8811 4.4219,6.9157 4.4101,6.9157C4.3973,6.9157 4.3877,6.8811 4.3877,6.8395" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4101,6.92C4.3925,6.92 4.384,6.88 4.384,6.84C4.384,6.7973 4.3925,6.7568 4.4101,6.7568C4.4272,6.7568 4.4352,6.7995 4.4352,6.84C4.4347,6.8795 4.4256,6.92 4.4101,6.92ZM4.4101,6.7659C4.4037,6.7659 4.392,6.7909 4.392,6.84C4.392,6.8859 4.4037,6.9125 4.4101,6.9125C4.4155,6.9125 4.4261,6.8859 4.4261,6.84C4.4256,6.7904 4.4155,6.7659 4.4101,6.7659Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.3787,6.7499C4.3787,6.7323 4.3909,6.7195 4.4101,6.7195C4.4261,6.7195 4.4416,6.7317 4.4416,6.7499C4.4416,6.7653 4.4261,6.7781 4.4101,6.7781C4.3909,6.7781 4.3787,6.7659 4.3787,6.7499" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4315,6.7408l0,0.0165l-0.0491,0l0,-0.0165l0.016,0l0,-0.0459l-0.0208,0l0,-0.0187l0.0208,0l0,-0.0203l0.0208,0l0,0.0197l0.0213,0l0,0.0187l-0.0213,0l0,0.0459l0.0123,0" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4357,6.7648L4.3776,6.7648L4.3776,6.7323L4.3936,6.7323L4.3936,6.6997L4.3717,6.6997L4.3717,6.6693L4.3936,6.6693L4.3936,6.6517L4.424,6.6517L4.424,6.6693L4.4443,6.6693L4.4443,6.6997L4.424,6.6997L4.424,6.7323L4.4352,6.7323L4.4352,6.7648L4.4357,6.7648ZM4.3877,6.7531L4.4251,6.7531L4.4251,6.7435L4.4139,6.7435L4.4139,6.6901L4.4352,6.6901L4.4352,6.68L4.4139,6.68L4.4139,6.6597L4.4037,6.6597L4.4037,6.68L4.3824,6.68L4.3824,6.6901L4.4037,6.6901L4.4037,6.7435L4.3877,6.7435L4.3877,6.7531Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4528,6.7408l0,0.0165l-0.0864,0l0,-0.0165l0.032,0l0,-0.0459l-0.0208,0l0,-0.0187l0.0208,0l0,-0.0203l0.0208,0l0,0.0197l0.0213,0l0,0.0187l-0.0213,0l0,0.0459l0.0336,0" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4571,6.7648L4.3621,6.7648L4.3621,6.7323L4.3941,6.7323L4.3941,6.6997L4.3723,6.6997L4.3723,6.6693L4.3941,6.6693L4.3941,6.6517L4.4245,6.6517L4.4245,6.6693L4.4448,6.6693L4.4448,6.6997L4.4245,6.6997L4.4245,6.7323L4.4576,6.7323L4.4576,6.7648L4.4571,6.7648ZM4.3723,6.7531L4.4475,6.7531L4.4475,6.7435L4.4139,6.7435L4.4139,6.6901L4.4352,6.6901L4.4352,6.68L4.4139,6.68L4.4139,6.6597L4.4037,6.6597L4.4037,6.68L4.3824,6.68L4.3824,6.6901L4.4037,6.6901L4.4037,6.7435L4.3723,6.7435L4.3723,6.7531Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4101,6.7824C4.3893,6.7824 4.3733,6.7685 4.3733,6.7499C4.3733,6.7323 4.3851,6.7195 4.4005,6.7157L4.4021,6.7264C4.3915,6.7285 4.3819,6.7387 4.3819,6.7504C4.3819,6.7648 4.3941,6.7755 4.4101,6.7755C4.424,6.7755 4.4357,6.7648 4.4357,6.7504C4.4357,6.7397 4.4288,6.7285 4.4165,6.7264L4.4192,6.7173C4.4352,6.72 4.4443,6.7333 4.4443,6.7504C4.4443,6.768 4.4288,6.7824 4.4101,6.7824Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4101,7.0555L4.2475,7.0555L4.2432,7.0155L4.2347,6.9739L4.2267,6.9205C4.1813,6.8635 4.1408,6.8235 4.1269,6.832C4.1301,6.8197 4.1344,6.8133 4.1429,6.8069C4.1819,6.7829 4.2651,6.8405 4.3264,6.9328C4.3312,6.9429 4.3376,6.9525 4.3419,6.9589L4.4757,6.9589C4.4805,6.9525 4.4864,6.9435 4.4917,6.9328C4.5531,6.84 4.6357,6.7829 4.6747,6.8069C4.6843,6.8133 4.6875,6.8192 4.6912,6.832C4.6779,6.8235 4.6368,6.8635 4.5909,6.9205L4.584,6.9739L4.5749,7.0155L4.5712,7.0555L4.4101,7.0555" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5765,7.0581L4.2427,7.0581L4.2379,7.0155L4.2315,6.9749L4.2224,6.9227C4.1765,6.8635 4.144,6.8352 4.1317,6.8352C4.1312,6.8352 4.1301,6.8352 4.1291,6.8352L4.1189,6.8421L4.1221,6.8309C4.1259,6.8187 4.1312,6.8091 4.1408,6.8043C4.1472,6.8005 4.1552,6.7973 4.1632,6.7973C4.2091,6.7973 4.2779,6.8528 4.3301,6.9317C4.336,6.9403 4.3408,6.9483 4.344,6.9557L4.4741,6.9557C4.4784,6.9483 4.4827,6.9403 4.488,6.9317C4.5408,6.8528 4.6096,6.7973 4.6549,6.7973C4.6635,6.7973 4.6725,6.8005 4.6784,6.8043C4.6875,6.8091 4.6923,6.8181 4.6965,6.8309L4.7003,6.8421L4.6901,6.8352C4.6896,6.8352 4.688,6.8352 4.688,6.8352C4.6757,6.8352 4.6432,6.8635 4.5968,6.9237L4.5877,6.9744L4.5813,7.0155L4.5765,7.0581ZM4.2501,7.0523L4.5691,7.0523L4.5723,7.016L4.5792,6.9723L4.5877,6.9189C4.6043,6.8981 4.6576,6.8309 4.6848,6.8283C4.6827,6.8197 4.6789,6.816 4.6736,6.8123C4.6688,6.8075 4.6624,6.8075 4.6544,6.8075C4.6123,6.8075 4.5467,6.8608 4.496,6.9376C4.4896,6.9461 4.4848,6.9547 4.4805,6.9627L4.4784,6.9659L4.3397,6.9659L4.3376,6.9627C4.3344,6.9547 4.3291,6.9461 4.3221,6.9376C4.272,6.8603 4.2059,6.8075 4.1632,6.8075C4.1557,6.8075 4.1499,6.8075 4.1445,6.8123C4.1392,6.816 4.1355,6.8203 4.1333,6.8283C4.1605,6.8309 4.2139,6.8981 4.2304,6.9189L4.2309,6.92L4.2389,6.9733L4.2469,7.016L4.2501,7.0523Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5285,6.9584L4.5216,6.9547C4.5813,6.8645 4.6539,6.8075 4.688,6.8283L4.6827,6.8336C4.6576,6.8197 4.5904,6.8656 4.5285,6.9584ZM4.2912,6.9584C4.2288,6.8656 4.1616,6.8197 4.1365,6.8336L4.1312,6.8283C4.1648,6.8075 4.2373,6.8645 4.2971,6.9547L4.2912,6.9584Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1691,7.128C4.1627,7.1072 4.1499,7.0923 4.1499,7.0923C4.2155,7.072 4.3067,7.0592 4.4091,7.0592C4.5104,7.0592 4.6037,7.0715 4.6688,7.0923C4.6688,7.0923 4.6613,7.1045 4.6507,7.1221C4.6453,7.1328 4.6373,7.1515 4.6379,7.1515C4.5781,7.1328 4.5024,7.1221 4.408,7.1221C4.3136,7.1221 4.2229,7.1328 4.1755,7.1536C4.1771,7.1531 4.1728,7.1408 4.1691,7.128L4.1691,7.128" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1787,7.1557L4.1755,7.1531L4.1723,7.1531C4.1723,7.1509 4.1691,7.1408 4.1643,7.1307L4.1627,7.1237L4.1627,7.1237C4.1563,7.1072 4.1461,7.0944 4.1456,7.0944L4.1413,7.0901L4.1472,7.088C4.2165,7.0667 4.3093,7.0555 4.4085,7.0555C4.5077,7.0555 4.6,7.0667 4.6693,7.088L4.6747,7.0901L4.672,7.0933C4.672,7.0933 4.6656,7.1067 4.6549,7.1259C4.6496,7.1333 4.6437,7.1493 4.6427,7.152L4.6389,7.1509L4.6373,7.1547C4.5781,7.1365 4.5003,7.128 4.408,7.128C4.3685,7.128 4.3291,7.128 4.2933,7.1323C4.2933,7.1323 4.2923,7.1323 4.2912,7.1323C4.2448,7.1387 4.2043,7.1445 4.1787,7.1557ZM4.1755,7.1323C4.1776,7.1397 4.1787,7.1435 4.1797,7.1445C4.2288,7.128 4.3179,7.1184 4.4091,7.1184C4.5008,7.1184 4.5765,7.128 4.6363,7.1445C4.6384,7.1403 4.6416,7.1323 4.648,7.1195C4.6544,7.1083 4.6603,7.0997 4.6635,7.0944C4.5963,7.0768 4.5045,7.0651 4.4096,7.0651C4.3136,7.0651 4.2251,7.0757 4.1568,7.0944C4.1611,7.1019 4.1691,7.1141 4.1728,7.128L4.1755,7.1323L4.1755,7.1323Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4091,7.2123C4.4912,7.2123 4.5813,7.2 4.6155,7.1904C4.6379,7.1829 4.6501,7.1749 4.648,7.1632C4.6475,7.1568 4.6421,7.1525 4.6357,7.1499C4.5872,7.1323 4.4981,7.1216 4.4096,7.1216C4.3195,7.1216 4.2315,7.1323 4.1819,7.1499C4.1755,7.1531 4.1707,7.1573 4.1696,7.1632C4.1669,7.1744 4.1803,7.1829 4.2032,7.1904C4.2352,7.2 4.3264,7.2123 4.4091,7.2123" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4091,7.2155L4.4091,7.2155C4.3269,7.2155 4.2347,7.2032 4.2005,7.1947C4.1664,7.184 4.1627,7.1696 4.1653,7.1621C4.1664,7.1552 4.1728,7.1488 4.1797,7.1445C4.2315,7.128 4.3216,7.1184 4.4091,7.1184C4.4965,7.1184 4.5856,7.128 4.6379,7.1445C4.6453,7.1488 4.6507,7.1557 4.6528,7.1621C4.6533,7.1696 4.6517,7.184 4.616,7.1947C4.5813,7.2032 4.4912,7.2155 4.4091,7.2155ZM4.4091,7.128C4.3221,7.128 4.2336,7.1387 4.1829,7.1531C4.1787,7.1563 4.1744,7.1584 4.1733,7.1643C4.1728,7.1707 4.1829,7.1808 4.2037,7.1867C4.2379,7.1947 4.328,7.2069 4.4091,7.2069C4.4901,7.2069 4.5803,7.1947 4.6139,7.1867C4.6352,7.1808 4.6459,7.1707 4.6443,7.1643C4.6437,7.1579 4.6395,7.1557 4.6352,7.1531C4.584,7.1387 4.4949,7.128 4.4091,7.128Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6725,7.0555L4.6533,7.0373C4.6533,7.0373 4.6336,7.0485 4.6096,7.0448C4.5856,7.0405 4.5781,7.0133 4.5781,7.0133C4.5781,7.0133 4.5509,7.0341 4.5291,7.032C4.5067,7.0309 4.4939,7.0133 4.4939,7.0133C4.4939,7.0133 4.4688,7.0293 4.448,7.0277C4.4277,7.0267 4.4064,6.9995 4.4064,6.9995C4.4064,6.9995 4.3856,7.0277 4.3659,7.0277C4.3435,7.0309 4.3264,7.0101 4.3264,7.0101C4.3264,7.0101 4.3168,7.0309 4.2907,7.0341C4.2629,7.0405 4.2405,7.0155 4.2405,7.0155C4.2405,7.0155 4.2245,7.0405 4.2069,7.0448C4.1893,7.0533 4.1659,7.0352 4.1659,7.0352C4.1659,7.0352 4.1616,7.0448 4.1589,7.0507C4.1563,7.056 4.1477,7.0571 4.1477,7.0571L4.1536,7.0725C4.2192,7.0528 4.3088,7.0416 4.4096,7.0416C4.5099,7.0416 4.6,7.0528 4.6656,7.0725L4.6725,7.0555" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6688,7.0779L4.6661,7.0779C4.5973,7.0571 4.5067,7.0453 4.4101,7.0443C4.3131,7.0453 4.2235,7.0565 4.1563,7.0779L4.1515,7.0779L4.1424,7.0528L4.1477,7.0528C4.1499,7.0528 4.1541,7.0517 4.1552,7.0475C4.1573,7.0432 4.1616,7.0331 4.1616,7.0331L4.1627,7.0293L4.168,7.032C4.168,7.032 4.1835,7.0421 4.1973,7.0421C4.2,7.0421 4.2037,7.0421 4.2064,7.0405C4.2224,7.0341 4.2379,7.0123 4.2379,7.0123L4.2411,7.0069L4.2437,7.0112C4.2437,7.0112 4.2661,7.0341 4.2896,7.0309C4.3131,7.0277 4.3221,7.008 4.3221,7.0069L4.3248,7.0027L4.3301,7.0069C4.3301,7.0069 4.3445,7.0245 4.3627,7.0245C4.3627,7.0245 4.3637,7.0245 4.3653,7.0245C4.384,7.0213 4.4037,6.9963 4.4037,6.9952L4.4069,6.9925L4.4107,6.9952C4.4112,6.9963 4.4304,7.0203 4.4491,7.0235C4.4501,7.0235 4.4501,7.0235 4.4512,7.0235C4.4699,7.0235 4.4912,7.0069 4.4912,7.0069L4.4939,7.0059L4.4971,7.0091C4.4971,7.0091 4.5093,7.0277 4.5296,7.0277C4.5307,7.0277 4.5312,7.0277 4.5312,7.0277C4.5509,7.0277 4.5749,7.008 4.5749,7.008L4.5813,7.0043L4.5819,7.0112C4.5819,7.0117 4.5899,7.0384 4.6096,7.0405C4.632,7.0437 4.6496,7.032 4.6496,7.032L4.6528,7.0309L4.6747,7.0517L4.6784,7.0517L4.6773,7.056L4.6688,7.0779ZM4.4101,7.0384C4.5056,7.0384 4.5957,7.0491 4.664,7.0683L4.6688,7.0565L4.6528,7.0427C4.6475,7.0453 4.6352,7.0517 4.6192,7.0517C4.6165,7.0517 4.6128,7.0517 4.6101,7.0507C4.5904,7.0453 4.5803,7.0304 4.576,7.0203C4.5669,7.0288 4.5477,7.0411 4.5291,7.0389C4.5109,7.0368 4.4976,7.0251 4.4928,7.0192C4.4853,7.0235 4.4667,7.0325 4.448,7.0325C4.4315,7.0315 4.4144,7.016 4.4069,7.0075C4.4005,7.016 4.3835,7.0315 4.3664,7.0325C4.3653,7.0325 4.3637,7.0325 4.3632,7.0325C4.3477,7.0325 4.3355,7.0229 4.3291,7.0187C4.3227,7.0256 4.312,7.0357 4.2917,7.0411C4.2693,7.0443 4.2507,7.0288 4.2416,7.0203C4.2363,7.0288 4.224,7.0443 4.2101,7.0501C4.2064,7.0517 4.2021,7.0528 4.1979,7.0528C4.1861,7.0528 4.1744,7.0453 4.168,7.0427C4.1669,7.0453 4.1648,7.0507 4.1632,7.0539C4.16,7.056 4.1563,7.0571 4.1536,7.0592L4.1563,7.0683C4.2251,7.0491 4.3147,7.0384 4.4101,7.0384Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4101,6.968L4.4192,6.9696C4.4176,6.9728 4.4171,6.9781 4.4171,6.9819C4.4171,7.0027 4.4347,7.0176 4.4549,7.0176C4.4725,7.0176 4.4853,7.0064 4.4912,6.9925C4.4912,6.9931 4.4939,6.9792 4.496,6.9803C4.4976,6.9803 4.4976,6.9931 4.4976,6.9931C4.5003,7.0107 4.5163,7.0235 4.5349,7.0235C4.5557,7.0235 4.5723,7.0069 4.5723,6.9893C4.5723,6.9867 4.5723,6.984 4.5723,6.9819L4.584,6.9707L4.5909,6.9872C4.5877,6.9904 4.5867,6.9957 4.5867,7.0027C4.5867,7.0192 4.6032,7.0363 4.6219,7.0363C4.6341,7.0363 4.6459,7.0304 4.6523,7.0192L4.6592,7.0117L4.6592,7.0229C4.6592,7.0341 4.6645,7.0437 4.6757,7.0469C4.6757,7.0469 4.6891,7.048 4.7061,7.0336C4.7243,7.0192 4.7339,7.0075 4.7339,7.0075L4.7344,7.0229C4.7344,7.0229 4.7179,7.0523 4.7024,7.0603C4.6928,7.0645 4.68,7.0688 4.6693,7.0688C4.6587,7.0672 4.6507,7.0576 4.6464,7.048C4.6395,7.0523 4.6304,7.0555 4.6203,7.0555C4.5995,7.0555 4.5797,7.0443 4.5717,7.0272C4.5621,7.0379 4.5493,7.0427 4.5333,7.0427C4.5157,7.0427 4.4997,7.0352 4.4907,7.024C4.4811,7.0315 4.4683,7.0395 4.4533,7.0395C4.4347,7.0395 4.4187,7.0283 4.4096,7.0144C4.4,7.0283 4.3824,7.0395 4.3637,7.0395C4.3504,7.0395 4.3365,7.0309 4.3269,7.024C4.3168,7.0352 4.3013,7.0427 4.2848,7.0427C4.2688,7.0427 4.2549,7.0373 4.2448,7.0272C4.2379,7.0448 4.2192,7.056 4.1973,7.056C4.1877,7.056 4.1787,7.0528 4.1701,7.0485C4.1664,7.0581 4.1589,7.0677 4.1477,7.0693C4.1381,7.0693 4.1248,7.0651 4.1163,7.0608C4.1003,7.0523 4.0816,7.0235 4.0816,7.0235L4.0837,7.008C4.0837,7.008 4.0944,7.0192 4.1104,7.0341C4.1291,7.0485 4.1413,7.0475 4.1413,7.0475C4.1536,7.0443 4.1584,7.0352 4.1584,7.0235L4.1584,7.0123L4.1669,7.0197C4.1733,7.0309 4.1835,7.0368 4.1963,7.0368C4.2171,7.0368 4.2325,7.0197 4.2325,7.0032C4.2325,6.9957 4.232,6.9909 4.2299,6.9877L4.2347,6.9707L4.2459,6.9819C4.2459,6.984 4.2453,6.9867 4.2453,6.9893C4.2453,7.0069 4.2624,7.0235 4.2832,7.0235C4.3019,7.0235 4.3184,7.0112 4.3205,6.9931C4.3211,6.9931 4.3211,6.9803 4.3221,6.9803C4.3237,6.9792 4.3269,6.9931 4.3275,6.9925C4.3317,7.0064 4.3472,7.0176 4.3621,7.0176C4.3845,7.0176 4.4,7.0027 4.4,6.9819C4.4,6.9776 4.3995,6.9723 4.3989,6.9696L4.4101,6.968" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6752,7.0752C4.6731,7.0752 4.6725,7.0752 4.6693,7.0741C4.6597,7.072 4.6507,7.0656 4.6459,7.056C4.6379,7.0576 4.6293,7.0608 4.6213,7.0608C4.6005,7.0608 4.5819,7.0512 4.5728,7.0336C4.5616,7.0443 4.5477,7.0491 4.5344,7.0491C4.5179,7.0491 4.5019,7.0421 4.4917,7.0315C4.4811,7.0411 4.4683,7.0437 4.4544,7.0437C4.4379,7.0437 4.4203,7.0352 4.4107,7.0229C4.3984,7.0352 4.3824,7.0437 4.3648,7.0437C4.3515,7.0437 4.3387,7.0405 4.3285,7.0315C4.3173,7.0427 4.3013,7.0491 4.2859,7.0491C4.2709,7.0491 4.2576,7.0437 4.2475,7.0336C4.2379,7.0512 4.2187,7.0608 4.1984,7.0608C4.1888,7.0608 4.1808,7.0576 4.1733,7.056C4.1675,7.0661 4.1589,7.072 4.1488,7.0741C4.1488,7.0752 4.1456,7.0752 4.1445,7.0752C4.1328,7.0752 4.12,7.0683 4.1141,7.0656C4.0987,7.056 4.08,7.0283 4.0795,7.0283L4.0779,7.0251L4.0832,7L4.0891,7.0075C4.0896,7.0075 4.0992,7.0187 4.1147,7.0315C4.1307,7.0432 4.1403,7.0437 4.1429,7.0437C4.1552,7.0421 4.1552,7.0283 4.1552,7.024L4.1552,6.9989L4.1707,7.0187C4.1771,7.0283 4.1867,7.032 4.1968,7.032C4.2144,7.032 4.2288,7.0187 4.2288,7.0027C4.2288,6.9952 4.2272,6.9925 4.2261,6.9904L4.2245,6.9872L4.2347,6.9653L4.2523,6.9819L4.2523,6.9829C4.2523,6.9851 4.2523,6.9872 4.2523,6.9893C4.2523,7.0053 4.2672,7.0197 4.2859,7.0197C4.3024,7.0197 4.3168,7.0075 4.3184,6.9936L4.3184,6.9904C4.3184,6.9904 4.3184,6.9904 4.3184,6.9904C4.3189,6.9803 4.3195,6.9771 4.3243,6.9771L4.3243,6.9771C4.3275,6.9771 4.3296,6.9797 4.3317,6.9856L4.3317,6.9856L4.3333,6.9909C4.3381,7.0048 4.3509,7.0149 4.3648,7.0149C4.3835,7.0149 4.3995,6.9995 4.3995,6.9824C4.3995,6.9781 4.3995,6.9739 4.3968,6.9701L4.3957,6.9659L4.4123,6.9648L4.4277,6.9659L4.4251,6.9701C4.4251,6.9744 4.4245,6.9787 4.4245,6.9824C4.4245,6.9989 4.4395,7.0149 4.4576,7.0149C4.472,7.0149 4.4843,7.0048 4.4896,6.9909L4.4907,6.9867L4.4907,6.9867C4.4939,6.9797 4.4939,6.9771 4.4987,6.9771C4.5029,6.9771 4.5029,6.9808 4.5035,6.9893C4.5035,6.9904 4.5035,6.9904 4.5035,6.9904L4.504,6.9936C4.5061,7.0069 4.5205,7.0197 4.5376,7.0197C4.5563,7.0197 4.5707,7.0059 4.5707,6.9893C4.5707,6.9872 4.5707,6.9851 4.5707,6.9829L4.5701,6.9819L4.5877,6.9653L4.5979,6.9872L4.5973,6.9904C4.5952,6.9931 4.5947,6.9957 4.5947,7.0027C4.5947,7.0181 4.6091,7.032 4.6261,7.032C4.6368,7.032 4.6469,7.0277 4.6528,7.0187L4.6688,6.9989L4.6683,7.024C4.6683,7.0283 4.6699,7.0421 4.6816,7.0437C4.6827,7.0437 4.6944,7.0432 4.7088,7.0315C4.7264,7.0192 4.7355,7.0075 4.7355,7.0075L4.7419,6.9989L4.7451,7.0251L4.7435,7.0272C4.7424,7.0283 4.7264,7.0565 4.7088,7.0656C4.7008,7.0672 4.688,7.0752 4.6752,7.0752ZM4.6501,7.0432L4.6517,7.0469C4.6533,7.0533 4.6597,7.0645 4.6715,7.0656C4.672,7.0656 4.6736,7.0656 4.6752,7.0656C4.6837,7.0656 4.6939,7.0613 4.7003,7.0571C4.7125,7.0507 4.7285,7.0277 4.7317,7.0219L4.7317,7.0197C4.7259,7.0251 4.7195,7.0309 4.7099,7.0395C4.6939,7.0528 4.6816,7.0528 4.6773,7.0528L4.6752,7.0528C4.6635,7.0507 4.6565,7.0405 4.656,7.0245C4.6475,7.0341 4.6352,7.04 4.6224,7.04C4.6,7.04 4.5819,7.0235 4.5819,7.0027C4.5819,6.9941 4.5835,6.9904 4.5851,6.9872L4.5819,6.9792L4.5765,6.9851C4.5765,6.9861 4.5765,6.9872 4.5765,6.9893C4.5765,7.0091 4.5579,7.0277 4.5349,7.0277C4.5147,7.0277 4.4976,7.0155 4.4939,6.9963C4.4875,7.0117 4.472,7.0203 4.4544,7.0203C4.4315,7.0203 4.4123,7.0027 4.4123,6.9819C4.4123,6.9776 4.4123,6.9765 4.4123,6.9712L4.4096,6.9701L4.4043,6.9712C4.4053,6.9765 4.4053,6.9776 4.4053,6.9819C4.4053,7.0027 4.3861,7.0203 4.3621,7.0203C4.3461,7.0203 4.3307,7.0117 4.3248,6.9963C4.32,7.0149 4.3029,7.0277 4.2832,7.0277C4.2597,7.0277 4.2405,7.0091 4.2405,6.9893C4.2405,6.9872 4.2405,6.9861 4.2405,6.9851L4.2352,6.9792L4.232,6.9872C4.2341,6.9904 4.2347,6.9947 4.2347,7.0027C4.2347,7.0235 4.2171,7.04 4.1947,7.04C4.1813,7.04 4.1691,7.0336 4.1621,7.0245C4.1621,7.04 4.1536,7.0507 4.1413,7.0528L4.1413,7.0528C4.1381,7.0528 4.1248,7.0528 4.1077,7.0395C4.0981,7.0309 4.0912,7.024 4.0864,7.0197L4.0853,7.0219C4.0896,7.0283 4.1045,7.0512 4.1173,7.0571C4.1285,7.0645 4.1387,7.0672 4.1472,7.0656C4.1584,7.0645 4.1637,7.0533 4.1659,7.0469L4.168,7.0432L4.1717,7.0448C4.1792,7.0501 4.1872,7.0533 4.1968,7.0533C4.2155,7.0533 4.2341,7.0411 4.2405,7.0261L4.2432,7.0197L4.2475,7.0245C4.2571,7.0336 4.2693,7.0405 4.2843,7.0405C4.2997,7.0405 4.3136,7.032 4.3227,7.0208L4.3253,7.0187L4.3291,7.0197C4.3381,7.0299 4.3499,7.0331 4.3627,7.0331C4.3797,7.0331 4.3957,7.0277 4.4043,7.0144L4.4085,7.0069L4.4112,7.0144C4.4208,7.0277 4.4363,7.0331 4.4523,7.0331C4.4651,7.0331 4.4773,7.0293 4.4864,7.0197L4.4896,7.0187L4.4923,7.0208C4.5019,7.032 4.5173,7.0405 4.5323,7.0405C4.5456,7.0405 4.5584,7.0331 4.5675,7.0245L4.5728,7.0197L4.5749,7.0261C4.5824,7.0405 4.5995,7.0533 4.6192,7.0533C4.6277,7.0533 4.6357,7.0501 4.6437,7.0448L4.6501,7.0432Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4091,7.0592C4.3067,7.0592 4.2155,7.0715 4.1504,7.0923C4.1445,7.0939 4.1397,7.0907 4.1381,7.0864C4.1376,7.0821 4.1408,7.0779 4.1445,7.0757C4.2107,7.0555 4.3045,7.0421 4.4096,7.0421C4.5131,7.0421 4.608,7.0555 4.6741,7.0757C4.6789,7.0779 4.6821,7.0821 4.68,7.0864C4.6789,7.0907 4.6725,7.0939 4.6693,7.0923C4.6037,7.072 4.5104,7.0592 4.4091,7.0592" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6709,7.096C4.6693,7.096 4.6693,7.0949 4.6672,7.0949C4.5995,7.0773 4.5067,7.0656 4.4091,7.0656C4.3104,7.0656 4.2192,7.0768 4.1504,7.0949C4.1445,7.0981 4.1365,7.0939 4.1349,7.0885C4.1333,7.0832 4.1333,7.0811 4.1349,7.0779C4.1365,7.0747 4.1397,7.0704 4.1435,7.0693C4.2128,7.0496 4.3067,7.0379 4.4096,7.0379C4.5104,7.0379 4.6069,7.0501 4.6757,7.0693C4.6821,7.0725 4.6864,7.0805 4.6853,7.088C4.6816,7.0933 4.6763,7.096 4.6709,7.096ZM4.4091,7.056C4.5077,7.056 4.6,7.0672 4.6693,7.0885L4.6704,7.0885C4.672,7.0885 4.6747,7.0864 4.6747,7.0832C4.6752,7.0821 4.6741,7.0805 4.672,7.0795C4.6037,7.0571 4.5083,7.0459 4.4085,7.0448C4.3093,7.0459 4.2123,7.0571 4.1451,7.0795C4.1435,7.0795 4.1435,7.0811 4.1424,7.0821C4.1419,7.0821 4.1419,7.0821 4.1419,7.0832C4.1424,7.0864 4.1445,7.0885 4.1472,7.0885C4.2171,7.0672 4.3099,7.056 4.4091,7.056Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.3099,7.0949C4.3099,7.0907 4.3163,7.0827 4.3253,7.0827C4.3333,7.0827 4.3397,7.0912 4.3397,7.0949C4.3397,7.1051 4.3328,7.1093 4.3253,7.1093C4.3163,7.1093 4.3099,7.1045 4.3099,7.0949" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4101,7.1029L4.3776,7.1029C4.3717,7.1029 4.3664,7.0965 4.3664,7.0917C4.3664,7.0859 4.3717,7.0805 4.3776,7.0805L4.4443,7.0805C4.4507,7.0805 4.4544,7.0859 4.4544,7.0917C4.4544,7.0965 4.4507,7.1029 4.4443,7.1029L4.4101,7.1029" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4443,7.1072L4.3776,7.1072C4.3691,7.1072 4.3621,7.1008 4.3621,7.0923C4.3621,7.0821 4.3691,7.0784 4.3771,7.0784L4.4437,7.0784C4.4517,7.0784 4.4587,7.0827 4.4587,7.0923C4.4592,7.1008 4.4517,7.1072 4.4443,7.1072ZM4.3771,7.0853C4.3733,7.0853 4.3707,7.0896 4.3707,7.0923C4.3707,7.0949 4.3733,7.0981 4.3776,7.0981L4.4443,7.0981C4.4475,7.0981 4.4507,7.0949 4.4507,7.0923C4.4507,7.0896 4.448,7.0853 4.4443,7.0853L4.3771,7.0853Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.2459,7.1157L4.2224,7.1173C4.216,7.1184 4.2101,7.1157 4.2101,7.1072C4.2096,7.1029 4.2128,7.0965 4.2192,7.096L4.2421,7.0939L4.2661,7.0907C4.2725,7.0907 4.2784,7.0923 4.2784,7.0981C4.2789,7.1035 4.2752,7.1077 4.2688,7.1093L4.2459,7.1157" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.2208,7.1211C4.2128,7.1211 4.2069,7.1157 4.2059,7.1077C4.2048,7.1061 4.2064,7.1035 4.208,7.0981C4.2101,7.0949 4.2139,7.0933 4.2187,7.0923L4.2661,7.0843C4.2661,7.0843 4.2667,7.0843 4.2683,7.0843C4.2752,7.0843 4.2816,7.0907 4.2832,7.0965C4.2848,7.1061 4.2784,7.1141 4.2699,7.1152L4.2224,7.12C4.2224,7.12 4.2219,7.1211 4.2208,7.1211ZM4.2683,7.0939L4.2192,7.1024C4.2181,7.1035 4.2165,7.1035 4.2155,7.1035C4.2139,7.1051 4.2133,7.1067 4.2139,7.1077C4.2144,7.1109 4.2181,7.1152 4.2224,7.1141L4.2688,7.1067C4.272,7.1061 4.2752,7.1035 4.2752,7.0992C4.2741,7.0949 4.2715,7.0939 4.2683,7.0939Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1504,7.1307l0.0112,-0.016l0.0224,0.0037l-0.0133,0.0181l-0.0203,-0.0059" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4784,7.0949C4.4784,7.0907 4.4848,7.0827 4.4928,7.0827C4.5003,7.0827 4.5067,7.0912 4.5067,7.0949C4.5067,7.1051 4.4997,7.1093 4.4928,7.1093C4.4848,7.1093 4.4784,7.1045 4.4784,7.0949" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5723,7.1157L4.5957,7.1173C4.6016,7.1184 4.6069,7.1157 4.608,7.1072C4.6096,7.1029 4.6053,7.0965 4.5989,7.096L4.5749,7.0939L4.5509,7.0907C4.5451,7.0907 4.5397,7.0923 4.5387,7.0981C4.5376,7.1035 4.5419,7.1077 4.5477,7.1093L4.5723,7.1157" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5973,7.1211C4.5973,7.1211 4.5963,7.12 4.5947,7.12L4.5472,7.1157C4.544,7.1157 4.5397,7.1115 4.5376,7.1072C4.5349,7.1045 4.5349,7.1019 4.5349,7.0965C4.5355,7.0901 4.544,7.0821 4.552,7.0843L4.6,7.0923C4.6032,7.0933 4.6069,7.0949 4.6096,7.0981C4.6123,7.1035 4.6123,7.1061 4.6123,7.1077C4.6112,7.1157 4.6048,7.1211 4.5973,7.1211ZM4.5504,7.0939C4.5477,7.0939 4.544,7.0949 4.544,7.0992C4.5435,7.1013 4.544,7.1035 4.544,7.1035C4.5451,7.1051 4.5472,7.1061 4.5488,7.1067L4.5973,7.1141C4.6,7.1141 4.6037,7.1109 4.6037,7.1077C4.6037,7.1067 4.6037,7.1051 4.6037,7.1035C4.6021,7.1035 4.6005,7.1035 4.5984,7.1024L4.5504,7.0939L4.5504,7.0939Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6656,7.1312l-0.0091,-0.0165l-0.0224,0.0011l0.0101,0.0187l0.0213,-0.0032" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4091,7.1936C4.3264,7.1931 4.2523,7.1851 4.1952,7.1696C4.2517,7.1563 4.3264,7.1467 4.4091,7.1467C4.4912,7.1467 4.5664,7.1563 4.6224,7.1696C4.5664,7.1856 4.4912,7.1931 4.4091,7.1936" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4091,7.1968L4.4091,7.1968C4.3237,7.1968 4.2507,7.1904 4.1941,7.176C4.192,7.1749 4.1915,7.1728 4.1915,7.1696C4.1915,7.1685 4.192,7.1669 4.1941,7.1669C4.2539,7.1531 4.3291,7.1435 4.4091,7.1429C4.488,7.1429 4.5643,7.1531 4.6235,7.1669C4.6251,7.1669 4.6267,7.1685 4.6267,7.1696C4.6267,7.1728 4.6251,7.1749 4.6235,7.176C4.568,7.1904 4.4939,7.1968 4.4091,7.1968ZM4.2139,7.1696C4.2661,7.1819 4.3333,7.1893 4.4085,7.1904C4.4848,7.1893 4.5499,7.1819 4.6032,7.1696C4.5472,7.1573 4.4784,7.1531 4.4085,7.1531C4.3376,7.1531 4.2693,7.1573 4.2139,7.1696Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6688,7.0155C4.6699,7.0069 4.6688,7.0032 4.6635,7.0011C4.6597,6.9989 4.6533,7.0032 4.6512,7.0085C4.6496,7.016 4.6507,7.0208 4.6565,7.024C4.6597,7.0251 4.6661,7.0197 4.6688,7.0155" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.504,6.9824C4.5051,6.9781 4.5024,6.9701 4.4976,6.9701C4.4923,6.9701 4.488,6.9749 4.488,6.9813C4.4864,6.9888 4.4896,6.9936 4.4944,6.9936C4.4992,6.9947 4.5035,6.9904 4.504,6.9824" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.3136,6.9824C4.3125,6.9781 4.3157,6.9701 4.3216,6.9701C4.3253,6.9701 4.3312,6.9749 4.3317,6.9813C4.3317,6.9888 4.3291,6.9936 4.3248,6.9936C4.3189,6.9947 4.3152,6.9904 4.3136,6.9824" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1504,7.0155C4.1477,7.0069 4.1504,7.0032 4.1541,7.0011C4.16,6.9989 4.1648,7.0032 4.1664,7.0085C4.1691,7.016 4.1669,7.0208 4.1627,7.024C4.1573,7.0251 4.1525,7.0197 4.1504,7.0155" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4091,6.8896l-0.0299,0.0165l0.0219,0.0469l0.008,0.0043l0.0075,-0.0043l0.0219,-0.0469l-0.0293,-0.0165" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4091,6.9637L4.3979,6.9557L4.3744,6.9029L4.4091,6.8821L4.4443,6.9029L4.4192,6.9557L4.4091,6.9637ZM4.4043,6.9499L4.4085,6.9531L4.4123,6.9499L4.4309,6.9072L4.4085,6.8939L4.3845,6.9072L4.4043,6.9499Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.3445,6.9573l0.0139,0.0208l0.0453,-0.0123l0.0048,-0.0085l-0.0048,-0.0043l-0.0453,-0.0144l-0.0139,0.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.3563,6.9824L4.3397,6.9573L4.3563,6.9323L4.4064,6.9467L4.4133,6.9573L4.4064,6.9685L4.3563,6.9824ZM4.3504,6.9573L4.36,6.9728L4.4005,6.9595L4.4037,6.9573L4.4005,6.9557L4.36,6.944L4.3504,6.9573Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4725,6.9573l-0.0123,0.0208l-0.0464,-0.0123l-0.0037,-0.0085l0.0037,-0.0043l0.0459,-0.0144l0.0128,0.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.4613,6.9824l-0.0501,-0.0139l-0.0075,-0.0112l0.008,-0.0107l0.0501,-0.0144l0.0171,0.0251z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.2192,6.9072l-0.0219,0.0235l0.0283,0.0379l0.0091,0.0021l0.0048,-0.0053l0.0107,-0.0459l-0.0309,-0.0123" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.2347,6.9781l-0.0117,-0.0064l-0.032,-0.0411l0.0277,-0.0277l0.0357,0.0139l-0.0112,0.0517z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1723,6.9867l0.0165,0.0165l0.0416,-0.0235l0.0032,-0.008l-0.0053,-0.0048l-0.048,-0.0027l-0.008,0.0224" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1877,7.0075l-0.0213,-0.0197l0.0112,-0.0304l0.0517,0.0064l0.0096,0.0064l-0.0048,0.0123z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.2976,6.9605l-0.0096,0.0219l-0.0464,-0.0043l-0.0069,-0.0064l0.0027,-0.0064l0.0411,-0.0219l0.0192,0.0171" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.2912,6.9877l-0.0528,-0.0053l-0.0101,-0.0085l0.0064,-0.0112l0.0453,-0.024l0.0219,0.0208z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1259,6.992l-0.0037,0.0235l-0.0469,0.0043l-0.0069,-0.0043l0.0005,-0.0085l0.0363,-0.0293l0.0208,0.0144" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.0747,7.024l-0.0117,-0.0059l0.0032,-0.0123l0.0389,-0.0336l0.0267,0.0187l-0.0053,0.0283z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.2181,6.9717C4.2181,6.9653 4.2256,6.9573 4.2352,6.9573C4.2443,6.9573 4.2507,6.9659 4.2507,6.9717C4.2507,6.9813 4.2443,6.9893 4.2352,6.9893C4.2251,6.9893 4.2181,6.9813 4.2181,6.9717" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5979,6.9072l0.0235,0.0235l-0.0299,0.0379l-0.0064,0.0021l-0.0064,-0.0053l-0.0096,-0.0459l0.0288,-0.0123" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5824,6.9781l-0.0075,-0.0096l-0.0123,-0.0517l0.0368,-0.0139l0.0272,0.0277l-0.0331,0.0411z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6459,6.9867l-0.0176,0.0165l-0.0411,-0.0235l-0.0027,-0.008l0.0064,-0.0048l0.0464,-0.0027l0.0085,0.0224" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6293,7.0075l-0.0443,-0.0251l-0.0064,-0.0123l0.0096,-0.0064l0.0533,-0.0064l0.0096,0.0304z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5216,6.9605l0.0085,0.0219l0.0475,-0.0043l0.0064,-0.0064l-0.0037,-0.0064l-0.0421,-0.0219l-0.0165,0.0171" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5275,6.9877l-0.0112,-0.0283l0.0219,-0.0208l0.0453,0.024l0.0053,0.0112l-0.0101,0.0085z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6848,6.992l0.0037,0.0235l0.0475,0.0043l0.0075,-0.0043l-0.0027,-0.0085l-0.0347,-0.0293l-0.0213,0.0144" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.7376,7.024l-0.0528,-0.0053l-0.0043,-0.0283l0.0261,-0.0187l0.0395,0.0336l0.0021,0.0123z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.392,6.9573C4.392,6.9488 4.4,6.9424 4.4091,6.9424C4.4187,6.9424 4.4251,6.9493 4.4251,6.9573C4.4251,6.9653 4.4181,6.9739 4.4091,6.9739C4.4,6.9739 4.392,6.9659 4.392,6.9573" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5675,6.9717C4.5675,6.9653 4.5755,6.9573 4.5851,6.9573C4.5941,6.9573 4.6005,6.9659 4.6005,6.9717C4.6005,6.9813 4.5941,6.9893 4.5851,6.9893C4.5755,6.9893 4.5675,6.9813 4.5675,6.9717" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.0629,7.0187C4.0629,7.0187 4.0507,7.0032 4.0411,6.9936C4.0336,6.9883 4.0176,6.9824 4.0176,6.9824C4.0176,6.9797 4.0272,6.9728 4.0379,6.9728C4.0437,6.9728 4.0491,6.976 4.0523,6.9797L4.0533,6.9728C4.0533,6.9728 4.0619,6.9749 4.0656,6.9824C4.0683,6.9936 4.0661,7.0075 4.0661,7.0075C4.0661,7.0075 4.0661,7.0155 4.0629,7.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.0629,7.0219C4.0603,7.0219 4.0603,7.0208 4.0544,7.0155C4.0501,7.0101 4.0432,7.0032 4.0379,6.9957C4.032,6.9931 4.0203,6.9893 4.016,6.9872L4.0128,6.9851L4.0128,6.9819C4.0128,6.9765 4.0251,6.9685 4.0379,6.9685C4.0411,6.9685 4.0459,6.9696 4.0496,6.9707L4.0501,6.9685L4.0539,6.9685C4.0544,6.9685 4.0651,6.9696 4.0688,6.9819C4.0736,6.9931 4.072,7.0069 4.0715,7.0069C4.0715,7.0091 4.0688,7.0171 4.0661,7.0192L4.0645,7.0213L4.0629,7.0213L4.0629,7.0219Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.0629,7.0096C4.0667,7.0064 4.0752,7.0075 4.0816,7.0128C4.088,7.0176 4.0891,7.0251 4.0848,7.0283C4.0816,7.0325 4.0725,7.0325 4.0667,7.0283C4.0608,7.0208 4.0597,7.0155 4.0629,7.0096" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.7493,7.0187C4.7499,7.0187 4.7627,7.0032 4.7717,6.9936C4.7787,6.9883 4.7941,6.9824 4.7941,6.9824C4.7941,6.9797 4.7851,6.9728 4.7749,6.9728C4.7691,6.9728 4.7632,6.976 4.76,6.9797L4.7579,6.9728C4.7579,6.9728 4.7504,6.9749 4.7461,6.9824C4.7419,6.9936 4.744,7.0075 4.744,7.0075C4.744,7.0075 4.7461,7.0155 4.7493,7.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.7493,7.0219L4.7493,7.0219L4.7472,7.0219L4.7461,7.0197C4.7419,7.0171 4.7413,7.0091 4.7413,7.0075C4.7408,7.0075 4.7381,6.9941 4.7413,6.9824C4.7472,6.9701 4.7563,6.9691 4.7563,6.9691L4.7611,6.9691L4.7621,6.9712C4.7653,6.9701 4.7691,6.9691 4.7739,6.9691C4.7845,6.9691 4.7973,6.9776 4.7973,6.9824L4.7973,6.9856L4.7941,6.9877C4.7899,6.9899 4.7776,6.9936 4.7733,6.9963C4.7675,7.0037 4.7595,7.0117 4.7552,7.016C4.752,7.0208 4.7515,7.0219 4.7493,7.0219Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.7504,7.0096C4.7456,7.0064 4.7381,7.0075 4.7317,7.0128C4.7253,7.0176 4.7237,7.0251 4.728,7.0283C4.7317,7.0325 4.7397,7.0325 4.7456,7.0283C4.7515,7.0208 4.7536,7.0155 4.7504,7.0096" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.0341,7.4032l0.7536,0l0,-0.1973l-0.7536,0z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.7941,7.4085L4.0272,7.4085L4.0272,7.1989L4.7941,7.1989L4.7941,7.4085ZM4.0411,7.3947L4.7813,7.3947L4.7813,7.2123L4.0411,7.2123L4.0411,7.3947Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1125,7.5333C4.1173,7.5323 4.1211,7.5323 4.1264,7.5323L4.6912,7.5323C4.6976,7.5323 4.7024,7.5323 4.7067,7.5344C4.688,7.528 4.6731,7.5115 4.6731,7.4907C4.6731,7.4699 4.688,7.4533 4.7077,7.4448C4.7035,7.4459 4.6971,7.448 4.6907,7.448L4.1264,7.448C4.1211,7.448 4.1157,7.4469 4.1104,7.4448L4.1136,7.4459C4.1349,7.4533 4.1456,7.4699 4.1456,7.4907C4.1456,7.5083 4.1328,7.528 4.1125,7.5333" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.7067,7.5424C4.7067,7.5424 4.7056,7.5424 4.7045,7.5408L4.7029,7.5408C4.6992,7.5408 4.6949,7.5408 4.6912,7.5408L4.1264,7.5408C4.1221,7.5408 4.12,7.5408 4.1179,7.5408C4.1157,7.5408 4.1157,7.5408 4.1147,7.5408C4.1109,7.5424 4.1072,7.5408 4.1061,7.5371C4.1056,7.5323 4.1061,7.5296 4.1093,7.528C4.1109,7.528 4.112,7.528 4.1125,7.528C4.128,7.5195 4.1381,7.5061 4.1381,7.4907C4.1381,7.4741 4.1285,7.4581 4.1141,7.4533C4.1125,7.4533 4.1099,7.4533 4.1088,7.4533C4.1056,7.4533 4.1035,7.448 4.104,7.4448C4.1051,7.4405 4.1083,7.4405 4.1125,7.4405L4.1173,7.4405C4.12,7.4405 4.1232,7.4405 4.1264,7.4405L4.6912,7.4405C4.6965,7.4405 4.7024,7.4405 4.7067,7.4405C4.7099,7.4384 4.7131,7.4405 4.7147,7.4437C4.7163,7.4448 4.7136,7.4512 4.7104,7.4533C4.6928,7.4576 4.6805,7.4741 4.6805,7.4907C4.6805,7.5072 4.6917,7.5211 4.7067,7.528C4.7072,7.528 4.7088,7.528 4.7099,7.528C4.7125,7.5307 4.7136,7.5323 4.7125,7.5387C4.712,7.5408 4.7099,7.5424 4.7067,7.5424ZM4.1376,7.5269L4.6811,7.5269C4.6725,7.5157 4.6667,7.5029 4.6667,7.4907C4.6667,7.4784 4.6725,7.4656 4.6816,7.4549L4.1381,7.4549C4.1477,7.4661 4.1525,7.4784 4.1525,7.4907C4.1525,7.5029 4.1472,7.5157 4.1376,7.5269Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1264,7.5323L4.6912,7.5323C4.7099,7.5323 4.7253,7.5445 4.7253,7.5573C4.7253,7.5739 4.7099,7.5856 4.6912,7.5856L4.1264,7.5856C4.1072,7.5856 4.0917,7.5744 4.0917,7.5573C4.0917,7.5445 4.1072,7.5323 4.1264,7.5323" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6912,7.592L4.1264,7.592C4.1035,7.592 4.0848,7.5781 4.0848,7.5573C4.0848,7.5408 4.1035,7.5269 4.1264,7.5269L4.6912,7.5269C4.7136,7.5269 4.7323,7.5403 4.7323,7.5573C4.7323,7.5781 4.7136,7.592 4.6912,7.592ZM4.1264,7.5408C4.1115,7.5408 4.0987,7.5483 4.0987,7.5573C4.0987,7.5696 4.1115,7.5781 4.1264,7.5781L4.6912,7.5781C4.7067,7.5781 4.7189,7.5696 4.7189,7.5573C4.7189,7.5477 4.7067,7.5408 4.6912,7.5408L4.1264,7.5408Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1264,7.4032L4.6912,7.4032C4.7104,7.4032 4.7259,7.4144 4.7259,7.4261C4.7259,7.4384 4.7104,7.448 4.6912,7.448L4.1264,7.448C4.1072,7.448 4.0917,7.4384 4.0917,7.4261C4.0917,7.4144 4.1072,7.4032 4.1264,7.4032" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6912,7.4549L4.1264,7.4549C4.1035,7.4549 4.0848,7.4427 4.0848,7.4261C4.0848,7.4085 4.1035,7.3947 4.1264,7.3947L4.6912,7.3947C4.7152,7.3947 4.7328,7.408 4.7328,7.4261C4.7328,7.4421 4.7152,7.4549 4.6912,7.4549ZM4.1264,7.4085C4.1099,7.4085 4.0987,7.4187 4.0987,7.4261C4.0987,7.4325 4.1099,7.4405 4.1264,7.4405L4.6912,7.4405C4.7083,7.4405 4.7195,7.432 4.7195,7.4261C4.7195,7.4181 4.7083,7.4085 4.6912,7.4085L4.1264,7.4085Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9376,10.728C4.8848,10.728 4.8379,10.7179 4.8037,10.6997C4.7701,10.6821 4.7243,10.6704 4.6731,10.6704C4.6224,10.6704 4.5749,10.6816 4.5408,10.6997C4.5061,10.7179 4.4597,10.728 4.408,10.728C4.3557,10.728 4.3093,10.7157 4.2747,10.6976C4.2411,10.6821 4.1968,10.6704 4.1467,10.6704C4.0955,10.6704 4.0496,10.6811 4.0155,10.6987C3.9813,10.7168 3.9344,10.728 3.8821,10.728L3.8821,10.8101C3.9344,10.8101 3.9813,10.7989 4.0155,10.7803C4.0496,10.7632 4.0955,10.7525 4.1467,10.7525C4.1968,10.7525 4.2405,10.7637 4.2747,10.7803C4.3093,10.7973 4.3557,10.8101 4.408,10.8101C4.4592,10.8101 4.5061,10.7989 4.5408,10.7808C4.5749,10.7653 4.6219,10.7525 4.6731,10.7525C4.7243,10.7525 4.7696,10.7648 4.8037,10.7808C4.8379,10.7995 4.8848,10.8101 4.9365,10.8101L4.9376,10.728" + android:strokeWidth="1" + android:fillColor="#005BBF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9435,10.8171L4.9365,10.8171C4.8848,10.8171 4.8379,10.8059 4.8005,10.7872C4.7664,10.7696 4.7221,10.7579 4.6736,10.7579C4.6256,10.7579 4.5792,10.7691 4.5445,10.7872C4.5072,10.8059 4.4603,10.8171 4.4091,10.8171C4.3595,10.8171 4.3104,10.8059 4.2731,10.7851C4.2384,10.7685 4.1947,10.7579 4.1483,10.7579C4.0981,10.7579 4.0544,10.7685 4.0197,10.7861C3.9824,10.8059 3.9344,10.8171 3.8837,10.8171L3.8763,10.8171L3.8763,10.7205L3.8827,10.7205C3.9312,10.7205 3.9787,10.712 4.0128,10.6933C4.0491,10.6747 4.0949,10.6651 4.1472,10.6651C4.1963,10.6651 4.2427,10.6747 4.2784,10.6928C4.3141,10.7109 4.36,10.7205 4.4085,10.7205C4.4565,10.7205 4.5035,10.712 4.5376,10.6933C4.5739,10.6768 4.6229,10.6651 4.6731,10.6651C4.7232,10.6651 4.7712,10.6757 4.8064,10.6933C4.8411,10.712 4.888,10.7205 4.9376,10.7205L4.9445,10.7205L4.9435,10.8171ZM4.1472,10.7445C4.1957,10.7445 4.2421,10.7557 4.2784,10.7739C4.3147,10.7936 4.36,10.8032 4.4085,10.8032C4.4565,10.8032 4.5035,10.7936 4.5376,10.776C4.5744,10.7573 4.6224,10.7445 4.6731,10.7445C4.7227,10.7445 4.7707,10.7568 4.8064,10.776C4.8411,10.7936 4.8827,10.8032 4.9296,10.8032L4.9307,10.7344C4.8816,10.7333 4.8352,10.7237 4.8,10.7056C4.7659,10.6885 4.7216,10.6779 4.6731,10.6779C4.6251,10.6779 4.5787,10.6891 4.544,10.7061C4.5077,10.7248 4.4597,10.7344 4.4085,10.7344C4.3584,10.7344 4.3099,10.7243 4.2725,10.7045C4.2384,10.6885 4.1941,10.6779 4.1477,10.6779C4.0976,10.6779 4.0539,10.6885 4.0192,10.7045C3.9851,10.7237 3.9381,10.7333 3.8896,10.7344L3.8896,10.8032C3.9349,10.8032 3.9797,10.792 4.0128,10.7749C4.0496,10.7563 4.0955,10.7445 4.1472,10.7445Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9376,10.8107C4.8848,10.8107 4.8379,10.8 4.8037,10.7813C4.7701,10.7659 4.7243,10.7531 4.6731,10.7531C4.6224,10.7531 4.5749,10.7653 4.5408,10.7813C4.5061,10.7989 4.4597,10.8107 4.408,10.8107C4.3557,10.8107 4.3093,10.7984 4.2747,10.7808C4.2411,10.7648 4.1968,10.7531 4.1467,10.7531C4.0955,10.7531 4.0496,10.7637 4.0155,10.7808C3.9813,10.7989 3.9344,10.8107 3.8821,10.8107L3.8821,10.8923C3.9344,10.8923 3.9813,10.8811 4.0155,10.8624C4.0496,10.8448 4.0955,10.8331 4.1467,10.8331C4.1968,10.8331 4.2405,10.8443 4.2747,10.8613C4.3093,10.8795 4.3557,10.8923 4.408,10.8923C4.4592,10.8923 4.5061,10.8811 4.5408,10.8635C4.5749,10.8448 4.6219,10.8331 4.6731,10.8331C4.7243,10.8331 4.7696,10.8443 4.8037,10.8635C4.8379,10.8811 4.8848,10.8923 4.9365,10.8923L4.9376,10.8107" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9435,10.8981L4.9365,10.8981C4.8848,10.8981 4.8379,10.8896 4.8005,10.8688C4.7664,10.8523 4.7221,10.8405 4.6736,10.8405C4.6256,10.8405 4.5792,10.8528 4.5445,10.8688C4.5072,10.8885 4.4603,10.8981 4.4091,10.8981C4.3595,10.8981 4.3104,10.8875 4.2731,10.8672C4.2384,10.8512 4.1947,10.8405 4.1483,10.8405C4.0981,10.8405 4.0544,10.8512 4.0197,10.8683C3.9829,10.8885 3.9349,10.8981 3.8837,10.8981L3.8763,10.8981L3.8763,10.8032L3.8827,10.8032C3.9312,10.8032 3.9787,10.7936 4.0128,10.7749C4.0496,10.7563 4.0955,10.7445 4.1472,10.7445C4.1963,10.7445 4.2427,10.7557 4.2784,10.7739C4.3147,10.7936 4.3605,10.8032 4.4085,10.8032C4.4565,10.8032 4.5035,10.7936 4.5376,10.776C4.5744,10.7573 4.6224,10.7445 4.6731,10.7445C4.7227,10.7445 4.7707,10.7568 4.8064,10.776C4.8411,10.7936 4.888,10.8032 4.9376,10.8032L4.9445,10.8032L4.9435,10.8981ZM4.1472,10.8283C4.1957,10.8283 4.2421,10.8389 4.2784,10.8565C4.3141,10.8752 4.36,10.8848 4.4085,10.8848C4.4565,10.8848 4.5035,10.8763 4.5376,10.8576C4.5744,10.84 4.6224,10.8283 4.6731,10.8283C4.7227,10.8283 4.7707,10.8395 4.8064,10.8576C4.8411,10.8752 4.8827,10.8837 4.9296,10.8848L4.9307,10.8176C4.8816,10.816 4.8352,10.8064 4.8,10.7877C4.7659,10.7701 4.7216,10.7584 4.6731,10.7584C4.6251,10.7584 4.5787,10.7696 4.544,10.7877C4.5067,10.8064 4.4597,10.8176 4.4085,10.8176C4.3589,10.8176 4.3099,10.8064 4.2725,10.7856C4.2384,10.7691 4.1941,10.7584 4.1477,10.7584C4.0976,10.7584 4.0539,10.7691 4.0192,10.7867C3.9845,10.8059 3.9381,10.816 3.8896,10.8176L3.8896,10.8848C3.9349,10.8837 3.9803,10.8741 4.0128,10.8565C4.0491,10.8384 4.0949,10.8283 4.1472,10.8283Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9376,10.8923C4.8848,10.8923 4.8379,10.8811 4.8037,10.8635C4.7701,10.8448 4.7243,10.8331 4.6731,10.8331C4.6224,10.8331 4.5749,10.8443 4.5408,10.8635C4.5061,10.8811 4.4597,10.8923 4.408,10.8923C4.3557,10.8923 4.3093,10.88 4.2747,10.8613C4.2411,10.8448 4.1968,10.8331 4.1467,10.8331C4.0955,10.8331 4.0496,10.8443 4.0155,10.8624C3.9813,10.8805 3.9344,10.8923 3.8821,10.8923L3.8821,10.9728C3.9344,10.9728 3.9813,10.9616 4.0155,10.9435C4.0496,10.9269 4.0955,10.9152 4.1467,10.9152C4.1968,10.9152 4.2405,10.9275 4.2747,10.9429C4.3093,10.9611 4.3557,10.9728 4.408,10.9728C4.4592,10.9728 4.5061,10.9621 4.5408,10.9445C4.5749,10.928 4.6219,10.9152 4.6731,10.9152C4.7243,10.9152 4.7696,10.9275 4.8037,10.9445C4.8379,10.9632 4.8848,10.9728 4.9365,10.9728L4.9376,10.8923" + android:strokeWidth="1" + android:fillColor="#005BBF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9435,10.9797L4.9365,10.9797C4.8848,10.9797 4.8379,10.9696 4.8005,10.9509C4.7669,10.9323 4.7227,10.9216 4.6736,10.9216C4.6256,10.9216 4.5792,10.9323 4.5445,10.9509C4.5077,10.9696 4.4603,10.9797 4.4091,10.9797C4.3589,10.9797 4.3104,10.9685 4.2731,10.9488C4.2384,10.9323 4.1947,10.9216 4.1483,10.9216C4.0981,10.9216 4.0544,10.9323 4.0197,10.9499C3.9829,10.9685 3.9355,10.9797 3.8837,10.9797L3.8763,10.9797L3.8763,10.8843L3.8827,10.8843C3.9312,10.8843 3.9787,10.8747 4.0128,10.856C4.0491,10.8384 4.0949,10.8277 4.1472,10.8277C4.1963,10.8277 4.2427,10.8384 4.2784,10.856C4.3147,10.8747 4.36,10.8843 4.4085,10.8843C4.4565,10.8843 4.5035,10.8757 4.5376,10.8571C4.5744,10.8395 4.6224,10.8277 4.6731,10.8277C4.7227,10.8277 4.7707,10.8389 4.8064,10.8571C4.8416,10.8757 4.888,10.8843 4.9376,10.8843L4.9445,10.8843L4.9435,10.9797ZM4.1472,10.9083C4.1952,10.9083 4.2421,10.9195 4.2784,10.9376C4.3141,10.9563 4.3595,10.9675 4.4085,10.9675C4.4565,10.9675 4.5035,10.9573 4.5376,10.9397C4.5744,10.92 4.6224,10.9083 4.6731,10.9083C4.7232,10.9083 4.7712,10.9195 4.8064,10.9397C4.8411,10.9563 4.8821,10.9659 4.9296,10.9659L4.9307,10.8981C4.8816,10.8971 4.8357,10.8875 4.8,10.8688C4.7659,10.8523 4.7216,10.8405 4.6731,10.8405C4.6251,10.8405 4.5787,10.8528 4.544,10.8688C4.5067,10.8885 4.4597,10.8981 4.4085,10.8981C4.3589,10.8981 4.3099,10.8875 4.2725,10.8672C4.2384,10.8512 4.1941,10.8405 4.1477,10.8405C4.0976,10.8405 4.0539,10.8512 4.0192,10.8683C3.9851,10.8875 3.9381,10.8971 3.8896,10.8981L3.8896,10.9659C3.9349,10.9659 3.9803,10.9557 4.0128,10.9387C4.0496,10.92 4.0955,10.9083 4.1472,10.9083Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9365,11.0549C4.8848,11.0549 4.8379,11.0437 4.8037,11.0272C4.7701,11.0075 4.7243,10.9968 4.6731,10.9968C4.6224,10.9968 4.5749,11.0075 4.5408,11.0272C4.5061,11.0437 4.4597,11.0549 4.408,11.0549C4.3557,11.0549 4.3093,11.0437 4.2747,11.0251C4.2411,11.0075 4.1968,10.9968 4.1467,10.9968C4.0955,10.9968 4.0496,11.0075 4.0155,11.0261C3.9813,11.0437 3.9344,11.0549 3.8821,11.0549L3.8821,10.9744C3.9344,10.9744 3.9813,10.9621 4.0155,10.944C4.0496,10.9275 4.0955,10.9157 4.1467,10.9157C4.1968,10.9157 4.2405,10.928 4.2747,10.9435C4.3093,10.9616 4.3557,10.9733 4.408,10.9733C4.4592,10.9733 4.5061,10.9627 4.5408,10.9451C4.5749,10.9285 4.6219,10.9157 4.6731,10.9157C4.7243,10.9157 4.7696,10.928 4.8037,10.9451C4.8379,10.9637 4.8848,10.9733 4.9376,10.9733L4.9365,11.0549" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9435,11.0613L4.9365,11.0613C4.8848,11.0613 4.8379,11.0517 4.8005,11.0309C4.7664,11.0155 4.7221,11.0043 4.6736,11.0043C4.6256,11.0043 4.5792,11.0155 4.5445,11.032C4.5077,11.0517 4.4603,11.0613 4.4091,11.0613C4.3595,11.0613 4.3104,11.0507 4.2731,11.0304C4.2389,11.0144 4.1947,11.0043 4.1483,11.0043C4.0981,11.0043 4.0544,11.0144 4.0197,11.0309C3.9824,11.0523 3.9349,11.0613 3.8827,11.0613L3.8763,11.0613L3.8763,10.9669L3.8827,10.9669C3.9307,10.9669 3.9787,10.9557 4.0128,10.9381C4.0496,10.9195 4.0949,10.9077 4.1472,10.9077C4.1952,10.9077 4.2421,10.9189 4.2784,10.9371C4.3141,10.9557 4.3595,10.9669 4.4085,10.9669C4.4565,10.9669 4.5035,10.9568 4.5376,10.9392C4.5744,10.9195 4.6224,10.9077 4.6731,10.9077C4.7232,10.9077 4.7712,10.9189 4.8064,10.9392C4.8411,10.9557 4.888,10.9669 4.9376,10.9669L4.9445,10.9669L4.9435,11.0613ZM4.1472,10.9904C4.1957,10.9904 4.2427,11.0016 4.2784,11.0187C4.3147,11.0384 4.36,11.048 4.4085,11.048C4.4565,11.048 4.5035,11.0395 4.5376,11.0197C4.5744,11.0032 4.6224,10.9904 4.6731,10.9904C4.7227,10.9904 4.7707,11.0027 4.8064,11.0197C4.8411,11.0384 4.8827,11.0469 4.9296,11.048L4.9307,10.9797C4.8816,10.9781 4.8347,10.9685 4.8,10.9509C4.7664,10.9323 4.7221,10.9216 4.6731,10.9216C4.6251,10.9216 4.5787,10.9323 4.544,10.9509C4.5072,10.9696 4.4597,10.9797 4.4085,10.9797C4.3584,10.9797 4.3099,10.9685 4.2725,10.9488C4.2379,10.9323 4.1941,10.9216 4.1477,10.9216C4.0976,10.9216 4.0539,10.9323 4.0192,10.9499C3.984,10.9685 3.9381,10.9797 3.8896,10.9808L3.8896,11.048C3.936,11.0469 3.9797,11.0373 4.0128,11.0197C4.0496,11.0021 4.0955,10.9904 4.1472,10.9904Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9365,11.1365C4.8848,11.1365 4.8379,11.1259 4.8037,11.1072C4.7701,11.0907 4.7243,11.0779 4.6731,11.0779C4.6224,11.0779 4.5749,11.0901 4.5408,11.1072C4.5061,11.1259 4.4597,11.1365 4.408,11.1365C4.3557,11.1365 4.3093,11.1243 4.2747,11.1061C4.2411,11.0907 4.1968,11.0779 4.1467,11.0779C4.0955,11.0779 4.0496,11.0901 4.0155,11.1072C3.9813,11.1248 3.9344,11.1365 3.8821,11.1365L3.8821,11.0565C3.9344,11.0565 3.9813,11.0443 4.0155,11.0261C4.0496,11.0075 4.0955,10.9968 4.1467,10.9968C4.1968,10.9968 4.2405,11.0075 4.2747,11.0251C4.3093,11.0432 4.3557,11.0549 4.408,11.0549C4.4592,11.0549 4.5061,11.0437 4.5408,11.0272C4.5749,11.0075 4.6219,10.9968 4.6731,10.9968C4.7243,10.9968 4.7696,11.0075 4.8037,11.0272C4.8379,11.0437 4.8848,11.0549 4.9371,11.0549L4.9365,11.1365" + android:strokeWidth="1" + android:fillColor="#005BBF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9435,11.144L4.9365,11.144C4.8848,11.144 4.8379,11.1328 4.8005,11.1147C4.7664,11.0949 4.7216,11.0853 4.6731,11.0853C4.6251,11.0853 4.5787,11.0949 4.544,11.1147C4.5067,11.1323 4.4597,11.144 4.4085,11.144C4.3589,11.144 4.3099,11.1328 4.2725,11.112C4.2379,11.0949 4.1941,11.0853 4.1477,11.0853C4.0976,11.0853 4.0539,11.0949 4.0192,11.1136C3.9819,11.1323 3.9344,11.144 3.8832,11.144L3.8763,11.144L3.8763,11.0491L3.8827,11.0491C3.9301,11.0491 3.9787,11.0395 4.0128,11.0197C4.0491,11.0021 4.0949,10.9904 4.1472,10.9904C4.1957,10.9904 4.2421,11.0016 4.2784,11.0187C4.3147,11.0384 4.36,11.048 4.4085,11.048C4.4565,11.048 4.5035,11.0395 4.5376,11.0197C4.5739,11.0032 4.6224,10.9904 4.6731,10.9904C4.7232,10.9904 4.7712,11.0027 4.8064,11.0197C4.8411,11.0395 4.888,11.048 4.9371,11.048L4.9445,11.048L4.9435,11.144ZM4.1472,11.072C4.1957,11.072 4.2421,11.0827 4.2784,11.1013C4.3152,11.12 4.3605,11.1301 4.4085,11.1301C4.4565,11.1301 4.5035,11.12 4.5376,11.1035C4.5744,11.0827 4.6224,11.072 4.6731,11.072C4.7232,11.072 4.7712,11.0827 4.8064,11.1035C4.8411,11.12 4.8832,11.1285 4.9296,11.1301L4.9301,11.0619C4.8816,11.0608 4.8357,11.0512 4.8,11.0315C4.7664,11.016 4.7221,11.0048 4.6731,11.0048C4.6251,11.0048 4.5787,11.016 4.544,11.0325C4.5072,11.0523 4.4597,11.0619 4.4085,11.0619C4.3589,11.0619 4.3099,11.0512 4.2725,11.0309C4.2379,11.0149 4.1941,11.0048 4.1477,11.0048C4.0976,11.0048 4.0539,11.0149 4.0192,11.0315C3.984,11.0512 3.9381,11.0619 3.8896,11.0629L3.8896,11.1301C3.9349,11.1285 3.9803,11.1189 4.0128,11.1024C4.0496,11.0821 4.0955,11.072 4.1472,11.072Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1125,10.3936C4.1147,10.4021 4.1168,10.4069 4.1168,10.4155C4.1168,10.4656 4.0747,10.5029 4.0224,10.5029L4.7979,10.5029C4.7461,10.5029 4.704,10.4656 4.704,10.4155C4.704,10.4069 4.704,10.4021 4.7067,10.3936C4.7019,10.3947 4.6965,10.3947 4.6912,10.3947L4.1264,10.3947C4.1221,10.3947 4.1163,10.3947 4.1125,10.3936" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.7979,10.5104L4.0224,10.5104C4.0192,10.5104 4.016,10.5072 4.016,10.5029C4.016,10.5008 4.0187,10.4955 4.0224,10.4955C4.0709,10.4955 4.1104,10.4592 4.1104,10.4155C4.1104,10.4091 4.1104,10.4053 4.1077,10.4011L4.1067,10.3947C4.1067,10.3936 4.1067,10.3904 4.1083,10.3904C4.1099,10.3883 4.1125,10.3872 4.1152,10.3883C4.1179,10.3904 4.1227,10.3904 4.1264,10.3904L4.6912,10.3904C4.6955,10.3904 4.7003,10.3904 4.7035,10.3883C4.7061,10.3872 4.7088,10.3883 4.7099,10.3904C4.7125,10.3904 4.7125,10.3936 4.7125,10.3947C4.7109,10.4032 4.7099,10.4069 4.7099,10.4155C4.7099,10.4592 4.7499,10.4955 4.7979,10.4955C4.8016,10.4955 4.8048,10.5008 4.8048,10.5029C4.8043,10.5072 4.8016,10.5104 4.7979,10.5104ZM4.0736,10.496L4.7477,10.496C4.7163,10.4816 4.6971,10.4512 4.6971,10.416C4.6971,10.4107 4.6976,10.4064 4.6976,10.4037C4.6955,10.4037 4.6944,10.4037 4.6912,10.4037L4.1264,10.4037C4.1253,10.4037 4.1237,10.4037 4.1221,10.4037C4.1221,10.4069 4.1232,10.4112 4.1232,10.416C4.1237,10.4512 4.1035,10.4811 4.0736,10.496Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1264,10.3435L4.6912,10.3435C4.7099,10.3435 4.7253,10.3547 4.7253,10.3701C4.7253,10.3824 4.7099,10.3952 4.6912,10.3952L4.1264,10.3952C4.1072,10.3952 4.0917,10.3829 4.0917,10.3701C4.0917,10.3547 4.1072,10.3435 4.1264,10.3435" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6912,10.4032L4.1264,10.4032C4.1035,10.4032 4.0848,10.3888 4.0848,10.3696C4.0848,10.352 4.1035,10.336 4.1264,10.336L4.6912,10.336C4.7136,10.336 4.7323,10.3515 4.7323,10.3696C4.7323,10.3888 4.7136,10.4032 4.6912,10.4032ZM4.1264,10.3499C4.1115,10.3499 4.0987,10.3573 4.0987,10.3696C4.0987,10.3808 4.1115,10.3904 4.1264,10.3904L4.6912,10.3904C4.7067,10.3904 4.7189,10.3803 4.7189,10.3696C4.7189,10.3573 4.7067,10.3499 4.6912,10.3499L4.1264,10.3499Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.0224,10.7029l0.7749,0l0,-0.2l-0.7749,0z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.8037,10.7072L4.016,10.7072L4.016,10.496L4.8037,10.496L4.8037,10.7072ZM4.0293,10.6949L4.7909,10.6949L4.7909,10.5104L4.0293,10.5104L4.0293,10.6949Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.9627,9.6448C3.8859,9.6896 3.8347,9.7323 3.8421,9.7563C3.8469,9.7781 3.8709,9.7931 3.9061,9.8155C3.9595,9.8528 3.9936,9.9205 3.9675,9.9531C4.0123,9.9157 4.0411,9.8624 4.0411,9.8032C4.0411,9.7387 4.0117,9.6811 3.9627,9.6448" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.9723,9.9573L3.9627,9.9488C3.9707,9.9403 3.9707,9.928 3.9691,9.9168C3.9653,9.8837 3.9376,9.8443 3.9024,9.8192L3.8987,9.8187C3.8656,9.7947 3.8416,9.7808 3.8363,9.7573C3.8229,9.72 3.9275,9.6571 3.96,9.6395L3.9627,9.6363L3.9659,9.6405C4.0187,9.6779 4.0475,9.7376 4.0475,9.8032C4.048,9.8624 4.0203,9.9189 3.9723,9.9573ZM3.9627,9.6533C3.8805,9.7003 3.8437,9.7408 3.8485,9.7536C3.8528,9.7723 3.8752,9.7877 3.9061,9.808L3.9093,9.8101C3.9477,9.8384 3.9781,9.8805 3.9819,9.9163C3.9829,9.9205 3.9829,9.9269 3.9824,9.9301C4.0155,9.8955 4.0341,9.8501 4.0341,9.8037C4.0347,9.7435 4.0091,9.6896 3.9627,9.6533Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1349,10.3104l0.5493,0l0,-2.6933l-0.5493,0z" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.5941,10.3072L4.5813,10.3072L4.5813,7.6197L4.5936,7.6197L4.5936,10.3072L4.5941,10.3072ZM4.5323,10.3072L4.5195,10.3072L4.5195,7.6197L4.5323,7.6197L4.5323,10.3072Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6912,10.3184L4.128,10.3184L4.128,7.6096L4.6912,7.6096L4.6912,10.3184ZM4.1413,10.3045L4.6779,10.3045L4.6779,7.6229L4.1413,7.6229L4.1413,10.3045Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.2459,8.6251C5.1253,8.5749 4.9227,8.5397 4.688,8.5307C4.6069,8.5312 4.5168,8.5397 4.4245,8.5547C4.0949,8.6075 3.8443,8.7408 3.8651,8.8459C3.8656,8.8501 3.8661,8.8549 3.8661,8.8565C3.8661,8.8565 3.7435,8.5787 3.7413,8.5685C3.7189,8.4491 3.9973,8.3035 4.3632,8.2427C4.4768,8.2235 4.5883,8.216 4.6853,8.2176C4.9195,8.2176 5.1227,8.2464 5.2448,8.2928L5.2459,8.6251" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.8661,8.8635C3.8635,8.8635 3.8613,8.8613 3.8597,8.8571C3.8395,8.8123 3.7365,8.5792 3.7349,8.5685C3.7296,8.5445 3.7376,8.5184 3.7563,8.4917C3.8293,8.3872 4.0725,8.2816 4.3611,8.2352C4.4624,8.2187 4.5696,8.2091 4.6693,8.2091L4.6853,8.2091C4.9099,8.2091 5.1195,8.2395 5.2475,8.2853C5.2496,8.2875 5.2512,8.2907 5.2512,8.2923L5.2533,8.6251C5.2533,8.6283 5.2512,8.6283 5.2501,8.6309C5.248,8.6315 5.2453,8.6315 5.2437,8.6315C5.12,8.5797 4.912,8.5451 4.688,8.5376C4.6043,8.5387 4.5136,8.5451 4.4256,8.5605C4.1696,8.6032 3.9531,8.6939 3.888,8.7856C3.8731,8.8075 3.8677,8.8283 3.8715,8.8448C3.8715,8.848 3.8725,8.8533 3.8725,8.8549C3.8731,8.8576 3.8725,8.8619 3.8693,8.864C3.8677,8.8635 3.8667,8.8635 3.8661,8.8635ZM4.6688,8.2229C4.5685,8.2229 4.4624,8.2325 4.3627,8.2491C4.0784,8.2949 3.8379,8.3957 3.7659,8.5003C3.7499,8.5232 3.7435,8.5451 3.7472,8.5659C3.7499,8.5765 3.8096,8.7157 3.8581,8.8203C3.8603,8.808 3.8667,8.7941 3.8773,8.7787C3.944,8.6827 4.1627,8.5909 4.4224,8.5472C4.5125,8.5328 4.6037,8.5253 4.688,8.5243C4.9083,8.5317 5.1131,8.5659 5.2389,8.616L5.2384,8.296C5.1109,8.2523 4.9051,8.2229 4.6853,8.2229L4.6688,8.2229Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1333,8.9637C3.9813,8.9531 3.8768,8.9104 3.8651,8.8459C3.8555,8.7947 3.9067,8.7408 3.9989,8.6907C4.0405,8.6939 4.0864,8.6997 4.1349,8.6997L4.1333,8.9637" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.1397,8.9696L4.1323,8.9696C3.9701,8.9573 3.8699,8.9141 3.8581,8.8475C3.848,8.7941 3.8976,8.7381 3.9957,8.6816L3.9973,8.6816L4.0128,8.6816C4.0501,8.688 4.0912,8.6928 4.1349,8.6928L4.1413,8.6928L4.1397,8.9696ZM4,8.6949C3.9083,8.7461 3.8624,8.8011 3.8709,8.8448C3.8811,8.9029 3.9765,8.944 4.1259,8.9563L4.1269,8.7061C4.0859,8.7056 4.0469,8.7019 4.0107,8.6955L4,8.6949Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6848,8.7573C4.7803,8.7696 4.8517,8.7947 4.888,8.824L4.8912,8.8299C4.9072,8.8656 4.824,8.9408 4.6848,9.0197L4.6848,8.7573" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.6779,9.0325L4.6789,8.7493L4.6859,8.7515C4.7819,8.7659 4.856,8.7909 4.8912,8.8192L4.8939,8.8203L4.8971,8.8288C4.9227,8.8816 4.7595,8.9851 4.688,9.0288L4.6779,9.0325ZM4.6912,8.7659L4.6912,9.0096C4.8507,8.9157 4.8955,8.8549 4.8848,8.8325L4.8816,8.8283C4.848,8.8032 4.7813,8.7781 4.6912,8.7659Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.7909,9.4821C3.7771,9.4405 3.9248,9.3531 4.1355,9.2747C4.2315,9.2405 4.3109,9.2043 4.4096,9.1611C4.7008,9.032 4.9163,8.8821 4.8907,8.8304L4.8875,8.8245C4.9029,8.8368 4.9269,9.1024 4.9269,9.1024C4.9531,9.1525 4.7557,9.2981 4.4869,9.4272C4.4005,9.4677 4.2192,9.5344 4.1339,9.5648C3.9803,9.6181 3.8277,9.7179 3.8416,9.7552L3.7909,9.4821" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.8427,9.7637C3.8405,9.7637 3.8379,9.7616 3.8368,9.7573C3.8357,9.7573 3.8352,9.7547 3.8352,9.7531L3.7851,9.4821C3.7669,9.4304 3.9477,9.3376 4.1339,9.2688C4.2213,9.2373 4.2949,9.2048 4.3813,9.1659L4.4064,9.1557C4.6597,9.0437 4.8597,8.9157 4.8848,8.8501C4.8869,8.8432 4.8869,8.8379 4.8848,8.8325L4.8816,8.8283C4.8805,8.8251 4.8816,8.8197 4.8837,8.8197C4.8853,8.8171 4.8896,8.8171 4.8912,8.8197C4.8933,8.8197 4.8944,8.8208 4.8955,8.8261L4.8971,8.8283C4.8976,8.8299 4.8987,8.8325 4.8997,8.8357C4.9131,8.8869 4.9285,9.0325 4.9344,9.1035C4.9381,9.1077 4.9381,9.1157 4.9349,9.1275C4.9131,9.1909 4.7259,9.32 4.4912,9.4325C4.4075,9.472 4.2288,9.5408 4.1365,9.5712C3.9877,9.6235 3.8485,9.7157 3.8475,9.7525L3.8485,9.7563C3.8496,9.7579 3.8469,9.7627 3.8432,9.7643C3.8443,9.7637 3.8437,9.7637 3.8427,9.7637ZM4.8923,8.8656C4.8539,8.9344 4.6603,9.0571 4.4128,9.1669L4.3867,9.1781C4.3003,9.2155 4.2256,9.2501 4.1381,9.2811C3.904,9.3669 3.7883,9.448 3.7979,9.4805C3.7979,9.4811 3.7979,9.4821 3.7979,9.4821L3.8443,9.728C3.8795,9.6779 4.016,9.6 4.1317,9.5584C4.2256,9.528 4.4032,9.4603 4.4853,9.4197C4.7141,9.3115 4.9019,9.1824 4.9227,9.1205C4.9237,9.1152 4.9237,9.1093 4.9221,9.1061C4.9216,9.1056 4.9211,9.1045 4.9211,9.1029C4.9131,9.0144 4.9008,8.9157 4.8923,8.8656Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.0965,8.4949C4.1632,8.4699 4.2069,8.4421 4.1856,8.3909C4.1728,8.3563 4.1381,8.3493 4.0853,8.3685L3.9941,8.4021L4.0763,8.6059C4.0853,8.6021 4.0944,8.5957 4.104,8.5941C4.1131,8.5909 4.1227,8.5888 4.1323,8.5835L4.0965,8.4949L4.0965,8.4949ZM4.0565,8.3957L4.0789,8.3893C4.0987,8.3808 4.1205,8.3904 4.1301,8.4155C4.1376,8.432 4.1349,8.4528 4.1125,8.4683C4.1061,8.4709 4.0971,8.4763 4.0896,8.4784L4.0565,8.3957M4.3109,8.3115C4.3013,8.3157 4.2912,8.3173 4.2816,8.3189C4.2725,8.32 4.2629,8.3211 4.2523,8.3232L4.3003,8.5344L4.4475,8.5061C4.4464,8.5029 4.4437,8.4955 4.4437,8.4933C4.4416,8.4896 4.4421,8.4821 4.4416,8.4784C4.416,8.4869 4.3877,8.4949 4.3536,8.5024L4.3109,8.3115M4.608,8.4949C4.6357,8.4181 4.6693,8.344 4.704,8.2688C4.6976,8.2699 4.6917,8.2699 4.6853,8.2699C4.6789,8.2699 4.6731,8.2699 4.6667,8.2699C4.6491,8.3259 4.6272,8.3797 4.6043,8.4325C4.576,8.3824 4.5445,8.3323 4.5221,8.2816C4.5104,8.2827 4.4981,8.2827 4.4869,8.2848C4.4757,8.2859 4.4635,8.2859 4.4512,8.2859C4.4949,8.3563 4.5355,8.4256 4.5749,8.4955C4.5797,8.4955 4.5856,8.4955 4.5915,8.4944C4.5973,8.4939 4.6027,8.4939 4.608,8.4949M4.9184,8.3312C4.9232,8.32 4.9291,8.3104 4.9349,8.3019C4.9259,8.2933 4.9013,8.2821 4.8725,8.2795C4.8133,8.2736 4.7787,8.3008 4.7739,8.3371C4.7653,8.4144 4.8853,8.4069 4.8811,8.4571C4.8789,8.4795 4.8549,8.4896 4.8304,8.4853C4.8032,8.4821 4.7824,8.4683 4.7787,8.4448L4.7717,8.4448C4.7675,8.4571 4.7621,8.4699 4.7557,8.4821C4.7728,8.4944 4.7968,8.5029 4.8187,8.5029C4.88,8.5093 4.9269,8.4843 4.9323,8.4448C4.9397,8.3707 4.8176,8.368 4.8229,8.3259C4.8251,8.3072 4.8384,8.2944 4.8699,8.2976C4.8923,8.3019 4.9072,8.3131 4.9131,8.3307L4.9184,8.3312" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.456,6.9989C9.456,6.9989 9.4315,7.0261 9.4133,7.0283C9.3947,7.0325 9.3723,7.0139 9.3723,7.0139C9.3723,7.0139 9.3557,7.0299 9.3355,7.0336C9.3157,7.0411 9.2885,7.0117 9.2885,7.0117C9.2885,7.0117 9.2688,7.0411 9.2512,7.0453C9.2347,7.0539 9.2139,7.0379 9.2139,7.0379C9.2139,7.0379 9.2059,7.0512 9.192,7.0576C9.1856,7.0608 9.1755,7.0565 9.1755,7.0565L9.1541,7.0443L9.1317,7.0192L9.1099,7.0107C9.1099,7.0107 9.1003,6.9797 9.1003,6.9755C9.0992,6.9691 9.0976,6.9563 9.0976,6.9563C9.0928,6.9328 9.1264,6.9077 9.1755,6.8965C9.2032,6.8912 9.2267,6.8912 9.2443,6.8955C9.2635,6.8816 9.3045,6.8693 9.3541,6.8693C9.3973,6.8693 9.4352,6.8789 9.456,6.8928C9.4763,6.8789 9.5147,6.8693 9.5584,6.8693C9.6069,6.8693 9.6475,6.8811 9.6667,6.8955C9.6848,6.8912 9.7083,6.8912 9.736,6.8965C9.7851,6.9077 9.8187,6.9328 9.8139,6.9563C9.8139,6.9563 9.8128,6.9691 9.8112,6.9755C9.8107,6.9803 9.8005,7.0107 9.8005,7.0107L9.7792,7.0192L9.7568,7.0443L9.7365,7.0565C9.7365,7.0565 9.7259,7.0608 9.72,7.0576C9.7067,7.0512 9.6976,7.0379 9.6976,7.0379C9.6976,7.0379 9.6768,7.0533 9.6597,7.0453C9.6427,7.0411 9.6235,7.0117 9.6235,7.0117C9.6235,7.0117 9.5963,7.0411 9.5755,7.0336C9.5563,7.0299 9.5397,7.0139 9.5397,7.0139C9.5397,7.0139 9.5168,7.0325 9.4987,7.0283C9.4805,7.0261 9.456,6.9989 9.456,6.9989" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7259,7.0645C9.7232,7.0645 9.7205,7.0635 9.7195,7.0624C9.7077,7.056 9.7008,7.048 9.6976,7.0437C9.6912,7.0448 9.6811,7.0533 9.6693,7.0533C9.6667,7.0533 9.6624,7.0523 9.6587,7.0501C9.6443,7.0437 9.6288,7.0283 9.6229,7.0187C9.616,7.0261 9.5979,7.0405 9.5813,7.0405C9.5792,7.0405 9.5771,7.0405 9.576,7.0395C9.5595,7.0341 9.5451,7.024 9.5397,7.0187C9.5323,7.0245 9.5136,7.0363 9.4981,7.032C9.4821,7.0304 9.4635,7.0133 9.4565,7.0053C9.448,7.0133 9.4293,7.0304 9.4133,7.032C9.3979,7.0363 9.3792,7.024 9.3728,7.0187C9.3664,7.024 9.3525,7.0341 9.336,7.0395C9.3355,7.0405 9.3317,7.0405 9.3301,7.0405C9.3136,7.0405 9.2955,7.0261 9.288,7.0187C9.2816,7.0283 9.2661,7.0437 9.2528,7.0501C9.2491,7.0523 9.2448,7.0533 9.2416,7.0533C9.2304,7.0533 9.2192,7.0448 9.2139,7.0437C9.2101,7.048 9.2037,7.056 9.1931,7.0624C9.1851,7.0656 9.1733,7.0603 9.1728,7.0592L9.1504,7.0448L9.1285,7.0219L9.1061,7.0155L9.1061,7.0123C9.1045,7.0069 9.096,6.9808 9.0944,6.976C9.0939,6.9696 9.0917,6.9563 9.0917,6.9563C9.0875,6.9312 9.1221,6.9029 9.1733,6.8933C9.2,6.8864 9.2245,6.8864 9.2437,6.8907C9.2651,6.8752 9.3061,6.8656 9.3536,6.8656C9.3941,6.8656 9.432,6.872 9.4555,6.8869C9.4784,6.872 9.5157,6.8656 9.5579,6.8656C9.6032,6.8656 9.6453,6.8752 9.6667,6.8907C9.6859,6.8864 9.7104,6.8864 9.7371,6.8933C9.7877,6.9035 9.8224,6.9312 9.8187,6.9563L9.816,6.976C9.8144,6.9813 9.8064,7.0075 9.8043,7.0123L9.8037,7.0155L9.7813,7.0219L9.7589,7.0459L9.7381,7.0581C9.7381,7.0592 9.7323,7.0645 9.7259,7.0645ZM9.7008,7.0309L9.7024,7.0336C9.7024,7.0347 9.7104,7.0459 9.7227,7.0533C9.7227,7.0533 9.7237,7.0549 9.7253,7.0549C9.7285,7.0549 9.7333,7.0533 9.7349,7.0533L9.7536,7.0411L9.7776,7.016L9.7973,7.0075C9.8,6.9968 9.8059,6.9781 9.8064,6.9739L9.8096,6.9547C9.8123,6.9344 9.7792,6.9115 9.7344,6.9029C9.7093,6.8944 9.6843,6.8944 9.6667,6.9019L9.6651,6.9029L9.6624,6.9008C9.6437,6.8821 9.6032,6.8725 9.5579,6.8725C9.5157,6.8725 9.4784,6.8821 9.4576,6.8944L9.4555,6.8965L9.4533,6.8944C9.4309,6.8821 9.3936,6.8725 9.3531,6.8725C9.3072,6.8725 9.2656,6.8821 9.2469,6.9008L9.2453,6.9029L9.2432,6.9019C9.2251,6.8944 9.2005,6.8944 9.1749,6.9029C9.1312,6.9115 9.0971,6.9344 9.1003,6.9547C9.1003,6.9547 9.1029,6.9685 9.1029,6.9739C9.104,6.9781 9.1099,6.9968 9.1131,7.0075L9.1344,7.016L9.1563,7.0411L9.1765,7.0533C9.1781,7.0533 9.1851,7.056 9.1877,7.0533C9.2005,7.0459 9.2085,7.0347 9.2085,7.0336L9.2107,7.0309L9.2149,7.0325C9.2155,7.0325 9.2283,7.0427 9.2405,7.0427C9.2432,7.0427 9.2469,7.0427 9.2485,7.0411C9.264,7.0347 9.2821,7.0085 9.2827,7.0075L9.2853,7.0048L9.2896,7.0075C9.2901,7.0075 9.312,7.0309 9.3291,7.0309C9.3307,7.0309 9.3312,7.0309 9.3333,7.0299C9.3515,7.0261 9.3669,7.0085 9.3675,7.0085L9.3701,7.0064L9.3733,7.0075C9.3739,7.0085 9.3947,7.0283 9.4101,7.0251C9.424,7.0197 9.4437,7.0032 9.4507,6.9947L9.4523,6.9947L9.4555,6.9947L9.4576,6.9947C9.4581,6.9947 9.4805,7.0197 9.4981,7.0251C9.5147,7.0283 9.5349,7.0085 9.5349,7.0075L9.5381,7.0064L9.5408,7.0085C9.5408,7.0085 9.5563,7.0261 9.5744,7.0299C9.5765,7.0309 9.5765,7.0309 9.5787,7.0309C9.5952,7.0309 9.6176,7.0075 9.6181,7.0075L9.6224,7.0048L9.6256,7.0075C9.6256,7.0085 9.6437,7.0347 9.6597,7.0411C9.6613,7.0427 9.664,7.0427 9.6672,7.0427C9.68,7.0427 9.6933,7.0325 9.6939,7.0325L9.7008,7.0309Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4085,6.856C9.4085,6.8197 9.4293,6.7904 9.4544,6.7904C9.4805,6.7904 9.5008,6.8197 9.5008,6.856C9.5008,6.8928 9.4805,6.9216 9.4544,6.9216C9.4293,6.9221 9.4085,6.8933 9.4085,6.856" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4549,6.928C9.4267,6.928 9.4043,6.8944 9.4043,6.856C9.4043,6.8171 9.4267,6.784 9.4549,6.784C9.4832,6.784 9.5067,6.8171 9.5067,6.856C9.5067,6.8949 9.4832,6.928 9.4549,6.928ZM9.4549,6.7936C9.4325,6.7936 9.4133,6.8208 9.4133,6.856C9.4133,6.8901 9.432,6.9184 9.4549,6.9184C9.4795,6.9184 9.4981,6.8901 9.4981,6.856C9.4981,6.8208 9.4789,6.7936 9.4549,6.7936Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4352,6.856C9.4352,6.8219 9.4443,6.7947 9.456,6.7947C9.4672,6.7947 9.4773,6.8219 9.4773,6.856C9.4773,6.8901 9.4677,6.9168 9.456,6.9168C9.4443,6.9173 9.4352,6.8907 9.4352,6.856" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.456,6.92C9.4384,6.92 9.4299,6.8885 9.4299,6.8565C9.4299,6.8251 9.4389,6.7909 9.456,6.7909C9.4725,6.7909 9.4816,6.8235 9.4816,6.8565C9.4816,6.8896 9.4731,6.92 9.456,6.92ZM9.456,6.8C9.4485,6.8 9.4379,6.8197 9.4379,6.856C9.4379,6.8901 9.4485,6.9131 9.456,6.9131C9.4629,6.9131 9.4725,6.8901 9.4725,6.856C9.4731,6.8197 9.4635,6.8 9.456,6.8Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.216,7.128C9.2091,7.1072 9.1957,7.0923 9.1957,7.0923C9.2619,7.072 9.3541,7.0592 9.4555,7.0592C9.5568,7.0592 9.6501,7.0715 9.7168,7.0923C9.7168,7.0923 9.7083,7.1045 9.6981,7.1221C9.6923,7.1328 9.6859,7.1515 9.6859,7.1515C9.6261,7.1328 9.5499,7.1221 9.4555,7.1221C9.3611,7.1221 9.2704,7.1328 9.2235,7.1536C9.2235,7.1531 9.2197,7.1408 9.216,7.128L9.216,7.128" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.2229,7.1563L9.2229,7.1531L9.2229,7.1531L9.2197,7.1531C9.2192,7.1509 9.2171,7.1429 9.2107,7.1307L9.2091,7.1237L9.2096,7.1237C9.2027,7.1072 9.1925,7.0944 9.192,7.0944L9.1883,7.0901L9.1947,7.088C9.2635,7.0667 9.3573,7.0555 9.4555,7.0555C9.5547,7.0555 9.648,7.0667 9.7168,7.088L9.7232,7.0901L9.7019,7.1253C9.6976,7.1317 9.6907,7.1483 9.6901,7.1515L9.6864,7.1504L9.6848,7.1541C9.6256,7.136 9.5483,7.1275 9.4555,7.1275C9.3637,7.1275 9.2736,7.1387 9.2261,7.1552L9.2256,7.1557L9.2229,7.1557L9.2229,7.1563ZM9.2219,7.1323C9.2235,7.1397 9.2256,7.1435 9.2256,7.1445C9.2757,7.128 9.3637,7.1184 9.4549,7.1184C9.5467,7.1184 9.6229,7.128 9.6821,7.1445C9.6843,7.1403 9.6885,7.1323 9.6944,7.1195L9.7093,7.0944C9.6416,7.0757 9.5504,7.0651 9.4549,7.0651C9.36,7.0651 9.2704,7.0757 9.2027,7.0944C9.2064,7.1019 9.2144,7.1141 9.2187,7.128L9.2219,7.1323L9.2219,7.1323Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4555,7.2123C9.5381,7.2123 9.6293,7.2 9.6624,7.1904C9.6848,7.1829 9.6981,7.1749 9.6949,7.1632C9.6949,7.1568 9.6885,7.1525 9.6827,7.1499C9.6336,7.1323 9.5451,7.1216 9.456,7.1216C9.3669,7.1216 9.2784,7.1323 9.2299,7.1499C9.2229,7.1531 9.2176,7.1573 9.2176,7.1632C9.2144,7.1744 9.2272,7.1829 9.2496,7.1904C9.2821,7.2 9.3728,7.2123 9.4555,7.2123" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4555,7.2155L9.4555,7.2155C9.3728,7.2155 9.2821,7.2032 9.248,7.1947C9.2128,7.184 9.2107,7.1696 9.2117,7.1621C9.2133,7.1552 9.2192,7.1488 9.2261,7.1445C9.2795,7.128 9.3685,7.1184 9.456,7.1184C9.5435,7.1184 9.6325,7.128 9.6843,7.1445C9.6923,7.1488 9.6981,7.1557 9.6997,7.1621C9.7013,7.1696 9.6987,7.184 9.664,7.1947C9.6293,7.2032 9.5376,7.2155 9.4555,7.2155ZM9.4555,7.128C9.3696,7.128 9.28,7.1387 9.2293,7.1531C9.2251,7.1563 9.2208,7.1584 9.2197,7.1643C9.2192,7.1707 9.2293,7.1808 9.2512,7.1867C9.2848,7.1947 9.3744,7.2069 9.456,7.2069C9.5371,7.2069 9.6272,7.1947 9.6608,7.1867C9.6827,7.1808 9.6923,7.1707 9.6912,7.1643C9.6901,7.1579 9.6859,7.1557 9.6811,7.1531C9.6309,7.1387 9.5419,7.128 9.4555,7.128Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6549,6.8853C9.6549,6.8779 9.6624,6.8699 9.6699,6.8699C9.6795,6.8699 9.6853,6.8784 9.6853,6.8853C9.6853,6.8939 9.6789,6.9008 9.6699,6.9008C9.6624,6.9008 9.6549,6.8939 9.6549,6.8853" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8069,6.9893C9.8059,6.9893 9.8048,6.9893 9.8043,6.9893C9.8027,6.9872 9.8011,6.9829 9.8021,6.9819C9.8069,6.9696 9.8096,6.9579 9.8096,6.9467C9.8096,6.8944 9.7685,6.8544 9.7184,6.8544C9.7029,6.8544 9.688,6.8571 9.6736,6.8656C9.6725,6.8683 9.6699,6.8672 9.6677,6.8656C9.6667,6.8635 9.6672,6.8592 9.6693,6.8571C9.6843,6.8507 9.7008,6.8448 9.7179,6.8448C9.7728,6.8448 9.8181,6.8907 9.8181,6.9467C9.8181,6.96 9.816,6.9728 9.8101,6.9851C9.8107,6.9888 9.8075,6.9893 9.8069,6.9893ZM9.64,6.9184L9.632,6.9147C9.6373,6.9045 9.6405,6.8949 9.6405,6.8864C9.6405,6.8501 9.6021,6.8197 9.5552,6.8197C9.5355,6.8197 9.5168,6.8261 9.5019,6.8341L9.4981,6.8277C9.5136,6.8165 9.5344,6.8112 9.5552,6.8112C9.6075,6.8112 9.6491,6.8448 9.6491,6.8864C9.6485,6.8949 9.6453,6.9072 9.64,6.9184Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7195,7.0555L9.6997,7.0373C9.6997,7.0373 9.6805,7.0485 9.6565,7.0448C9.632,7.0405 9.6251,7.0133 9.6251,7.0133C9.6251,7.0133 9.5973,7.0341 9.5749,7.032C9.5531,7.0309 9.5397,7.0133 9.5397,7.0133C9.5397,7.0133 9.5163,7.0293 9.4939,7.0277C9.4731,7.0267 9.4533,6.9995 9.4533,6.9995C9.4533,6.9995 9.4315,7.0277 9.4112,7.0277C9.3909,7.0309 9.3728,7.0101 9.3728,7.0101C9.3728,7.0101 9.3627,7.0309 9.3371,7.0341C9.3099,7.0405 9.2875,7.0155 9.2875,7.0155C9.2875,7.0155 9.272,7.0405 9.2533,7.0448C9.2347,7.0533 9.2117,7.0352 9.2117,7.0352C9.2117,7.0352 9.2075,7.0448 9.2048,7.0507C9.2021,7.056 9.1936,7.0571 9.1936,7.0571L9.2,7.0725C9.2661,7.0528 9.3547,7.0416 9.4555,7.0416C9.5563,7.0416 9.6475,7.0528 9.7125,7.0725L9.7195,7.0555" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7168,7.0779L9.712,7.0779C9.6448,7.0571 9.5541,7.0453 9.456,7.0443C9.3605,7.0453 9.2693,7.0565 9.2021,7.0779L9.1979,7.0779L9.1883,7.0528L9.1947,7.0528C9.1957,7.0528 9.2011,7.0517 9.2016,7.0475C9.2043,7.0432 9.2085,7.0331 9.2085,7.0331L9.2107,7.0293L9.2149,7.032C9.2149,7.032 9.2304,7.0421 9.2448,7.0421C9.248,7.0421 9.2512,7.0421 9.2533,7.0405C9.2699,7.0341 9.2843,7.0123 9.2843,7.0123L9.2869,7.0069L9.2917,7.0112C9.2917,7.0112 9.3136,7.0331 9.3365,7.0309C9.3605,7.0277 9.3696,7.0069 9.3696,7.0069L9.3728,7.0027L9.3765,7.0069C9.3765,7.0069 9.3925,7.0267 9.4112,7.0245C9.4304,7.0213 9.4507,6.9963 9.4507,6.9952L9.4539,6.9925L9.4565,6.9952C9.4565,6.9963 9.4757,7.0203 9.4944,7.0235C9.496,7.0235 9.4971,7.0235 9.4971,7.0235C9.5157,7.0235 9.5371,7.0069 9.5376,7.0069L9.5408,7.0059L9.5429,7.0091C9.5435,7.0091 9.5557,7.0277 9.5755,7.0277C9.576,7.0277 9.5771,7.0277 9.5781,7.0277C9.5968,7.0277 9.6219,7.008 9.6219,7.008L9.6267,7.0043L9.6277,7.0112C9.6277,7.0117 9.6352,7.0384 9.6555,7.0405C9.6779,7.0437 9.6965,7.032 9.6965,7.032L9.6992,7.0309L9.72,7.0517L9.7243,7.0517L9.7168,7.0779ZM9.456,7.0384C9.552,7.0384 9.6421,7.0491 9.7104,7.0683L9.7147,7.0565L9.6992,7.0427C9.6944,7.0453 9.6821,7.0517 9.6667,7.0517C9.6635,7.0517 9.6597,7.0517 9.656,7.0507C9.6363,7.0453 9.6261,7.0304 9.6224,7.0203C9.6128,7.0288 9.5941,7.0411 9.5755,7.0389C9.5573,7.0368 9.544,7.0251 9.5387,7.0192C9.5317,7.0235 9.5125,7.0325 9.4944,7.0325C9.4768,7.0315 9.4603,7.016 9.4539,7.0075C9.4469,7.016 9.4293,7.0315 9.4123,7.0325C9.4107,7.0325 9.4101,7.0325 9.4091,7.0325C9.3941,7.0325 9.3803,7.0229 9.3744,7.0187C9.3691,7.0256 9.3579,7.0357 9.3381,7.0411C9.3163,7.0437 9.2965,7.0288 9.288,7.0203C9.2821,7.0288 9.2699,7.0443 9.2555,7.0501C9.2523,7.0517 9.248,7.0528 9.2443,7.0528C9.232,7.0528 9.2203,7.0453 9.2139,7.0427C9.2133,7.0453 9.2107,7.0507 9.2096,7.0539C9.2069,7.0571 9.2043,7.0581 9.2005,7.0603L9.2037,7.0693C9.2731,7.0491 9.3611,7.0384 9.456,7.0384Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.2229,6.8853C9.2229,6.8779 9.2299,6.8699 9.2384,6.8699C9.248,6.8699 9.2544,6.8784 9.2544,6.8853C9.2544,6.8939 9.248,6.9008 9.2384,6.9008C9.2299,6.9008 9.2229,6.8939 9.2229,6.8853" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1029,6.9893C9.1008,6.9893 9.0997,6.9883 9.0981,6.9851C9.0939,6.9728 9.0917,6.9589 9.0917,6.9467C9.0917,6.8907 9.1355,6.8448 9.192,6.8448C9.2075,6.8448 9.2256,6.8512 9.24,6.8571C9.2421,6.8592 9.2427,6.8635 9.2421,6.8656C9.2411,6.8672 9.2384,6.8683 9.2357,6.8656C9.2224,6.8571 9.2075,6.8544 9.192,6.8544C9.1413,6.8544 9.1003,6.8944 9.1003,6.9467C9.1003,6.9579 9.1024,6.9696 9.1072,6.9819C9.1072,6.984 9.1072,6.9872 9.1045,6.9893C9.104,6.9893 9.104,6.9893 9.1029,6.9893ZM9.2699,6.9173C9.2651,6.9072 9.2603,6.896 9.2603,6.8864C9.2603,6.8448 9.3019,6.8112 9.3541,6.8112C9.3755,6.8112 9.3947,6.8171 9.4117,6.8277L9.4069,6.8341C9.3915,6.8256 9.3728,6.8197 9.3541,6.8197C9.3072,6.8197 9.2693,6.8501 9.2693,6.8864C9.2693,6.8949 9.2725,6.9029 9.2784,6.9125L9.2699,6.9173Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4565,6.968L9.4661,6.9696C9.464,6.9728 9.4635,6.9781 9.4635,6.9819C9.4635,7.0027 9.4811,7.0176 9.5008,7.0176C9.5184,7.0176 9.5323,7.0064 9.5376,6.9925C9.5381,6.9931 9.5413,6.9792 9.5419,6.9803C9.544,6.9803 9.5435,6.9931 9.544,6.9931C9.5461,7.0107 9.5627,7.0235 9.5813,7.0235C9.6016,7.0235 9.6187,7.0069 9.6187,6.9893C9.6187,6.9867 9.6187,6.984 9.6187,6.9819L9.6299,6.9707L9.6363,6.9872C9.6341,6.9904 9.6325,6.9957 9.6325,7.0027C9.6325,7.0192 9.6491,7.0363 9.6688,7.0363C9.6811,7.0363 9.6923,7.0304 9.6987,7.0192L9.7067,7.0117L9.7067,7.0229C9.7067,7.0341 9.7115,7.0437 9.7227,7.0469C9.7227,7.0469 9.736,7.048 9.7541,7.0336C9.7723,7.0192 9.7819,7.0075 9.7819,7.0075L9.7819,7.0229C9.7819,7.0229 9.7653,7.0523 9.7493,7.0603C9.7413,7.0645 9.7275,7.0688 9.7168,7.0688C9.7067,7.0672 9.6981,7.0576 9.6944,7.048C9.6864,7.0523 9.6773,7.0555 9.6672,7.0555C9.6464,7.0555 9.6267,7.0443 9.6192,7.0272C9.6101,7.0379 9.5963,7.0427 9.5797,7.0427C9.5632,7.0427 9.5477,7.0352 9.5381,7.024C9.5291,7.0315 9.5152,7.0395 9.5008,7.0395C9.4821,7.0395 9.4656,7.0283 9.456,7.0144C9.4464,7.0283 9.4293,7.0395 9.4107,7.0395C9.3968,7.0395 9.3835,7.0309 9.3733,7.024C9.3632,7.0352 9.3483,7.0427 9.3323,7.0427C9.3157,7.0427 9.3013,7.0373 9.2917,7.0272C9.2848,7.0437 9.2656,7.0555 9.2448,7.0555C9.2347,7.0555 9.2261,7.0523 9.2171,7.048C9.2139,7.0576 9.2053,7.0672 9.1947,7.0688C9.184,7.0688 9.1707,7.0645 9.1627,7.0603C9.1467,7.0517 9.1285,7.0229 9.1285,7.0229L9.1301,7.0075C9.1301,7.0075 9.1403,7.0187 9.1573,7.0336C9.176,7.048 9.1888,7.0469 9.1888,7.0469C9.2005,7.0437 9.2048,7.0347 9.2048,7.0229L9.2048,7.0117L9.2133,7.0192C9.2203,7.0304 9.2299,7.0363 9.2421,7.0363C9.2629,7.0363 9.2795,7.0192 9.2795,7.0027C9.2795,6.9952 9.2773,6.9904 9.2752,6.9872L9.2816,6.9707L9.2928,6.9819C9.2923,6.984 9.2923,6.9867 9.2923,6.9893C9.2923,7.0069 9.3099,7.0235 9.3296,7.0235C9.3483,7.0235 9.3648,7.0112 9.3669,6.9931C9.368,6.9931 9.3675,6.9803 9.3696,6.9803C9.3707,6.9792 9.3733,6.9931 9.3744,6.9925C9.3792,7.0064 9.3941,7.0176 9.4107,7.0176C9.4315,7.0176 9.448,7.0027 9.448,6.9819C9.448,6.9776 9.448,6.9723 9.4464,6.9696L9.4565,6.968" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7221,7.0752C9.7195,7.0752 9.7189,7.0752 9.7168,7.0741C9.7072,7.072 9.6981,7.0656 9.6928,7.056C9.6859,7.0576 9.6763,7.0608 9.6677,7.0608C9.648,7.0608 9.6288,7.0512 9.6192,7.0336C9.608,7.0443 9.5952,7.0491 9.5803,7.0491C9.5637,7.0491 9.5483,7.0421 9.5387,7.0315C9.5275,7.0411 9.5147,7.0437 9.5013,7.0437C9.4837,7.0437 9.4672,7.0352 9.4565,7.0229C9.4453,7.0352 9.4299,7.0437 9.4112,7.0437C9.3989,7.0437 9.3856,7.0405 9.3749,7.0315C9.3643,7.0427 9.3488,7.0491 9.3328,7.0491C9.3173,7.0491 9.3051,7.0437 9.2939,7.0336C9.2837,7.0512 9.2651,7.0608 9.2453,7.0608C9.2363,7.0608 9.2272,7.0576 9.2203,7.056C9.2139,7.0661 9.2053,7.072 9.1952,7.0741C9.1941,7.0752 9.1925,7.0752 9.1904,7.0752C9.1781,7.0752 9.1653,7.0683 9.1611,7.0656C9.1445,7.056 9.1259,7.0283 9.1248,7.0283L9.1237,7.0251L9.1285,7L9.1344,7.0075C9.1344,7.0075 9.144,7.0187 9.1611,7.0315C9.1755,7.0432 9.1861,7.0437 9.1888,7.0437C9.1995,7.0421 9.2011,7.0283 9.2011,7.024L9.2011,6.9989L9.2171,7.0187C9.2224,7.0283 9.2325,7.032 9.2421,7.032C9.2608,7.032 9.2741,7.0187 9.2741,7.0027C9.2741,6.9952 9.2736,6.9925 9.2709,6.9904L9.2699,6.9872L9.2795,6.9653L9.2981,6.9819L9.2981,6.9829C9.2976,6.9851 9.2981,6.9872 9.2981,6.9893C9.2981,7.0053 9.312,7.0197 9.3301,7.0197C9.3483,7.0197 9.3611,7.0075 9.3637,6.9936L9.3637,6.9904L9.3637,6.9904C9.3637,6.9803 9.3637,6.9771 9.3701,6.9771L9.3701,6.9771C9.3733,6.9771 9.3755,6.9797 9.3771,6.9867L9.3797,6.9909C9.3829,7.0048 9.3957,7.0149 9.4112,7.0149C9.4299,7.0149 9.4448,6.9995 9.4448,6.9824C9.4448,6.9781 9.4443,6.9739 9.4427,6.9701L9.44,6.9659L9.4571,6.9648L9.472,6.9659L9.4699,6.9701C9.4693,6.9749 9.4688,6.9787 9.4688,6.9824C9.4688,6.9989 9.4832,7.0149 9.5013,7.0149C9.5173,7.0149 9.5296,7.0048 9.5333,6.9909L9.536,6.9867L9.536,6.9867C9.5376,6.9797 9.5387,6.9771 9.5424,6.9771C9.5483,6.9771 9.5483,6.9813 9.5483,6.9904L9.5483,6.992L9.5483,6.9936C9.5509,7.0069 9.5643,7.0197 9.5824,7.0197C9.6005,7.0197 9.6149,7.0059 9.6149,6.9893C9.6149,6.9872 9.6149,6.9851 9.6144,6.9829L9.6139,6.9819L9.6325,6.9653L9.6421,6.9872L9.6421,6.9904C9.6389,6.9931 9.6389,6.9957 9.6389,7.0027C9.6389,7.0181 9.6523,7.032 9.6704,7.032C9.6805,7.032 9.6907,7.0277 9.696,7.0187L9.712,6.9989L9.7115,7.024C9.7115,7.0283 9.7131,7.0405 9.7248,7.0437C9.7264,7.0437 9.7381,7.0432 9.7515,7.0315C9.7696,7.0192 9.7792,7.0075 9.7792,7.0075L9.7861,6.9979L9.7877,7.0261L9.7867,7.0272C9.7867,7.0283 9.7691,7.0565 9.7525,7.0656C9.7472,7.0683 9.7344,7.0752 9.7221,7.0752ZM9.6971,7.0432L9.6981,7.0469C9.7003,7.0533 9.7067,7.0645 9.7179,7.0656C9.7189,7.0656 9.72,7.0656 9.7216,7.0656C9.7285,7.0656 9.7376,7.0635 9.7472,7.0571C9.7595,7.0507 9.7739,7.0277 9.7776,7.0219L9.7776,7.0197C9.7723,7.0251 9.7664,7.0309 9.7563,7.0395C9.7403,7.0528 9.7269,7.0528 9.7227,7.0528L9.7227,7.0528C9.7104,7.0507 9.7024,7.0405 9.7019,7.0245C9.6939,7.0341 9.6816,7.04 9.6688,7.04C9.6469,7.04 9.6283,7.0235 9.6283,7.0027C9.6283,6.9941 9.6288,6.9904 9.6309,6.9872L9.6283,6.9792L9.6219,6.9851C9.6219,6.9861 9.6219,6.9872 9.6219,6.9893C9.6219,7.0091 9.6032,7.0277 9.5808,7.0277C9.5595,7.0277 9.5435,7.0155 9.5392,6.9963C9.5328,7.0117 9.5179,7.0203 9.4997,7.0203C9.4779,7.0203 9.4587,7.0027 9.4587,6.9819C9.4587,6.9776 9.4592,6.9765 9.4592,6.9712L9.456,6.9707L9.4507,6.9717C9.4512,6.9771 9.4517,6.9781 9.4517,6.9824C9.4517,7.0032 9.4325,7.0208 9.4101,7.0208C9.3925,7.0208 9.3776,7.0123 9.3712,6.9968C9.3669,7.0155 9.3504,7.0283 9.3296,7.0283C9.3072,7.0283 9.288,7.0096 9.288,6.9899C9.288,6.9877 9.288,6.9867 9.288,6.9856L9.2816,6.9797L9.2789,6.9877C9.2816,6.9909 9.2816,6.9952 9.2816,7.0032C9.2816,7.024 9.264,7.0405 9.2411,7.0405C9.2288,7.0405 9.216,7.0341 9.2091,7.0251C9.2085,7.0405 9.2,7.0512 9.1877,7.0533L9.1877,7.0533C9.184,7.0533 9.1707,7.0533 9.1536,7.04C9.144,7.0315 9.1376,7.0245 9.1317,7.0203L9.1312,7.0224C9.1355,7.0288 9.1504,7.0517 9.1632,7.0576C9.1744,7.0651 9.1845,7.0677 9.1931,7.0661C9.2043,7.0651 9.2096,7.0539 9.2123,7.0475L9.2139,7.0437L9.2187,7.0453C9.2256,7.0507 9.2347,7.0539 9.2437,7.0539C9.2624,7.0539 9.2805,7.0416 9.2875,7.0267L9.2901,7.0203L9.2939,7.0251C9.3035,7.0341 9.3163,7.0411 9.3312,7.0411C9.3456,7.0411 9.36,7.0325 9.3685,7.0213L9.3717,7.0192L9.3749,7.0203C9.3845,7.0304 9.3968,7.0336 9.4091,7.0336C9.4261,7.0336 9.4416,7.0283 9.4507,7.0149L9.4544,7.0075L9.4581,7.0149C9.4672,7.0283 9.4832,7.0336 9.4992,7.0336C9.5115,7.0336 9.5243,7.0299 9.5339,7.0203L9.5365,7.0192L9.5397,7.0213C9.5488,7.0325 9.5632,7.0411 9.5781,7.0411C9.5925,7.0411 9.6053,7.0336 9.6149,7.0251L9.6192,7.0203L9.6213,7.0267C9.6288,7.0411 9.6459,7.0539 9.6656,7.0539C9.6741,7.0539 9.6837,7.0507 9.6901,7.0453L9.6971,7.0432Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4555,7.0592C9.3541,7.0592 9.2624,7.0715 9.1963,7.0923C9.192,7.0939 9.1861,7.0907 9.1856,7.0864C9.1835,7.0821 9.1867,7.0779 9.192,7.0757C9.2576,7.0555 9.3509,7.0421 9.456,7.0421C9.5611,7.0421 9.6549,7.0555 9.7205,7.0757C9.7259,7.0779 9.7291,7.0821 9.7264,7.0864C9.7264,7.0907 9.72,7.0939 9.7157,7.0923C9.6496,7.072 9.5568,7.0592 9.4555,7.0592" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7173,7.096C9.7168,7.096 9.7157,7.0949 9.7136,7.0949C9.6459,7.0773 9.5547,7.0656 9.456,7.0656C9.3573,7.0656 9.2672,7.0768 9.1984,7.0949C9.192,7.0981 9.1835,7.0939 9.1813,7.0885C9.1797,7.0811 9.1824,7.0731 9.1899,7.0699C9.2608,7.0501 9.3547,7.0384 9.456,7.0384C9.5568,7.0384 9.6539,7.0507 9.7227,7.0699C9.7259,7.0709 9.7285,7.0752 9.7296,7.0784C9.7323,7.0816 9.7323,7.0837 9.7312,7.0891C9.7291,7.0933 9.7227,7.096 9.7173,7.096ZM9.4555,7.056C9.5541,7.056 9.648,7.0672 9.7168,7.0885L9.7173,7.0885C9.7195,7.0885 9.7232,7.0864 9.7232,7.0832C9.7232,7.0821 9.7232,7.0821 9.7227,7.0821C9.7221,7.0811 9.72,7.0795 9.72,7.0795C9.6512,7.0571 9.5552,7.0459 9.456,7.0448C9.3552,7.0459 9.2613,7.0571 9.192,7.0795C9.1909,7.0805 9.1888,7.0821 9.1888,7.0832C9.1893,7.0864 9.192,7.0885 9.1947,7.0885C9.264,7.0672 9.3568,7.056 9.4555,7.056Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.3568,7.0949C9.3568,7.0907 9.3632,7.0827 9.3717,7.0827C9.3792,7.0827 9.3856,7.0912 9.3856,7.0949C9.3856,7.1051 9.3787,7.1093 9.3717,7.1093C9.3632,7.1093 9.3568,7.1045 9.3568,7.0949" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4571,7.1029L9.424,7.1029C9.4176,7.1029 9.4133,7.0965 9.4133,7.0917C9.4133,7.0859 9.4176,7.0805 9.424,7.0805L9.4907,7.0805C9.4965,7.0805 9.5013,7.0859 9.5013,7.0917C9.5013,7.0965 9.4965,7.1029 9.4907,7.1029L9.4571,7.1029" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4901,7.1072L9.424,7.1072C9.4155,7.1072 9.4085,7.1008 9.4085,7.0923C9.4085,7.0821 9.416,7.0784 9.424,7.0784L9.4907,7.0784C9.4987,7.0784 9.5056,7.0827 9.5056,7.0923C9.5056,7.1008 9.4981,7.1072 9.4901,7.1072ZM9.4235,7.0853C9.4192,7.0853 9.4165,7.0896 9.4165,7.0923C9.4165,7.0949 9.4197,7.0981 9.424,7.0981L9.4907,7.0981C9.4944,7.0981 9.4976,7.0949 9.4976,7.0923C9.4976,7.0896 9.4949,7.0853 9.4907,7.0853L9.4235,7.0853Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.2923,7.1157L9.2699,7.1173C9.2635,7.1184 9.2576,7.1157 9.2576,7.1072C9.256,7.1029 9.2603,7.0965 9.2667,7.096L9.2891,7.0939L9.3141,7.0907C9.3205,7.0907 9.3259,7.0923 9.3264,7.0981C9.3264,7.1035 9.3237,7.1077 9.3173,7.1093L9.2923,7.1157" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.2667,7.1211C9.2603,7.1211 9.2539,7.1157 9.2517,7.1077C9.2507,7.1061 9.2523,7.1035 9.2539,7.0981C9.2565,7.0949 9.2603,7.0933 9.2645,7.0923L9.3125,7.0843C9.3131,7.0843 9.3131,7.0843 9.3141,7.0843C9.3227,7.0843 9.3291,7.0907 9.3296,7.0965C9.3307,7.1029 9.3291,7.1056 9.3275,7.1072C9.3253,7.1115 9.3211,7.1157 9.3168,7.1157L9.2693,7.12C9.2693,7.12 9.2683,7.1211 9.2667,7.1211ZM9.3141,7.0939L9.2667,7.1024C9.264,7.1035 9.2635,7.1035 9.2619,7.1035C9.2608,7.1051 9.2608,7.1067 9.2608,7.1077C9.2613,7.1109 9.2651,7.1152 9.2688,7.1141L9.3168,7.1067C9.3173,7.1061 9.3195,7.1051 9.3195,7.1035C9.3211,7.1035 9.3216,7.1013 9.3216,7.0992C9.3205,7.0949 9.3179,7.0939 9.3141,7.0939Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1979,7.1307l0.0101,-0.016l0.0224,0.0037l-0.0133,0.0181l-0.0192,-0.0059" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.5253,7.0949C9.5253,7.0907 9.5323,7.0827 9.5397,7.0827C9.5483,7.0827 9.5541,7.0912 9.5541,7.0949C9.5541,7.1051 9.5477,7.1093 9.5397,7.1093C9.5323,7.1093 9.5253,7.1045 9.5253,7.0949" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6197,7.1157L9.6421,7.1173C9.648,7.1184 9.6539,7.1157 9.6544,7.1072C9.6555,7.1029 9.6512,7.0965 9.6453,7.096L9.6224,7.0939L9.5973,7.0907C9.5909,7.0907 9.5861,7.0923 9.5851,7.0981C9.5851,7.1035 9.5883,7.1077 9.5941,7.1093L9.6197,7.1157" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6443,7.1211C9.6432,7.1211 9.6421,7.12 9.6416,7.12L9.5947,7.1157C9.5904,7.1157 9.5861,7.1115 9.584,7.1072C9.5819,7.1045 9.5808,7.1019 9.5819,7.0965C9.5819,7.0901 9.5904,7.0821 9.5984,7.0843L9.6469,7.0923C9.6507,7.0933 9.6539,7.0949 9.6571,7.0981C9.6592,7.1035 9.6603,7.1061 9.6597,7.1077C9.6576,7.1157 9.6512,7.1211 9.6443,7.1211ZM9.5979,7.0939C9.5936,7.0939 9.5909,7.0949 9.5899,7.0992C9.5899,7.1013 9.5899,7.1035 9.5915,7.1035C9.5915,7.1051 9.5941,7.1061 9.5952,7.1067L9.6443,7.1141C9.6475,7.1141 9.6507,7.1109 9.6507,7.1077C9.6507,7.1067 9.6507,7.1051 9.6496,7.1035C9.648,7.1035 9.648,7.1035 9.6448,7.1024L9.5979,7.0939L9.5979,7.0939Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7115,7.1312l-0.0075,-0.0165l-0.0235,0.0011l0.0112,0.0187l0.0197,-0.0032" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4555,7.1936C9.3728,7.1931 9.2981,7.1851 9.2416,7.1696C9.2981,7.1563 9.3728,7.1467 9.4555,7.1467C9.5381,7.1467 9.6133,7.1563 9.6693,7.1696C9.6133,7.1856 9.5381,7.1931 9.4555,7.1936" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4555,7.1968L9.4555,7.1968C9.3701,7.1968 9.2965,7.1904 9.2416,7.176C9.2384,7.1749 9.2384,7.1728 9.2384,7.1696C9.2384,7.1685 9.2384,7.1669 9.2416,7.1669C9.3008,7.1531 9.3755,7.1435 9.4555,7.1429C9.5355,7.1429 9.6107,7.1531 9.6693,7.1669C9.6725,7.1669 9.6731,7.1685 9.6731,7.1696C9.6731,7.1728 9.6731,7.1749 9.6693,7.176C9.6149,7.1904 9.5408,7.1968 9.4555,7.1968ZM9.2603,7.1696C9.3131,7.1819 9.3797,7.1893 9.4555,7.1904C9.5312,7.1893 9.5979,7.1819 9.6507,7.1696C9.5947,7.1573 9.5259,7.1531 9.4555,7.1531C9.3856,7.1531 9.3168,7.1573 9.2603,7.1696Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7152,7.0155C9.7168,7.0069 9.7152,7.0032 9.7104,7.0011C9.7061,6.9989 9.7008,7.0032 9.6981,7.0085C9.6965,7.016 9.6981,7.0208 9.7029,7.024C9.7072,7.0251 9.7131,7.0197 9.7152,7.0155" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.5509,6.9824C9.552,6.9781 9.5483,6.9701 9.5445,6.9701C9.5387,6.9701 9.5344,6.9749 9.5339,6.9813C9.5323,6.9888 9.5355,6.9936 9.5419,6.9936C9.5451,6.9947 9.5509,6.9904 9.5509,6.9824" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.3605,6.9824C9.3605,6.9781 9.3632,6.9701 9.368,6.9701C9.3728,6.9701 9.3776,6.9749 9.3787,6.9813C9.3792,6.9888 9.376,6.9936 9.3712,6.9936C9.3669,6.9947 9.3616,6.9904 9.3605,6.9824" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1973,7.0155C9.1947,7.0069 9.1973,7.0032 9.2011,7.0011C9.2064,6.9989 9.2117,7.0032 9.2133,7.0085C9.216,7.016 9.2133,7.0208 9.2096,7.024C9.2043,7.0251 9.1989,7.0197 9.1973,7.0155" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4555,6.8896l-0.0299,0.0165l0.0224,0.0469l0.0075,0.0043l0.008,-0.0043l0.0224,-0.0469l-0.0304,-0.0165" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4555,6.9637L9.4443,6.9557L9.4203,6.9029L9.4549,6.8821L9.4896,6.9029L9.4661,6.9557L9.4555,6.9637ZM9.4507,6.9499L9.4555,6.9531L9.4597,6.9499L9.4795,6.9072L9.456,6.8939L9.4325,6.9072L9.4507,6.9499Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.3915,6.9573l0.0128,0.0208l0.0459,-0.0123l0.0037,-0.0085l-0.0037,-0.0043l-0.0459,-0.0144l-0.0128,0.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4032,6.9824l-0.0171,-0.0251l0.0171,-0.0251l0.0501,0.0144l0.0069,0.0107l-0.0075,0.0112z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.5195,6.9573l-0.0128,0.0208l-0.0459,-0.0123l-0.0043,-0.0085l0.0043,-0.0043l0.0459,-0.0144l0.0128,0.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.5072,6.9824L9.4576,6.9685L9.4507,6.9573L9.4576,6.9467L9.5072,6.9323L9.5248,6.9573L9.5072,6.9824ZM9.4635,6.9595L9.5045,6.9728L9.5141,6.9573L9.504,6.944L9.4629,6.9557L9.4608,6.9573L9.4635,6.9595Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.2667,6.9072l-0.0224,0.0235l0.0283,0.0379l0.008,0.0021l0.0053,-0.0053l0.0107,-0.0459l-0.0299,-0.0123" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.2821,6.9781l-0.0123,-0.0064l-0.0315,-0.0411l0.0277,-0.0277l0.0352,0.0139l-0.0107,0.0517z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.2197,6.9867l0.016,0.0165l0.0416,-0.0235l0.0032,-0.008l-0.0053,-0.0048l-0.0475,-0.0027l-0.008,0.0224" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.2352,7.0075l-0.0224,-0.0197l0.0112,-0.0304l0.0517,0.0064l0.0096,0.0064l-0.0048,0.0123z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.344,6.9605l-0.0085,0.0219l-0.0469,-0.0043l-0.0064,-0.0064l0.0032,-0.0064l0.0405,-0.0219l0.0181,0.0171" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.3381,6.9877l-0.0528,-0.0053l-0.0096,-0.0085l0.0059,-0.0112l0.0448,-0.024l0.0219,0.0208z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1728,6.992l-0.0032,0.0235l-0.0475,0.0043l-0.0075,-0.0043l0.0021,-0.0085l0.0352,-0.0293l0.0208,0.0144" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1211,7.024l-0.0107,-0.0059l0.0027,-0.0123l0.0384,-0.0336l0.0267,0.0187l-0.0053,0.0283z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.264,6.9717C9.264,6.9653 9.272,6.9573 9.2816,6.9573C9.2907,6.9573 9.2981,6.9659 9.2981,6.9717C9.2981,6.9813 9.2907,6.9893 9.2816,6.9893C9.272,6.9893 9.264,6.9813 9.264,6.9717" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6443,6.9072l0.0229,0.0235l-0.0293,0.0379l-0.0075,0.0021l-0.0053,-0.0053l-0.0112,-0.0459l0.0304,-0.0123" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6293,6.9781l-0.008,-0.0096l-0.0107,-0.0517l0.0352,-0.0139l0.0272,0.0277l-0.0315,0.0411z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6928,6.9867l-0.0171,0.0165l-0.0411,-0.0235l-0.0032,-0.008l0.0059,-0.0048l0.0475,-0.0027l0.008,0.0224" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6757,7.0075l-0.0443,-0.0251l-0.0053,-0.0123l0.0096,-0.0064l0.0523,-0.0064l0.0101,0.0304z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.568,6.9605l0.0085,0.0219l0.0475,-0.0043l0.0059,-0.0064l-0.0032,-0.0064l-0.0416,-0.0219l-0.0171,0.0171" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.5739,6.9877l-0.0107,-0.0283l0.0224,-0.0208l0.0448,0.024l0.0053,0.0112l-0.0096,0.0085z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7323,6.992l0.0032,0.0235l0.0469,0.0043l0.008,-0.0043l-0.0021,-0.0085l-0.0352,-0.0293l-0.0208,0.0144" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.784,7.024l-0.0523,-0.0053l-0.0053,-0.0283l0.0267,-0.0187l0.0384,0.0336l0.0027,0.0123z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4384,6.9573C9.4384,6.9488 9.4464,6.9424 9.4555,6.9424C9.4645,6.9424 9.4725,6.9493 9.4725,6.9573C9.4725,6.9653 9.4645,6.9739 9.4555,6.9739C9.4464,6.9739 9.4384,6.9659 9.4384,6.9573" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6133,6.9717C9.6133,6.9653 9.6219,6.9573 9.6309,6.9573C9.64,6.9573 9.648,6.9659 9.648,6.9717C9.648,6.9813 9.64,6.9893 9.6309,6.9893C9.6219,6.9893 9.6133,6.9813 9.6133,6.9717" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4245,6.7808C9.4245,6.7659 9.4379,6.752 9.4555,6.752C9.4725,6.752 9.4869,6.7653 9.4869,6.7808C9.4869,6.7947 9.4725,6.8085 9.4555,6.8085C9.4384,6.8085 9.4245,6.7947 9.4245,6.7808" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4779,6.7696l0,0.0208l-0.0485,0l0,-0.0208l0.0155,0l0,-0.0437l-0.0203,0l0,-0.0197l0.0203,0l0,-0.0197l0.0219,0l0,0.0197l0.0197,0l0,0.0197l-0.0197,0l0,0.0437l0.0112,0" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4821,6.7947L9.4245,6.7947L9.4245,6.7653L9.44,6.7653L9.44,6.7307L9.4192,6.7307L9.4192,6.7019L9.44,6.7019L9.44,6.6811L9.4709,6.6811L9.4709,6.7019L9.4917,6.7019L9.4917,6.7307L9.4709,6.7307L9.4709,6.7653L9.4821,6.7653L9.4821,6.7947ZM9.4352,6.7835L9.4725,6.7835L9.4725,6.7749L9.4603,6.7749L9.4603,6.72L9.4821,6.72L9.4821,6.7104L9.4603,6.7104L9.4603,6.6907L9.4507,6.6907L9.4507,6.7104L9.4293,6.7104L9.4293,6.72L9.4512,6.72L9.4512,6.7755L9.4357,6.7755L9.4357,6.7835L9.4352,6.7835Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4997,6.7696l0,0.0208l-0.0864,0l0,-0.0208l0.0315,0l0,-0.0437l-0.0203,0l0,-0.0197l0.0203,0l0,-0.0197l0.0219,0l0,0.0197l0.0197,0l0,0.0197l-0.0197,0l0,0.0437l0.0331,0" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4555,6.8155C9.4352,6.8155 9.4192,6.7989 9.4192,6.7808C9.4192,6.7659 9.4309,6.7531 9.4464,6.7461L9.448,6.7568C9.4368,6.7579 9.4288,6.7691 9.4288,6.7813C9.4288,6.7941 9.4411,6.8064 9.4555,6.8064C9.4699,6.8064 9.4816,6.7947 9.4816,6.7813C9.4816,6.7696 9.4747,6.7579 9.4629,6.7568L9.4661,6.7472C9.4805,6.7536 9.4912,6.7659 9.4912,6.7808C9.4917,6.7989 9.4757,6.8155 9.4555,6.8155Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1099,7.0187C9.1093,7.0187 9.0965,7.0032 9.0875,6.9936C9.0805,6.9883 9.064,6.9824 9.064,6.9824C9.064,6.9797 9.0736,6.9728 9.0843,6.9728C9.0901,6.9728 9.0955,6.976 9.0987,6.9797L9.1008,6.9728C9.1008,6.9728 9.1088,6.9749 9.1125,6.9824C9.1168,6.9936 9.1131,7.0075 9.1131,7.0075C9.1131,7.0075 9.112,7.0155 9.1099,7.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1099,7.0219C9.1072,7.0219 9.1072,7.0208 9.1013,7.0155C9.0981,7.0112 9.0901,7.0032 9.0843,6.9957C9.0789,6.9931 9.0667,6.9893 9.0629,6.9872L9.0603,6.9851L9.0603,6.9819C9.0603,6.9765 9.0725,6.9685 9.0837,6.9685C9.088,6.9685 9.0917,6.9696 9.0955,6.9696L9.0965,6.9685L9.1003,6.9685C9.1003,6.9685 9.1115,6.9696 9.1163,6.9819C9.1195,6.9931 9.1173,7.0069 9.1173,7.0069C9.1168,7.0091 9.1163,7.0171 9.1125,7.0192L9.1099,7.0213L9.1099,7.0213L9.1099,7.0219Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1104,7.0096C9.1131,7.0064 9.1221,7.0075 9.128,7.0128C9.1339,7.0176 9.1355,7.0251 9.1317,7.0283C9.128,7.0325 9.1195,7.0325 9.1131,7.0283C9.1072,7.0208 9.1061,7.0155 9.1104,7.0096" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7957,7.0187C9.7968,7.0187 9.8085,7.0032 9.8181,6.9936C9.8245,6.9883 9.8416,6.9824 9.8416,6.9824C9.8416,6.9797 9.832,6.9728 9.8208,6.9728C9.8149,6.9728 9.8096,6.976 9.8064,6.9797L9.8043,6.9728C9.8043,6.9728 9.7963,6.9749 9.7925,6.9824C9.7883,6.9936 9.792,7.0075 9.792,7.0075C9.792,7.0075 9.7925,7.0155 9.7957,7.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7957,7.0219L9.7957,7.0219L9.7947,7.0219L9.7925,7.0197C9.7883,7.0171 9.7877,7.0091 9.7872,7.0085C9.7867,7.008 9.7845,6.9941 9.7883,6.9824C9.7931,6.9701 9.8043,6.9691 9.8043,6.9691L9.808,6.9691L9.8091,6.9712C9.8133,6.9701 9.8165,6.9691 9.8208,6.9691C9.832,6.9691 9.8443,6.9776 9.8443,6.9824L9.8443,6.9856L9.8411,6.9877C9.8379,6.9899 9.8251,6.9936 9.8203,6.9963C9.8149,7.0037 9.8069,7.0107 9.8037,7.016C9.7984,7.0208 9.7979,7.0219 9.7957,7.0219Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7963,7.0096C9.792,7.0064 9.7845,7.0075 9.7781,7.0128C9.7728,7.0176 9.7696,7.0251 9.7739,7.0283C9.7781,7.0325 9.7856,7.0325 9.7915,7.0283C9.7979,7.0208 9.8005,7.0155 9.7963,7.0096" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.0789,7.4032l0.7536,0l0,-0.1973l-0.7536,0z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8395,7.4085L9.0725,7.4085L9.0725,7.1989L9.8395,7.1989L9.8395,7.4085ZM9.0853,7.3947L9.8261,7.3947L9.8261,7.2123L9.0853,7.2123L9.0853,7.3947Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7541,7.5333C9.7493,7.5323 9.7456,7.5323 9.7403,7.5323L9.1755,7.5323C9.1691,7.5323 9.1643,7.5323 9.16,7.5344C9.1787,7.528 9.1931,7.5115 9.1931,7.4907C9.1931,7.4699 9.1781,7.4533 9.1579,7.4448C9.1627,7.4459 9.1691,7.448 9.1755,7.448L9.7403,7.448C9.7456,7.448 9.7509,7.4469 9.7563,7.4448L9.7531,7.4459C9.7317,7.4533 9.7211,7.4699 9.7211,7.4907C9.7211,7.5083 9.7339,7.528 9.7541,7.5333" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1605,7.5424C9.1573,7.5424 9.1541,7.5408 9.1541,7.5376C9.1525,7.5323 9.1541,7.5307 9.1568,7.528L9.1595,7.528C9.1755,7.5205 9.1867,7.5072 9.1867,7.4907C9.1867,7.4741 9.1744,7.4571 9.1568,7.4533C9.1531,7.4512 9.1504,7.4448 9.152,7.4437C9.1541,7.4405 9.1568,7.4384 9.1605,7.4405C9.1659,7.4405 9.1712,7.4405 9.176,7.4405L9.7408,7.4405C9.7435,7.4405 9.7467,7.4405 9.7493,7.4405L9.7552,7.4405C9.7595,7.4405 9.7621,7.4405 9.7637,7.4448C9.7643,7.448 9.7621,7.4533 9.7584,7.4533C9.7573,7.4533 9.7552,7.4533 9.7531,7.4533C9.7381,7.4587 9.7291,7.4741 9.7291,7.4907C9.7291,7.5061 9.7397,7.52 9.7547,7.528C9.7552,7.528 9.7563,7.528 9.7584,7.528C9.7616,7.5296 9.7627,7.5323 9.7616,7.5371C9.7605,7.5408 9.7568,7.5424 9.7531,7.5408C9.752,7.5408 9.752,7.5408 9.7499,7.5408C9.7477,7.5408 9.7456,7.5408 9.7413,7.5408L9.1765,7.5408C9.1723,7.5408 9.1675,7.5408 9.1643,7.5408L9.1632,7.5408C9.1611,7.5424 9.1605,7.5424 9.1605,7.5424ZM9.1856,7.5269L9.7291,7.5269C9.7195,7.5157 9.7141,7.5029 9.7141,7.4907C9.7141,7.4784 9.7195,7.4656 9.7285,7.4549L9.1856,7.4549C9.1947,7.4661 9.2005,7.4784 9.2005,7.4907C9.2005,7.5029 9.1947,7.5157 9.1856,7.5269Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.176,7.5323L9.7408,7.5323C9.76,7.5323 9.7749,7.5445 9.7749,7.5573C9.7749,7.5739 9.7595,7.5856 9.7408,7.5856L9.176,7.5856C9.1573,7.5856 9.1419,7.5744 9.1419,7.5573C9.1419,7.5445 9.1568,7.5323 9.176,7.5323" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7403,7.592L9.1755,7.592C9.1525,7.592 9.1344,7.5781 9.1344,7.5573C9.1344,7.5408 9.1525,7.5269 9.1755,7.5269L9.7403,7.5269C9.7632,7.5269 9.7813,7.5403 9.7813,7.5573C9.7813,7.5781 9.7632,7.592 9.7403,7.592ZM9.176,7.5408C9.1605,7.5408 9.1483,7.5483 9.1483,7.5573C9.1483,7.5696 9.1605,7.5781 9.176,7.5781L9.7408,7.5781C9.7552,7.5781 9.7685,7.5696 9.7685,7.5573C9.7685,7.5477 9.7557,7.5408 9.7408,7.5408L9.176,7.5408Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.176,7.4032L9.7408,7.4032C9.76,7.4032 9.7749,7.4144 9.7749,7.4261C9.7749,7.4384 9.7595,7.448 9.7408,7.448L9.176,7.448C9.1563,7.448 9.1413,7.4384 9.1413,7.4261C9.1408,7.4144 9.1563,7.4032 9.176,7.4032" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7403,7.4549L9.1755,7.4549C9.1515,7.4549 9.1339,7.4427 9.1339,7.4261C9.1339,7.4085 9.1515,7.3947 9.1755,7.3947L9.7403,7.3947C9.7632,7.3947 9.7813,7.408 9.7813,7.4261C9.7813,7.4421 9.7632,7.4549 9.7403,7.4549ZM9.176,7.4085C9.1589,7.4085 9.1483,7.4187 9.1483,7.4261C9.1483,7.4325 9.1589,7.4405 9.176,7.4405L9.7408,7.4405C9.7552,7.4405 9.7685,7.432 9.7685,7.4261C9.7685,7.4181 9.7573,7.4085 9.7408,7.4085L9.176,7.4085Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.9296,10.728C8.9824,10.728 9.0293,10.7179 9.0635,10.6997C9.0971,10.6821 9.1429,10.6704 9.1941,10.6704C9.2448,10.6704 9.2923,10.6816 9.3264,10.6997C9.3611,10.7179 9.4075,10.728 9.4587,10.728C9.5109,10.728 9.5579,10.7157 9.592,10.6976C9.6261,10.6821 9.6699,10.6704 9.72,10.6704C9.7712,10.6704 9.8171,10.6811 9.8512,10.6987C9.8848,10.7168 9.9323,10.728 9.9845,10.728L9.9845,10.8101C9.9323,10.8101 9.8848,10.7989 9.8512,10.7803C9.8171,10.7632 9.7712,10.7525 9.72,10.7525C9.6699,10.7525 9.6261,10.7637 9.592,10.7803C9.5573,10.7973 9.5109,10.8101 9.4587,10.8101C9.4075,10.8101 9.3611,10.7989 9.3264,10.7808C9.2923,10.7653 9.2453,10.7525 9.1941,10.7525C9.1429,10.7525 9.0976,10.7648 9.0635,10.7808C9.0293,10.7995 8.9824,10.8101 8.9307,10.8101L8.9296,10.728" + android:strokeWidth="1" + android:fillColor="#005BBF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9909,10.8171L9.984,10.8171C9.9339,10.8171 9.8837,10.8059 9.848,10.7861C9.8133,10.7685 9.7696,10.7579 9.7195,10.7579C9.6731,10.7579 9.6293,10.7685 9.5947,10.7851C9.5573,10.8059 9.5077,10.8171 9.4581,10.8171C9.4069,10.8171 9.3605,10.8059 9.3232,10.7872C9.2885,10.7696 9.2421,10.7579 9.1941,10.7579C9.1456,10.7579 9.1013,10.7691 9.0661,10.7872C9.0293,10.8059 8.9824,10.8171 8.9312,10.8171L8.9243,10.8171L8.9232,10.7205L8.9296,10.7205C8.9792,10.7205 9.0261,10.712 9.0608,10.6933C9.0965,10.6757 9.1445,10.6651 9.1941,10.6651C9.2443,10.6651 9.2933,10.6763 9.3296,10.6933C9.3637,10.712 9.4101,10.7205 9.4587,10.7205C9.5077,10.7205 9.5531,10.7109 9.5888,10.6928C9.6245,10.6747 9.6709,10.6651 9.72,10.6651C9.7723,10.6651 9.8181,10.6747 9.8539,10.6933C9.8885,10.7109 9.936,10.7205 9.9845,10.7205L9.9915,10.7205L9.9915,10.8171L9.9909,10.8171ZM9.1936,10.7445C9.2443,10.7445 9.2923,10.7568 9.3291,10.776C9.3632,10.7936 9.4101,10.8032 9.4581,10.8032C9.5067,10.8032 9.552,10.7936 9.5883,10.7739C9.624,10.7563 9.6704,10.7445 9.7195,10.7445C9.7712,10.7445 9.8171,10.7557 9.8533,10.7749C9.8869,10.792 9.9317,10.8032 9.9771,10.8032L9.9771,10.7344C9.9291,10.7333 9.8816,10.7237 9.8475,10.7045C9.8128,10.6885 9.7691,10.6779 9.7189,10.6779C9.6725,10.6779 9.6288,10.6885 9.5941,10.7045C9.5568,10.7243 9.5077,10.7344 9.4576,10.7344C9.4064,10.7344 9.3584,10.7248 9.3227,10.7061C9.288,10.6896 9.2416,10.6779 9.1936,10.6779C9.1451,10.6779 9.1008,10.6885 9.0656,10.7056C9.0315,10.7237 8.9851,10.7333 8.936,10.7344L8.9371,10.8032C8.9829,10.8032 9.0261,10.7931 9.0603,10.776C9.096,10.7573 9.144,10.7445 9.1936,10.7445Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.9296,10.8107C8.9824,10.8107 9.0293,10.8 9.0635,10.7813C9.0971,10.7659 9.1429,10.7531 9.1941,10.7531C9.2448,10.7531 9.2923,10.7653 9.3264,10.7813C9.3611,10.7989 9.4075,10.8107 9.4587,10.8107C9.5109,10.8107 9.5579,10.7984 9.592,10.7808C9.6261,10.7648 9.6699,10.7531 9.72,10.7531C9.7712,10.7531 9.8171,10.7637 9.8512,10.7808C9.8848,10.7989 9.9323,10.8107 9.9845,10.8107L9.9845,10.8923C9.9323,10.8923 9.8848,10.8811 9.8512,10.8624C9.8171,10.8448 9.7712,10.8331 9.72,10.8331C9.6699,10.8331 9.6261,10.8443 9.592,10.8613C9.5573,10.8795 9.5109,10.8923 9.4587,10.8923C9.4075,10.8923 9.3611,10.8811 9.3264,10.8635C9.2923,10.8448 9.2453,10.8331 9.1941,10.8331C9.1429,10.8331 9.0976,10.8443 9.0635,10.8635C9.0293,10.8811 8.9824,10.8923 8.9307,10.8923L8.9296,10.8107" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9909,10.8981L9.984,10.8981C9.9333,10.8981 9.8837,10.8875 9.848,10.8683C9.8133,10.8512 9.7696,10.8405 9.7195,10.8405C9.6731,10.8405 9.6293,10.8512 9.5947,10.8672C9.5573,10.8875 9.5083,10.8981 9.4581,10.8981C9.4069,10.8981 9.3605,10.8885 9.3232,10.8688C9.2885,10.8533 9.2421,10.8405 9.1941,10.8405C9.1456,10.8405 9.1013,10.8517 9.0661,10.8688C9.0293,10.8896 8.9824,10.8981 8.9312,10.8981L8.9243,10.8981L8.9232,10.8032L8.9296,10.8032C8.9792,10.8032 9.0261,10.7936 9.0608,10.776C9.0965,10.7573 9.1445,10.7445 9.1941,10.7445C9.2448,10.7445 9.2939,10.7568 9.3296,10.776C9.3637,10.7936 9.4107,10.8032 9.4587,10.8032C9.5067,10.8032 9.5525,10.7936 9.5888,10.7739C9.6245,10.7563 9.6709,10.7445 9.72,10.7445C9.7717,10.7445 9.8176,10.7557 9.8539,10.7749C9.8885,10.7936 9.936,10.8032 9.9845,10.8032L9.9915,10.8032L9.9915,10.8981L9.9909,10.8981ZM9.1936,10.8283C9.2443,10.8283 9.2923,10.8395 9.3291,10.8576C9.3632,10.8763 9.4101,10.8848 9.4581,10.8848C9.5067,10.8848 9.5525,10.8752 9.5883,10.8565C9.624,10.8389 9.6704,10.8283 9.7195,10.8283C9.7717,10.8283 9.8176,10.8389 9.8539,10.8565C9.8859,10.8741 9.9317,10.8837 9.9771,10.8848L9.9771,10.8176C9.9291,10.816 9.8816,10.8064 9.8475,10.7867C9.8128,10.7691 9.7691,10.7584 9.7189,10.7584C9.6725,10.7584 9.6288,10.7691 9.5941,10.7856C9.5568,10.8064 9.5072,10.8176 9.4576,10.8176C9.4064,10.8176 9.3589,10.8064 9.3227,10.7877C9.288,10.7701 9.2416,10.7584 9.1936,10.7584C9.1451,10.7584 9.1008,10.7696 9.0656,10.7877C9.0309,10.8059 8.9851,10.816 8.936,10.8176L8.9371,10.8848C8.9829,10.8837 9.0261,10.8752 9.0603,10.8576C9.096,10.8395 9.144,10.8283 9.1936,10.8283Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.9296,10.8923C8.9824,10.8923 9.0293,10.8811 9.0635,10.8635C9.0971,10.8448 9.1429,10.8331 9.1941,10.8331C9.2448,10.8331 9.2923,10.8443 9.3264,10.8635C9.3611,10.8811 9.4075,10.8923 9.4587,10.8923C9.5109,10.8923 9.5579,10.88 9.592,10.8613C9.6261,10.8448 9.6699,10.8331 9.72,10.8331C9.7712,10.8331 9.8171,10.8443 9.8512,10.8624C9.8848,10.8805 9.9323,10.8923 9.9845,10.8923L9.9845,10.9728C9.9323,10.9728 9.8848,10.9616 9.8512,10.9435C9.8171,10.9269 9.7712,10.9152 9.72,10.9152C9.6699,10.9152 9.6261,10.9275 9.592,10.9429C9.5573,10.9611 9.5109,10.9728 9.4587,10.9728C9.4075,10.9728 9.3611,10.9621 9.3264,10.9445C9.2923,10.928 9.2453,10.9152 9.1941,10.9152C9.1429,10.9152 9.0976,10.9275 9.0635,10.9445C9.0293,10.9632 8.9824,10.9728 8.9307,10.9728L8.9296,10.8923" + android:strokeWidth="1" + android:fillColor="#005BBF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9909,10.9797L9.984,10.9797C9.9333,10.9797 9.8837,10.9685 9.848,10.9499C9.8133,10.9323 9.7696,10.9216 9.7195,10.9216C9.6731,10.9216 9.6293,10.9323 9.5947,10.9488C9.5573,10.9685 9.5088,10.9797 9.4581,10.9797C9.4069,10.9797 9.3595,10.9696 9.3232,10.9509C9.2885,10.9323 9.2421,10.9216 9.1941,10.9216C9.1451,10.9216 9.1013,10.9323 9.0661,10.9509C9.0293,10.9696 8.9824,10.9797 8.9312,10.9797L8.9243,10.9797L8.9232,10.8843L8.9296,10.8843C8.9792,10.8843 9.0261,10.8757 9.0608,10.8571C9.0965,10.8395 9.1445,10.8277 9.1941,10.8277C9.2448,10.8277 9.2933,10.8389 9.3296,10.8571C9.3637,10.8757 9.4107,10.8843 9.4587,10.8843C9.5072,10.8843 9.5525,10.8747 9.5888,10.856C9.6245,10.8384 9.6709,10.8277 9.72,10.8277C9.7723,10.8277 9.8181,10.8384 9.8544,10.856C9.8885,10.8747 9.9355,10.8843 9.9845,10.8843L9.9915,10.8843L9.9915,10.9797L9.9909,10.9797ZM9.1936,10.9083C9.2443,10.9083 9.2923,10.9195 9.3291,10.9397C9.3632,10.9563 9.4101,10.9675 9.4581,10.9675C9.5072,10.9675 9.5525,10.9563 9.5883,10.9376C9.6245,10.92 9.6709,10.9083 9.7195,10.9083C9.7712,10.9083 9.8171,10.9195 9.8533,10.9387C9.8864,10.9557 9.9317,10.9659 9.9771,10.9659L9.9771,10.8981C9.9291,10.8971 9.8816,10.8869 9.8475,10.8683C9.8128,10.8512 9.7691,10.8405 9.7189,10.8405C9.6725,10.8405 9.6288,10.8512 9.5941,10.8672C9.5568,10.8875 9.5072,10.8981 9.4576,10.8981C9.4064,10.8981 9.3589,10.8885 9.3227,10.8688C9.288,10.8533 9.2416,10.8405 9.1936,10.8405C9.1451,10.8405 9.1008,10.8517 9.0656,10.8688C9.0309,10.8875 8.9851,10.8971 8.936,10.8981L8.9371,10.9659C8.9845,10.9659 9.0256,10.9563 9.0603,10.9397C9.0955,10.92 9.1435,10.9083 9.1936,10.9083Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.9307,11.0549C8.9819,11.0549 9.0293,11.0437 9.0635,11.0272C9.0971,11.0075 9.1429,10.9968 9.1941,10.9968C9.2448,10.9968 9.2923,11.0075 9.3264,11.0272C9.3611,11.0437 9.4075,11.0549 9.4587,11.0549C9.5109,11.0549 9.5579,11.0437 9.592,11.0251C9.6261,11.0075 9.6699,10.9968 9.72,10.9968C9.7712,10.9968 9.8171,11.0075 9.8512,11.0261C9.8848,11.0437 9.9323,11.0549 9.9845,11.0549L9.9845,10.9744C9.9323,10.9744 9.8848,10.9621 9.8512,10.944C9.8171,10.9275 9.7712,10.9157 9.72,10.9157C9.6699,10.9157 9.6261,10.928 9.592,10.9435C9.5573,10.9616 9.5109,10.9733 9.4587,10.9733C9.4075,10.9733 9.3611,10.9627 9.3264,10.9451C9.2923,10.9285 9.2453,10.9157 9.1941,10.9157C9.1429,10.9157 9.0976,10.928 9.0635,10.9451C9.0293,10.9637 8.9824,10.9733 8.9296,10.9733L8.9307,11.0549" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9909,11.0613L9.984,11.0613C9.9333,11.0613 9.8832,11.0507 9.848,11.0309C9.8133,11.0144 9.7696,11.0043 9.7195,11.0043C9.6731,11.0043 9.6293,11.0144 9.5947,11.0304C9.5573,11.0507 9.5083,11.0613 9.4581,11.0613C9.4069,11.0613 9.3595,11.0517 9.3232,11.032C9.2885,11.0155 9.2421,11.0043 9.1941,11.0043C9.1456,11.0043 9.1013,11.0155 9.0661,11.0309C9.0293,11.0517 8.9824,11.0613 8.9312,11.0613L8.9243,11.0613L8.9232,10.9669L8.9296,10.9669C8.9792,10.9669 9.0261,10.9557 9.0608,10.9392C9.096,10.9195 9.144,10.9077 9.1941,10.9077C9.2448,10.9077 9.2928,10.9189 9.3296,10.9392C9.3637,10.9557 9.4107,10.9669 9.4587,10.9669C9.5077,10.9669 9.5531,10.9557 9.5888,10.9371C9.6251,10.9195 9.6715,10.9077 9.72,10.9077C9.7717,10.9077 9.8176,10.9189 9.8539,10.9381C9.8885,10.9557 9.9365,10.9669 9.9845,10.9669L9.9915,10.9669L9.9915,11.0613L9.9909,11.0613ZM9.1936,10.9904C9.2443,10.9904 9.2933,11.0027 9.3291,11.0197C9.3632,11.0384 9.4101,11.048 9.4581,11.048C9.5067,11.048 9.552,11.0384 9.5883,11.0187C9.624,11.0021 9.6709,10.9904 9.7195,10.9904C9.7712,10.9904 9.8171,11.0016 9.8533,11.0197C9.8859,11.0373 9.9312,11.0469 9.9771,11.048L9.9771,10.9808C9.9291,10.9797 9.8816,10.9691 9.8475,10.9499C9.8128,10.9323 9.7691,10.9216 9.7189,10.9216C9.6725,10.9216 9.6288,10.9323 9.5941,10.9488C9.5568,10.9685 9.5083,10.9797 9.4576,10.9797C9.4064,10.9797 9.3589,10.9696 9.3227,10.9509C9.288,10.9323 9.2416,10.9216 9.1936,10.9216C9.1445,10.9216 9.1008,10.9323 9.0656,10.9509C9.032,10.9685 8.9851,10.9781 8.936,10.9797L8.9371,11.048C8.9829,11.0469 9.0261,11.0373 9.0603,11.0197C9.096,11.0032 9.144,10.9904 9.1936,10.9904Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.9307,11.1365C8.9819,11.1365 9.0293,11.1259 9.0635,11.1072C9.0971,11.0907 9.1429,11.0779 9.1941,11.0779C9.2448,11.0779 9.2923,11.0901 9.3264,11.1072C9.3611,11.1259 9.4075,11.1365 9.4587,11.1365C9.5109,11.1365 9.5579,11.1243 9.592,11.1061C9.6261,11.0907 9.6699,11.0779 9.72,11.0779C9.7712,11.0779 9.8171,11.0901 9.8512,11.1072C9.8848,11.1248 9.9323,11.1365 9.9845,11.1365L9.9845,11.0565C9.9323,11.0565 9.8848,11.0443 9.8512,11.0261C9.8171,11.0075 9.7712,10.9968 9.72,10.9968C9.6699,10.9968 9.6261,11.0075 9.592,11.0251C9.5573,11.0432 9.5109,11.0549 9.4587,11.0549C9.4075,11.0549 9.3611,11.0437 9.3264,11.0272C9.2923,11.0075 9.2453,10.9968 9.1941,10.9968C9.1429,10.9968 9.0976,11.0075 9.0635,11.0272C9.0293,11.0437 8.9824,11.0549 8.9301,11.0549L8.9307,11.1365" + android:strokeWidth="1" + android:fillColor="#005BBF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9909,11.144L9.984,11.144C9.9339,11.144 9.8837,11.1328 9.848,11.1136C9.8133,11.0949 9.7696,11.0853 9.7195,11.0853C9.6731,11.0853 9.6293,11.0949 9.5947,11.1125C9.5568,11.1323 9.5077,11.144 9.4581,11.144C9.4069,11.144 9.3595,11.1328 9.3232,11.1147C9.2885,11.0949 9.2421,11.0853 9.1941,11.0853C9.1456,11.0853 9.1013,11.0949 9.0672,11.1147C9.0299,11.1323 8.9824,11.144 8.9312,11.144L8.9243,11.144L8.9232,11.048L8.9301,11.048C8.9797,11.048 9.0261,11.0395 9.0608,11.0197C9.096,11.0032 9.144,10.9904 9.1941,10.9904C9.2448,10.9904 9.2933,11.0027 9.3296,11.0197C9.3637,11.0384 9.4107,11.048 9.4587,11.048C9.5072,11.048 9.5525,11.0384 9.5888,11.0187C9.6245,11.0021 9.6709,10.9904 9.72,10.9904C9.7717,10.9904 9.8176,11.0016 9.8539,11.0197C9.8885,11.0395 9.9365,11.0491 9.9845,11.0491L9.9915,11.0491L9.9915,11.144L9.9909,11.144ZM9.1936,11.072C9.2437,11.072 9.2928,11.0827 9.3291,11.1035C9.3632,11.12 9.4101,11.1301 9.4581,11.1301C9.5061,11.1301 9.5515,11.12 9.5883,11.1013C9.624,11.0827 9.6709,11.072 9.7195,11.072C9.7712,11.072 9.8171,11.0827 9.8533,11.1024C9.8864,11.1189 9.9317,11.1285 9.9771,11.1301L9.9771,11.0629C9.9291,11.0619 9.8821,11.0507 9.8475,11.0315C9.8128,11.0149 9.7691,11.0048 9.7189,11.0048C9.6725,11.0048 9.6288,11.0149 9.5941,11.0309C9.5568,11.0512 9.5077,11.0619 9.4576,11.0619C9.4064,11.0619 9.3589,11.0523 9.3227,11.0325C9.2885,11.016 9.2416,11.0048 9.1936,11.0048C9.1445,11.0048 9.1008,11.016 9.0656,11.0315C9.0309,11.0512 8.9851,11.0608 8.9365,11.0619L8.9371,11.1301C8.9824,11.1285 9.0256,11.1189 9.0597,11.1035C9.096,11.0821 9.144,11.072 9.1936,11.072Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7541,10.3936C9.752,10.4021 9.7499,10.4069 9.7499,10.4155C9.7499,10.4656 9.792,10.5029 9.8443,10.5029L9.0693,10.5029C9.1205,10.5029 9.1632,10.4656 9.1632,10.4155C9.1632,10.4069 9.1627,10.4021 9.1605,10.3936C9.1648,10.3947 9.1696,10.3947 9.176,10.3947L9.7403,10.3947C9.7445,10.3947 9.7504,10.3947 9.7541,10.3936" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8443,10.5104L9.0693,10.5104C9.0651,10.5104 9.0624,10.5072 9.0624,10.5029C9.0624,10.5008 9.0651,10.4955 9.0693,10.4955C9.1168,10.4955 9.1568,10.4592 9.1568,10.4155C9.1568,10.4069 9.1557,10.4032 9.1541,10.3947C9.1541,10.3936 9.1541,10.3904 9.1568,10.3904C9.1573,10.3883 9.16,10.3872 9.1632,10.3883C9.1664,10.3904 9.1712,10.3904 9.1755,10.3904L9.7397,10.3904C9.744,10.3904 9.7483,10.3904 9.7509,10.3883C9.7536,10.3872 9.7568,10.3883 9.7589,10.3904C9.76,10.3904 9.76,10.3936 9.76,10.3947L9.7589,10.4011C9.7568,10.4059 9.7568,10.4096 9.7568,10.4155C9.7568,10.4592 9.7957,10.4955 9.8443,10.4955C9.8475,10.4955 9.8507,10.5008 9.8507,10.5029C9.8507,10.5072 9.848,10.5104 9.8443,10.5104ZM9.1195,10.496L9.7931,10.496C9.7632,10.4816 9.7429,10.4512 9.7429,10.416C9.7429,10.4107 9.744,10.4064 9.744,10.4037C9.7424,10.4037 9.7413,10.4037 9.7397,10.4037L9.1755,10.4037C9.1728,10.4037 9.1707,10.4037 9.1691,10.4037C9.1691,10.4069 9.1691,10.4112 9.1691,10.416C9.1696,10.4512 9.1509,10.4811 9.1195,10.496Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.176,10.3435L9.7408,10.3435C9.76,10.3435 9.7749,10.3547 9.7749,10.3701C9.7749,10.3824 9.7595,10.3952 9.7408,10.3952L9.176,10.3952C9.1573,10.3952 9.1419,10.3829 9.1419,10.3701C9.1419,10.3547 9.1568,10.3435 9.176,10.3435" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7403,10.4032L9.1755,10.4032C9.1525,10.4032 9.1344,10.3888 9.1344,10.3696C9.1344,10.352 9.1525,10.336 9.1755,10.336L9.7403,10.336C9.7632,10.336 9.7813,10.3515 9.7813,10.3696C9.7813,10.3888 9.7632,10.4032 9.7403,10.4032ZM9.176,10.3499C9.1605,10.3499 9.1483,10.3573 9.1483,10.3696C9.1483,10.3808 9.1605,10.3904 9.176,10.3904L9.7408,10.3904C9.7552,10.3904 9.7685,10.3803 9.7685,10.3696C9.7685,10.3573 9.7557,10.3499 9.7408,10.3499L9.176,10.3499Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.0693,10.7029l0.7744,0l0,-0.2l-0.7744,0l0,0.2z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8507,10.7072L9.0629,10.7072L9.0629,10.496L9.8507,10.496L9.8507,10.7072ZM9.0757,10.6949L9.8373,10.6949L9.8373,10.5104L9.0757,10.5104L9.0757,10.6949Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.904,9.6448C9.9808,9.6896 10.032,9.7323 10.0245,9.7563C10.0197,9.7781 9.9957,9.7931 9.9605,9.8155C9.9067,9.8528 9.8725,9.9205 9.8987,9.9531C9.8539,9.9157 9.8256,9.8624 9.8256,9.8032C9.8256,9.7387 9.8555,9.6811 9.904,9.6448" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8944,9.9573C9.8464,9.9189 9.8192,9.8624 9.8192,9.8032C9.8192,9.7376 9.8475,9.6784 9.9003,9.6405L9.9035,9.6363L9.9061,9.6395C9.9477,9.6635 10.0437,9.7205 10.0293,9.7573C10.0245,9.7808 10.0005,9.7947 9.9675,9.8187L9.9632,9.8197C9.928,9.8448 9.8997,9.8843 9.8965,9.9173C9.8944,9.9285 9.8949,9.9408 9.9029,9.9493L9.8944,9.9573ZM9.904,9.6533C9.8581,9.6896 9.832,9.7435 9.832,9.8032C9.832,9.8496 9.8507,9.8949 9.8837,9.9296C9.8832,9.9259 9.8837,9.9195 9.8843,9.9157C9.888,9.88 9.9184,9.8379 9.9568,9.8096L9.9605,9.8075C9.9915,9.7877 10.0139,9.7723 10.0176,9.7557C10.0229,9.7408 9.9861,9.7003 9.904,9.6533Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1824,10.3104l0.5499,0l0,-2.6933l-0.5499,0z" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6507,10.3029L9.6368,10.3029L9.6368,7.6155L9.6507,7.6155L9.6507,10.3029ZM9.5883,10.3029L9.576,10.3029L9.576,7.6155L9.5883,7.6155L9.5883,10.3029Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7392,10.3184L9.176,10.3184L9.176,7.6096L9.7392,7.6096L9.7392,10.3184ZM9.1893,10.3045L9.7259,10.3045L9.7259,7.6229L9.1893,7.6229L9.1893,10.3045Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6213,8.6251C8.7419,8.5749 8.9445,8.5397 9.1792,8.5307C9.2603,8.5312 9.3504,8.5397 9.4427,8.5547C9.7723,8.6075 10.0229,8.7408 10.0021,8.8459C10.0016,8.8501 10.0011,8.8549 10.0011,8.8565C10.0011,8.8565 10.1237,8.5787 10.1259,8.5685C10.1483,8.4491 9.8699,8.3035 9.5045,8.2427C9.3909,8.2235 9.2795,8.216 9.1824,8.2176C8.9483,8.2176 8.7445,8.2464 8.6235,8.2928L8.6213,8.6251" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M10.0005,8.8635C10,8.8635 9.9984,8.8635 9.9979,8.8624C9.9947,8.8613 9.9931,8.8571 9.9947,8.8544C9.9947,8.8528 9.9947,8.8507 9.9947,8.8475L9.9952,8.8443C9.9989,8.8277 9.9936,8.8069 9.9792,8.7851C9.9136,8.6933 9.6981,8.6027 9.4416,8.56C9.3531,8.5445 9.2629,8.5381 9.1792,8.5371C8.9557,8.5445 8.7477,8.5792 8.6235,8.6309C8.6219,8.6309 8.6192,8.6309 8.6171,8.6304C8.6155,8.6277 8.6139,8.6277 8.6139,8.6245L8.6165,8.2917C8.6165,8.2901 8.6176,8.2869 8.6197,8.2848C8.7477,8.2389 8.9573,8.2085 9.1819,8.2085L9.1979,8.2085C9.2981,8.2085 9.4048,8.2181 9.5061,8.2347C9.7947,8.2816 10.0384,8.3867 10.1104,8.4912C10.1291,8.5179 10.1365,8.544 10.1323,8.568C10.1307,8.5792 10.0272,8.8117 10.0075,8.8565C10.0053,8.8613 10.0032,8.8635 10.0005,8.8635ZM9.1792,8.5237C9.2635,8.5248 9.3541,8.5323 9.4448,8.5467C9.7045,8.5904 9.9232,8.6821 9.9893,8.7781C10,8.7936 10.0064,8.8075 10.0085,8.8197C10.0571,8.7157 10.1168,8.5771 10.1195,8.5653C10.1227,8.5445 10.1168,8.5227 10.1008,8.4997C10.0293,8.3957 9.7883,8.2944 9.504,8.2485C9.4037,8.232 9.2976,8.2224 9.1979,8.2224L9.1819,8.2224C8.9616,8.2224 8.7563,8.2517 8.6288,8.2955L8.6277,8.6155C8.7541,8.5659 8.9589,8.5312 9.1792,8.5237Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7339,8.9637C9.8859,8.9531 9.9904,8.9104 10.0021,8.8459C10.0117,8.7947 9.9605,8.7408 9.8683,8.6907C9.8267,8.6939 9.7808,8.6997 9.7323,8.6997L9.7339,8.9637" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7269,8.9696L9.7259,8.6933L9.7323,8.6933C9.776,8.6933 9.8171,8.6896 9.8544,8.6821L9.8699,8.6821L9.8715,8.6821C9.9696,8.7381 10.0187,8.7947 10.0085,8.848C9.9968,8.9147 9.8971,8.9573 9.7344,8.9701L9.7269,8.9701L9.7269,8.9696ZM9.7392,8.7061L9.7408,8.9563C9.8901,8.944 9.9856,8.9029 9.9957,8.8448C10.0048,8.8011 9.9589,8.7456 9.8672,8.6949L9.856,8.696C9.8197,8.7019 9.7797,8.7056 9.7392,8.7061Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1819,8.7573C9.0864,8.7696 9.0149,8.7947 8.9792,8.824L8.976,8.8299C8.9595,8.8656 9.0432,8.9408 9.1824,9.0197L9.1824,8.7573" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1888,9.0325L9.1787,9.0283C9.1067,8.9845 8.944,8.8811 8.9691,8.8283L8.9749,8.8187C9.0117,8.7904 9.0821,8.7653 9.1803,8.7509L9.1872,8.7488L9.1888,9.0325ZM8.9856,8.8283L8.9824,8.8325C8.9717,8.8549 9.0171,8.9157 9.176,9.0096L9.176,8.7659C9.0859,8.7781 9.0192,8.8021 8.9856,8.8283Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M10.0757,9.4821C10.0891,9.4405 9.9419,9.3531 9.7312,9.2747C9.6357,9.2405 9.5557,9.2043 9.4571,9.1611C9.1659,9.032 8.9499,8.8821 8.976,8.8304L8.9792,8.8245C8.9632,8.8368 8.9397,9.1024 8.9397,9.1024C8.9136,9.1525 9.1104,9.2981 9.3792,9.4272C9.4651,9.4677 9.6469,9.5344 9.7323,9.5648C9.8859,9.6181 10.0384,9.7179 10.0245,9.7552L10.0757,9.4821" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M10.0245,9.7637C10.0235,9.7637 10.0229,9.7637 10.0229,9.7637C10.0197,9.7621 10.0165,9.7573 10.0176,9.7557L10.0187,9.752C10.0181,9.7157 9.8789,9.6229 9.7296,9.5707C9.6629,9.5477 9.4688,9.4779 9.3749,9.432C9.1403,9.3195 8.9531,9.1904 8.9317,9.1269C8.9285,9.1157 8.9291,9.1072 8.9323,9.1029C8.9387,9.032 8.9536,8.8864 8.9664,8.8352C8.9669,8.832 8.9685,8.8293 8.9691,8.8277L8.9701,8.8256C8.9717,8.8213 8.9723,8.8192 8.9744,8.8192C8.976,8.8165 8.9797,8.8165 8.9819,8.8192C8.984,8.8192 8.9851,8.8245 8.984,8.8277L8.9808,8.832C8.9787,8.8373 8.9787,8.8432 8.9808,8.8507C9.0059,8.9152 9.2059,9.0432 9.4592,9.1552L9.4843,9.1653C9.5707,9.2043 9.6443,9.2373 9.7317,9.2683C9.9184,9.3371 10.0987,9.4304 10.0811,9.4827L10.0811,9.4827L10.0309,9.7525C10.0309,9.7541 10.0309,9.7568 10.0293,9.7568C10.0293,9.7616 10.0267,9.7637 10.0245,9.7637ZM8.9749,8.8656C8.9664,8.9157 8.9541,9.0133 8.9461,9.1029C8.9461,9.1045 8.9456,9.1056 8.9451,9.1061C8.944,9.1093 8.944,9.1157 8.9451,9.1205C8.9659,9.1819 9.1531,9.3109 9.3819,9.4197C9.4635,9.4603 9.6416,9.528 9.7355,9.5584C9.8507,9.6 9.9872,9.6784 10.0229,9.728L10.0693,9.4811C10.0789,9.4475 9.9632,9.3669 9.7291,9.2811C9.6416,9.2496 9.5664,9.2155 9.48,9.1781L9.4539,9.1669C9.2064,9.0571 9.0133,8.9344 8.9749,8.8656Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.9632,8.5061C8.9856,8.4283 9.0112,8.3531 9.0384,8.2736C9.032,8.2768 9.0261,8.2779 9.0197,8.2779C9.0139,8.2779 9.0075,8.2795 9.0011,8.2795C8.9888,8.3344 8.9728,8.3904 8.9541,8.4448C8.9211,8.3968 8.8853,8.3509 8.8571,8.3019C8.8464,8.3029 8.8352,8.3061 8.8229,8.3072C8.8123,8.3083 8.8005,8.3093 8.7883,8.3115C8.8379,8.3781 8.8853,8.4432 8.9301,8.5115C8.9355,8.5093 8.9413,8.5072 8.9477,8.5072C8.9525,8.5061 8.9579,8.5072 8.9632,8.5061M9.1728,8.2773C9.1632,8.2773 9.1531,8.2784 9.1424,8.2784C9.1323,8.2784 9.1227,8.2763 9.1131,8.2752L9.1093,8.4907L9.2608,8.4939C9.2608,8.4907 9.2592,8.4843 9.2597,8.4811C9.2597,8.4773 9.2608,8.4699 9.2608,8.4677C9.2341,8.4693 9.2048,8.4704 9.1701,8.4704L9.1728,8.2773M9.4107,8.3115C9.4352,8.3147 9.4587,8.3184 9.4821,8.3211C9.4821,8.3173 9.4816,8.3136 9.4821,8.3077C9.4821,8.3035 9.4832,8.2992 9.4853,8.2955L9.2789,8.2789C9.2789,8.2832 9.28,8.2875 9.2795,8.2912C9.2789,8.2955 9.2784,8.3019 9.2763,8.3051C9.2981,8.3035 9.3227,8.3035 9.3509,8.3067L9.3333,8.5029C9.344,8.5029 9.3541,8.5029 9.3632,8.5029C9.3728,8.5029 9.3829,8.5056 9.3931,8.5061L9.4107,8.3115M9.4944,8.5259C9.5045,8.528 9.5152,8.528 9.5253,8.5307C9.5355,8.5323 9.5445,8.5344 9.5541,8.5387L9.5781,8.4395L9.5803,8.4405C9.5856,8.4528 9.5941,8.4699 9.5973,8.4779L9.6277,8.5547C9.6389,8.5563 9.6507,8.5573 9.6624,8.5595C9.6747,8.5637 9.6864,8.5659 9.6971,8.5701L9.6869,8.5461C9.6709,8.5136 9.6528,8.4784 9.6389,8.4453C9.6768,8.4453 9.7056,8.4331 9.7131,8.4037C9.7179,8.3819 9.7099,8.3664 9.6901,8.3515C9.6752,8.3408 9.6464,8.3339 9.6283,8.3312L9.5467,8.3131L9.4944,8.5259M9.6005,8.3408C9.6256,8.3461 9.6549,8.352 9.6549,8.3781C9.6549,8.3835 9.6544,8.3904 9.6533,8.3936C9.6448,8.4272 9.6213,8.4368 9.5813,8.4251L9.6005,8.3408M9.8859,8.5904C9.8848,8.6144 9.88,8.6363 9.8757,8.6613C9.8859,8.6656 9.8965,8.6699 9.9072,8.6768C9.9168,8.6811 9.9259,8.688 9.9355,8.6933L9.9557,8.4485C9.9509,8.4453 9.9467,8.4443 9.9419,8.4427C9.9381,8.44 9.9333,8.4379 9.9296,8.4325L9.7136,8.5701C9.72,8.5744 9.7259,8.5776 9.7312,8.5803C9.7365,8.5819 9.7424,8.5861 9.7472,8.5904C9.7648,8.5749 9.784,8.5621 9.8059,8.5445L9.8859,8.5904L9.8859,8.5904ZM9.8256,8.5333L9.8976,8.4885L9.888,8.5685L9.8256,8.5333" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1573,6.3936C6.1163,6.3936 6.0837,6.3621 6.0837,6.3227C6.0837,6.2832 6.1163,6.2528 6.1573,6.2528C6.1984,6.2528 6.2315,6.2832 6.2315,6.3227C6.2315,6.3621 6.1989,6.3936 6.1573,6.3936ZM6.1573,6.2549C6.1179,6.2549 6.0848,6.2848 6.0848,6.3232C6.0848,6.3616 6.1179,6.3925 6.1573,6.3925C6.1973,6.3925 6.2304,6.3616 6.2304,6.3232C6.2304,6.2848 6.1979,6.2549 6.1573,6.2549Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.912,5.7237C7.1365,5.7237 7.3365,5.7573 7.4667,5.8069C7.5419,5.8416 7.6416,5.8667 7.7509,5.8821C7.8357,5.8933 7.9136,5.8944 7.9829,5.8907C8.0763,5.8896 8.2091,5.9157 8.3424,5.9739C8.4533,6.0219 8.5451,6.0821 8.6069,6.1408L8.5536,6.1877L8.5387,6.32L8.3925,6.4885L8.32,6.5499L8.1483,6.6875L8.0608,6.6949L8.0331,6.7701L6.92,6.6411L5.8027,6.7701L5.776,6.6949L5.6885,6.6875L5.5163,6.5499L5.4432,6.4885L5.2987,6.32L5.2827,6.1877L5.2293,6.1408C5.2912,6.0827 5.3829,6.0219 5.4933,5.9739C5.6261,5.9157 5.7605,5.8896 5.8523,5.8907C5.9216,5.8949 6.0011,5.8933 6.0843,5.8821C6.1941,5.8672 6.2944,5.8421 6.3685,5.8069C6.4976,5.7573 6.6875,5.7237 6.912,5.7237Z" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0352,6.776L8.032,6.7749L6.9195,6.6448L5.7995,6.776L5.7728,6.6987L5.6853,6.6901L5.6853,6.6901L5.5131,6.5525L5.4395,6.4901L5.2928,6.3227L5.2928,6.3205L5.2784,6.1904L5.2229,6.1403L5.2261,6.1371C5.2912,6.0779 5.3856,6.0165 5.4923,5.9696C5.6117,5.9168 5.7435,5.8843 5.8443,5.8843C5.8469,5.8843 5.8501,5.8853 5.8528,5.8853C5.9243,5.8907 6.0043,5.8896 6.0843,5.8779C6.1979,5.8624 6.2955,5.8373 6.368,5.8043C6.5061,5.7493 6.7003,5.7195 6.9136,5.7195C7.1307,5.7195 7.3333,5.7509 7.4704,5.8043C7.5429,5.8373 7.6395,5.8619 7.7531,5.8779C7.8336,5.8891 7.9136,5.8901 7.9835,5.8853C7.9867,5.8853 7.9899,5.8843 7.9931,5.8843C8.0933,5.8843 8.2251,5.9173 8.3461,5.9696C8.4523,6.0171 8.5461,6.0779 8.6112,6.1371L8.6149,6.1403L8.5589,6.1904L8.544,6.3227L8.3979,6.4901L8.3253,6.5525L8.1515,6.6901L8.1504,6.6901L8.0656,6.6987L8.0352,6.776ZM5.6885,6.6821L5.7787,6.6907L5.8048,6.7659L6.9189,6.6357L8.0288,6.7659L8.0565,6.6907L8.1451,6.6821L8.3163,6.5445L8.3888,6.4832L8.5333,6.32L8.5483,6.1845L8.5995,6.1408C8.536,6.0816 8.4443,6.024 8.3408,5.9781C8.2213,5.9259 8.0917,5.8949 7.9915,5.8949C7.9883,5.8949 7.9851,5.8949 7.9824,5.8949C7.96,5.8949 7.9349,5.896 7.9099,5.896C7.8576,5.896 7.8037,5.8939 7.7504,5.8864C7.6363,5.8699 7.5381,5.8448 7.4651,5.8133C7.3291,5.7573 7.128,5.728 6.912,5.728C6.7008,5.728 6.5067,5.7573 6.3691,5.8133C6.2976,5.8448 6.1979,5.8693 6.0843,5.8864C6.0037,5.896 5.9227,5.8997 5.8507,5.8949C5.8485,5.8949 5.8459,5.8949 5.8427,5.8949C5.7435,5.8949 5.6123,5.9264 5.4939,5.9781C5.3909,6.024 5.2981,6.0811 5.2347,6.1408L5.2859,6.1845L5.2864,6.1877L5.3008,6.32L5.4459,6.4848L5.5184,6.5451L5.6885,6.6821Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9291,7.1936C6.5136,7.1936 6.1419,7.1435 5.8773,7.0656C5.8576,7.0571 5.848,7.0405 5.8485,7.0208C5.848,7.0048 5.8587,6.9883 5.8773,6.9824C6.1424,6.9035 6.5136,6.8533 6.9291,6.8533C7.3445,6.8533 7.7157,6.9035 7.9803,6.9824C7.9989,6.9888 8.0091,7.0048 8.0085,7.0208C8.0101,7.0405 8,7.0571 7.9803,7.0656C7.7152,7.144 7.3445,7.1936 6.9291,7.1936" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9291,7.2011L6.9291,7.2011C6.5259,7.2 6.1509,7.1531 5.8757,7.0699C5.8539,7.0656 5.8416,7.0448 5.8421,7.0197C5.8421,7.0011 5.8544,6.9824 5.8757,6.9771C6.1515,6.8933 6.5259,6.8459 6.9291,6.8448C7.3317,6.8459 7.7067,6.8933 7.9819,6.9771C8.0032,6.9824 8.0165,7.0011 8.0155,7.0208C8.0165,7.0448 8.0043,7.0656 7.9819,7.0699C7.7067,7.1531 7.3317,7.2 6.9291,7.2011ZM6.9291,6.8581C6.5269,6.8592 6.1541,6.9061 5.8789,6.9893C5.8635,6.9936 5.8549,7.0059 5.8555,7.0208C5.8544,7.0405 5.8635,7.0533 5.8789,7.0571C6.1541,7.1403 6.5264,7.1861 6.9291,7.1872C7.3312,7.1861 7.704,7.1403 7.9792,7.0571C7.9947,7.0528 8.0032,7.0405 8.0021,7.0219C8.0027,7.0064 7.9936,6.9936 7.9792,6.9893C7.704,6.9061 7.3307,6.8592 6.9291,6.8581Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.928,7.1408C6.5536,7.1408 6.2149,7.0949 5.9568,7.0283C6.2149,6.9627 6.5541,6.92 6.928,6.92C7.3019,6.92 7.6421,6.9627 7.9003,7.0283C7.6421,7.0949 7.3019,7.1408 6.928,7.1408" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9851,7.0187l0.0315,0l0,0.0219l-0.0315,0z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,6.8533C6.5067,6.8533 6.1285,6.9067 5.8635,6.9888C5.8859,6.9781 5.8843,6.9515 5.8565,6.88C5.8229,6.7941 5.7723,6.7973 5.7723,6.7973C6.0651,6.712 6.4725,6.6576 6.928,6.6565C7.3819,6.6576 7.7941,6.712 8.0869,6.7973C8.0869,6.7973 8.0347,6.7941 8.0021,6.88C7.9755,6.9515 7.9723,6.9787 7.9941,6.9888C7.7291,6.9061 7.3456,6.8533 6.9253,6.8533" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9931,6.9936C7.7168,6.9072 7.3291,6.8592 6.9259,6.8571C6.5291,6.8592 6.1419,6.9072 5.8667,6.9936L5.8613,6.9813C5.8757,6.9749 5.8795,6.9563 5.8507,6.8821C5.8219,6.8059 5.7781,6.8043 5.7728,6.8043L5.7696,6.7904C6.0779,6.7008 6.488,6.6507 6.928,6.6496C7.3691,6.6507 7.7819,6.7008 8.088,6.7904L8.0864,6.8043L8.0864,6.8043C8.0816,6.8043 8.0379,6.8059 8.0085,6.8821C7.9792,6.9563 7.9824,6.9749 7.9979,6.9813L7.9931,6.9936ZM6.9253,6.8448C7.3189,6.8448 7.7003,6.8939 7.9755,6.9749C7.9691,6.9557 7.9787,6.9227 7.9963,6.8779C8.0165,6.8277 8.0416,6.8059 8.0608,6.7957C7.7568,6.7104 7.3568,6.6645 6.928,6.6635C6.5003,6.6645 6.1003,6.7104 5.7973,6.7957C5.8171,6.8064 5.8432,6.8283 5.8629,6.8779C5.8811,6.9227 5.8901,6.9557 5.8843,6.9749C6.1595,6.8939 6.5376,6.8448 6.9253,6.8448Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.928,6.656C6.4725,6.6571 6.0656,6.7115 5.7723,6.7968C5.752,6.8032 5.7312,6.7947 5.7253,6.7781C5.7189,6.7573 5.7291,6.7387 5.7488,6.7323C6.0437,6.6405 6.4624,6.5845 6.9275,6.5824C7.3931,6.5835 7.8123,6.6405 8.1072,6.7323C8.1275,6.7387 8.1371,6.7573 8.1307,6.7781C8.1243,6.7947 8.1035,6.8032 8.0843,6.7968C7.7915,6.7115 7.3819,6.6571 6.928,6.656" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0981,6.8064C8.0939,6.8064 8.088,6.8064 8.0837,6.8048C7.7781,6.7157 7.3675,6.6656 6.928,6.6635C6.4885,6.6656 6.0789,6.7157 5.7733,6.8048C5.7691,6.8064 5.7632,6.8064 5.7589,6.8064C5.7403,6.8064 5.7248,6.7952 5.7189,6.7797C5.7163,6.7685 5.7163,6.7573 5.7216,6.7461C5.7264,6.7365 5.7355,6.7285 5.7472,6.7264C6.056,6.6315 6.4752,6.5787 6.9275,6.5787C7.3744,6.5787 7.8053,6.6331 8.1093,6.7264C8.1205,6.7285 8.1296,6.7371 8.1344,6.7461C8.1408,6.7573 8.1408,6.7691 8.1371,6.7797C8.1323,6.7947 8.1168,6.8064 8.0981,6.8064ZM6.928,6.6501C7.3691,6.6512 7.7808,6.7024 8.088,6.7909C8.104,6.7952 8.1211,6.7909 8.1253,6.7765C8.1285,6.7691 8.1275,6.76 8.1237,6.7536C8.1195,6.7451 8.1131,6.7413 8.1067,6.7403C7.8032,6.6453 7.3728,6.5915 6.928,6.5915C6.4757,6.5915 6.0587,6.6448 5.7504,6.7403C5.7435,6.7413 5.7376,6.7456 5.7333,6.7536C5.7296,6.76 5.7291,6.7691 5.7317,6.7765C5.7365,6.7909 5.7541,6.7952 5.7696,6.7909C6.0768,6.7019 6.488,6.6512 6.928,6.6501Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.6037,6.7584C6.6037,6.7408 6.6197,6.7248 6.6411,6.7248C6.6608,6.7248 6.6779,6.7403 6.6779,6.7584C6.6779,6.7781 6.6608,6.7947 6.6411,6.7947C6.6197,6.7947 6.6037,6.7781 6.6037,6.7584" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.6416,6.8032C6.6165,6.8032 6.5979,6.7824 6.5979,6.7584C6.5979,6.7365 6.6165,6.7184 6.6416,6.7184C6.6651,6.7184 6.6853,6.7365 6.6853,6.7584C6.6853,6.7824 6.6651,6.8032 6.6416,6.8032ZM6.6416,6.7312C6.624,6.7312 6.6101,6.7435 6.6101,6.7584C6.6101,6.776 6.624,6.7899 6.6416,6.7899C6.6571,6.7899 6.672,6.7765 6.672,6.7584C6.6715,6.744 6.6571,6.7312 6.6416,6.7312Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9291,6.7877L6.8176,6.7877C6.7979,6.7877 6.7803,6.7701 6.7803,6.7536C6.7803,6.7328 6.7973,6.7179 6.8171,6.7179L7.0421,6.7179C7.0635,6.7179 7.0795,6.7328 7.0795,6.7536C7.0795,6.7701 7.0624,6.7877 7.0421,6.7877L6.9291,6.7877" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0416,6.7936L6.8176,6.7936C6.7936,6.7936 6.7733,6.776 6.7733,6.7531C6.7733,6.728 6.7936,6.7093 6.8171,6.7093L7.0421,6.7093C7.0672,6.7093 7.0859,6.728 7.0859,6.7531C7.0853,6.776 7.0667,6.7936 7.0416,6.7936ZM6.8165,6.7237C6.8005,6.7237 6.7867,6.736 6.7867,6.7531C6.7867,6.768 6.8005,6.7813 6.8176,6.7813L7.0416,6.7813C7.0587,6.7813 7.0731,6.7685 7.0731,6.7531C7.0731,6.7365 7.0592,6.7237 7.0416,6.7237L6.8165,6.7237Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.3696,6.8181L6.2907,6.8283C6.2693,6.8299 6.2507,6.816 6.248,6.7957C6.2459,6.7781 6.2603,6.7595 6.2811,6.7573L6.3611,6.7477L6.4432,6.7403C6.4635,6.736 6.4821,6.7499 6.4853,6.7696C6.4869,6.7893 6.4731,6.8059 6.4512,6.8069L6.3696,6.8181" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.2853,6.8325C6.2629,6.8325 6.2443,6.8192 6.2416,6.7973C6.2411,6.7872 6.2437,6.7776 6.2507,6.7675C6.2571,6.7573 6.2683,6.7536 6.28,6.7525L6.4421,6.7328C6.4667,6.7301 6.4885,6.7451 6.4917,6.7691C6.4917,6.7787 6.4891,6.7909 6.4821,6.7984C6.4757,6.808 6.464,6.8149 6.4528,6.816L6.2917,6.8325C6.2891,6.8325 6.288,6.8325 6.2853,6.8325ZM6.4475,6.7445C6.4464,6.7445 6.4443,6.7445 6.4443,6.7445L6.2816,6.7653C6.2725,6.7653 6.2661,6.7685 6.2597,6.776C6.256,6.7813 6.2533,6.7893 6.2544,6.7947C6.2565,6.8112 6.2725,6.8219 6.2885,6.8197L6.4501,6.8032C6.4592,6.8021 6.4661,6.7947 6.4725,6.7909C6.4757,6.7835 6.4789,6.7787 6.4779,6.7701C6.4757,6.7563 6.4629,6.7445 6.4475,6.7445Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0448,6.8251C6.0448,6.8059 6.0619,6.7909 6.0816,6.7909C6.1029,6.7909 6.1189,6.8059 6.1189,6.8251C6.1189,6.8448 6.1029,6.8592 6.0816,6.8592C6.0619,6.8592 6.0448,6.8448 6.0448,6.8251" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0816,6.8656C6.0581,6.8656 6.0379,6.8469 6.0379,6.8251C6.0379,6.8032 6.0581,6.7824 6.0816,6.7824C6.1067,6.7824 6.1253,6.8032 6.1253,6.8251C6.1253,6.8469 6.1067,6.8656 6.0816,6.8656ZM6.0816,6.7947C6.0656,6.7947 6.0512,6.8069 6.0512,6.8251C6.0512,6.8405 6.0651,6.8533 6.0816,6.8533C6.0987,6.8533 6.1131,6.8411 6.1131,6.8251C6.1131,6.8075 6.0992,6.7947 6.0816,6.7947Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.7979,6.8907l0.0411,-0.0571l0.1152,0.016l-0.0917,0.0661l-0.0645,-0.0251" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.8629,6.9227L5.7877,6.8901L5.8357,6.8277L5.9696,6.8443L5.8629,6.9227ZM5.8085,6.8853L5.8613,6.9072L5.936,6.8528L5.8421,6.8416L5.8085,6.8853Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.488,6.8181L7.5664,6.8283C7.5877,6.8299 7.6064,6.816 7.6091,6.7957C7.6107,6.7781 7.5973,6.7595 7.576,6.7573L7.496,6.7477L7.4139,6.7403C7.3936,6.736 7.3749,6.7499 7.3723,6.7696C7.3701,6.7893 7.3845,6.8059 7.4059,6.8069L7.488,6.8181" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.5728,6.8325L7.5728,6.8325C7.5696,6.8325 7.5685,6.8325 7.5664,6.8325L7.4048,6.816C7.3931,6.8149 7.3819,6.8075 7.3755,6.7984C7.368,6.7909 7.3653,6.7787 7.3664,6.7691C7.3691,6.7451 7.3915,6.7301 7.4155,6.7328L7.5776,6.7525C7.5888,6.7536 7.6,6.7579 7.6069,6.7675C7.6133,6.7776 7.6165,6.7867 7.6165,6.7973C7.6128,6.8187 7.5941,6.8325 7.5728,6.8325ZM7.4101,6.7445C7.3941,6.7445 7.3819,6.7557 7.3792,6.7696C7.3792,6.7781 7.3808,6.7829 7.3851,6.7904C7.3904,6.7947 7.3973,6.8016 7.4069,6.8027L7.568,6.8192C7.5851,6.8213 7.6005,6.8096 7.6027,6.7941C7.6037,6.7888 7.6005,6.7808 7.5968,6.7755C7.5915,6.768 7.5845,6.7648 7.5755,6.7648L7.4128,6.744C7.4128,6.7445 7.4107,6.7445 7.4101,6.7445Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1787,6.7584C7.1787,6.7408 7.1963,6.7248 7.216,6.7248C7.2373,6.7248 7.2533,6.7403 7.2533,6.7584C7.2533,6.7781 7.2368,6.7947 7.216,6.7947C7.1963,6.7947 7.1787,6.7781 7.1787,6.7584" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2165,6.8032C7.1925,6.8032 7.1728,6.7824 7.1728,6.7584C7.1728,6.7365 7.1925,6.7184 7.2165,6.7184C7.2416,6.7184 7.2603,6.7365 7.2603,6.7584C7.2603,6.7824 7.2416,6.8032 7.2165,6.8032ZM7.2165,6.7312C7.2005,6.7312 7.1856,6.7435 7.1856,6.7584C7.1856,6.776 7.2005,6.7899 7.2165,6.7899C7.2336,6.7899 7.248,6.7765 7.248,6.7584C7.2475,6.744 7.2336,6.7312 7.2165,6.7312Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7381,6.8251C7.7381,6.8059 7.7541,6.7909 7.7755,6.7909C7.7952,6.7909 7.8128,6.8059 7.8128,6.8251C7.8128,6.8448 7.7952,6.8592 7.7755,6.8592C7.7541,6.8592 7.7381,6.8448 7.7381,6.8251" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7755,6.8656C7.7504,6.8656 7.7317,6.8469 7.7317,6.8251C7.7317,6.8032 7.7504,6.7824 7.7755,6.7824C7.7989,6.7824 7.8192,6.8032 7.8192,6.8251C7.8192,6.8469 7.7995,6.8656 7.7755,6.8656ZM7.7755,6.7947C7.7579,6.7947 7.744,6.8069 7.744,6.8251C7.744,6.8405 7.7579,6.8533 7.7755,6.8533C7.7915,6.8533 7.8059,6.8411 7.8059,6.8251C7.8059,6.8075 7.7915,6.7947 7.7755,6.7947Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0603,6.8907l-0.0416,-0.0571l-0.1147,0.016l0.0912,0.0661l0.0651,-0.0251" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9941,6.9227L7.8869,6.8448L8.0208,6.8283L8.0688,6.8907L7.9941,6.9227ZM7.9221,6.8533L7.9968,6.9077L8.0496,6.8859L8.016,6.8427L7.9221,6.8533ZM7.9435,7.0459C7.6704,6.9696 7.3104,6.928 6.9285,6.928C6.5483,6.928 6.1877,6.9696 5.9147,7.0459L5.9109,7.0336C6.1856,6.9573 6.5461,6.9157 6.9285,6.9157C7.3109,6.9157 7.6731,6.9573 7.9472,7.0336L7.9435,7.0459Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0891,6.0181L6.136,6.0555L6.2069,5.9403C6.1301,5.8933 6.0784,5.8133 6.0784,5.7195C6.0784,5.7083 6.0789,5.6997 6.0795,5.6901C6.0875,5.5429 6.2667,5.4192 6.4928,5.4192C6.6101,5.4192 6.7163,5.4528 6.7915,5.5051C6.7941,5.4816 6.7957,5.464 6.7989,5.4416C6.7168,5.3941 6.6101,5.3648 6.4928,5.3648C6.232,5.3648 6.0283,5.5136 6.0181,5.6896C6.0165,5.6992 6.0165,5.7072 6.0165,5.7189C6.0165,5.8139 6.0597,5.8971 6.1264,5.9552L6.0891,6.0181" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1381,6.0656L6.0811,6.0197L6.1184,5.9573C6.0491,5.8949 6.0101,5.8085 6.0101,5.72C6.0101,5.7088 6.0101,5.6992 6.0112,5.6896C6.0224,5.5029 6.2331,5.3573 6.4928,5.3573C6.6069,5.3573 6.7163,5.3867 6.8021,5.4368L6.8069,5.4405L6.8059,5.4437C6.8032,5.4613 6.8011,5.4795 6.7979,5.5061L6.7979,5.5173L6.7883,5.5104C6.712,5.4571 6.6043,5.4283 6.4928,5.4283C6.2725,5.4283 6.0944,5.5435 6.0864,5.6907C6.0853,5.7003 6.0853,5.7083 6.0853,5.72C6.0853,5.8064 6.1317,5.8869 6.2101,5.9344L6.2165,5.9397L6.1381,6.0656ZM6.0976,6.0155L6.1349,6.0448L6.1973,5.9435C6.1184,5.8923 6.0715,5.8075 6.0715,5.72C6.0715,5.7077 6.0725,5.6992 6.0725,5.6896C6.0811,5.5344 6.2656,5.4155 6.4928,5.4155C6.6037,5.4155 6.7072,5.4432 6.7856,5.4933C6.7877,5.4747 6.7893,5.4592 6.7915,5.4443C6.7077,5.3973 6.6021,5.3701 6.4928,5.3701C6.2405,5.3701 6.0352,5.5109 6.0251,5.6901C6.0235,5.6997 6.0229,5.7088 6.0229,5.7195C6.0229,5.8069 6.0635,5.8917 6.1323,5.9531L6.1355,5.9557L6.0976,6.0155Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0917,6.0187C6.0037,5.9531 5.9472,5.8624 5.9472,5.7632C5.9472,5.6475 6.0224,5.5445 6.1365,5.4779C6.0661,5.5333 6.0235,5.6069 6.0176,5.6901C6.016,5.6997 6.016,5.7077 6.016,5.7195C6.016,5.8144 6.0592,5.8976 6.1259,5.9557L6.0917,6.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0944,6.0283L6.088,6.0251C5.9941,5.9531 5.9413,5.8603 5.9413,5.7637C5.9413,5.6523 6.0112,5.5451 6.1333,5.472L6.1413,5.4827C6.0704,5.5408 6.0304,5.6117 6.0245,5.6912C6.0229,5.7008 6.0224,5.7099 6.0224,5.7205C6.0224,5.808 6.0629,5.8928 6.1317,5.9541L6.1349,5.9568L6.0944,6.0283ZM6.0757,5.5296C5.9979,5.5947 5.9541,5.6779 5.9541,5.7632C5.9541,5.8544 6.0032,5.9419 6.0907,6.008L6.1189,5.9568C6.0496,5.8944 6.0101,5.808 6.0101,5.7195C6.0101,5.7083 6.0101,5.6987 6.0112,5.6891C6.0165,5.6315 6.0379,5.5781 6.0757,5.5296Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.3067,6.1344C5.2565,6.0795 5.2261,6.0075 5.2261,5.928C5.2261,5.8811 5.2379,5.8341 5.2571,5.7947C5.3291,5.6448 5.5557,5.5392 5.824,5.5392C5.8976,5.5392 5.9669,5.5445 6.032,5.5611C6.0176,5.5776 6.0069,5.5936 5.9952,5.6112C5.9413,5.6016 5.8843,5.5947 5.824,5.5947C5.5792,5.5947 5.3728,5.6907 5.3131,5.8197C5.2976,5.8533 5.288,5.8907 5.288,5.928C5.288,6.0069 5.3253,6.0779 5.3819,6.1259L5.2939,6.2699L5.2453,6.2325L5.3067,6.1344" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.2944,6.2805L5.2368,6.2331L5.2981,6.1349C5.2469,6.0779 5.2192,6.0027 5.2192,5.9275C5.2192,5.88 5.2304,5.8325 5.2512,5.7899C5.3269,5.6357 5.5568,5.5317 5.824,5.5317C5.8971,5.5317 5.9664,5.5403 6.0336,5.5541L6.0448,5.5568L6.0373,5.5653C6.0229,5.5808 6.0128,5.5968 6.0011,5.6155L5.9989,5.6187L5.9952,5.6181C5.9403,5.6069 5.8827,5.6032 5.8251,5.6032C5.5877,5.6032 5.3803,5.6933 5.3205,5.8219C5.3045,5.856 5.2955,5.8907 5.2955,5.928C5.2955,6.0032 5.3301,6.0699 5.3877,6.1195L5.3925,6.1237L5.2944,6.2805ZM5.2539,6.2315L5.2912,6.2608L5.3733,6.1285C5.3147,6.0763 5.2816,6.0037 5.2816,5.9285C5.2816,5.8912 5.2901,5.8533 5.3067,5.8176C5.3691,5.6827 5.5819,5.5899 5.824,5.5899C5.8816,5.5899 5.9381,5.5941 5.992,5.6032C6.0005,5.5909 6.0101,5.5781 6.0192,5.5659C5.9568,5.5536 5.8912,5.5451 5.824,5.5451C5.5664,5.5451 5.3349,5.6491 5.2629,5.7973C5.2432,5.84 5.2325,5.8827 5.2325,5.9285C5.2325,6.0037 5.2603,6.0741 5.3115,6.1317L5.3125,6.1328L5.3125,6.1381L5.3125,6.1413L5.2539,6.2315Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.3979,5.6469C5.3333,5.6896 5.2853,5.7397 5.2571,5.7947C5.2384,5.8341 5.2261,5.8811 5.2261,5.928C5.2261,6.0069 5.2571,6.0795 5.3067,6.1344L5.2528,6.2219C5.2,6.1563 5.1707,6.0779 5.1707,5.9947C5.1707,5.8549 5.2613,5.7307 5.3979,5.6469" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.2539,6.2336L5.2475,6.2283C5.1931,6.1573 5.1643,6.0784 5.1643,5.9947C5.1643,5.8581 5.2475,5.7307 5.3947,5.6421L5.4016,5.6533C5.3376,5.6939 5.2896,5.744 5.2635,5.7973C5.2437,5.84 5.2331,5.8827 5.2331,5.9285C5.2331,6.0037 5.2608,6.0741 5.312,6.1317L5.3152,6.1339L5.2539,6.2336ZM5.2619,5.7707C5.2064,5.8405 5.1776,5.9152 5.1776,5.9947C5.1776,6.0699 5.2037,6.1445 5.2523,6.2112L5.2987,6.1349C5.2475,6.0779 5.2197,6.0027 5.2197,5.9275C5.2197,5.88 5.2309,5.8325 5.2517,5.7899C5.2544,5.7845 5.2576,5.7781 5.2619,5.7707Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,5.3365C6.9851,5.3365 7.0352,5.376 7.0475,5.4283C7.0565,5.4763 7.0603,5.5285 7.0624,5.5845C7.0624,5.5909 7.0619,5.5952 7.0619,5.6032C7.0619,5.6075 7.0629,5.6155 7.0629,5.6229C7.0656,5.7424 7.0816,5.8459 7.1067,5.9115L6.9253,6.0843L6.7413,5.9115C6.7664,5.8459 6.7819,5.7424 6.7851,5.6229C6.7851,5.6155 6.7856,5.6075 6.7856,5.6032C6.7856,5.5947 6.7851,5.5909 6.7851,5.5845C6.7867,5.5285 6.7909,5.4763 6.8,5.4283C6.8123,5.376 6.8656,5.3365 6.9253,5.3365" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,6.0949L6.7333,5.9147L6.7349,5.9072C6.76,5.8437 6.7755,5.7371 6.7787,5.6229C6.7787,5.6197 6.7787,5.6155 6.7787,5.6133C6.7787,5.608 6.7787,5.6059 6.7787,5.6027C6.7787,5.6005 6.7787,5.5963 6.7787,5.5941C6.7787,5.5915 6.7787,5.5888 6.7787,5.5835C6.7797,5.5285 6.7851,5.4773 6.7936,5.4272C6.8064,5.3691 6.8629,5.3285 6.9253,5.3285C6.9872,5.3285 7.0411,5.3685 7.0539,5.4272C7.0629,5.4763 7.0672,5.5275 7.0693,5.5835C7.0693,5.5888 7.0693,5.5899 7.0688,5.5941C7.0688,5.5963 7.0688,5.5995 7.0688,5.6027C7.0688,5.6053 7.0693,5.6069 7.0693,5.6117C7.0693,5.6155 7.0693,5.6197 7.0693,5.6229C7.0725,5.7355 7.088,5.8432 7.1131,5.9072L7.1136,5.9147L6.9253,6.0949ZM6.7488,5.9083L6.9253,6.0768L7.0981,5.9083C7.0741,5.8421 7.0581,5.7344 7.0565,5.6229C7.0565,5.6197 7.0565,5.6155 7.056,5.6133C7.0555,5.608 7.0549,5.6059 7.0549,5.6027C7.0549,5.5995 7.0549,5.5952 7.0549,5.5941C7.0549,5.5899 7.0555,5.5888 7.0549,5.5835C7.0533,5.5285 7.0496,5.4773 7.0411,5.4288C7.0293,5.3787 6.9808,5.3424 6.9253,5.3424C6.8693,5.3424 6.8171,5.3797 6.8064,5.4288C6.7973,5.4773 6.7936,5.5301 6.792,5.5835C6.792,5.5888 6.792,5.5915 6.792,5.5941C6.792,5.5963 6.792,5.5995 6.792,5.6027C6.792,5.6059 6.7915,5.6091 6.7909,5.6149C6.7909,5.6165 6.7909,5.6192 6.7909,5.6224C6.7888,5.7355 6.7728,5.8432 6.7488,5.9083Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,5.3931C6.9563,5.3931 6.9813,5.4123 6.9877,5.4405C6.9957,5.4821 7,5.5333 7.0011,5.5883C7.0011,5.5936 7.0005,5.5989 7.0005,5.6027C7.0005,5.6101 7.0027,5.6165 7.0027,5.6235C7.0037,5.736 7.0203,5.8341 7.0437,5.8944L6.9232,6.008L6.8032,5.8944C6.8261,5.8352 6.8427,5.736 6.8443,5.6235C6.8443,5.6165 6.8464,5.6101 6.8464,5.6027C6.8464,5.5984 6.8459,5.5931 6.8459,5.5883C6.8469,5.5328 6.8512,5.4821 6.8597,5.4405C6.8667,5.4123 6.8944,5.3931 6.9253,5.3931" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9237,6.0187L6.7968,5.8976L6.7973,5.8933C6.8213,5.8309 6.8363,5.7307 6.8379,5.6235C6.8379,5.6192 6.8384,5.6165 6.8389,5.6139C6.8395,5.6085 6.84,5.6064 6.84,5.6027C6.84,5.6027 6.84,5.5984 6.84,5.5941C6.84,5.5931 6.84,5.5899 6.84,5.5877C6.8416,5.5344 6.8453,5.4827 6.8544,5.4389C6.8608,5.4064 6.8917,5.3856 6.9259,5.3856C6.9595,5.3856 6.9883,5.4064 6.9947,5.4389C7.0032,5.4827 7.0069,5.536 7.0085,5.5877C7.0085,5.5899 7.0085,5.5931 7.0085,5.5941C7.0085,5.5984 7.0085,5.6027 7.0085,5.6027C7.0085,5.6069 7.0091,5.6101 7.0096,5.6149C7.0096,5.6165 7.0101,5.6192 7.0107,5.6235C7.0112,5.7307 7.0261,5.8309 7.0512,5.8933L7.0517,5.8976L6.9237,6.0187ZM6.8117,5.8949L6.9237,6.0021L7.0352,5.8949C7.0128,5.8309 6.9973,5.7307 6.9957,5.6245C6.9957,5.6197 6.9952,5.6187 6.9947,5.6155C6.9941,5.6112 6.9941,5.6069 6.9941,5.6032C6.9941,5.6032 6.9941,5.5989 6.9941,5.5947C6.9941,5.5936 6.9941,5.5904 6.9941,5.5883C6.9941,5.5371 6.9888,5.4864 6.9813,5.4405C6.9749,5.4155 6.9525,5.3995 6.9253,5.3995C6.8976,5.3995 6.8715,5.4171 6.8661,5.4405C6.8581,5.4853 6.8539,5.5371 6.8528,5.5883C6.8528,5.5904 6.8528,5.5936 6.8533,5.5947C6.8533,5.5989 6.8533,5.6032 6.8533,5.6032C6.8533,5.6075 6.8528,5.6117 6.8523,5.6155C6.8517,5.6181 6.8512,5.6197 6.8512,5.6245C6.8507,5.7307 6.8352,5.8315 6.8117,5.8949Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7595,6.0181L7.7131,6.0555L7.6416,5.9403C7.7189,5.8933 7.7707,5.8133 7.7707,5.7195C7.7707,5.7083 7.7696,5.6997 7.7696,5.6901C7.7616,5.5429 7.5819,5.4192 7.3568,5.4192C7.2384,5.4192 7.1323,5.4528 7.0571,5.5051C7.0549,5.4816 7.0533,5.464 7.0501,5.4416C7.1323,5.3941 7.2389,5.3648 7.3568,5.3648C7.6171,5.3648 7.8213,5.5136 7.8315,5.6896C7.832,5.6992 7.832,5.7072 7.832,5.7189C7.832,5.8139 7.7893,5.8971 7.7227,5.9552L7.7595,6.0181" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7104,6.0656L7.6325,5.9397L7.6384,5.9344C7.7168,5.8869 7.7637,5.8064 7.7637,5.72C7.7637,5.7088 7.7632,5.7003 7.7627,5.6907C7.7547,5.5435 7.576,5.4283 7.3563,5.4283C7.2427,5.4283 7.1381,5.4576 7.0603,5.5104L7.0507,5.5173L7.0507,5.5061C7.048,5.4821 7.0469,5.4656 7.0432,5.4437L7.0421,5.4405L7.0464,5.4368C7.1317,5.3861 7.2421,5.3573 7.3563,5.3573C7.6155,5.3573 7.8267,5.5029 7.8379,5.6907C7.8379,5.7003 7.8379,5.7093 7.8379,5.72C7.8379,5.8085 7.7995,5.8949 7.7301,5.9573L7.768,6.0197L7.7104,6.0656ZM7.6507,5.9435L7.7136,6.0448L7.7504,6.0155L7.7131,5.9557L7.7173,5.9531C7.7861,5.8923 7.8256,5.8075 7.8256,5.7195C7.8256,5.7099 7.8256,5.7008 7.8245,5.6901C7.8139,5.5109 7.6085,5.3701 7.3568,5.3701C7.2469,5.3701 7.1413,5.3973 7.0571,5.4443C7.0603,5.4613 7.0608,5.4779 7.0635,5.4933C7.1419,5.4427 7.2448,5.4155 7.3568,5.4155C7.584,5.4155 7.768,5.5344 7.776,5.6907C7.7765,5.6992 7.7776,5.7072 7.7776,5.72C7.7771,5.8075 7.7301,5.8907 7.6507,5.9435Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7568,6.0187C7.8448,5.9531 7.9008,5.8624 7.9008,5.7632C7.9008,5.6475 7.8256,5.5445 7.712,5.4779C7.7819,5.5333 7.8245,5.6069 7.8309,5.6901C7.8315,5.6997 7.8315,5.7077 7.8315,5.7195C7.8315,5.8144 7.7888,5.8976 7.7221,5.9557L7.7568,6.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7541,6.0283L7.7131,5.9557L7.7173,5.9531C7.7861,5.8923 7.8256,5.8075 7.8256,5.7195C7.8256,5.7099 7.8256,5.7008 7.8245,5.6901C7.8187,5.6112 7.7787,5.5403 7.7072,5.4816L7.7157,5.4709C7.8379,5.544 7.9072,5.6512 7.9072,5.7627C7.9072,5.8597 7.8549,5.952 7.7605,6.024L7.7541,6.0283ZM7.7301,5.9573L7.7584,6.0085C7.8464,5.9424 7.8944,5.8549 7.8944,5.7637C7.8944,5.6784 7.8507,5.5952 7.7728,5.5301C7.8101,5.5787 7.8325,5.6315 7.8384,5.6901C7.8384,5.7008 7.8384,5.7099 7.8384,5.7205C7.8379,5.8085 7.7995,5.8949 7.7301,5.9573Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.5419,6.1344C8.592,6.0795 8.6229,6.0075 8.6229,5.928C8.6229,5.8811 8.6112,5.8341 8.5915,5.7947C8.5189,5.6448 8.2928,5.5392 8.0245,5.5392C7.9504,5.5392 7.8816,5.5445 7.8165,5.5611C7.832,5.5776 7.8416,5.5936 7.8539,5.6112C7.9067,5.6016 7.9648,5.5947 8.0245,5.5947C8.2699,5.5947 8.4757,5.6907 8.5355,5.8197C8.5509,5.8533 8.5605,5.8907 8.5605,5.928C8.5605,6.0069 8.5237,6.0779 8.4667,6.1259L8.5547,6.2699L8.6032,6.2325L8.5419,6.1344" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.5541,6.2805L8.4565,6.1237L8.4619,6.1195C8.5195,6.0693 8.5541,6.0027 8.5541,5.928C8.5541,5.8907 8.5451,5.856 8.5291,5.8219C8.4693,5.6933 8.2624,5.6032 8.0245,5.6032C7.9664,5.6032 7.9088,5.6075 7.8539,5.6181L7.8507,5.6187L7.848,5.6155C7.8357,5.5947 7.8256,5.5808 7.8123,5.5653L7.8043,5.5568L7.8155,5.5541C7.8821,5.5403 7.952,5.5317 8.0245,5.5317C8.2912,5.5317 8.5221,5.6357 8.5979,5.7899C8.6181,5.8325 8.6293,5.88 8.6293,5.9275C8.6293,6.0027 8.6005,6.0773 8.5509,6.1349L8.6117,6.2331L8.5541,6.2805ZM8.4752,6.128L8.5568,6.2603L8.5941,6.2309L8.5339,6.1339L8.5365,6.1307C8.5883,6.0736 8.6155,6.0027 8.6155,5.9275C8.6155,5.8816 8.6053,5.8389 8.5851,5.7963C8.5125,5.6485 8.2816,5.544 8.024,5.544C7.9563,5.544 7.8907,5.5525 7.8283,5.5648C7.8379,5.5771 7.8469,5.5899 7.856,5.6021C7.9093,5.5925 7.9659,5.5888 8.0235,5.5888C8.2656,5.5888 8.4784,5.6816 8.5408,5.8165C8.5573,5.8523 8.5659,5.8901 8.5659,5.9275C8.5669,6.0032 8.5333,6.0763 8.4752,6.128Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.4507,5.6469C8.5157,5.6896 8.5643,5.7397 8.592,5.7947C8.6107,5.8341 8.6235,5.8811 8.6235,5.928C8.6235,6.0069 8.592,6.0795 8.5424,6.1344L8.5968,6.2219C8.6491,6.1563 8.6784,6.0779 8.6784,5.9947C8.6779,5.8549 8.5877,5.7307 8.4507,5.6469" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.5947,6.2336L8.5339,6.1333L8.5371,6.1312C8.5883,6.0741 8.6155,6.0032 8.6155,5.928C8.6155,5.8821 8.6053,5.8395 8.5851,5.7968C8.56,5.7435 8.5109,5.6939 8.4475,5.6528L8.4539,5.6416C8.6,5.7301 8.6843,5.8576 8.6843,5.9941C8.6843,6.0773 8.6549,6.1568 8.6005,6.2277L8.5947,6.2336ZM8.5504,6.1355L8.5968,6.2117C8.6448,6.1451 8.6709,6.0699 8.6709,5.9952C8.6709,5.9173 8.6416,5.8411 8.5883,5.7733C8.592,5.7787 8.5947,5.7845 8.5984,5.7909C8.6187,5.8336 8.6299,5.8816 8.6299,5.9285C8.6293,6.0032 8.6005,6.0779 8.5504,6.1355Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8603,5.9323C6.8603,5.9008 6.8891,5.8731 6.9259,5.8731C6.9605,5.8731 6.9893,5.9013 6.9893,5.9323C6.9893,5.968 6.9605,5.9947 6.9259,5.9947C6.8891,5.9947 6.8603,5.968 6.8603,5.9323" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,6.0032C6.8848,6.0032 6.8539,5.9696 6.8539,5.9323C6.8539,5.8949 6.8853,5.8656 6.9253,5.8656C6.9632,5.8656 6.9957,5.8949 6.9957,5.9323C6.9957,5.9696 6.9637,6.0032 6.9253,6.0032ZM6.9253,5.8795C6.8928,5.8795 6.8661,5.9029 6.8661,5.9323C6.8661,5.9659 6.8928,5.9893 6.9253,5.9893C6.9568,5.9893 6.9819,5.9653 6.9819,5.9323C6.9824,5.9029 6.9568,5.8795 6.9253,5.8795Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8603,5.8155C6.8603,5.7813 6.8891,5.7531 6.9259,5.7531C6.9605,5.7531 6.9893,5.7813 6.9893,5.8155C6.9893,5.8469 6.9605,5.8757 6.9259,5.8757C6.8891,5.8763 6.8603,5.8469 6.8603,5.8155" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,5.8811C6.8848,5.8811 6.8539,5.8528 6.8539,5.8155C6.8539,5.7781 6.8853,5.7445 6.9253,5.7445C6.9632,5.7445 6.9957,5.7781 6.9957,5.8155C6.9957,5.8528 6.9637,5.8811 6.9253,5.8811ZM6.9253,5.7584C6.8928,5.7584 6.8661,5.7835 6.8661,5.8155C6.8661,5.8437 6.8928,5.8688 6.9253,5.8688C6.9568,5.8688 6.9819,5.8437 6.9819,5.8155C6.9824,5.7835 6.9568,5.7584 6.9253,5.7584Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8731,5.6853C6.8731,5.6571 6.8971,5.6373 6.9259,5.6373C6.9541,5.6373 6.976,5.6571 6.976,5.6853C6.976,5.7136 6.9541,5.7333 6.9259,5.7333C6.8971,5.7333 6.8731,5.7136 6.8731,5.6853" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,5.7408C6.8923,5.7408 6.8661,5.7157 6.8661,5.6853C6.8661,5.6555 6.8923,5.6304 6.9253,5.6304C6.9568,5.6304 6.9819,5.6555 6.9819,5.6853C6.9824,5.7157 6.9568,5.7408 6.9253,5.7408ZM6.9253,5.6437C6.9003,5.6437 6.8795,5.6624 6.8795,5.6853C6.8795,5.7072 6.9003,5.728 6.9253,5.728C6.9493,5.728 6.9691,5.7072 6.9691,5.6853C6.9691,5.6624 6.9499,5.6437 6.9253,5.6437Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.888,5.5696C6.888,5.5509 6.904,5.5333 6.9253,5.5333C6.9451,5.5333 6.9616,5.5509 6.9616,5.5696C6.9616,5.5904 6.9445,5.6053 6.9253,5.6053C6.904,5.6059 6.888,5.5904 6.888,5.5696" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,5.6112C6.9003,5.6112 6.8816,5.5931 6.8816,5.5696C6.8816,5.5456 6.9003,5.528 6.9253,5.528C6.9483,5.528 6.9685,5.5456 6.9685,5.5696C6.9685,5.5931 6.9488,5.6112 6.9253,5.6112ZM6.9253,5.5408C6.9077,5.5408 6.8939,5.5531 6.8939,5.5701C6.8939,5.5856 6.9072,5.5984 6.9253,5.5984C6.9413,5.5984 6.9552,5.5861 6.9552,5.5701C6.9552,5.5531 6.9413,5.5408 6.9253,5.5408Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8944,5.4688C6.8944,5.4533 6.9083,5.4405 6.9253,5.4405C6.9413,5.4405 6.9536,5.4528 6.9536,5.4688C6.9536,5.4821 6.9413,5.4949 6.9253,5.4949C6.9083,5.4949 6.8944,5.4821 6.8944,5.4688" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,5.5029C6.904,5.5029 6.888,5.4885 6.888,5.4688C6.888,5.4496 6.9045,5.4325 6.9253,5.4325C6.944,5.4325 6.9605,5.4496 6.9605,5.4688C6.9611,5.4885 6.9445,5.5029 6.9253,5.5029Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9301,6.3008L6.9728,6.3072C6.9659,6.3259 6.9637,6.3435 6.9637,6.3643C6.9637,6.4507 7.0384,6.5195 7.1307,6.5195C7.2043,6.5195 7.2667,6.4757 7.288,6.4123C7.2912,6.4144 7.304,6.3557 7.3109,6.3563C7.3163,6.3563 7.3163,6.4155 7.3189,6.4155C7.3285,6.4944 7.4011,6.5488 7.4832,6.5488C7.5749,6.5488 7.6496,6.4779 7.6496,6.3904C7.6496,6.384 7.6491,6.3781 7.6475,6.3707L7.7003,6.3195L7.7285,6.3861C7.7168,6.4069 7.7125,6.4304 7.7125,6.4555C7.7125,6.5392 7.784,6.6053 7.8715,6.6053C7.9259,6.6053 7.9749,6.5776 8.0037,6.5392L8.0373,6.4944L8.0373,6.5477C8.0373,6.6011 8.0597,6.6459 8.1104,6.6555C8.1104,6.6555 8.1691,6.6571 8.2459,6.5979C8.3237,6.5376 8.3669,6.4869 8.3669,6.4869L8.3733,6.5467C8.3733,6.5467 8.3088,6.6469 8.2384,6.6885C8.2011,6.7093 8.1419,6.7323 8.0955,6.728C8.0469,6.7184 8.0123,6.6779 7.9947,6.632C7.9595,6.6544 7.9179,6.6656 7.8736,6.6656C7.7792,6.6656 7.6944,6.6155 7.6608,6.5355C7.6171,6.5824 7.5557,6.6128 7.4848,6.6128C7.4085,6.6128 7.3387,6.5787 7.2955,6.5264C7.2533,6.5659 7.1952,6.5899 7.1312,6.5899C7.0475,6.5899 6.9733,6.5461 6.9296,6.4848C6.888,6.5461 6.8139,6.5899 6.7296,6.5899C6.6651,6.5899 6.6075,6.5659 6.5637,6.5264C6.5205,6.5787 6.4512,6.6128 6.376,6.6128C6.3045,6.6128 6.2432,6.5824 6.2,6.5355C6.1669,6.6155 6.0805,6.6656 5.9856,6.6656C5.9419,6.6656 5.9008,6.6544 5.8661,6.632C5.848,6.6779 5.8133,6.7184 5.7637,6.728C5.7173,6.7323 5.6603,6.7093 5.6208,6.6885C5.5509,6.6469 5.4864,6.5467 5.4864,6.5467L5.4933,6.4869C5.4933,6.4869 5.536,6.5376 5.6139,6.5979C5.6923,6.6571 5.7499,6.6555 5.7499,6.6555C5.8011,6.6453 5.8235,6.6005 5.8235,6.5477L5.8235,6.4944L5.856,6.5392C5.8848,6.5776 5.9328,6.6053 5.9888,6.6053C6.0763,6.6053 6.1467,6.5392 6.1467,6.4555C6.1467,6.4304 6.1419,6.4069 6.1312,6.3861L6.1589,6.3195L6.2107,6.3707C6.2107,6.3781 6.2107,6.384 6.2107,6.3904C6.2107,6.4779 6.2843,6.5488 6.376,6.5488C6.4571,6.5488 6.5296,6.4944 6.5413,6.4155C6.5429,6.4155 6.5419,6.3563 6.5483,6.3563C6.5547,6.3557 6.5691,6.4144 6.5707,6.4123C6.5925,6.4757 6.6549,6.5195 6.7296,6.5195C6.8208,6.5195 6.8949,6.4507 6.8949,6.3643C6.8949,6.3435 6.8949,6.3259 6.8875,6.3072L6.9301,6.3008" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1141,6.7333C8.1067,6.7333 8.1008,6.7323 8.0944,6.7323C8.0507,6.7259 8.0133,6.6933 7.9915,6.6437C7.9547,6.6635 7.9147,6.672 7.8731,6.672C7.7803,6.672 7.6944,6.6219 7.6571,6.5472C7.6117,6.5941 7.5504,6.6192 7.4843,6.6192C7.4107,6.6192 7.3413,6.5877 7.2944,6.5349C7.2501,6.5744 7.1915,6.5952 7.1307,6.5952C7.0507,6.5952 6.9755,6.5579 6.9291,6.496C6.8837,6.5573 6.8096,6.5952 6.7291,6.5952C6.6672,6.5952 6.6101,6.5744 6.5637,6.5349C6.5184,6.5883 6.4475,6.6192 6.3755,6.6192C6.3088,6.6192 6.2475,6.5941 6.2005,6.5472C6.1637,6.6224 6.0789,6.672 5.9851,6.672C5.944,6.672 5.904,6.6635 5.8693,6.6437C5.8469,6.6933 5.8091,6.7259 5.7643,6.7323C5.7579,6.7323 5.7515,6.7333 5.744,6.7333C5.6923,6.7333 5.6379,6.7061 5.6165,6.6939C5.5467,6.6533 5.4827,6.5557 5.4805,6.5531L5.4789,6.5499L5.488,6.4699L5.4976,6.4821C5.4976,6.4821 5.5413,6.5323 5.6165,6.5931C5.6848,6.6448 5.7381,6.6485 5.7477,6.6485C5.7909,6.6416 5.8165,6.6043 5.8165,6.5477L5.816,6.4779L5.8603,6.5333C5.8885,6.5749 5.9365,6.5989 5.9883,6.5989C6.0715,6.5989 6.1397,6.5333 6.1397,6.4555C6.1397,6.4293 6.1355,6.4069 6.1253,6.3904L6.1232,6.3861L6.1573,6.3072L6.2176,6.3696L6.2171,6.3728C6.2171,6.3797 6.2171,6.3851 6.2171,6.3904C6.2171,6.4747 6.2885,6.5419 6.376,6.5419C6.4571,6.5419 6.5243,6.4891 6.5344,6.4155L6.5355,6.4059L6.5355,6.4059C6.5355,6.4027 6.5355,6.3984 6.5355,6.3947C6.5381,6.3573 6.5381,6.3509 6.5477,6.3493L6.5477,6.3493C6.5563,6.3493 6.56,6.3573 6.5696,6.392C6.5712,6.3947 6.5728,6.3989 6.5728,6.4032L6.5733,6.4032L6.576,6.4085C6.5973,6.4709 6.6592,6.5157 6.7285,6.5157C6.816,6.5157 6.8875,6.4448 6.8875,6.3648C6.8875,6.3451 6.8875,6.3285 6.8805,6.3104L6.8779,6.3029L6.9301,6.2933L6.9819,6.3029L6.9792,6.3104C6.9723,6.328 6.9707,6.3456 6.9707,6.3648C6.9707,6.4448 7.0421,6.5157 7.1307,6.5157C7.2005,6.5157 7.2608,6.4709 7.2821,6.4096L7.2853,6.4032L7.2853,6.4032C7.2869,6.3989 7.288,6.3947 7.2885,6.3909C7.2997,6.3573 7.304,6.3493 7.3109,6.3493C7.32,6.3515 7.3221,6.3579 7.3232,6.3952C7.3232,6.4005 7.3237,6.4037 7.3237,6.4064L7.3253,6.416C7.3349,6.4901 7.4016,6.5424 7.4832,6.5424C7.5717,6.5424 7.6427,6.4752 7.6427,6.3909C7.6427,6.3845 7.6421,6.3787 7.6411,6.3733L7.6411,6.3701L7.7029,6.3077L7.7349,6.3867L7.7349,6.3909C7.7243,6.4075 7.7189,6.4299 7.7189,6.456C7.7189,6.5339 7.7877,6.5995 7.8715,6.5995C7.9221,6.5995 7.9691,6.5755 7.9973,6.5339L8.0437,6.4784L8.0432,6.5483C8.0432,6.6048 8.0688,6.6427 8.1099,6.6491C8.1211,6.6491 8.1733,6.6448 8.2411,6.5936C8.3179,6.5328 8.36,6.4827 8.3605,6.4827L8.3712,6.4704L8.3797,6.5504L8.3792,6.5536C8.3755,6.5563 8.3131,6.6539 8.2416,6.6944C8.2208,6.7061 8.1664,6.7333 8.1141,6.7333ZM7.9979,6.624L8.0005,6.6315C8.0192,6.6816 8.0544,6.7136 8.0971,6.72C8.1024,6.72 8.1083,6.72 8.1141,6.72C8.1648,6.72 8.2192,6.6907 8.2352,6.6827C8.2976,6.6453 8.3568,6.56 8.3669,6.5451L8.3616,6.5035C8.3445,6.52 8.3067,6.5589 8.2507,6.6037C8.1792,6.6592 8.1227,6.6629 8.112,6.6629L8.1104,6.6629C8.0603,6.6533 8.0304,6.6117 8.0304,6.5483L8.0304,6.5157L8.0091,6.5435C7.9787,6.5856 7.9264,6.6128 7.872,6.6128C7.7808,6.6128 7.7067,6.5408 7.7067,6.456C7.7067,6.4283 7.7109,6.4064 7.7211,6.3867L7.6976,6.3323L7.6549,6.3749C7.656,6.3797 7.6565,6.3856 7.6565,6.3904C7.6565,6.4821 7.5787,6.5557 7.4832,6.5557C7.3947,6.5557 7.3232,6.4971 7.3125,6.4181C7.3104,6.4155 7.3099,6.4069 7.3099,6.3957C7.3099,6.3904 7.3099,6.3813 7.3088,6.3728C7.3067,6.3813 7.3035,6.3904 7.3008,6.3947C7.2971,6.4069 7.296,6.4144 7.2939,6.4155C7.2693,6.4821 7.2043,6.528 7.1301,6.528C7.0347,6.528 6.9563,6.4528 6.9563,6.3643C6.9563,6.3467 6.9573,6.3307 6.9627,6.3141L6.9296,6.3067L6.8949,6.3141C6.8997,6.3291 6.9003,6.3456 6.9003,6.3643C6.9003,6.4528 6.8229,6.528 6.728,6.528C6.6528,6.528 6.5872,6.4821 6.5643,6.4155C6.5621,6.4144 6.56,6.4069 6.5557,6.3947C6.5552,6.3904 6.552,6.3813 6.5493,6.3728C6.5488,6.3813 6.5477,6.3904 6.5472,6.3947C6.5467,6.4069 6.5467,6.4155 6.5456,6.4187C6.5339,6.4965 6.4619,6.5557 6.3744,6.5557C6.2789,6.5557 6.2021,6.4821 6.2021,6.3904C6.2021,6.3861 6.2027,6.3803 6.2027,6.3749L6.1589,6.3323L6.1365,6.3867C6.1461,6.4064 6.1515,6.4283 6.1515,6.456C6.1515,6.5408 6.0773,6.6128 5.9867,6.6128C5.9307,6.6128 5.8795,6.5856 5.8491,6.5424L5.8272,6.5157L5.8272,6.5483C5.8272,6.6117 5.7979,6.6533 5.7488,6.6629L5.7461,6.6629C5.7349,6.6629 5.6784,6.6587 5.608,6.6037C5.5525,6.5589 5.5131,6.5205 5.4965,6.5035L5.4917,6.5451C5.5013,6.5595 5.56,6.6453 5.6229,6.6827C5.672,6.7109 5.7248,6.7264 5.7621,6.72C5.8032,6.7136 5.8384,6.6816 5.8587,6.6315L5.8613,6.624L5.8683,6.6283C5.9029,6.6491 5.9435,6.6587 5.984,6.6587C6.0757,6.6587 6.1589,6.6075 6.1925,6.5328L6.1968,6.5243L6.2032,6.5317C6.2469,6.5787 6.3088,6.6064 6.3749,6.6064C6.4459,6.6064 6.5147,6.5744 6.5579,6.5205L6.5627,6.5163L6.568,6.5205C6.6112,6.56 6.6683,6.5829 6.7285,6.5829C6.8075,6.5829 6.8816,6.5456 6.9237,6.4821L6.9285,6.4747L6.9349,6.4821C6.9781,6.5456 7.0501,6.5829 7.1301,6.5829C7.1909,6.5829 7.2475,6.56 7.2912,6.5205L7.296,6.5163L7.3003,6.5205C7.344,6.5749 7.4128,6.6064 7.4843,6.6064C7.5504,6.6064 7.6101,6.5787 7.6544,6.5317L7.6619,6.5243L7.6667,6.5328C7.6981,6.608 7.7819,6.6587 7.8736,6.6587C7.9152,6.6587 7.9557,6.6491 7.9909,6.6283L7.9979,6.624Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0725,6.5072C8.0816,6.4805 8.0725,6.4528 8.0539,6.4448C8.032,6.4405 8.0085,6.4571 7.9984,6.4853C7.9883,6.5147 7.9973,6.5408 8.0181,6.5467C8.0379,6.5531 8.0629,6.5365 8.0725,6.5072" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0256,6.5557L8.0256,6.5557C8.0224,6.5557 8.0192,6.5557 8.016,6.5531C8.0064,6.552 7.9984,6.5445 7.9936,6.5333C7.9861,6.52 7.9856,6.5029 7.992,6.4821C8.0032,6.4528 8.0315,6.432 8.0544,6.4405C8.0635,6.4432 8.072,6.4491 8.0763,6.4571C8.0837,6.4715 8.0848,6.4917 8.0784,6.5093C8.0693,6.5376 8.0475,6.5557 8.0256,6.5557ZM8.0443,6.4533C8.0288,6.4533 8.0128,6.4656 8.0048,6.4885C8.0005,6.5029 8.0005,6.5184 8.0059,6.528C8.0091,6.5344 8.0133,6.5403 8.0192,6.5403C8.0224,6.5419 8.024,6.5419 8.0256,6.5419C8.0416,6.5419 8.0592,6.528 8.0661,6.5061C8.0709,6.4907 8.0704,6.4768 8.0656,6.4656C8.0629,6.4592 8.0587,6.4544 8.0507,6.4533C8.0491,6.4533 8.0475,6.4533 8.0443,6.4533Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3493,6.3685C7.3536,6.3392 7.3381,6.3131 7.3173,6.3104C7.2965,6.3077 7.2752,6.3296 7.2725,6.3573C7.2693,6.3899 7.2821,6.4155 7.304,6.4171C7.3259,6.4187 7.3451,6.3968 7.3493,6.3685" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3067,6.4229L7.3067,6.4229C7.3061,6.4229 7.304,6.4229 7.304,6.4229C7.2933,6.4208 7.2853,6.4171 7.2779,6.4075C7.2677,6.3952 7.2629,6.3781 7.2667,6.3573C7.2699,6.3259 7.2939,6.3019 7.3195,6.3029C7.3291,6.3056 7.3381,6.3093 7.3445,6.3184C7.3541,6.3307 7.3584,6.3499 7.3563,6.3685C7.3515,6.4011 7.3312,6.4229 7.3067,6.4229ZM7.3141,6.3173C7.2976,6.3173 7.2816,6.3355 7.2789,6.3595C7.2773,6.376 7.2805,6.3909 7.288,6.4011C7.2923,6.4064 7.2981,6.4085 7.3045,6.4096C7.3221,6.4128 7.3392,6.3936 7.3429,6.3675C7.3445,6.3536 7.3419,6.3376 7.3339,6.3285C7.3291,6.32 7.3227,6.3184 7.3163,6.3173C7.3163,6.3173 7.3157,6.3173 7.3141,6.3173Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.5104,6.3685C6.5067,6.3392 6.52,6.3131 6.5419,6.3104C6.5637,6.3072 6.5824,6.3296 6.5867,6.3573C6.5904,6.3899 6.5755,6.4155 6.5547,6.4171C6.5339,6.4187 6.5131,6.3968 6.5104,6.3685" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.5515,6.4229C6.5291,6.4229 6.5067,6.4011 6.504,6.3685C6.5008,6.3499 6.5045,6.3323 6.5152,6.3184C6.5221,6.3088 6.5307,6.3056 6.5408,6.3029C6.5659,6.3029 6.5883,6.3259 6.5931,6.3573C6.5952,6.3781 6.5915,6.3947 6.5819,6.4075C6.5744,6.4176 6.5664,6.4208 6.5563,6.4229C6.5541,6.4229 6.5541,6.4229 6.5515,6.4229ZM6.5445,6.3173C6.5445,6.3173 6.5429,6.3173 6.5419,6.3173C6.5355,6.3184 6.5301,6.32 6.5259,6.3285C6.5179,6.3381 6.5141,6.3536 6.5168,6.3675C6.5195,6.3936 6.5371,6.4128 6.5541,6.4096C6.5605,6.4085 6.5664,6.4064 6.5707,6.4011C6.5792,6.3904 6.5819,6.376 6.5797,6.3595C6.5765,6.3355 6.5611,6.3173 6.5445,6.3173Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.7867,6.5072C5.7765,6.4805 5.7851,6.4528 5.8064,6.4448C5.8256,6.4405 5.8507,6.4571 5.8603,6.4853C5.8693,6.5147 5.8608,6.5408 5.8416,6.5467C5.8203,6.5531 5.7968,6.5365 5.7867,6.5072" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.832,6.5557C5.8107,6.5557 5.7899,6.5376 5.7808,6.5093C5.7744,6.4923 5.776,6.472 5.7819,6.4571C5.7872,6.4485 5.7941,6.4432 5.8043,6.4405C5.8069,6.4395 5.8107,6.4384 5.8149,6.4384C5.8363,6.4384 5.8576,6.4571 5.8672,6.4821C5.8736,6.5029 5.8736,6.5195 5.8656,6.5333C5.8613,6.5445 5.8533,6.552 5.8437,6.5531C5.8395,6.5557 5.8357,6.5557 5.832,6.5557ZM5.8144,6.4533C5.8133,6.4533 5.8101,6.4533 5.8075,6.4533C5.8005,6.4549 5.7963,6.4597 5.7941,6.4656C5.7877,6.4768 5.7877,6.4907 5.7931,6.5061C5.8005,6.5307 5.8229,6.5445 5.8384,6.5403C5.8443,6.5403 5.8496,6.5339 5.8528,6.528C5.8581,6.5179 5.8587,6.5029 5.8533,6.4885C5.8469,6.4656 5.8299,6.4533 5.8144,6.4533Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1003,6.0272C6.1365,6.048 6.1675,6.0853 6.1787,6.128C6.1787,6.128 6.1824,6.1195 6.2027,6.1072C6.2224,6.096 6.2389,6.0965 6.2389,6.0965C6.2389,6.0965 6.2336,6.1301 6.2309,6.1419C6.2283,6.1531 6.2272,6.1893 6.2192,6.2197C6.2123,6.2533 6.1979,6.2779 6.1979,6.2779C6.1845,6.2656 6.1653,6.2592 6.1445,6.2645C6.1248,6.2672 6.1093,6.2779 6.0997,6.2939C6.0997,6.2939 6.0779,6.2752 6.0592,6.2459C6.0405,6.2197 6.0277,6.1877 6.0208,6.1781C6.0133,6.1669 5.9968,6.1387 5.9968,6.1387C5.9968,6.1387 6.0123,6.1323 6.0347,6.1365C6.0576,6.1408 6.0656,6.1461 6.0656,6.1461C6.0603,6.1029 6.0757,6.0571 6.1003,6.0272" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1024,6.3029L6.0965,6.2987C6.0949,6.2965 6.0731,6.2779 6.0539,6.2517C6.0427,6.232 6.0331,6.2155 6.0261,6.2005C6.0224,6.1915 6.0192,6.1829 6.016,6.1808C6.0091,6.1696 5.992,6.1419 5.9909,6.1403L5.9883,6.1333L5.9947,6.1312C5.9952,6.1312 6.0048,6.128 6.0192,6.128C6.0256,6.128 6.0315,6.128 6.0373,6.1296C6.0464,6.1312 6.0539,6.1323 6.0581,6.1355C6.0565,6.0949 6.0699,6.0533 6.0949,6.0197L6.0987,6.0171L6.1035,6.0197C6.1408,6.0432 6.1691,6.0779 6.1813,6.1157C6.1845,6.1115 6.1909,6.1072 6.1995,6.1035C6.2192,6.0912 6.2357,6.0912 6.2389,6.0912L6.2475,6.0912L6.2459,6.0987C6.2459,6.1008 6.2405,6.1323 6.2379,6.1445C6.2363,6.1477 6.2352,6.1563 6.2352,6.1664C6.2336,6.1813 6.232,6.2037 6.2267,6.2219C6.2192,6.2544 6.2053,6.2805 6.2043,6.2816L6.2005,6.2896L6.1941,6.2832C6.1819,6.272 6.1637,6.2683 6.1467,6.2709C6.1291,6.2731 6.1147,6.2832 6.1067,6.2971L6.1024,6.3029ZM6.0075,6.1424C6.0133,6.1536 6.0229,6.1659 6.0272,6.1733C6.0304,6.1787 6.0341,6.1845 6.0384,6.1952C6.0459,6.2085 6.0544,6.2288 6.0661,6.2443C6.0784,6.2619 6.0917,6.2784 6.1003,6.2827C6.1104,6.2704 6.1259,6.2597 6.1445,6.2576C6.1632,6.2533 6.1819,6.2576 6.1973,6.2688C6.2011,6.2576 6.2096,6.2411 6.2139,6.2192C6.2197,6.2005 6.2203,6.1787 6.2229,6.1648C6.2229,6.1536 6.2235,6.1451 6.2251,6.1408C6.2261,6.1323 6.2293,6.1157 6.232,6.1051C6.2256,6.1067 6.2165,6.1077 6.2069,6.1163C6.1888,6.1248 6.1851,6.1317 6.1851,6.1317L6.176,6.1451L6.1723,6.1301C6.1627,6.0944 6.1371,6.0576 6.1019,6.0336C6.0784,6.0672 6.0677,6.1077 6.072,6.1451L6.0736,6.1659L6.0603,6.1536L6.0603,6.1536C6.0603,6.1536 6.0533,6.1451 6.0347,6.1435C6.0256,6.1408 6.0139,6.1408 6.0075,6.1424Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1163,6.3696C6.104,6.3621 6.0955,6.3499 6.0933,6.3333C6.0907,6.32 6.0944,6.3056 6.1008,6.2933C6.1008,6.2933 6.0715,6.2784 6.0389,6.2699C6.0149,6.2645 5.9728,6.2635 5.9595,6.2635C5.9461,6.2624 5.9195,6.2619 5.9195,6.2619C5.9195,6.2619 5.9227,6.2683 5.9291,6.2805C5.9381,6.2944 5.9467,6.3061 5.9467,6.3061C5.904,6.3157 5.8667,6.3435 5.8448,6.3781C5.8779,6.4 5.9232,6.4144 5.9664,6.4075C5.9664,6.4075 5.9627,6.4197 5.96,6.44C5.9573,6.4533 5.9573,6.4576 5.9573,6.4576C5.9573,6.4576 5.9819,6.4512 5.9936,6.4453C6.0053,6.4411 6.0453,6.4288 6.0672,6.4149C6.0928,6.3947 6.1163,6.3696 6.1163,6.3696" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9504,6.4688L5.9504,6.4581C5.9504,6.4571 5.9504,6.4528 5.9525,6.4384C5.9536,6.4277 5.9552,6.4197 5.9568,6.4155C5.9163,6.4187 5.8752,6.4059 5.84,6.3819L5.8352,6.3776L5.8379,6.3712C5.8629,6.3387 5.8976,6.3131 5.9349,6.3024C5.9317,6.2949 5.9285,6.2901 5.9232,6.2816C5.9163,6.2693 5.9131,6.2651 5.9131,6.2651L5.9099,6.2539L5.9195,6.2549C5.9195,6.2549 5.9461,6.2555 5.9595,6.2555L5.9621,6.2555C5.9792,6.2555 6.0171,6.2565 6.0416,6.264C6.0731,6.2693 6.1035,6.2859 6.104,6.2869L6.1104,6.2901L6.1072,6.2944C6.1003,6.3067 6.0981,6.3195 6.1003,6.3317C6.1019,6.344 6.1099,6.3568 6.12,6.3653L6.1168,6.3696L6.1211,6.3771C6.12,6.3781 6.0981,6.4011 6.0699,6.4187C6.0512,6.432 6.0171,6.4448 6.0005,6.4512L5.9504,6.4688ZM5.9755,6.4032L5.9728,6.4117C5.9723,6.4117 5.9685,6.4224 5.9659,6.4411C5.9653,6.4443 5.9643,6.4453 5.9643,6.4501L5.9947,6.4389C6.0107,6.4325 6.0448,6.4203 6.0629,6.4075C6.0821,6.3952 6.0981,6.3781 6.1072,6.3701C6.0965,6.3616 6.0891,6.3493 6.0869,6.336C6.0848,6.3216 6.0859,6.3077 6.0917,6.2955C6.0821,6.2912 6.0603,6.2832 6.0384,6.2779C6.016,6.2704 5.976,6.2704 5.9621,6.2704L5.9595,6.2704C5.9509,6.2693 5.9392,6.2693 5.9312,6.2693C5.9323,6.2704 5.9339,6.2747 5.9355,6.2789C5.9445,6.2928 5.9509,6.304 5.9509,6.304L5.9579,6.3093L5.9477,6.3136C5.9115,6.3211 5.8773,6.3445 5.8539,6.376C5.8875,6.3957 5.9269,6.4075 5.9648,6.4043L5.9755,6.4043L5.9755,6.4032Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.2123,6.3547C6.2192,6.3435 6.2224,6.328 6.2197,6.3147C6.2171,6.2981 6.2096,6.2853 6.1973,6.2784C6.1973,6.2784 6.2197,6.2533 6.2475,6.2336C6.2683,6.2203 6.3083,6.2064 6.32,6.2032C6.3317,6.1968 6.3563,6.1909 6.3563,6.1909C6.3563,6.1909 6.3563,6.1952 6.3536,6.2085C6.3515,6.2283 6.3472,6.24 6.3472,6.24C6.3909,6.2325 6.4357,6.2496 6.4688,6.2715C6.4469,6.3051 6.4096,6.3328 6.3664,6.3429C6.3664,6.3429 6.3749,6.3541 6.384,6.368C6.3909,6.3813 6.3941,6.3872 6.3941,6.3872C6.3941,6.3872 6.3675,6.3861 6.3541,6.3851C6.3413,6.3851 6.2987,6.3851 6.2747,6.3787C6.2421,6.3701 6.2123,6.3563 6.2123,6.3563" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.4037,6.3931L6.3936,6.3931C6.3936,6.3931 6.3669,6.392 6.3541,6.392L6.3504,6.392C6.3349,6.3904 6.296,6.3904 6.2725,6.384C6.2411,6.3765 6.2101,6.3611 6.2091,6.36L6.2123,6.3541L6.2064,6.3525C6.2128,6.3403 6.216,6.3275 6.2128,6.3152C6.2112,6.3029 6.2037,6.2901 6.1936,6.2816L6.1872,6.2773L6.1925,6.2699C6.1931,6.2688 6.2155,6.2459 6.2432,6.2272C6.2635,6.2149 6.3013,6.2021 6.3152,6.1936C6.3291,6.1893 6.3525,6.1813 6.3525,6.1813L6.3616,6.1787L6.3616,6.1888C6.3616,6.1899 6.3616,6.1941 6.3595,6.2096C6.3589,6.2181 6.3568,6.2261 6.3557,6.2304C6.3968,6.2288 6.4368,6.2416 6.4725,6.2645L6.4779,6.2688L6.4747,6.2763C6.4496,6.3077 6.4155,6.3333 6.3781,6.344C6.3808,6.3504 6.3845,6.3552 6.3888,6.3648C6.3968,6.3771 6.3995,6.3813 6.3995,6.3813L6.4037,6.3931ZM6.2213,6.3531C6.232,6.3563 6.2539,6.3653 6.2757,6.3707C6.2981,6.3781 6.3355,6.3781 6.3509,6.3781L6.3547,6.3781C6.3632,6.3781 6.3749,6.3781 6.3829,6.3797C6.3824,6.3781 6.3803,6.3739 6.3792,6.3696C6.3696,6.3563 6.3627,6.3445 6.3627,6.3445L6.3557,6.3392L6.3664,6.3349C6.4021,6.3275 6.4363,6.304 6.4603,6.2736C6.4256,6.2528 6.3856,6.24 6.3483,6.2443L6.3381,6.2443L6.3413,6.2357C6.3413,6.2357 6.3451,6.2251 6.3477,6.2064C6.3483,6.2037 6.3488,6.2021 6.3493,6.1979C6.3413,6.2021 6.3296,6.2053 6.3227,6.2064L6.3216,6.2064C6.3093,6.2139 6.2704,6.2272 6.2512,6.24C6.232,6.2523 6.2171,6.2683 6.2075,6.2773C6.2181,6.2859 6.2251,6.2981 6.2272,6.3115C6.2288,6.3259 6.2277,6.3408 6.2213,6.3531Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0853,6.3227C6.0853,6.2843 6.1173,6.2528 6.1579,6.2528C6.1979,6.2528 6.232,6.2843 6.232,6.3227C6.232,6.3611 6.1984,6.3931 6.1579,6.3931C6.1173,6.3931 6.0853,6.3616 6.0853,6.3227" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1573,6.3995C6.1131,6.3995 6.0789,6.3659 6.0789,6.3227C6.0789,6.2811 6.1131,6.2453 6.1573,6.2453C6.2016,6.2453 6.2379,6.2805 6.2379,6.3227C6.2379,6.3659 6.2016,6.3995 6.1573,6.3995ZM6.1573,6.2592C6.1211,6.2592 6.0912,6.2896 6.0912,6.3227C6.0912,6.3568 6.1211,6.3861 6.1573,6.3861C6.1941,6.3861 6.2245,6.3568 6.2245,6.3227C6.2251,6.2896 6.1941,6.2592 6.1573,6.2592Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9275,5.9157C6.9627,5.9451 6.9899,5.9947 6.9936,6.0437C6.9936,6.0437 7,6.0331 7.024,6.0272C7.048,6.0171 7.0672,6.0197 7.0672,6.0197C7.0672,6.0197 7.0539,6.056 7.0485,6.0688C7.0432,6.0816 7.0352,6.12 7.0197,6.1531C7.0059,6.1883 6.9851,6.2144 6.9851,6.2144C6.9717,6.1979 6.9504,6.1883 6.9291,6.1883C6.9061,6.1883 6.8853,6.1979 6.8731,6.2144C6.8731,6.2144 6.8507,6.1883 6.8363,6.1531C6.8213,6.1195 6.8133,6.0811 6.808,6.0688C6.8027,6.0565 6.7888,6.0197 6.7888,6.0197C6.7888,6.0197 6.808,6.0171 6.832,6.0272C6.8571,6.0336 6.8635,6.0437 6.8635,6.0437C6.8667,5.9947 6.8923,5.9445 6.9275,5.9157" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9851,6.224L6.9797,6.2181C6.9664,6.2032 6.9477,6.1947 6.9291,6.1947C6.9083,6.1947 6.8896,6.2032 6.8768,6.2181L6.872,6.224L6.8667,6.2181C6.8667,6.2155 6.8448,6.1904 6.8304,6.1563C6.8208,6.1344 6.8139,6.1115 6.8096,6.0939C6.8069,6.0827 6.8043,6.0763 6.8021,6.0699C6.7968,6.0576 6.7835,6.024 6.7829,6.0219L6.7808,6.0155L6.7888,6.0155C6.7888,6.0155 6.808,6.008 6.8357,6.0197C6.8453,6.0229 6.8539,6.0283 6.8581,6.0309C6.8645,5.9851 6.8885,5.9403 6.9232,5.9083L6.928,5.9061L6.9323,5.9083C6.968,5.9419 6.992,5.9861 6.9989,6.0304C7.0048,6.0277 7.0117,6.0224 7.0235,6.0192C7.0496,6.008 7.0699,6.0139 7.0699,6.0149L7.0763,6.0149L7.0741,6.0213C7.0736,6.0235 7.0613,6.0565 7.0549,6.0693C7.0539,6.0757 7.0512,6.0816 7.0485,6.0933C7.0432,6.1109 7.0368,6.1339 7.0267,6.1557C7.0123,6.1899 6.9925,6.2149 6.9909,6.2176L6.9851,6.224ZM6.7979,6.0272C6.8027,6.0379 6.8101,6.0576 6.8133,6.0656C6.816,6.0699 6.8192,6.0795 6.8224,6.0907C6.8256,6.1072 6.8325,6.1307 6.8416,6.152C6.8528,6.1749 6.8661,6.1936 6.8725,6.2032C6.888,6.1909 6.9067,6.1813 6.9285,6.1813C6.9493,6.1813 6.9691,6.1909 6.984,6.2032C6.9909,6.1936 7.0037,6.1749 7.0139,6.152C7.0229,6.1312 7.0293,6.1072 7.0352,6.0907C7.0379,6.0795 7.0405,6.0699 7.0427,6.0656C7.0469,6.0571 7.0539,6.0373 7.0581,6.0272C7.0507,6.0283 7.0395,6.0283 7.0261,6.0325C7.0043,6.0411 6.9984,6.0459 6.9984,6.0469L6.9877,6.0603L6.9867,6.0437C6.9835,6.0021 6.9616,5.9563 6.9275,5.9237C6.8939,5.9563 6.8725,6.0011 6.8693,6.0437L6.8693,6.0619L6.8581,6.0459L6.8581,6.0459C6.8581,6.0459 6.8517,6.0405 6.8304,6.0325C6.8165,6.0283 6.8064,6.0272 6.7979,6.0272Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8725,6.3029C6.8619,6.2907 6.8544,6.2747 6.8544,6.2571C6.8544,6.2405 6.8613,6.2245 6.8725,6.2133C6.8725,6.2133 6.8416,6.1904 6.8075,6.1749C6.7813,6.1637 6.7349,6.1547 6.7195,6.1531C6.7056,6.1499 6.6768,6.1435 6.6768,6.1435C6.6768,6.1435 6.6784,6.152 6.6837,6.1653C6.6912,6.1851 6.6971,6.1979 6.6971,6.1979C6.6469,6.2021 6.6,6.2272 6.568,6.2571C6.6,6.2907 6.6469,6.3152 6.6971,6.3168C6.6971,6.3168 6.6907,6.3291 6.6837,6.3477C6.6784,6.3653 6.6768,6.3696 6.6768,6.3696C6.6768,6.3696 6.7056,6.3653 6.7195,6.3632C6.7349,6.3589 6.7813,6.3525 6.8075,6.3403C6.8416,6.3248 6.8725,6.3029 6.8725,6.3029" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.6693,6.3781L6.6704,6.3696C6.6704,6.3696 6.6725,6.3621 6.6779,6.3445C6.6816,6.336 6.6853,6.328 6.6875,6.3216C6.6416,6.3168 6.5979,6.2944 6.5632,6.2635L6.5595,6.2571L6.5632,6.2528C6.5979,6.2192 6.6421,6.1968 6.6875,6.192C6.6853,6.1861 6.6816,6.1781 6.6779,6.1685C6.6725,6.1531 6.6704,6.1445 6.6704,6.1445L6.6693,6.1349L6.7253,6.1445C6.744,6.1499 6.7861,6.1568 6.8101,6.1685C6.8443,6.1829 6.8752,6.2059 6.8752,6.2069L6.8816,6.2123L6.8768,6.2171C6.8661,6.2283 6.8613,6.2432 6.8613,6.2571C6.8613,6.2704 6.8667,6.2864 6.8779,6.2976L6.8725,6.3029L6.8763,6.3072C6.8757,6.3072 6.8443,6.3312 6.8101,6.3445C6.7877,6.3568 6.7472,6.3653 6.7285,6.368L6.6693,6.3781ZM6.5781,6.2571C6.6112,6.2896 6.6544,6.3072 6.6976,6.3104L6.7077,6.3115L6.704,6.32C6.704,6.32 6.6971,6.3323 6.6907,6.3525C6.6885,6.3563 6.6875,6.3589 6.6859,6.3637L6.7264,6.3557C6.7451,6.3531 6.7845,6.344 6.8059,6.3323C6.8299,6.3227 6.8533,6.3072 6.8635,6.3019C6.8544,6.2896 6.8485,6.2715 6.8485,6.2571C6.8485,6.2421 6.8544,6.2277 6.8635,6.2155C6.8533,6.2069 6.8299,6.192 6.8059,6.1813C6.7824,6.1701 6.7419,6.1637 6.7232,6.1584L6.6864,6.1531C6.688,6.1563 6.6885,6.1584 6.6912,6.1653C6.6976,6.1819 6.7045,6.1947 6.7045,6.1947L6.7083,6.2032L6.6981,6.2048C6.656,6.2075 6.6112,6.2283 6.5781,6.2571Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9835,6.3029C6.9947,6.2907 7.0005,6.2747 7.0005,6.2571C7.0005,6.2405 6.9941,6.2245 6.984,6.2133C6.984,6.2133 7.0133,6.1904 7.0475,6.1749C7.0736,6.1637 7.1216,6.1547 7.1355,6.1531C7.1504,6.1499 7.1787,6.1435 7.1787,6.1435C7.1787,6.1435 7.1781,6.152 7.1723,6.1653C7.1653,6.1851 7.1589,6.1979 7.1589,6.1979C7.2085,6.2021 7.2555,6.2272 7.288,6.2571C7.2555,6.2907 7.2091,6.3152 7.1589,6.3168C7.1589,6.3168 7.1653,6.3291 7.1723,6.3477C7.1776,6.3653 7.1787,6.3696 7.1787,6.3696C7.1787,6.3696 7.1504,6.3653 7.1355,6.3632C7.1216,6.3589 7.0736,6.3525 7.0475,6.3403C7.0133,6.3248 6.9835,6.3029 6.9835,6.3029" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1872,6.3781L7.1275,6.368C7.1077,6.3653 7.0688,6.3568 7.0448,6.3445C7.0107,6.3312 6.9808,6.3072 6.9787,6.3072L6.9829,6.3029L6.9787,6.2976C6.9883,6.2864 6.9941,6.2704 6.9941,6.2571C6.9941,6.2432 6.9883,6.2277 6.9787,6.2171L6.9739,6.2123L6.9797,6.2069C6.9819,6.2059 7.0107,6.1829 7.0448,6.1685C7.0693,6.1573 7.1131,6.1499 7.1312,6.1445L7.1867,6.1349L7.1851,6.1445C7.1851,6.1445 7.1845,6.1531 7.1787,6.1685C7.1755,6.1781 7.1717,6.1867 7.1691,6.192C7.2128,6.1968 7.2581,6.2197 7.2917,6.2528L7.2976,6.2571L7.2917,6.2635C7.2581,6.2949 7.2133,6.3173 7.1691,6.3216C7.1717,6.328 7.1755,6.336 7.1787,6.3445C7.184,6.3621 7.1851,6.3696 7.1851,6.3696L7.1872,6.3781ZM6.9931,6.3019C7.0043,6.3072 7.0256,6.3227 7.0507,6.3323C7.0731,6.3435 7.1109,6.3531 7.1291,6.3557L7.1691,6.3637C7.1691,6.3584 7.1675,6.3557 7.1664,6.3525C7.16,6.3328 7.1541,6.32 7.1541,6.32L7.1477,6.3115L7.1584,6.3104C7.2011,6.3072 7.2443,6.2896 7.2789,6.2571C7.2443,6.2277 7.2005,6.2069 7.1584,6.2043L7.1477,6.2027L7.1541,6.1941C7.1541,6.1941 7.1605,6.1819 7.1664,6.1648C7.1675,6.1573 7.1691,6.1552 7.1691,6.1525L7.1328,6.1579C7.1152,6.1632 7.0736,6.1691 7.0501,6.1808C7.0251,6.192 7.0037,6.2069 6.9936,6.2149C7.0032,6.2272 7.0069,6.2416 7.0069,6.2565C7.0075,6.2731 7.0027,6.2896 6.9931,6.3019Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7579,6.0272C7.7227,6.048 7.6912,6.0853 7.68,6.128C7.68,6.128 7.6752,6.1195 7.6565,6.1072C7.6357,6.096 7.6192,6.0965 7.6192,6.0965C7.6192,6.0965 7.6256,6.1301 7.6283,6.1419C7.6315,6.1531 7.632,6.1893 7.6384,6.2197C7.6469,6.2533 7.6608,6.2779 7.6608,6.2779C7.6747,6.2656 7.6949,6.2592 7.7136,6.2645C7.7333,6.2672 7.7493,6.2779 7.7589,6.2939C7.7589,6.2939 7.7813,6.2752 7.7995,6.2459C7.8176,6.2197 7.8309,6.1877 7.8379,6.1781C7.8448,6.1669 7.8619,6.1387 7.8619,6.1387C7.8619,6.1387 7.8459,6.1323 7.8229,6.1365C7.8005,6.1408 7.7936,6.1461 7.7936,6.1461C7.7979,6.1029 7.784,6.0571 7.7579,6.0272" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7568,6.3029L7.7531,6.2955C7.7445,6.2821 7.7291,6.2715 7.7125,6.2693C7.6944,6.2667 7.6779,6.2704 7.664,6.2816L7.6576,6.288L7.6539,6.28C7.6539,6.2789 7.64,6.2523 7.6315,6.2203C7.6272,6.2027 7.6251,6.1808 7.624,6.1648C7.6224,6.1552 7.6224,6.1461 7.6219,6.1429C7.6192,6.1307 7.6128,6.0992 7.6128,6.0971L7.6112,6.0896L7.6192,6.0896L7.6192,6.0896C7.6224,6.0896 7.6395,6.0896 7.6603,6.1019C7.6672,6.1061 7.6725,6.1104 7.6773,6.1141C7.6907,6.0768 7.7189,6.0416 7.7541,6.0181L7.76,6.0155L7.7627,6.0181C7.7877,6.0517 7.8016,6.0933 7.8,6.1339C7.8053,6.1307 7.8123,6.1296 7.8213,6.128C7.8272,6.1264 7.8325,6.1264 7.8384,6.1264C7.8533,6.1264 7.8624,6.1296 7.8624,6.1296L7.8709,6.1317L7.8661,6.1392C7.8661,6.1408 7.8496,6.1685 7.8421,6.1797C7.8405,6.1808 7.8368,6.1893 7.832,6.1984C7.8251,6.2139 7.816,6.2309 7.8037,6.2507C7.7851,6.2768 7.7627,6.2955 7.7627,6.2976L7.7568,6.3029ZM7.7024,6.256C7.7067,6.256 7.7104,6.256 7.7141,6.2571C7.7317,6.2592 7.7483,6.2693 7.76,6.2821C7.7664,6.2779 7.7819,6.2613 7.7941,6.2437C7.8043,6.2283 7.8133,6.2075 7.8208,6.1936C7.8256,6.1829 7.8288,6.1781 7.832,6.1728C7.8363,6.1653 7.8453,6.1531 7.8507,6.1419C7.8443,6.1403 7.8341,6.1403 7.824,6.1429C7.8037,6.1445 7.7979,6.1531 7.7979,6.1531L7.7856,6.1643L7.7867,6.1445C7.7915,6.1072 7.7797,6.0667 7.7568,6.0331C7.7227,6.0571 7.696,6.0933 7.6864,6.1296L7.6816,6.1456L7.6741,6.1312L7.6741,6.1312C7.6741,6.1312 7.6688,6.1237 7.6528,6.1157C7.6421,6.1072 7.6331,6.1061 7.6272,6.1045C7.6288,6.1157 7.6315,6.1323 7.6352,6.1403C7.6352,6.1445 7.6363,6.1525 7.6379,6.1653C7.6379,6.1803 7.6405,6.1995 7.6443,6.2187C7.6507,6.2405 7.6576,6.2571 7.6629,6.2683C7.6741,6.2592 7.688,6.256 7.7024,6.256Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7435,6.3696C7.7541,6.3621 7.7632,6.3499 7.7664,6.3333C7.7691,6.32 7.7664,6.3056 7.7579,6.2933C7.7579,6.2933 7.7883,6.2784 7.8192,6.2699C7.8443,6.2645 7.888,6.2635 7.9003,6.2635C7.9125,6.2624 7.9381,6.2619 7.9381,6.2619C7.9381,6.2619 7.9365,6.2683 7.9285,6.2805C7.92,6.2944 7.9125,6.3061 7.9125,6.3061C7.9552,6.3157 7.9909,6.3435 8.0149,6.3781C7.9813,6.4 7.9371,6.4144 7.8928,6.4075C7.8928,6.4075 7.8965,6.4197 7.8997,6.44C7.9013,6.4533 7.9008,6.4576 7.9008,6.4576C7.9008,6.4576 7.8773,6.4512 7.8656,6.4453C7.8533,6.4411 7.8123,6.4288 7.7925,6.4149C7.7664,6.3947 7.7435,6.3696 7.7435,6.3696" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9083,6.4688L7.8603,6.4512C7.8432,6.4448 7.8091,6.4325 7.7893,6.4187C7.7632,6.4011 7.7392,6.3781 7.7381,6.3771L7.7435,6.3696L7.7387,6.3653C7.7504,6.3568 7.7568,6.3445 7.7605,6.3317C7.7621,6.3195 7.7605,6.3067 7.7531,6.2944L7.7488,6.2901L7.7552,6.2869C7.7568,6.2859 7.7856,6.2693 7.8187,6.264C7.8416,6.2565 7.8805,6.2555 7.8976,6.2555L7.9003,6.2555C7.9125,6.2555 7.9376,6.2549 7.9376,6.2549L7.9472,6.2539L7.944,6.2651C7.944,6.2651 7.9424,6.2693 7.9344,6.2816C7.9307,6.2901 7.9259,6.2949 7.9227,6.3024C7.9605,6.3131 7.9957,6.3387 8.0197,6.3712L8.024,6.3776L8.0187,6.3819C7.9845,6.4059 7.9408,6.4176 7.9019,6.4155C7.9035,6.4208 7.9045,6.4277 7.9061,6.4384C7.9083,6.4528 7.9083,6.4571 7.9077,6.4581L7.9083,6.4688ZM7.7531,6.3696C7.76,6.3781 7.7781,6.3947 7.7973,6.4069C7.8144,6.4192 7.8491,6.432 7.8635,6.4384L7.8944,6.4496C7.8944,6.4448 7.8944,6.4437 7.8944,6.4405C7.8917,6.4219 7.8875,6.4112 7.8875,6.4112L7.8843,6.4027L7.8944,6.4027C7.9317,6.4059 7.9728,6.3941 8.0059,6.3744C7.9819,6.3429 7.9477,6.3189 7.9109,6.312L7.9003,6.3077L7.9067,6.3024C7.9067,6.3024 7.9152,6.2912 7.9232,6.2773C7.9253,6.2731 7.9269,6.2688 7.9285,6.2677C7.9189,6.2677 7.9072,6.2677 7.9003,6.2688L7.8976,6.2688C7.8816,6.2688 7.8443,6.2688 7.8219,6.2763C7.7989,6.2816 7.7776,6.2896 7.7664,6.2939C7.7723,6.3061 7.7755,6.32 7.7723,6.3344C7.7691,6.3488 7.7632,6.3616 7.7531,6.3696Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6475,6.3547C7.6389,6.3435 7.6352,6.328 7.6379,6.3147C7.6411,6.2981 7.6496,6.2853 7.6603,6.2784C7.6603,6.2784 7.6379,6.2533 7.6107,6.2336C7.5909,6.2203 7.5499,6.2064 7.5376,6.2032C7.5253,6.1968 7.5019,6.1909 7.5019,6.1909C7.5019,6.1909 7.5019,6.1952 7.5035,6.2085C7.5061,6.2283 7.5099,6.24 7.5099,6.24C7.4661,6.2325 7.4219,6.2496 7.3883,6.2715C7.4123,6.3051 7.4485,6.3328 7.4907,6.3429C7.4907,6.3429 7.4837,6.3541 7.4747,6.368C7.4672,6.3808 7.4667,6.3867 7.4667,6.3867C7.4667,6.3867 7.4917,6.3856 7.504,6.3845C7.5168,6.3845 7.56,6.3845 7.5851,6.3781C7.6165,6.3696 7.6469,6.3557 7.6469,6.3557" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.4565,6.3931L7.4597,6.3819C7.4597,6.3819 7.4613,6.3776 7.4688,6.3653C7.4725,6.3557 7.4773,6.3509 7.4805,6.3445C7.4421,6.3339 7.4069,6.3083 7.3835,6.2768L7.3792,6.2693L7.3845,6.2651C7.4192,6.2416 7.4624,6.2293 7.5013,6.2309C7.4997,6.2267 7.4987,6.2187 7.4971,6.2101C7.4949,6.1947 7.4949,6.1904 7.4949,6.1893L7.4949,6.1792L7.5035,6.1819C7.5035,6.1819 7.528,6.1904 7.5408,6.1941L7.5413,6.1941C7.5557,6.2027 7.5936,6.2149 7.6144,6.2277C7.6411,6.2464 7.664,6.2693 7.6656,6.2704L7.6699,6.2779L7.6645,6.2821C7.6533,6.2907 7.6469,6.3029 7.6432,6.3157C7.6416,6.328 7.6437,6.3408 7.6517,6.3531L7.6459,6.3547L7.6491,6.3605C7.6469,6.3616 7.6176,6.3771 7.5845,6.3845C7.5621,6.3909 7.5237,6.3909 7.5067,6.3925L7.504,6.3925C7.4917,6.3925 7.4667,6.3936 7.4667,6.3936L7.4565,6.3936L7.4565,6.3931ZM7.3984,6.2741C7.4229,6.3051 7.4571,6.3285 7.4939,6.3355L7.5045,6.3397L7.4981,6.3451C7.4981,6.3451 7.4896,6.3563 7.4816,6.3701C7.4795,6.3744 7.4779,6.3787 7.4763,6.3803C7.4859,6.3787 7.4976,6.3787 7.5045,6.3787L7.5083,6.3787C7.5243,6.3787 7.5616,6.3787 7.5829,6.3712C7.6059,6.3659 7.6277,6.3568 7.6384,6.3536C7.632,6.3413 7.6293,6.3275 7.632,6.3131C7.6352,6.2997 7.6416,6.2869 7.6512,6.2789C7.6443,6.2693 7.6267,6.2539 7.6075,6.2416C7.5883,6.2293 7.552,6.2165 7.5387,6.208L7.536,6.208C7.5291,6.2069 7.5179,6.2037 7.5104,6.1995C7.5104,6.2037 7.5104,6.2053 7.5109,6.208C7.5131,6.2267 7.5168,6.2373 7.5173,6.2373L7.5205,6.2459L7.5104,6.2459C7.4725,6.2405 7.432,6.2533 7.3984,6.2741Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6283,6.3227C7.6283,6.2843 7.6603,6.2528 7.7008,6.2528C7.7419,6.2528 7.7749,6.2843 7.7749,6.3227C7.7749,6.3611 7.7413,6.3931 7.7008,6.3931C7.6603,6.3931 7.6283,6.3616 7.6283,6.3227" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7003,6.3995C7.6565,6.3995 7.6208,6.3659 7.6208,6.3227C7.6208,6.2811 7.6565,6.2453 7.7003,6.2453C7.7445,6.2453 7.7813,6.2805 7.7813,6.3227C7.7819,6.3659 7.7445,6.3995 7.7003,6.3995ZM7.7003,6.2592C7.6635,6.2592 7.6347,6.2896 7.6347,6.3227C7.6347,6.3568 7.6635,6.3861 7.7003,6.3861C7.7376,6.3861 7.7675,6.3568 7.7675,6.3227C7.7675,6.2896 7.7381,6.2592 7.7003,6.2592Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.448,6.4779C8.4309,6.4581 8.3941,6.4645 8.3685,6.4853C8.3419,6.5072 8.3339,6.5419 8.3509,6.5595C8.3685,6.5781 8.4048,6.5749 8.4309,6.5531C8.4565,6.528 8.4651,6.4949 8.448,6.4779" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.3808,6.5781L8.3808,6.5781C8.3669,6.5781 8.3541,6.5728 8.3461,6.5659C8.3381,6.5563 8.3355,6.5451 8.3355,6.5323C8.3355,6.5157 8.3467,6.4949 8.3632,6.4811C8.3792,6.4672 8.3995,6.4581 8.4181,6.4581C8.432,6.4581 8.4448,6.4656 8.4528,6.4725C8.4608,6.4811 8.464,6.4917 8.4635,6.5045C8.4635,6.5216 8.4523,6.5419 8.4357,6.5573C8.4192,6.5696 8.3989,6.5781 8.3808,6.5781ZM8.4176,6.472C8.4027,6.472 8.3851,6.48 8.3728,6.4907C8.3579,6.5029 8.3488,6.5189 8.3477,6.5323C8.3477,6.5435 8.3504,6.5509 8.3557,6.5563C8.3691,6.5696 8.4032,6.5659 8.4256,6.5456C8.4416,6.5333 8.4501,6.5184 8.4507,6.5029C8.4507,6.4944 8.448,6.4885 8.4432,6.4821C8.4373,6.4773 8.4293,6.472 8.4176,6.472Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.3445,6.5211C8.3483,6.5088 8.3557,6.4949 8.3685,6.4859C8.3947,6.4651 8.4309,6.4587 8.448,6.4784C8.4507,6.4811 8.4528,6.4827 8.4544,6.4859C8.4544,6.4859 8.4917,6.416 8.5355,6.3925C8.5792,6.3691 8.6544,6.3755 8.6544,6.3755C8.6544,6.32 8.6096,6.2784 8.5525,6.2784C8.5195,6.2784 8.4875,6.2907 8.4688,6.3157L8.4608,6.2784C8.4608,6.2784 8.4149,6.288 8.3941,6.3408C8.3733,6.3925 8.3952,6.4688 8.3952,6.4688C8.3952,6.4688 8.3845,6.4352 8.3669,6.4155C8.3504,6.392 8.3061,6.3685 8.2821,6.3573C8.2603,6.3461 8.2363,6.3312 8.2363,6.3312C8.2363,6.3312 8.2357,6.3371 8.2357,6.3531C8.2341,6.3685 8.2357,6.3797 8.2357,6.3797C8.1931,6.3739 8.1451,6.3813 8.1056,6.3947C8.1221,6.4283 8.1536,6.4571 8.1947,6.4736C8.1947,6.4736 8.1792,6.4848 8.1659,6.4987C8.1541,6.5093 8.1509,6.5152 8.1509,6.5152C8.1509,6.5152 8.1797,6.5195 8.1947,6.5205C8.2085,6.5237 8.2571,6.5312 8.2853,6.5296C8.3061,6.528 8.3291,6.5248 8.3445,6.5211" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.2752,6.5365L8.2752,6.5365C8.2496,6.5365 8.216,6.5312 8.1995,6.528L8.1397,6.5195L8.1451,6.512C8.1456,6.5109 8.1499,6.5056 8.1605,6.4944C8.1685,6.4869 8.176,6.4805 8.1824,6.4757C8.1461,6.4581 8.1168,6.432 8.1003,6.3984L8.0971,6.3915L8.104,6.3899C8.1413,6.3755 8.1888,6.368 8.2288,6.3701C8.2283,6.3664 8.2283,6.3579 8.2288,6.3515C8.2299,6.336 8.2299,6.3301 8.2299,6.3291L8.2325,6.3189L8.2411,6.3253C8.2411,6.3264 8.264,6.3397 8.2859,6.3525C8.2971,6.3568 8.3515,6.3819 8.3739,6.408C8.376,6.4133 8.3781,6.4155 8.3803,6.4192C8.3776,6.3941 8.3776,6.3637 8.3893,6.3371C8.4117,6.2816 8.4581,6.2704 8.4608,6.2693L8.4683,6.2693L8.4747,6.3008C8.4933,6.2811 8.5232,6.2693 8.5536,6.2693C8.6144,6.2693 8.6619,6.3152 8.6619,6.3744L8.6619,6.3808L8.6544,6.3808C8.6544,6.3808 8.6453,6.3803 8.6331,6.3803C8.6107,6.3803 8.568,6.3819 8.5392,6.3973C8.4976,6.4192 8.4613,6.4891 8.4613,6.4901L8.4549,6.5013L8.448,6.4907C8.448,6.4875 8.4443,6.4832 8.4427,6.4821C8.4373,6.4768 8.4293,6.4715 8.4176,6.4715C8.4027,6.4715 8.3851,6.4795 8.3728,6.4901C8.3611,6.5008 8.3541,6.512 8.3504,6.5237L8.3483,6.528L8.344,6.528C8.3301,6.5312 8.3067,6.5333 8.2848,6.5355C8.2816,6.5365 8.2789,6.5365 8.2752,6.5365ZM8.1632,6.5104L8.2005,6.5157C8.2165,6.5189 8.2507,6.5232 8.2752,6.5232L8.2752,6.5232C8.2789,6.5232 8.2821,6.5232 8.2853,6.5221C8.3035,6.52 8.3248,6.5189 8.3381,6.5157C8.344,6.5035 8.352,6.4907 8.3632,6.4816C8.3717,6.4752 8.3792,6.4704 8.3883,6.4661C8.3845,6.4565 8.3749,6.4325 8.3616,6.4187C8.3483,6.4 8.3083,6.3787 8.2795,6.3648C8.2656,6.3573 8.2507,6.3483 8.2416,6.3424C8.2416,6.3451 8.2416,6.3483 8.2416,6.3536C8.2405,6.3691 8.2416,6.3787 8.2416,6.3787L8.2421,6.3883L8.2341,6.3861C8.1979,6.3819 8.1509,6.3872 8.1147,6.3995C8.1317,6.4304 8.1627,6.4549 8.1963,6.4677L8.2069,6.4704L8.1979,6.4789C8.1979,6.4789 8.1835,6.4912 8.1696,6.504C8.1669,6.5061 8.1659,6.5072 8.1632,6.5104ZM8.4176,6.4581C8.4315,6.4581 8.4443,6.4656 8.4523,6.4725C8.4528,6.4725 8.4528,6.4725 8.4539,6.4736C8.4651,6.4528 8.4955,6.4053 8.5317,6.3861C8.5611,6.3696 8.6032,6.3669 8.632,6.3669C8.6384,6.3669 8.6432,6.3669 8.6469,6.3669C8.6432,6.3195 8.6032,6.2821 8.552,6.2821C8.5195,6.2821 8.4917,6.2944 8.4731,6.3184L8.4645,6.3296L8.4555,6.2864C8.4432,6.2907 8.4144,6.3045 8.4,6.3419C8.3824,6.3829 8.3963,6.4443 8.4005,6.4613C8.4069,6.4592 8.4123,6.4581 8.4176,6.4581Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.5157,6.5211C5.512,6.5088 5.504,6.4949 5.4917,6.4859C5.4645,6.4651 5.4293,6.4587 5.4112,6.4784C5.4096,6.4811 5.4069,6.4827 5.4053,6.4859C5.4053,6.4859 5.368,6.416 5.3243,6.3925C5.2805,6.3691 5.2059,6.3755 5.2059,6.3755C5.2059,6.32 5.2507,6.2784 5.3067,6.2784C5.3413,6.2784 5.3728,6.2907 5.3915,6.3157L5.3984,6.2784C5.3984,6.2784 5.4443,6.288 5.4667,6.3408C5.4869,6.3925 5.4635,6.4688 5.4635,6.4688C5.4635,6.4688 5.4757,6.4352 5.4923,6.4155C5.5104,6.392 5.5541,6.3685 5.5765,6.3573C5.6,6.3461 5.6229,6.3312 5.6229,6.3312C5.6229,6.3312 5.624,6.3371 5.6251,6.3531C5.6256,6.3685 5.6245,6.3797 5.6245,6.3797C5.6667,6.3739 5.7157,6.3813 5.7541,6.3947C5.7381,6.4283 5.7072,6.4571 5.6656,6.4736C5.6656,6.4736 5.6795,6.4848 5.6939,6.4987C5.7045,6.5093 5.7083,6.5152 5.7083,6.5152C5.7083,6.5152 5.6789,6.5195 5.6656,6.5205C5.6507,6.5237 5.6032,6.5312 5.5749,6.5296C5.5541,6.528 5.5291,6.5248 5.5157,6.5211" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.5851,6.5365C5.5808,6.5365 5.5771,6.5365 5.5739,6.5355C5.5515,6.5333 5.5285,6.5312 5.5141,6.528L5.5104,6.528L5.5099,6.5237C5.5061,6.5125 5.4981,6.5008 5.4875,6.4901C5.464,6.4693 5.4309,6.4667 5.4171,6.4816C5.4144,6.4816 5.4139,6.4864 5.4117,6.4901L5.4064,6.5013L5.4005,6.4901C5.4,6.4891 5.3637,6.4192 5.3216,6.3973C5.2928,6.3819 5.2512,6.3803 5.2272,6.3803C5.2149,6.3803 5.2075,6.3808 5.2075,6.3808L5.1995,6.3808L5.1995,6.3744C5.1995,6.3152 5.2469,6.2693 5.3072,6.2693C5.3387,6.2693 5.3669,6.2805 5.3877,6.3008L5.3941,6.2693L5.4011,6.2693C5.4021,6.2704 5.4501,6.2816 5.4725,6.3371C5.4827,6.3643 5.4827,6.3941 5.4795,6.4192C5.4821,6.4149 5.4859,6.4128 5.488,6.408C5.5083,6.3819 5.5637,6.3568 5.5739,6.3525C5.5963,6.3403 5.6197,6.3264 5.6197,6.3253L5.6288,6.3189L5.6293,6.3291C5.6293,6.3291 5.6304,6.3349 5.632,6.3515C5.632,6.3579 5.632,6.3664 5.632,6.3701C5.6715,6.368 5.7195,6.3755 5.7568,6.3899L5.7632,6.3915L5.76,6.3989C5.7424,6.4325 5.7131,6.4581 5.6779,6.4763C5.6827,6.4811 5.6912,6.4875 5.6976,6.4949C5.7099,6.5061 5.7131,6.5115 5.7131,6.5125L5.7195,6.52L5.6603,6.5301C5.6416,6.5312 5.6101,6.5365 5.5851,6.5365ZM5.52,6.5157C5.5349,6.5189 5.5568,6.52 5.5755,6.5221C5.5989,6.5253 5.6379,6.5189 5.6565,6.5157L5.6949,6.5104C5.6939,6.5072 5.6912,6.5061 5.6875,6.5029C5.6752,6.4907 5.6603,6.4779 5.6603,6.4779L5.6517,6.4693L5.6624,6.4667C5.6971,6.4544 5.7259,6.4293 5.7435,6.3984C5.7061,6.3861 5.6608,6.3808 5.6245,6.3851L5.6155,6.3872L5.6165,6.3776C5.6165,6.3776 5.6181,6.368 5.6171,6.3525C5.6171,6.3472 5.6165,6.344 5.616,6.3413C5.6069,6.3472 5.5931,6.3563 5.5776,6.3637C5.5493,6.3771 5.5115,6.3984 5.4965,6.4176C5.4843,6.4315 5.4741,6.4555 5.4709,6.4651C5.4784,6.4693 5.4869,6.4747 5.4939,6.4805C5.5067,6.4907 5.5163,6.5029 5.52,6.5157ZM5.2267,6.3669C5.2571,6.3669 5.2976,6.3696 5.3269,6.3861C5.3627,6.4053 5.3941,6.4528 5.4059,6.4736C5.4064,6.4725 5.4064,6.4725 5.4064,6.4725C5.4181,6.4603 5.4379,6.456 5.4581,6.4613C5.4624,6.4448 5.4752,6.3835 5.4597,6.3419C5.4437,6.3045 5.416,6.2901 5.4037,6.2864L5.3941,6.3296L5.3851,6.3184C5.3685,6.2944 5.3381,6.2821 5.3067,6.2821C5.2565,6.2821 5.216,6.3195 5.2128,6.3669C5.216,6.3669 5.2208,6.3669 5.2267,6.3669Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.4112,6.4779C5.4293,6.4581 5.4645,6.4645 5.4917,6.4853C5.5184,6.5072 5.5259,6.5419 5.5083,6.5595C5.4917,6.5781 5.4555,6.5749 5.4293,6.5531C5.4011,6.528 5.3941,6.4949 5.4112,6.4779" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.4789,6.5781C5.4603,6.5781 5.4405,6.5696 5.424,6.5573C5.4064,6.5424 5.3963,6.5221 5.3952,6.5045C5.3941,6.4923 5.3984,6.4811 5.4064,6.4725C5.4251,6.4528 5.4661,6.4571 5.4944,6.4811C5.5125,6.4944 5.5221,6.5152 5.5237,6.5323C5.5248,6.5445 5.5205,6.5563 5.5125,6.5659C5.5045,6.5728 5.4923,6.5781 5.4789,6.5781ZM5.4416,6.472C5.4309,6.472 5.4229,6.4773 5.4165,6.4827C5.4101,6.4891 5.408,6.4949 5.4091,6.5035C5.4101,6.5189 5.4192,6.5339 5.4325,6.5461C5.4571,6.5659 5.4891,6.5701 5.504,6.5568C5.5088,6.5515 5.5115,6.544 5.5104,6.5328C5.5104,6.5195 5.5003,6.5035 5.4869,6.4912C5.4725,6.4795 5.4565,6.472 5.4416,6.472Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8549,6.2571C6.8549,6.2187 6.8885,6.1883 6.9291,6.1883C6.9696,6.1883 7.0016,6.2187 7.0016,6.2571C7.0016,6.2944 6.9696,6.328 6.9291,6.328C6.888,6.328 6.8549,6.2949 6.8549,6.2571" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9291,6.3323C6.8848,6.3323 6.848,6.2997 6.848,6.2571C6.848,6.2155 6.8843,6.1808 6.9291,6.1808C6.9728,6.1808 7.008,6.2149 7.008,6.2571C7.008,6.3003 6.9728,6.3323 6.9291,6.3323ZM6.9291,6.1947C6.8917,6.1947 6.8619,6.2219 6.8619,6.2571C6.8619,6.2917 6.8917,6.3195 6.9291,6.3195C6.9653,6.3195 6.9947,6.2917 6.9947,6.2571C6.9947,6.2219 6.9653,6.1947 6.9291,6.1947Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.7755,5.2032C6.7755,5.1232 6.8427,5.0592 6.9253,5.0592C7.008,5.0592 7.0752,5.1227 7.0752,5.2032C7.0752,5.2811 7.008,5.344 6.9253,5.344C6.8427,5.344 6.7755,5.2805 6.7755,5.2032" + android:strokeWidth="1" + android:fillColor="#005BBF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9253,5.3477C6.8405,5.3477 6.7712,5.2821 6.7712,5.2032C6.7712,5.12 6.8405,5.056 6.9253,5.056C7.0101,5.056 7.0789,5.12 7.0789,5.2032C7.0789,5.2821 7.0101,5.3477 6.9253,5.3477ZM6.9253,5.0656C6.8448,5.0656 6.7797,5.1269 6.7797,5.2032C6.7797,5.2784 6.8448,5.3408 6.9253,5.3408C7.0053,5.3408 7.0704,5.2784 7.0704,5.2032C7.0709,5.1269 7.0059,5.0656 6.9253,5.0656Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8859,4.8032L6.8859,4.8811L6.8037,4.8811L6.8037,4.9579L6.8859,4.9579L6.8859,5.0661L6.8859,5.1829L6.7824,5.1829C6.7819,5.1915 6.7755,5.1952 6.7755,5.2037C6.7755,5.2203 6.7792,5.2411 6.7877,5.2581L6.7877,5.2581L7.0629,5.2581C7.0629,5.2581 7.0629,5.2581 7.0635,5.2581C7.072,5.2416 7.0752,5.2208 7.0752,5.2037C7.0752,5.1952 7.0688,5.1915 7.0683,5.1829L6.968,5.1829L6.968,5.0661L6.968,4.9579L7.0501,4.9579L7.0501,4.8811L6.968,4.8811L6.968,4.8032L6.8859,4.8032Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0667,5.2635L6.7856,5.2635L6.7856,5.2613C6.7851,5.2603 6.784,5.2592 6.7835,5.2581C6.776,5.2405 6.7717,5.2208 6.7717,5.2027C6.7717,5.1952 6.7733,5.1925 6.776,5.1904C6.7771,5.1861 6.7792,5.1819 6.7792,5.1808L6.7792,5.1776L6.8821,5.1776L6.8821,4.9632L6.8011,4.9632L6.8011,4.8768L6.8821,4.8768L6.8821,4.8L6.9728,4.8L6.9728,4.8773L7.0544,4.8773L7.0544,4.9637L6.9728,4.9637L6.9728,5.1781L7.0731,5.1781L7.0731,5.1813C7.0731,5.1824 7.0747,5.1867 7.0757,5.1909C7.0784,5.1936 7.08,5.1963 7.08,5.2032C7.08,5.2208 7.0757,5.2405 7.0683,5.2587L7.0667,5.2635ZM6.7915,5.2533L7.0603,5.2533C7.0677,5.2389 7.0715,5.2197 7.0715,5.2032C7.0715,5.1989 7.0693,5.1947 7.0683,5.1931C7.0667,5.1904 7.0667,5.1893 7.0651,5.1861L6.9632,5.1861L6.9632,4.9525L7.0453,4.9525L7.0453,4.8837L6.9632,4.8837L6.9632,4.8064L6.8912,4.8064L6.8912,4.8837L6.8085,4.8837L6.8085,4.9525L6.8912,4.9525L6.8912,5.1861L6.7861,5.1861C6.7851,5.1893 6.7851,5.1904 6.7829,5.1931C6.7819,5.1947 6.7797,5.1989 6.7797,5.2032C6.7797,5.2197 6.7835,5.2384 6.7915,5.2533Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9408,11.1904C6.4976,11.1904 6.0597,11.0821 5.6907,10.9029C5.4192,10.7669 5.2379,10.4944 5.2379,10.184L5.2379,9.0571L8.6352,9.0571L8.6352,10.184C8.6352,10.4944 8.4555,10.7669 8.1835,10.9029C7.8149,11.0821 7.3824,11.1904 6.9408,11.1904" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9408,11.2C6.5131,11.2 6.0688,11.0949 5.6864,10.9083C5.4043,10.7696 5.2293,10.4933 5.2293,10.1845L5.2293,9.0501L8.6443,9.0501L8.6443,10.1845C8.6443,10.4933 8.4693,10.7701 8.1883,10.9083C7.8005,11.1003 7.3691,11.2 6.9408,11.2ZM5.2475,9.0672L5.2475,10.1845C5.2475,10.4853 5.4187,10.7573 5.6944,10.8939C6.0736,11.08 6.5168,11.1824 6.9408,11.1824C7.3664,11.1824 7.7947,11.0821 8.1792,10.8939C8.456,10.7573 8.6267,10.4853 8.6267,10.1845L8.6267,9.0672L5.2475,9.0672L5.2475,9.0672Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9328,9.056l1.7024,0l0,-1.8853l-1.7024,0l0,1.8853z" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6443,9.0656L6.9243,9.0656L6.9243,7.1648L8.6443,7.1648L8.6443,9.0656ZM6.9413,9.0469L8.6267,9.0469L8.6267,7.1813L6.9413,7.1813L6.9413,9.0469Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9349,10.1824C6.9349,10.6283 6.5568,10.9909 6.0875,10.9909C5.6165,10.9909 5.2352,10.6283 5.2352,10.1824L5.2352,9.056L6.9349,9.056L6.9349,10.1824" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.6069,10.8491C5.6603,10.8784 5.7328,10.9243 5.8107,10.9435L5.8064,9.016L5.6069,9.016L5.6069,10.8491Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.8192,10.9531L5.8091,10.9531C5.7445,10.9355 5.6853,10.9029 5.6363,10.8757C5.6251,10.8683 5.6133,10.8624 5.6032,10.8571L5.5979,10.8544L5.5979,9.0069L5.8149,9.0069L5.8149,9.0155L5.8192,10.9531ZM5.6165,10.8437C5.6256,10.8491 5.6352,10.8533 5.6443,10.8581C5.6896,10.8832 5.7445,10.9152 5.8021,10.9312L5.7979,9.0251L5.6165,9.0251L5.6165,10.8437Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.2331,10.1685C5.2384,10.4059 5.3328,10.5819 5.4272,10.6987L5.4272,9.0256L5.2352,9.0256L5.2331,10.1685Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.4272,10.7072C5.4251,10.7072 5.4229,10.7061 5.4203,10.7045C5.3349,10.5979 5.2304,10.4197 5.2256,10.1685L5.2272,9.0256C5.2272,9.0192 5.232,9.0165 5.2352,9.0165L5.4272,9.0165C5.432,9.0165 5.4352,9.0192 5.4352,9.0256L5.4352,10.6987C5.4352,10.7029 5.4336,10.7061 5.4299,10.7072C5.4288,10.7072 5.4288,10.7072 5.4272,10.7072ZM5.2443,9.0325L5.2411,10.1691C5.2475,10.4005 5.3381,10.5691 5.4192,10.6752L5.4192,9.0325L5.2443,9.0325Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9851,10.9845C6.0629,10.9936 6.1216,10.9909 6.1851,10.9845L6.1851,9.016L5.9851,9.016L5.9851,10.9845Z" + android:strokeWidth="1" + android:fillColor="#C7B500" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0853,10.9989L6.0853,10.9989C6.0539,10.9989 6.0208,10.9968 5.9851,10.9936L5.9765,10.9931L5.9765,9.0069L6.1936,9.0069L6.1936,10.9931L6.1851,10.9936C6.1488,10.9968 6.1168,10.9989 6.0853,10.9989ZM5.9941,10.9781C6.0261,10.9808 6.0565,10.9813 6.0848,10.9813L6.0848,10.9813C6.1136,10.9813 6.1429,10.9808 6.1749,10.9781L6.1749,9.0251L5.9936,9.0251L5.9936,10.9781L5.9941,10.9781Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.36,10.9435C6.4379,10.9285 6.5253,10.8784 6.5627,10.8533L6.5627,9.016L6.3637,9.016L6.36,10.9435Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.3504,10.9531L6.3557,9.0075L6.5723,9.0075L6.5723,10.8576L6.568,10.8608C6.5285,10.888 6.4395,10.936 6.3605,10.9536L6.3504,10.9536L6.3504,10.9531ZM6.3728,9.0251L6.3685,10.9323C6.4384,10.9157 6.5163,10.8741 6.5541,10.8491L6.5541,9.0251L6.3728,9.0251L6.3728,9.0251Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.2357,9.056l1.6981,0l0,-1.8853l-1.6981,0z" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9424,9.0656L5.2277,9.0656L5.2277,7.1648L6.9424,7.1648L6.9424,9.0656ZM5.2443,9.0469L6.9253,9.0469L6.9253,7.1813L5.2443,7.1813L5.2443,9.0469L5.2443,9.0469Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.7477,10.6805C6.832,10.6059 6.9093,10.4405 6.9376,10.2475L6.9419,9.0149L6.7435,9.0149L6.7477,10.6805Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.7392,10.7003L6.7349,9.0075L6.9504,9.0075L6.9504,9.016L6.9456,10.2485C6.9179,10.4373 6.8427,10.608 6.7536,10.6869L6.7392,10.7003ZM6.752,9.0251L6.7568,10.6587C6.8352,10.5787 6.904,10.416 6.9291,10.2464L6.9333,9.0251L6.752,9.0251Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0875,10.9989C5.6128,10.9989 5.2272,10.632 5.2272,10.1824L5.2272,9.0459L6.9435,9.0459L6.9435,10.1824C6.9435,10.6325 6.5595,10.9989 6.0875,10.9989ZM5.2443,9.0656L5.2443,10.1824C5.2443,10.6229 5.6224,10.9813 6.0875,10.9813C6.5499,10.9813 6.9253,10.6229 6.9253,10.1824L6.9253,9.0656L5.2443,9.0656Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6373,9.0555L8.6373,10.1819C8.6373,10.6277 8.2555,10.9904 7.7851,10.9904C7.3163,10.9904 6.9349,10.6277 6.9349,10.1819L6.9349,9.0555L8.6373,9.0555" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7851,10.9989C7.3109,10.9989 6.9253,10.632 6.9253,10.1824L6.9253,9.0459L8.6459,9.0459L8.6459,10.1824C8.6459,10.6325 8.2603,10.9989 7.7851,10.9989ZM6.9435,9.0656L6.9435,10.1824C6.9435,10.6229 7.3211,10.9813 7.7856,10.9813C8.2512,10.9813 8.6299,10.6229 8.6299,10.1824L8.6299,9.0656L6.9435,9.0656Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2443,9.9072C7.2475,9.9136 7.248,9.9184 7.248,9.9248C7.248,9.9445 7.2309,9.9621 7.2091,9.9621C7.1872,9.9621 7.1696,9.9445 7.1696,9.9248C7.1696,9.9184 7.1707,9.9136 7.1733,9.9072L7.1184,9.9072C7.1168,9.9136 7.1168,9.9184 7.1168,9.9248C7.1168,9.9653 7.144,9.9957 7.1813,10.0069L7.1813,10.1435L7.2384,10.1445L7.2384,10.0069C7.2667,9.9984 7.2875,9.9776 7.2965,9.9525L7.4517,9.9525L7.4517,9.9067L7.2443,9.9067M8.0075,9.9072L8.0075,9.9531L7.8677,9.9531C7.8661,9.9584 7.8629,9.9653 7.8587,9.9696L8.0213,10.1557L7.9776,10.1904L7.816,10.0059C7.8128,10.0059 7.8112,10.0069 7.808,10.0069L7.8075,10.3152L7.7504,10.3152L7.7504,10.0069C7.7477,10.0069 7.7461,10.0053 7.744,10.0043L7.5755,10.1904L7.5317,10.1557L7.7003,9.9685C7.6976,9.9653 7.6944,9.9573 7.6928,9.9531L7.5477,9.9531L7.5477,9.9072L8.0075,9.9072L8.0075,9.9072ZM8.1003,9.9072L8.1003,9.9531L8.2565,9.9531C8.2661,9.9781 8.288,9.9989 8.3136,10.0075L8.3136,10.1451L8.3723,10.144L8.3723,10.0075C8.4096,9.9963 8.4363,9.9659 8.4363,9.9253C8.4363,9.9189 8.4352,9.9141 8.4347,9.9077L8.3787,9.9077C8.3813,9.9141 8.3835,9.9189 8.3835,9.9253C8.3835,9.9451 8.3664,9.9627 8.344,9.9627C8.3227,9.9627 8.304,9.9451 8.304,9.9253C8.304,9.9189 8.3061,9.9141 8.3088,9.9077L8.1003,9.9077M7.8667,10.6864C7.9109,10.6795 7.9541,10.6672 7.9947,10.6501L8.0229,10.6971C7.976,10.7189 7.9243,10.7323 7.8709,10.7408C7.8624,10.7808 7.8261,10.8096 7.7813,10.8096C7.7365,10.8096 7.7003,10.7813 7.6912,10.7408C7.6347,10.7323 7.5808,10.72 7.5307,10.6971L7.5595,10.6501C7.6027,10.6683 7.6485,10.6811 7.6981,10.6869C7.7072,10.6656 7.7259,10.6469 7.7509,10.6405L7.7509,10.4032L7.8075,10.4032L7.8085,10.6405C7.8336,10.6448 7.8549,10.6656 7.8667,10.6864L7.8667,10.6864ZM7.4768,10.6075L7.4485,10.6565C7.4005,10.6272 7.3568,10.5899 7.32,10.5461C7.2912,10.5568 7.2571,10.5515 7.232,10.5312C7.1941,10.4992 7.1883,10.4443 7.2224,10.408L7.2267,10.4037C7.2037,10.3493 7.1877,10.2928 7.1813,10.2331L7.24,10.2331C7.2437,10.2832 7.256,10.3333 7.2768,10.3787C7.2939,10.3755 7.3099,10.3787 7.3253,10.3829L7.4704,10.2224L7.5141,10.2576L7.3701,10.4187C7.3899,10.4464 7.3888,10.4848 7.3664,10.5163C7.4,10.5499 7.4357,10.5813 7.4768,10.6075ZM7.2629,10.4405C7.2763,10.4229 7.3013,10.4197 7.3184,10.4341C7.3349,10.4475 7.3371,10.4704 7.3227,10.4885C7.3088,10.5029 7.2837,10.5056 7.2667,10.4923C7.2507,10.4779 7.248,10.4549 7.2629,10.4405ZM7.1893,10.2811L7.1301,10.2683L7.1221,10.1173L7.1813,10.0971L7.1813,10.1824C7.1808,10.2171 7.184,10.2491 7.1893,10.2811ZM7.2384,10.0939L7.2976,10.1072C7.2976,10.1072 7.3003,10.2048 7.3003,10.1824C7.2976,10.1573 7.3067,10.2576 7.3067,10.2576L7.2469,10.2784C7.2416,10.2469 7.2379,10.216 7.2379,10.1824L7.2384,10.0939L7.2384,10.0939ZM7.4341,10.5771C7.4843,10.6155 7.5413,10.6448 7.6037,10.6656L7.6176,10.6085C7.5659,10.5936 7.5189,10.5701 7.4757,10.5397L7.4341,10.5771M7.4059,10.6261C7.4571,10.6645 7.5136,10.6939 7.5755,10.7157L7.5317,10.7563C7.4816,10.7397 7.4352,10.7157 7.392,10.6843L7.4059,10.6261M7.4821,10.2939L7.5387,10.3184L7.6427,10.2032L7.6091,10.1531L7.4821,10.2939M7.4384,10.2571L7.4048,10.2069L7.5088,10.0933L7.5653,10.1184L7.4384,10.2571M8.0757,10.6075L8.104,10.6565C8.1531,10.6272 8.1957,10.5899 8.2325,10.5461C8.2629,10.5568 8.2955,10.5515 8.3205,10.5312C8.3605,10.4992 8.3637,10.4443 8.3317,10.408L8.3259,10.4037C8.3499,10.3493 8.3659,10.2928 8.3707,10.2331L8.3136,10.2331C8.3088,10.2832 8.296,10.3333 8.2763,10.3787C8.2608,10.3755 8.2427,10.3787 8.2267,10.3829L8.0821,10.2224L8.0384,10.2576L8.1824,10.4187C8.1637,10.4464 8.1637,10.4848 8.1856,10.5163C8.1541,10.5499 8.1163,10.5813 8.0757,10.6075ZM8.2912,10.4405C8.2757,10.4229 8.2507,10.4197 8.2352,10.4341C8.2187,10.4475 8.2165,10.4704 8.2304,10.4885C8.2443,10.5029 8.2693,10.5056 8.2859,10.4923C8.3029,10.4779 8.3045,10.4549 8.2912,10.4405ZM8.3632,10.2811L8.4229,10.2683L8.432,10.1173L8.3733,10.0971L8.3733,10.1824C8.3728,10.2171 8.3691,10.2491 8.3632,10.2811ZM8.3141,10.0939L8.2549,10.1072C8.2549,10.1072 8.2517,10.2048 8.2539,10.1824C8.2544,10.1573 8.2469,10.2576 8.2469,10.2576L8.3067,10.2784C8.3131,10.2469 8.3141,10.216 8.3141,10.1824L8.3141,10.0939M8.1195,10.5771C8.0693,10.6155 8.0107,10.6448 7.9483,10.6656L7.9355,10.6085C7.9872,10.5936 8.0357,10.5701 8.0763,10.5397L8.1195,10.5771M8.1477,10.6261C8.0976,10.6645 8.0389,10.6939 7.9771,10.7157L8.0213,10.7563C8.0709,10.7397 8.1179,10.7157 8.16,10.6843L8.1477,10.6261M8.0699,10.2939L8.0133,10.3184L7.9104,10.2032L7.9445,10.1531L8.0699,10.2939M8.1136,10.2571L8.1472,10.2069L8.0437,10.0933L7.9877,10.1184L8.1136,10.2571M7.4059,9.9531L7.4224,10.0085L7.5813,10.0085L7.5995,9.9531L7.4059,9.9531M8.1504,9.9531L8.1328,10.0085L7.9733,10.0085L7.9568,9.9531L8.1504,9.9531M7.7413,10.7221C7.7413,10.7035 7.7589,10.6848 7.7808,10.6848C7.8027,10.6848 7.8192,10.7035 7.8192,10.7221C7.8192,10.744 7.8021,10.7595 7.7808,10.7595C7.7589,10.7595 7.7413,10.744 7.7413,10.7221ZM7.808,10.4501L7.8672,10.4325L7.8672,10.2827L7.808,10.2661L7.808,10.4501M7.7504,10.4501L7.6912,10.4325L7.6912,10.2827L7.7504,10.2661L7.7504,10.4501" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1184,9.9072C7.1259,9.8779 7.1504,9.8528 7.1819,9.8421L7.1813,9.656L7.2384,9.656L7.2384,9.8432C7.2667,9.8533 7.2885,9.872 7.2981,9.8997L7.4523,9.9008L7.4523,9.9072L7.2448,9.9072C7.2384,9.896 7.2245,9.8896 7.2096,9.8896C7.1947,9.8896 7.1803,9.896 7.1739,9.9072L7.1184,9.9072M7.5477,9.9072L7.5477,9.9008L7.6917,9.9008C7.6944,9.8944 7.696,9.8901 7.6981,9.8864L7.5211,9.6907L7.5648,9.6533L7.7403,9.8469C7.7429,9.8448 7.7461,9.8448 7.7493,9.8437L7.7493,9.5845L7.8069,9.5845L7.8069,9.8421C7.8096,9.8437 7.8133,9.8437 7.816,9.8448L7.9867,9.6501L8.0309,9.6837L7.8592,9.8784C7.8635,9.8848 7.8667,9.8923 7.8699,9.9013L8.008,9.9013L8.008,9.9077L7.5477,9.9077L7.5477,9.9072ZM8.3093,9.9072C8.3163,9.896 8.3291,9.8896 8.344,9.8896C8.36,9.8896 8.3728,9.896 8.3787,9.9072L8.4347,9.9072C8.4272,9.8779 8.4032,9.8528 8.3723,9.8421L8.3723,9.656L8.3147,9.656L8.3147,9.8437C8.2864,9.8533 8.2645,9.872 8.2565,9.8997L8.1003,9.9008L8.1003,9.9072L8.3093,9.9072M7.2475,9.3824L7.4597,9.6208L7.5035,9.5867L7.2896,9.3483C7.2939,9.3424 7.2971,9.3349 7.3003,9.3285L7.456,9.3285L7.456,9.2731L7.2997,9.2731C7.288,9.2389 7.2528,9.2139 7.2112,9.2139C7.16,9.2139 7.1189,9.2533 7.1189,9.3013C7.1189,9.3397 7.144,9.3701 7.1813,9.3824L7.1808,9.5685L7.2373,9.5685L7.2373,9.3835C7.2416,9.3824 7.2443,9.3824 7.2475,9.3824ZM8.3728,9.3824L8.3728,9.5685L8.3152,9.5685L8.3152,9.3824C8.3104,9.3824 8.3067,9.3808 8.3024,9.3781L8.0907,9.6181L8.0469,9.5824L8.2635,9.3397C8.2608,9.3344 8.2592,9.3312 8.2571,9.3285L8.1008,9.3285L8.1008,9.2731L8.2571,9.2731C8.2693,9.2389 8.304,9.2139 8.3445,9.2139C8.3963,9.2139 8.4379,9.2533 8.4379,9.3013C8.4373,9.3408 8.4107,9.3717 8.3728,9.3824ZM7.8069,9.3824L7.8069,9.4949L7.7493,9.4949L7.7493,9.3835C7.7205,9.3771 7.6976,9.3547 7.6885,9.328L7.5488,9.328L7.5488,9.2725L7.6885,9.2725C7.7003,9.2384 7.7349,9.2133 7.776,9.2133C7.8176,9.2133 7.8528,9.2384 7.8645,9.2725L8.0069,9.2725L8.0069,9.328L7.864,9.328C7.8549,9.3531 7.8352,9.3749 7.8069,9.3824ZM7.1819,9.52L7.1227,9.5376L7.1227,9.6896L7.1819,9.7045L7.1819,9.52M7.2389,9.52L7.2981,9.5376L7.2981,9.6896L7.2389,9.7045L7.2389,9.52M8.3141,9.52L8.2549,9.5376L8.2549,9.6896L8.3141,9.7045L8.3141,9.52M8.3728,9.52L8.4315,9.5376L8.4315,9.6896L8.3728,9.7045L8.3728,9.52M7.4725,9.5509L7.5285,9.528L7.6315,9.6405L7.5973,9.6907L7.4725,9.5509M7.4288,9.5856L7.3941,9.6347L7.4976,9.7515L7.5536,9.7275L7.4288,9.5856M8.0789,9.5445L8.0219,9.5216L7.9195,9.6395L7.9541,9.6875L8.0789,9.5445M8.1227,9.5813L8.1568,9.6309L8.0539,9.7451L7.9979,9.7211L8.1227,9.5813M7.4059,9.9003L7.4224,9.8443L7.5813,9.8443L7.5995,9.9003L7.4059,9.9003M7.1728,9.3008C7.1728,9.2795 7.1899,9.2635 7.2117,9.2635C7.2336,9.2635 7.2507,9.2795 7.2507,9.3008C7.2507,9.3195 7.2336,9.3381 7.2117,9.3381C7.1899,9.3381 7.1728,9.32 7.1728,9.3008ZM7.5979,9.328L7.5813,9.3835L7.4219,9.3835L7.4037,9.328L7.5979,9.328M7.5979,9.272L7.5813,9.216L7.4219,9.216L7.4037,9.272L7.5979,9.272M8.1504,9.9003L8.1328,9.8443L7.9733,9.8443L7.9568,9.9003L8.1504,9.9003M8.3051,9.3008C8.3051,9.2795 8.3232,9.2635 8.3445,9.2635C8.3669,9.2635 8.3845,9.2795 8.3845,9.3008C8.3845,9.3195 8.3669,9.3381 8.3445,9.3381C8.3227,9.3387 8.3051,9.32 8.3051,9.3008ZM7.7371,9.3008C7.7371,9.2795 7.7541,9.2635 7.776,9.2635C7.7979,9.2635 7.8165,9.2795 7.8165,9.3008C7.8165,9.3195 7.7979,9.3381 7.776,9.3381C7.7547,9.3387 7.7371,9.32 7.7371,9.3008ZM7.9573,9.328L7.9755,9.3835L8.1349,9.3835L8.1515,9.328L7.9573,9.328M7.9573,9.272L7.9755,9.216L8.1349,9.216L8.1515,9.272L7.9573,9.272M7.7499,9.4501L7.6907,9.4656L7.6907,9.6171L7.7499,9.632L7.7499,9.4501M7.8069,9.4501L7.8667,9.4656L7.8667,9.6171L7.8069,9.632L7.8069,9.4501" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7808,10.8155C7.7365,10.8155 7.6976,10.7851 7.6869,10.7445C7.6491,10.7403 7.6123,10.7323 7.5771,10.7195L7.5328,10.7616L7.5307,10.76C7.4821,10.7429 7.4347,10.7184 7.3904,10.6901L7.3883,10.6869L7.4005,10.6277C7.3717,10.6053 7.3445,10.5792 7.3195,10.5525C7.288,10.5589 7.2539,10.5525 7.2299,10.5317C7.2107,10.5168 7.1979,10.4944 7.1963,10.4693C7.1947,10.4443 7.2027,10.4203 7.2197,10.4027L7.2229,10.4016C7.2053,10.3632 7.1936,10.3237 7.1856,10.2827L7.1259,10.2693L7.1168,10.1152L7.176,10.0944L7.176,10.0112C7.1381,9.9989 7.112,9.9643 7.112,9.9248C7.112,9.8853 7.1381,9.8507 7.1765,9.8384L7.176,9.6517L7.2427,9.6517L7.2427,9.8395C7.2699,9.848 7.2917,9.8688 7.3008,9.8939L7.4571,9.8949L7.4571,9.9573L7.2997,9.9573C7.2896,9.9824 7.2699,10.0032 7.2437,10.0107L7.2437,10.0907L7.3029,10.1045L7.3029,10.1072C7.3029,10.1072 7.304,10.1696 7.3045,10.1824C7.3072,10.2011 7.3104,10.2576 7.3104,10.2576L7.3109,10.2629L7.2517,10.2816C7.2576,10.3131 7.2672,10.3435 7.28,10.3723C7.2944,10.3701 7.3109,10.3723 7.3259,10.3787L7.4709,10.216L7.5216,10.2576L7.3765,10.4187C7.3947,10.4485 7.3941,10.4848 7.3733,10.5163C7.392,10.5339 7.4133,10.5536 7.4347,10.5707L7.4768,10.5333L7.4795,10.5355C7.5211,10.5669 7.568,10.5915 7.6197,10.6069L7.6229,10.6075L7.6107,10.6656C7.6373,10.6709 7.6661,10.6789 7.6949,10.6832C7.7056,10.6613 7.7232,10.6459 7.7461,10.6373L7.7467,10.3989L7.8128,10.3989L7.8133,10.6363C7.8384,10.6448 7.8571,10.6613 7.8688,10.6832C7.9104,10.6757 7.9509,10.6645 7.9931,10.6459L7.9968,10.6448L8.0293,10.7019L8.0256,10.704C7.9776,10.7227 7.9264,10.7376 7.8752,10.7456C7.8629,10.7856 7.8251,10.8155 7.7808,10.8155ZM7.5851,10.7147C7.6187,10.7248 7.6539,10.7323 7.6912,10.7376L7.6939,10.7387L7.6939,10.7408C7.7035,10.7781 7.7387,10.8064 7.7803,10.8064C7.8213,10.8064 7.8571,10.7781 7.8661,10.7408L7.8661,10.7376L7.8688,10.7365C7.9205,10.728 7.9691,10.7157 8.016,10.6949L7.992,10.656C7.9499,10.672 7.9099,10.6827 7.8661,10.6907L7.8629,10.6907L7.8619,10.6896C7.8512,10.6672 7.8315,10.6512 7.8064,10.6437L7.8037,10.6421L7.8037,10.4075L7.7547,10.4075L7.7541,10.6432L7.7515,10.6437C7.7291,10.6533 7.7104,10.6672 7.7008,10.6896L7.6997,10.6907L7.6965,10.6907C7.6667,10.6875 7.6357,10.6805 7.6075,10.6709L7.6075,10.6709L7.6037,10.6699C7.5941,10.6683 7.5867,10.6656 7.5787,10.6624C7.5723,10.6592 7.5664,10.6571 7.56,10.6555L7.5365,10.6944C7.5504,10.7019 7.5627,10.7056 7.5776,10.7109L7.5851,10.7147L7.5851,10.7147ZM7.3979,10.6821C7.4395,10.7115 7.4848,10.7323 7.5312,10.7531L7.5675,10.7173C7.5541,10.7136 7.5413,10.7072 7.5291,10.7035L7.5237,10.7013L7.5237,10.7003C7.4981,10.6896 7.4736,10.6773 7.4501,10.6619L7.4501,10.6619L7.4464,10.6587C7.4331,10.6533 7.4203,10.6437 7.4075,10.6325L7.3979,10.6821ZM7.4549,10.6533C7.4789,10.6683 7.504,10.6816 7.5291,10.6923L7.5525,10.6533C7.5269,10.6411 7.5024,10.6283 7.4789,10.6139L7.4549,10.6533ZM7.4416,10.5771C7.4848,10.6075 7.5317,10.6341 7.5819,10.6533C7.5883,10.6565 7.5941,10.6576 7.6011,10.6608L7.6128,10.6128C7.5627,10.5952 7.5168,10.5733 7.4768,10.544L7.4416,10.5771ZM7.4037,10.6187L7.408,10.6208C7.4208,10.6315 7.4341,10.6405 7.4475,10.6491L7.4709,10.6075C7.4315,10.5824 7.3957,10.5531 7.3637,10.5173L7.3616,10.5157L7.3632,10.5115C7.3851,10.4832 7.3856,10.448 7.3669,10.4197L7.3664,10.4171L7.5088,10.2571L7.4731,10.2277L7.3285,10.3883L7.3259,10.3867C7.3104,10.3808 7.2939,10.3792 7.2784,10.3808L7.2752,10.3819L7.2731,10.3776C7.2608,10.3472 7.2507,10.3152 7.2443,10.2816L7.2443,10.2816L7.2427,10.2789C7.2421,10.2688 7.24,10.2619 7.2389,10.2523C7.2389,10.2459 7.2379,10.2411 7.2373,10.2368L7.1893,10.2363C7.1899,10.2512 7.1925,10.2651 7.1957,10.28L7.1957,10.2859L7.1957,10.2859C7.2043,10.3243 7.2165,10.3632 7.2331,10.3995L7.2331,10.4027L7.2267,10.408C7.2112,10.4277 7.2048,10.4464 7.2053,10.4693C7.2075,10.4917 7.2176,10.512 7.2363,10.5275C7.2587,10.544 7.2917,10.5525 7.3205,10.5424L7.3237,10.5413L7.3243,10.5429C7.3477,10.5696 7.3755,10.5947 7.4037,10.6187ZM7.1349,10.2656L7.1835,10.2763C7.1813,10.2608 7.1787,10.2459 7.1787,10.2325L7.1776,10.2283L7.1787,10.2283C7.1765,10.2149 7.1755,10.1989 7.1755,10.1824L7.1755,10.144L7.1755,10.1157L7.1755,10.1035L7.1253,10.12L7.1349,10.2656ZM7.2475,10.2533C7.2475,10.2576 7.2485,10.2656 7.2501,10.272L7.3008,10.2565C7.3003,10.2443 7.2971,10.2059 7.296,10.1888C7.2955,10.1867 7.2949,10.1845 7.2949,10.1824C7.2944,10.1797 7.2944,10.1781 7.2949,10.1781C7.2944,10.1584 7.2939,10.1221 7.2939,10.1115L7.2427,10.1003L7.2427,10.1824C7.2432,10.2075 7.2443,10.2315 7.2475,10.2533L7.2475,10.2533L7.2475,10.2533ZM7.1872,10.2283L7.2352,10.2283C7.2352,10.216 7.2352,10.2 7.2352,10.1824L7.2352,10.1488L7.1851,10.1477L7.1851,10.1819C7.1851,10.1989 7.1851,10.2144 7.1872,10.2283ZM7.1851,10.1408L7.2352,10.1408L7.2352,10.0048L7.2379,10.0032C7.2629,9.9947 7.2827,9.9771 7.2912,9.9531L7.2928,9.9488L7.4475,9.9488L7.4475,9.9029L7.2939,9.9029L7.2928,9.8997C7.2848,9.8741 7.2635,9.8544 7.2373,9.8443L7.2341,9.8443L7.2341,9.6576L7.1856,9.6576L7.1856,9.8432L7.1824,9.8443C7.1467,9.8555 7.1211,9.8901 7.1211,9.9243C7.1211,9.9595 7.1467,9.9931 7.1824,10.0021L7.1856,10.0048L7.1856,10.1408L7.1851,10.1408ZM7.2923,10.5056C7.2816,10.5056 7.2725,10.5029 7.2635,10.4944C7.2544,10.488 7.2496,10.4779 7.248,10.4651C7.2475,10.4549 7.2507,10.4443 7.2592,10.4357C7.2677,10.4272 7.2795,10.4192 7.2923,10.4192C7.3035,10.4192 7.3131,10.4256 7.3211,10.4304C7.3301,10.44 7.3349,10.4485 7.3365,10.4597C7.3381,10.4693 7.3339,10.4816 7.3253,10.4901C7.3173,10.5008 7.3056,10.5056 7.2923,10.5056ZM7.2923,10.4309C7.2816,10.4309 7.2725,10.4336 7.2661,10.4421C7.2597,10.4491 7.2565,10.4571 7.2565,10.4656C7.2576,10.4752 7.2629,10.4821 7.2688,10.4896C7.2752,10.4939 7.2837,10.4949 7.2917,10.4949C7.3024,10.4949 7.3125,10.4923 7.3184,10.4843C7.3248,10.4779 7.328,10.4699 7.3275,10.4613C7.3264,10.4528 7.3221,10.4448 7.3157,10.4395C7.3093,10.4325 7.3003,10.4309 7.2923,10.4309ZM7.8128,10.3189L7.7461,10.3189L7.7461,10.0107C7.7456,10.0096 7.7445,10.0096 7.7445,10.0096L7.576,10.1963L7.5259,10.1568L7.6944,9.9685C7.6933,9.9659 7.6917,9.9616 7.6901,9.9573L7.5445,9.9573L7.5445,9.8949L7.6891,9.8949C7.6912,9.8907 7.6917,9.8896 7.6933,9.8853L7.5147,9.6875L7.5653,9.6448L7.7419,9.8405C7.7419,9.8405 7.744,9.8405 7.7445,9.8405L7.7445,9.5797L7.8107,9.5797L7.8107,9.8384C7.8107,9.8384 7.8107,9.8384 7.8112,9.8384C7.8128,9.8384 7.8133,9.8395 7.8139,9.8395L7.9856,9.6432L8.0368,9.6821L7.864,9.8779C7.8667,9.8821 7.8693,9.8885 7.872,9.8944L8.0128,9.8944L8.0128,9.9568L7.8709,9.9568C7.8693,9.9621 7.8667,9.9653 7.864,9.9691L8.0283,10.1557L7.9776,10.1952L7.8149,10.0096L7.8149,10.0096C7.8139,10.0107 7.8133,10.0107 7.8133,10.0117L7.8133,10.3189L7.8128,10.3189ZM7.7547,10.3093L7.8037,10.3093L7.8037,10.0059L7.8064,10.0048C7.8085,10.0032 7.8096,10.0032 7.8101,10.0032C7.8117,10.0032 7.8123,10.0032 7.8139,10.0032L7.8165,10.0011L7.8187,10.0032L7.9781,10.1835L8.0149,10.1547L7.8533,9.9696L7.8544,9.9685C7.8581,9.9632 7.8613,9.9573 7.8624,9.9531L7.864,9.9488L8.0032,9.9488L8.0032,9.9029L7.8651,9.9029L7.8635,9.9008C7.8613,9.8901 7.8581,9.8843 7.8544,9.8795L7.8533,9.8779L7.8549,9.8747L8.0235,9.6832L7.9867,9.6555L7.816,9.8475L7.8133,9.8464C7.8128,9.8453 7.8101,9.8453 7.8091,9.8443C7.8069,9.8443 7.8064,9.8443 7.8048,9.8443L7.8016,9.8443L7.8016,9.5893L7.7536,9.5893L7.7536,9.8448L7.7504,9.8459C7.7477,9.848 7.744,9.8491 7.7413,9.8512L7.7381,9.8533L7.5637,9.6576L7.5275,9.6901L7.7045,9.8837L7.7029,9.888C7.7013,9.8912 7.6987,9.8955 7.6971,9.9013L7.6955,9.9035L7.5536,9.9035L7.5536,9.9493L7.6971,9.9493L7.6981,9.9536C7.6997,9.9579 7.7013,9.9632 7.7045,9.9659L7.7061,9.9691L7.5387,10.1563L7.576,10.184L7.7429,9.9995L7.7483,10.0037C7.7493,10.0037 7.7509,10.0037 7.752,10.0037L7.7552,10.0053L7.7547,10.3093ZM7.4603,9.6283L7.4571,9.624L7.2459,9.3877C7.2443,9.3877 7.2443,9.3888 7.2432,9.3888C7.2432,9.3888 7.2427,9.3888 7.2427,9.3888L7.2427,9.5701L7.176,9.5701L7.1765,9.3856C7.1392,9.3723 7.1147,9.3397 7.1147,9.3013C7.1147,9.2501 7.1579,9.2075 7.2117,9.2075C7.2533,9.2075 7.2891,9.2325 7.3035,9.2688L7.4603,9.2688L7.4603,9.3312L7.3035,9.3312C7.3008,9.3387 7.2981,9.3429 7.2955,9.3467L7.5104,9.5861L7.4603,9.6283ZM7.2485,9.3781L7.2507,9.3797L7.4613,9.6155L7.4981,9.584L7.2859,9.3477L7.2864,9.3445C7.2907,9.3403 7.2933,9.3323 7.296,9.3269L7.2976,9.3216L7.4517,9.3216L7.4517,9.2779L7.2976,9.2779L7.296,9.2747C7.2848,9.2405 7.2512,9.2171 7.2123,9.2171C7.1637,9.2171 7.1237,9.2544 7.1237,9.3008C7.1237,9.3349 7.1483,9.3669 7.1829,9.3781L7.1861,9.3797L7.1861,9.3824L7.1861,9.5637L7.2352,9.5637L7.2352,9.3813L7.2384,9.3797C7.2389,9.3797 7.2416,9.3781 7.2427,9.3781C7.2448,9.3781 7.2459,9.3781 7.2469,9.3781L7.2485,9.3781Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0203,10.7621L7.9696,10.7147L7.976,10.7115C8.0197,10.6949 8.0608,10.6779 8.0981,10.6533L8.0741,10.6133C8.0352,10.6373 7.9925,10.6571 7.9504,10.6693L7.9445,10.6704L7.9296,10.6059L7.9339,10.6053C7.9845,10.5904 8.032,10.5653 8.0731,10.5339L8.0757,10.5317L8.1189,10.5691C8.1413,10.5525 8.1605,10.5328 8.1792,10.5147C8.16,10.4832 8.1579,10.4469 8.176,10.4171L8.0315,10.256L8.0816,10.2144L8.2277,10.3771C8.2416,10.3707 8.2576,10.3685 8.272,10.3707C8.2843,10.3419 8.2939,10.3115 8.3003,10.28L8.2411,10.2613L8.2416,10.256C8.2416,10.256 8.2475,10.2016 8.2475,10.1808C8.2475,10.1685 8.2501,10.1077 8.2501,10.1056L8.2501,10.1029L8.3099,10.0891L8.3099,10.0091C8.2843,10.0016 8.2635,9.9808 8.2539,9.9557L8.0976,9.9557L8.0976,9.8933L8.2533,9.8923C8.2635,9.8672 8.2832,9.8464 8.3104,9.8379L8.3104,9.7056L8.2507,9.6907L8.2507,9.5323L8.3104,9.5157L8.3104,9.3867C8.3083,9.3845 8.3061,9.3835 8.304,9.3824L8.0917,9.6219L8.04,9.5824L8.0432,9.5781L8.2571,9.3387C8.2571,9.3355 8.2555,9.3323 8.2544,9.3312L8.0971,9.3312L8.0971,9.2688L8.2544,9.2688C8.2683,9.2325 8.3045,9.2075 8.3445,9.2075C8.3984,9.2075 8.4421,9.2501 8.4421,9.3013C8.4421,9.3408 8.4171,9.3744 8.3781,9.3877L8.3771,9.5701L8.32,9.5701L8.32,9.6523L8.3771,9.6523L8.3765,9.8389C8.4155,9.8523 8.4421,9.8859 8.4421,9.9253C8.4421,9.9659 8.4171,9.9995 8.3771,10.0117L8.3771,10.0939L8.4357,10.1157L8.4272,10.2699L8.368,10.2832C8.3605,10.3227 8.3483,10.3632 8.3323,10.4021L8.3349,10.4032C8.3509,10.4219 8.36,10.4448 8.3573,10.4699C8.3557,10.4949 8.3445,10.5173 8.3237,10.5323C8.3003,10.5531 8.2661,10.5595 8.2357,10.5531C8.2107,10.5797 8.1824,10.6059 8.1536,10.6283L8.1669,10.6875L8.1637,10.6907C8.12,10.7189 8.0736,10.7435 8.0235,10.7605L8.0203,10.7621ZM7.9851,10.7173L8.0224,10.7531C8.0688,10.7323 8.1131,10.7115 8.1557,10.6821L8.144,10.632C8.1317,10.6432 8.1189,10.6528 8.1067,10.6581L8.1029,10.6624L8.1024,10.6613C8.0667,10.6821 8.0256,10.7029 7.9851,10.7173ZM7.9408,10.6123L7.9515,10.6603C8.008,10.6421 8.0629,10.6133 8.1125,10.5771L8.0757,10.5435C8.0352,10.5728 7.9904,10.5947 7.9408,10.6123ZM8.0816,10.6075L8.1056,10.6491C8.1189,10.6405 8.1317,10.6315 8.144,10.6208L8.1504,10.6181L8.1504,10.6187C8.1787,10.5947 8.2053,10.5696 8.2288,10.5435L8.2315,10.5419L8.2341,10.5429C8.2629,10.5531 8.2944,10.5445 8.3173,10.528C8.3349,10.5125 8.3467,10.4923 8.3477,10.4699C8.3504,10.4469 8.3424,10.4283 8.328,10.4085L8.3205,10.4032L8.3227,10.4C8.3376,10.3627 8.3504,10.3237 8.3579,10.2853L8.3589,10.2805C8.3616,10.2656 8.3632,10.2517 8.3653,10.2368L8.3163,10.2373C8.3125,10.2853 8.2997,10.3323 8.2795,10.3781L8.2789,10.3824L8.2757,10.3813C8.2603,10.3797 8.2432,10.3813 8.2293,10.3872L8.2261,10.3888L8.0821,10.2283L8.0448,10.2576L8.1888,10.4176L8.1861,10.4203C8.1675,10.4485 8.1696,10.4837 8.1893,10.512L8.192,10.5163L8.1888,10.5179C8.1568,10.5531 8.1211,10.5824 8.0816,10.6075ZM8.3755,10.2283L8.3755,10.2325C8.3733,10.2459 8.3728,10.2608 8.3691,10.2763L8.4192,10.2656L8.4267,10.12L8.3765,10.1035L8.3765,10.1157L8.3765,10.1483L8.3765,10.1483L8.3765,10.1824C8.3765,10.1989 8.3755,10.2144 8.3755,10.2283L8.3755,10.2283L8.3755,10.2283ZM8.2507,10.256L8.304,10.2715C8.3072,10.2443 8.3104,10.2176 8.3104,10.1819L8.3104,10.0997L8.2603,10.1109C8.2597,10.1216 8.2576,10.1579 8.2571,10.1776C8.2576,10.1776 8.2576,10.1792 8.2571,10.1819C8.2571,10.184 8.2571,10.1861 8.2571,10.1883C8.2555,10.2059 8.2523,10.2437 8.2507,10.256ZM8.3195,10.1488L8.3195,10.1824C8.3195,10.2 8.3189,10.216 8.3173,10.2283L8.3669,10.2283C8.3675,10.2149 8.3685,10.1989 8.3685,10.1824L8.3685,10.1483L8.3195,10.1488ZM8.1056,9.9488L8.2603,9.9488L8.2608,9.9531C8.2693,9.9781 8.2901,9.9947 8.3163,10.0032L8.3189,10.0048L8.3189,10.1408L8.368,10.1408L8.368,10.1157L8.368,10.0059L8.3712,10.0032C8.4069,9.9936 8.4315,9.9616 8.4315,9.9253C8.4315,9.8912 8.4064,9.8565 8.3707,9.8453L8.3675,9.8443L8.3675,9.8411L8.368,9.6587L8.3189,9.6587L8.3189,9.8453L8.3163,9.8453C8.288,9.8555 8.2693,9.8752 8.2603,9.9008L8.2597,9.904L8.1061,9.904L8.1061,9.9488L8.1056,9.9488ZM8.2603,9.6832L8.3104,9.6976L8.3104,9.5269L8.2603,9.5403L8.2603,9.6832ZM8.0528,9.5813L8.0891,9.6107L8.3003,9.3712L8.3035,9.3744C8.3077,9.3776 8.3125,9.3787 8.3157,9.3787L8.3184,9.3803L8.3184,9.5643L8.3675,9.5643L8.3685,9.3813L8.3712,9.3803C8.4075,9.3691 8.4315,9.3371 8.4315,9.3019C8.4315,9.2555 8.3931,9.2181 8.3435,9.2181C8.3061,9.2181 8.272,9.2416 8.2603,9.2757L8.2597,9.2789L8.104,9.2789L8.104,9.3227L8.2597,9.3227L8.2608,9.328C8.2624,9.3291 8.2635,9.3333 8.2656,9.3355L8.2667,9.3387L8.2667,9.3408L8.0528,9.5813ZM8.2603,10.5056C8.248,10.5056 8.2352,10.5008 8.2272,10.4907C8.2192,10.4821 8.2165,10.4699 8.2165,10.4603C8.2176,10.4491 8.2229,10.4405 8.232,10.4309C8.2405,10.4256 8.2507,10.4197 8.2603,10.4197C8.2731,10.4197 8.2853,10.4283 8.2944,10.4363C8.3013,10.4448 8.3056,10.4555 8.304,10.4656C8.304,10.4779 8.2976,10.4885 8.2885,10.4949C8.2816,10.5029 8.2709,10.5056 8.2603,10.5056ZM8.2603,10.4309C8.2523,10.4309 8.2443,10.4325 8.2379,10.44C8.2304,10.4453 8.2256,10.4533 8.2256,10.4619C8.2256,10.4704 8.2283,10.4784 8.2341,10.4848C8.2459,10.4981 8.2693,10.5013 8.2837,10.4901C8.2917,10.4827 8.2949,10.4757 8.2955,10.4661C8.2965,10.4576 8.2939,10.4496 8.288,10.4427C8.2805,10.4336 8.2709,10.4309 8.2603,10.4309ZM7.5413,10.3221L7.4752,10.2949L7.6096,10.1451L7.6475,10.2032L7.5413,10.3221ZM7.4907,10.2923L7.5381,10.3125L7.6384,10.2032L7.6085,10.1605L7.4907,10.2923ZM7.4379,10.2656L7.3995,10.2075L7.5067,10.0907L7.5728,10.1157L7.4379,10.2656ZM7.4101,10.2085L7.4395,10.2523L7.5573,10.12L7.5104,10.0997L7.4101,10.2085ZM7.2091,9.9659C7.1856,9.9659 7.1648,9.9472 7.1648,9.9253C7.1648,9.9035 7.1851,9.8827 7.2091,9.8827C7.2331,9.8827 7.2533,9.9035 7.2533,9.9253C7.2533,9.9472 7.2325,9.9659 7.2091,9.9659ZM7.2091,9.8907C7.1893,9.8907 7.1733,9.9061 7.1733,9.9248C7.1733,9.9429 7.1893,9.9573 7.2091,9.9573C7.2293,9.9573 7.2443,9.9435 7.2443,9.9248C7.2443,9.9061 7.2288,9.8907 7.2091,9.8907ZM7.2352,9.7083L7.2352,9.5157L7.3029,9.5323L7.3029,9.6907L7.2352,9.7083ZM7.2443,9.5269L7.2443,9.6976L7.2944,9.6832L7.2944,9.5403L7.2443,9.5269ZM7.1856,9.7083L7.1179,9.6907L7.1179,9.5323L7.1856,9.5157L7.1856,9.7083ZM7.1259,9.6821L7.1771,9.6976L7.1771,9.5269L7.1259,9.5403L7.1259,9.6821ZM7.8107,9.5008L7.7445,9.5008L7.7445,9.3872C7.7179,9.3776 7.696,9.3568 7.6859,9.3312L7.5445,9.3312L7.5445,9.2688L7.6859,9.2688C7.7008,9.2325 7.7355,9.2075 7.7765,9.2075C7.8176,9.2075 7.8544,9.2325 7.8677,9.2688L8.0117,9.2688L8.0117,9.3312L7.8667,9.3312C7.8565,9.3573 7.8379,9.3781 7.8112,9.3856L7.8107,9.5008ZM7.7541,9.4907L7.8021,9.4907L7.8027,9.3797L7.8059,9.3781C7.8315,9.3696 7.8501,9.352 7.8603,9.3269L7.8608,9.3216L8.0032,9.3216L8.0032,9.2779L7.8613,9.2779L7.8603,9.2747C7.8485,9.2405 7.8155,9.2171 7.776,9.2171C7.7381,9.2171 7.7045,9.2405 7.6933,9.2747L7.6917,9.2779L7.5541,9.2779L7.5541,9.3216L7.6917,9.3216L7.6933,9.3269C7.7019,9.3531 7.7232,9.3696 7.7504,9.3797L7.7536,9.3813L7.7536,9.4907L7.7541,9.4907Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7808,10.7659C7.7568,10.7659 7.7365,10.7451 7.7365,10.7221C7.7365,10.7003 7.7568,10.6816 7.7808,10.6816C7.8043,10.6816 7.8245,10.7003 7.8245,10.7221C7.8245,10.7445 7.8043,10.7659 7.7808,10.7659ZM7.7808,10.6907C7.7611,10.6907 7.7451,10.7045 7.7451,10.7221C7.7451,10.7408 7.7611,10.7563 7.7808,10.7563C7.8005,10.7563 7.8165,10.7408 7.8165,10.7221C7.8165,10.7045 7.8005,10.6907 7.7808,10.6907ZM7.7547,10.4555L7.6869,10.4363L7.6869,10.2779L7.7547,10.2592L7.7547,10.4555ZM7.6949,10.4299L7.7456,10.4437L7.7456,10.2699L7.6949,10.2843L7.6949,10.4299ZM7.8037,10.4555L7.8037,10.2592L7.8725,10.2779L7.8725,10.4363L7.8037,10.4555ZM7.8128,10.2699L7.8128,10.4437L7.8629,10.4299L7.8629,10.2848L7.8128,10.2699ZM8.0128,10.3221L8.0101,10.32L7.904,10.2032L7.944,10.1451L8.0779,10.2949L8.0128,10.3221ZM7.9163,10.2032L8.0149,10.3125L8.0629,10.2923L7.944,10.1605L7.9163,10.2032ZM8.1147,10.2656L7.9813,10.1157L8.0459,10.0907L8.1541,10.2075L8.1147,10.2656ZM7.9952,10.12L8.1131,10.2523L8.1424,10.2085L8.0437,10.0997L7.9952,10.12ZM8.136,10.0155L7.9701,10.0155L7.9504,9.9488L8.1568,9.9488L8.136,10.0155ZM7.9771,10.0059L8.1296,10.0059L8.1445,9.9573L7.9632,9.9573L7.9771,10.0059ZM7.5851,10.0155L7.4192,10.0155L7.4005,9.9488L7.6059,9.9488L7.5851,10.0155ZM7.4256,10.0059L7.5787,10.0059L7.5941,9.9573L7.4117,9.9573L7.4256,10.0059ZM8.3445,9.9659C8.32,9.9659 8.3008,9.9472 8.3008,9.9253C8.3008,9.9035 8.32,9.8827 8.3445,9.8827C8.3696,9.8827 8.3883,9.9035 8.3883,9.9253C8.3883,9.9472 8.3691,9.9659 8.3445,9.9659ZM8.3445,9.8907C8.3259,9.8907 8.3099,9.9061 8.3099,9.9248C8.3099,9.9429 8.3259,9.9573 8.3445,9.9573C8.3637,9.9573 8.3792,9.944 8.3792,9.9248C8.3792,9.9056 8.3632,9.8907 8.3445,9.8907ZM8.1568,9.9029L7.9504,9.9029L7.9701,9.8384L8.136,9.8384L8.1568,9.9029ZM7.9632,9.8949L8.1445,9.8949L8.1296,9.8448L7.9771,9.8448L7.9632,9.8949ZM7.6059,9.9029L7.4005,9.9029L7.4192,9.8384L7.5851,9.8384L7.6059,9.9029ZM7.4117,9.8949L7.5941,9.8949L7.5787,9.8448L7.4256,9.8448L7.4117,9.8949ZM7.4971,9.7547L7.3883,9.6341L7.4283,9.5781L7.5616,9.728L7.4971,9.7547ZM7.4005,9.6325L7.4992,9.744L7.5477,9.7232L7.4288,9.5925L7.4005,9.6325ZM8.0555,9.7509L7.9909,9.7227L8.1232,9.5728L8.1632,9.6293L8.0555,9.7509ZM8.0048,9.72L8.0533,9.7408L8.1509,9.6283L8.1232,9.5888L8.0048,9.72ZM8.3675,9.7083L8.3675,9.5157L8.4357,9.5323L8.4357,9.6907L8.3675,9.7083ZM8.3765,9.5269L8.3765,9.6976L8.4277,9.6821L8.4277,9.5403L8.3765,9.5269ZM7.5984,9.6949L7.4651,9.5483L7.5301,9.52L7.5323,9.5221L7.6384,9.6411L7.5984,9.6949ZM7.4789,9.5531L7.5979,9.6821L7.6261,9.6405L7.5275,9.5312L7.4789,9.5531ZM7.9531,9.6939L7.9131,9.6379L8.0197,9.5157L8.0853,9.544L8.0821,9.5483L7.9531,9.6939ZM7.9248,9.6384L7.9541,9.6779L8.0709,9.5456L8.0229,9.528L7.9248,9.6384ZM8.1381,9.3893L7.9728,9.3893L7.9515,9.3227L8.1573,9.3227L8.1381,9.3893ZM7.9787,9.3797L8.1317,9.3797L8.1456,9.3323L7.9627,9.3323L7.9787,9.3797ZM7.5845,9.3893L7.4187,9.3893L7.3979,9.3227L7.6037,9.3227L7.5845,9.3893ZM7.4256,9.3797L7.5781,9.3797L7.5925,9.3323L7.4107,9.3323L7.4256,9.3797ZM8.3445,9.3424C8.3205,9.3424 8.3008,9.3232 8.3008,9.3013C8.3008,9.2784 8.3205,9.2576 8.3445,9.2576C8.3696,9.2576 8.3883,9.2784 8.3883,9.3013C8.3883,9.3227 8.3691,9.3424 8.3445,9.3424ZM8.3445,9.2672C8.3259,9.2672 8.3104,9.2821 8.3104,9.3008C8.3104,9.3184 8.3259,9.3323 8.3445,9.3323C8.3637,9.3323 8.3797,9.3189 8.3797,9.3008C8.3797,9.2821 8.3637,9.2672 8.3445,9.2672ZM7.776,9.3424C7.7525,9.3424 7.7317,9.3232 7.7317,9.3013C7.7317,9.2784 7.752,9.2576 7.776,9.2576C7.8005,9.2576 7.8203,9.2784 7.8203,9.3013C7.8203,9.3227 7.8005,9.3424 7.776,9.3424ZM7.776,9.2672C7.7568,9.2672 7.7413,9.2821 7.7413,9.3008C7.7413,9.3184 7.7568,9.3323 7.776,9.3323C7.7957,9.3323 7.8117,9.3189 7.8117,9.3008C7.8117,9.2821 7.7957,9.2672 7.776,9.2672ZM7.2112,9.3424C7.1877,9.3424 7.1669,9.3232 7.1669,9.3013C7.1669,9.2784 7.1877,9.2576 7.2112,9.2576C7.2347,9.2576 7.2555,9.2784 7.2555,9.3013C7.2555,9.3227 7.2352,9.3424 7.2112,9.3424ZM7.2112,9.2672C7.1915,9.2672 7.1755,9.2821 7.1755,9.3008C7.1755,9.3184 7.1915,9.3323 7.2112,9.3323C7.2309,9.3323 7.2464,9.3189 7.2464,9.3008C7.2469,9.2821 7.2315,9.2672 7.2112,9.2672ZM8.1573,9.2779L7.9515,9.2779L7.9728,9.2123L8.1381,9.2123L8.1573,9.2779ZM7.9632,9.2688L8.1456,9.2688L8.1317,9.2197L7.9787,9.2197L7.9632,9.2688ZM7.6037,9.2779L7.3979,9.2779L7.4187,9.2123L7.5845,9.2123L7.6037,9.2779ZM7.4101,9.2688L7.592,9.2688L7.5776,9.2197L7.4251,9.2197L7.4101,9.2688ZM7.8027,9.6395L7.8027,9.4437L7.8704,9.4624L7.8704,9.6197L7.8027,9.6395ZM7.8112,9.4549L7.8112,9.6283L7.8619,9.6149L7.8619,9.4693L7.8112,9.4549ZM7.7541,9.6395L7.6859,9.6197L7.6859,9.4624L7.7541,9.4437L7.7541,9.6395ZM7.6944,9.6144L7.7451,9.6277L7.7451,9.4544L7.6944,9.4683L7.6944,9.6144Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.688,9.9269C7.688,9.8779 7.7291,9.8384 7.7808,9.8384C7.832,9.8384 7.8725,9.8779 7.8725,9.9269C7.8725,9.9739 7.8315,10.0144 7.7808,10.0144C7.7291,10.0144 7.688,9.9739 7.688,9.9269" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8005,7.6363L7.8032,7.6155L7.8059,7.6032C7.8059,7.6032 7.7504,7.6075 7.7227,7.6011C7.6944,7.592 7.6677,7.5808 7.6416,7.5573C7.6144,7.5344 7.6043,7.52 7.5856,7.5184C7.5387,7.5104 7.5045,7.5312 7.5045,7.5312C7.5045,7.5312 7.5387,7.5435 7.5637,7.5771C7.5899,7.6075 7.6181,7.6229 7.6299,7.6283C7.6512,7.6325 7.72,7.6283 7.7387,7.6299C7.7573,7.6315 7.8005,7.6363 7.8005,7.6363" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8069,7.6437L7.8005,7.6432C7.8,7.6432 7.7568,7.6373 7.7381,7.6363C7.7328,7.6363 7.7227,7.6363 7.7104,7.6368C7.7003,7.6373 7.688,7.6373 7.6757,7.6373C7.6507,7.6373 7.6357,7.6363 7.6283,7.632C7.6165,7.6293 7.5856,7.6155 7.5589,7.5792C7.5355,7.5504 7.5013,7.5381 7.5008,7.5381L7.4885,7.5317L7.5008,7.5264C7.5008,7.5253 7.528,7.5077 7.5653,7.5077C7.5733,7.5077 7.5792,7.5088 7.5856,7.5109C7.6027,7.5152 7.6133,7.5221 7.6293,7.5381C7.6341,7.5419 7.6389,7.5456 7.6453,7.5525C7.6693,7.5712 7.6928,7.5829 7.7243,7.5931C7.7355,7.5952 7.7509,7.5973 7.7728,7.5973C7.7904,7.5973 7.8048,7.5952 7.8053,7.5952L7.8144,7.5941L7.8101,7.6165L7.8069,7.6437ZM7.7323,7.6229C7.7349,7.6229 7.7376,7.6229 7.7381,7.6229C7.7536,7.624 7.7819,7.6283 7.7941,7.6283L7.7973,7.6107C7.7909,7.6117 7.7813,7.6117 7.7723,7.6117C7.7499,7.6117 7.7317,7.6096 7.72,7.6064C7.6875,7.5957 7.6613,7.5824 7.6368,7.5637C7.6299,7.5573 7.6251,7.5531 7.6192,7.5472C7.6043,7.5328 7.5963,7.5285 7.584,7.5253C7.5776,7.5232 7.5717,7.5221 7.5648,7.5221C7.5456,7.5221 7.5291,7.5285 7.5195,7.5317C7.5317,7.5403 7.5525,7.5525 7.5696,7.5701C7.5925,7.6027 7.6197,7.6176 7.632,7.6203C7.6384,7.6235 7.6533,7.6245 7.6757,7.6245C7.6875,7.6245 7.7003,7.6245 7.7104,7.6245C7.7195,7.6229 7.7264,7.6229 7.7323,7.6229Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0555,7.5584C8.0555,7.5584 8.0555,7.5824 8.0576,7.6075C8.0597,7.6299 8.0501,7.6496 8.0539,7.6619C8.0576,7.6741 8.0597,7.6827 8.0645,7.6939C8.0688,7.704 8.0725,7.7259 8.0725,7.7259C8.0725,7.7259 8.0592,7.7163 8.0475,7.7072C8.0352,7.6976 8.0256,7.6933 8.0256,7.6933C8.0256,7.6933 8.0288,7.7168 8.0293,7.7291C8.0315,7.7387 8.0379,7.7584 8.0475,7.7696C8.0565,7.7808 8.0757,7.8 8.0816,7.8155C8.088,7.8288 8.088,7.8635 8.088,7.8635C8.088,7.8635 8.072,7.8379 8.0576,7.8331C8.0443,7.8288 8.0155,7.8123 8.0155,7.8123C8.0155,7.8123 8.0416,7.8395 8.0416,7.8656C8.0416,7.8917 8.0315,7.9195 8.0315,7.9195C8.0315,7.9195 8.0192,7.896 8.0037,7.8811C7.9872,7.8672 7.9653,7.8512 7.9653,7.8512C7.9653,7.8512 7.9819,7.8917 7.9819,7.9168C7.9819,7.9435 7.9776,8 7.9776,8C7.9776,8 7.9637,7.9792 7.9504,7.9664C7.9376,7.9568 7.9211,7.9467 7.9163,7.9413C7.9115,7.9328 7.9317,7.9627 7.9349,7.9803C7.9365,7.9952 7.9445,8.0581 7.9995,8.1392C8.0315,8.184 8.08,8.2661 8.1851,8.2411C8.2912,8.2128 8.2512,8.0704 8.2288,8.0053C8.2064,7.9413 8.1968,7.8661 8.1973,7.8411C8.1984,7.816 8.2165,7.7408 8.2144,7.7264C8.2128,7.712 8.2064,7.6576 8.2187,7.616C8.2325,7.5691 8.2437,7.5536 8.2507,7.5328C8.2587,7.5163 8.2645,7.5035 8.2667,7.4891C8.2688,7.4704 8.2688,7.4411 8.2688,7.4411C8.2688,7.4411 8.2885,7.4784 8.2939,7.4912C8.2987,7.5035 8.2987,7.5413 8.2987,7.5413C8.2987,7.5413 8.3029,7.504 8.3317,7.4843C8.3621,7.4667 8.3957,7.4459 8.4043,7.4363C8.4133,7.4267 8.4155,7.4197 8.4155,7.4197C8.4155,7.4197 8.4128,7.4832 8.3941,7.5083C8.3819,7.5269 8.3355,7.5808 8.3355,7.5808C8.3355,7.5808 8.3595,7.5707 8.3755,7.5696C8.3936,7.5691 8.4059,7.5696 8.4059,7.5696C8.4059,7.5696 8.3856,7.5851 8.3579,7.6256C8.3317,7.6661 8.3419,7.6688 8.3232,7.7008C8.3035,7.7333 8.2875,7.7333 8.2635,7.7541C8.2261,7.7835 8.2453,7.9019 8.2512,7.9195C8.2555,7.9355 8.32,8.0795 8.32,8.1157C8.3221,8.1493 8.3285,8.2283 8.2672,8.2784C8.2272,8.3088 8.1632,8.3088 8.1483,8.3195C8.1328,8.3296 8.1045,8.3573 8.1045,8.4171C8.1045,8.4795 8.1264,8.4869 8.1429,8.5035C8.1611,8.5168 8.1824,8.5088 8.1872,8.5211C8.192,8.5323 8.1952,8.5397 8.2011,8.5461C8.2096,8.5547 8.2133,8.5605 8.2112,8.5733C8.2096,8.5856 8.1808,8.6171 8.1712,8.6357C8.1605,8.6576 8.1419,8.712 8.1419,8.72C8.1419,8.7296 8.1392,8.7541 8.1483,8.7669C8.1483,8.7669 8.1787,8.8032 8.1573,8.8085C8.1451,8.8139 8.1312,8.8011 8.1248,8.8032C8.1067,8.8075 8.0971,8.8181 8.0917,8.8165C8.0795,8.8165 8.0795,8.808 8.0784,8.7915C8.0768,8.7739 8.0779,8.7664 8.0725,8.7664C8.0645,8.7664 8.0608,8.7717 8.0608,8.7819C8.0587,8.7915 8.0587,8.8123 8.0507,8.8123C8.0421,8.8123 8.0293,8.7957 8.0224,8.7941C8.0144,8.7915 7.9941,8.7861 7.9925,8.7792C7.9925,8.7691 8.0048,8.7477 8.0187,8.7456C8.0325,8.7413 8.0448,8.7333 8.0363,8.7291C8.0267,8.7205 8.0187,8.7205 8.0107,8.7291C8.0016,8.7333 7.9829,8.7291 7.9851,8.7189C7.9867,8.7077 7.9888,8.6955 7.9867,8.6901C7.9867,8.6827 7.9707,8.6704 7.9904,8.6608C8.0101,8.6512 8.0187,8.6704 8.0384,8.6677C8.0576,8.6651 8.0672,8.6565 8.0747,8.6453C8.0827,8.6331 8.0805,8.608 8.0672,8.5941C8.0549,8.5787 8.0405,8.5787 8.0357,8.5675C8.0299,8.5573 8.0235,8.5355 8.0235,8.5355C8.0235,8.5355 8.0261,8.5781 8.024,8.5824C8.0219,8.5888 8.0235,8.6128 8.0235,8.6128C8.0235,8.6128 8.0101,8.5963 7.9984,8.5856C7.9883,8.5744 7.976,8.5408 7.976,8.5408C7.976,8.5408 7.976,8.5712 7.976,8.5835C7.976,8.5957 7.9899,8.6075 7.9856,8.6149C7.9797,8.6187 7.9573,8.5909 7.9509,8.5835C7.9445,8.5797 7.9259,8.5659 7.9168,8.5483C7.9072,8.5328 7.9013,8.5088 7.8992,8.5024C7.8971,8.4933 7.8928,8.4576 7.8971,8.4469C7.9029,8.4325 7.9131,8.4085 7.9131,8.4085C7.9131,8.4085 7.8907,8.4085 7.8651,8.4085C7.8389,8.4085 7.8208,8.4032 7.8107,8.4192C7.8005,8.4357 7.8069,8.4704 7.8187,8.5163C7.8309,8.5621 7.8384,8.5829 7.8347,8.5915C7.8309,8.6011 7.8149,8.6192 7.8091,8.6208C7.8027,8.6272 7.7856,8.6251 7.7787,8.6208C7.7707,8.6181 7.7589,8.6123 7.7355,8.6123C7.712,8.6123 7.6981,8.6133 7.6885,8.6101C7.6805,8.608 7.6608,8.5968 7.6501,8.6005C7.64,8.6037 7.6235,8.6112 7.6277,8.6245C7.6357,8.6453 7.6197,8.6507 7.6107,8.6485C7.6011,8.6464 7.592,8.6443 7.5797,8.6411C7.568,8.6368 7.5493,8.6411 7.5515,8.6277C7.5541,8.6133 7.5595,8.6123 7.5653,8.6027C7.5712,8.5915 7.5733,8.5829 7.5664,8.5829C7.5573,8.5829 7.5493,8.5819 7.5424,8.5872C7.5355,8.5931 7.5253,8.6037 7.5163,8.6C7.5077,8.5952 7.5008,8.584 7.5008,8.5643C7.5008,8.5413 7.4784,8.5216 7.4997,8.5237C7.5205,8.5248 7.5472,8.5413 7.552,8.5291C7.5563,8.5168 7.5536,8.5115 7.5424,8.504C7.5312,8.4928 7.5163,8.4885 7.5312,8.4768C7.5472,8.4656 7.5504,8.4656 7.5563,8.4581C7.5627,8.4528 7.5707,8.4315 7.5813,8.4352C7.6027,8.4459 7.5819,8.4603 7.6037,8.4832C7.6256,8.5083 7.6379,8.5168 7.6731,8.5125C7.7093,8.5083 7.7189,8.504 7.7189,8.4949C7.7189,8.4837 7.7163,8.4667 7.7141,8.4587C7.7125,8.4533 7.7189,8.4261 7.7189,8.4261C7.7189,8.4261 7.7035,8.4347 7.6976,8.4459C7.6939,8.456 7.6843,8.4709 7.6843,8.4709C7.6843,8.4709 7.68,8.4533 7.6816,8.4347C7.6816,8.4261 7.6848,8.4085 7.6848,8.4059C7.6843,8.3957 7.6773,8.3728 7.6773,8.3728C7.6773,8.3728 7.6725,8.3968 7.6677,8.4059C7.6635,8.4128 7.6624,8.4416 7.6624,8.4416C7.6624,8.4416 7.6395,8.4208 7.6453,8.3904C7.6496,8.3643 7.6411,8.3307 7.6496,8.3195C7.656,8.3083 7.6747,8.2651 7.7184,8.2624C7.7621,8.2597 7.7968,8.2656 7.8123,8.2635C7.8283,8.2624 7.8821,8.2539 7.8821,8.2539C7.8821,8.2539 7.7813,8.2005 7.7595,8.184C7.7365,8.1707 7.7003,8.1301 7.6891,8.112C7.6779,8.0939 7.6672,8.0576 7.6672,8.0576C7.6672,8.0576 7.6496,8.0576 7.6331,8.0688C7.6165,8.0789 7.6,8.0912 7.5909,8.1024C7.5813,8.1131 7.5659,8.1365 7.5659,8.1365C7.5659,8.1365 7.5685,8.1045 7.5685,8.0949C7.5685,8.0843 7.5669,8.0656 7.5669,8.0656C7.5669,8.0656 7.5563,8.1083 7.5328,8.1259C7.5099,8.1419 7.4832,8.1653 7.4832,8.1653C7.4832,8.1653 7.4859,8.1403 7.4859,8.1328C7.4859,8.1291 7.4912,8.1013 7.4912,8.1013C7.4912,8.1013 7.4752,8.1253 7.4501,8.1301C7.4251,8.1328 7.3893,8.1317 7.3867,8.1488C7.384,8.1648 7.3941,8.1835 7.3877,8.1941C7.3813,8.2064 7.3691,8.2149 7.3691,8.2149C7.3691,8.2149 7.3552,8.2027 7.3429,8.2027C7.3307,8.2016 7.3195,8.2069 7.3195,8.2069C7.3195,8.2069 7.3083,8.1936 7.3125,8.1829C7.3163,8.1755 7.3349,8.1616 7.3307,8.1557C7.3259,8.1515 7.3104,8.1568 7.3008,8.1632C7.2917,8.1669 7.2715,8.1696 7.2731,8.1557C7.2757,8.1403 7.2795,8.1317 7.2757,8.1195C7.2699,8.1088 7.2731,8.1029 7.2811,8.1008C7.288,8.0965 7.3195,8.1019 7.3227,8.0933C7.3248,8.0864 7.3136,8.0779 7.2944,8.0725C7.2741,8.0683 7.264,8.0571 7.2757,8.0453C7.2853,8.0368 7.288,8.0331 7.2933,8.0256C7.2976,8.0149 7.3008,7.9995 7.3184,8.0069C7.336,8.0155 7.3317,8.0352 7.3515,8.0416C7.3707,8.0485 7.416,8.04 7.4261,8.0325C7.4357,8.0272 7.4661,8.0053 7.4763,8.0011C7.4869,7.9936 7.5307,7.9627 7.5307,7.9627C7.5307,7.9627 7.5045,7.944 7.4949,7.9344C7.4859,7.9269 7.4688,7.9035 7.4608,7.9003C7.4512,7.8939 7.4096,7.8789 7.3947,7.8773C7.3808,7.8773 7.3365,7.8619 7.3365,7.8619C7.3365,7.8619 7.3573,7.8555 7.3637,7.8507C7.3701,7.8443 7.3861,7.8309 7.3931,7.832C7.4011,7.832 7.4027,7.832 7.4027,7.832C7.4027,7.832 7.3616,7.8309 7.3536,7.8277C7.3451,7.8267 7.32,7.8101 7.3109,7.8101C7.3013,7.8101 7.2816,7.8155 7.2816,7.8155C7.2816,7.8155 7.3072,7.7979 7.3285,7.7947C7.3488,7.7904 7.3659,7.7904 7.3659,7.7904C7.3659,7.7904 7.3323,7.7819 7.3259,7.7707C7.3173,7.76 7.3109,7.7445 7.3045,7.7371C7.2981,7.7301 7.2949,7.7184 7.2843,7.7179C7.2731,7.7152 7.2549,7.7301 7.2448,7.7291C7.2347,7.7275 7.2261,7.72 7.2261,7.7056C7.2256,7.6901 7.2261,7.6944 7.2224,7.6891C7.2181,7.68 7.2032,7.6608 7.2171,7.6565C7.2325,7.6523 7.2624,7.6576 7.2651,7.6523C7.2677,7.648 7.2485,7.6315 7.2363,7.6261C7.224,7.6187 7.2048,7.6064 7.2139,7.5989C7.2251,7.5893 7.2357,7.5867 7.2421,7.5771C7.2475,7.5685 7.2544,7.5467 7.2672,7.5547C7.2789,7.5627 7.2955,7.5968 7.3051,7.5936C7.3147,7.592 7.3163,7.5659 7.3136,7.5552C7.312,7.544 7.3136,7.5269 7.3232,7.5269C7.3323,7.5296 7.3408,7.5419 7.3563,7.5424C7.3712,7.5435 7.3952,7.5392 7.392,7.5509C7.3904,7.5611 7.3824,7.5749 7.3707,7.5861C7.3605,7.5973 7.3557,7.6203 7.3627,7.6373C7.3696,7.6517 7.3856,7.6768 7.4005,7.6875C7.4165,7.696 7.4448,7.7035 7.4629,7.7147C7.4816,7.7269 7.5232,7.7611 7.5381,7.7648C7.5525,7.768 7.5664,7.7771 7.5664,7.7771C7.5664,7.7771 7.5824,7.7675 7.6048,7.7675C7.6272,7.7675 7.6779,7.7707 7.6971,7.7643C7.7168,7.7547 7.7413,7.7419 7.7328,7.7248C7.7253,7.7061 7.6832,7.6917 7.6875,7.6784C7.6912,7.6645 7.7067,7.6645 7.7317,7.6645C7.7573,7.6635 7.7936,7.6677 7.8005,7.6309C7.8069,7.5936 7.8085,7.5749 7.7728,7.5659C7.7355,7.5557 7.7093,7.5557 7.7029,7.5312C7.696,7.5051 7.6891,7.4987 7.6971,7.4912C7.704,7.4832 7.7179,7.48 7.7445,7.4789C7.7717,7.4773 7.8016,7.4773 7.8107,7.4688C7.8197,7.4645 7.8213,7.4459 7.8325,7.4395C7.8421,7.4309 7.8837,7.4272 7.8837,7.4272C7.8837,7.4272 7.9328,7.4512 7.9792,7.4827C8.0203,7.5152 8.0571,7.5589 8.0571,7.5589" + android:strokeWidth="1" + android:fillColor="#ED72AA" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0912,8.8219C8.0912,8.8219 8.0912,8.8219 8.0901,8.8219C8.0725,8.8197 8.0725,8.8075 8.0715,8.7931L8.0704,8.7819C8.0704,8.7792 8.0699,8.7765 8.0693,8.7723C8.0688,8.7733 8.0667,8.7765 8.0667,8.7819C8.0667,8.7819 8.0661,8.7851 8.0661,8.7893C8.064,8.8016 8.0635,8.8181 8.0507,8.8181C8.0421,8.8181 8.0357,8.8112 8.0283,8.8059C8.0251,8.8032 8.0213,8.8 8.0203,8.7989C8.0176,8.7979 8.0149,8.7957 8.0123,8.7947C8.0016,8.7931 7.9883,8.7893 7.9861,8.7781C7.9851,8.7659 8.0005,8.7424 8.0176,8.7387C8.0251,8.7355 8.0299,8.7323 8.0315,8.7323C8.0251,8.728 8.0203,8.728 8.0144,8.7323C8.0069,8.7397 7.9957,8.7376 7.9877,8.7323C7.9808,8.7296 7.9765,8.7227 7.9781,8.7173L7.9792,8.7072C7.9797,8.7029 7.9808,8.6939 7.9797,8.6907C7.9797,8.6907 7.9797,8.6896 7.9792,8.6875C7.9765,8.6821 7.9728,8.6779 7.9739,8.6688C7.9765,8.6645 7.9797,8.6576 7.9867,8.656C8.0011,8.6469 8.0107,8.6533 8.0197,8.6565C8.0251,8.6576 8.0299,8.6619 8.0363,8.6597C8.0555,8.6576 8.064,8.6512 8.0699,8.6411C8.0757,8.6325 8.0736,8.6107 8.0629,8.5984C8.0565,8.5909 8.0507,8.5877 8.0453,8.5829C8.0395,8.5813 8.0363,8.5787 8.0331,8.5733C8.0325,8.5787 8.032,8.5829 8.0309,8.584C8.0304,8.5893 8.0304,8.6027 8.0304,8.6128L8.0315,8.6315L8.0192,8.6165C8.0192,8.6165 8.0059,8.6043 7.9952,8.5915C7.9904,8.5861 7.9867,8.5792 7.9835,8.5707C7.9835,8.5792 7.9835,8.5819 7.9835,8.584C7.9835,8.5915 7.9867,8.5947 7.9899,8.5984C7.9931,8.6053 7.9968,8.6128 7.9909,8.6192C7.9835,8.6277 7.9712,8.616 7.9573,8.5984C7.9536,8.5952 7.9499,8.5909 7.9488,8.5909C7.9371,8.5813 7.9205,8.5675 7.912,8.5536C7.9035,8.536 7.8976,8.5152 7.8949,8.5051C7.8923,8.4949 7.8869,8.4576 7.8923,8.4453C7.896,8.4368 7.9013,8.4251 7.9045,8.416L7.8667,8.416C7.8592,8.416 7.8528,8.416 7.8469,8.416C7.8304,8.4149 7.8235,8.4149 7.8181,8.4213C7.8112,8.4357 7.8133,8.4661 7.8267,8.5163L7.8315,8.5328C7.8421,8.5701 7.8459,8.5851 7.8427,8.5941C7.8384,8.6037 7.8213,8.6224 7.8139,8.6283C7.8059,8.6325 7.7851,8.6309 7.7776,8.6283C7.7707,8.6229 7.7589,8.6181 7.7371,8.6181C7.7307,8.6181 7.7248,8.6181 7.7189,8.6181C7.7056,8.6181 7.696,8.6187 7.6891,8.6155C7.6869,8.6155 7.6827,8.6155 7.6779,8.6133C7.6709,8.608 7.6581,8.6043 7.6523,8.6059C7.6459,8.6069 7.6384,8.6117 7.6363,8.6155C7.6347,8.6187 7.6341,8.6197 7.6357,8.6208C7.64,8.6341 7.6373,8.6432 7.6341,8.6459C7.6277,8.6533 7.6187,8.6565 7.6123,8.6549C7.6043,8.6533 7.5984,8.6533 7.5904,8.6501C7.5872,8.6491 7.5835,8.6469 7.5797,8.6448C7.5765,8.6448 7.5728,8.6448 7.5691,8.6448C7.5616,8.6437 7.5531,8.6437 7.5493,8.6373C7.5461,8.632 7.5461,8.6293 7.5461,8.6261C7.5493,8.6155 7.5525,8.6085 7.5557,8.6048C7.5579,8.6032 7.5584,8.6021 7.5611,8.5968C7.5632,8.5936 7.5648,8.5904 7.5648,8.5904C7.5584,8.5893 7.5525,8.5893 7.5493,8.592L7.5461,8.5947C7.5381,8.6021 7.5275,8.6101 7.5152,8.6059C7.5024,8.5979 7.496,8.5835 7.496,8.5637C7.496,8.5557 7.4933,8.5483 7.4896,8.5408C7.4869,8.5323 7.4832,8.5285 7.4869,8.52C7.4907,8.5157 7.4971,8.5157 7.5019,8.5157C7.5104,8.5173 7.5195,8.52 7.5269,8.5211C7.5339,8.5243 7.5456,8.5285 7.5477,8.5264C7.5509,8.5173 7.5504,8.5157 7.5392,8.5067C7.5381,8.5061 7.5365,8.5035 7.5339,8.5035C7.5269,8.4971 7.5205,8.4933 7.5205,8.4848C7.5205,8.48 7.5237,8.4752 7.5301,8.4704C7.5365,8.4661 7.5419,8.4619 7.5456,8.4581C7.5488,8.4571 7.552,8.4565 7.5536,8.4539C7.5552,8.4528 7.5557,8.4496 7.5579,8.4453C7.5637,8.4389 7.5728,8.4235 7.5861,8.4304C7.5995,8.4373 7.6,8.4453 7.6005,8.4539C7.6011,8.4624 7.6016,8.4693 7.6101,8.4789C7.6304,8.504 7.6427,8.5083 7.6741,8.5056C7.7083,8.504 7.7136,8.4965 7.7136,8.4944C7.7136,8.4848 7.7115,8.4704 7.7104,8.4651L7.7093,8.4576C7.7088,8.4549 7.7099,8.4469 7.7115,8.4411C7.7083,8.4437 7.7067,8.4453 7.7051,8.4464C7.7019,8.4576 7.6917,8.4747 7.6912,8.4757L7.6827,8.4912L7.6789,8.4725C7.6789,8.4715 7.6741,8.4539 7.6763,8.4331C7.6763,8.4288 7.6763,8.4224 7.6779,8.4165C7.6789,8.4133 7.6795,8.4069 7.6795,8.4064C7.6795,8.4037 7.6789,8.4027 7.6784,8.3984C7.6763,8.4037 7.6763,8.4064 7.6747,8.408C7.6736,8.4123 7.6704,8.4288 7.6704,8.4416L7.6693,8.4555L7.6587,8.4453C7.6581,8.4453 7.6336,8.4235 7.6405,8.3883C7.6421,8.3776 7.6421,8.3643 7.6416,8.3541C7.6405,8.3355 7.6395,8.3227 7.6453,8.3168C7.6459,8.3157 7.648,8.3125 7.6485,8.3083C7.6581,8.2917 7.6789,8.2571 7.72,8.2555C7.7472,8.2539 7.7701,8.2555 7.7888,8.2565C7.7989,8.2571 7.8075,8.2571 7.8139,8.2571C7.8235,8.2565 7.8464,8.2539 7.864,8.2485C7.8331,8.2331 7.7739,8.2037 7.7579,8.1915C7.7328,8.1755 7.6976,8.1333 7.6864,8.1163C7.6768,8.1019 7.6677,8.0779 7.664,8.0661C7.6576,8.0661 7.648,8.0688 7.6379,8.0736C7.6203,8.0832 7.6048,8.0955 7.5979,8.1067C7.5888,8.1168 7.5739,8.1413 7.5739,8.1413L7.5616,8.136C7.5616,8.136 7.5643,8.1077 7.5643,8.0965C7.5579,8.1088 7.5488,8.1227 7.5387,8.1317C7.5157,8.1461 7.4896,8.1701 7.4896,8.1701L7.4773,8.1813L7.4784,8.1653C7.4805,8.1541 7.4811,8.1403 7.4811,8.1339C7.4811,8.1328 7.4821,8.1285 7.4832,8.1216C7.4752,8.1291 7.4651,8.1339 7.4533,8.1371C7.4469,8.1392 7.4395,8.1403 7.4331,8.1413C7.4176,8.1413 7.3957,8.1445 7.3947,8.152C7.3931,8.1573 7.3947,8.1664 7.3952,8.1707C7.3973,8.1819 7.3984,8.1915 7.3952,8.2005C7.3883,8.2123 7.3739,8.2208 7.3733,8.2208L7.3701,8.2229L7.3664,8.2208C7.3632,8.2165 7.3515,8.2085 7.3429,8.2085C7.3323,8.2085 7.3232,8.2149 7.3232,8.2149L7.3173,8.2171L7.3136,8.2128C7.3136,8.2096 7.3013,8.1952 7.3072,8.1835C7.3083,8.1792 7.3136,8.1728 7.3168,8.1696C7.3195,8.1669 7.3216,8.1648 7.3232,8.1616C7.3184,8.1637 7.3083,8.1669 7.3045,8.1701C7.2971,8.1723 7.2821,8.1797 7.2731,8.1712C7.2699,8.1701 7.2661,8.1669 7.2667,8.1573C7.2667,8.1536 7.2683,8.1461 7.2693,8.1451C7.2699,8.1349 7.272,8.1317 7.2693,8.1259C7.2651,8.1173 7.2667,8.1093 7.2672,8.1051C7.2693,8.1013 7.2731,8.0965 7.2789,8.0955C7.2816,8.0949 7.288,8.0949 7.296,8.0939C7.3008,8.0939 7.3109,8.0939 7.3157,8.0923C7.3131,8.0901 7.3067,8.0837 7.2928,8.0811C7.2779,8.0795 7.2672,8.0699 7.2651,8.0597C7.2635,8.0544 7.2656,8.0475 7.2704,8.0437C7.2816,8.0336 7.2832,8.0325 7.2885,8.0224C7.2885,8.0213 7.2885,8.0203 7.2896,8.0187C7.2917,8.0117 7.2949,8.0048 7.3035,8.0027C7.3077,7.9995 7.3136,8.0005 7.3211,8.0048C7.3323,8.0091 7.3355,8.0171 7.3403,8.0224C7.344,8.0299 7.3467,8.0336 7.3547,8.0368C7.3707,8.0437 7.4139,8.0336 7.4224,8.0293C7.4261,8.0283 7.4347,8.0208 7.4437,8.0171C7.4549,8.0075 7.4672,7.9995 7.4736,7.9963C7.48,7.992 7.5051,7.9755 7.52,7.9648C7.5109,7.9573 7.4981,7.9461 7.4912,7.9419C7.4875,7.9387 7.4821,7.9333 7.4784,7.9296C7.4709,7.92 7.4613,7.9088 7.4576,7.9077C7.4485,7.9045 7.4075,7.8869 7.3952,7.8859C7.3797,7.8837 7.3392,7.8715 7.3355,7.8704L7.3168,7.864L7.3355,7.8576C7.3424,7.8544 7.3552,7.8501 7.36,7.8464L7.3632,7.8448C7.3643,7.8421 7.3675,7.8421 7.3696,7.84C7.3611,7.8389 7.3552,7.8379 7.3515,7.8357C7.3488,7.8336 7.3424,7.8325 7.336,7.8293C7.3285,7.8251 7.3141,7.8181 7.3109,7.8181C7.3029,7.8181 7.2885,7.8208 7.2827,7.8208L7.2784,7.8085C7.28,7.8085 7.3051,7.792 7.3269,7.7899C7.3296,7.7888 7.3328,7.7888 7.3349,7.7883C7.3291,7.7835 7.3237,7.7808 7.32,7.7781C7.3173,7.7707 7.3125,7.7659 7.3088,7.7584C7.3051,7.7531 7.3013,7.7461 7.2987,7.7419C7.2987,7.7419 7.2955,7.7387 7.2949,7.7344C7.2907,7.7291 7.288,7.7259 7.2837,7.7248C7.28,7.7248 7.2736,7.7291 7.2672,7.7307C7.2592,7.7333 7.2512,7.7376 7.2448,7.7365C7.2293,7.7344 7.2197,7.7253 7.2197,7.7083L7.2192,7.704C7.2192,7.6997 7.2187,7.6965 7.2187,7.6955C7.2171,7.6955 7.2171,7.6944 7.2171,7.6912C7.216,7.6912 7.2139,7.6891 7.2139,7.6859C7.208,7.6784 7.2027,7.6688 7.2059,7.6576C7.2075,7.6565 7.2096,7.6533 7.216,7.6512C7.224,7.648 7.2363,7.6491 7.2459,7.6491C7.2496,7.6501 7.2544,7.6501 7.2571,7.6501C7.2517,7.6448 7.2427,7.6368 7.2336,7.6325C7.2176,7.624 7.2069,7.616 7.2048,7.6075C7.2048,7.6032 7.2048,7.5989 7.2112,7.5952C7.2149,7.5909 7.2203,7.5888 7.2235,7.5845C7.2299,7.5813 7.2331,7.5781 7.2357,7.576C7.2368,7.5728 7.2384,7.5696 7.2389,7.5685C7.2443,7.5589 7.2485,7.5509 7.2571,7.5477C7.2603,7.5456 7.2635,7.5456 7.2693,7.5499C7.2757,7.5531 7.2816,7.5621 7.2885,7.5696C7.2939,7.5781 7.3008,7.5883 7.304,7.5904C7.3067,7.5872 7.3093,7.5696 7.3067,7.5568C7.3051,7.5472 7.3056,7.5317 7.3131,7.5253C7.3163,7.52 7.3195,7.5189 7.3243,7.52C7.3291,7.5211 7.3349,7.5264 7.3381,7.5291C7.3445,7.5317 7.3488,7.5365 7.3563,7.5371C7.36,7.5371 7.3632,7.5371 7.368,7.5371C7.3797,7.5365 7.3909,7.536 7.3952,7.5419C7.3973,7.5445 7.3984,7.5477 7.3973,7.5531C7.3947,7.5669 7.3819,7.5824 7.3749,7.5904C7.3664,7.6016 7.3627,7.6197 7.3675,7.6341C7.3744,7.6507 7.3904,7.6725 7.4037,7.6821C7.4112,7.6864 7.4219,7.6907 7.4315,7.6944C7.4432,7.6997 7.456,7.7045 7.4656,7.7099C7.472,7.7152 7.4789,7.7195 7.4875,7.7264C7.5061,7.7397 7.5307,7.7568 7.5392,7.7568C7.5504,7.7621 7.5616,7.7669 7.5659,7.768C7.5723,7.7664 7.5872,7.7627 7.6043,7.7627C7.6096,7.7627 7.6155,7.7627 7.6224,7.7627C7.6443,7.7637 7.68,7.7648 7.6939,7.7563C7.7125,7.7499 7.7243,7.7413 7.7269,7.7333C7.7285,7.7312 7.7285,7.7301 7.7269,7.7269C7.7248,7.7195 7.7136,7.7147 7.7045,7.7061C7.6917,7.6976 7.6779,7.6896 7.6816,7.6768C7.6859,7.656 7.7072,7.656 7.7323,7.656C7.7355,7.656 7.7387,7.656 7.7429,7.656C7.7707,7.656 7.7888,7.6544 7.7947,7.6299C7.8016,7.5925 7.8016,7.5792 7.7717,7.5728C7.7664,7.5707 7.7611,7.5685 7.7552,7.5685C7.7264,7.5643 7.7035,7.5573 7.6971,7.5312C7.6955,7.5248 7.6923,7.5189 7.6917,7.5147C7.6875,7.5024 7.6853,7.4939 7.6928,7.4864C7.7024,7.4768 7.7173,7.4741 7.7456,7.4709C7.752,7.4709 7.7573,7.4699 7.7632,7.4699C7.7803,7.4688 7.8021,7.4688 7.808,7.4645C7.8112,7.4645 7.8128,7.456 7.8144,7.4533C7.8176,7.4453 7.8213,7.4395 7.8288,7.4331C7.8395,7.4267 7.8789,7.4187 7.8827,7.4187L7.8853,7.4187L7.8864,7.4187C7.8869,7.4187 7.9365,7.4437 7.9824,7.4784C8.0235,7.5083 8.0603,7.552 8.0608,7.5552L8.0576,7.5573L8.064,7.5573C8.064,7.5584 8.064,7.5813 8.0656,7.6053C8.0672,7.6176 8.0645,7.6299 8.064,7.6395C8.0613,7.6469 8.0613,7.6544 8.0613,7.6571C8.0629,7.6624 8.064,7.6645 8.064,7.6677C8.0672,7.6773 8.0677,7.6811 8.0715,7.6896C8.0768,7.6992 8.08,7.7189 8.08,7.7232L8.0811,7.7397L8.0693,7.7296C8.0693,7.7296 8.056,7.7184 8.0437,7.7109C8.0405,7.7072 8.0379,7.7061 8.0363,7.7045C8.0363,7.7125 8.0363,7.7184 8.0373,7.7259C8.0389,7.7333 8.0448,7.752 8.0533,7.7643C8.0549,7.7659 8.0581,7.7685 8.0613,7.7707C8.0715,7.7819 8.0848,7.7968 8.0891,7.8101C8.096,7.8267 8.0955,7.8592 8.0955,7.8613L8.0949,7.8811L8.0832,7.8645C8.0768,7.8549 8.0651,7.8395 8.0576,7.8384C8.0517,7.8357 8.0459,7.8309 8.0395,7.8299C8.0459,7.8395 8.0501,7.8517 8.0501,7.8635C8.0501,7.8896 8.0395,7.9179 8.0395,7.9189L8.0331,7.9312L8.0267,7.9189C8.0267,7.9189 8.0144,7.8981 7.9995,7.8827C7.9936,7.8773 7.9867,7.872 7.9803,7.8683C7.9856,7.8816 7.9899,7.9008 7.9899,7.9152C7.9899,7.9419 7.9867,7.9952 7.9861,7.9995L7.9835,8.0192L7.9744,8.0027C7.9744,8.0027 7.9611,7.9808 7.9488,7.9691C7.9456,7.968 7.9424,7.9664 7.9387,7.9648C7.9403,7.9691 7.9429,7.9755 7.9429,7.9771C7.9493,8.0304 7.9707,8.0811 8.0064,8.1323L8.0117,8.1397C8.0432,8.1867 8.0896,8.2565 8.1856,8.2315C8.2085,8.2272 8.2272,8.2139 8.2368,8.1941C8.2587,8.1557 8.2539,8.0933 8.2245,8.0064C8.2021,7.9397 8.1915,7.8645 8.1931,7.8395C8.1931,7.8272 8.1973,7.8053 8.2021,7.7813C8.2053,7.7595 8.2117,7.7312 8.2101,7.7269C8.2069,7.7072 8.2021,7.6549 8.2149,7.6112C8.2245,7.5792 8.2336,7.5611 8.24,7.5456C8.2432,7.5392 8.2459,7.5349 8.2469,7.5301C8.2496,7.5248 8.2512,7.5189 8.2523,7.5163C8.2576,7.5051 8.2613,7.496 8.2624,7.4859C8.2651,7.4688 8.2651,7.4395 8.2651,7.4395L8.2773,7.4384C8.2773,7.4395 8.2971,7.4736 8.3024,7.4875C8.3035,7.4912 8.3056,7.4971 8.3056,7.5045C8.312,7.4933 8.3184,7.4853 8.3307,7.4768C8.3371,7.4731 8.3445,7.4683 8.352,7.4645C8.3733,7.4523 8.3957,7.4384 8.4011,7.4304C8.4085,7.4197 8.4123,7.4149 8.4123,7.4149L8.4245,7.4181C8.4245,7.4192 8.4208,7.4848 8.4021,7.5131C8.3931,7.5227 8.3712,7.5483 8.3568,7.5653C8.3643,7.5653 8.3707,7.5632 8.3771,7.5632C8.3952,7.5611 8.408,7.5632 8.4085,7.5632L8.4245,7.5653L8.4123,7.5744C8.4123,7.5749 8.3909,7.5904 8.3648,7.6283C8.3509,7.6501 8.3477,7.6587 8.3445,7.6699C8.3419,7.6784 8.3392,7.6896 8.3312,7.7035C8.3152,7.7285 8.3024,7.7349 8.2885,7.7451C8.2821,7.7483 8.2757,7.7536 8.2683,7.7573C8.2363,7.7835 8.2523,7.8949 8.2587,7.9157C8.2592,7.92 8.2661,7.9376 8.2747,7.9563C8.296,8.0075 8.3275,8.0885 8.328,8.1147L8.3285,8.1189C8.3312,8.1557 8.3333,8.2315 8.272,8.2816C8.2448,8.3035 8.2069,8.3109 8.1797,8.3157C8.1685,8.3189 8.1568,8.32 8.1525,8.3232C8.1461,8.3285 8.112,8.3536 8.112,8.416C8.112,8.4661 8.1275,8.4784 8.1419,8.4912C8.1435,8.4928 8.1461,8.4944 8.1493,8.4955C8.1557,8.504 8.1648,8.504 8.1723,8.5067C8.1808,8.5072 8.1899,8.5083 8.1941,8.5179L8.1957,8.5205C8.1989,8.5307 8.2021,8.5349 8.2075,8.5413C8.2144,8.5456 8.2224,8.5568 8.2187,8.5749C8.2181,8.5835 8.208,8.5947 8.1989,8.6075C8.1904,8.6187 8.1829,8.6293 8.1776,8.6411C8.1675,8.6597 8.1488,8.7141 8.1488,8.72L8.1488,8.7243C8.1488,8.7339 8.1488,8.7547 8.1541,8.7627C8.1579,8.7669 8.176,8.7899 8.1707,8.8043C8.1701,8.8085 8.1675,8.8128 8.16,8.8165C8.1488,8.8192 8.1387,8.8155 8.1323,8.8101C8.1296,8.808 8.1259,8.808 8.1259,8.808C8.1168,8.8091 8.1104,8.8165 8.104,8.8181C8.1003,8.8197 8.096,8.8219 8.0912,8.8219ZM8.072,8.7584C8.0821,8.7584 8.0832,8.7696 8.0837,8.7824L8.0848,8.7925C8.0848,8.8075 8.0848,8.8075 8.0917,8.8085C8.0917,8.8085 8.0944,8.8075 8.0976,8.8064C8.104,8.8032 8.1109,8.7968 8.1227,8.7952C8.1275,8.7941 8.1317,8.7952 8.1371,8.7973C8.1424,8.8016 8.1493,8.8037 8.1547,8.8037C8.1568,8.8027 8.1568,8.8005 8.1568,8.8005C8.16,8.7941 8.1504,8.7787 8.1419,8.7701C8.1333,8.7568 8.1344,8.7339 8.1349,8.7232L8.1349,8.7189C8.1349,8.7077 8.1552,8.6533 8.1648,8.6325C8.1691,8.6213 8.1787,8.6096 8.1872,8.5989C8.1941,8.5893 8.2037,8.5781 8.2037,8.5696C8.2064,8.5632 8.2037,8.5563 8.1973,8.5499C8.1883,8.5429 8.1856,8.5355 8.1813,8.5269L8.1803,8.5205C8.1787,8.5195 8.1755,8.5184 8.1691,8.5179C8.16,8.5168 8.1477,8.5152 8.1376,8.5061C8.1349,8.5029 8.1339,8.5029 8.1312,8.5008C8.1152,8.4875 8.0971,8.4704 8.0971,8.4155C8.0971,8.3445 8.1349,8.3168 8.1435,8.3125C8.1499,8.3072 8.1595,8.3061 8.1749,8.3029C8.2,8.2976 8.2368,8.2907 8.2613,8.2693C8.3168,8.2256 8.3147,8.1557 8.3125,8.1195L8.3125,8.1152C8.3125,8.0901 8.2789,8.008 8.2597,7.96C8.2507,7.9403 8.2448,7.9248 8.2437,7.9195C8.2437,7.9184 8.2128,7.7819 8.2576,7.7477C8.2661,7.7419 8.272,7.7371 8.2784,7.7323C8.2928,7.7248 8.3035,7.7184 8.3157,7.6949C8.3248,7.6827 8.3269,7.6752 8.3296,7.6656C8.3333,7.6555 8.3371,7.6437 8.352,7.6197C8.3664,7.5989 8.3803,7.5835 8.3888,7.576C8.3845,7.576 8.3808,7.576 8.376,7.5771C8.36,7.5781 8.3371,7.5856 8.3371,7.5856L8.3285,7.576C8.3296,7.5749 8.3771,7.52 8.3883,7.5045C8.3989,7.4907 8.4032,7.4645 8.4059,7.4432C8.3968,7.4533 8.3781,7.4645 8.3557,7.4779C8.3493,7.4811 8.3419,7.4853 8.3344,7.4901C8.3093,7.5056 8.3051,7.5403 8.3045,7.5403L8.2912,7.5403C8.2912,7.5307 8.2907,7.5029 8.2869,7.4917C8.2843,7.4869 8.28,7.4779 8.2747,7.4667C8.2747,7.4747 8.2747,7.4816 8.2731,7.4901C8.272,7.5024 8.2672,7.5099 8.2624,7.5205C8.2608,7.5269 8.2597,7.5307 8.2565,7.5339C8.2549,7.5403 8.2523,7.5451 8.2496,7.5525C8.2432,7.5664 8.2341,7.584 8.2245,7.6149C8.2123,7.6565 8.2181,7.7067 8.2208,7.7232C8.2219,7.7317 8.2187,7.7525 8.2123,7.7845C8.2085,7.8064 8.2037,7.8272 8.2032,7.84C8.2032,7.8651 8.2123,7.936 8.2347,8.0027C8.2656,8.0933 8.2688,8.1568 8.2469,8.2005C8.2347,8.2224 8.2139,8.2389 8.1867,8.2443C8.0811,8.2704 8.0288,8.1941 7.9973,8.1472L7.9936,8.1413C7.9563,8.0885 7.9344,8.0325 7.928,7.9797C7.9253,7.968 7.9141,7.9488 7.9099,7.9429L7.9099,7.9429L7.9072,7.9397L7.9093,7.9333L7.912,7.9301L7.9157,7.9312C7.9173,7.9312 7.9184,7.9312 7.92,7.9344L7.92,7.9333C7.9232,7.9397 7.9307,7.944 7.9397,7.9509C7.9435,7.952 7.9499,7.9563 7.9531,7.9605C7.9595,7.9648 7.9659,7.9717 7.9717,7.9797C7.9728,7.9605 7.9744,7.9312 7.9744,7.9147C7.9744,7.8896 7.9584,7.8523 7.9584,7.8523L7.9493,7.8304L7.968,7.8427C7.968,7.8437 7.9904,7.8571 8.0059,7.8741C8.0155,7.8816 8.0229,7.8928 8.0277,7.9024C8.0304,7.8901 8.0341,7.8773 8.0341,7.864C8.0341,7.84 8.0091,7.8149 8.0091,7.8149L8.0176,7.8048C8.0181,7.8048 8.0464,7.8187 8.0592,7.8261C8.0661,7.8272 8.0747,7.8336 8.08,7.8411C8.0795,7.8309 8.0784,7.8197 8.0752,7.8144C8.072,7.8043 8.0597,7.7909 8.0501,7.7808C8.0475,7.7765 8.0437,7.7744 8.0411,7.7701C8.0304,7.7568 8.0245,7.7365 8.0224,7.7264C8.0224,7.7152 8.0187,7.6907 8.0187,7.6907L8.0181,7.6768L8.0293,7.6853C8.0293,7.6853 8.0379,7.6912 8.0501,7.7019C8.0544,7.7035 8.0592,7.7061 8.0624,7.7083C8.0613,7.7035 8.0597,7.6976 8.0587,7.6939C8.0544,7.6885 8.0528,7.6805 8.0501,7.6699C8.0501,7.6688 8.0491,7.6645 8.0475,7.6635C8.0459,7.6549 8.0475,7.6459 8.0491,7.6373C8.0501,7.6267 8.0528,7.6176 8.0507,7.6059C8.0496,7.5893 8.0485,7.5685 8.0485,7.5621C8.0405,7.5515 8.0085,7.5141 7.9733,7.4891C7.9344,7.4587 7.8907,7.4379 7.8811,7.4309C7.8656,7.4352 7.8405,7.4395 7.8347,7.4432C7.8315,7.4475 7.8283,7.4533 7.8251,7.4576C7.8224,7.464 7.8187,7.4699 7.8139,7.4763C7.8064,7.4805 7.7893,7.4805 7.7627,7.4827C7.7563,7.4827 7.7504,7.4837 7.744,7.4848C7.7205,7.4869 7.7072,7.4891 7.7003,7.4944C7.6992,7.4965 7.6987,7.4976 7.7029,7.5077C7.704,7.5141 7.7067,7.5189 7.7088,7.5291C7.7125,7.5451 7.728,7.5515 7.7563,7.5557C7.7627,7.5557 7.7675,7.5568 7.7728,7.5589C7.8171,7.5685 7.8123,7.6005 7.8064,7.6309C7.7995,7.6683 7.7659,7.6683 7.7419,7.6683C7.7381,7.6683 7.7349,7.6683 7.7312,7.6683C7.7061,7.6683 7.6955,7.6704 7.6939,7.6795C7.6939,7.6816 7.7051,7.6912 7.712,7.6949C7.7221,7.704 7.7344,7.7125 7.7381,7.72C7.7408,7.7264 7.7408,7.7312 7.7387,7.7387C7.7344,7.7499 7.7221,7.7584 7.6987,7.768C7.6816,7.7765 7.6469,7.7765 7.6208,7.7755C7.6144,7.7755 7.6091,7.7755 7.6037,7.7755C7.584,7.7755 7.5685,7.7808 7.5685,7.7808L7.5659,7.7808L7.5627,7.7808C7.5627,7.7808 7.5504,7.7744 7.536,7.7696C7.5253,7.7675 7.5061,7.7547 7.4805,7.736C7.4725,7.7301 7.4651,7.7248 7.4597,7.72C7.4501,7.7147 7.4384,7.7109 7.4277,7.7067C7.416,7.7024 7.4053,7.6971 7.3973,7.6928C7.3813,7.6816 7.3627,7.6571 7.3563,7.64C7.3477,7.6224 7.3536,7.5952 7.3659,7.5819C7.3749,7.5696 7.3824,7.5579 7.3845,7.5515C7.3813,7.5493 7.3728,7.5504 7.368,7.5504C7.3621,7.5504 7.3584,7.5504 7.3541,7.5504C7.3435,7.5493 7.336,7.544 7.3301,7.5397C7.3264,7.5365 7.3237,7.5333 7.3211,7.5323C7.3189,7.5355 7.3179,7.5435 7.3184,7.5547C7.3205,7.5637 7.3216,7.5947 7.3061,7.6021C7.296,7.6037 7.2875,7.5925 7.2784,7.5787C7.272,7.5696 7.2661,7.5637 7.2624,7.5605C7.2603,7.5595 7.2597,7.5595 7.2597,7.5595C7.2565,7.5605 7.2533,7.5691 7.2501,7.5739C7.2491,7.5771 7.2475,7.5803 7.2459,7.5813C7.2411,7.5888 7.2357,7.5915 7.2299,7.5936C7.2256,7.5979 7.2224,7.6021 7.2187,7.6037C7.2181,7.6053 7.2192,7.6096 7.2384,7.6187C7.2485,7.6251 7.2677,7.6395 7.2709,7.6491C7.2725,7.6523 7.2715,7.6555 7.2699,7.6565C7.2667,7.664 7.2581,7.664 7.2443,7.6619C7.2352,7.6619 7.2256,7.6608 7.2192,7.664C7.2165,7.6651 7.2224,7.6763 7.224,7.6789C7.2256,7.6816 7.2261,7.6816 7.2277,7.6848C7.2288,7.6869 7.2288,7.6891 7.2288,7.6901C7.2315,7.6928 7.2315,7.6933 7.2315,7.7024L7.2315,7.7056C7.232,7.7189 7.2395,7.72 7.2437,7.7211C7.248,7.7221 7.2549,7.7189 7.2603,7.7163C7.2688,7.7136 7.2763,7.7083 7.2837,7.7093C7.2944,7.7109 7.2997,7.7189 7.304,7.7269C7.3061,7.7285 7.3061,7.7301 7.3083,7.7312C7.312,7.7376 7.3157,7.7424 7.3189,7.7509C7.3221,7.7563 7.3259,7.7621 7.3296,7.7669C7.3349,7.7728 7.3536,7.7808 7.3659,7.7829L7.3643,7.7963C7.3637,7.7963 7.3483,7.7952 7.3285,7.8005C7.3237,7.8016 7.3189,7.8016 7.3147,7.8032C7.3216,7.8048 7.3301,7.8091 7.3413,7.8144C7.3477,7.8176 7.3515,7.8197 7.3536,7.8208C7.3584,7.8229 7.3749,7.8251 7.3877,7.8261C7.3899,7.8261 7.3909,7.8251 7.3931,7.8261C7.3968,7.8272 7.4,7.8272 7.4005,7.8272C7.4011,7.8272 7.4011,7.8272 7.4016,7.8272L7.4011,7.8395C7.4011,7.8395 7.4011,7.8395 7.4,7.8395C7.3989,7.8395 7.3936,7.8395 7.3893,7.8395C7.3856,7.8395 7.3787,7.8437 7.3696,7.8517L7.3664,7.8549C7.3637,7.856 7.36,7.8581 7.3557,7.8613C7.3691,7.8645 7.3877,7.8688 7.3936,7.8699C7.4096,7.872 7.4533,7.8896 7.4624,7.8939C7.4688,7.896 7.4752,7.9051 7.4875,7.9173C7.4907,7.9211 7.4955,7.9275 7.4987,7.9301C7.5077,7.9397 7.5328,7.9563 7.5333,7.9563L7.5408,7.9627L7.5339,7.9675C7.5285,7.9691 7.4885,8.0011 7.4784,8.0053C7.472,8.0075 7.4603,8.0171 7.4501,8.0251C7.4411,8.0304 7.432,8.0363 7.4283,8.0395C7.4165,8.0437 7.3696,8.0549 7.3488,8.048C7.3365,8.0437 7.3312,8.0336 7.328,8.0272C7.3248,8.0197 7.3216,8.016 7.3147,8.0149C7.3115,8.0117 7.3083,8.0117 7.3061,8.0128C7.3045,8.0139 7.3029,8.0181 7.3003,8.0203C7.2997,8.024 7.2997,8.0277 7.2981,8.0277C7.2933,8.0389 7.2896,8.04 7.2789,8.0517C7.2757,8.0544 7.2763,8.056 7.2763,8.056C7.2779,8.0581 7.2843,8.0656 7.2944,8.0672C7.3109,8.0699 7.3216,8.0784 7.3264,8.0832C7.328,8.0896 7.328,8.0933 7.328,8.0944C7.3237,8.1045 7.3104,8.1056 7.2955,8.1056C7.2907,8.1056 7.2843,8.1056 7.2816,8.1056C7.2795,8.1067 7.2784,8.1067 7.2784,8.1067C7.2784,8.1109 7.2784,8.1152 7.2811,8.1179C7.2843,8.1275 7.2827,8.1355 7.2811,8.144C7.2805,8.1483 7.2795,8.1525 7.2784,8.1563C7.2784,8.1563 7.2784,8.1573 7.2784,8.1573C7.2805,8.1605 7.2901,8.1584 7.2965,8.1563C7.3104,8.1499 7.3264,8.1424 7.3339,8.152C7.3403,8.1573 7.3328,8.1675 7.3248,8.1771C7.3216,8.1797 7.3179,8.1824 7.3173,8.1867C7.3157,8.1899 7.3179,8.1941 7.3205,8.1979C7.3248,8.1947 7.3339,8.1936 7.3429,8.1936C7.3531,8.1936 7.3632,8.2021 7.3685,8.2048C7.3723,8.2016 7.3781,8.1973 7.3808,8.192C7.3835,8.1893 7.3813,8.1803 7.3808,8.1717C7.3792,8.1643 7.3781,8.1552 7.3792,8.1467C7.3824,8.1301 7.4059,8.1269 7.4288,8.1269C7.4357,8.1248 7.4432,8.1237 7.4496,8.1227C7.4709,8.1184 7.4853,8.0955 7.4853,8.0955L7.4971,8.1019C7.4944,8.1141 7.4917,8.1312 7.4917,8.1323C7.4917,8.1365 7.4912,8.1424 7.4901,8.1477C7.5003,8.1392 7.5152,8.1285 7.5275,8.1184C7.5493,8.1045 7.5595,8.064 7.5595,8.064L7.5728,8.064C7.5728,8.064 7.5739,8.0827 7.5739,8.0933C7.5739,8.0965 7.5739,8.1035 7.5739,8.1099C7.5771,8.1045 7.5813,8.0992 7.5851,8.0933C7.5936,8.0859 7.6107,8.0693 7.6288,8.0608C7.6464,8.0512 7.6651,8.0512 7.6661,8.0501L7.6715,8.0501L7.6731,8.0544C7.6731,8.0544 7.6843,8.0885 7.6939,8.1056C7.7056,8.1243 7.7403,8.1637 7.7616,8.1765C7.784,8.192 7.8837,8.2432 7.8843,8.2432L7.9024,8.2533L7.8827,8.256C7.88,8.256 7.8272,8.2672 7.8112,8.2672C7.8048,8.2683 7.7957,8.2672 7.7851,8.2672C7.7675,8.2667 7.7445,8.2656 7.7173,8.2667C7.6837,8.2683 7.6672,8.2976 7.6581,8.3141C7.6555,8.3168 7.6549,8.3184 7.6533,8.3195C7.6507,8.3269 7.6523,8.3392 7.6523,8.3509C7.6523,8.3632 7.6528,8.3771 7.6512,8.3893C7.6491,8.4016 7.6523,8.4144 7.6549,8.4219C7.6565,8.4144 7.6581,8.4053 7.6608,8.4021C7.6629,8.3947 7.6677,8.3797 7.6693,8.3685L7.6747,8.3445L7.6821,8.3685C7.6821,8.3696 7.6896,8.3936 7.6896,8.4021C7.6896,8.4053 7.6896,8.4085 7.6885,8.4176C7.6875,8.4229 7.6864,8.4293 7.6864,8.4331C7.6864,8.4395 7.6864,8.4437 7.6864,8.4496C7.688,8.4443 7.6896,8.4421 7.6907,8.4389C7.696,8.4288 7.7125,8.4181 7.7147,8.4171L7.7269,8.4085L7.7237,8.4251C7.7211,8.4373 7.7189,8.4512 7.7195,8.4555L7.7205,8.4597C7.7205,8.4683 7.7232,8.4816 7.7232,8.4923C7.7232,8.5077 7.7067,8.5141 7.672,8.5168C7.6336,8.5195 7.6181,8.5109 7.5963,8.4869C7.5845,8.4731 7.584,8.4619 7.5835,8.4533C7.5829,8.4448 7.5829,8.4432 7.5765,8.4395C7.5733,8.4395 7.5675,8.4491 7.5653,8.4517C7.5643,8.456 7.5611,8.4571 7.56,8.4603C7.5557,8.4645 7.5531,8.4672 7.5483,8.4688C7.5456,8.4699 7.5408,8.4752 7.5339,8.48C7.5296,8.4816 7.5296,8.4827 7.5296,8.4827C7.5296,8.4848 7.536,8.4901 7.5392,8.4901C7.5403,8.4928 7.5419,8.4944 7.5456,8.4944C7.5579,8.5056 7.5627,8.5152 7.5563,8.5301C7.552,8.5424 7.536,8.5392 7.5205,8.5328C7.5125,8.5317 7.5045,8.5301 7.4976,8.5291C7.4971,8.5291 7.496,8.5291 7.496,8.5291C7.4965,8.5307 7.4981,8.5317 7.4987,8.5349C7.5019,8.5435 7.5061,8.5525 7.5061,8.5632C7.5061,8.5872 7.5147,8.592 7.5173,8.5936C7.5205,8.5947 7.5291,8.5893 7.5333,8.5829C7.5339,8.5819 7.536,8.5819 7.536,8.5808C7.5456,8.5739 7.5552,8.5755 7.5643,8.5776C7.5707,8.5776 7.5733,8.5803 7.5733,8.5819C7.5765,8.5883 7.5733,8.5941 7.568,8.6043C7.5664,8.6069 7.5643,8.6101 7.5621,8.6133C7.5589,8.6171 7.5579,8.6197 7.5552,8.6277C7.5552,8.6277 7.5552,8.6293 7.5552,8.6293C7.5568,8.6309 7.5643,8.6309 7.5669,8.632C7.5701,8.632 7.5755,8.632 7.5792,8.632C7.5824,8.6341 7.5867,8.6363 7.5904,8.6373C7.5973,8.6405 7.6021,8.6405 7.608,8.6421C7.6123,8.6421 7.6171,8.6405 7.6192,8.6405C7.6203,8.6363 7.6203,8.632 7.6187,8.6272C7.6171,8.6197 7.6171,8.616 7.6203,8.6096C7.6251,8.6021 7.6363,8.5952 7.6453,8.5941C7.6544,8.5909 7.6651,8.5952 7.6795,8.6016C7.6827,8.6037 7.6859,8.6037 7.6885,8.6037C7.6933,8.6064 7.7019,8.6053 7.7147,8.6053C7.7205,8.6053 7.7264,8.6053 7.7328,8.6053C7.7579,8.6053 7.7707,8.6112 7.7787,8.6165C7.7851,8.6181 7.7989,8.6192 7.8027,8.6165C7.8075,8.6155 7.8229,8.5957 7.8261,8.5904C7.8272,8.5829 7.8219,8.5653 7.8144,8.5381L7.8096,8.5189C7.7952,8.4661 7.7925,8.4331 7.8027,8.4165C7.8117,8.4 7.8272,8.4021 7.8453,8.4043C7.8501,8.4043 7.856,8.4043 7.8624,8.4043L7.92,8.4043L7.9168,8.4139C7.9168,8.4139 7.9061,8.4379 7.9003,8.4523C7.8976,8.4587 7.9003,8.4917 7.9024,8.5003L7.9029,8.5035C7.9051,8.5099 7.9109,8.5328 7.9195,8.5461C7.9243,8.5573 7.9349,8.5696 7.9509,8.5808C7.9536,8.5824 7.9573,8.5835 7.9621,8.592C7.9637,8.592 7.9664,8.5952 7.968,8.5963C7.9664,8.5936 7.9659,8.5909 7.9659,8.5851C7.9659,8.5717 7.9664,8.5424 7.9664,8.5424L7.9787,8.5392C7.9819,8.5467 7.9909,8.5733 8,8.5829C8.0037,8.5872 8.0085,8.5925 8.0133,8.5963C8.0133,8.5909 8.0133,8.584 8.0144,8.5813C8.016,8.5787 8.0144,8.5563 8.0133,8.5381L8.0256,8.5339C8.0256,8.5339 8.032,8.5573 8.0379,8.5675C8.0379,8.5691 8.0421,8.5717 8.0469,8.5739C8.0533,8.5803 8.0597,8.5835 8.0683,8.5925C8.0837,8.6091 8.0843,8.6352 8.0752,8.6496C8.0661,8.664 8.0539,8.6715 8.0341,8.6747C8.0235,8.6779 8.0155,8.6715 8.0091,8.6704C8.0016,8.6672 7.9968,8.664 7.9883,8.6672C7.9845,8.6704 7.9829,8.6715 7.9819,8.6736C7.9813,8.6768 7.984,8.68 7.9845,8.6827C7.9872,8.6843 7.9872,8.6864 7.9877,8.6896C7.9899,8.6955 7.9877,8.7051 7.9872,8.7125L7.9861,8.7211C7.9861,8.7221 7.9877,8.7221 7.9888,8.7232C7.9936,8.7264 7.9984,8.7264 8.0005,8.7232C8.0117,8.7157 8.0235,8.7157 8.0341,8.7232C8.04,8.7307 8.04,8.7339 8.04,8.7344C8.0373,8.7456 8.0245,8.7499 8.0149,8.7541C8.0043,8.7552 7.9931,8.7717 7.9936,8.7792C7.9952,8.7803 8.0069,8.7845 8.0112,8.7845C8.0149,8.7867 8.0181,8.7877 8.0197,8.7899C8.0235,8.792 8.0272,8.7947 8.0309,8.7973C8.0357,8.8016 8.0421,8.8075 8.0453,8.8075C8.0459,8.8059 8.0464,8.7952 8.0475,8.7904C8.0475,8.7861 8.048,8.7851 8.0485,8.7835C8.0555,8.7627 8.0667,8.7584 8.072,8.7584Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.704,7.5323C7.704,7.5323 7.6976,7.5184 7.6971,7.5147C7.696,7.5072 7.6928,7.5035 7.6928,7.5035C7.6928,7.5035 7.7227,7.5035 7.7221,7.5131C7.7205,7.5205 7.712,7.5205 7.7104,7.5253C7.7077,7.528 7.704,7.5323 7.704,7.5323" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8389,7.4875L7.8379,7.472C7.8379,7.472 7.8635,7.472 7.8757,7.4816C7.8944,7.4949 7.9072,7.5157 7.9067,7.5173C7.9035,7.52 7.8885,7.5072 7.8779,7.5035C7.8779,7.5035 7.8699,7.5067 7.8629,7.5067C7.8544,7.5067 7.8512,7.5035 7.8507,7.4992C7.8496,7.4949 7.8512,7.4907 7.8512,7.4907L7.8389,7.4875" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.904,7.5189C7.9013,7.5189 7.8971,7.5157 7.8917,7.5125C7.8864,7.5083 7.8821,7.5061 7.8779,7.5056C7.8763,7.5056 7.8699,7.5072 7.8629,7.5072C7.8544,7.5072 7.8512,7.5029 7.8491,7.4987C7.8485,7.4944 7.8496,7.4901 7.8501,7.4901L7.8384,7.488L7.8384,7.4869L7.8363,7.4693L7.8379,7.4693C7.8384,7.4693 7.8635,7.4704 7.8757,7.4805C7.8944,7.4928 7.9072,7.5141 7.9072,7.5147C7.9072,7.5163 7.9072,7.5163 7.9072,7.5163C7.9067,7.5184 7.9051,7.5189 7.904,7.5189ZM7.8773,7.5029L7.8773,7.5029C7.8816,7.5045 7.8875,7.5072 7.8912,7.5104C7.8976,7.5147 7.9019,7.5157 7.9035,7.5157C7.9035,7.5157 7.904,7.5157 7.9045,7.5157C7.9035,7.5147 7.8917,7.4949 7.8752,7.4821C7.8635,7.4747 7.8427,7.4725 7.8379,7.4725L7.84,7.4859L7.8512,7.488L7.8507,7.4901C7.8507,7.4901 7.8496,7.4944 7.8507,7.4976C7.8507,7.5029 7.8544,7.5056 7.8624,7.5056C7.8693,7.5056 7.8768,7.5029 7.8773,7.5029L7.8773,7.5029Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3253,7.528C7.3253,7.528 7.3413,7.5403 7.3536,7.5419C7.3659,7.5435 7.3797,7.5435 7.3813,7.5435C7.3835,7.5435 7.3877,7.5269 7.3845,7.5141C7.3781,7.4715 7.3408,7.464 7.3408,7.464C7.3408,7.464 7.3525,7.4891 7.3472,7.4992C7.3403,7.5157 7.3253,7.528 7.3253,7.528" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3819,7.552C7.3776,7.552 7.3653,7.5509 7.3541,7.5488C7.3392,7.5445 7.3227,7.5333 7.3221,7.5323L7.3152,7.5296L7.3216,7.5237C7.3216,7.5237 7.3355,7.5115 7.3419,7.4955C7.3445,7.4901 7.3403,7.4747 7.3355,7.4651L7.3307,7.4528L7.344,7.4571C7.3445,7.4571 7.3856,7.4683 7.392,7.5125C7.3941,7.5237 7.3915,7.544 7.3883,7.5477L7.3856,7.5509L7.3819,7.552ZM7.3355,7.528C7.3413,7.5312 7.3493,7.5333 7.3552,7.5355C7.3632,7.5376 7.3728,7.5376 7.3781,7.5376C7.3787,7.5323 7.3808,7.5211 7.3787,7.5157C7.3755,7.4933 7.3627,7.4816 7.3536,7.4763C7.3552,7.4837 7.3563,7.4949 7.3536,7.5035C7.3483,7.5136 7.3413,7.5211 7.3355,7.528Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2475,7.5659C7.2475,7.5659 7.2336,7.5387 7.2037,7.5408C7.1723,7.5451 7.1525,7.5691 7.1525,7.5691C7.1525,7.5691 7.1861,7.5675 7.1941,7.5733C7.2064,7.5819 7.2101,7.6037 7.2101,7.6037C7.2101,7.6037 7.2288,7.5915 7.2352,7.5829C7.2405,7.5781 7.2475,7.5659 7.2475,7.5659" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2069,7.6133L7.2043,7.6027C7.2043,7.5973 7.1995,7.5819 7.192,7.5776C7.1888,7.5776 7.1808,7.5755 7.16,7.5755C7.1557,7.5755 7.1536,7.5755 7.1536,7.5755L7.1387,7.5755L7.1483,7.5648C7.1483,7.5637 7.1701,7.5387 7.2032,7.5323C7.2379,7.5301 7.2544,7.5573 7.2544,7.5595L7.256,7.5648L7.2544,7.5664C7.2544,7.5675 7.2459,7.5797 7.2405,7.5877C7.2341,7.5941 7.2171,7.6053 7.2144,7.6064L7.2069,7.6133ZM7.1691,7.5627C7.1915,7.5637 7.1963,7.5659 7.1973,7.5675C7.2064,7.5733 7.2123,7.5824 7.2144,7.5925C7.2203,7.5888 7.2267,7.5824 7.2288,7.5803C7.2325,7.5765 7.2379,7.5691 7.2405,7.5664C7.2352,7.5579 7.2235,7.5456 7.2037,7.5477C7.1893,7.5499 7.1781,7.5563 7.1691,7.5627Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2101,7.6699C7.2101,7.6699 7.1851,7.6731 7.1701,7.6907C7.1568,7.7061 7.1579,7.7376 7.1579,7.7376C7.1579,7.7376 7.1755,7.7189 7.1915,7.7189C7.2069,7.7189 7.2299,7.7248 7.2299,7.7248C7.2299,7.7248 7.2229,7.7061 7.2229,7.696C7.2224,7.6907 7.2101,7.6699 7.2101,7.6699" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1531,7.7531L7.1515,7.7376C7.1515,7.7355 7.1504,7.7035 7.1664,7.6853C7.1819,7.6683 7.2091,7.6645 7.2101,7.6645L7.2139,7.6635L7.2165,7.6656C7.2192,7.6699 7.2288,7.6885 7.2288,7.696C7.2288,7.7035 7.2331,7.7157 7.2357,7.7211L7.2416,7.7323L7.2293,7.7312C7.2293,7.7312 7.2053,7.7259 7.192,7.7259C7.1808,7.7259 7.1669,7.7371 7.1637,7.7403L7.1531,7.7531Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.696,7.6699l0.0203,-0.0293l0.0187,0.0283z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7317,7.6656l0.0133,-0.0187l0.0149,0.0176l-0.0283,0.0011" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7195,7.5824l-0.0053,-0.0357l0.0443,0.0181z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7531,7.5648l0.0251,0.0053l-0.0208,0.0133l-0.0043,-0.0187" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6709,8.0645L7.6651,8.0533C7.6656,8.0533 7.7008,8.0325 7.7131,8.0283C7.7301,8.016 7.7445,7.9979 7.7477,7.9925C7.7477,7.9803 7.7445,7.9536 7.7413,7.9408C7.7381,7.9323 7.7381,7.9221 7.7381,7.9136C7.7323,7.92 7.7259,7.9269 7.7205,7.9307C7.7125,7.9376 7.6885,7.9531 7.6592,7.9573C7.6357,7.9659 7.6256,7.9696 7.6256,7.9696L7.6165,7.96C7.6165,7.96 7.6341,7.9317 7.6352,7.9077C7.6352,7.904 7.6352,7.8981 7.6331,7.8901L7.6331,7.8901C7.6256,7.8944 7.6101,7.9024 7.6064,7.904C7.6043,7.9051 7.5947,7.9109 7.5883,7.9152C7.5808,7.9195 7.5728,7.9275 7.5659,7.9307C7.5547,7.9381 7.5408,7.9568 7.536,7.9648L7.5253,7.9563C7.5259,7.9563 7.5419,7.9285 7.5589,7.9189C7.5664,7.9147 7.5733,7.9083 7.5813,7.9051C7.5925,7.8949 7.5984,7.8928 7.6027,7.8917C7.6059,7.8901 7.6213,7.8816 7.632,7.8779C7.6315,7.8757 7.6315,7.8736 7.6309,7.8704C7.6304,7.8581 7.6368,7.8443 7.6427,7.8331C7.6331,7.8373 7.624,7.8405 7.6176,7.8405C7.6069,7.8405 7.6016,7.8405 7.5893,7.8352C7.5851,7.8331 7.5787,7.832 7.5707,7.8304C7.544,7.8224 7.5243,7.8405 7.5243,7.8405L7.5136,7.848L7.5125,7.8347C7.5125,7.8336 7.512,7.816 7.5248,7.7952C7.5365,7.7787 7.5643,7.7701 7.5659,7.7701L7.5701,7.7824C7.5627,7.7835 7.5429,7.7925 7.5365,7.8032C7.5307,7.8085 7.5285,7.8155 7.5269,7.8208C7.5376,7.8171 7.5547,7.8123 7.5739,7.8171C7.5824,7.8197 7.5893,7.8208 7.5936,7.8229C7.6053,7.8283 7.608,7.8283 7.6165,7.8283C7.6261,7.8283 7.6491,7.8187 7.6581,7.816L7.6805,7.8075L7.6645,7.8283C7.6581,7.8325 7.6427,7.8565 7.6443,7.8699C7.6453,7.8784 7.6459,7.8821 7.6475,7.8896C7.6485,7.896 7.6501,7.9029 7.6496,7.9104C7.6491,7.9248 7.6427,7.9408 7.6373,7.9531C7.6427,7.9499 7.6491,7.9467 7.6576,7.9445C7.6848,7.9403 7.7056,7.9269 7.7141,7.9195C7.7264,7.9099 7.7424,7.8869 7.7424,7.8869L7.7547,7.8917C7.7531,7.9019 7.7504,7.9264 7.7547,7.936C7.7573,7.9456 7.7611,7.968 7.7611,7.9819C7.7675,7.9776 7.7744,7.9707 7.7813,7.9685C7.7893,7.9653 7.8048,7.9563 7.8096,7.9456C7.8123,7.9419 7.8176,7.9237 7.8197,7.9141L7.8331,7.9152C7.8331,7.9152 7.8363,7.9429 7.8453,7.9557C7.8512,7.9653 7.8576,7.984 7.8635,7.9995C7.8672,7.9899 7.8725,7.9792 7.8779,7.9723C7.8949,7.9525 7.8997,7.944 7.9003,7.9397C7.9013,7.9323 7.8987,7.9189 7.8976,7.9147L7.9099,7.9083L7.9232,7.9397L7.9136,7.9429C7.9109,7.9525 7.9035,7.9648 7.888,7.9813C7.8795,7.9899 7.8709,8.0139 7.8688,8.0187L7.8624,8.0395L7.8565,8.0187C7.8523,8.0064 7.8411,7.9739 7.8325,7.9632C7.8299,7.9557 7.8261,7.9509 7.8245,7.9424C7.8235,7.9467 7.8219,7.952 7.8197,7.952C7.8133,7.9643 7.7957,7.9749 7.7883,7.9787C7.7755,7.9856 7.7605,7.9989 7.7595,8L7.7584,8.0011C7.7536,8.0064 7.7381,8.0272 7.7195,8.0373C7.7077,8.0448 7.6725,8.0635 7.6709,8.0645Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2976,8.0123C7.2976,8.0123 7.2832,7.9957 7.2587,8.0027C7.2341,8.0059 7.2171,8.032 7.2171,8.032C7.2171,8.032 7.2379,8.0277 7.2507,8.0309C7.2629,8.032 7.2731,8.0443 7.2731,8.0443C7.2731,8.0443 7.2837,8.0357 7.2885,8.0309C7.2912,8.0272 7.2976,8.0123 7.2976,8.0123" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2709,8.056L7.2667,8.0507C7.2667,8.0507 7.2597,8.04 7.2501,8.0384C7.2411,8.0352 7.2197,8.0405 7.2197,8.0405L7.2043,8.0448L7.2123,8.0315C7.2133,8.0299 7.2299,8 7.2571,7.9952C7.2853,7.9909 7.3019,8.0075 7.3029,8.0075L7.3136,8.0187L7.3013,8.0187C7.2997,8.0229 7.2949,8.0309 7.2923,8.0341C7.288,8.0405 7.2779,8.0507 7.2757,8.0528L7.2709,8.056ZM7.2427,8.024C7.2464,8.024 7.2501,8.024 7.2528,8.0251C7.2613,8.0283 7.2688,8.0325 7.2731,8.0373C7.2757,8.032 7.2805,8.0293 7.2821,8.0277C7.2843,8.0245 7.288,8.0181 7.2896,8.0155C7.2853,8.0091 7.2747,8.0053 7.2603,8.0069C7.2485,8.0091 7.2389,8.0181 7.2325,8.0245C7.2357,8.024 7.2395,8.024 7.2427,8.024Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2693,8.1136C7.2693,8.1136 7.2475,8.1072 7.2299,8.1243C7.2123,8.1397 7.2101,8.1659 7.2101,8.1659C7.2101,8.1659 7.2288,8.1536 7.2416,8.1536C7.2544,8.1563 7.2715,8.1643 7.2715,8.1643C7.2715,8.1643 7.2741,8.1456 7.2757,8.1413C7.2779,8.128 7.2693,8.1136 7.2693,8.1136" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2037,8.1813L7.2037,8.1659C7.2037,8.1659 7.2053,8.1333 7.2256,8.1189C7.2395,8.1077 7.2549,8.1067 7.2629,8.1067C7.2672,8.1067 7.2693,8.1067 7.2693,8.1067L7.2725,8.1077L7.2752,8.1088C7.2752,8.112 7.2848,8.1285 7.2816,8.1424C7.2805,8.1451 7.2773,8.1648 7.2773,8.1648L7.2752,8.1712L7.2683,8.1691C7.2677,8.1691 7.2528,8.1616 7.2411,8.1595L7.2379,8.1595C7.2299,8.1595 7.2187,8.1685 7.2149,8.1701L7.2037,8.1813Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3179,8.2059C7.3179,8.2059 7.3163,8.2325 7.3291,8.248C7.3429,8.2656 7.3675,8.2688 7.3675,8.2688C7.3675,8.2688 7.36,8.2512 7.3579,8.2405C7.3568,8.2283 7.3691,8.2155 7.3691,8.2155C7.3691,8.2155 7.3568,8.2032 7.344,8.2032C7.3312,8.2032 7.3179,8.2059 7.3179,8.2059" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3787,8.2779L7.3664,8.2757C7.3664,8.2757 7.3387,8.2704 7.3243,8.2528C7.3104,8.2331 7.3109,8.2059 7.3115,8.2043L7.3115,8.1995L7.3168,8.1984C7.3179,8.1984 7.3317,8.1952 7.3445,8.1952C7.3605,8.1952 7.3728,8.2085 7.3744,8.2107L7.3792,8.2149L7.3739,8.2192C7.3712,8.2235 7.3632,8.2315 7.3643,8.24C7.3653,8.2453 7.3717,8.2597 7.3733,8.2651L7.3787,8.2779ZM7.9163,8.4155L7.9056,8.4059C7.9061,8.4053 7.9413,8.36 7.9419,8.328C7.944,8.3029 7.8976,8.2672 7.8784,8.256L7.8848,8.2448C7.8928,8.2496 7.9568,8.2907 7.9557,8.328C7.9541,8.3659 7.9173,8.4123 7.9163,8.4155Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.5664,8.4437C7.5664,8.4437 7.5493,8.4197 7.5253,8.4219C7.5008,8.4229 7.4757,8.4448 7.4757,8.4448C7.4757,8.4448 7.5067,8.4437 7.5131,8.4533C7.5216,8.4645 7.5285,8.4773 7.5285,8.4773C7.5285,8.4773 7.5419,8.4688 7.5477,8.4661C7.5541,8.4581 7.5664,8.4437 7.5664,8.4437" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.5264,8.4832L7.5232,8.4795C7.5232,8.4779 7.5163,8.4672 7.5088,8.4571C7.5067,8.4544 7.4997,8.4528 7.4853,8.4528C7.4805,8.4528 7.4773,8.4528 7.4773,8.4528L7.4571,8.4528L7.4725,8.4405C7.4725,8.4405 7.4987,8.4171 7.5253,8.4155L7.5253,8.4155C7.5531,8.4155 7.5707,8.4395 7.5717,8.4405L7.5755,8.4437L7.5728,8.4469C7.5701,8.4491 7.5589,8.4656 7.5525,8.4699C7.5461,8.4747 7.5323,8.4811 7.5317,8.4811L7.5264,8.4832ZM7.4971,8.4405C7.5072,8.4405 7.5157,8.4437 7.5195,8.4496C7.5237,8.456 7.5291,8.4624 7.5317,8.4672C7.5355,8.4656 7.5413,8.4613 7.544,8.4571C7.5472,8.4571 7.5536,8.4496 7.5573,8.4437C7.552,8.4395 7.5413,8.4283 7.5264,8.4283C7.5163,8.4299 7.5045,8.4336 7.4971,8.4405Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.4928,8.5397C7.4928,8.5397 7.4608,8.5323 7.4459,8.5509C7.4309,8.5653 7.4315,8.5947 7.4315,8.5947C7.4315,8.5947 7.4501,8.576 7.4677,8.5781C7.4848,8.5781 7.5035,8.5893 7.5035,8.5893C7.5035,8.5893 7.5008,8.5696 7.4992,8.5621C7.4976,8.5531 7.4928,8.5397 7.4928,8.5397" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.4256,8.6133L7.4256,8.5947C7.4256,8.5947 7.4245,8.5643 7.4416,8.5445C7.4528,8.5323 7.4699,8.5312 7.4827,8.5312C7.4891,8.5312 7.4944,8.5323 7.4944,8.5323L7.4976,8.5323L7.4992,8.5365C7.4992,8.5365 7.504,8.5531 7.5061,8.5605C7.5072,8.5691 7.5104,8.5877 7.5104,8.5877L7.5131,8.6L7.5013,8.5947C7.5013,8.5936 7.4832,8.5851 7.4672,8.5824L7.4672,8.5824C7.4549,8.5824 7.4421,8.5947 7.4368,8.6021L7.4256,8.6133ZM7.4827,8.5445C7.4752,8.5445 7.4603,8.5445 7.4507,8.5547C7.4443,8.5616 7.4416,8.5707 7.4395,8.5813C7.4475,8.576 7.4581,8.5701 7.4693,8.5701C7.4789,8.5712 7.488,8.5755 7.496,8.5787C7.4944,8.5723 7.4944,8.5675 7.4933,8.5653C7.4917,8.5579 7.4891,8.5509 7.488,8.5456C7.4864,8.5445 7.4853,8.5445 7.4827,8.5445Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.5605,8.6405C7.5605,8.6405 7.5451,8.6603 7.5568,8.6779C7.5685,8.6944 7.592,8.7029 7.592,8.7029C7.592,8.7029 7.584,8.6907 7.5883,8.6768C7.5915,8.6656 7.6107,8.6485 7.6107,8.6485L7.5605,8.6405" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6085,8.7157L7.5904,8.7083C7.5888,8.7083 7.5637,8.7008 7.5509,8.6811C7.5381,8.6603 7.5541,8.6363 7.5552,8.6341L7.5669,8.6187L7.5669,8.632L7.6251,8.6443L7.6139,8.6528C7.6064,8.6581 7.5947,8.6693 7.5936,8.6779C7.5909,8.6901 7.5968,8.6997 7.5968,8.6997L7.6085,8.7157Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9808,8.6795C7.9808,8.6795 7.9531,8.6725 7.9381,8.6821C7.9227,8.6907 7.9104,8.7296 7.9104,8.7296C7.9104,8.7296 7.9355,8.7072 7.9536,8.7115C7.9717,8.7157 7.9856,8.72 7.9856,8.72C7.9856,8.72 7.9883,8.7067 7.9856,8.6949C7.9845,8.6896 7.9808,8.6795 7.9808,8.6795" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8971,8.7493L7.904,8.728C7.9045,8.7227 7.9168,8.6869 7.9344,8.6779C7.9413,8.6715 7.9493,8.6693 7.96,8.6693C7.9717,8.6693 7.9819,8.6725 7.9819,8.6725L7.9851,8.6736L7.9867,8.6779C7.9867,8.6779 7.9915,8.6875 7.9915,8.6933C7.9941,8.7056 7.9915,8.7205 7.9915,8.7216L7.9893,8.7312L7.9819,8.728C7.9819,8.728 7.9696,8.7195 7.9515,8.7179C7.9504,8.7179 7.9504,8.7179 7.9504,8.7179C7.9376,8.7179 7.9189,8.7291 7.9136,8.7328L7.8971,8.7493ZM7.96,8.6821C7.9515,8.6821 7.9445,8.6853 7.9413,8.6896C7.9349,8.6907 7.9291,8.7029 7.9237,8.7125C7.9328,8.7072 7.9445,8.7029 7.9541,8.7045C7.9643,8.7061 7.9728,8.7083 7.9792,8.712C7.9792,8.7072 7.9792,8.7019 7.9792,8.6949C7.9792,8.6933 7.9771,8.6896 7.976,8.6853C7.9728,8.6843 7.9664,8.6821 7.96,8.6821Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9941,8.7813C7.9941,8.7813 7.9723,8.8032 7.9808,8.8197C7.9883,8.8405 8.0016,8.8571 8.0016,8.8571C8.0016,8.8571 8.0011,8.8309 8.0107,8.8235C8.0224,8.8128 8.0448,8.8101 8.0448,8.8101C8.0448,8.8101 8.0267,8.7947 8.0208,8.7931C8.0155,8.7904 7.9941,8.7813 7.9941,8.7813" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0091,8.8795L7.9963,8.8624C7.9952,8.8613 7.9819,8.8421 7.9744,8.8229C7.9653,8.8032 7.9877,8.7781 7.9888,8.7781L7.992,8.7728L7.9973,8.776C8.0027,8.7781 8.0192,8.7845 8.0224,8.7872C8.0288,8.7899 8.0432,8.8021 8.0485,8.8064L8.0597,8.816L8.0443,8.8187C8.0443,8.8187 8.024,8.8203 8.0128,8.8288C8.0101,8.8331 8.0075,8.8475 8.008,8.8581L8.0091,8.8795Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0992,8.8133C8.0992,8.8133 8.088,8.8405 8.1088,8.856C8.1291,8.8725 8.1461,8.8757 8.1461,8.8757C8.1461,8.8757 8.1312,8.8475 8.1349,8.832C8.1413,8.8187 8.1536,8.808 8.1536,8.808C8.1536,8.808 8.1285,8.8016 8.1253,8.8027C8.1216,8.8032 8.0992,8.8133 8.0992,8.8133" + android:strokeWidth="1" + android:fillColor="#DB4446" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1579,8.8821L8.1451,8.8821C8.1445,8.8821 8.1253,8.8795 8.104,8.8613C8.0816,8.8405 8.0923,8.8112 8.0933,8.8101L8.0944,8.8069L8.0965,8.8069C8.104,8.8027 8.1189,8.7947 8.1232,8.7947L8.1253,8.7947C8.1317,8.7947 8.1504,8.8032 8.1557,8.8032L8.1675,8.8075L8.1563,8.816C8.1563,8.816 8.1456,8.8235 8.1408,8.8357C8.1376,8.8453 8.1472,8.8661 8.1509,8.8709L8.1579,8.8821ZM8.104,8.8181C8.1035,8.824 8.1008,8.8405 8.1131,8.8528C8.1205,8.8571 8.128,8.8624 8.1339,8.8651C8.1296,8.8539 8.1253,8.84 8.1291,8.8309C8.1317,8.8224 8.1371,8.8171 8.1413,8.8123C8.1339,8.8091 8.128,8.8069 8.1253,8.8069C8.1243,8.8075 8.1136,8.8144 8.104,8.8181Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0224,10.6907C7.0923,10.7125 7.1285,10.7659 7.1285,10.8283C7.1285,10.9072 7.0501,10.9685 6.9493,10.9685C6.8475,10.9685 6.7659,10.9077 6.7659,10.8283C6.7659,10.7659 6.8,10.6971 6.8693,10.6933C6.8693,10.6933 6.8677,10.6864 6.8619,10.6773C6.8539,10.6688 6.84,10.6533 6.84,10.6533C6.84,10.6533 6.8661,10.6491 6.8816,10.6549C6.8971,10.6608 6.9077,10.6699 6.9077,10.6699C6.9077,10.6699 6.9157,10.6565 6.9248,10.6448C6.936,10.6325 6.9499,10.6283 6.9499,10.6283C6.9499,10.6283 6.9659,10.6405 6.9701,10.6491C6.9749,10.6576 6.9787,10.6688 6.9787,10.6688C6.9787,10.6688 6.9936,10.6565 7.0059,10.6533C7.0181,10.6459 7.0347,10.6432 7.0347,10.6432C7.0347,10.6432 7.0288,10.6571 7.0256,10.6656C7.0235,10.6741 7.0224,10.6907 7.0224,10.6907" + android:strokeWidth="1" + android:fillColor="#FFD691" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9499,10.9781C6.8416,10.9781 6.7568,10.9104 6.7568,10.8283C6.7568,10.7648 6.7915,10.6971 6.8571,10.6853C6.8571,10.6821 6.856,10.6821 6.8544,10.6805C6.8485,10.6741 6.8347,10.6592 6.8347,10.6592L6.8229,10.648L6.8384,10.6448C6.8395,10.6448 6.8507,10.6432 6.8635,10.6432C6.8731,10.6432 6.88,10.6437 6.8859,10.6448C6.8949,10.6501 6.9008,10.6533 6.9072,10.6571C6.9104,10.6528 6.9141,10.6448 6.9195,10.6405C6.9317,10.6283 6.9451,10.6197 6.9461,10.6187L6.9504,10.6155L6.9557,10.6197C6.9563,10.6197 6.9723,10.6331 6.9787,10.6437C6.9797,10.6469 6.9813,10.6523 6.9829,10.6549C6.9883,10.6512 6.9957,10.6448 7.0032,10.6437C7.0165,10.6395 7.032,10.6331 7.032,10.6331L7.048,10.6309L7.0432,10.6443C7.0432,10.6443 7.0384,10.6608 7.0357,10.6693C7.0341,10.6715 7.0325,10.6779 7.0325,10.6827C7.0987,10.7067 7.1387,10.7579 7.1387,10.8272C7.1381,10.9125 7.0565,10.9781 6.9499,10.9781ZM6.8603,10.6603C6.8629,10.6656 6.8667,10.6672 6.8693,10.6699C6.8757,10.6821 6.8789,10.6907 6.8789,10.6907L6.8816,10.7019L6.8704,10.7029C6.8069,10.7061 6.7749,10.768 6.7749,10.8277C6.7749,10.9019 6.8507,10.9568 6.9493,10.9568C7.0464,10.9568 7.1189,10.9024 7.1189,10.8277C7.1189,10.7653 7.0827,10.7184 7.0187,10.6987L7.0123,10.6955L7.0123,10.6901C7.0123,10.688 7.0144,10.6704 7.0187,10.664C7.0187,10.6597 7.0192,10.6565 7.0203,10.6555C7.016,10.6565 7.0123,10.6565 7.0085,10.6587C6.9968,10.6651 6.9845,10.6741 6.9845,10.6752L6.9744,10.6816L6.9701,10.6693C6.9701,10.6693 6.9669,10.6597 6.9627,10.6528C6.96,10.6485 6.9536,10.6416 6.9488,10.6384C6.944,10.6405 6.9376,10.6448 6.9317,10.6517C6.9227,10.6603 6.9163,10.6736 6.9163,10.6741L6.9104,10.6832L6.9024,10.6779C6.9024,10.6779 6.8933,10.6677 6.8789,10.6635C6.8757,10.6603 6.8672,10.6592 6.8603,10.6603Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9349,11.0555C6.9349,11.0555 6.8005,10.9653 6.7413,10.9531C6.6661,10.9365 6.5829,10.9488 6.5477,10.9456C6.5477,10.9477 6.5909,10.9781 6.6096,10.9957C6.6283,11.0155 6.6901,11.0528 6.7259,11.0624C6.8341,11.0907 6.9349,11.0555 6.9349,11.0555" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8139,11.0811L6.8139,11.0811C6.7819,11.0811 6.7509,11.0779 6.7227,11.0699C6.688,11.0613 6.6229,11.024 6.6032,11.0032C6.5883,10.9909 6.5579,10.9659 6.5472,10.9573C6.5435,10.9557 6.5419,10.9531 6.5419,10.9531L6.5259,10.9376L6.5483,10.9397C6.5584,10.9408 6.5733,10.9397 6.592,10.9376C6.6107,10.9365 6.6309,10.9344 6.6533,10.9344C6.6885,10.9344 6.7173,10.9387 6.744,10.944C6.8032,10.9563 6.9344,11.0443 6.9392,11.0469L6.9541,11.0576L6.9381,11.0651C6.9349,11.0656 6.8843,11.0811 6.8139,11.0811ZM6.5728,10.9563C6.5872,10.9659 6.6043,10.9808 6.616,10.9904C6.632,11.0069 6.6933,11.0448 6.7275,11.0528C6.7541,11.0592 6.784,11.0651 6.8144,11.0651C6.8576,11.0651 6.8939,11.0565 6.9136,11.0528C6.8763,11.0277 6.7851,10.9696 6.7403,10.96C6.7157,10.9552 6.6869,10.9525 6.6533,10.9525C6.6315,10.9525 6.6107,10.9525 6.592,10.9541C6.5851,10.9557 6.5787,10.9557 6.5728,10.9563Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9728,11.0635C6.9728,11.0635 7.0597,10.9728 7.1499,10.9605C7.2571,10.9451 7.3259,10.9701 7.3669,10.9808C7.3685,10.9808 7.3328,10.9957 7.3141,11.0096C7.2955,11.0219 7.2475,11.064 7.1744,11.0656C7.1008,11.0656 7.0192,11.056 7.0069,11.0571C6.9925,11.0592 6.9728,11.0635 6.9728,11.0635" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9483,11.0773L6.9664,11.0576C6.9696,11.0533 7.056,10.9659 7.1477,10.9536C7.1712,10.9493 7.1941,10.9472 7.2165,10.9472C7.2789,10.9472 7.3259,10.9595 7.3568,10.9691L7.3749,10.9733L7.3755,10.9787C7.3776,10.9851 7.3728,10.9893 7.3648,10.9925C7.3536,10.9963 7.3317,11.0075 7.3195,11.0176L7.3131,11.0213C7.2907,11.0389 7.2432,11.0715 7.1744,11.0725L7.1616,11.0725C7.1227,11.0725 7.0821,11.0704 7.0533,11.0693C7.0304,11.0677 7.0133,11.0661 7.0069,11.0677C6.9947,11.0693 6.9744,11.0704 6.9744,11.0704L6.9483,11.0773ZM7.0128,11.0491C7.0213,11.0491 7.0352,11.0501 7.0539,11.0523C7.0827,11.0533 7.1227,11.056 7.1616,11.056L7.1739,11.056C7.2379,11.0549 7.2816,11.0224 7.3029,11.0075L7.3104,11.0032C7.3195,10.9947 7.3323,10.9909 7.3435,10.9824C7.3125,10.9749 7.2709,10.9659 7.2165,10.9659C7.1941,10.9659 7.1728,10.9659 7.1504,10.9701C7.0896,10.9787 7.0293,11.0245 6.9995,11.0512C7.0005,11.0501 7.0037,11.0501 7.0043,11.0501C7.0069,11.0496 7.0096,11.0491 7.0128,11.0491Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9477,10.9531C6.9131,10.9195 6.8917,10.8768 6.8917,10.8283C6.8917,10.7781 6.9131,10.7323 6.9477,10.7024C6.9813,10.7328 7.0016,10.7787 7.0016,10.8283C7.0016,10.8773 6.9808,10.92 6.9477,10.9531" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9477,10.9659L6.9413,10.9573C6.904,10.9248 6.8832,10.8784 6.8832,10.8283C6.8832,10.7781 6.904,10.728 6.9413,10.6949L6.9477,10.6907L6.9541,10.6949C6.9899,10.7285 7.0101,10.7781 7.0101,10.8283C7.0101,10.8784 6.9893,10.9253 6.9541,10.9573L6.9477,10.9659ZM6.9477,10.7147C6.9173,10.744 6.9008,10.7824 6.9008,10.8283C6.9008,10.8699 6.9168,10.9083 6.9477,10.9408C6.976,10.9083 6.9931,10.8688 6.9931,10.8283C6.9931,10.7824 6.976,10.744 6.9477,10.7147Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9131,11.1355C6.9131,11.1355 6.9339,11.0832 6.9355,11.0405C6.9381,11.0032 6.9307,10.9669 6.9307,10.9669C6.9307,10.9669 6.9419,10.9669 6.9477,10.9669C6.9536,10.9669 6.9568,10.9669 6.9568,10.9669C6.9568,10.9669 6.9707,11.0059 6.9707,11.0405C6.9707,11.0752 6.9643,11.1195 6.9643,11.1195C6.9643,11.1195 6.9456,11.1227 6.9397,11.1269C6.9333,11.128 6.9131,11.1355 6.9131,11.1355" + android:strokeWidth="1" + android:fillColor="#058E6E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8976,11.1509L6.904,11.1323C6.904,11.1323 6.9253,11.0821 6.9264,11.0405C6.9285,11.0048 6.9227,10.9685 6.9227,10.9685L6.9195,10.9573L6.9632,10.9573L6.9664,10.9659C6.9664,10.9659 6.9792,11.0059 6.9792,11.0411C6.9792,11.0752 6.9733,11.12 6.9728,11.12L6.9728,11.1285L6.9664,11.1285C6.9589,11.1312 6.9477,11.1328 6.944,11.1328C6.9376,11.1381 6.9179,11.144 6.9168,11.1451L6.8976,11.1509ZM6.9413,10.976C6.9424,10.9904 6.9451,11.0155 6.944,11.0405C6.9429,11.0699 6.9339,11.1029 6.9269,11.1195C6.9312,11.1195 6.9339,11.1184 6.9349,11.1184C6.9408,11.1152 6.9499,11.1152 6.9563,11.1131C6.9579,11.0987 6.9616,11.0651 6.9616,11.04C6.9616,11.0149 6.9531,10.9877 6.9499,10.9755L6.9413,10.9755L6.9413,10.976Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6155,6.2645C8.6155,6.2437 8.6315,6.2283 8.6523,6.2283C8.6725,6.2283 8.6885,6.2437 8.6885,6.2645C8.6885,6.2821 8.6725,6.2981 8.6523,6.2981C8.632,6.2981 8.6155,6.2821 8.6155,6.2645" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6528,6.3045C8.6293,6.3045 8.6091,6.2864 8.6091,6.2645C8.6091,6.2405 8.6293,6.2208 8.6528,6.2208C8.6763,6.2208 8.696,6.2405 8.696,6.2645C8.696,6.2864 8.6763,6.3045 8.6528,6.3045ZM8.6528,6.2341C8.6357,6.2341 8.6229,6.2464 8.6229,6.2645C8.6229,6.2779 8.6352,6.2923 8.6528,6.2923C8.6693,6.2923 8.6827,6.2784 8.6827,6.2645C8.6821,6.2469 8.6693,6.2341 8.6528,6.2341Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6667,6.1728C8.6667,6.1531 8.6816,6.1392 8.704,6.1392C8.7227,6.1392 8.7403,6.1525 8.7403,6.1728C8.7403,6.1931 8.7227,6.2069 8.704,6.2069C8.6816,6.2075 8.6667,6.1931 8.6667,6.1728" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.704,6.2155C8.6789,6.2155 8.6603,6.1947 8.6603,6.1728C8.6603,6.1509 8.6789,6.1323 8.704,6.1323C8.7269,6.1323 8.7467,6.1509 8.7467,6.1728C8.7467,6.1947 8.7269,6.2155 8.704,6.2155ZM8.704,6.1445C8.6859,6.1445 8.6725,6.1568 8.6725,6.1728C8.6725,6.1904 8.6848,6.2032 8.704,6.2032C8.7189,6.2032 8.7333,6.1909 8.7333,6.1728C8.7333,6.1573 8.7195,6.1445 8.704,6.1445Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.7003,6.0699C8.7003,6.0512 8.7168,6.0336 8.7376,6.0336C8.7568,6.0336 8.7744,6.0512 8.7744,6.0699C8.7744,6.0907 8.7568,6.1045 8.7376,6.1045C8.7168,6.1045 8.7003,6.0907 8.7003,6.0699" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.7376,6.1115C8.7131,6.1115 8.6933,6.0923 8.6933,6.0699C8.6933,6.0448 8.7131,6.0283 8.7376,6.0283C8.7611,6.0283 8.7813,6.0448 8.7813,6.0699C8.7808,6.0923 8.7611,6.1115 8.7376,6.1115ZM8.7376,6.0405C8.72,6.0405 8.7067,6.0528 8.7067,6.0699C8.7067,6.0843 8.7195,6.0981 8.7376,6.0981C8.7541,6.0981 8.7675,6.0848 8.7675,6.0699C8.7675,6.0533 8.7541,6.0405 8.7376,6.0405Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.704,5.9573C8.704,5.9397 8.72,5.9221 8.7413,5.9221C8.7616,5.9221 8.7787,5.9397 8.7787,5.9573C8.7787,5.9781 8.7611,5.9931 8.7413,5.9931C8.7205,5.9931 8.704,5.9781 8.704,5.9573" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.7419,6C8.7168,6 8.6981,5.9813 8.6981,5.9573C8.6981,5.9333 8.7168,5.9157 8.7419,5.9157C8.7659,5.9157 8.7856,5.9333 8.7856,5.9573C8.7856,5.9813 8.7659,6 8.7419,6ZM8.7419,5.9296C8.7248,5.9296 8.7104,5.9419 8.7104,5.9573C8.7104,5.9728 8.7243,5.9867 8.7419,5.9867C8.7573,5.9867 8.7723,5.9733 8.7723,5.9573C8.7723,5.9424 8.7573,5.9296 8.7419,5.9296Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6763,5.8469C8.6763,5.8283 8.6939,5.8133 8.7131,5.8133C8.7344,5.8133 8.7504,5.8277 8.7504,5.8469C8.7504,5.8672 8.7344,5.8821 8.7131,5.8821C8.6939,5.8821 8.6763,5.8672 8.6763,5.8469" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.7131,5.8907C8.6896,5.8907 8.6693,5.8699 8.6693,5.8469C8.6693,5.8251 8.6896,5.8064 8.7131,5.8064C8.7381,5.8064 8.7568,5.8251 8.7568,5.8469C8.7568,5.8699 8.7381,5.8907 8.7131,5.8907ZM8.7131,5.8197C8.6981,5.8197 8.6827,5.832 8.6827,5.8469C8.6827,5.8645 8.6976,5.8784 8.7131,5.8784C8.7307,5.8784 8.7445,5.8651 8.7445,5.8469C8.7445,5.8325 8.7307,5.8197 8.7131,5.8197Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6192,5.7477C8.6192,5.728 8.6357,5.7136 8.6565,5.7136C8.6768,5.7136 8.6939,5.728 8.6939,5.7477C8.6939,5.768 8.6768,5.7819 8.6565,5.7819C8.6357,5.7824 8.6192,5.768 8.6192,5.7477" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.6565,5.7904C8.6315,5.7904 8.6128,5.7696 8.6128,5.7477C8.6128,5.7259 8.6315,5.7061 8.6565,5.7061C8.6805,5.7061 8.7003,5.7259 8.7003,5.7477C8.7003,5.7696 8.6805,5.7904 8.6565,5.7904ZM8.6565,5.72C8.6395,5.72 8.6251,5.7323 8.6251,5.7483C8.6251,5.7659 8.6389,5.7787 8.6565,5.7787C8.6725,5.7787 8.6875,5.7664 8.6875,5.7483C8.6875,5.7323 8.6731,5.72 8.6565,5.72Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.544,5.6656C8.544,5.6459 8.5605,5.6315 8.5808,5.6315C8.6005,5.6315 8.6171,5.6459 8.6171,5.6656C8.6171,5.6853 8.6005,5.7029 8.5808,5.7029C8.5605,5.7029 8.544,5.6853 8.544,5.6656" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.5808,5.7072C8.5568,5.7072 8.5371,5.6907 8.5371,5.6656C8.5371,5.6437 8.5568,5.6251 8.5808,5.6251C8.6043,5.6251 8.6245,5.6437 8.6245,5.6656C8.6245,5.6907 8.6043,5.7072 8.5808,5.7072ZM8.5808,5.6384C8.5632,5.6384 8.5504,5.6507 8.5504,5.6656C8.5504,5.6821 8.5627,5.6949 8.5808,5.6949C8.5979,5.6949 8.6107,5.6827 8.6107,5.6656C8.6107,5.6512 8.5979,5.6384 8.5808,5.6384Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.4549,5.5979C8.4549,5.5781 8.472,5.5637 8.4917,5.5637C8.5131,5.5637 8.5291,5.5781 8.5291,5.5979C8.5291,5.6171 8.5131,5.632 8.4917,5.632C8.472,5.6325 8.4549,5.6171 8.4549,5.5979" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.4917,5.6405C8.4683,5.6405 8.448,5.6197 8.448,5.5979C8.448,5.576 8.4683,5.5563 8.4917,5.5563C8.5168,5.5563 8.5355,5.576 8.5355,5.5979C8.5355,5.6197 8.5168,5.6405 8.4917,5.6405ZM8.4917,5.5696C8.4757,5.5696 8.4613,5.5819 8.4613,5.5979C8.4613,5.6155 8.4752,5.6283 8.4917,5.6283C8.5093,5.6283 8.5232,5.616 8.5232,5.5979C8.5227,5.5824 8.5093,5.5696 8.4917,5.5696Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.3493,5.5424C8.3493,5.5221 8.3664,5.5077 8.3861,5.5077C8.4064,5.5077 8.4229,5.5221 8.4229,5.5424C8.4229,5.5621 8.4064,5.5781 8.3861,5.5781C8.3669,5.5781 8.3493,5.5621 8.3493,5.5424" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.3867,5.5824C8.3632,5.5824 8.3429,5.5659 8.3429,5.5424C8.3429,5.52 8.3632,5.5024 8.3867,5.5024C8.4107,5.5024 8.4304,5.52 8.4304,5.5424C8.4304,5.5659 8.4107,5.5824 8.3867,5.5824ZM8.3867,5.5157C8.3696,5.5157 8.3563,5.528 8.3563,5.5424C8.3563,5.5573 8.3691,5.5701 8.3867,5.5701C8.4043,5.5701 8.4171,5.5579 8.4171,5.5424C8.4165,5.528 8.4043,5.5157 8.3867,5.5157Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.2395,5.5029C8.2395,5.4821 8.2565,5.4683 8.2763,5.4683C8.2976,5.4683 8.3131,5.4821 8.3131,5.5029C8.3131,5.5205 8.2976,5.5381 8.2763,5.5381C8.2565,5.5387 8.2395,5.5211 8.2395,5.5029" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.2768,5.5445C8.2533,5.5445 8.2331,5.5269 8.2331,5.5029C8.2331,5.4795 8.2533,5.4603 8.2768,5.4603C8.3008,5.4603 8.3205,5.4795 8.3205,5.5029C8.3205,5.5269 8.3003,5.5445 8.2768,5.5445ZM8.2768,5.4741C8.2603,5.4741 8.2464,5.4875 8.2464,5.5035C8.2464,5.5195 8.2603,5.5317 8.2768,5.5317C8.2944,5.5317 8.3072,5.5195 8.3072,5.5035C8.3072,5.4875 8.2944,5.4741 8.2768,5.4741Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1168,5.4811C8.1168,5.4613 8.1339,5.4448 8.1541,5.4448C8.176,5.4448 8.1915,5.4613 8.1915,5.4811C8.1915,5.5008 8.1755,5.5152 8.1541,5.5152C8.1339,5.5157 8.1168,5.5008 8.1168,5.4811" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1541,5.5221C8.1301,5.5221 8.1104,5.5035 8.1104,5.4816C8.1104,5.4576 8.1301,5.4411 8.1541,5.4411C8.1792,5.4411 8.1979,5.4576 8.1979,5.4816C8.1979,5.5029 8.1787,5.5221 8.1541,5.5221ZM8.1541,5.4533C8.1381,5.4533 8.1237,5.4656 8.1237,5.4816C8.1237,5.4949 8.1381,5.5088 8.1541,5.5088C8.1712,5.5088 8.1856,5.4955 8.1856,5.4816C8.1851,5.4656 8.1712,5.4533 8.1541,5.4533Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0005,5.4752C8.0005,5.456 8.0171,5.4411 8.0379,5.4411C8.0581,5.4411 8.0752,5.456 8.0752,5.4752C8.0752,5.4939 8.0581,5.5093 8.0379,5.5093C8.0171,5.5093 8.0005,5.4939 8.0005,5.4752" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0379,5.5157C8.0133,5.5157 7.9941,5.4971 7.9941,5.4752C7.9941,5.4533 8.0133,5.4325 8.0379,5.4325C8.0624,5.4325 8.0816,5.4533 8.0816,5.4752C8.0816,5.4971 8.0624,5.5157 8.0379,5.5157ZM8.0379,5.4448C8.0213,5.4448 8.0064,5.4571 8.0064,5.4752C8.0064,5.4907 8.0208,5.5035 8.0379,5.5035C8.0544,5.5035 8.0693,5.4912 8.0693,5.4752C8.0693,5.4571 8.0544,5.4448 8.0379,5.4448Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8869,5.4779C7.8869,5.4581 7.904,5.4437 7.9237,5.4437C7.9445,5.4437 7.9605,5.4581 7.9605,5.4779C7.9605,5.4976 7.9445,5.5152 7.9237,5.5152C7.904,5.5157 7.8869,5.4981 7.8869,5.4779" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9237,5.52C7.9003,5.52 7.88,5.5035 7.88,5.4784C7.88,5.4565 7.9003,5.4379 7.9237,5.4379C7.9477,5.4379 7.9675,5.4565 7.9675,5.4784C7.9669,5.5029 7.9477,5.52 7.9237,5.52ZM7.9237,5.4512C7.9067,5.4512 7.8933,5.4635 7.8933,5.4784C7.8933,5.4949 7.9067,5.5077 7.9237,5.5077C7.9413,5.5077 7.9541,5.4955 7.9541,5.4784C7.9541,5.4635 7.9413,5.4512 7.9237,5.4512Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7728,5.4779C7.7728,5.4581 7.7893,5.4437 7.8101,5.4437C7.8299,5.4437 7.8469,5.4581 7.8469,5.4779C7.8469,5.4976 7.8299,5.5152 7.8101,5.5152C7.7888,5.5157 7.7728,5.4981 7.7728,5.4779" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8101,5.52C7.7851,5.52 7.7664,5.5035 7.7664,5.4784C7.7664,5.4565 7.7851,5.4379 7.8101,5.4379C7.8336,5.4379 7.8539,5.4565 7.8539,5.4784C7.8539,5.5029 7.8336,5.52 7.8101,5.52ZM7.8101,5.4512C7.7931,5.4512 7.7787,5.4635 7.7787,5.4784C7.7787,5.4949 7.7925,5.5077 7.8101,5.5077C7.8261,5.5077 7.8405,5.4955 7.8405,5.4784C7.8405,5.4635 7.8261,5.4512 7.8101,5.4512Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8293,5.5781C7.8293,5.5573 7.8464,5.5408 7.8661,5.5408C7.888,5.5408 7.9035,5.5573 7.9035,5.5781C7.9035,5.5947 7.8875,5.6117 7.8661,5.6117C7.8464,5.6112 7.8293,5.5947 7.8293,5.5781" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8667,5.6187C7.8432,5.6187 7.8229,5.6 7.8229,5.5781C7.8229,5.5531 7.8432,5.5333 7.8667,5.5333C7.8917,5.5333 7.9104,5.5531 7.9104,5.5781C7.9104,5.6 7.8912,5.6187 7.8667,5.6187ZM7.8667,5.5467C7.8507,5.5467 7.8363,5.56 7.8363,5.5781C7.8363,5.592 7.8507,5.6059 7.8667,5.6059C7.8837,5.6059 7.8981,5.5925 7.8981,5.5781C7.8976,5.5605 7.8837,5.5467 7.8667,5.5467Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8533,5.6832C7.8533,5.6656 7.8693,5.6496 7.8901,5.6496C7.9104,5.6496 7.9269,5.6651 7.9269,5.6832C7.9269,5.7029 7.9099,5.7195 7.8901,5.7195C7.8693,5.72 7.8533,5.7029 7.8533,5.6832" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8901,5.7269C7.8667,5.7269 7.8464,5.7072 7.8464,5.6832C7.8464,5.6613 7.8661,5.6432 7.8901,5.6432C7.9141,5.6432 7.9339,5.6613 7.9339,5.6832C7.9339,5.7072 7.9136,5.7269 7.8901,5.7269ZM7.8901,5.656C7.8725,5.656 7.8603,5.6683 7.8603,5.6832C7.8603,5.7008 7.8725,5.7136 7.8901,5.7136C7.9067,5.7136 7.9205,5.7013 7.9205,5.6832C7.9205,5.6688 7.9067,5.656 7.8901,5.656Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8565,5.792C7.8565,5.7717 7.8731,5.7573 7.8939,5.7573C7.9147,5.7573 7.9312,5.7717 7.9312,5.792C7.9312,5.8112 7.9141,5.8277 7.8939,5.8277C7.8736,5.8283 7.8565,5.8112 7.8565,5.792" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8944,5.8325C7.8699,5.8325 7.8507,5.816 7.8507,5.7925C7.8507,5.7701 7.8699,5.7515 7.8944,5.7515C7.9189,5.7515 7.9381,5.7701 7.9381,5.7925C7.9381,5.8155 7.9189,5.8325 7.8944,5.8325ZM7.8944,5.7659C7.8779,5.7659 7.8629,5.7781 7.8629,5.7925C7.8629,5.8075 7.8773,5.8203 7.8944,5.8203C7.9109,5.8203 7.9253,5.808 7.9253,5.7925C7.9248,5.7781 7.9109,5.7659 7.8944,5.7659Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8229,5.8907C7.8229,5.8699 7.84,5.856 7.8603,5.856C7.8816,5.856 7.8976,5.8699 7.8976,5.8907C7.8976,5.9093 7.8811,5.9259 7.8603,5.9259C7.84,5.9259 7.8229,5.9093 7.8229,5.8907" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8603,5.9323C7.8363,5.9323 7.8165,5.9147 7.8165,5.8907C7.8165,5.8672 7.8363,5.8491 7.8603,5.8491C7.8853,5.8491 7.904,5.8672 7.904,5.8907C7.904,5.9147 7.8853,5.9323 7.8603,5.9323ZM7.8603,5.8619C7.8443,5.8619 7.8299,5.8747 7.8299,5.8907C7.8299,5.9067 7.8443,5.9189 7.8603,5.9189C7.8773,5.9189 7.8917,5.9067 7.8917,5.8907C7.8917,5.8747 7.8773,5.8619 7.8603,5.8619Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.76,5.9808C7.76,5.9616 7.7765,5.9451 7.7973,5.9451C7.8176,5.9451 7.8347,5.9616 7.8347,5.9808C7.8347,6 7.8176,6.0155 7.7973,6.0155C7.7771,6.0155 7.76,6 7.76,5.9808" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7979,6.0208C7.7733,6.0208 7.7541,6.0032 7.7541,5.9808C7.7541,5.9573 7.7733,5.9397 7.7979,5.9397C7.8219,5.9397 7.8416,5.9573 7.8416,5.9808C7.8416,6.0032 7.8219,6.0208 7.7979,6.0208ZM7.7979,5.9531C7.7808,5.9531 7.7664,5.9653 7.7664,5.9808C7.7664,5.9947 7.7808,6.0075 7.7979,6.0075C7.8139,6.0075 7.8283,5.9952 7.8283,5.9808C7.8283,5.9659 7.8139,5.9531 7.7979,5.9531Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6859,5.4107C7.6859,5.3909 7.7029,5.3771 7.7227,5.3771C7.744,5.3771 7.76,5.3904 7.76,5.4107C7.76,5.4309 7.744,5.4448 7.7227,5.4448C7.7029,5.4448 7.6859,5.4309 7.6859,5.4107" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7227,5.4533C7.6992,5.4533 7.6789,5.4325 7.6789,5.4107C7.6789,5.3888 7.6992,5.3691 7.7227,5.3691C7.7472,5.3691 7.7664,5.3888 7.7664,5.4107C7.7664,5.4325 7.7477,5.4533 7.7227,5.4533ZM7.7227,5.3824C7.7067,5.3824 7.6928,5.3947 7.6928,5.4107C7.6928,5.4283 7.7067,5.4411 7.7227,5.4411C7.7403,5.4411 7.7536,5.4288 7.7536,5.4107C7.7541,5.3947 7.7408,5.3824 7.7227,5.3824Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.5851,5.3547C7.5851,5.3344 7.6011,5.32 7.6224,5.32C7.6421,5.32 7.6592,5.3344 7.6592,5.3547C7.6592,5.3739 7.6421,5.3904 7.6224,5.3904C7.6011,5.3904 7.5851,5.3739 7.5851,5.3547" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6224,5.3947C7.5973,5.3947 7.5787,5.3781 7.5787,5.3547C7.5787,5.3312 7.5973,5.3136 7.6224,5.3136C7.6459,5.3136 7.6661,5.3312 7.6661,5.3547C7.6661,5.3781 7.6459,5.3947 7.6224,5.3947ZM7.6224,5.3269C7.6048,5.3269 7.5909,5.3403 7.5909,5.3547C7.5909,5.3696 7.6043,5.3824 7.6224,5.3824C7.6379,5.3824 7.6523,5.3701 7.6523,5.3547C7.6523,5.3408 7.6379,5.3269 7.6224,5.3269Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.4725,5.32C7.4725,5.3035 7.4896,5.2859 7.5099,5.2859C7.5307,5.2859 7.5472,5.3035 7.5472,5.32C7.5472,5.3408 7.5307,5.3563 7.5099,5.3563C7.4896,5.3563 7.4725,5.3408 7.4725,5.32" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.5104,5.3637C7.4864,5.3637 7.4667,5.344 7.4667,5.32C7.4667,5.2971 7.4864,5.28 7.5104,5.28C7.5355,5.28 7.5541,5.2971 7.5541,5.32C7.5541,5.344 7.5349,5.3637 7.5104,5.3637ZM7.5104,5.2933C7.4944,5.2933 7.4795,5.3056 7.4795,5.32C7.4795,5.3365 7.4944,5.3504 7.5104,5.3504C7.5275,5.3504 7.5419,5.3371 7.5419,5.32C7.5413,5.3056 7.5269,5.2933 7.5104,5.2933Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3568,5.3019C7.3568,5.2811 7.3733,5.2656 7.3941,5.2656C7.4144,5.2656 7.4315,5.2811 7.4315,5.3019C7.4315,5.3195 7.4144,5.3355 7.3941,5.3355C7.3733,5.3355 7.3568,5.32 7.3568,5.3019" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3941,5.3435C7.3691,5.3435 7.3504,5.3243 7.3504,5.3024C7.3504,5.2784 7.3691,5.2587 7.3941,5.2587C7.4181,5.2587 7.4379,5.2784 7.4379,5.3024C7.4379,5.3237 7.4181,5.3435 7.3941,5.3435ZM7.3941,5.272C7.3771,5.272 7.3627,5.2843 7.3627,5.3024C7.3627,5.3157 7.3771,5.3301 7.3941,5.3301C7.4101,5.3301 7.4245,5.3163 7.4245,5.3024C7.4245,5.2843 7.4107,5.272 7.3941,5.272Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2437,5.3029C7.2437,5.2821 7.2603,5.2683 7.2805,5.2683C7.3008,5.2683 7.3173,5.2821 7.3173,5.3029C7.3173,5.3216 7.3008,5.3381 7.2805,5.3381C7.2603,5.3387 7.2437,5.3221 7.2437,5.3029" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.28,5.3445C7.2565,5.3445 7.2363,5.3269 7.2363,5.3029C7.2363,5.2795 7.2565,5.2613 7.28,5.2613C7.3035,5.2613 7.3237,5.2795 7.3237,5.3029C7.3237,5.3269 7.304,5.3445 7.28,5.3445ZM7.28,5.2747C7.2629,5.2747 7.2501,5.2875 7.2501,5.3035C7.2501,5.3195 7.2624,5.3317 7.28,5.3317C7.2976,5.3317 7.3104,5.3195 7.3104,5.3035C7.3104,5.2875 7.2976,5.2747 7.28,5.2747Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1253,5.3221C7.1253,5.3035 7.1413,5.2885 7.1621,5.2885C7.1819,5.2885 7.1989,5.3029 7.1989,5.3221C7.1989,5.3424 7.1819,5.3573 7.1621,5.3573C7.1413,5.3573 7.1253,5.3424 7.1253,5.3221" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1621,5.3659C7.1381,5.3659 7.1184,5.3451 7.1184,5.3221C7.1184,5.3003 7.1381,5.2816 7.1621,5.2816C7.1856,5.2816 7.2059,5.3003 7.2059,5.3221C7.2059,5.3445 7.1856,5.3659 7.1621,5.3659ZM7.1621,5.2949C7.1445,5.2949 7.1317,5.3072 7.1317,5.3221C7.1317,5.3397 7.1445,5.3536 7.1621,5.3536C7.1787,5.3536 7.192,5.3403 7.192,5.3221C7.192,5.3072 7.1787,5.2949 7.1621,5.2949Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0155,5.3605C7.0155,5.3408 7.0315,5.3264 7.0523,5.3264C7.0725,5.3264 7.0891,5.3408 7.0891,5.3605C7.0891,5.3797 7.0725,5.3947 7.0523,5.3947C7.032,5.3947 7.0155,5.3797 7.0155,5.3605" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0523,5.4032C7.0288,5.4032 7.0085,5.3824 7.0085,5.3605C7.0085,5.3387 7.0288,5.3189 7.0523,5.3189C7.0757,5.3189 7.096,5.3387 7.096,5.3605C7.096,5.3824 7.0763,5.4032 7.0523,5.4032ZM7.0523,5.3323C7.0352,5.3323 7.0224,5.3445 7.0224,5.3605C7.0224,5.3781 7.0347,5.3909 7.0523,5.3909C7.0693,5.3909 7.0827,5.3787 7.0827,5.3605C7.0827,5.3445 7.0693,5.3323 7.0523,5.3323Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.1595,6.2645C5.1595,6.2437 5.1755,6.2283 5.1963,6.2283C5.216,6.2283 5.2325,6.2437 5.2325,6.2645C5.2325,6.2821 5.216,6.2981 5.1963,6.2981C5.1755,6.2981 5.1595,6.2821 5.1595,6.2645" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.1963,6.3045C5.1723,6.3045 5.1525,6.2864 5.1525,6.2645C5.1525,6.2405 5.1723,6.2208 5.1963,6.2208C5.2197,6.2208 5.2395,6.2405 5.2395,6.2645C5.2395,6.2864 5.2197,6.3045 5.1963,6.3045ZM5.1963,6.2341C5.1787,6.2341 5.1659,6.2464 5.1659,6.2645C5.1659,6.2779 5.1781,6.2923 5.1963,6.2923C5.2128,6.2923 5.2261,6.2784 5.2261,6.2645C5.2261,6.2469 5.2128,6.2341 5.1963,6.2341Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.1083,6.1728C5.1083,6.1531 5.1253,6.1392 5.1445,6.1392C5.1659,6.1392 5.1813,6.1525 5.1813,6.1728C5.1813,6.1931 5.1659,6.2069 5.1445,6.2069C5.1253,6.2075 5.1083,6.1931 5.1083,6.1728" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.1445,6.2155C5.1211,6.2155 5.1013,6.1947 5.1013,6.1728C5.1013,6.1509 5.1211,6.1323 5.1445,6.1323C5.1691,6.1323 5.1888,6.1509 5.1888,6.1728C5.1888,6.1947 5.1691,6.2155 5.1445,6.2155ZM5.1445,6.1445C5.1285,6.1445 5.1147,6.1568 5.1147,6.1728C5.1147,6.1904 5.128,6.2032 5.1445,6.2032C5.1627,6.2032 5.1755,6.1909 5.1755,6.1728C5.1755,6.1573 5.1632,6.1445 5.1445,6.1445Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.0752,6.0699C5.0752,6.0512 5.0912,6.0336 5.112,6.0336C5.1317,6.0336 5.1483,6.0512 5.1483,6.0699C5.1483,6.0907 5.1317,6.1045 5.112,6.1045C5.0912,6.1045 5.0752,6.0907 5.0752,6.0699" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.112,6.1115C5.088,6.1115 5.0677,6.0923 5.0677,6.0699C5.0677,6.0448 5.088,6.0283 5.112,6.0283C5.1355,6.0283 5.1552,6.0448 5.1552,6.0699C5.1552,6.0923 5.1355,6.1115 5.112,6.1115ZM5.112,6.0405C5.0944,6.0405 5.0816,6.0528 5.0816,6.0699C5.0816,6.0843 5.0939,6.0981 5.112,6.0981C5.1285,6.0981 5.1419,6.0848 5.1419,6.0699C5.1419,6.0533 5.1285,6.0405 5.112,6.0405Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.0699,5.9573C5.0699,5.9397 5.0869,5.9221 5.1067,5.9221C5.128,5.9221 5.144,5.9397 5.144,5.9573C5.144,5.9781 5.128,5.9931 5.1067,5.9931C5.0869,5.9931 5.0699,5.9781 5.0699,5.9573" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.1067,6C5.0832,6 5.0629,5.9813 5.0629,5.9573C5.0629,5.9333 5.0832,5.9157 5.1067,5.9157C5.1317,5.9157 5.1504,5.9333 5.1504,5.9573C5.1504,5.9813 5.1317,6 5.1067,6ZM5.1067,5.9296C5.0912,5.9296 5.0763,5.9419 5.0763,5.9573C5.0763,5.9728 5.0907,5.9867 5.1067,5.9867C5.1243,5.9867 5.1381,5.9733 5.1381,5.9573C5.1381,5.9424 5.1243,5.9296 5.1067,5.9296Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.0976,5.8469C5.0976,5.8283 5.1141,5.8133 5.1349,5.8133C5.1552,5.8133 5.1723,5.8277 5.1723,5.8469C5.1723,5.8672 5.1552,5.8821 5.1349,5.8821C5.1141,5.8821 5.0976,5.8672 5.0976,5.8469" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.1349,5.8907C5.1104,5.8907 5.0912,5.8699 5.0912,5.8469C5.0912,5.8251 5.1104,5.8064 5.1349,5.8064C5.1595,5.8064 5.1787,5.8251 5.1787,5.8469C5.1787,5.8699 5.1595,5.8907 5.1349,5.8907ZM5.1349,5.8197C5.1184,5.8197 5.1035,5.832 5.1035,5.8469C5.1035,5.8645 5.1179,5.8784 5.1349,5.8784C5.1509,5.8784 5.1659,5.8651 5.1659,5.8469C5.1659,5.8325 5.1509,5.8197 5.1349,5.8197Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.1541,5.7477C5.1541,5.728 5.1717,5.7136 5.1915,5.7136C5.2128,5.7136 5.2283,5.728 5.2283,5.7477C5.2283,5.768 5.2128,5.7819 5.1915,5.7819C5.1717,5.7824 5.1541,5.768 5.1541,5.7477" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.1915,5.7904C5.1675,5.7904 5.1472,5.7696 5.1472,5.7477C5.1472,5.7259 5.1675,5.7061 5.1915,5.7061C5.216,5.7061 5.2347,5.7259 5.2347,5.7477C5.2347,5.7696 5.216,5.7904 5.1915,5.7904ZM5.1915,5.72C5.1755,5.72 5.1611,5.7323 5.1611,5.7483C5.1611,5.7659 5.1749,5.7787 5.1915,5.7787C5.2085,5.7787 5.2224,5.7664 5.2224,5.7483C5.2224,5.7323 5.2091,5.72 5.1915,5.72Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.232,5.6656C5.232,5.6459 5.2475,5.6315 5.2683,5.6315C5.288,5.6315 5.3051,5.6459 5.3051,5.6656C5.3051,5.6853 5.288,5.7029 5.2683,5.7029C5.2475,5.7029 5.232,5.6853 5.232,5.6656" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.2683,5.7072C5.2443,5.7072 5.2245,5.6907 5.2245,5.6656C5.2245,5.6437 5.2443,5.6251 5.2683,5.6251C5.2917,5.6251 5.312,5.6437 5.312,5.6656C5.312,5.6907 5.2917,5.7072 5.2683,5.7072ZM5.2683,5.6384C5.2507,5.6384 5.2379,5.6507 5.2379,5.6656C5.2379,5.6821 5.2501,5.6949 5.2683,5.6949C5.2853,5.6949 5.2981,5.6827 5.2981,5.6656C5.2981,5.6512 5.2853,5.6384 5.2683,5.6384Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.3195,5.5979C5.3195,5.5781 5.336,5.5637 5.3568,5.5637C5.3771,5.5637 5.3941,5.5781 5.3941,5.5979C5.3941,5.6171 5.3765,5.632 5.3568,5.632C5.3355,5.6325 5.3195,5.6171 5.3195,5.5979" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.3568,5.6405C5.3317,5.6405 5.3131,5.6197 5.3131,5.5979C5.3131,5.576 5.3317,5.5563 5.3568,5.5563C5.3808,5.5563 5.4005,5.576 5.4005,5.5979C5.4005,5.6197 5.3808,5.6405 5.3568,5.6405ZM5.3568,5.5696C5.3397,5.5696 5.3253,5.5819 5.3253,5.5979C5.3253,5.6155 5.3392,5.6283 5.3568,5.6283C5.3728,5.6283 5.3872,5.616 5.3872,5.5979C5.3872,5.5824 5.3728,5.5696 5.3568,5.5696Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.4256,5.5424C5.4256,5.5221 5.4416,5.5077 5.4624,5.5077C5.4821,5.5077 5.4992,5.5221 5.4992,5.5424C5.4992,5.5621 5.4816,5.5781 5.4624,5.5781C5.4416,5.5781 5.4256,5.5621 5.4256,5.5424" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.4624,5.5824C5.4379,5.5824 5.4187,5.5659 5.4187,5.5424C5.4187,5.52 5.4379,5.5024 5.4624,5.5024C5.4859,5.5024 5.5061,5.52 5.5061,5.5424C5.5061,5.5659 5.4859,5.5824 5.4624,5.5824ZM5.4624,5.5157C5.4448,5.5157 5.4315,5.528 5.4315,5.5424C5.4315,5.5573 5.4448,5.5701 5.4624,5.5701C5.4789,5.5701 5.4923,5.5579 5.4923,5.5424C5.4923,5.528 5.4789,5.5157 5.4624,5.5157Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.5349,5.5029C5.5349,5.4821 5.5504,5.4683 5.5717,5.4683C5.5915,5.4683 5.6091,5.4821 5.6091,5.5029C5.6091,5.5205 5.5915,5.5381 5.5717,5.5381C5.5504,5.5387 5.5349,5.5211 5.5349,5.5029" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.5717,5.5445C5.5477,5.5445 5.5285,5.5269 5.5285,5.5029C5.5285,5.4795 5.5472,5.4603 5.5717,5.4603C5.5957,5.4603 5.6155,5.4795 5.6155,5.5029C5.6155,5.5269 5.5957,5.5445 5.5717,5.5445ZM5.5717,5.4741C5.5547,5.4741 5.5413,5.4875 5.5413,5.5035C5.5413,5.5195 5.5547,5.5317 5.5717,5.5317C5.5877,5.5317 5.6021,5.5195 5.6021,5.5035C5.6021,5.4875 5.5883,5.4741 5.5717,5.4741Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.6565,5.4811C5.6565,5.4613 5.6736,5.4448 5.6939,5.4448C5.7141,5.4448 5.7312,5.4613 5.7312,5.4811C5.7312,5.5008 5.7141,5.5152 5.6939,5.5152C5.6736,5.5152 5.6565,5.5008 5.6565,5.4811" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.6944,5.5221C5.6699,5.5221 5.6507,5.5035 5.6507,5.4816C5.6507,5.4576 5.6699,5.4411 5.6944,5.4411C5.7189,5.4411 5.7381,5.4576 5.7381,5.4816C5.7381,5.5029 5.7189,5.5221 5.6944,5.5221ZM5.6944,5.4533C5.6779,5.4533 5.6635,5.4656 5.6635,5.4816C5.6635,5.4949 5.6779,5.5088 5.6944,5.5088C5.7109,5.5088 5.7259,5.4955 5.7259,5.4816C5.7253,5.4656 5.7109,5.4533 5.6944,5.4533Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.7733,5.4752C5.7733,5.456 5.7904,5.4411 5.8101,5.4411C5.832,5.4411 5.8475,5.456 5.8475,5.4752C5.8475,5.4939 5.8315,5.5093 5.8101,5.5093C5.7904,5.5093 5.7733,5.4939 5.7733,5.4752" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.8101,5.5157C5.7867,5.5157 5.7664,5.4971 5.7664,5.4752C5.7664,5.4533 5.7867,5.4325 5.8101,5.4325C5.8352,5.4325 5.8539,5.4533 5.8539,5.4752C5.8539,5.4971 5.8352,5.5157 5.8101,5.5157ZM5.8101,5.4448C5.7941,5.4448 5.7797,5.4571 5.7797,5.4752C5.7797,5.4907 5.7941,5.5035 5.8101,5.5035C5.8277,5.5035 5.8416,5.4912 5.8416,5.4752C5.8416,5.4571 5.8277,5.4448 5.8101,5.4448Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.888,5.4779C5.888,5.4581 5.904,5.4437 5.9248,5.4437C5.9445,5.4437 5.9616,5.4581 5.9616,5.4779C5.9616,5.4976 5.9445,5.5152 5.9248,5.5152C5.904,5.5157 5.888,5.4981 5.888,5.4779" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9248,5.52C5.9003,5.52 5.8816,5.5035 5.8816,5.4784C5.8816,5.4565 5.9003,5.4379 5.9248,5.4379C5.9483,5.4379 5.9685,5.4565 5.9685,5.4784C5.9685,5.5029 5.9488,5.52 5.9248,5.52ZM5.9248,5.4512C5.9072,5.4512 5.8939,5.4635 5.8939,5.4784C5.8939,5.4949 5.9072,5.5077 5.9248,5.5077C5.9413,5.5077 5.9552,5.4955 5.9552,5.4784C5.9552,5.4635 5.9413,5.4512 5.9248,5.4512Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0016,5.4779C6.0016,5.4581 6.0187,5.4437 6.0384,5.4437C6.0603,5.4437 6.0757,5.4581 6.0757,5.4779C6.0757,5.4976 6.0603,5.5152 6.0384,5.5152C6.0187,5.5157 6.0016,5.4981 6.0016,5.4779" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0384,5.52C6.0149,5.52 5.9947,5.5035 5.9947,5.4784C5.9947,5.4565 6.0149,5.4379 6.0384,5.4379C6.0629,5.4379 6.0821,5.4565 6.0821,5.4784C6.0821,5.5029 6.0629,5.52 6.0384,5.52ZM6.0384,5.4512C6.0229,5.4512 6.0085,5.4635 6.0085,5.4784C6.0085,5.4949 6.0229,5.5077 6.0384,5.5077C6.056,5.5077 6.0693,5.4955 6.0693,5.4784C6.0693,5.4635 6.056,5.4512 6.0384,5.4512Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9445,5.5781C5.9445,5.5573 5.9616,5.5408 5.9819,5.5408C6.0021,5.5408 6.0192,5.5573 6.0192,5.5781C6.0192,5.5947 6.0021,5.6117 5.9819,5.6117C5.9616,5.6117 5.9445,5.5947 5.9445,5.5781" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9819,5.6187C5.9573,5.6187 5.9381,5.6 5.9381,5.5781C5.9381,5.5531 5.9573,5.5333 5.9819,5.5333C6.0064,5.5333 6.0256,5.5531 6.0256,5.5781C6.0256,5.6 6.0064,5.6187 5.9819,5.6187ZM5.9819,5.5467C5.9653,5.5467 5.9509,5.56 5.9509,5.5781C5.9509,5.592 5.9653,5.6059 5.9819,5.6059C5.9984,5.6059 6.0133,5.5925 6.0133,5.5781C6.0128,5.5605 5.9984,5.5467 5.9819,5.5467Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9221,5.6832C5.9221,5.6656 5.9381,5.6496 5.9589,5.6496C5.9792,5.6496 5.9957,5.6651 5.9957,5.6832C5.9957,5.7029 5.9792,5.7195 5.9589,5.7195C5.9381,5.72 5.9221,5.7029 5.9221,5.6832" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9584,5.7269C5.9349,5.7269 5.9147,5.7072 5.9147,5.6832C5.9147,5.6613 5.9349,5.6432 5.9584,5.6432C5.9819,5.6432 6.0021,5.6613 6.0021,5.6832C6.0021,5.7072 5.9819,5.7269 5.9584,5.7269ZM5.9584,5.656C5.9413,5.656 5.9285,5.6683 5.9285,5.6832C5.9285,5.7008 5.9408,5.7136 5.9584,5.7136C5.9755,5.7136 5.9883,5.7013 5.9883,5.6832C5.9888,5.6688 5.9755,5.656 5.9584,5.656Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9168,5.792C5.9168,5.7717 5.9344,5.7573 5.9541,5.7573C5.976,5.7573 5.9915,5.7717 5.9915,5.792C5.9915,5.8112 5.9755,5.8277 5.9541,5.8277C5.9339,5.8283 5.9168,5.8112 5.9168,5.792" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9541,5.8325C5.9307,5.8325 5.9104,5.816 5.9104,5.7925C5.9104,5.7701 5.9307,5.7515 5.9541,5.7515C5.9792,5.7515 5.9979,5.7701 5.9979,5.7925C5.9979,5.8155 5.9787,5.8325 5.9541,5.8325ZM5.9541,5.7659C5.9381,5.7659 5.9237,5.7781 5.9237,5.7925C5.9237,5.8075 5.9381,5.8203 5.9541,5.8203C5.9717,5.8203 5.9856,5.808 5.9856,5.7925C5.9851,5.7781 5.9712,5.7659 5.9541,5.7659Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9504,5.8907C5.9504,5.8699 5.9675,5.856 5.9877,5.856C6.0085,5.856 6.0251,5.8699 6.0251,5.8907C6.0251,5.9093 6.0085,5.9259 5.9877,5.9259C5.9675,5.9259 5.9504,5.9093 5.9504,5.8907" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9883,5.9323C5.9637,5.9323 5.9445,5.9147 5.9445,5.8907C5.9445,5.8672 5.9637,5.8491 5.9883,5.8491C6.0133,5.8491 6.032,5.8672 6.032,5.8907C6.032,5.9147 6.0128,5.9323 5.9883,5.9323ZM5.9883,5.8619C5.9717,5.8619 5.9573,5.8747 5.9573,5.8907C5.9573,5.9067 5.9717,5.9189 5.9883,5.9189C6.0048,5.9189 6.0197,5.9067 6.0197,5.8907C6.0197,5.8747 6.0048,5.8619 5.9883,5.8619Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0133,5.9808C6.0133,5.9616 6.0309,5.9451 6.0501,5.9451C6.0715,5.9451 6.0875,5.9616 6.0875,5.9808C6.0875,6 6.0715,6.0155 6.0501,6.0155C6.0309,6.0155 6.0133,6 6.0133,5.9808" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.0507,6.0208C6.0272,6.0208 6.0069,6.0032 6.0069,5.9808C6.0069,5.9573 6.0272,5.9397 6.0507,5.9397C6.0757,5.9397 6.0944,5.9573 6.0944,5.9808C6.0944,6.0032 6.0757,6.0208 6.0507,6.0208ZM6.0507,5.9531C6.0352,5.9531 6.0203,5.9653 6.0203,5.9808C6.0203,5.9947 6.0352,6.0075 6.0507,6.0075C6.0683,6.0075 6.0821,5.9952 6.0821,5.9808C6.0816,5.9659 6.0677,5.9531 6.0507,5.9531Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.088,5.4107C6.088,5.3909 6.104,5.3771 6.1253,5.3771C6.1451,5.3771 6.1627,5.3904 6.1627,5.4107C6.1627,5.4309 6.1451,5.4448 6.1253,5.4448C6.104,5.4448 6.088,5.4309 6.088,5.4107" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1253,5.4533C6.1003,5.4533 6.0816,5.4325 6.0816,5.4107C6.0816,5.3888 6.1003,5.3691 6.1253,5.3691C6.1488,5.3691 6.1691,5.3888 6.1691,5.4107C6.1691,5.4325 6.1493,5.4533 6.1253,5.4533ZM6.1253,5.3824C6.1083,5.3824 6.0939,5.3947 6.0939,5.4107C6.0939,5.4283 6.1077,5.4411 6.1253,5.4411C6.1413,5.4411 6.1557,5.4288 6.1557,5.4107C6.1557,5.3947 6.1413,5.3824 6.1253,5.3824Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1893,5.3547C6.1893,5.3344 6.2069,5.32 6.2261,5.32C6.248,5.32 6.2629,5.3344 6.2629,5.3547C6.2629,5.3739 6.2475,5.3904 6.2261,5.3904C6.2069,5.3904 6.1893,5.3739 6.1893,5.3547" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.2261,5.3947C6.2027,5.3947 6.1824,5.3781 6.1824,5.3547C6.1824,5.3312 6.2027,5.3136 6.2261,5.3136C6.2507,5.3136 6.2699,5.3312 6.2699,5.3547C6.2699,5.3781 6.2507,5.3947 6.2261,5.3947ZM6.2261,5.3269C6.2101,5.3269 6.1963,5.3403 6.1963,5.3547C6.1963,5.3696 6.2101,5.3824 6.2261,5.3824C6.2437,5.3824 6.2571,5.3701 6.2571,5.3547C6.2565,5.3408 6.2437,5.3269 6.2261,5.3269Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.3003,5.32C6.3003,5.3035 6.3173,5.2859 6.3376,5.2859C6.3584,5.2859 6.3749,5.3035 6.3749,5.32C6.3749,5.3408 6.3584,5.3563 6.3376,5.3563C6.3179,5.3563 6.3003,5.3408 6.3003,5.32" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.3381,5.3637C6.3141,5.3637 6.2944,5.344 6.2944,5.32C6.2944,5.2971 6.3141,5.28 6.3381,5.28C6.3632,5.28 6.3819,5.2971 6.3819,5.32C6.3819,5.344 6.3632,5.3637 6.3381,5.3637ZM6.3381,5.2933C6.3221,5.2933 6.3072,5.3056 6.3072,5.32C6.3072,5.3365 6.3216,5.3504 6.3381,5.3504C6.3552,5.3504 6.3696,5.3371 6.3696,5.32C6.3691,5.3056 6.3552,5.2933 6.3381,5.2933Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.4171,5.3019C6.4171,5.2811 6.4341,5.2656 6.4539,5.2656C6.4757,5.2656 6.4912,5.2811 6.4912,5.3019C6.4912,5.3195 6.4752,5.3355 6.4539,5.3355C6.4341,5.3355 6.4171,5.32 6.4171,5.3019" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.4539,5.3435C6.4304,5.3435 6.4101,5.3243 6.4101,5.3024C6.4101,5.2784 6.4304,5.2587 6.4539,5.2587C6.4789,5.2587 6.4976,5.2784 6.4976,5.3024C6.4976,5.3237 6.4789,5.3435 6.4539,5.3435ZM6.4539,5.272C6.4379,5.272 6.424,5.2843 6.424,5.3024C6.424,5.3157 6.4379,5.3301 6.4539,5.3301C6.4715,5.3301 6.4853,5.3163 6.4853,5.3024C6.4853,5.2843 6.4715,5.272 6.4539,5.272Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.5317,5.3029C6.5317,5.2821 6.5477,5.2683 6.5685,5.2683C6.5883,5.2683 6.6053,5.2821 6.6053,5.3029C6.6053,5.3216 6.5883,5.3381 6.5685,5.3381C6.5477,5.3387 6.5317,5.3221 6.5317,5.3029" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.5685,5.3445C6.5445,5.3445 6.5248,5.3269 6.5248,5.3029C6.5248,5.2795 6.544,5.2613 6.5685,5.2613C6.592,5.2613 6.6123,5.2795 6.6123,5.3029C6.6117,5.3269 6.592,5.3445 6.5685,5.3445ZM6.5685,5.2747C6.5509,5.2747 6.5381,5.2875 6.5381,5.3035C6.5381,5.3195 6.5509,5.3317 6.5685,5.3317C6.5851,5.3317 6.5984,5.3195 6.5984,5.3035C6.5984,5.2875 6.5851,5.2747 6.5685,5.2747Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.6501,5.3221C6.6501,5.3035 6.6667,5.2885 6.6869,5.2885C6.7072,5.2885 6.7237,5.3029 6.7237,5.3221C6.7237,5.3424 6.7072,5.3573 6.6869,5.3573C6.6667,5.3573 6.6501,5.3424 6.6501,5.3221" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.6869,5.3659C6.6635,5.3659 6.6432,5.3451 6.6432,5.3221C6.6432,5.3003 6.6629,5.2816 6.6869,5.2816C6.7104,5.2816 6.7307,5.3003 6.7307,5.3221C6.7301,5.3445 6.7104,5.3659 6.6869,5.3659ZM6.6869,5.2949C6.6693,5.2949 6.6571,5.3072 6.6571,5.3221C6.6571,5.3397 6.6693,5.3536 6.6869,5.3536C6.704,5.3536 6.7168,5.3413 6.7168,5.3221C6.7168,5.3072 6.704,5.2949 6.6869,5.2949Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.7595,5.3605C6.7595,5.3408 6.7755,5.3264 6.7963,5.3264C6.8165,5.3264 6.8331,5.3408 6.8331,5.3605C6.8331,5.3797 6.8165,5.3947 6.7963,5.3947C6.7755,5.3947 6.7595,5.3797 6.7595,5.3605" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.7963,5.4032C6.7728,5.4032 6.7525,5.3824 6.7525,5.3605C6.7525,5.3387 6.7728,5.3189 6.7963,5.3189C6.8197,5.3189 6.84,5.3387 6.84,5.3605C6.84,5.3824 6.8197,5.4032 6.7963,5.4032ZM6.7963,5.3323C6.7787,5.3323 6.7664,5.3445 6.7664,5.3605C6.7664,5.3781 6.7787,5.3909 6.7963,5.3909C6.8128,5.3909 6.8261,5.3787 6.8261,5.3605C6.8261,5.3445 6.8128,5.3323 6.7963,5.3323Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.8192,7.6075L5.7877,7.6075L5.7877,7.5781L5.7323,7.5781L5.7323,7.7029L5.7877,7.7029L5.7877,7.7872L5.6693,7.7872L5.6693,8.0384L5.7317,8.0384L5.7317,8.5387L5.6069,8.5387L5.6069,8.7947L6.5691,8.7947L6.5691,8.5387L6.4443,8.5387L6.4443,8.0384L6.5067,8.0384L6.5067,7.7872L6.3893,7.7872L6.3893,7.7029L6.4443,7.7029L6.4443,7.5781L6.3893,7.5781L6.3893,7.6075L6.3579,7.6075L6.3579,7.5781L6.304,7.5781L6.304,7.6075L6.264,7.6075L6.264,7.5781L6.2101,7.5781L6.2101,7.7029L6.264,7.7029L6.264,7.7872L6.1477,7.7872L6.1477,7.5152L6.2101,7.5152L6.2101,7.3893L6.1477,7.3893L6.1477,7.4197L6.1163,7.4197L6.1163,7.3893L6.0608,7.3893L6.0608,7.4197L6.0293,7.4197L6.0293,7.3893L5.9664,7.3893L5.9664,7.5152L6.0293,7.5152L6.0293,7.7872L5.9125,7.7872L5.9125,7.7029L5.9664,7.7029L5.9664,7.5781L5.9125,7.5781L5.9125,7.6075L5.8811,7.6075L5.8811,7.5781L5.8187,7.5781L5.8187,7.6075L5.8192,7.6075ZM5.6075,8.7947L6.5696,8.7947M5.6075,8.7323L6.5696,8.7323M5.6075,8.6699L6.5696,8.6699M5.6075,8.6075L6.5696,8.6075M5.6075,8.5387L6.5696,8.5387M5.7323,8.4821L6.4443,8.4821M5.7323,8.4197L6.4443,8.4197M5.7323,8.3509L6.4443,8.3509M5.7323,8.2885L6.4443,8.2885M5.7323,8.2261L6.4443,8.2261M5.7323,8.1637L6.4443,8.1637M5.7323,8.1008L6.4443,8.1008M5.6699,8.0384L6.5067,8.0384M5.6699,7.9749L6.5067,7.9749M5.6699,7.9125L6.5067,7.9125M5.6699,7.8501L6.5067,7.8501M5.7883,7.7877L6.3893,7.7877M6.0299,7.7248L6.1477,7.7248M6.0299,7.6624L6.1477,7.6624M6.0299,7.6L6.1477,7.6M6.0299,7.5376L6.1477,7.5376M5.9669,7.4571L6.2101,7.4571M5.7883,7.7248L5.9131,7.7248M5.7323,7.6448L5.9669,7.6448M5.7323,8.7947L5.7323,8.7323M5.7323,8.6699L5.7323,8.6075M5.6699,8.6699L5.6699,8.7323M5.7883,8.7323L5.7883,8.6699M5.8507,8.7947L5.8507,8.7323M5.8507,8.6699L5.8507,8.6075M5.8507,8.5387L5.8507,8.4827M5.8507,8.4197L5.8507,8.3509M5.7883,8.6075L5.7883,8.5387M5.6699,8.6075L5.6699,8.5387M5.9131,8.5387L5.9131,8.6075M5.9669,8.5387L5.9669,8.4827M5.7883,8.4197L5.7883,8.4821M5.9131,8.4197L5.9131,8.4821M6.0299,8.4197L6.0299,8.4821M5.9669,8.4197L5.9669,8.3509M6.0299,8.2885L6.0299,8.3509M6.0299,8.1637L6.0299,8.2261M5.9669,8.1008L5.9669,8.1632M6.0299,8.0384L6.0299,8.1008M5.9131,8.0384L5.9131,8.1008M5.7883,8.0384L5.7883,8.1008M5.7323,7.9749L5.7323,8.0384M5.8507,7.9749L5.8507,8.0384M5.9669,7.9749L5.9669,8.0384M6.0299,7.9125L6.0299,7.9749M5.9131,7.9125L5.9131,7.9749M5.7883,7.9125L5.7883,7.9749M5.7323,7.8501L5.7323,7.9125M5.9669,7.8501L5.9669,7.9125M5.8507,7.7248L5.8507,7.7872M6.3893,7.7248L6.264,7.7248M6.4443,7.6448L6.2101,7.6448M6.4443,8.7947L6.4443,8.7323M6.4443,8.6699L6.4443,8.6075M6.5067,8.6699L6.5067,8.7323M6.3893,8.7323L6.3893,8.6699M6.3264,8.7947L6.3264,8.7323M6.3264,8.6699L6.3264,8.6075M6.3264,8.5387L6.3264,8.4827M6.3264,8.4197L6.3264,8.3509M6.3893,8.6075L6.3893,8.5387M6.5067,8.6075L6.5067,8.5387M6.264,8.5387L6.264,8.6075M6.2101,8.5387L6.2101,8.4827M6.3893,8.4197L6.3893,8.4821M6.264,8.4197L6.264,8.4821M6.1477,8.4197L6.1477,8.4821M6.2101,8.4197L6.2101,8.3509M6.1477,8.2885L6.1477,8.3509M6.1477,8.1637L6.1477,8.2261M6.2101,8.1008L6.2101,8.1632M6.1477,8.0384L6.1477,8.1008M6.264,8.0384L6.264,8.1008M6.3893,8.0384L6.3893,8.1008M6.4443,7.9749L6.4443,8.0384M6.3264,7.9749L6.3264,8.0384M6.2101,7.9749L6.2101,8.0384M6.1477,7.9125L6.1477,7.9749M6.264,7.9125L6.264,7.9749M6.3893,7.9125L6.3893,7.9749M6.4443,7.8501L6.4443,7.9125M6.2101,7.8501L6.2101,7.9125M6.3264,7.7248L6.3264,7.7872M6.0853,8.4197L6.0853,8.3509M6.0853,8.1637L6.0853,8.1013M6.0853,8.2885L6.0853,8.2261M6.0853,8.0384L6.0853,7.9749M6.0853,7.9125L6.0853,7.8501M6.0853,7.7248L6.0853,7.6624M6.0853,7.6L6.0853,7.5376M5.7883,7.7029L5.9131,7.7029M6.0299,7.5157L6.1477,7.5157M6.264,7.7029L6.3893,7.7029" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.5771,8.8032L5.6005,8.8032L5.6005,8.5307L5.7253,8.5307L5.7253,8.0448L5.6629,8.0448L5.6629,7.7797L5.7792,7.7797L5.7792,7.7072L5.7253,7.7072L5.7253,7.5685L5.7947,7.5685L5.7947,7.6L5.8107,7.6L5.8107,7.5685L5.8885,7.5685L5.8885,7.6L5.904,7.6L5.904,7.5685L5.9749,7.5685L5.9749,7.7072L5.92,7.7072L5.92,7.7797L6.0224,7.7797L6.0224,7.52L5.96,7.52L5.96,7.3813L6.0379,7.3813L6.0379,7.4128L6.0539,7.4128L6.0539,7.3813L6.1232,7.3813L6.1232,7.4128L6.1387,7.4128L6.1387,7.3813L6.2165,7.3813L6.2165,7.52L6.1547,7.52L6.1547,7.7797L6.2565,7.7797L6.2565,7.7072L6.2011,7.7072L6.2011,7.5685L6.272,7.5685L6.272,7.6L6.2949,7.6L6.2949,7.5685L6.3659,7.5685L6.3659,7.6L6.3813,7.6L6.3813,7.5685L6.4512,7.5685L6.4512,7.7072L6.3968,7.7072L6.3968,7.7797L6.5136,7.7797L6.5136,8.0448L6.4512,8.0448L6.4512,8.5307L6.576,8.5307L6.576,8.8032L6.5771,8.8032ZM6.4517,8.7888L6.5616,8.7888L6.5616,8.7408L6.4517,8.7408L6.4517,8.7888ZM6.3349,8.7888L6.4357,8.7888L6.4357,8.7408L6.3349,8.7408L6.3349,8.7888ZM5.8576,8.7888L6.3195,8.7888L6.3195,8.7408L5.8576,8.7408L5.8576,8.7888ZM5.7413,8.7888L5.8416,8.7888L5.8416,8.7408L5.7413,8.7408L5.7413,8.7888ZM5.6165,8.7888L5.7259,8.7888L5.7259,8.7408L5.6165,8.7408L5.6165,8.7888ZM6.3979,8.7259L6.4987,8.7259L6.4987,8.6779L6.3979,8.6779L6.3979,8.7259ZM5.7947,8.7259L6.3819,8.7259L6.3819,8.6779L5.7947,8.6779L5.7947,8.7259L5.7947,8.7259ZM5.6789,8.7259L5.7792,8.7259L5.7792,8.6779L5.6789,8.6779L5.6789,8.7259ZM6.4517,8.6635L6.5616,8.6635L6.5616,8.6155L6.4517,8.6155L6.4517,8.6635ZM6.3349,8.6635L6.4357,8.6635L6.4357,8.6155L6.3349,8.6155L6.3349,8.6635ZM5.8576,8.6635L6.3195,8.6635L6.3195,8.6155L5.8576,8.6155L5.8576,8.6635ZM5.7413,8.6635L5.8416,8.6635L5.8416,8.6155L5.7413,8.6155L5.7413,8.6635ZM5.6165,8.6635L5.7259,8.6635L5.7259,8.6155L5.6165,8.6155L5.6165,8.6635ZM6.5141,8.6011L6.5611,8.6011L6.5611,8.5451L6.5141,8.5451L6.5141,8.6011ZM6.3979,8.6011L6.4987,8.6011L6.4987,8.5451L6.3979,8.5451L6.3979,8.6011ZM6.2725,8.6011L6.3819,8.6011L6.3819,8.5451L6.2725,8.5451L6.2725,8.6011ZM5.92,8.6011L6.2565,8.6011L6.2565,8.5451L5.92,8.5451L5.92,8.6011ZM5.7947,8.6011L5.9045,8.6011L5.9045,8.5451L5.7947,8.5451L5.7947,8.6011ZM5.6789,8.6011L5.7792,8.6011L5.7792,8.5451L5.6789,8.5451L5.6789,8.6011ZM5.6165,8.6011L5.6629,8.6011L5.6629,8.5451L5.6165,8.5451L5.6165,8.6011ZM6.3349,8.5307L6.4357,8.5307L6.4357,8.4907L6.3349,8.4907L6.3349,8.5307ZM6.2171,8.5307L6.3189,8.5307L6.3189,8.4907L6.2171,8.4907L6.2171,8.5307ZM5.9755,8.5307L6.2016,8.5307L6.2016,8.4907L5.9755,8.4907L5.9755,8.5307ZM5.8576,8.5307L5.96,8.5307L5.96,8.4907L5.8576,8.4907L5.8576,8.5307ZM5.7413,8.5307L5.8416,8.5307L5.8416,8.4907L5.7413,8.4907L5.7413,8.5307ZM6.2725,8.4763L6.3819,8.4763L6.3819,8.4283L6.2725,8.4283L6.2725,8.4763ZM6.1547,8.4763L6.2565,8.4763L6.2565,8.4283L6.1547,8.4283L6.1547,8.4763ZM6.0379,8.4763L6.1387,8.4763L6.1387,8.4283L6.0379,8.4283L6.0379,8.4763ZM5.92,8.4763L6.0224,8.4763L6.0224,8.4283L5.92,8.4283L5.92,8.4763ZM5.7947,8.4763L5.9045,8.4763L5.9045,8.4283L5.7947,8.4283L5.7947,8.4763ZM6.3349,8.4133L6.4357,8.4133L6.4357,8.3573L6.3349,8.3573L6.3349,8.4133ZM6.2171,8.4133L6.3189,8.4133L6.3189,8.3573L6.2171,8.3573L6.2171,8.4133ZM6.0917,8.4133L6.2016,8.4133L6.2016,8.3573L6.0917,8.3573L6.0917,8.4133ZM5.9755,8.4133L6.0763,8.4133L6.0763,8.3573L5.9755,8.3573L5.9755,8.4133ZM5.8576,8.4133L5.96,8.4133L5.96,8.3573L5.8576,8.3573L5.8576,8.4133ZM5.7413,8.4133L5.8416,8.4133L5.8416,8.3573L5.7413,8.3573L5.7413,8.4133ZM6.1547,8.3424L6.4363,8.3424L6.4363,8.2949L6.1547,8.2949L6.1547,8.3424ZM6.0379,8.3424L6.1387,8.3424L6.1387,8.2949L6.0379,8.2949L6.0379,8.3424ZM5.7413,8.3424L6.0224,8.3424L6.0224,8.2949L5.7413,8.2949L5.7413,8.3424ZM6.0917,8.2795L6.4363,8.2795L6.4363,8.232L6.0917,8.232L6.0917,8.2795ZM5.7413,8.2795L6.0763,8.2795L6.0763,8.232L5.7413,8.232L5.7413,8.2795ZM6.1547,8.2171L6.4363,8.2171L6.4363,8.1696L6.1547,8.1696L6.1547,8.2171ZM6.0379,8.2171L6.1387,8.2171L6.1387,8.1696L6.0379,8.1696L6.0379,8.2171ZM5.7413,8.2171L6.0224,8.2171L6.0224,8.1696L5.7413,8.1696L5.7413,8.2171ZM6.2171,8.1547L6.4363,8.1547L6.4363,8.1072L6.2171,8.1072L6.2171,8.1547ZM6.0917,8.1547L6.2016,8.1547L6.2016,8.1072L6.0917,8.1072L6.0917,8.1547ZM5.9755,8.1547L6.0763,8.1547L6.0763,8.1072L5.9755,8.1072L5.9755,8.1547ZM5.7413,8.1547L5.96,8.1547L5.96,8.1072L5.7413,8.1072L5.7413,8.1547ZM6.2725,8.0923L6.3819,8.0923L6.3819,8.0448L6.2725,8.0448L6.2725,8.0923ZM6.1547,8.0923L6.2565,8.0923L6.2565,8.0448L6.1547,8.0448L6.1547,8.0923ZM6.0379,8.0923L6.1387,8.0923L6.1387,8.0448L6.0379,8.0448L6.0379,8.0923ZM5.92,8.0923L6.0224,8.0923L6.0224,8.0448L5.92,8.0448L5.92,8.0923ZM5.7947,8.0923L5.9045,8.0923L5.9045,8.0448L5.7947,8.0448L5.7947,8.0923ZM6.3349,8.0299L6.4357,8.0299L6.4357,7.9824L6.3349,7.9824L6.3349,8.0299ZM6.2171,8.0299L6.3189,8.0299L6.3189,7.9824L6.2171,7.9824L6.2171,8.0299ZM6.0917,8.0299L6.2016,8.0299L6.2016,7.9824L6.0917,7.9824L6.0917,8.0299ZM5.9755,8.0299L6.0763,8.0299L6.0763,7.9824L5.9755,7.9824L5.9755,8.0299ZM5.8576,8.0299L5.96,8.0299L5.96,7.9824L5.8576,7.9824L5.8576,8.0299ZM5.7413,8.0299L5.8416,8.0299L5.8416,7.9824L5.7413,7.9824L5.7413,8.0299ZM6.3979,7.9669L6.4987,7.9669L6.4987,7.92L6.3979,7.92L6.3979,7.9669ZM6.2725,7.9669L6.3819,7.9669L6.3819,7.92L6.2725,7.92L6.2725,7.9669ZM6.1547,7.9669L6.2565,7.9669L6.2565,7.92L6.1547,7.92L6.1547,7.9669ZM6.0379,7.9669L6.1387,7.9669L6.1387,7.92L6.0379,7.92L6.0379,7.9669ZM5.92,7.9669L6.0224,7.9669L6.0224,7.92L5.92,7.92L5.92,7.9669ZM5.7947,7.9669L5.9045,7.9669L5.9045,7.92L5.7947,7.92L5.7947,7.9669ZM5.6789,7.9669L5.7792,7.9669L5.7792,7.92L5.6789,7.92L5.6789,7.9669ZM6.2171,7.9045L6.4363,7.9045L6.4363,7.8571L6.2171,7.8571L6.2171,7.9045ZM6.0917,7.9045L6.2016,7.9045L6.2016,7.8571L6.0917,7.8571L6.0917,7.9045ZM5.9755,7.9045L6.0763,7.9045L6.0763,7.8571L5.9755,7.8571L5.9755,7.9045ZM5.7413,7.9045L5.96,7.9045L5.96,7.8571L5.7413,7.8571L5.7413,7.9045ZM5.6789,7.8421L6.4987,7.8421L6.4987,7.7947L5.6789,7.7947L5.6789,7.8421ZM6.0379,7.7797L6.1387,7.7797L6.1387,7.7323L6.0379,7.7323L6.0379,7.7797ZM6.2725,7.7173L6.3819,7.7173L6.3819,7.7072L6.2725,7.7072L6.2725,7.7173ZM5.7947,7.7173L5.9045,7.7173L5.9045,7.7072L5.7947,7.7072L5.7947,7.7173ZM6.3893,7.6939L6.4363,7.6939L6.4363,7.6549L6.2171,7.6549L6.2171,7.6939L6.3893,7.6939ZM5.9131,7.6939L5.96,7.6939L5.96,7.6549L5.7413,7.6549L5.7413,7.6939L5.9131,7.6939ZM6.0379,7.6549L6.1387,7.6549L6.1387,7.6075L6.0379,7.6075L6.0379,7.6549ZM6.2171,7.6405L6.4363,7.6405L6.4363,7.5824L6.3979,7.5824L6.3979,7.616L6.3509,7.616L6.3509,7.5824L6.3115,7.5824L6.3115,7.616L6.2571,7.616L6.2571,7.5824L6.2176,7.5824L6.2176,7.6405L6.2171,7.6405ZM5.7413,7.6405L5.96,7.6405L5.96,7.5824L5.92,7.5824L5.92,7.616L5.8731,7.616L5.8731,7.5824L5.8261,7.5824L5.8261,7.616L5.7797,7.616L5.7797,7.5824L5.7419,7.5824L5.7419,7.6405L5.7413,7.6405ZM6.0379,7.5296L6.1387,7.5296L6.1387,7.52L6.0379,7.52L6.0379,7.5296ZM6.1477,7.5061L6.2016,7.5061L6.2016,7.4672L5.9755,7.4672L5.9755,7.5061L6.1477,7.5061ZM5.9755,7.4533L6.2016,7.4533L6.2016,7.3952L6.1547,7.3952L6.1547,7.4288L6.1077,7.4288L6.1077,7.3952L6.0693,7.3952L6.0693,7.4288L6.0229,7.4288L6.0229,7.3952L5.976,7.3952L5.976,7.4533L5.9755,7.4533Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.2485,8.7947C6.2485,8.7179 6.2485,8.6635 6.2485,8.6309C6.2485,8.6005 6.2331,8.5061 6.0853,8.5061C5.9445,8.5061 5.9291,8.6011 5.9291,8.6309C5.9291,8.6635 5.9291,8.7179 5.9291,8.7947L6.2485,8.7947Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.2565,8.8032L5.92,8.8032L5.92,8.6315C5.92,8.6085 5.9291,8.4992 6.0853,8.4992C6.248,8.4992 6.2571,8.6085 6.2571,8.6315L6.2571,8.8032L6.2565,8.8032ZM5.9355,8.7888L6.2411,8.7888L6.2411,8.6315C6.2411,8.6128 6.2331,8.5157 6.0848,8.5157C5.9429,8.5157 5.9355,8.6128 5.9355,8.6315L5.9355,8.7888L5.9355,8.7888Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9824,8.6405L5.9045,8.6309C5.9045,8.6005 5.9131,8.5531 5.936,8.5381L6.0069,8.5931C5.9984,8.6011 5.9824,8.624 5.9824,8.6405Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9915,8.648L5.8976,8.6395L5.8976,8.6309C5.8976,8.5947 5.9067,8.5477 5.9317,8.5307L5.936,8.5275L6.0181,8.5915L6.0117,8.5973C6.0032,8.6053 5.9909,8.6277 5.9909,8.64L5.9909,8.648L5.9915,8.648ZM5.9131,8.6251L5.9755,8.6315C5.9787,8.6187 5.9877,8.6032 5.9947,8.5941L5.936,8.5472C5.9216,8.5627 5.9131,8.5947 5.9131,8.6251Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1941,8.6405L6.2725,8.6309C6.2725,8.6005 6.264,8.5531 6.2411,8.5381L6.1701,8.5931C6.1787,8.6011 6.1941,8.624 6.1941,8.6405Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1861,8.648L6.1861,8.6405C6.1861,8.6283 6.1728,8.6059 6.1653,8.5979L6.1589,8.592L6.2411,8.528L6.2443,8.5312C6.2704,8.5477 6.2789,8.5947 6.2789,8.6315L6.2789,8.64L6.1861,8.648ZM6.1819,8.5936C6.1888,8.6032 6.1979,8.6181 6.2005,8.6309L6.264,8.6245C6.2629,8.5941 6.256,8.5621 6.2416,8.5467L6.1819,8.5936Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1163,8.5616L6.1547,8.4907C6.1392,8.4821 6.1077,8.4763 6.0853,8.4763C6.0693,8.4763 6.0384,8.4827 6.0229,8.4907L6.0613,8.5616C6.0768,8.5616 6.1003,8.5616 6.1163,8.5616Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.12,8.5685L6.0565,8.5685L6.0112,8.4885L6.0192,8.4821C6.0352,8.4768 6.0677,8.4672 6.0853,8.4672C6.1104,8.4672 6.1419,8.4773 6.1584,8.4821L6.1664,8.4885L6.12,8.5685ZM6.0667,8.5531L6.1115,8.5531L6.1445,8.4949C6.1291,8.4896 6.104,8.4827 6.0853,8.4827C6.0731,8.4827 6.0485,8.4901 6.0331,8.4949L6.0667,8.5531Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9669,8.3659C5.9669,8.3659 5.9669,8.2411 5.9669,8.1941C5.9669,8.1461 5.9355,8.1077 5.8816,8.1077C5.8261,8.1077 5.7947,8.1461 5.7947,8.1941C5.7947,8.2411 5.7947,8.3659 5.7947,8.3659L5.9669,8.3659Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9755,8.3739L5.7877,8.3739L5.7877,8.1936C5.7877,8.1392 5.8251,8.1008 5.8816,8.1008C5.9365,8.1008 5.9755,8.1392 5.9755,8.1936L5.9755,8.3739ZM5.8037,8.3573L5.96,8.3573L5.96,8.1936C5.96,8.1547 5.9349,8.1157 5.8816,8.1157C5.8272,8.1157 5.8037,8.1547 5.8037,8.1936L5.8037,8.3573L5.8037,8.3573Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.2101,8.3659C6.2101,8.3659 6.2101,8.2411 6.2101,8.1941C6.2101,8.1461 6.2416,8.1077 6.2955,8.1077C6.3509,8.1077 6.3819,8.1461 6.3819,8.1941C6.3819,8.2411 6.3819,8.3659 6.3819,8.3659L6.2101,8.3659Z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.3888,8.3739L6.2011,8.3739L6.2011,8.1936C6.2011,8.1392 6.24,8.1008 6.2949,8.1008C6.3504,8.1008 6.3888,8.1392 6.3888,8.1936L6.3888,8.3739ZM6.2171,8.3573L6.3733,8.3573L6.3733,8.1936C6.3733,8.1547 6.3499,8.1157 6.2949,8.1157C6.2411,8.1157 6.2171,8.1547 6.2171,8.1936L6.2171,8.3573L6.2171,8.3573Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1477,7.944l0.0155,-0.1563l-0.1488,0l0.0085,0.1563z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1541,7.9531L6.0149,7.9531L6.0069,7.7797L6.1717,7.7797L6.1541,7.9531ZM6.0288,7.9355L6.1403,7.9355L6.1536,7.7947L6.0224,7.7947L6.0288,7.9355Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.264,7.944l-0.0155,-0.1563l0.1563,0l-0.0155,0.1563z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.3968,7.9531L6.2565,7.9531L6.24,7.7797L6.4128,7.7797L6.3968,7.9531ZM6.2715,7.9355L6.3819,7.9355L6.3968,7.7947L6.2565,7.7947L6.2715,7.9355Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9131,7.944l0.0069,-0.1563l-0.1472,0l0.0155,0.1563z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9195,7.9531L5.7808,7.9531L5.7632,7.7797L5.9291,7.7797L5.9195,7.9531ZM5.7941,7.9355L5.9051,7.9355L5.9131,7.7947L5.7808,7.7947L5.7941,7.9355Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1941,8.7947C6.1941,8.7323 6.1941,8.6779 6.1941,8.6555C6.1941,8.6309 6.1787,8.5611 6.0848,8.5611C5.9979,8.5611 5.9824,8.6309 5.9824,8.6555C5.9824,8.6779 5.9824,8.7323 5.9824,8.7947L6.1941,8.7947ZM5.9515,8.3509C5.9515,8.3509 5.9515,8.2405 5.9515,8.2032C5.9515,8.1637 5.9291,8.1232 5.8821,8.1232C5.8357,8.1232 5.8112,8.1637 5.8112,8.2032C5.8112,8.2405 5.8112,8.3509 5.8112,8.3509L5.9515,8.3509ZM6.2256,8.3509C6.2256,8.3509 6.2256,8.2405 6.2256,8.2032C6.2256,8.1637 6.2485,8.1232 6.2955,8.1232C6.3424,8.1232 6.3664,8.1637 6.3664,8.2032C6.3664,8.2405 6.3664,8.3509 6.3664,8.3509L6.2256,8.3509Z" + android:strokeWidth="1" + android:fillColor="#0039F0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.3883,9.048C6.3883,8.7072 6.6352,8.4299 6.9381,8.4299C7.2416,8.4299 7.488,8.7077 7.488,9.048C7.488,9.3909 7.2416,9.6672 6.9381,9.6672C6.6352,9.6672 6.3883,9.3904 6.3883,9.048" + android:strokeWidth="1" + android:fillColor="#AD1519" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9381,9.6779C6.6288,9.6779 6.3781,9.3947 6.3781,9.0475C6.3781,8.7029 6.6288,8.4192 6.9381,8.4192C7.248,8.4192 7.4981,8.7024 7.4981,9.0475C7.4981,9.3947 7.2475,9.6779 6.9381,9.6779ZM6.9381,8.4405C6.6416,8.4405 6.3984,8.7136 6.3984,9.048C6.3984,9.3824 6.6416,9.6576 6.9381,9.6576C7.2352,9.6576 7.4784,9.3824 7.4784,9.048C7.4784,8.7136 7.2352,8.4405 6.9381,8.4405Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.5509,9.0459C6.5509,8.7947 6.7253,8.5936 6.9381,8.5936C7.152,8.5936 7.3259,8.7947 7.3259,9.0459C7.3259,9.2981 7.1525,9.5019 6.9381,9.5019C6.7248,9.5019 6.5509,9.2981 6.5509,9.0459" + android:strokeWidth="1" + android:fillColor="#005BBF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9381,9.5115C6.7195,9.5115 6.5413,9.3029 6.5413,9.0459C6.5413,8.7904 6.7189,8.5824 6.9381,8.5824C7.1573,8.5824 7.3355,8.7909 7.3355,9.0459C7.3349,9.3029 7.1568,9.5115 6.9381,9.5115ZM6.9381,8.6032C6.7312,8.6032 6.5621,8.8032 6.5621,9.0459C6.5621,9.2923 6.7312,9.4907 6.9381,9.4907C7.1461,9.4907 7.3152,9.2923 7.3152,9.0459C7.3152,8.8032 7.1461,8.6032 6.9381,8.6032Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.7557,8.7344C6.7557,8.7344 6.7104,8.7845 6.7104,8.8325C6.7104,8.8784 6.7291,8.9184 6.7291,8.9184C6.7227,8.8992 6.704,8.8853 6.6821,8.8853C6.6544,8.8853 6.6315,8.9072 6.6315,8.9323C6.6315,8.9408 6.6357,8.9531 6.6389,8.9595L6.656,8.9936C6.6608,8.9813 6.6741,8.9744 6.6885,8.9744C6.7093,8.9744 6.7259,8.9904 6.7259,9.0075C6.7259,9.0117 6.7253,9.016 6.7243,9.0176L6.6827,9.0176L6.6827,9.0533L6.72,9.0533L6.6923,9.1067L6.7296,9.0928L6.7563,9.1237L6.7851,9.0928L6.8203,9.1067L6.7936,9.0533L6.8299,9.0533L6.8299,9.0176L6.7888,9.0176C6.7888,9.016 6.7888,9.0117 6.7888,9.0075C6.7888,8.9909 6.8048,8.9744 6.8235,8.9744C6.8384,8.9744 6.8512,8.9813 6.8571,8.9936L6.8731,8.9595C6.8768,8.9531 6.8821,8.9408 6.8821,8.9323C6.8821,8.9072 6.8597,8.8853 6.8315,8.8853C6.8091,8.8853 6.7904,8.8987 6.7829,8.9184C6.7829,8.9184 6.8027,8.8784 6.8027,8.8325C6.8027,8.7845 6.7557,8.7344 6.7557,8.7344" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.7557,9.128L6.7557,9.128C6.7541,9.128 6.7525,9.128 6.7509,9.128L6.7264,9.0987L6.6944,9.1115C6.6917,9.1131 6.6891,9.112 6.688,9.1088C6.6859,9.1067 6.6853,9.1056 6.6869,9.1024L6.7099,9.0565L6.6816,9.0565C6.6784,9.0565 6.6763,9.0549 6.6763,9.0523L6.6763,9.0165C6.6763,9.0149 6.6784,9.0107 6.6816,9.0107L6.7189,9.0107C6.7189,9.0085 6.7189,9.0075 6.7189,9.0064C6.7189,8.9925 6.7051,8.9787 6.6875,8.9787C6.6752,8.9787 6.6645,8.9845 6.6597,8.9936C6.6597,8.9957 6.6571,8.9968 6.6549,8.9979C6.6533,8.9979 6.6501,8.9957 6.6501,8.9936L6.6336,8.9621C6.6309,8.9557 6.6251,8.9424 6.6251,8.9307C6.6251,8.9013 6.6501,8.8789 6.6811,8.8789C6.6917,8.8789 6.7035,8.8805 6.7125,8.8891C6.7072,8.8715 6.7035,8.8517 6.7035,8.8309C6.7035,8.7851 6.744,8.7392 6.7499,8.7307C6.752,8.7264 6.7568,8.7264 6.7595,8.7296C6.7648,8.736 6.8075,8.784 6.8075,8.8304C6.8075,8.8512 6.8032,8.8709 6.8,8.8885C6.8085,8.88 6.8187,8.8784 6.8309,8.8784C6.8619,8.8784 6.8869,8.9008 6.8869,8.9301C6.8869,8.9413 6.8811,8.9541 6.8784,8.9616L6.8619,8.9931C6.8603,8.9952 6.8592,8.9973 6.8565,8.9973C6.8539,8.9979 6.8523,8.9952 6.8507,8.9931C6.8475,8.9835 6.8363,8.9781 6.8224,8.9781C6.8064,8.9781 6.7931,8.9915 6.7931,9.0059C6.7931,9.0069 6.7931,9.008 6.7931,9.0101L6.8288,9.0101C6.832,9.0101 6.8347,9.0144 6.8347,9.016L6.8347,9.0517C6.8347,9.0544 6.832,9.056 6.8288,9.056L6.8021,9.056L6.8251,9.1019C6.8251,9.1051 6.8251,9.1061 6.8245,9.1083C6.8224,9.1115 6.8197,9.1125 6.8181,9.1109L6.7851,9.0981L6.76,9.1275C6.7589,9.128 6.7568,9.128 6.7557,9.128ZM6.7291,9.0864C6.7296,9.0864 6.7317,9.0875 6.7323,9.0896L6.7563,9.1157L6.7797,9.0896C6.7819,9.0864 6.7845,9.0853 6.7861,9.0875L6.8085,9.0949L6.7883,9.0549C6.7872,9.0533 6.7877,9.0523 6.7883,9.0491C6.7888,9.0469 6.7915,9.0448 6.7931,9.0448L6.824,9.0448L6.824,9.0219L6.7883,9.0219C6.7856,9.0219 6.784,9.0197 6.7824,9.0187C6.7819,9.0155 6.7819,9.0112 6.7819,9.0075C6.7819,8.9867 6.8005,8.9691 6.8229,8.9691C6.8373,8.9691 6.848,8.9733 6.8565,8.9824L6.8677,8.9573C6.872,8.952 6.8752,8.9408 6.8752,8.9323C6.8752,8.9104 6.8555,8.8907 6.8309,8.8907C6.8128,8.8907 6.7973,8.9019 6.7909,8.9157C6.7888,8.9189 6.7877,8.92 6.7877,8.92C6.7872,8.9232 6.7835,8.9243 6.7808,8.9221C6.7787,8.9211 6.776,8.9189 6.7776,8.9157C6.7781,8.9147 6.7781,8.9115 6.7797,8.9083C6.7845,8.8976 6.7963,8.8683 6.7963,8.832C6.7963,8.7947 6.7659,8.7568 6.7552,8.7435C6.744,8.7568 6.7152,8.7947 6.7152,8.832C6.7152,8.8667 6.7264,8.8976 6.7312,8.9093C6.7317,8.9115 6.7333,8.9147 6.7344,8.9157C6.7344,8.9189 6.7339,8.9211 6.7312,8.9221C6.7285,8.9243 6.7248,8.9232 6.7232,8.92C6.7232,8.92 6.7221,8.9189 6.7211,8.9157C6.7125,8.9013 6.6976,8.8907 6.6811,8.8907C6.656,8.8907 6.6357,8.9104 6.6357,8.9323C6.6357,8.9408 6.64,8.9509 6.6437,8.9573L6.656,8.9824C6.6624,8.9728 6.6747,8.9691 6.6875,8.9691C6.7115,8.9691 6.7307,8.9867 6.7307,9.0075C6.7307,9.0128 6.7301,9.016 6.7285,9.0187C6.7285,9.0197 6.7253,9.0219 6.7232,9.0219L6.688,9.0219L6.688,9.0448L6.7195,9.0448C6.7216,9.0448 6.7227,9.0469 6.7243,9.0491C6.7253,9.0523 6.7253,9.0533 6.7248,9.0549L6.704,9.0949L6.7259,9.0875C6.7264,9.0864 6.728,9.0864 6.7291,9.0864Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.6821,9.0533l0.1472,0l0,-0.0357l-0.1472,0z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8352,9.0571L6.6768,9.0571L6.6768,9.0112L6.8352,9.0112L6.8352,9.0571ZM6.688,9.0448L6.824,9.0448L6.824,9.0219L6.688,9.0219L6.688,9.0448Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1157,8.7344C7.1157,8.7344 7.0693,8.7845 7.0693,8.8325C7.0693,8.8784 7.088,8.9184 7.088,8.9184C7.0816,8.8992 7.0629,8.8853 7.0416,8.8853C7.0133,8.8853 6.9909,8.9072 6.9909,8.9323C6.9909,8.9408 6.9947,8.9531 6.9984,8.9595L7.0155,8.9936C7.0203,8.9813 7.0336,8.9744 7.048,8.9744C7.0688,8.9744 7.0853,8.9904 7.0853,9.0075C7.0853,9.0117 7.0848,9.016 7.0837,9.0176L7.0421,9.0176L7.0421,9.0533L7.0795,9.0533L7.0517,9.1067L7.0885,9.0928L7.1163,9.1237L7.1451,9.0928L7.1803,9.1067L7.1536,9.0533L7.1899,9.0533L7.1899,9.0176L7.1488,9.0176C7.1488,9.016 7.1488,9.0117 7.1488,9.0075C7.1488,8.9909 7.1643,8.9744 7.184,8.9744C7.1989,8.9744 7.2117,8.9813 7.2176,8.9936L7.2336,8.9595C7.2373,8.9531 7.2427,8.9408 7.2427,8.9323C7.2427,8.9072 7.2203,8.8853 7.192,8.8853C7.1701,8.8853 7.1515,8.8987 7.144,8.9184C7.144,8.9184 7.1637,8.8784 7.1637,8.8325C7.1621,8.7845 7.1152,8.7344 7.1157,8.7344" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1157,9.128C7.1136,9.128 7.1125,9.128 7.1104,9.128L7.0859,9.0987L7.0539,9.1115C7.0512,9.1131 7.0485,9.112 7.0475,9.1088C7.0453,9.1067 7.0448,9.1056 7.0464,9.1024L7.0688,9.0565L7.0411,9.0565C7.0379,9.0565 7.0357,9.0549 7.0357,9.0523L7.0357,9.0165C7.0357,9.0149 7.0379,9.0107 7.0411,9.0107L7.0784,9.0107C7.0784,9.0085 7.0784,9.0075 7.0784,9.0064C7.0784,8.9925 7.0645,8.9787 7.0469,8.9787C7.0347,8.9787 7.0245,8.9845 7.0187,8.9936C7.0187,8.9957 7.0155,8.9989 7.0144,8.9979C7.0123,8.9979 7.0096,8.9957 7.0096,8.9936L6.9931,8.9621C6.9899,8.9557 6.9845,8.9424 6.9845,8.9307C6.9845,8.9013 7.0096,8.8789 7.0405,8.8789C7.0512,8.8789 7.0624,8.8805 7.072,8.8891C7.0667,8.8715 7.0624,8.8517 7.0624,8.8309C7.0624,8.7851 7.1035,8.7381 7.1093,8.7307C7.112,8.7264 7.1168,8.7264 7.1184,8.7296C7.1248,8.736 7.1669,8.784 7.1669,8.8304C7.1669,8.8512 7.1621,8.8709 7.1595,8.8885C7.168,8.88 7.1781,8.8784 7.1899,8.8784C7.2213,8.8784 7.2469,8.9008 7.2469,8.9301C7.2469,8.9413 7.2405,8.9541 7.2373,8.9616L7.2213,8.9931C7.2197,8.9952 7.2176,8.9973 7.216,8.9973C7.2133,8.9973 7.2117,8.9952 7.2101,8.9931C7.2064,8.9835 7.1957,8.9781 7.1824,8.9781C7.1659,8.9781 7.1525,8.9915 7.1525,9.0059C7.1525,9.0069 7.1525,9.008 7.1525,9.0101L7.1883,9.0101C7.1915,9.0101 7.1936,9.0144 7.1936,9.016L7.1936,9.0517C7.1936,9.0544 7.1915,9.056 7.1883,9.056L7.1611,9.056L7.1845,9.1019C7.1851,9.1051 7.1845,9.1061 7.184,9.1083C7.1813,9.1115 7.1792,9.1125 7.1776,9.1109L7.144,9.0981L7.1189,9.1275C7.1189,9.128 7.1163,9.128 7.1157,9.128ZM7.088,9.0864C7.0891,9.0864 7.0912,9.0875 7.0912,9.0896L7.1152,9.1157L7.1387,9.0896C7.1408,9.0864 7.1435,9.0853 7.1451,9.0875L7.1675,9.0949L7.1472,9.0549C7.1461,9.0533 7.1467,9.0523 7.1472,9.0491C7.1477,9.0469 7.1499,9.0448 7.152,9.0448L7.1829,9.0448L7.1829,9.0219L7.1472,9.0219C7.1445,9.0219 7.1429,9.0197 7.1419,9.0187C7.1413,9.0155 7.1413,9.0123 7.1413,9.0075C7.1413,8.9867 7.16,8.9691 7.1829,8.9691C7.1968,8.9691 7.208,8.9733 7.2165,8.9824L7.2277,8.9573C7.2315,8.952 7.2352,8.9408 7.2352,8.9323C7.2352,8.9104 7.2155,8.8907 7.1909,8.8907C7.1733,8.8907 7.1573,8.9019 7.1509,8.9157C7.1493,8.9189 7.1483,8.92 7.1483,8.92C7.1477,8.9232 7.144,8.9243 7.1413,8.9232C7.1387,8.9211 7.1365,8.9189 7.1387,8.9157C7.1387,8.9147 7.1392,8.9115 7.1408,8.9083C7.1445,8.8976 7.1573,8.8672 7.1573,8.832C7.1573,8.7947 7.1264,8.7568 7.1163,8.7435C7.1045,8.7568 7.0763,8.7947 7.0763,8.832C7.0763,8.8667 7.0875,8.8976 7.0923,8.9093C7.0928,8.9115 7.0944,8.9147 7.0949,8.9157C7.0949,8.9189 7.0949,8.9211 7.0923,8.9232C7.0891,8.9243 7.0859,8.9232 7.0843,8.92C7.0843,8.92 7.0827,8.9189 7.0821,8.9157C7.0736,8.9013 7.0587,8.8907 7.0421,8.8907C7.0171,8.8907 6.9968,8.9104 6.9968,8.9323C6.9968,8.9408 7.0011,8.9509 7.0048,8.9573L7.0171,8.9824C7.0235,8.9728 7.0357,8.9691 7.0485,8.9691C7.0725,8.9691 7.0912,8.9867 7.0912,9.0075C7.0912,9.0128 7.0907,9.016 7.0896,9.0187C7.0891,9.0197 7.0869,9.0219 7.0843,9.0219L7.0485,9.0219L7.0485,9.0448L7.08,9.0448C7.0821,9.0448 7.0832,9.0469 7.0853,9.0491C7.0864,9.0523 7.0864,9.0533 7.0853,9.0549L7.064,9.0949L7.0864,9.0875C7.0864,9.0864 7.0875,9.0864 7.088,9.0864Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0416,9.0533l0.1472,0l0,-0.0357l-0.1472,0z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.1947,9.0571L7.0363,9.0571L7.0363,9.0112L7.1947,9.0112L7.1947,9.0571ZM7.0475,9.0448L7.1835,9.0448L7.1835,9.0219L7.0475,9.0219L7.0475,9.0448Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9349,9.0448C6.9349,9.0448 6.8891,9.0949 6.8891,9.1408C6.8891,9.1888 6.9088,9.2283 6.9088,9.2283C6.9013,9.2075 6.8827,9.1947 6.8603,9.1947C6.8325,9.1947 6.8096,9.2155 6.8096,9.2432C6.8096,9.2523 6.8149,9.2635 6.8187,9.2699L6.8347,9.3035C6.8411,9.2912 6.8533,9.2827 6.8683,9.2827C6.8875,9.2827 6.9035,9.2992 6.9035,9.3184C6.9035,9.32 6.9035,9.3243 6.9035,9.3285L6.8624,9.3285L6.8624,9.3621L6.8987,9.3621L6.872,9.4165L6.9067,9.4043L6.9344,9.4336L6.9627,9.4043L7,9.4165L6.9723,9.3621L7.0096,9.3621L7.0096,9.328L6.968,9.328C6.9669,9.3237 6.9664,9.3195 6.9664,9.3179C6.9664,9.2987 6.9829,9.2821 7.0037,9.2821C7.0181,9.2821 7.0309,9.2907 7.0363,9.3029L7.0539,9.2693C7.0565,9.2629 7.0613,9.2517 7.0613,9.2427C7.0613,9.2149 7.0384,9.1941 7.0101,9.1941C6.9877,9.1941 6.9691,9.2064 6.9632,9.2277C6.9632,9.2277 6.9819,9.1883 6.9819,9.1403C6.9819,9.0949 6.9349,9.0448 6.9349,9.0448" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.9349,9.4395C6.9339,9.4395 6.9317,9.4373 6.9317,9.4363L6.9067,9.4069L6.8736,9.4192C6.872,9.4203 6.8693,9.4192 6.8672,9.4192C6.8661,9.4176 6.8661,9.4149 6.8661,9.4139L6.8896,9.3664L6.8629,9.3664C6.8592,9.3664 6.8565,9.3648 6.8565,9.3605L6.8565,9.328C6.8565,9.3227 6.8592,9.3195 6.8629,9.3195L6.8987,9.3195C6.8987,9.3195 6.8987,9.3184 6.8987,9.3179C6.8987,9.3029 6.8848,9.2901 6.8683,9.2901C6.8549,9.2901 6.8437,9.2944 6.84,9.3051C6.8389,9.3067 6.8368,9.3067 6.8347,9.3067C6.832,9.3067 6.8309,9.3067 6.8293,9.3051L6.8128,9.2704C6.8101,9.2651 6.8037,9.2528 6.8037,9.2427C6.8037,9.2139 6.8293,9.1899 6.8603,9.1899C6.872,9.1899 6.8827,9.1925 6.8912,9.1973C6.8875,9.1819 6.8832,9.1632 6.8832,9.1403C6.8832,9.0944 6.9232,9.0475 6.9296,9.04C6.9312,9.0379 6.9376,9.0379 6.9397,9.04C6.9445,9.0453 6.9877,9.0944 6.9877,9.1403C6.9877,9.1632 6.984,9.1819 6.9787,9.1973C6.9877,9.1925 6.9989,9.1899 7.0096,9.1899C7.0411,9.1899 7.0661,9.2139 7.0661,9.2427C7.0661,9.2528 7.0608,9.2651 7.0576,9.2704L7.0411,9.3051C7.0411,9.3067 7.0379,9.3067 7.0363,9.3067L7.0363,9.3067C7.0352,9.3067 7.0315,9.3067 7.0315,9.3051C7.0261,9.2939 7.016,9.2901 7.0037,9.2901C6.9861,9.2901 6.9723,9.3024 6.9723,9.3179C6.9723,9.3184 6.9723,9.3195 6.9723,9.3195L7.0096,9.3195C7.0123,9.3195 7.0149,9.3227 7.0149,9.328L7.0149,9.3616C7.0149,9.3659 7.0123,9.3675 7.0096,9.3675L6.9813,9.3675L7.0048,9.4149C7.0064,9.416 7.0059,9.4187 7.0037,9.4203C7.0032,9.4203 7.0005,9.4213 6.9973,9.4203L6.9653,9.408L6.9392,9.4373C6.9381,9.4373 6.9371,9.4395 6.9349,9.4395ZM6.9077,9.3947C6.9104,9.3947 6.9109,9.3947 6.9131,9.3968L6.9355,9.424L6.9605,9.3968C6.9611,9.3947 6.9632,9.3947 6.9669,9.3947L6.9888,9.4048L6.968,9.3659C6.9675,9.3627 6.9675,9.3595 6.968,9.3573C6.9696,9.3573 6.9707,9.3563 6.9733,9.3563L7.0048,9.3563L7.0048,9.3323L6.9696,9.3323C6.9675,9.3323 6.9643,9.3307 6.9643,9.328C6.9632,9.3248 6.9627,9.3195 6.9627,9.3179C6.9627,9.2944 6.9813,9.2779 7.0053,9.2779C7.0176,9.2779 7.0304,9.2821 7.0368,9.2901L7.0491,9.2667C7.0528,9.2576 7.0571,9.2485 7.0571,9.2427C7.0571,9.2192 7.0363,9.2016 7.0117,9.2016C6.9952,9.2016 6.9797,9.2091 6.9712,9.2245C6.9707,9.2277 6.9696,9.2293 6.9696,9.2293C6.968,9.232 6.9643,9.232 6.9616,9.232C6.9589,9.2309 6.9584,9.2277 6.9584,9.2245C6.9595,9.2224 6.9611,9.2192 6.9616,9.2192C6.9664,9.2069 6.9776,9.1776 6.9776,9.1403C6.9776,9.1056 6.9483,9.0651 6.9365,9.0528C6.9253,9.0651 6.896,9.1056 6.896,9.1403C6.896,9.1776 6.9077,9.2069 6.9131,9.2192C6.9141,9.2192 6.9141,9.2213 6.9152,9.2245C6.9168,9.2277 6.9147,9.2309 6.912,9.232C6.9093,9.232 6.9061,9.232 6.9051,9.2293C6.9051,9.2293 6.9045,9.2277 6.9019,9.2235C6.8955,9.2091 6.88,9.2016 6.8619,9.2016C6.8373,9.2016 6.8176,9.2192 6.8176,9.2427C6.8176,9.2491 6.8208,9.2587 6.8245,9.2651L6.8363,9.2901C6.8448,9.2816 6.8555,9.2779 6.8699,9.2779C6.8923,9.2779 6.9115,9.2944 6.9115,9.3179C6.9115,9.3195 6.9115,9.3248 6.9109,9.328C6.9099,9.3307 6.9083,9.3323 6.9056,9.3323L6.8699,9.3323L6.8699,9.3563L6.9008,9.3563C6.9019,9.3563 6.9056,9.3573 6.9056,9.3573C6.9067,9.3595 6.9067,9.3627 6.9056,9.3659L6.8853,9.4048L6.9077,9.3947C6.9067,9.3947 6.9067,9.3947 6.9077,9.3947Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.8629,9.3616l0.1472,0l0,-0.0336l-0.1472,0z" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0155,9.3669L6.8565,9.3669L6.8565,9.3195L7.0155,9.3195L7.0155,9.3669ZM6.8683,9.3563L7.0037,9.3563L7.0037,9.3323L6.8683,9.3323L6.8683,9.3563Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0357,7.4155L8.0256,7.4155C8.0256,7.4155 8.0219,7.4229 8.0171,7.4277C8.0085,7.4352 7.9952,7.4363 7.9883,7.4293C7.9856,7.4267 7.9824,7.4192 7.984,7.4155C7.9787,7.4187 7.9728,7.4187 7.9669,7.4155C7.9573,7.4101 7.9557,7.3979 7.9621,7.3893C7.9632,7.3861 7.9632,7.3819 7.9659,7.3819L7.9648,7.3696L7.9536,7.3749L7.9499,7.3813C7.9419,7.3909 7.9323,7.3909 7.9259,7.3867C7.9232,7.3824 7.9216,7.3781 7.9216,7.3781C7.9216,7.3781 7.9189,7.3808 7.9157,7.3813C7.8976,7.3856 7.8901,7.3451 7.8896,7.3344L7.8837,7.344C7.8837,7.344 7.8885,7.3685 7.8859,7.3888C7.8837,7.4075 7.8757,7.4283 7.8757,7.4283C7.9013,7.4336 7.9392,7.456 7.9765,7.4837C8.0139,7.5141 8.0437,7.544 8.056,7.5659C8.056,7.5659 8.0747,7.5557 8.0955,7.5493C8.1157,7.5424 8.1408,7.5424 8.1408,7.5424L8.1488,7.5333C8.1371,7.5365 8.0949,7.5397 8.0965,7.52C8.0965,7.5173 8.0981,7.5157 8.0987,7.5157C8.0987,7.5157 8.0912,7.5157 8.088,7.5125C8.0821,7.5072 8.0821,7.4971 8.0891,7.4907L8.0949,7.4832L8.0955,7.472L8.0837,7.4752C8.0832,7.4773 8.0805,7.4784 8.0779,7.4784C8.0693,7.488 8.056,7.488 8.0491,7.4811C8.0453,7.4773 8.0432,7.4699 8.0464,7.4661C8.04,7.4661 8.0352,7.4661 8.0304,7.464C8.0213,7.4576 8.0203,7.4453 8.0277,7.4357C8.0304,7.4315 8.0368,7.4261 8.0368,7.4251L8.0357,7.4155" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0544,7.5707L8.0533,7.5685C8.0411,7.5445 8.0107,7.5152 7.9755,7.4885C7.9387,7.4592 7.9013,7.4405 7.8763,7.4325L7.8715,7.4315L7.8736,7.4283C7.8736,7.4283 7.88,7.4075 7.8827,7.3877C7.8859,7.3691 7.88,7.3451 7.88,7.3451L7.88,7.3435L7.8955,7.3211L7.8955,7.3344C7.8955,7.3467 7.9024,7.3781 7.9141,7.3781C7.9141,7.3781 7.9141,7.3781 7.9152,7.3781C7.9173,7.3781 7.9173,7.3771 7.9184,7.376L7.9237,7.368L7.9264,7.3781L7.9264,7.3781C7.9264,7.3797 7.9285,7.3824 7.9296,7.3824C7.9301,7.3835 7.9323,7.3835 7.9333,7.3835C7.9387,7.3835 7.9429,7.3824 7.9467,7.3781L7.9509,7.3696L7.9696,7.3653L7.9696,7.3829L7.9691,7.3851C7.968,7.3861 7.9669,7.3883 7.9669,7.3904L7.9669,7.3904C7.9637,7.3947 7.9627,7.4 7.9637,7.4027C7.9637,7.4069 7.9669,7.4091 7.9696,7.4112C7.9733,7.4155 7.9776,7.4155 7.9824,7.4117L7.9888,7.4069L7.9888,7.4155C7.9888,7.4197 7.9888,7.424 7.992,7.4277C7.9973,7.4309 8.0075,7.4304 8.0144,7.4235C8.0187,7.4192 8.0224,7.4149 8.0235,7.4139L8.0235,7.4107L8.0261,7.4096L8.0373,7.4085L8.0405,7.4107L8.0421,7.4139L8.0448,7.4272L8.0421,7.4272C8.0405,7.4288 8.0357,7.4315 8.0325,7.4379C8.0299,7.4416 8.0288,7.4453 8.0299,7.4523C8.0299,7.4539 8.0325,7.4565 8.0352,7.4565C8.0389,7.4597 8.0421,7.4608 8.0464,7.4587L8.0549,7.4565L8.0517,7.4651C8.0517,7.4693 8.0517,7.4736 8.0549,7.4773C8.0613,7.4816 8.0704,7.4816 8.0779,7.4763C8.0784,7.4752 8.08,7.4741 8.08,7.4731C8.0805,7.472 8.0827,7.4699 8.0827,7.4699L8.0827,7.4688L8.1013,7.4672L8.1013,7.4859L8.0944,7.4912C8.0917,7.4939 8.0891,7.5003 8.0901,7.5024C8.0907,7.5056 8.0923,7.5067 8.0923,7.5067C8.0939,7.5067 8.0976,7.5077 8.0987,7.5088L8.1109,7.5088L8.1024,7.5184L8.1003,7.52C8.1003,7.5211 8.1008,7.5232 8.1029,7.5253C8.1067,7.5285 8.1184,7.5317 8.1339,7.5317C8.1408,7.5317 8.1461,7.5317 8.1488,7.5312L8.1627,7.5285L8.1445,7.5451L8.1419,7.5451C8.1419,7.5451 8.1168,7.5451 8.0976,7.5536C8.0779,7.5579 8.0587,7.5701 8.0587,7.5701L8.0544,7.5707ZM7.8816,7.4261C7.9088,7.4325 7.944,7.4533 7.9792,7.4816C8.0139,7.5077 8.0443,7.5376 8.0576,7.5595C8.0645,7.5563 8.0789,7.5499 8.0939,7.5451C8.1029,7.5424 8.1109,7.5408 8.1189,7.5408C8.1099,7.5397 8.1003,7.5355 8.0965,7.5312C8.0939,7.528 8.0917,7.5237 8.0917,7.52C8.0917,7.52 8.0917,7.5189 8.0923,7.5184C8.0912,7.5173 8.0875,7.5173 8.0869,7.5157C8.0832,7.5147 8.0816,7.5093 8.0805,7.5056C8.0789,7.4992 8.0811,7.4923 8.0864,7.4853L8.0875,7.4843L8.0907,7.4821L8.0907,7.4779L8.0869,7.4779C8.0859,7.4795 8.0848,7.4805 8.0848,7.4811C8.0843,7.4811 8.0832,7.4821 8.0821,7.4821C8.072,7.4907 8.0565,7.4923 8.0475,7.4821C8.0443,7.4795 8.0411,7.4747 8.0411,7.4699C8.0379,7.4699 8.0325,7.4688 8.0288,7.4656C8.0245,7.4645 8.0213,7.4571 8.0192,7.4533C8.0192,7.4448 8.0192,7.4411 8.0245,7.4325C8.0261,7.4299 8.0309,7.4261 8.0336,7.4229L8.032,7.4197L8.0288,7.4197C8.0267,7.4219 8.0229,7.4283 8.0197,7.4309C8.0101,7.4411 7.9941,7.4411 7.9851,7.4325C7.9819,7.4299 7.9797,7.4272 7.9787,7.4213C7.9739,7.4224 7.9691,7.4213 7.9632,7.4203C7.9589,7.416 7.9552,7.4123 7.9536,7.4069C7.9525,7.4005 7.9536,7.3931 7.9573,7.3872L7.9579,7.3851C7.9589,7.3829 7.9595,7.3829 7.9595,7.3819L7.9595,7.3787L7.9552,7.3787L7.9531,7.3829C7.9435,7.3941 7.9291,7.3952 7.9216,7.3915C7.9205,7.3904 7.9184,7.3872 7.9184,7.384C7.9173,7.3851 7.9157,7.3851 7.9157,7.3851C7.9147,7.3861 7.9125,7.3861 7.9125,7.3861C7.9013,7.3861 7.8939,7.3765 7.8907,7.3653C7.8907,7.3707 7.8907,7.3803 7.8907,7.3904C7.888,7.4032 7.8853,7.4181 7.8816,7.4261Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.96,7.4384C7.9611,7.4352 7.9653,7.4352 7.9675,7.4384C7.9696,7.4405 7.9712,7.4437 7.9691,7.4448C7.968,7.4459 7.9643,7.4459 7.9616,7.4448C7.9595,7.4432 7.9579,7.4405 7.96,7.4384" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0757,7.5408C8.0741,7.5408 8.0731,7.5408 8.0704,7.5408C8.0693,7.5397 8.0677,7.5365 8.0677,7.5344C8.0677,7.5323 8.0683,7.5323 8.0693,7.5312C8.0704,7.528 8.0752,7.528 8.0784,7.5312C8.0789,7.5323 8.0811,7.5333 8.0811,7.5365C8.0811,7.5387 8.0811,7.5408 8.0795,7.5408C8.0789,7.5408 8.0773,7.5408 8.0757,7.5408Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9856,7.3344l-0.0192,0.0011l-0.0037,0.0304l0.0011,0.0043l0.0053,0l0.0251,-0.0165l-0.0085,-0.0192" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9317,7.3531l0,0.0165l0.0315,0.0043l0.0037,-0.0043l0,-0.0043l-0.0181,-0.0235l-0.0171,0.0112" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9963,7.3888l-0.0171,0.0075l-0.0181,-0.0229l-0.0005,-0.0048l0.0059,-0.0027l0.0315,0.0043l-0.0016,0.0187" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9557,7.3659C7.9584,7.3605 7.9643,7.3584 7.9691,7.3627C7.9733,7.3659 7.9755,7.3701 7.9723,7.3749C7.9691,7.3781 7.9627,7.3808 7.9589,7.3781C7.9541,7.376 7.9541,7.3696 7.9557,7.3659" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9637,7.3824C7.9616,7.3824 7.9595,7.3824 7.9568,7.3824C7.9541,7.3797 7.9504,7.3781 7.9504,7.3728C7.9499,7.3696 7.9504,7.3653 7.9515,7.3632C7.9563,7.3557 7.9648,7.3541 7.9712,7.3568C7.9744,7.3589 7.976,7.3643 7.9776,7.3669C7.9781,7.3696 7.9781,7.3739 7.9749,7.3781C7.9733,7.3813 7.9691,7.3824 7.9637,7.3824Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8827,7.3344C7.8816,7.3344 7.8789,7.32 7.8741,7.3104C7.8715,7.3045 7.8608,7.2949 7.8608,7.2949C7.8624,7.2949 7.8752,7.2907 7.8912,7.3003C7.9035,7.3088 7.8896,7.3285 7.8896,7.3285C7.8896,7.3285 7.8859,7.3323 7.8827,7.3344" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9179,7.3445l-0.0139,0.0123l-0.0229,-0.0187l0.0011,-0.0053l0.0011,-0.0037l0.0315,-0.0016l0.0032,0.0171" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8789,7.3323C7.8805,7.328 7.8853,7.3248 7.888,7.3269C7.8917,7.328 7.8944,7.3323 7.8912,7.3376C7.8901,7.3424 7.8848,7.3451 7.8816,7.344C7.8789,7.3435 7.8773,7.3387 7.8789,7.3323" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.8837,7.3488C7.8821,7.3488 7.8821,7.3488 7.8821,7.3477C7.8752,7.3445 7.8731,7.3403 7.8752,7.3312C7.8773,7.3248 7.8848,7.32 7.8901,7.3205C7.896,7.3237 7.8987,7.3312 7.8965,7.3392C7.8944,7.3445 7.8885,7.3488 7.8837,7.3488Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0629,7.3824l-0.0203,-0.0011l-0.0075,0.0272l0,0.0075l0.0059,0l0.0277,-0.0133l-0.0059,-0.0203" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0069,7.392l-0.0027,0.0171l0.0293,0.0091l0.0048,-0.0027l0,-0.0043l-0.0133,-0.0272l-0.0181,0.008" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0651,7.4363l-0.0171,0.0075l-0.0155,-0.0267l0.0005,-0.0048l0.0053,-0.0021l0.0304,0.0085l-0.0037,0.0176" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0288,7.4075C8.0315,7.4048 8.0379,7.4048 8.0411,7.4075C8.0459,7.4107 8.0464,7.416 8.0432,7.4197C8.0395,7.4251 8.0336,7.4251 8.0288,7.4208C8.0256,7.4187 8.0256,7.4133 8.0288,7.4075" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0352,7.4283C8.032,7.4283 8.0288,7.4283 8.0267,7.4261C8.024,7.4229 8.0224,7.4197 8.0219,7.4155C8.0219,7.4123 8.0224,7.4069 8.0256,7.4059C8.0288,7.4016 8.0379,7.3995 8.0443,7.4027C8.0475,7.4059 8.0496,7.408 8.0507,7.4133C8.0507,7.4155 8.0496,7.4197 8.048,7.4229C8.0443,7.4283 8.04,7.4283 8.0352,7.4283Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1291,7.4448l0.0037,0.0208l-0.0288,0.0085l-0.0059,-0.0021l0,-0.0037l0.0123,-0.0277l0.0187,0.0043" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1243,7.4992l-0.0192,0.0043l-0.0112,-0.0272l0.0016,-0.0064l0.0043,0l0.0293,0.0112l-0.0048,0.0181" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0725,7.4459l-0.0064,0.0197l0.0288,0.0112l0.0053,-0.0011l0.0011,-0.0064l-0.0101,-0.0277l-0.0187,0.0043" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1045,7.4795C8.1088,7.4768 8.1088,7.4693 8.1051,7.4656C8.1008,7.4635 8.0944,7.4635 8.0912,7.4656C8.088,7.4699 8.088,7.4763 8.0912,7.4779C8.0944,7.4821 8.1003,7.4821 8.1045,7.4795" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1504,7.5408C8.1504,7.5408 8.168,7.5408 8.1781,7.544C8.1851,7.5451 8.1957,7.5536 8.1957,7.5536C8.1979,7.5536 8.2,7.5403 8.1861,7.5275C8.1728,7.5163 8.1568,7.5328 8.1568,7.5328C8.1568,7.5328 8.152,7.5376 8.1504,7.5408" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1957,7.5573L8.1936,7.5563C8.1909,7.5547 8.1824,7.5488 8.1771,7.5467C8.1717,7.5445 8.1632,7.5445 8.1568,7.5445C8.1504,7.5445 8.1493,7.5445 8.1477,7.5435L8.1472,7.5403L8.1477,7.5403C8.1477,7.5339 8.1525,7.5307 8.1541,7.5301C8.1541,7.5291 8.1648,7.5184 8.1771,7.5184C8.1819,7.5184 8.1851,7.5195 8.1883,7.5216C8.2005,7.5323 8.2016,7.5445 8.2011,7.5488C8.2011,7.552 8.2011,7.5547 8.1984,7.5563L8.1957,7.5573Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1328,7.5093l-0.0101,0.0176l0.0261,0.0165l0.0032,-0.0032l0.0048,0l-0.0043,-0.0325l-0.0197,0.0016" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1541,7.544C8.1589,7.5408 8.1611,7.5365 8.1595,7.5328C8.1568,7.5312 8.1515,7.5312 8.1477,7.5328C8.1419,7.536 8.1403,7.5413 8.1413,7.544C8.1445,7.5445 8.1493,7.5445 8.1541,7.544" + android:strokeWidth="1" + android:fillColor="#C8B100" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.504,6.7947L9.4085,6.7947L9.4085,6.7653L9.4405,6.7653L9.4405,6.7307L9.4197,6.7307L9.4197,6.7019L9.4405,6.7019L9.4405,6.6811L9.4715,6.6811L9.4715,6.7019L9.4923,6.7019L9.4923,6.7307L9.4715,6.7307L9.4715,6.7653L9.5045,6.7653L9.5045,6.7947L9.504,6.7947ZM9.4192,6.7835L9.4949,6.7835L9.4949,6.7749L9.4608,6.7749L9.4608,6.72L9.4827,6.72L9.4827,6.7104L9.4608,6.7104L9.4608,6.6907L9.4507,6.6907L9.4507,6.7104L9.4293,6.7104L9.4293,6.72L9.4512,6.72L9.4512,6.7755L9.4192,6.7755L9.4192,6.7835Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_eu.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_eu.xml new file mode 100644 index 0000000000000000000000000000000000000000..8a53ac1d2b8a7ebe6eaf7c9588fd601f3a101f6e --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_eu.xml @@ -0,0 +1,18 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M12,2L12.2735,2.558L12.8845,2.647L12.4425,3.081L12.547,3.6945L12,3.405L11.4535,3.6945L11.558,3.081L11.116,2.647L11.727,2.558L12,2ZM9.373,2.791L9.6465,3.349L10.2575,3.4385L9.8155,3.8725L9.92,4.486L9.3735,4.1965L8.827,4.486L8.931,3.8725L8.489,3.4385L9.1005,3.349L9.373,2.791ZM7.5065,4.5245L7.78,5.0825L8.3915,5.1715L7.9495,5.6055L8.0535,6.219L7.507,5.9295L6.9605,6.219L7.065,5.6055L6.623,5.1715L7.234,5.0825L7.5065,4.5245ZM14.627,2.791L14.3535,3.349L13.7425,3.4385L14.1845,3.8725L14.08,4.486L14.6265,4.1965L15.173,4.486L15.069,3.8725L15.511,3.4385L14.8995,3.349L14.627,2.791ZM9.373,11.2225L9.6465,11.7805L10.2575,11.87L9.8155,12.304L9.92,12.9175L9.3735,12.628L8.827,12.9175L8.931,12.304L8.489,11.87L9.1005,11.7805L9.373,11.2225ZM14.627,11.2225L14.3535,11.7805L13.7425,11.87L14.1845,12.304L14.08,12.9175L14.6265,12.628L15.173,12.9175L15.069,12.304L15.511,11.87L14.8995,11.7805L14.627,11.2225ZM16.4935,4.5245L16.22,5.0825L15.6085,5.1715L16.0505,5.6055L15.9465,6.219L16.493,5.9295L17.0395,6.219L16.935,5.6055L17.377,5.1715L16.766,5.0825L16.4935,4.5245ZM7.5065,9.464L7.78,10.022L8.3915,10.1115L7.9495,10.5455L8.0535,11.159L7.507,10.8695L6.9605,11.159L7.065,10.5455L6.623,10.1115L7.234,10.022L7.5065,9.464ZM16.4935,9.464L16.22,10.022L15.6085,10.1115L16.0505,10.5455L15.9465,11.159L16.493,10.8695L17.0395,11.159L16.935,10.5455L17.377,10.1115L16.766,10.022L16.4935,9.464ZM17.1155,7.1525L17.389,7.7105L18,7.8L17.558,8.234L17.6625,8.8475L17.116,8.558L16.5695,8.8475L16.674,8.234L16.2305,7.8L16.842,7.7105L17.1155,7.1525ZM6.8845,7.1525L7.158,7.7105L7.7695,7.8L7.327,8.234L7.4315,8.8475L6.885,8.558L6.3385,8.8475L6.443,8.234L6,7.8L6.611,7.7105L6.8845,7.1525ZM12,12.305L12.2735,12.863L12.8845,12.9525L12.4425,13.3865L12.5465,14L12,13.7105L11.4535,14L11.558,13.3865L11.116,12.9525L11.727,12.863L12,12.305Z" + android:strokeWidth="1" + android:fillColor="#FFEB3B" + android:fillType="nonZero" + android:strokeColor="#00000000"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_fi.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_fi.xml new file mode 100644 index 0000000000000000000000000000000000000000..508f22f3a7ff97c14299ae8a5591ac70f71b1613 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_fi.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0h24v16h-24z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,6h24v4.2667h-24z" + android:strokeWidth="1" + android:fillColor="#003580" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.6667,0h4v16h-4z" + android:strokeWidth="1" + android:fillColor="#003580" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_fr.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_fr.xml new file mode 100644 index 0000000000000000000000000000000000000000..db1fadc8372675e18398bf60913e752f05755318 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_fr.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M7.6364,0l8.7273,0l0,16l-8.7273,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M16.3636,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M-0,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_gr.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_gr.xml new file mode 100644 index 0000000000000000000000000000000000000000..8aaf3c23a235d16cc9ee2be41dbeddf592143fe1 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_gr.xml @@ -0,0 +1,22 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,16L24,16L24,14.1749L0,14.1749L0,16ZM0,12.4976L24,12.4976L24,10.6725L0,10.6725L0,12.4976ZM8.5489,3.5664L8.5489,1.8245L24,1.8245L24,0L-0.0002,0L-0.0002,8.9125L8.5489,8.9125L24,8.9056L24,7.0805L8.5489,7.0805L8.5489,5.4165L24,5.4165L24,3.5915L8.5762,3.5915L8.5762,5.4048L5.1878,5.4048L5.1878,8.9109L3.4102,8.9109L3.4102,5.4048L0.0008,5.4048L0.0008,3.5659L3.4102,3.5659L3.4102,-0.002L5.1878,-0.002L5.1878,3.5664L8.5489,3.5664Z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_hr.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_hr.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c1ce141612214134e986ff05d2a9b0daceca57e --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_hr.xml @@ -0,0 +1,88 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M24,5.33l-24,-0l-0,-5.33l24,-0z" + android:strokeWidth="1" + android:fillColor="#F44336" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M24,15.99l-24,-0l-0,-5.33l24,-0z" + android:strokeWidth="1" + android:fillColor="#0D47A1" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M24,10.66l-24,-0l-0,-5.33l24,-0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M12,12.2393C10.2976,12.2393 8.9122,10.8538 8.9122,9.1515L8.9122,5.4211L15.0878,5.4211L15.0878,9.1515C15.0878,10.8538 13.7024,12.2393 12,12.2393Z" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M14.9515,5.5575L14.9515,9.1515C14.9515,10.7791 13.6276,12.1029 12,12.1029C10.3724,12.1029 9.0485,10.7791 9.0485,9.1515L9.0485,5.5575L14.9515,5.5575M15.2242,5.2847L8.7758,5.2847L8.7758,9.1515C8.7758,10.9324 10.2191,12.3756 12,12.3756C13.7809,12.3756 15.2242,10.9324 15.2242,9.1515L15.2242,5.2847L15.2242,5.2847Z" + android:strokeWidth="1" + android:fillColor="#F44336" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.8393,5.4669L15.0595,5.4669L15.0595,6.8065L13.8393,6.8065L13.8393,5.4669ZM11.394,5.4669L12.6142,5.4669L12.6142,6.8065L11.394,6.8065L11.394,5.4669ZM8.9493,5.4669L10.1695,5.4669L10.1695,6.8065L8.9493,6.8065L8.9493,5.4669ZM13.8393,8.1555L15.0595,8.1555L15.0595,9.4951L13.8393,9.4951L13.8393,8.1555ZM11.394,8.1555L12.6142,8.1555L12.6142,9.4951L11.394,9.4951L11.394,8.1555ZM8.9493,8.1555L10.1695,8.1555L10.1695,9.4951L8.9493,9.4951L8.9493,8.1555ZM13.8393,11.5733C14.2402,11.2695 14.4502,10.9591 14.5304,10.8418L13.8393,10.8418L13.8393,11.5733ZM10.1684,11.5733C9.7675,11.2695 9.5575,10.9591 9.4773,10.8418L10.1684,10.8418L10.1684,11.5733ZM11.394,12.1275C11.394,12.1275 11.6116,12.188 12.0065,12.188C12.4009,12.188 12.6142,12.188 12.6142,12.188L12.6142,10.8418L11.394,10.8418L11.394,12.1275L11.394,12.1275ZM12.6158,9.4956L13.836,9.4956L13.836,10.8353L12.6158,10.8353L12.6158,9.4956ZM10.1705,9.4956L11.3907,9.4956L11.3907,10.8353L10.1705,10.8353L10.1705,9.4956ZM12.6158,6.8071L13.836,6.8071L13.836,8.1467L12.6158,8.1467L12.6158,6.8071ZM10.1705,6.8071L11.3907,6.8071L11.3907,8.1467L10.1705,8.1467L10.1705,6.8071Z" + android:strokeWidth="1" + android:fillColor="#F44336" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.1238,5.2793L8.4545,3.7662L8.9482,2.9578L9.8345,3.2873L10.242,4.8887C10.2415,4.8893 9.612,5.0529 9.1238,5.2793Z" + android:strokeWidth="1" + android:fillColor="#4FC3F7" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.406,4.6978L11.2729,3.0495L10.4536,2.576L9.834,3.2873L10.2431,4.8871C10.2436,4.8871 10.8895,4.7278 11.406,4.6978ZM12.5956,4.6978L12.7287,3.0495L13.548,2.576L14.1676,3.2873L13.7585,4.8871C13.7585,4.8871 13.1127,4.7278 12.5956,4.6978Z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M12.5956,4.6978L12.7287,3.0495L12.0011,2.45L11.2729,3.0495L11.406,4.6978C11.406,4.6978 12.1315,4.6422 12.5956,4.6978ZM14.8762,5.2793L15.5455,3.7662L15.0518,2.9578L14.1655,3.2873L13.758,4.8887C13.7585,4.8893 14.388,5.0529 14.8762,5.2793Z" + android:strokeWidth="1" + android:fillColor="#4FC3F7" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M14.8762,5.2793L15.5455,3.7662L15.0518,2.9578L14.1655,3.2873L13.758,4.8887C13.7585,4.8893 14.388,5.0529 14.8762,5.2793Z" + android:strokeWidth="1" + android:fillColor="#4FC3F7" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9376,3.6915C10.7984,3.4984 11.0662,3.4727 11.3062,3.4564L11.2735,3.0495L11.2713,3.0484C11.1153,3.0565 10.584,3.0996 9.8345,3.2889L9.9376,3.6915ZM11.3733,4.2876L11.34,3.8725C10.8409,3.8971 10.1918,4.0493 10.0391,4.0864L10.1449,4.4993C10.6598,4.3504 11.16,4.3018 11.3733,4.2876Z" + android:strokeWidth="1" + android:fillColor="#F44336" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.8595,4.4922C14.406,4.6318 14.8342,4.8085 15.0431,4.9029L15.3005,4.3209C14.7071,4.0438 14.1425,3.8998 14.0176,3.8698L13.8595,4.4922Z" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.8878,4.3798C14.0493,4.4158 14.4916,4.5304 15.0878,4.8015L15.258,4.4169C15.1129,4.3542 14.5042,4.0967 13.9904,3.9767L13.8878,4.3798Z" + android:strokeWidth="1" + android:fillColor="#F44336" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_hu.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_hu.xml new file mode 100644 index 0000000000000000000000000000000000000000..11981ea63f26c8590e715d86c32f8b08bf3f700c --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_hu.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,10.66l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#689F38" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.33l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,-0l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_ie.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_ie.xml new file mode 100644 index 0000000000000000000000000000000000000000..5866f260127cbcf8204fc1145da7381bc372bb07 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_ie.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M7.6364,0l8.7273,0l0,16l-8.7273,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M16.3636,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#FF9800" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#689F38" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_is.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_is.xml new file mode 100644 index 0000000000000000000000000000000000000000..f1609e2208091fd749cb111b07653fe9ba2b8ee7 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_is.xml @@ -0,0 +1,40 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,6l24,0l0,4.3636l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0909,0l4.3636,0l0,16l-4.3636,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1818,0l2.1818,0l0,16l-2.1818,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,7.0909l24,0l0,2.1818l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_it.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_it.xml new file mode 100644 index 0000000000000000000000000000000000000000..732c0f51cf5f812b0f50d17bb022fb2b57d353fe --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_it.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M7.6364,0l8.7273,0l0,16l-8.7273,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M16.3636,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#689F38" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_li.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_li.xml new file mode 100644 index 0000000000000000000000000000000000000000..6bd23985f440f6ca7b2c2b9f7c965aab210b2b04 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_li.xml @@ -0,0 +1,590 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0h24v8h-24z" + android:strokeWidth="1" + android:fillColor="#002B7F" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,8h24v8h-24z" + android:strokeWidth="1" + android:fillColor="#CE1126" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M4.9191,3.431L4.875,4.931L3.3529,4.931C3.1657,4.567 3.011,4.2578 3.011,3.8391C3.011,3.4887 3.2866,3.2104 3.6838,3.2104C4.1043,3.2104 4.5662,3.3521 4.9191,3.431Z" + android:strokeLineJoin="round" + android:strokeWidth="1" + android:fillColor="#FFD83D" + android:fillType="nonZero" + android:strokeColor="#00000000" + android:strokeLineCap="round"/> + <path + android:pathData="M3.231,3.4999L3.231,4.3657" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.3532,3.4116L3.3532,4.5644" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.4755,3.3509L3.4755,4.7243" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.5977,3.3226L3.5977,4.3997" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.72,3.3172L3.72,4.4051" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.8422,3.2792L3.8422,4.4045" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.9644,3.2792L3.9644,4.4045" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.0867,3.2902L4.0867,4.4155" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.2089,3.3013L4.2089,4.4265" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.3312,3.373L4.3312,4.4982" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.4534,3.384L4.4534,4.6526" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.5757,3.384L4.5757,4.5092" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.6979,3.384L4.6979,4.5092" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.9595,3.3262C4.2179,3.3688 4.7853,3.6343 4.7206,3.9935C4.6288,4.5025 4.3316,4.2982 3.9375,4.2251L3.6397,4.3244C3.5331,4.4331 3.3762,4.5328 3.2702,4.4016L3.0937,4.4016L3.0937,5.0909L5.0459,5.0909L5.0459,3.4255L3.9595,3.3262Z" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#000000" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.8336,3.2077m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.5672,3.1435m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.2968,3.0756m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.0255,3.0304m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.7541,3.0036m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.488,3.0188m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.2343,3.1056m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M3.0207,3.2628m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M2.869,3.482m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M2.7959,3.7398m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M2.7987,4.0073m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M2.8497,4.2692m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M4.886,3.3648L4.875,3.5192C4.58,3.474 4.1618,3.3097 3.772,3.3097C3.4119,3.3097 3.1323,3.4537 3.1323,3.817C3.1323,4.1751 3.284,4.5007 3.4853,4.8317L3.2757,4.931C3.0884,4.567 2.9338,4.2578 2.9338,3.8391C2.9338,3.4887 3.2094,3.1442 3.6838,3.1442C4.1043,3.1442 4.5332,3.2859 4.886,3.3648Z" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.1875,3.431L5.2316,4.931L6.7537,4.931C6.9409,4.567 7.0956,4.2578 7.0956,3.8391C7.0956,3.4887 6.82,3.2104 6.4228,3.2104C6.0023,3.2104 5.5403,3.3521 5.1875,3.431Z" + android:strokeLineJoin="round" + android:strokeWidth="1" + android:fillColor="#FFD83D" + android:fillType="nonZero" + android:strokeColor="#00000000" + android:strokeLineCap="round"/> + <path + android:pathData="M6.8756,3.4999L6.8756,4.3657" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.7533,3.4116L6.7533,4.5644" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.6311,3.3509L6.6311,4.7243" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.5089,3.3226L6.5089,4.3997" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.3866,3.3172L6.3866,4.4051" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.2644,3.2792L6.2644,4.4045" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.1421,3.2792L6.1421,4.4045" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.0199,3.2902L6.0199,4.4155" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.8977,3.3013L5.8977,4.4265" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.7754,3.373L5.7754,4.4982" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.6532,3.384L5.6532,4.6526" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.5309,3.384L5.5309,4.5092" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.4087,3.384L5.4087,4.5092" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.147,3.3262C5.8887,3.3688 5.3213,3.6343 5.386,3.9935C5.4777,4.5025 5.775,4.2982 6.1691,4.2251L6.4669,4.3244C6.5735,4.4331 6.7304,4.5328 6.8364,4.4016L7.0129,4.4016L7.0129,5.0909L5.0607,5.0909L5.0607,3.4255L6.147,3.3262Z" + android:strokeLineJoin="round" + android:strokeWidth="0.05" + android:fillColor="#000000" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.273,3.2077m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.5394,3.1435m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.8097,3.0756m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.0811,3.0304m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.3525,3.0036m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.6186,3.0188m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M6.8722,3.1056m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M7.0859,3.2628m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M7.2376,3.482m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M7.3107,3.7398m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M7.3079,4.0073m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M7.2569,4.2692m1,0a1,1 0,1 0,-2 0a1,1 0,1 0,2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.2206,3.3648L5.2316,3.5192C5.5266,3.474 5.9448,3.3097 6.3345,3.3097C6.6947,3.3097 6.9743,3.4537 6.9743,3.817C6.9743,4.1751 6.8226,4.5007 6.6213,4.8317L6.8309,4.931C7.0181,4.567 7.1728,4.2578 7.1728,3.8391C7.1728,3.4887 6.8972,3.1442 6.4228,3.1442C6.0023,3.1442 5.5734,3.2859 5.2206,3.3648Z" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0533,1.7711L4.9295,2.0028L5.0533,2.2338L5.177,2.0028L5.0533,1.7711ZM5.0533,2.3561L4.9295,2.5871L5.0533,2.8188L5.177,2.5871L5.0533,2.3561Z" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:fillType="nonZero" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M4.6121,2.2949L4.8073,2.4187L5.0018,2.2949L4.8073,2.1712L4.6121,2.2949ZM5.1048,2.2949L5.2993,2.4187L5.4944,2.2949L5.2993,2.1712L5.1048,2.2949Z" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:fillType="nonZero" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0533,2.2977m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:fillType="nonZero" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0533,2.8961m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:fillType="nonZero" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M4.9903,2.6531C4.9903,2.7278 4.9898,2.7712 4.9895,2.8121C4.929,2.8148 4.8694,2.8211 4.811,2.8308M5.2955,2.8308C5.2372,2.8211 5.1775,2.8148 5.117,2.8121C5.117,2.7713 5.117,2.728 5.117,2.6531M4.8103,3.0276C4.8894,2.9726 4.9705,2.9433 5.0533,2.9433C5.1361,2.9433 5.2172,2.9726 5.2963,3.0276" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:fillType="evenOdd" + android:strokeLineCap="round"/> + <path + android:pathData="M4.808,3.3206C4.7842,3.7305 4.7358,4.1481 4.5763,4.4516L4.8358,4.3466C4.9264,4.0027 4.9455,3.5583 4.973,3.3483L4.808,3.3206ZM5.2985,3.3206L5.1335,3.3483C5.1611,3.5583 5.1802,4.0027 5.2708,4.3466L5.5303,4.4516C5.3707,4.1481 5.3223,3.7305 5.2985,3.3206Z" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:fillType="nonZero" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0529,4.2086C4.743,4.2086 4.5153,4.3546 4.5017,4.7268C4.4259,4.5935 4.1054,4.1742 3.8064,4.2303C3.6286,4.2637 3.4714,4.5103 3.4982,4.7928C3.3509,4.3697 2.9196,4.3004 2.6049,4.5506C2.8843,4.7803 3.0086,5.4586 3.2439,5.7528L5.0529,5.7528L6.8619,5.7528C7.0972,5.4586 7.2223,4.7803 7.5017,4.5506C7.187,4.3004 6.7557,4.3697 6.6084,4.7928C6.6351,4.5103 6.4773,4.2637 6.2994,4.2303C6.0004,4.1742 5.6807,4.5935 5.6049,4.7268C5.5912,4.3546 5.3628,4.2086 5.0529,4.2086Z" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:fillType="nonZero" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M6.8566,5.7527C6.8566,5.8866 6.0487,6.0339 5.0533,6.0339C4.0579,6.0339 3.25,5.8866 3.25,5.7527C3.25,5.6187 4.0579,5.5486 5.0533,5.5486C6.0487,5.5486 6.8566,5.6187 6.8566,5.7527Z" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#000000" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0533,3.2427m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0533,3.4247m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0533,3.6205m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0533,3.8383m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0533,4.081m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + <path + android:pathData="M5.0275,4.317C5.001,4.3168 4.9759,4.328 4.9826,4.3493C4.9904,4.3743 5.0002,4.4211 5.0095,4.4528C5.0201,4.4886 5.0619,4.4799 5.0725,4.452C5.0831,4.4241 5.0788,4.4063 5.0815,4.3545C5.0828,4.3286 5.054,4.3172 5.0275,4.317ZM5.129,4.317C5.1025,4.3172 5.0737,4.3286 5.0751,4.3545C5.0777,4.4063 5.0734,4.4241 5.0841,4.452C5.0947,4.4799 5.1364,4.4886 5.147,4.4528C5.1563,4.4211 5.1661,4.3743 5.1739,4.3493C5.1806,4.328 5.1555,4.3168 5.129,4.317ZM4.9457,4.3305C4.9193,4.3322 4.892,4.3444 4.8936,4.3575C4.8964,4.3814 4.9108,4.41 4.9164,4.446C4.9221,4.4832 4.979,4.4687 4.9848,4.4475C4.9905,4.4263 4.997,4.3949 4.9913,4.3538C4.9891,4.3383 4.9745,4.3315 4.9571,4.3305C4.9535,4.3303 4.9494,4.3303 4.9457,4.3305ZM5.2034,4.3305C5.186,4.3315 5.1714,4.3383 5.1692,4.3538C5.1635,4.3949 5.17,4.4263 5.1758,4.4475C5.1815,4.4687 5.2384,4.4832 5.2441,4.446C5.2497,4.41 5.2641,4.3814 5.2669,4.3575C5.2685,4.3444 5.2412,4.3322 5.2148,4.3305C5.2111,4.3303 5.2071,4.3303 5.2034,4.3305ZM4.84,4.3725C4.8129,4.3754 4.7881,4.3887 4.7962,4.404C4.8123,4.4345 4.8272,4.4683 4.8272,4.4993C4.8272,4.5258 4.8823,4.5163 4.8855,4.4978C4.8887,4.4792 4.8947,4.4398 4.8947,4.404C4.8947,4.3773 4.867,4.3696 4.84,4.3725ZM5.3073,4.3725C5.2881,4.3747 5.2708,4.3839 5.2708,4.404C5.2708,4.4398 5.2767,4.4792 5.2799,4.4978C5.2831,4.5163 5.3382,4.5258 5.3382,4.4993C5.3382,4.4683 5.3531,4.4345 5.3692,4.404C5.3773,4.3887 5.3525,4.3754 5.3255,4.3725C5.3187,4.3718 5.3136,4.3718 5.3073,4.3725ZM3.8727,4.3766C3.8554,4.3762 3.8433,4.3942 3.8551,4.4141C3.8741,4.446 3.8943,4.4661 3.9136,4.5004C3.9309,4.5309 3.9573,4.5119 3.9487,4.4906C3.9401,4.4694 3.9307,4.4457 3.9048,4.4006C3.8951,4.3837 3.883,4.3769 3.8727,4.3766ZM6.257,4.3766C6.2466,4.3769 6.2345,4.3837 6.2248,4.4006C6.1989,4.4457 6.1896,4.4694 6.1809,4.4906C6.1723,4.5119 6.1988,4.5309 6.216,4.5004C6.2354,4.4661 6.2555,4.446 6.2745,4.4141C6.2864,4.3942 6.2742,4.3762 6.257,4.3766ZM3.9684,4.3781C3.9547,4.3811 3.9464,4.3935 3.9547,4.4081C3.9715,4.4373 3.9956,4.4672 4.0124,4.4989C4.0273,4.5267 4.0603,4.5188 4.0491,4.4936C4.038,4.4684 4.0347,4.4536 4.0124,4.4059C4.0013,4.382 3.9821,4.3751 3.9684,4.3781ZM6.1562,4.3781C6.1445,4.3799 6.131,4.388 6.1226,4.4059C6.1004,4.4536 6.0971,4.4684 6.0859,4.4936C6.0748,4.5188 6.1078,4.5267 6.1226,4.4989C6.1395,4.4672 6.1636,4.4373 6.1803,4.4081C6.1887,4.3935 6.1804,4.3811 6.1667,4.3781C6.1633,4.3774 6.1601,4.3775 6.1562,4.3781ZM4.0897,4.4014C4.0728,4.4037 4.0597,4.4225 4.0712,4.4456C4.0858,4.4748 4.1065,4.5024 4.1247,4.5356C4.1428,4.5688 4.173,4.5621 4.1658,4.5409C4.1585,4.5196 4.1496,4.4844 4.1277,4.4314C4.1182,4.4081 4.1029,4.3995 4.0897,4.4014ZM6.0439,4.4014C6.0307,4.3995 6.0154,4.4081 6.0059,4.4314C5.984,4.4844 5.9751,4.5196 5.9678,4.5409C5.9606,4.5621 5.9908,4.5688 6.0089,4.5356C6.0271,4.5024 6.0478,4.4748 6.0624,4.4456C6.0739,4.4225 6.0608,4.4037 6.0439,4.4014ZM3.7994,4.4179C3.7774,4.4192 3.7574,4.441 3.771,4.4576C3.7929,4.4842 3.8067,4.4932 3.8277,4.5214C3.8496,4.5506 3.8735,4.5279 3.8647,4.5094C3.856,4.4908 3.8448,4.4691 3.8339,4.4426C3.8259,4.4232 3.8126,4.417 3.7994,4.4179ZM6.3464,4.4179C6.3332,4.417 6.3198,4.4232 6.3118,4.4426C6.3009,4.4691 6.2897,4.4908 6.281,4.5094C6.2723,4.5279 6.2962,4.5506 6.318,4.5214C6.3391,4.4932 6.3529,4.4842 6.3747,4.4576C6.3883,4.441 6.3683,4.4192 6.3464,4.4179ZM4.7283,4.485C4.7047,4.485 4.6796,4.5036 4.688,4.521C4.7013,4.5489 4.722,4.5736 4.7371,4.6095C4.7505,4.6414 4.7885,4.6255 4.7862,4.6043C4.784,4.583 4.7779,4.5541 4.7623,4.509C4.7564,4.4921 4.7424,4.485 4.7283,4.485ZM5.4188,4.485C5.4047,4.485 5.3906,4.4921 5.3848,4.509C5.3692,4.5541 5.3631,4.583 5.3608,4.6043C5.3586,4.6255 5.3966,4.6414 5.41,4.6095C5.425,4.5736 5.4457,4.5489 5.4591,4.521C5.4675,4.5036 5.4423,4.485 5.4188,4.485ZM5.0533,4.5135C5.036,4.5135 5.0336,4.5367 5.033,4.5555C5.0311,4.6172 5.0054,4.6772 4.9835,4.707C4.9616,4.7369 4.9294,4.7289 4.8995,4.713C4.8697,4.6971 4.8519,4.6852 4.82,4.6613C4.7882,4.6374 4.764,4.6513 4.802,4.7055C4.9129,4.8634 5.033,4.9984 5.033,5.256C5.033,5.2893 5.0389,5.2995 5.0533,5.2995C5.0677,5.2995 5.0743,5.2893 5.0743,5.256C5.0743,4.9984 5.1937,4.8634 5.3045,4.7055C5.3425,4.6513 5.3184,4.6374 5.2865,4.6613C5.2547,4.6852 5.2369,4.6971 5.207,4.713C5.1772,4.7289 5.1449,4.7369 5.123,4.707C5.1011,4.6772 5.0755,4.6172 5.0735,4.5555C5.0729,4.5367 5.0705,4.5135 5.0533,4.5135ZM4.2166,4.4749C4.214,4.4748 4.2111,4.4752 4.2087,4.4756C4.1975,4.4776 4.19,4.4854 4.1943,4.4989C4.2021,4.5229 4.2312,4.5701 4.2428,4.5926C4.2544,4.6152 4.3029,4.6104 4.2913,4.5799C4.2797,4.5493 4.2803,4.5401 4.2664,4.5056C4.2588,4.4867 4.2351,4.4752 4.2166,4.4749ZM5.9327,4.4749C5.9143,4.4752 5.8906,4.4867 5.8829,4.5056C5.869,4.5401 5.8697,4.5493 5.858,4.5799C5.8465,4.6104 5.8949,4.6152 5.9065,4.5926C5.9181,4.5701 5.9472,4.5229 5.955,4.4989C5.9594,4.4854 5.9519,4.4776 5.9406,4.4756C5.9383,4.4752 5.9354,4.4748 5.9327,4.4749ZM3.7067,4.4846C3.6899,4.4857 3.678,4.5032 3.6949,4.5289C3.7132,4.5566 3.7446,4.5915 3.759,4.6114C3.7734,4.6313 3.7982,4.6178 3.7807,4.5926C3.7631,4.5674 3.7572,4.5384 3.7364,4.5026C3.7287,4.4892 3.7167,4.484 3.7067,4.4846ZM6.4168,4.4846C6.4068,4.484 6.3948,4.4892 6.387,4.5026C6.3663,4.5384 6.3604,4.5674 6.3428,4.5926C6.3252,4.6178 6.3501,4.6313 6.3645,4.6114C6.3788,4.5915 6.4102,4.5566 6.4285,4.5289C6.4455,4.5032 6.4335,4.4857 6.4168,4.4846ZM2.9441,4.5645C2.9267,4.5637 2.9212,4.5926 2.9376,4.6118C2.9615,4.6396 2.9781,4.6544 3.0054,4.677C3.0271,4.6949 3.0334,4.6717 3.0226,4.6538C3.0117,4.6358 2.9961,4.6176 2.9744,4.5878C2.9625,4.5714 2.9521,4.5649 2.9441,4.5645ZM7.1707,4.5645C7.1627,4.5649 7.1523,4.5714 7.1404,4.5878C7.1187,4.6176 7.1031,4.6358 7.0922,4.6538C7.0814,4.6717 7.0877,4.6949 7.1094,4.677C7.1367,4.6544 7.1533,4.6396 7.1772,4.6118C7.1936,4.5926 7.1881,4.5637 7.1707,4.5645ZM3.066,4.5885C3.0512,4.5887 3.0415,4.5981 3.053,4.62C3.0694,4.6514 3.0912,4.6869 3.105,4.7108C3.1188,4.7346 3.1609,4.7427 3.144,4.7055C3.1271,4.6684 3.1238,4.6493 3.1084,4.6148C3.1008,4.5975 3.0807,4.5883 3.066,4.5885ZM7.0541,4.5885C7.0393,4.5883 7.0193,4.5975 7.0116,4.6148C6.9963,4.6493 6.9929,4.6684 6.9761,4.7055C6.9592,4.7427 7.0013,4.7346 7.0151,4.7108C7.0289,4.6869 7.0506,4.6514 7.0671,4.62C7.0786,4.5981 7.0688,4.5887 7.0541,4.5885ZM2.8295,4.5968C2.811,4.597 2.8094,4.6165 2.8258,4.6291C2.8477,4.6458 2.8738,4.6644 2.8993,4.6858C2.9291,4.7109 2.9407,4.6878 2.9248,4.6669C2.9089,4.646 2.8934,4.6248 2.8535,4.6039C2.8436,4.5986 2.8357,4.5967 2.8295,4.5968ZM7.277,4.5968C7.2708,4.5967 7.263,4.5986 7.253,4.6039C7.2132,4.6248 7.1977,4.646 7.1818,4.6669C7.1659,4.6878 7.1774,4.7109 7.2073,4.6858C7.2328,4.6644 7.2589,4.6458 7.2808,4.6291C7.2972,4.6165 7.2956,4.597 7.277,4.5968ZM4.6577,4.614C4.6393,4.6155 4.6234,4.6273 4.6312,4.6425C4.6453,4.6704 4.6613,4.6999 4.671,4.7288C4.6804,4.7566 4.7375,4.757 4.7281,4.7318C4.7187,4.7065 4.714,4.675 4.6976,4.6365C4.6914,4.6221 4.6785,4.6151 4.6657,4.614C4.663,4.6138 4.6604,4.6138 4.6577,4.614ZM5.4844,4.614C5.4716,4.6151 5.4587,4.6221 5.4525,4.6365C5.4361,4.675 5.4314,4.7065 5.422,4.7318C5.4126,4.757 5.4697,4.7566 5.4791,4.7288C5.4889,4.6999 5.5049,4.6704 5.519,4.6425C5.5267,4.6273 5.5108,4.6155 5.4924,4.614C5.4898,4.6138 5.4871,4.6138 5.4844,4.614ZM3.923,4.5664C3.9149,4.5686 3.9102,4.5842 3.9163,4.6061C3.9501,4.7275 3.9605,4.7915 3.9545,4.8214C3.9486,4.8512 3.9322,4.8553 3.9103,4.8454C3.8884,4.8354 3.8627,4.821 3.8428,4.8071C3.8229,4.7932 3.8022,4.8098 3.8308,4.8334C3.9761,4.9528 4.0768,5.0893 4.1158,5.2549C4.1238,5.2887 4.145,5.2927 4.139,5.2549C4.1061,5.0463 4.0998,4.8749 4.1495,4.7674C4.1682,4.727 4.1494,4.6882 4.1195,4.7539C4.0996,4.7977 4.0674,4.8149 4.0415,4.7771C4.0157,4.7393 3.9622,4.6384 3.9463,4.5926C3.9403,4.5754 3.9329,4.5675 3.9268,4.5664C3.9255,4.5661 3.9242,4.566 3.923,4.5664ZM6.1798,4.5664C6.1736,4.5675 6.1663,4.5754 6.1603,4.5926C6.1444,4.6384 6.0909,4.7393 6.065,4.7771C6.0392,4.8149 6.0069,4.7977 5.987,4.7539C5.9572,4.6882 5.9383,4.727 5.957,4.7674C6.0068,4.8749 6.0005,5.0463 5.9675,5.2549C5.9616,5.2927 5.9828,5.2887 5.9908,5.2549C6.0297,5.0893 6.1305,4.9528 6.2758,4.8334C6.3044,4.8098 6.2837,4.7932 6.2638,4.8071C6.2439,4.821 6.2182,4.8354 6.1963,4.8454C6.1744,4.8553 6.158,4.8512 6.152,4.8214C6.1461,4.7915 6.1564,4.7275 6.1903,4.6061C6.1964,4.5842 6.1917,4.5686 6.1835,4.5664C6.1824,4.566 6.1811,4.5661 6.1798,4.5664ZM3.2045,4.6245C3.1834,4.6247 3.166,4.6339 3.1756,4.6538C3.191,4.6856 3.2228,4.7201 3.2335,4.74C3.2441,4.7599 3.2785,4.7506 3.2721,4.7228C3.2657,4.6949 3.2625,4.6783 3.254,4.6478C3.2497,4.6325 3.2256,4.6243 3.2045,4.6245ZM6.9399,4.6245C6.9188,4.6243 6.8947,4.6325 6.8904,4.6478C6.8819,4.6783 6.8787,4.6949 6.8723,4.7228C6.8659,4.7506 6.9003,4.7599 6.9109,4.74C6.9216,4.7201 6.9534,4.6856 6.9688,4.6538C6.9784,4.6339 6.961,4.6247 6.9399,4.6245ZM3.6435,4.5829C3.628,4.5801 3.6258,4.6194 3.6389,4.6354C3.6564,4.6566 3.6807,4.6823 3.705,4.7111C3.7252,4.735 3.7377,4.7138 3.7256,4.6939C3.7135,4.674 3.6955,4.6528 3.6632,4.6024C3.6552,4.5898 3.6486,4.5838 3.6435,4.5829ZM6.4644,4.5829C6.4593,4.5838 6.4528,4.5898 6.4447,4.6024C6.4124,4.6528 6.3945,4.674 6.3824,4.6939C6.3702,4.7138 6.3827,4.735 6.4029,4.7111C6.4272,4.6823 6.4515,4.6566 6.469,4.6354C6.4821,4.6194 6.4799,4.5801 6.4644,4.5829ZM3.3129,4.6778C3.292,4.6771 3.2743,4.6848 3.2831,4.704C3.2953,4.7308 3.3131,4.753 3.3278,4.7783C3.3424,4.8035 3.3807,4.7992 3.3807,4.7753C3.3807,4.7514 3.3713,4.7247 3.3625,4.6995C3.3581,4.6869 3.3337,4.6784 3.3129,4.6778ZM6.8484,4.6778C6.8275,4.6784 6.8031,4.6869 6.7988,4.6995C6.79,4.7247 6.7805,4.7514 6.7805,4.7753C6.7805,4.7992 6.8189,4.8035 6.8335,4.7783C6.8482,4.753 6.866,4.7308 6.8782,4.704C6.887,4.6848 6.8693,4.6771 6.8484,4.6778ZM3.6095,4.7119C3.5947,4.7141 3.5816,4.7285 3.599,4.7509C3.6269,4.7867 3.6574,4.8118 3.668,4.8251C3.6787,4.8384 3.7055,4.8335 3.6883,4.8056C3.6707,4.7771 3.644,4.7428 3.632,4.7216C3.6276,4.7137 3.6185,4.7105 3.6095,4.7119ZM6.491,4.7119C6.4845,4.7125 6.4779,4.7156 6.4745,4.7216C6.4626,4.7428 6.4359,4.7771 6.4183,4.8056C6.401,4.8335 6.4279,4.8384 6.4385,4.8251C6.4492,4.8118 6.4797,4.7867 6.5075,4.7509C6.525,4.7285 6.5119,4.7141 6.497,4.7119C6.4948,4.7115 6.4932,4.7116 6.491,4.7119ZM3.1138,4.812C3.1021,4.8109 3.098,4.8204 3.1138,4.842C3.1496,4.8911 3.1891,4.9654 3.1918,4.9973C3.1945,5.0291 3.1787,5.0288 3.164,5.0288C3.1202,5.0288 3.0988,4.9968 3.059,4.9875C3.0192,4.9782 3.0134,4.9992 3.0418,5.0198C3.1878,5.1259 3.3341,5.2444 3.3928,5.352C3.4167,5.3958 3.449,5.4118 3.431,5.37C3.3761,5.2419 3.3628,5.1335 3.3748,5.0678C3.3867,5.0021 3.403,4.9578 3.401,4.92C3.399,4.8822 3.3776,4.8848 3.3688,4.92C3.3628,4.9439 3.3513,4.9756 3.3433,4.9875C3.3353,4.9995 3.3033,5.0061 3.2728,4.965C3.2423,4.9239 3.1653,4.8447 3.14,4.8248C3.1306,4.8173 3.1208,4.8126 3.1138,4.812ZM6.9928,4.812C6.9858,4.8126 6.976,4.8173 6.9665,4.8248C6.9413,4.8447 6.8643,4.9239 6.8338,4.965C6.8033,5.0061 6.7713,4.9995 6.7633,4.9875C6.7553,4.9756 6.7438,4.9439 6.7378,4.92C6.729,4.8848 6.7075,4.8822 6.7055,4.92C6.7035,4.9578 6.7198,5.0021 6.7318,5.0678C6.7437,5.1335 6.7304,5.2419 6.6755,5.37C6.6576,5.4118 6.6899,5.3958 6.7138,5.352C6.7725,5.2444 6.9188,5.1259 7.0648,5.0198C7.0931,4.9992 7.0874,4.9782 7.0475,4.9875C7.0077,4.9968 6.9863,5.0288 6.9425,5.0288C6.9279,5.0288 6.9121,5.0291 6.9148,4.9973C6.9174,4.9654 6.957,4.8911 6.9928,4.842C7.0086,4.8204 7.0045,4.8109 6.9928,4.812Z" + android:strokeLineJoin="round" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000" + android:strokeLineCap="round"/> + <path + android:pathData="M3.3291,5.5997L3.4291,5.7479M3.4253,5.5716L3.5253,5.7214M3.5293,5.5545L3.6293,5.7073M3.6258,5.5352L3.7258,5.6876M3.7495,5.523L3.8495,5.6764M3.8812,5.5232L3.9812,5.6762M4.0171,5.4797L4.0975,5.6339M4.138,5.4875L4.2184,5.6417M4.255,5.4719L4.3353,5.6261M4.3861,5.4598L4.4303,5.6148M4.5139,5.4597L4.5522,5.6149M4.6298,5.4519L4.6624,5.6071M4.7573,5.4441L4.7845,5.5993M4.9016,5.4402L4.9287,5.5954M6.8307,5.5997L6.7307,5.7479M6.7398,5.5716L6.6398,5.7214M6.6488,5.5545L6.5488,5.7073M6.5503,5.5352L6.4503,5.6876M6.4323,5.523L6.3323,5.6764M6.2987,5.5232L6.1987,5.6762M6.1655,5.4797L6.0851,5.6339M6.0446,5.4875L5.9642,5.6417M5.9276,5.4719L5.8472,5.6261M5.7964,5.4598L5.7522,5.6148M5.6687,5.4597L5.6304,5.6149M5.5528,5.4519L5.5201,5.6071M5.4252,5.4441L5.3981,5.5993M5.281,5.4402L5.2538,5.5954M5.0913,5.4301L5.0913,5.601" + android:strokeLineJoin="round" + android:strokeWidth="0.01" + android:fillColor="#FFD83D" + android:strokeColor="#000000" + android:fillType="nonZero" + android:strokeLineCap="round"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_lt.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_lt.xml new file mode 100644 index 0000000000000000000000000000000000000000..9fe84631800b0af02d0cf70d60afb63ab3da3241 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_lt.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,10.66l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.33l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#689F38" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,-0l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#FFEB3B" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_lu.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_lu.xml new file mode 100644 index 0000000000000000000000000000000000000000..e530dac7ebc0010aeb0a2721b59c0cf76d85cfcd --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_lu.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,-0l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#F44336" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.33l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,10.66l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#64B5F6" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_lv.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_lv.xml new file mode 100644 index 0000000000000000000000000000000000000000..45c635d9384a677aa326683e28f2f1988d8f4ff6 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_lv.xml @@ -0,0 +1,22 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#B71C1C" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,6l24,0l0,4.3636l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_mt.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_mt.xml new file mode 100644 index 0000000000000000000000000000000000000000..de07d43126dae2d530bd63a9a82567bd0646803c --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_mt.xml @@ -0,0 +1,388 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M12,0h12v16h-12z" + android:strokeWidth="1" + android:fillColor="#CF142B" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0h12v16h-12z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0.5925,2.2088L0.5925,3.4211L1.8048,3.4211C1.8048,3.6229 2.0067,3.8251 2.2088,3.8251L2.2088,5.0371L3.4208,5.0371L3.4208,3.8251C3.6229,3.8251 3.8248,3.6229 3.8248,3.4211L5.0371,3.4211L5.0371,2.2088L3.8248,2.2088C3.8248,2.0067 3.6229,1.8048 3.4208,1.8048L3.4208,0.5925L2.2088,0.5925L2.2088,1.8048C2.0067,1.8048 1.8048,2.0067 1.8048,2.2088L0.5925,2.2088Z" + android:strokeWidth="1" + android:fillColor="#E60D2E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0.6733,2.2896L0.6733,3.34L1.8856,3.34C1.8856,3.5421 2.0875,3.744 2.2896,3.744L2.2896,4.9563L3.34,4.9563L3.34,3.744C3.5421,3.744 3.744,3.5421 3.744,3.34L4.956,3.34L4.956,2.2896L3.744,2.2896C3.744,2.0875 3.5421,1.8856 3.34,1.8856L3.34,0.6733L2.2896,0.6733L2.2896,1.8856C2.0875,1.8856 1.8856,2.0875 1.8856,2.2896L0.6733,2.2896Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0.7139,2.3299L0.7139,3.2997L1.9259,3.2997C1.9259,3.5016 2.128,3.7037 2.3299,3.7037L2.3299,4.9157L3.2997,4.9157L3.2997,3.7037C3.5016,3.7037 3.7037,3.5016 3.7037,3.2997L4.9157,3.2997L4.9157,2.3299L3.7037,2.3299C3.7037,2.128 3.5016,1.9259 3.2997,1.9259L3.2997,0.7139L2.3299,0.7139L2.3299,1.9259C2.128,1.9259 1.9259,2.128 1.9259,2.3299L0.7139,2.3299Z" + android:strokeWidth="1" + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.2544,1.9115C2.3253,1.9824 2.3061,2.1168 2.2115,2.2115C2.1168,2.3061 1.9824,2.3253 1.9115,2.2544C1.8405,2.1835 1.8597,2.0491 1.9544,1.9544C2.0491,1.8597 2.1832,1.84 2.2544,1.9115Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M1.8971,2.1256l0.0285,-0.0285l0.1144,0.0571l-0.0571,-0.1141l0.0285,-0.0285l0.1141,0.2285l-0.2285,-0.1144z" + android:strokeWidth="1" + android:fillColor="#D0D0D0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.0685,1.9544l0.0285,-0.0285l0.1715,0.1712l-0.0285,0.0288z" + android:strokeWidth="1" + android:fillColor="#D0D0D0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.7181,2.2544C3.6472,2.3253 3.5128,2.3061 3.4181,2.2115C3.3235,2.1168 3.3043,1.9824 3.3752,1.9115C3.4461,1.8405 3.5805,1.8597 3.6752,1.9544C3.7699,2.0491 3.7891,2.1835 3.7181,2.2544Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.504,1.8971l0.0285,0.0288l-0.0571,0.1141l0.1141,-0.0571l0.0285,0.0285l-0.2285,0.1144z" + android:strokeWidth="1" + android:fillColor="#D0D0D0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.6752,2.0685l0.0288,0.0288l-0.1715,0.1712l-0.0285,-0.0285z" + android:strokeWidth="1" + android:fillColor="#D0D0D0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.3752,3.7181C3.3043,3.6472 3.3235,3.5128 3.4181,3.4181C3.5128,3.3235 3.6472,3.3043 3.7181,3.3755C3.7891,3.4467 3.7699,3.5808 3.6752,3.6755C3.5805,3.7701 3.4464,3.7893 3.3752,3.7181Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.7333,3.504l-0.0285,0.0285l-0.1144,-0.0571l0.0571,0.1141l-0.0285,0.0288l-0.1141,-0.2285z" + android:strokeWidth="1" + android:fillColor="#D0D0D0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.5611,3.6755l-0.0285,0.0285l-0.1725,-0.1715l0.0285,-0.0285z" + android:strokeWidth="1" + android:fillColor="#D0D0D0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M1.9115,3.3755C1.9824,3.3043 2.1168,3.3221 2.2115,3.4181C2.3061,3.5141 2.3253,3.6472 2.2544,3.7181C2.1835,3.7891 2.0491,3.7701 1.9544,3.6752C1.8597,3.5803 1.84,3.4464 1.9115,3.3755Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.1256,3.7333l-0.0285,-0.0285l0.0571,-0.1144l-0.1141,0.0573l-0.0285,-0.0288l0.2285,-0.1149z" + android:strokeWidth="1" + android:fillColor="#D0D0D0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M1.9544,3.5611l-0.0288,-0.0285l0.1715,-0.1725l0.0285,0.0285z" + android:strokeWidth="1" + android:fillColor="#D0D0D0" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8149,3.6704C2.4689,3.6705 2.1569,3.4621 2.0244,3.1425C1.8919,2.8228 1.965,2.4548 2.2097,2.2101C2.4543,1.9654 2.8223,1.8922 3.142,2.0246C3.4617,2.157 3.6701,2.4689 3.6701,2.8149C3.6695,3.287 3.287,3.6697 2.8149,3.6704ZM2.8149,1.9731C2.4744,1.973 2.1673,2.178 2.037,2.4926C1.9066,2.8072 1.9785,3.1693 2.2193,3.4101C2.46,3.651 2.8222,3.723 3.1368,3.5927C3.4514,3.4625 3.6565,3.1555 3.6565,2.8149C3.6559,2.3504 3.2795,1.9739 2.8149,1.9733L2.8149,1.9731Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8149,3.4683C2.5507,3.4683 2.3125,3.3091 2.2113,3.065C2.1102,2.8208 2.1661,2.5398 2.353,2.353C2.5398,2.1661 2.8208,2.1102 3.065,2.2113C3.3091,2.3125 3.4683,2.5507 3.4683,2.8149C3.4678,3.1756 3.1756,3.4678 2.8149,3.4683L2.8149,3.4683ZM2.8149,2.1752C2.4615,2.1752 2.1749,2.4617 2.1749,2.8152C2.1749,3.1687 2.4615,3.4552 2.8149,3.4552C3.1684,3.4552 3.4549,3.1687 3.4549,2.8152C3.4549,2.4617 3.1684,2.1752 2.8149,2.1752Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.5012,3.5113m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.1479,3.5113m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.788,3.5016L2.788,3.5437L2.7347,3.5437C2.6813,3.5437 2.6813,3.5859 2.7347,3.5859L2.788,3.5859L2.788,3.628C2.788,3.6717 2.8349,3.6771 2.8384,3.6317L2.8419,3.5861L2.8952,3.5861C2.9485,3.5861 2.9485,3.544 2.8952,3.544L2.8419,3.544L2.8419,3.5019C2.8419,3.4871 2.8299,3.4752 2.8152,3.4752C2.8005,3.4752 2.7885,3.4871 2.7885,3.5019L2.788,3.5016Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.0267,3.024L2.0824,3.0107L2.0763,2.984C2.0755,2.9792 2.0729,2.9749 2.0691,2.972C2.0639,2.9695 2.0581,2.9688 2.0525,2.9701L2.0525,2.9661L2.1005,2.9549L2.1005,2.9587C2.0964,2.9594 2.0924,2.9612 2.0891,2.9637C2.0869,2.9655 2.0853,2.9679 2.0845,2.9707C2.0836,2.9743 2.0836,2.9782 2.0845,2.9819L2.0907,3.0085L2.1352,2.9979C2.14,2.997 2.1447,2.9954 2.1491,2.9931C2.1508,2.9917 2.152,2.9898 2.1525,2.9877C2.1533,2.9844 2.1533,2.9809 2.1525,2.9776L2.1525,2.9723L2.1563,2.9723L2.1709,3.0328L2.1669,3.0328L2.1669,3.0277C2.1661,3.0229 2.163,3.0186 2.1587,3.0163C2.1531,3.0152 2.1474,3.0157 2.1421,3.0176L2.0507,3.0395C2.0459,3.0403 2.0412,3.0418 2.0368,3.044C2.0351,3.0454 2.0339,3.0473 2.0333,3.0493C2.0325,3.0528 2.0325,3.0563 2.0333,3.0597L2.0333,3.0645L2.0267,3.0667L2.0016,2.96L2.0325,2.9515L2.0325,2.9549C2.0276,2.9574 2.0232,2.9607 2.0195,2.9648C2.0171,2.9678 2.0155,2.9714 2.0149,2.9752C2.0145,2.9809 2.0152,2.9866 2.0168,2.992L2.0267,3.024ZM1.9896,2.7733C1.9905,2.7547 1.9993,2.7373 2.0139,2.7256C2.0286,2.7129 2.0478,2.7065 2.0672,2.7077C2.0874,2.7084 2.1066,2.7171 2.1205,2.7317C2.1338,2.7456 2.1407,2.7643 2.1395,2.7835C2.1387,2.8026 2.1299,2.8205 2.1152,2.8328C2.0995,2.8458 2.0792,2.852 2.0589,2.8499C2.0376,2.8494 2.0176,2.8397 2.004,2.8232C1.9922,2.8094 1.9864,2.7915 1.9877,2.7733L1.9896,2.7733ZM1.9973,2.7785C1.9962,2.7913 2.0009,2.804 2.0101,2.8124C2.0248,2.8249 2.0431,2.8315 2.0619,2.8311C2.0812,2.8336 2.1007,2.8291 2.1173,2.8184C2.1273,2.8111 2.1334,2.7992 2.1336,2.7864C2.1347,2.7726 2.1295,2.759 2.1197,2.7499C2.1056,2.7382 2.088,2.7321 2.0701,2.7326C2.0505,2.7299 2.0307,2.7342 2.0136,2.7448C2.0035,2.7526 1.9974,2.7651 1.9973,2.7785L1.9973,2.7785ZM2.2077,2.5091L2.1941,2.5453L2.1141,2.5672C2.1141,2.5707 2.112,2.5733 2.1112,2.5755C2.1104,2.5776 2.1112,2.5773 2.1112,2.5784C2.1111,2.5794 2.1111,2.5804 2.1112,2.5813L2.1507,2.5963C2.1558,2.5991 2.1616,2.6003 2.1675,2.5997C2.1717,2.5979 2.1749,2.5943 2.1763,2.5899L2.1784,2.5845L2.1821,2.5845L2.16,2.6429L2.1563,2.6413L2.1547,2.64C2.1571,2.6355 2.1571,2.6301 2.1547,2.6256C2.1506,2.622 2.1458,2.6194 2.1405,2.6179L2.0533,2.5835C2.0482,2.5808 2.0423,2.5797 2.0365,2.5803C2.0322,2.5821 2.0289,2.5857 2.0275,2.5901L2.0256,2.5952L2.0219,2.5952L2.0408,2.5456C2.0445,2.5347 2.0496,2.5244 2.056,2.5149C2.0607,2.5089 2.0671,2.5044 2.0744,2.5019C2.0818,2.4991 2.0899,2.4991 2.0973,2.5019C2.1053,2.5049 2.1119,2.5108 2.1157,2.5184C2.1202,2.5278 2.1214,2.5384 2.1192,2.5485L2.1688,2.5355C2.1774,2.5336 2.1856,2.5303 2.1931,2.5256C2.1983,2.5213 2.2026,2.5159 2.2056,2.5099L2.2091,2.5099L2.2077,2.5091ZM2.1351,2.6196C2.1349,2.6177 2.1349,2.6159 2.1351,2.6141L2.1351,2.61C2.1437,2.5938 2.1469,2.5749 2.1441,2.5566C2.1394,2.5422 2.1288,2.531 2.1154,2.526C2.1032,2.5205 2.0894,2.5205 2.0772,2.526C2.0651,2.5322 2.0558,2.5434 2.0515,2.557C2.0487,2.5661 2.0466,2.5754 2.0451,2.5849L2.1359,2.6219L2.1351,2.6196ZM2.4107,2.0989L2.4373,2.1352L2.4341,2.1373C2.4265,2.1307 2.4173,2.126 2.4075,2.1237C2.3954,2.1215 2.3829,2.1242 2.3728,2.1312C2.3581,2.1398 2.3492,2.1555 2.3493,2.1725C2.3494,2.1882 2.3542,2.2034 2.3632,2.2163C2.37,2.227 2.3791,2.2361 2.3899,2.2429C2.3992,2.2492 2.4101,2.2525 2.4213,2.2525C2.4308,2.2525 2.44,2.2499 2.448,2.2448C2.4524,2.2419 2.4564,2.2385 2.46,2.2347C2.4635,2.2307 2.4664,2.2263 2.4688,2.2216L2.4483,2.1867C2.446,2.1824 2.4428,2.1787 2.4389,2.1757C2.4368,2.1744 2.4342,2.1738 2.4317,2.1741C2.4277,2.175 2.4239,2.1768 2.4205,2.1792L2.4184,2.1757L2.4656,2.1453L2.4677,2.1488L2.4656,2.1501C2.4614,2.1521 2.4588,2.1564 2.4589,2.1611C2.4601,2.1663 2.4624,2.1712 2.4656,2.1755L2.4899,2.2128C2.4856,2.2205 2.4805,2.2276 2.4747,2.2341C2.4685,2.2406 2.4616,2.2464 2.4541,2.2512C2.4344,2.2658 2.4091,2.2702 2.3856,2.2632C2.3696,2.2582 2.3558,2.2477 2.3467,2.2336C2.3397,2.2228 2.3355,2.2104 2.3344,2.1976C2.333,2.1828 2.3356,2.1678 2.3421,2.1544C2.3483,2.1427 2.3575,2.133 2.3688,2.1261C2.3728,2.1234 2.3771,2.1211 2.3816,2.1192C2.3876,2.1171 2.3938,2.1154 2.4,2.1141C2.4028,2.1136 2.4055,2.1127 2.408,2.1115C2.4093,2.1108 2.41,2.1094 2.4099,2.108C2.4098,2.1055 2.409,2.1031 2.4075,2.1011L2.4109,2.0989L2.4107,2.0989ZM2.6472,2.1152L2.5939,2.1296L2.5901,2.1544C2.5895,2.1587 2.5895,2.1631 2.5901,2.1675C2.5908,2.1697 2.5925,2.1715 2.5947,2.1723C2.5993,2.1735 2.6042,2.1735 2.6088,2.1723L2.6088,2.176L2.5643,2.1867L2.5643,2.1827C2.5682,2.1812 2.5718,2.1788 2.5747,2.1757C2.5783,2.1684 2.5804,2.1604 2.5811,2.1523L2.5997,2.0237L2.6032,2.0237L2.6832,2.1275C2.6873,2.1337 2.6926,2.139 2.6989,2.1429C2.7037,2.1446 2.7089,2.1446 2.7136,2.1429L2.7136,2.1469L2.6584,2.1616L2.6584,2.1579C2.6624,2.1569 2.6661,2.1548 2.6691,2.152C2.67,2.1499 2.67,2.1475 2.6691,2.1453C2.6672,2.1405 2.6645,2.136 2.6611,2.132L2.6472,2.1141L2.6472,2.1152ZM2.6939,2.1376L2.6132,2.0579L2.5939,2.1579L2.6939,2.1376L2.6939,2.1376ZM2.8987,2.1083L2.9024,2.1083L2.8883,2.1472L2.776,2.1427L2.776,2.1387L2.7816,2.1387C2.7867,2.1393 2.7917,2.1373 2.7949,2.1333C2.7972,2.1284 2.7982,2.123 2.7979,2.1176L2.8013,2.0237C2.8024,2.018 2.8016,2.012 2.7992,2.0067C2.796,2.0032 2.7916,2.0013 2.7869,2.0013L2.7813,2.0013L2.7813,1.9973L2.8469,1.9997L2.8469,2.0037C2.8415,2.0032 2.8359,2.0038 2.8307,2.0053C2.8279,2.0064 2.8256,2.0082 2.824,2.0107C2.8222,2.0159 2.8214,2.0214 2.8216,2.0269L2.8181,2.1184C2.8173,2.1224 2.8173,2.1266 2.8181,2.1307C2.8189,2.1323 2.8202,2.1335 2.8219,2.1341C2.8273,2.1354 2.8328,2.1359 2.8384,2.1357L2.8491,2.1357C2.8569,2.1363 2.8648,2.1357 2.8725,2.1341C2.8774,2.1324 2.8818,2.1296 2.8853,2.1259C2.8903,2.12 2.8943,2.1134 2.8973,2.1064L2.8987,2.1083ZM3.0933,2.16L3.0965,2.1616L3.0723,2.1952L2.9656,2.16L2.9656,2.1563L2.9709,2.1579C2.9757,2.1599 2.9811,2.1592 2.9853,2.1563C2.9888,2.1521 2.9912,2.1472 2.9923,2.1419L3.0219,2.0533C3.0243,2.0479 3.0252,2.0419 3.0243,2.036C3.0224,2.0313 3.0183,2.0278 3.0133,2.0267L3.0083,2.0251L3.0083,2.0211L3.0707,2.0419L3.0707,2.0456C3.0656,2.0435 3.0601,2.0425 3.0547,2.0427C3.0518,2.0427 3.049,2.0438 3.0469,2.0459C3.0437,2.0505 3.0413,2.0556 3.04,2.0611L3.0133,2.148C3.0118,2.1518 3.011,2.1559 3.0109,2.16C3.0114,2.1618 3.0124,2.1634 3.0139,2.1645C3.0188,2.1671 3.024,2.1692 3.0293,2.1707L3.0395,2.1741C3.0468,2.1769 3.0546,2.1786 3.0624,2.1792C3.0675,2.1788 3.0724,2.1773 3.0768,2.1747C3.083,2.1706 3.0885,2.1656 3.0933,2.16ZM3.2493,2.2424L3.2035,2.2099L3.1821,2.2229C3.1783,2.2251 3.1748,2.2279 3.1717,2.2312C3.1709,2.2333 3.1709,2.2357 3.1717,2.2379C3.1739,2.2421 3.1771,2.2457 3.1811,2.2483L3.1789,2.2517L3.1416,2.2251L3.1437,2.2219C3.1474,2.224 3.1515,2.2251 3.1557,2.2253C3.1637,2.2233 3.1712,2.2199 3.1779,2.2152L3.2885,2.1472L3.2917,2.1493L3.2632,2.2773C3.2611,2.2844 3.2604,2.2919 3.2613,2.2992C3.2627,2.3041 3.2657,2.3083 3.2699,2.3112L3.2675,2.3144L3.2205,2.2813L3.2229,2.2779C3.2261,2.2805 3.23,2.2821 3.2341,2.2824C3.2365,2.2822 3.2387,2.2811 3.2403,2.2792C3.2427,2.2746 3.2444,2.2697 3.2453,2.2645L3.2501,2.2424L3.2493,2.2424ZM3.286,2.272L3.312,2.172L3.212,2.2254L3.2885,2.272L3.286,2.272ZM3.4227,2.2667L3.4461,2.2984L3.4115,2.4347L3.4789,2.3845C3.4861,2.3792 3.4899,2.3752 3.4907,2.3723C3.4913,2.3676 3.4898,2.3629 3.4867,2.3595L3.4837,2.3555L3.4869,2.3531L3.5171,2.3939L3.5139,2.396L3.5107,2.392C3.5082,2.3875 3.5035,2.3848 3.4984,2.3848C3.4932,2.3861 3.4885,2.3887 3.4845,2.3923L3.3867,2.464L3.3843,2.4611L3.4213,2.3144L3.3493,2.3677C3.3421,2.3731 3.3384,2.3771 3.3376,2.38C3.337,2.3846 3.3385,2.3892 3.3416,2.3925L3.3445,2.3968L3.3413,2.3992L3.3115,2.3584L3.3144,2.3563L3.3176,2.3603C3.3202,2.3646 3.3248,2.3673 3.3299,2.3675C3.335,2.3662 3.3398,2.3636 3.3437,2.36L3.4237,2.3C3.4248,2.2955 3.4255,2.291 3.4259,2.2864C3.4257,2.2828 3.4249,2.2793 3.4237,2.276C3.4225,2.2731 3.4208,2.2704 3.4187,2.268L3.4219,2.2656L3.4227,2.2667ZM3.6059,2.6043L3.5733,2.616L3.5733,2.6123C3.5774,2.6104 3.5811,2.6079 3.5843,2.6048C3.5872,2.6017 3.5893,2.5978 3.5901,2.5936C3.5905,2.5886 3.5898,2.5836 3.588,2.5789L3.5811,2.5595L3.4765,2.5965C3.4709,2.5979 3.4657,2.6007 3.4616,2.6048C3.4597,2.609 3.4597,2.6139 3.4616,2.6181L3.4632,2.6229L3.4595,2.6229L3.44,2.5661L3.4437,2.5661L3.4456,2.5709C3.4469,2.5758 3.4504,2.5798 3.4552,2.5816C3.4605,2.5818 3.4658,2.5807 3.4707,2.5784L3.5733,2.5403L3.5675,2.5237C3.566,2.519 3.5639,2.5145 3.5611,2.5104C3.5584,2.5072 3.5547,2.5051 3.5507,2.5043C3.5453,2.5028 3.5397,2.5028 3.5344,2.5043L3.5344,2.5005L3.5669,2.4907L3.6067,2.6027L3.6059,2.6043ZM3.4909,2.8619L3.4891,2.8232L3.5541,2.7699C3.5541,2.7661 3.5541,2.7632 3.5541,2.7611C3.5543,2.76 3.5543,2.7589 3.5541,2.7579L3.5541,2.7547L3.512,2.7568C3.5061,2.7564 3.5003,2.7578 3.4952,2.7608C3.4921,2.7641 3.4906,2.7686 3.4912,2.7731L3.4912,2.7789L3.4872,2.7789L3.484,2.7168L3.488,2.7168L3.488,2.7224C3.4877,2.7276 3.4903,2.7325 3.4947,2.7352C3.4998,2.7365 3.5052,2.7365 3.5104,2.7352L3.6043,2.7304C3.6101,2.7307 3.6159,2.7294 3.6211,2.7267C3.6241,2.7232 3.6256,2.7185 3.6251,2.7139L3.6251,2.7085L3.6291,2.7085L3.6317,2.7619C3.6328,2.7734 3.6322,2.7849 3.6301,2.7963C3.6282,2.8036 3.6243,2.8102 3.6189,2.8155C3.6131,2.8208 3.6055,2.8239 3.5976,2.8243C3.589,2.8247 3.5806,2.8219 3.5739,2.8165C3.5661,2.8095 3.5607,2.8002 3.5587,2.7899L3.5187,2.8219C3.5115,2.8269 3.5054,2.8332 3.5005,2.8405C3.4974,2.8466 3.4956,2.8534 3.4955,2.8603L3.4909,2.8619ZM3.5604,2.7582L3.5604,2.7658C3.5602,2.7674 3.5602,2.769 3.5604,2.7706C3.56,2.7933 3.5658,2.8155 3.5768,2.8333C3.5864,2.8462 3.6,2.8531 3.6139,2.8522C3.627,2.8518 3.6395,2.8446 3.6484,2.8322C3.657,2.8194 3.6611,2.8026 3.6597,2.7858C3.659,2.7744 3.6575,2.7632 3.6551,2.7523L3.56,2.7582L3.5604,2.7582ZM3.6,3.0528L3.5872,3.1019L3.5835,3.1019L3.5835,3.0989C3.5841,3.0962 3.5841,3.0934 3.5835,3.0907C3.5827,3.0866 3.5812,3.0828 3.5792,3.0792C3.5757,3.0742 3.5717,3.0695 3.5675,3.0651L3.5229,3.0171L3.4877,3.008C3.4789,3.0056 3.4733,3.0051 3.4707,3.008C3.4667,3.0105 3.4639,3.0146 3.4629,3.0192L3.4629,3.0237L3.4592,3.0237L3.4747,2.964L3.4787,2.964L3.4787,2.9691C3.4769,2.9738 3.4777,2.9792 3.4808,2.9832C3.4851,2.9863 3.49,2.9884 3.4952,2.9893L3.5285,2.9981L3.5976,2.9749C3.6028,2.9733 3.6079,2.9713 3.6128,2.9691C3.6163,2.9667 3.6193,2.9638 3.6219,2.9605C3.6232,2.9589 3.624,2.957 3.6243,2.9549L3.6283,2.9549L3.6125,3.0152L3.6085,3.0152L3.6085,3.012C3.6093,3.0089 3.6093,3.0057 3.6085,3.0027C3.6079,2.9997 3.6056,2.9975 3.6027,2.9968C3.5975,2.9965 3.5923,2.9974 3.5875,2.9995L3.5341,3.0168L3.5704,3.0557C3.5737,3.0601 3.5781,3.0636 3.5832,3.0659C3.585,3.0664 3.587,3.0664 3.5888,3.0659C3.5907,3.0651 3.5923,3.0639 3.5936,3.0624C3.5953,3.06 3.5964,3.0573 3.5971,3.0544L3.6008,3.0544L3.6,3.0528Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.276,2.9393C3.2937,2.9364 3.3117,2.9364 3.3294,2.9393C3.3294,2.9393 3.3324,2.9556 3.3237,2.9609C3.3382,2.9653 3.3532,2.9668 3.368,2.9654C3.368,2.9654 3.3548,2.9778 3.348,2.9826C3.3587,2.9863 3.3684,2.9934 3.376,3.003C3.3623,3.0069 3.348,3.0069 3.3343,3.003C3.3388,3.0136 3.3412,3.0253 3.3412,3.0371C3.3155,3.0296 3.2928,3.012 3.2771,2.9871" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.3376,3.0339L3.3335,3.0339C3.3097,3.0267 3.2888,3.0094 3.2744,2.9851L3.2801,2.981C3.2927,3.0014 3.3106,3.016 3.3308,3.0223C3.3302,3.0139 3.3283,3.0056 3.3254,2.9979L3.3203,2.9864L3.3301,2.9926C3.3391,2.9961 3.3486,2.9971 3.3578,2.9955C3.353,2.9895 3.3469,2.9854 3.3403,2.9835L3.3298,2.9835L3.3386,2.9768C3.3419,2.9745 3.345,2.9718 3.348,2.969C3.3376,2.9698 3.3272,2.9681 3.3173,2.964L3.3119,2.9603L3.3173,2.9566C3.321,2.9541 3.321,2.9479 3.321,2.9442C3.3066,2.9413 3.2919,2.9413 3.2774,2.9442L3.2774,2.9359C3.2936,2.9333 3.3099,2.9333 3.3261,2.9359L3.3285,2.9359L3.3285,2.9388C3.3294,2.9454 3.3287,2.9522 3.3264,2.9582C3.3377,2.9598 3.349,2.9598 3.3602,2.9582L3.371,2.9582L3.3626,2.9661L3.3501,2.9773C3.3575,2.9816 3.3641,2.9876 3.3697,2.995L3.3744,3.0008L3.368,3.0008C3.3575,3.0027 3.3468,3.0027 3.3362,3.0008C3.3387,3.0089 3.3398,3.0175 3.3396,3.0261L3.3376,3.0339Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.2536,2.9399C3.2416,2.9829 3.1536,2.9027 3.1536,2.9027C3.1759,2.9529 3.2105,2.9888 3.2504,3.0027" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.2445,3.0003C3.2059,2.9881 3.1723,2.9547 3.1512,2.9076L3.1564,2.9003C3.1731,2.9154 3.2207,2.9526 3.2389,2.9437C3.2414,2.9425 3.2434,2.9398 3.2445,2.9364L3.2512,2.9406C3.2495,2.9469 3.2458,2.9517 3.2412,2.9537C3.2154,2.9541 3.1902,2.9433 3.169,2.9228C3.188,2.9574 3.2152,2.9812 3.2456,2.9898L3.2445,3.0003Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.4848,3.2976l0.6901,0l0.0533,-0.0424l-0.0888,-0.0477l-0.1368,-0.0464l-0.0533,-0.0301l-0.1011,0.0053l-0.0848,0.0451l-0.116,0.0139l-0.0267,0.0315l-0.0861,0.0067l-0.1352,-0.0027l0.2256,0.0355l-0.1867,-0.0096l0.0477,0.0411z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.1757,3.3003L2.4837,3.3003L2.4304,3.2536L2.5725,3.2608L2.3981,3.2341L2.3981,3.2288L2.5336,3.2315L2.6181,3.2248L2.6448,3.1933L2.6448,3.1933L2.7603,3.1797L2.8456,3.1344L2.9477,3.1291L2.9477,3.1291L3.0024,3.1592L3.1387,3.2053L3.2315,3.2552L3.1757,3.3003ZM2.4859,3.2949L3.1733,3.2949L3.2227,3.2557L3.1376,3.2099L3.0013,3.1635L2.948,3.1336L2.8483,3.1389L2.7629,3.1843L2.648,3.1976L2.6213,3.2291L2.6213,3.2291L2.5352,3.2357L2.4395,3.2339L2.6261,3.2632L2.6261,3.2685L2.4483,3.2595L2.4859,3.2949Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8565,3.0995C2.7701,3.0531 2.7448,3.1675 2.7075,3.1952C2.7579,3.2037 2.7957,3.1565 2.8387,3.1336C2.8715,3.2224 2.9229,3.1637 2.9229,3.1637C2.9229,3.1637 2.9763,3.2488 3.0477,3.2101C3.06,3.2185 3.076,3.2191 3.0888,3.2115C3.0888,3.2115 3.1155,3.2163 3.1203,3.2048C3.1339,3.2093 3.1491,3.1923 3.1491,3.1923C3.1491,3.1923 3.1787,3.1923 3.1845,3.1773C3.2285,3.1853 3.2869,3.0872 3.2869,3.0872L3.3048,3.0531L3.3315,3.0475C3.3315,3.0475 3.3331,3.0304 3.3192,3.0312C3.3192,3.0208 3.3099,3.0155 3.2973,3.0176C3.2997,3.0112 3.2904,3.0067 3.2904,3.0067C3.2659,3.0128 3.2637,3.0749 3.2637,3.0749C3.2449,3.0895 3.2253,3.1032 3.2051,3.1157C3.2051,3.0803 3.1448,3.0323 3.1571,3.0091C3.1693,2.9859 3.208,3.0443 3.2419,3.0336C3.2757,3.0229 3.2923,2.9803 3.2952,2.9448C3.2854,2.9237 3.2745,2.9031 3.2624,2.8832L3.2405,2.8832L3.2213,2.8368C3.2213,2.8368 3.1811,2.8635 3.1816,2.8859C3.1821,2.9083 3.224,2.9283 3.224,2.9283C3.2102,2.9368 3.1936,2.9398 3.1776,2.9365C3.1755,2.9597 3.2043,2.9555 3.216,2.9557C3.2199,2.9669 3.2277,2.9763 3.2379,2.9824C3.2379,2.9824 3.248,3.0091 3.2213,3.0056C3.1947,3.0021 3.1632,2.9419 3.1256,2.9701C3.088,2.9984 3.1435,3.0549 3.1435,3.0549C3.1184,3.0704 3.0988,3.0933 3.0875,3.1205C3.0024,3.0488 2.9525,3.0821 2.8579,3.1013L2.8565,3.0995Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.0104,3.2229C2.991,3.2224 2.9723,3.2156 2.9571,3.2035C2.9437,3.1936 2.932,3.1816 2.9224,3.168C2.9114,3.1798 2.8956,3.186 2.8795,3.1848C2.8624,3.1819 2.8483,3.1659 2.8373,3.1376C2.8252,3.1447 2.8134,3.1526 2.8021,3.1611C2.7733,3.1821 2.7432,3.2037 2.7072,3.1979L2.7008,3.1979L2.7059,3.1941C2.7181,3.1827 2.7285,3.1694 2.7365,3.1547C2.7632,3.1144 2.7941,3.0645 2.8571,3.0976C2.8739,3.0941 2.8891,3.0904 2.904,3.0867C2.9688,3.0704 3.016,3.0584 3.0851,3.1152C3.0967,3.09 3.1152,3.0687 3.1384,3.0536C3.1216,3.0379 3.111,3.0167 3.1085,2.9939C3.1092,2.9832 3.1147,2.9733 3.1235,2.9672C3.1501,2.948 3.1715,2.9672 3.1912,2.9837C3.1993,2.9924 3.2096,2.9988 3.2211,3.0021C3.2259,3.0035 3.2312,3.002 3.2347,2.9984C3.2368,2.9937 3.2368,2.9882 3.2347,2.9835C3.2251,2.9775 3.2175,2.9688 3.2131,2.9584L3.2096,2.9584C3.1987,2.9601 3.1875,2.9575 3.1784,2.9512C3.1748,2.9471 3.1733,2.9416 3.1741,2.9363L3.1741,2.9333L3.1773,2.9333C3.1908,2.9364 3.2049,2.9345 3.2171,2.928C3.2059,2.9219 3.1787,2.9053 3.1779,2.8856C3.1779,2.8613 3.2171,2.8352 3.2187,2.8341L3.2216,2.8323L3.2413,2.8803L3.2629,2.8816L3.2629,2.8816C3.2752,2.9015 3.2862,2.9222 3.296,2.9435L3.296,2.9435C3.2944,2.98 3.2768,3.0235 3.2427,3.0349C3.2243,3.0405 3.2048,3.0275 3.1893,3.0171C3.1792,3.0101 3.1696,3.0037 3.1627,3.0051C3.1627,3.0051 3.16,3.0051 3.1584,3.0091C3.1528,3.0195 3.1656,3.0376 3.1789,3.0571C3.1915,3.0728 3.2006,3.0909 3.2056,3.1104C3.2213,3.1011 3.2531,3.0771 3.2589,3.0725C3.2589,3.0629 3.2624,3.0091 3.2856,3.0029L3.2856,3.0029L3.2856,3.0029C3.2899,3.0047 3.2931,3.0085 3.2941,3.0131C3.2997,3.0124 3.3054,3.0139 3.3099,3.0173C3.313,3.0197 3.315,3.0233 3.3155,3.0272C3.3186,3.0274 3.3215,3.0287 3.3237,3.0309C3.3271,3.0353 3.3286,3.0409 3.328,3.0464L3.328,3.0485L3.3013,3.0541L3.284,3.0872C3.2816,3.0912 3.2285,3.1792 3.1843,3.1792L3.1808,3.1792C3.1736,3.1925 3.1504,3.1939 3.1448,3.1941C3.1378,3.2026 3.1272,3.2073 3.1163,3.2067C3.1091,3.2165 3.0896,3.2141 3.084,3.2133C3.0712,3.2209 3.0552,3.2209 3.0424,3.2133C3.0325,3.2187 3.0216,3.222 3.0104,3.2229L3.0104,3.2229ZM2.9232,3.1592L2.9251,3.1621C2.9272,3.1656 2.9784,3.2448 3.0467,3.2077L3.0467,3.2077L3.0467,3.2077C3.0583,3.215 3.0731,3.215 3.0848,3.2077L3.0848,3.2077L3.0848,3.2077C3.0915,3.2077 3.1096,3.2104 3.1133,3.2024L3.1133,3.2003L3.1155,3.2003C3.1272,3.2043 3.1421,3.1888 3.1421,3.1888L3.1421,3.1888L3.1421,3.1888C3.1421,3.1888 3.1688,3.1888 3.1749,3.1757L3.1749,3.1736L3.1773,3.1736L3.1819,3.1736C3.2232,3.1736 3.2763,3.0851 3.2768,3.0843L3.2952,3.0491L3.3203,3.0437C3.3204,3.0404 3.3194,3.0371 3.3173,3.0344C3.3155,3.0328 3.3131,3.032 3.3107,3.0323L3.308,3.0323L3.308,3.0296C3.308,3.0264 3.3065,3.0233 3.304,3.0213C3.2998,3.0183 3.2944,3.0173 3.2893,3.0187L3.2845,3.0187L3.2861,3.0144C3.2861,3.0115 3.2835,3.0085 3.2816,3.0075C3.264,3.0133 3.2592,3.0563 3.2587,3.0728L3.2587,3.0728L3.2587,3.0728C3.2397,3.0876 3.2199,3.1013 3.1995,3.1139L3.1957,3.116L3.1957,3.1117C3.1916,3.092 3.1824,3.0736 3.1691,3.0584C3.1547,3.0379 3.1424,3.0181 3.1483,3.0051C3.1498,3.0019 3.1526,2.9996 3.156,2.9987C3.164,2.9965 3.1741,3.0035 3.1859,3.0112C3.1976,3.0189 3.2187,3.0333 3.2347,3.0283C3.2653,3.0187 3.2829,2.9781 3.2845,2.9427C3.2752,2.9223 3.2647,2.9024 3.2531,2.8832L3.2309,2.8832L3.2123,2.8384C3.2035,2.8445 3.1763,2.8651 3.1768,2.8832C3.1773,2.9013 3.2171,2.9229 3.2176,2.9232L3.2219,2.9253L3.2179,2.928C3.2043,2.9362 3.1883,2.9395 3.1725,2.9373C3.1726,2.9401 3.1736,2.9428 3.1755,2.9448C3.1811,2.9509 3.1939,2.9507 3.2021,2.9504L3.2096,2.9504L3.2096,2.9523C3.2136,2.9625 3.2209,2.9711 3.2304,2.9765L3.2304,2.9765L3.2304,2.9765C3.2334,2.9833 3.2334,2.9911 3.2304,2.9979C3.2257,3.0029 3.2187,3.0051 3.212,3.0035C3.1994,3.0002 3.188,2.9934 3.1792,2.9837C3.16,2.9677 3.1403,2.9509 3.1181,2.9675C3.1107,2.9727 3.106,2.981 3.1053,2.9901C3.1037,3.0168 3.136,3.0477 3.1363,3.048L3.1389,3.0507L3.1357,3.0525C3.1111,3.0677 3.0919,3.0902 3.0808,3.1168L3.0808,3.12L3.0779,3.1176C3.0096,3.06 2.9656,3.0712 2.8989,3.088C2.8837,3.0917 2.868,3.0957 2.8507,3.0992L2.8507,3.0992L2.8507,3.0992C2.7917,3.0675 2.7624,3.1133 2.7365,3.1539C2.729,3.167 2.72,3.1794 2.7099,3.1907C2.7408,3.1933 2.7672,3.1741 2.7949,3.1539C2.807,3.144 2.8199,3.1351 2.8333,3.1272L2.836,3.1272L2.836,3.1301C2.8464,3.1568 2.8595,3.1741 2.8752,3.1768C2.8906,3.1774 2.9054,3.1709 2.9155,3.1592L2.9232,3.1592Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.7323,2.9779C2.7677,3.0115 2.7429,3.0669 2.7568,3.0776C2.7707,3.0883 2.7923,3.0723 2.7923,3.0723C2.8273,3.076 2.8628,3.0722 2.8963,3.0613C2.9256,3.0776 2.9139,3.0533 2.9317,3.0544C2.9475,3.0947 3,3.0872 3,3.0872C2.9769,3.0629 2.9507,3.0418 2.9221,3.0243C2.8898,3.0358 2.8553,3.0404 2.8211,3.0379C2.8083,3.0357 2.8163,3.02 2.8101,3.0112C2.8347,2.9875 2.8152,2.9283 2.8019,2.9045C2.7485,2.8685 2.6827,2.9312 2.7323,2.9771L2.7323,2.9779Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.9907,3.0904C2.9656,3.0925 2.9416,3.0793 2.9299,3.0571C2.9256,3.0571 2.9243,3.0597 2.9221,3.0627C2.92,3.0656 2.9133,3.0736 2.8955,3.0643C2.8623,3.075 2.8272,3.0788 2.7925,3.0752C2.7877,3.0787 2.7691,3.0909 2.7547,3.0797C2.7483,3.0749 2.7485,3.0635 2.7491,3.0493C2.7533,3.0244 2.7463,2.9989 2.7299,2.9797L2.7299,2.9797C2.7199,2.9721 2.7134,2.9607 2.7118,2.9483C2.7103,2.9358 2.7138,2.9232 2.7216,2.9133C2.7417,2.8899 2.7763,2.8855 2.8016,2.9032L2.8016,2.9032C2.8163,2.9275 2.8339,2.9848 2.8109,3.0099C2.8125,3.0139 2.8132,3.0181 2.8131,3.0224C2.8131,3.0301 2.8131,3.0331 2.8189,3.0339C2.8525,3.0364 2.8863,3.032 2.9181,3.0208L2.9181,3.0208L2.9181,3.0208C2.9475,3.0383 2.9744,3.0597 2.9981,3.0843L3.0019,3.088L2.9965,3.088C2.9946,3.0889 2.9927,3.0897 2.9907,3.0904L2.9907,3.0904ZM2.9307,3.0517L2.9333,3.0517L2.9333,3.0533C2.9446,3.0753 2.9683,3.0879 2.9928,3.0851C2.9715,3.0629 2.9475,3.0435 2.9213,3.0275C2.8886,3.0387 2.854,3.0431 2.8195,3.0405C2.8096,3.0389 2.8093,3.0304 2.8091,3.0237C2.8094,3.0198 2.8087,3.0158 2.8069,3.0123L2.8069,3.0104L2.8085,3.0088C2.832,2.9859 2.8125,2.9288 2.8003,2.9075C2.7771,2.891 2.7452,2.8949 2.7267,2.9165C2.7196,2.9254 2.7164,2.9367 2.7179,2.9479C2.7193,2.9591 2.7253,2.9693 2.7344,2.976L2.7344,2.976C2.752,2.9961 2.7597,3.023 2.7555,3.0493C2.7555,3.0616 2.7555,3.0723 2.7587,3.076C2.7715,3.0859 2.7907,3.0707 2.7909,3.0707L2.7909,3.0707L2.7909,3.0707C2.8255,3.0743 2.8603,3.0705 2.8933,3.0597L2.8933,3.0597L2.8933,3.0597C2.9085,3.0683 2.9107,3.0651 2.9133,3.0597C2.9163,3.0531 2.9237,3.0496 2.9307,3.0517Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.496,2.8779C2.4512,2.8899 2.3739,2.82 2.3376,2.8469C2.3013,2.8739 2.3181,2.9397 2.3424,2.9725C2.3667,3.0053 2.3077,3.0163 2.292,3.0355C2.2763,3.0547 2.2968,3.0741 2.2968,3.0741L2.3133,3.0845L2.3104,3.1088L2.3192,3.1379C2.3192,3.1379 2.3272,3.1448 2.3299,3.1357C2.3373,3.1435 2.3299,3.1651 2.3491,3.1677C2.3424,3.1539 2.3539,3.1144 2.3539,3.1144C2.3539,3.1144 2.3864,3.1168 2.3944,3.1029C2.4024,3.0891 2.3867,3.0584 2.3867,3.0584L2.3965,3.0584C2.3886,3.0503 2.3834,3.0398 2.3819,3.0285C2.3819,3.0285 2.4267,3.0152 2.4267,2.9813C2.4267,2.9475 2.3536,2.9109 2.3803,2.8933C2.4069,2.8757 2.4603,2.944 2.5051,2.9117C2.5499,2.8795 2.5203,2.9117 2.5203,2.9117C2.5203,2.9117 2.5403,2.8669 2.4963,2.8789L2.496,2.8779Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.3539,3.1712L2.3488,3.1712C2.3352,3.1691 2.3331,3.1584 2.3315,3.1496C2.3313,3.147 2.3307,3.1444 2.3299,3.1419C2.329,3.1427 2.328,3.1434 2.3269,3.1437C2.3234,3.1441 2.3199,3.143 2.3173,3.1405L2.3173,3.1405L2.3083,3.1104L2.3083,3.1104L2.3109,3.0877L2.296,3.0781C2.2837,3.0673 2.2815,3.049 2.2907,3.0355C2.2979,3.0283 2.3063,3.0224 2.3155,3.0179C2.3291,3.0101 2.3421,3.0021 2.3453,2.9912C2.3461,2.9856 2.3445,2.9798 2.3408,2.9755C2.3141,2.9397 2.3,2.8731 2.3365,2.8461C2.3571,2.8307 2.3899,2.8448 2.4219,2.8587C2.4442,2.8717 2.4699,2.8779 2.4957,2.8765L2.4957,2.8765C2.5093,2.8731 2.5189,2.8741 2.5237,2.88C2.5272,2.8846 2.5287,2.8903 2.5277,2.896C2.5288,2.8951 2.5304,2.8951 2.5315,2.896C2.5315,2.896 2.5347,2.8995 2.5227,2.9128L2.5181,2.9099C2.5189,2.9082 2.5195,2.9065 2.52,2.9048L2.5069,2.9141C2.4803,2.9333 2.4536,2.9189 2.4288,2.9061C2.4099,2.8965 2.3939,2.888 2.3821,2.8957C2.3797,2.8971 2.3779,2.8994 2.3773,2.9021C2.3773,2.9099 2.3875,2.9211 2.3989,2.9331C2.4104,2.9451 2.4293,2.9645 2.4296,2.9816C2.4296,3.0131 2.3952,3.028 2.3856,3.0317C2.3869,3.0418 2.3914,3.0511 2.3984,3.0584L2.4056,3.0632L2.3917,3.0632C2.3957,3.0723 2.4045,3.0944 2.3973,3.1064C2.3901,3.1184 2.3643,3.1197 2.3565,3.1195C2.351,3.1349 2.3495,3.1515 2.352,3.1677L2.3539,3.1712ZM2.3272,3.1307L2.3304,3.1339C2.3334,3.1379 2.3351,3.1427 2.3355,3.1477C2.3371,3.1557 2.3384,3.1613 2.3437,3.1637C2.3429,3.1471 2.3451,3.1305 2.3501,3.1147L2.3501,3.1128L2.3523,3.1128C2.3608,3.1128 2.3843,3.1128 2.3904,3.1027C2.3965,3.0925 2.3867,3.0688 2.3824,3.0608L2.3805,3.0568L2.388,3.0568C2.3826,3.0487 2.379,3.0397 2.3773,3.0301L2.3773,3.028L2.3795,3.028C2.3795,3.028 2.4227,3.0139 2.4221,2.9824C2.4221,2.9677 2.4064,2.9517 2.3928,2.9376C2.3792,2.9235 2.3688,2.9125 2.3699,2.9024C2.3706,2.8982 2.3731,2.8945 2.3768,2.8923C2.3912,2.8827 2.4096,2.8923 2.4301,2.9021C2.4544,2.9147 2.4795,2.9288 2.5027,2.9107C2.5085,2.9062 2.5145,2.902 2.5208,2.8981C2.5223,2.8931 2.5215,2.8876 2.5187,2.8832C2.5141,2.8781 2.504,2.8795 2.4963,2.8816L2.4963,2.8816C2.4691,2.8833 2.4421,2.8769 2.4187,2.8632C2.3883,2.8501 2.3568,2.8365 2.3387,2.8501C2.3048,2.8752 2.3189,2.9379 2.344,2.972C2.3487,2.9775 2.3507,2.9848 2.3496,2.992C2.3469,3.0048 2.3317,3.0133 2.3171,3.0219C2.3084,3.026 2.3005,3.0315 2.2936,3.0381C2.2805,3.0541 2.2981,3.0731 2.2984,3.0733L2.3157,3.0843L2.3128,3.1096L2.3211,3.1363C2.3224,3.1367 2.3238,3.1367 2.3251,3.1363C2.3251,3.1363 2.3264,3.1347 2.3267,3.1339L2.3272,3.1307Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.7267,2.4C2.6669,2.3752 2.5448,2.3733 2.4765,2.34C2.4561,2.3403 2.4382,2.3538 2.4323,2.3733C2.4011,2.3733 2.3789,2.4211 2.3843,2.4309C2.3275,2.4077 2.3011,2.4979 2.3195,2.5163C2.2709,2.5181 2.2768,2.5803 2.2723,2.5976C2.2568,2.6352 2.2757,2.648 2.3064,2.6344C2.3093,2.6403 2.3092,2.6472 2.3061,2.6529C2.3029,2.6586 2.2972,2.6625 2.2907,2.6632C2.3749,2.7595 2.4227,2.6037 2.4965,2.6043C2.5451,2.5932 2.5896,2.5686 2.6248,2.5333L2.6611,2.5381L2.7267,2.4Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.3451,2.6979L2.3427,2.6979C2.3212,2.6947 2.302,2.683 2.2893,2.6653L2.2864,2.6619L2.2907,2.6619C2.2959,2.661 2.3006,2.6581 2.3037,2.6539C2.3055,2.6492 2.3055,2.6441 2.3037,2.6395C2.2885,2.6453 2.2771,2.6451 2.2691,2.6395C2.2611,2.6339 2.2592,2.6229 2.2691,2.5992C2.2691,2.5963 2.2691,2.5912 2.2709,2.5853C2.2731,2.5611 2.2771,2.5213 2.3136,2.5165C2.3074,2.4944 2.3115,2.4705 2.3248,2.4517C2.3348,2.4306 2.3587,2.4199 2.3811,2.4267C2.3825,2.4154 2.3867,2.4047 2.3933,2.3955C2.401,2.3819 2.4145,2.3728 2.4299,2.3707C2.4367,2.3505 2.4553,2.3367 2.4765,2.336L2.4765,2.336L2.4765,2.336C2.5221,2.3549 2.57,2.3674 2.6189,2.3733C2.656,2.3778 2.6924,2.3861 2.7277,2.3981L2.7304,2.3981L2.7304,2.4005L2.664,2.5405L2.6272,2.5357C2.5917,2.5712 2.5472,2.5961 2.4984,2.6077L2.4984,2.6077C2.4717,2.6077 2.4467,2.6309 2.4229,2.6531C2.3992,2.6752 2.3733,2.6979 2.3451,2.6979ZM2.2957,2.6651C2.3073,2.6799 2.3243,2.6894 2.3429,2.6917L2.3467,2.6917C2.3733,2.6917 2.3944,2.6704 2.4184,2.648C2.4424,2.6256 2.468,2.6013 2.4984,2.6013L2.4984,2.6013C2.5465,2.5899 2.5904,2.5651 2.6251,2.5299L2.6251,2.5299L2.6608,2.5347L2.7243,2.4013C2.6901,2.3903 2.655,2.3826 2.6195,2.3781C2.5707,2.3728 2.5229,2.3608 2.4773,2.3427C2.458,2.3425 2.4409,2.355 2.4349,2.3733L2.4349,2.3757L2.4323,2.3757C2.4178,2.3768 2.4049,2.3853 2.3981,2.3981C2.391,2.407 2.3871,2.418 2.3872,2.4293L2.3901,2.4357L2.3837,2.4331C2.3637,2.4246 2.3406,2.4328 2.3304,2.452C2.3152,2.4749 2.3128,2.5053 2.3216,2.5141L2.3261,2.5184L2.32,2.5184C2.2835,2.52 2.28,2.5576 2.2776,2.5824C2.2774,2.5875 2.2766,2.5926 2.2755,2.5976C2.2685,2.6144 2.2683,2.6267 2.2755,2.6325C2.2827,2.6384 2.2928,2.6379 2.3072,2.6325L2.3101,2.6325L2.3101,2.6355C2.3132,2.6423 2.3132,2.6502 2.3101,2.6571C2.3067,2.6616 2.3014,2.6645 2.2957,2.6651Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8037,2.3301m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.804,2.4211C2.7672,2.4212 2.734,2.3991 2.7198,2.3651C2.7056,2.3311 2.7134,2.292 2.7393,2.2659C2.7653,2.2399 2.8045,2.232 2.8385,2.2461C2.8725,2.2602 2.8947,2.2933 2.8947,2.3301C2.8947,2.3803 2.8541,2.4209 2.804,2.4211L2.804,2.4211ZM2.804,2.2448C2.7693,2.2447 2.738,2.2655 2.7247,2.2975C2.7114,2.3295 2.7187,2.3664 2.7432,2.3909C2.7677,2.4154 2.8046,2.4228 2.8366,2.4094C2.8686,2.3961 2.8894,2.3648 2.8893,2.3301C2.8892,2.2831 2.8511,2.2449 2.804,2.2448L2.804,2.2448Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.6488,3.0243C2.5955,3.0144 2.5037,2.9576 2.4944,2.8835C2.5453,2.6837 2.8077,2.788 2.8304,2.6376C2.8217,2.5394 2.8453,2.441 2.8976,2.3573C2.9126,2.3382 2.9331,2.324 2.9563,2.3165C2.9595,2.3283 2.9585,2.3408 2.9536,2.352C2.9968,2.3472 3.0563,2.3715 3.0971,2.3739C3.1063,2.3879 3.1092,2.4053 3.1051,2.4216C3.1024,2.4363 3.0861,2.4325 3.0861,2.4325C3.0726,2.4472 3.052,2.453 3.0328,2.4477C3.0122,2.4592 2.9894,2.4661 2.9659,2.468C2.9659,2.468 3.0608,2.5683 3.0459,2.5992C3.0653,2.614 3.082,2.632 3.0952,2.6525C3.1277,2.636 3.157,2.6137 3.1816,2.5867C3.2192,2.5867 3.2808,2.6261 3.3115,2.6304C3.3491,2.6611 3.3867,2.6933 3.3867,2.6933C3.3867,2.6933 3.3419,2.7227 3.3224,2.6837C3.2989,2.6859 3.248,2.6304 3.1776,2.6469C3.1755,2.7093 3.1067,2.7536 3.1067,2.7536C3.1404,2.7485 3.1749,2.7527 3.2064,2.7659C3.2429,2.7968 3.2965,2.8384 3.2965,2.8384L3.3443,2.9203C3.3443,2.9203 3.3005,2.928 3.2843,2.8712C3.2677,2.9171 3.2672,2.8429 3.2021,2.8083C3.186,2.8131 3.1686,2.8095 3.1557,2.7987C3.1091,2.8115 3.0536,2.8387 2.9877,2.8315C2.9408,2.8461 2.9077,2.8848 2.8592,2.9067C2.8107,2.9285 2.7979,2.9176 2.7979,2.9176L2.7595,2.9176C2.7539,2.9408 2.7571,2.9757 2.7363,2.9819C2.7496,2.9963 2.7267,3.0573 2.7035,3.068C2.7144,3.1072 2.7464,3.1192 2.78,3.1389C2.7959,3.1314 2.8147,3.133 2.8291,3.1432C2.8459,3.1637 2.8593,3.1867 2.8688,3.2115C2.851,3.213 2.833,3.2121 2.8155,3.2088C2.8027,3.2032 2.8016,3.1899 2.7867,3.1936C2.6941,3.1115 2.6453,3.144 2.6365,3.1253C2.6277,3.1067 2.6584,3.056 2.6488,3.0243L2.6488,3.0243Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8469,3.2149C2.836,3.2155 2.825,3.2142 2.8144,3.2112C2.8099,3.209 2.8058,3.2059 2.8024,3.2021C2.7979,3.1976 2.7949,3.1944 2.7875,3.1963L2.7875,3.1963L2.7875,3.1963C2.7259,3.1429 2.6851,3.1384 2.6605,3.1363C2.6483,3.1363 2.64,3.1347 2.6365,3.1272C2.6335,3.1122 2.6353,3.0966 2.6416,3.0827C2.6485,3.065 2.651,3.046 2.6491,3.0272C2.5899,3.0155 2.5029,2.9565 2.4941,2.8845L2.4941,2.8845C2.5208,2.7779 2.6107,2.7557 2.6893,2.7376C2.7595,2.7213 2.82,2.7075 2.8301,2.6389C2.8211,2.5403 2.8448,2.4414 2.8976,2.3576C2.9129,2.3377 2.9339,2.323 2.9579,2.3155L2.9605,2.3155L2.9605,2.3181C2.9637,2.3289 2.9637,2.3404 2.9605,2.3512C2.9885,2.3515 3.0163,2.3556 3.0432,2.3632C3.0617,2.3681 3.0805,2.3716 3.0995,2.3736L3.1011,2.3736L3.1011,2.3736C3.1105,2.3883 3.1135,2.4062 3.1093,2.4232C3.1089,2.4276 3.1064,2.4316 3.1027,2.4339C3.0985,2.4365 3.0934,2.4375 3.0885,2.4365C3.0749,2.4511 3.0544,2.4568 3.0352,2.4515C3.0162,2.4625 2.995,2.4692 2.9731,2.4712C2.9917,2.4915 3.06,2.568 3.0501,2.5992C3.0685,2.6133 3.0843,2.6306 3.0968,2.6501C3.1279,2.6341 3.1559,2.6126 3.1795,2.5867L3.1795,2.5867L3.1795,2.5867C3.2074,2.5902 3.2345,2.5986 3.2595,2.6117C3.2758,2.6199 3.2929,2.6262 3.3107,2.6304L3.3107,2.6304C3.3477,2.6605 3.3853,2.6917 3.3856,2.692L3.3885,2.6944L3.3856,2.6963C3.3723,2.7051 3.3563,2.7086 3.3405,2.7061C3.3307,2.7033 3.3226,2.6964 3.3181,2.6872C3.3063,2.6852 3.295,2.6806 3.2851,2.6739C3.2539,2.6526 3.2157,2.644 3.1784,2.6499C3.172,2.6908 3.1489,2.7271 3.1147,2.7504C3.1458,2.7464 3.1774,2.7512 3.2059,2.7643C3.2424,2.7947 3.2957,2.8363 3.2963,2.8368L3.2963,2.8368L3.3459,2.9221L3.3421,2.9221C3.3138,2.9246 3.288,2.906 3.2813,2.8784C3.2784,2.8845 3.2757,2.8872 3.2725,2.8875C3.2693,2.8877 3.2629,2.8816 3.2565,2.8704C3.2434,2.8454 3.2234,2.8246 3.1989,2.8104C3.1829,2.8147 3.1657,2.8112 3.1525,2.8011C3.1419,2.8037 3.1307,2.8075 3.1189,2.8115C3.0766,2.8285 3.0311,2.8361 2.9856,2.8336C2.9607,2.8428 2.9373,2.856 2.9165,2.8725C2.8982,2.8863 2.8785,2.8983 2.8579,2.9083C2.8152,2.9277 2.7987,2.9219 2.7947,2.9195L2.7592,2.9208C2.7592,2.9264 2.7573,2.9325 2.7565,2.9389C2.7544,2.9576 2.752,2.9771 2.7381,2.9837C2.741,2.9924 2.741,3.0017 2.7381,3.0104C2.7342,3.034 2.7219,3.0554 2.7035,3.0707C2.7128,3.1016 2.7363,3.1144 2.7632,3.1296L2.7771,3.1373C2.7936,3.1296 2.813,3.1316 2.8277,3.1424C2.8449,3.1632 2.8585,3.1866 2.868,3.2117L2.8696,3.2152L2.8659,3.2152C2.8659,3.2152 2.8584,3.2149 2.8469,3.2149ZM2.7915,3.1904C2.7974,3.1908 2.8028,3.1937 2.8064,3.1984C2.8091,3.2018 2.8126,3.2044 2.8165,3.2061C2.8324,3.2094 2.8487,3.2104 2.8648,3.2091C2.8559,3.1858 2.8432,3.1642 2.8272,3.1451C2.8136,3.1357 2.796,3.1344 2.7811,3.1416L2.7797,3.1416L2.7797,3.1416L2.7648,3.1333C2.7355,3.122 2.7126,3.0986 2.7019,3.0691L2.7019,3.0667L2.704,3.0667C2.7219,3.0523 2.7339,3.0318 2.7376,3.0091C2.74,2.9973 2.7395,2.9885 2.7357,2.9848L2.7328,2.9816L2.7371,2.9816C2.7507,2.9776 2.7528,2.9587 2.7552,2.94C2.7558,2.9331 2.7569,2.9262 2.7584,2.9195L2.7584,2.9173L2.7997,2.9173L2.7997,2.9173C2.7997,2.9173 2.8136,2.9264 2.8584,2.9061C2.8787,2.8962 2.898,2.8843 2.916,2.8707C2.937,2.8523 2.9609,2.8374 2.9867,2.8267L2.9867,2.8267C3.0322,2.8295 3.0778,2.8221 3.12,2.8048C3.1323,2.8008 3.1437,2.7971 3.1549,2.7941L3.1549,2.7941L3.1549,2.7941C3.1671,2.8045 3.1837,2.8079 3.1989,2.8032L3.2011,2.8032C3.2266,2.818 3.2475,2.8397 3.2613,2.8659C3.2653,2.8725 3.2701,2.8803 3.2723,2.8803L3.2723,2.8803C3.2723,2.8803 3.2749,2.8803 3.2792,2.8677L3.2821,2.8597L3.2843,2.8677C3.2968,2.9109 3.3259,2.9152 3.3376,2.9152L3.3376,2.9152L3.2923,2.8376C3.2872,2.8336 3.2368,2.7944 3.2024,2.7653C3.1688,2.7451 3.1053,2.7536 3.1048,2.7536L3.1029,2.7488C3.1029,2.7488 3.1707,2.7048 3.1728,2.6443L3.1728,2.6424L3.1749,2.6424C3.2144,2.6351 3.2551,2.6438 3.2883,2.6664C3.2979,2.6728 3.3087,2.6772 3.32,2.6792L3.3219,2.6792L3.3219,2.6808C3.3255,2.6894 3.3329,2.6959 3.3419,2.6984C3.3547,2.7006 3.3679,2.698 3.3789,2.6912L3.3075,2.6328C3.2906,2.628 3.2742,2.6214 3.2587,2.6133C3.235,2.601 3.2095,2.5926 3.1832,2.5885C3.1586,2.6153 3.1293,2.6374 3.0968,2.6539L3.0947,2.6539L3.0947,2.652C3.082,2.6315 3.0658,2.6134 3.0467,2.5987L3.044,2.5987L3.0453,2.5963C3.0576,2.572 2.992,2.4955 2.9653,2.468L2.9613,2.464L2.9669,2.464C2.9899,2.4621 3.0123,2.4554 3.0325,2.4443L3.0325,2.4443L3.0325,2.4443C3.0505,2.4492 3.0696,2.4436 3.0821,2.4299L3.0821,2.4299L3.0821,2.4299C3.086,2.4308 3.0901,2.4302 3.0936,2.4283C3.0961,2.4267 3.0977,2.424 3.0979,2.4211C3.1019,2.4059 3.0993,2.3897 3.0907,2.3765C3.0719,2.3743 3.0533,2.3708 3.0349,2.3661C3.0072,2.3579 2.9783,2.354 2.9493,2.3547L2.9437,2.3547L2.9467,2.3501C2.9512,2.3406 2.9522,2.3297 2.9496,2.3195C2.9285,2.3273 2.91,2.3409 2.8963,2.3587C2.8441,2.4416 2.8207,2.5395 2.8299,2.6371C2.8189,2.7096 2.7536,2.7248 2.6848,2.7408C2.6077,2.7587 2.5205,2.7789 2.4936,2.8832C2.5035,2.9584 2.5963,3.012 2.6459,3.0211L2.6459,3.0229L2.6475,3.0229L2.6536,3.0291L2.6493,3.0291C2.6506,3.0481 2.6479,3.0672 2.6413,3.0851C2.6358,3.0978 2.6338,3.1118 2.6357,3.1256C2.6379,3.1301 2.6437,3.1307 2.6555,3.1317C2.7043,3.1354 2.7501,3.1569 2.7843,3.192L2.7915,3.1904Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.4267,2.6573C2.4315,2.6515 2.4653,2.6643 2.4653,2.6643L2.5272,2.7029L2.6528,2.7829L2.6973,2.8477L2.6173,2.8211L2.5067,2.7269L2.4467,2.6883C2.4467,2.6883 2.4227,2.6635 2.4275,2.6573L2.4267,2.6573Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.7037,2.8533L2.6149,2.8243L2.5037,2.7285L2.4443,2.6901C2.4341,2.6797 2.4176,2.6621 2.4243,2.6552L2.4243,2.6552C2.4299,2.6485 2.4552,2.6571 2.4661,2.6611L2.5283,2.7L2.6547,2.7819L2.7037,2.8533ZM2.6181,2.8197L2.6901,2.8432L2.6507,2.7856L2.5253,2.7056L2.4637,2.6667C2.4528,2.6614 2.4407,2.659 2.4285,2.6595C2.4285,2.6619 2.4352,2.6739 2.4477,2.6861L2.5067,2.7248L2.6181,2.8197Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.1693,2.8632C3.1259,2.8523 3.0189,2.9821 3.0189,2.9821L3.0989,3.0696C3.0989,3.0696 3.1021,2.9205 3.1693,2.8632Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.1021,3.0763L3.0155,2.9821L3.0171,2.9803C3.0211,2.9752 3.1168,2.86 3.164,2.86C3.166,2.8597 3.1681,2.8597 3.1701,2.86L3.1752,2.86L3.1712,2.8635C3.1056,2.9195 3.1024,3.0661 3.1024,3.0677L3.1021,3.0763ZM3.0221,2.9819L3.0965,3.0619C3.0965,3.0325 3.1064,2.9173 3.1624,2.8643C3.1216,2.8661 3.0352,2.9672 3.0227,2.9819L3.0221,2.9819Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.64,2.5011C2.6165,2.5315 2.6133,2.5925 2.6451,2.6171C2.648,2.6541 2.6795,2.7291 2.7043,2.736C2.7291,2.7429 2.8395,2.7688 2.8819,2.7627C2.8739,2.8312 2.9277,2.8864 2.9776,2.9227C2.9766,2.9302 2.9785,2.9378 2.9829,2.944C2.9885,2.9515 3.0147,2.9528 3.0157,2.9488C3.0275,2.9651 3.0837,2.9723 3.0877,2.9648C3.0917,2.9573 3.0051,2.8973 2.9859,2.8789C2.9602,2.831 2.9422,2.7794 2.9325,2.7259C2.9022,2.6945 2.8605,2.6766 2.8168,2.6763L2.8189,2.5771L2.8232,2.4651L2.7835,2.4445C2.788,2.4424 2.7921,2.4396 2.7957,2.4363C2.8053,2.4403 2.8224,2.4211 2.8259,2.4155C2.8349,2.4189 2.8432,2.4187 2.8448,2.4139C2.8464,2.4091 2.848,2.3904 2.8512,2.3805C2.8811,2.3539 2.8469,2.2984 2.8011,2.2976C2.7552,2.2968 2.7459,2.3509 2.7477,2.3557C2.752,2.3728 2.7509,2.3824 2.7477,2.3856C2.7418,2.3908 2.7353,2.3955 2.7285,2.3995C2.7106,2.3923 2.6905,2.3923 2.6725,2.3995C2.6419,2.4112 2.6072,2.4261 2.6056,2.4472C2.5873,2.4522 2.5722,2.4653 2.5645,2.4827C2.5523,2.4803 2.5363,2.4907 2.5112,2.5333C2.464,2.5541 2.4613,2.6549 2.4613,2.6549C2.4552,2.6634 2.4506,2.673 2.448,2.6832C2.448,2.6931 2.4525,2.7021 2.4587,2.7003C2.4587,2.7069 2.468,2.7125 2.4717,2.7107C2.4744,2.7171 2.4811,2.7209 2.488,2.7197C2.488,2.7243 2.5067,2.7232 2.5083,2.7197C2.5099,2.7163 2.5064,2.6931 2.5083,2.6912C2.5101,2.6893 2.5253,2.7011 2.5293,2.6981C2.5333,2.6952 2.5293,2.6851 2.5264,2.6813C2.5235,2.6776 2.5115,2.6741 2.5083,2.6581C2.5075,2.6449 2.5104,2.6317 2.5165,2.62C2.5165,2.62 2.5677,2.5795 2.5736,2.5451C2.612,2.5488 2.6325,2.5152 2.6435,2.5024L2.64,2.5011Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.076,2.9696C3.0546,2.97 3.0337,2.9637 3.016,2.9517L3.0133,2.9517C3.0021,2.9537 2.9905,2.951 2.9813,2.9443C2.9765,2.9382 2.9744,2.9304 2.9755,2.9227C2.9077,2.8733 2.8747,2.8189 2.8795,2.7645C2.832,2.7701 2.7227,2.7435 2.704,2.7379C2.6773,2.7304 2.6467,2.6563 2.6429,2.6176C2.6193,2.5916 2.6128,2.5543 2.6261,2.5219C2.6131,2.5378 2.5934,2.5467 2.5728,2.5459C2.5607,2.575 2.541,2.6004 2.5157,2.6195C2.51,2.6306 2.5074,2.643 2.508,2.6555C2.5095,2.6633 2.5144,2.67 2.5213,2.6739C2.523,2.675 2.5245,2.6763 2.5259,2.6779C2.528,2.6813 2.5344,2.6933 2.5283,2.6981C2.5221,2.7029 2.5179,2.6981 2.5117,2.6944L2.5067,2.6933C2.5067,2.696 2.5067,2.7008 2.5067,2.704C2.5076,2.7091 2.5076,2.7144 2.5067,2.7195C2.5051,2.7243 2.4944,2.7253 2.4891,2.7245C2.4866,2.7245 2.4843,2.7237 2.4824,2.7221L2.4824,2.7221C2.4758,2.7221 2.4696,2.7187 2.4661,2.7131L2.4661,2.7131C2.4645,2.7135 2.4627,2.7135 2.4611,2.7131C2.4572,2.7112 2.4543,2.708 2.4528,2.704C2.451,2.7039 2.4493,2.7032 2.448,2.7019C2.4431,2.6972 2.4408,2.6904 2.4416,2.6837C2.4441,2.6733 2.4486,2.6635 2.4549,2.6549C2.4549,2.6445 2.46,2.5531 2.5056,2.532C2.5283,2.4955 2.5453,2.4787 2.5589,2.4805C2.567,2.4638 2.5817,2.4511 2.5995,2.4456C2.6032,2.4253 2.6379,2.4093 2.6677,2.3976C2.686,2.3907 2.7062,2.3907 2.7245,2.3976C2.7307,2.3941 2.7365,2.39 2.7419,2.3853C2.744,2.3827 2.7459,2.3755 2.7419,2.3587C2.743,2.343 2.749,2.3281 2.7589,2.316C2.7678,2.3019 2.7833,2.2933 2.8,2.2933L2.8,2.2933C2.8273,2.2948 2.8512,2.3121 2.8611,2.3376C2.868,2.3523 2.8649,2.3699 2.8533,2.3813C2.8514,2.3884 2.85,2.3956 2.8491,2.4029C2.8491,2.408 2.8491,2.412 2.8472,2.4139C2.8466,2.4159 2.8451,2.4175 2.8432,2.4184C2.8379,2.4203 2.8322,2.4203 2.8269,2.4184C2.8235,2.4232 2.8195,2.4275 2.8149,2.4312C2.81,2.4362 2.8033,2.4389 2.7963,2.4387C2.7941,2.4408 2.7917,2.4426 2.7891,2.444L2.8256,2.4627L2.8216,2.5765L2.8192,2.6731C2.8628,2.674 2.9042,2.6922 2.9344,2.7237L2.9344,2.7251C2.9444,2.7781 2.9623,2.8292 2.9877,2.8768C2.9949,2.8837 3.0117,2.8965 3.0291,2.9099C3.0824,2.9509 3.0931,2.9603 3.0899,2.9656C3.0867,2.9709 3.0851,2.9696 3.0787,2.9699L3.076,2.9696ZM3.0152,2.9429L3.0187,2.9477C3.0334,2.9592 3.0515,2.9654 3.0701,2.9653C3.0752,2.9664 3.0805,2.9664 3.0856,2.9653C3.0672,2.9475 3.0475,2.9311 3.0267,2.9163C3.0088,2.9027 2.9917,2.8896 2.9845,2.8824L2.9845,2.8824C2.9585,2.8345 2.9399,2.7829 2.9296,2.7293C2.8997,2.699 2.8591,2.6817 2.8165,2.6811L2.8136,2.6811L2.816,2.5789L2.82,2.4688L2.7771,2.4464L2.7821,2.444C2.7863,2.4421 2.7901,2.4395 2.7936,2.4365L2.7949,2.4352L2.7965,2.4352C2.7997,2.4365 2.8053,2.4352 2.8115,2.4288C2.8161,2.4251 2.82,2.4207 2.8232,2.4157L2.8232,2.4136L2.8256,2.4136C2.8301,2.4156 2.8352,2.4161 2.84,2.4149C2.84,2.4145 2.84,2.414 2.84,2.4136C2.84,2.412 2.84,2.408 2.8416,2.4035C2.8426,2.3956 2.8441,2.3879 2.8461,2.3803L2.8461,2.3803L2.8461,2.3803C2.8566,2.3708 2.8597,2.3555 2.8539,2.3427C2.8448,2.3193 2.8229,2.3034 2.7979,2.3021C2.7848,2.3016 2.7723,2.307 2.7637,2.3168C2.754,2.3282 2.7479,2.3422 2.7461,2.3571C2.7501,2.3733 2.7499,2.3837 2.7461,2.3893C2.7401,2.3948 2.7334,2.3996 2.7261,2.4035L2.7261,2.4035L2.7248,2.4035C2.7077,2.3967 2.6886,2.3967 2.6715,2.4035C2.6448,2.4141 2.6077,2.4301 2.6061,2.4491L2.6061,2.4512L2.604,2.4512C2.5871,2.4556 2.573,2.467 2.5653,2.4827L2.5653,2.4851L2.5627,2.4851C2.5496,2.4824 2.5333,2.4981 2.5109,2.5344L2.5109,2.5344L2.5109,2.5344C2.4659,2.5544 2.4627,2.6525 2.4627,2.6536L2.4627,2.6552C2.4567,2.6632 2.4523,2.6722 2.4496,2.6819C2.4491,2.6868 2.4507,2.6917 2.4539,2.6955C2.4555,2.6955 2.4565,2.6955 2.4568,2.6955L2.46,2.6955L2.46,2.6987C2.4607,2.7019 2.4629,2.7047 2.4659,2.7061C2.4675,2.7061 2.4688,2.7061 2.4691,2.7061L2.4723,2.7043L2.4723,2.708C2.4723,2.7128 2.4811,2.7157 2.4856,2.7149L2.4883,2.7149L2.4883,2.7176C2.4883,2.7176 2.4904,2.7176 2.4939,2.7176L2.4955,2.7176C2.4983,2.7176 2.501,2.7169 2.5035,2.7155C2.5037,2.7112 2.5037,2.7069 2.5035,2.7027C2.5035,2.6917 2.5035,2.688 2.5035,2.6861C2.5035,2.6843 2.5085,2.6861 2.5139,2.6888C2.5173,2.6908 2.521,2.6922 2.5248,2.6931C2.5248,2.6931 2.5248,2.6861 2.5208,2.6797L2.5179,2.6776C2.5099,2.6728 2.5042,2.6649 2.5024,2.6557C2.5015,2.6419 2.5045,2.628 2.5109,2.6157L2.5109,2.6157C2.5109,2.6157 2.5616,2.5755 2.5672,2.5424L2.5672,2.54L2.5699,2.54C2.5955,2.5411 2.6199,2.5284 2.6336,2.5067L2.6387,2.5005L2.6427,2.504C2.62,2.5333 2.6181,2.5931 2.6472,2.6163L2.6472,2.6163L2.6472,2.6163C2.6501,2.652 2.6813,2.7264 2.7045,2.7328C2.7277,2.7392 2.8397,2.7653 2.8811,2.7595L2.8845,2.7595L2.8845,2.7632C2.8781,2.8165 2.9112,2.8699 2.9792,2.9205L2.9792,2.9205L2.9792,2.9221C2.9782,2.929 2.9799,2.936 2.984,2.9416C2.9924,2.9468 3.0025,2.9486 3.0123,2.9467L3.0152,2.9429Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.5515,2.3636C2.5632,2.3317 2.6048,2.3338 2.6048,2.3338C2.6048,2.3338 2.62,2.2892 2.6771,2.3156C2.6984,2.2972 2.7549,2.3237 2.7549,2.3237C2.7664,2.3064 2.7845,2.2962 2.8037,2.296C2.836,2.2979 2.8612,2.3281 2.8605,2.3641C2.8323,2.3722 2.7837,2.3386 2.7467,2.3481C2.7213,2.3595 2.6978,2.3756 2.6771,2.3957C2.6427,2.3999 2.6061,2.3606 2.5509,2.3627L2.5515,2.3636Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.6723,2.3949C2.6562,2.3934 2.6406,2.3888 2.6261,2.3814C2.604,2.3703 2.5799,2.364 2.5555,2.363L2.5475,2.363L2.5491,2.3588C2.56,2.3305 2.5952,2.3305 2.6024,2.3305C2.6069,2.3212 2.6144,2.3138 2.6235,2.3096C2.641,2.3032 2.6602,2.3045 2.6768,2.3133C2.6979,2.2983 2.7443,2.3164 2.7544,2.3206C2.7662,2.3041 2.7847,2.2945 2.8043,2.2949C2.8252,2.2965 2.8442,2.3087 2.8552,2.3277C2.8619,2.3382 2.8648,2.351 2.8632,2.3636L2.8632,2.365L2.8632,2.365C2.8458,2.3668 2.8282,2.3644 2.8117,2.3579C2.792,2.3501 2.7708,2.3473 2.7499,2.3497L2.7299,2.3605C2.7117,2.368 2.6952,2.3794 2.6813,2.3938L2.6813,2.3938L2.6747,2.3938L2.6723,2.3949ZM2.5557,2.3648C2.5808,2.366 2.6055,2.3732 2.6283,2.386C2.6431,2.3952 2.6594,2.4002 2.676,2.4008C2.6903,2.384 2.7073,2.3708 2.7259,2.3619C2.7331,2.3577 2.74,2.3535 2.7459,2.3494L2.7459,2.3494C2.7679,2.3462 2.7902,2.3494 2.8109,2.3587C2.8259,2.3654 2.8419,2.3683 2.8579,2.3674C2.8578,2.3559 2.855,2.3448 2.8499,2.3352C2.84,2.3152 2.8225,2.3023 2.8032,2.3008C2.7849,2.3014 2.7679,2.3119 2.7568,2.3294L2.7568,2.3317L2.7549,2.3317C2.7549,2.3317 2.6997,2.304 2.6797,2.3223L2.6797,2.3223L2.6797,2.3223C2.6644,2.3127 2.6465,2.311 2.6301,2.3175C2.6217,2.3218 2.615,2.3297 2.6112,2.3397L2.6112,2.342L2.6053,2.342C2.6053,2.342 2.5688,2.3375 2.5557,2.3648L2.5557,2.3648Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.6584,2.404C2.6712,2.3963 2.7027,2.3824 2.724,2.3992C2.7413,2.4165 2.7603,2.4321 2.7808,2.4456L2.8197,2.4621L2.8373,2.4731L2.8267,2.6515C2.7904,2.6144 2.7568,2.608 2.7309,2.5645C2.7171,2.5459 2.7277,2.5013 2.7043,2.4717C2.6808,2.4421 2.6547,2.4221 2.66,2.404L2.6584,2.404Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.828,2.6576L2.8237,2.6533C2.811,2.6406 2.7971,2.6292 2.7821,2.6192C2.7604,2.6058 2.7422,2.5876 2.7288,2.5659C2.7227,2.5547 2.7195,2.5423 2.7195,2.5296C2.719,2.5096 2.7129,2.4901 2.7019,2.4733L2.6835,2.4523C2.6661,2.4333 2.6525,2.4181 2.6568,2.4032L2.6568,2.4032L2.6568,2.4032C2.6611,2.4008 2.6995,2.3781 2.7253,2.3987C2.7425,2.416 2.7615,2.4316 2.7819,2.4451L2.8203,2.4611L2.84,2.4731L2.84,2.4749L2.828,2.6576ZM2.6608,2.4059C2.6581,2.4176 2.6707,2.4325 2.6875,2.4488C2.6936,2.4555 2.6997,2.4624 2.7059,2.4699C2.7179,2.4873 2.7245,2.5079 2.7248,2.5291C2.7249,2.5409 2.7278,2.5525 2.7333,2.5629C2.7467,2.5846 2.765,2.6029 2.7867,2.6163C2.8003,2.6253 2.8132,2.6354 2.8251,2.6467L2.8363,2.4757L2.8197,2.4659L2.7813,2.4496C2.7598,2.4352 2.7399,2.4186 2.7219,2.4C2.7005,2.384 2.6667,2.4016 2.6608,2.4059Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.752,2.4572C2.752,2.4572 2.7832,2.4496 2.7925,2.4572C2.8018,2.4647 2.8135,2.4663 2.8168,2.4788C2.8285,2.4831 2.8366,2.4912 2.8366,2.5031C2.8475,2.5068 2.852,2.5333 2.852,2.5333L2.8415,2.5538C2.835,2.5457 2.8305,2.5352 2.8285,2.5236C2.8208,2.5187 2.8046,2.5133 2.8006,2.4993C2.7893,2.4991 2.7795,2.4886 2.7771,2.4739C2.765,2.4771 2.7528,2.455 2.7528,2.455L2.752,2.4572Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8376,2.5517L2.8342,2.5479C2.8282,2.5405 2.8238,2.5313 2.8214,2.5212L2.8176,2.5212C2.8089,2.5185 2.8013,2.512 2.7961,2.5029C2.786,2.502 2.7772,2.4937 2.7738,2.4818C2.7645,2.4797 2.7563,2.4729 2.7512,2.463L2.7467,2.4546L2.7527,2.4546C2.758,2.4546 2.7829,2.448 2.7904,2.4546L2.7904,2.4546C2.7997,2.4565 2.8079,2.4631 2.8131,2.4729C2.8244,2.4776 2.8312,2.4855 2.8323,2.4949C2.8425,2.501 2.8463,2.5212 2.8467,2.5235L2.8467,2.5235L2.8376,2.5517ZM2.7812,2.4626L2.7812,2.4702C2.7835,2.486 2.7934,2.4972 2.8048,2.4969L2.8077,2.4969L2.8077,2.501C2.8106,2.5126 2.8227,2.5188 2.8314,2.5235L2.8387,2.5283L2.8387,2.5283L2.8387,2.5324C2.8402,2.5429 2.8437,2.5526 2.8488,2.5605L2.8565,2.5441C2.8565,2.5352 2.8493,2.5167 2.842,2.514L2.8382,2.514L2.8382,2.5105C2.8382,2.4975 2.8275,2.49 2.8184,2.4859L2.8184,2.4859L2.8184,2.4859C2.816,2.4743 2.8058,2.4695 2.7947,2.464L2.7908,2.464C2.7796,2.4593 2.7677,2.4593 2.7565,2.464C2.7614,2.4708 2.7686,2.4784 2.7744,2.4763L2.7812,2.4626Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.9248,2.3392C2.9131,2.3261 2.8928,2.3357 2.8928,2.3357L2.8395,2.4299L2.8155,2.4499L2.8133,2.5235L2.8333,2.5925L2.8264,2.6459C2.8391,2.6345 2.8495,2.6209 2.8571,2.6056C2.8565,2.5857 2.8531,2.5659 2.8469,2.5469C2.8365,2.521 2.8377,2.4918 2.8504,2.4669C2.8701,2.4136 2.9152,2.372 2.9261,2.3392L2.9248,2.3392Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8213,2.6531L2.8291,2.5928L2.8093,2.524L2.8115,2.4485L2.836,2.4283L2.8907,2.3336L2.8907,2.3336C2.8907,2.3336 2.9133,2.3232 2.9261,2.3376L2.9261,2.3376L2.9261,2.3392C2.9181,2.3583 2.9075,2.3762 2.8947,2.3925C2.8767,2.4157 2.8618,2.4411 2.8501,2.468C2.8381,2.4923 2.8368,2.5206 2.8467,2.5459C2.8531,2.5654 2.8566,2.5858 2.8571,2.6064C2.8498,2.6221 2.8394,2.6361 2.8267,2.6477L2.8213,2.6531ZM2.8147,2.5232L2.8347,2.5923L2.8347,2.5923L2.8288,2.6376C2.839,2.6282 2.8473,2.6169 2.8531,2.6043C2.8525,2.5847 2.8491,2.5653 2.8429,2.5467C2.8322,2.5202 2.8335,2.4905 2.8464,2.4651C2.8582,2.4377 2.8735,2.4119 2.8917,2.3883C2.9038,2.3732 2.9138,2.3566 2.9216,2.3389C2.9137,2.3336 2.9035,2.3329 2.8949,2.3371L2.84,2.4312L2.8171,2.4504L2.8147,2.5232Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.0597,2.4232C3.0027,2.4993 2.9244,2.5569 2.8347,2.5885C2.796,2.5976 2.8101,2.4984 2.8101,2.4984L2.8005,2.5011C2.8005,2.5011 2.7789,2.5984 2.8307,2.5995C2.9709,2.5728 3.0763,2.424 3.0763,2.424L3.0595,2.424L3.0597,2.4232Z" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8312,2.6021C2.8208,2.6026 2.8109,2.5981 2.8045,2.5899C2.7837,2.5632 2.7968,2.5029 2.7973,2.5005L2.7973,2.4989L2.8125,2.4947L2.8125,2.4987C2.8125,2.4987 2.8032,2.5667 2.8211,2.5832C2.8246,2.5862 2.8294,2.5872 2.8339,2.5859C2.9228,2.5541 3.0005,2.497 3.0573,2.4216L3.0589,2.4216L3.0589,2.4195L3.0656,2.4195L3.0656,2.4195L3.0824,2.4195L3.0795,2.4237C3.0773,2.4267 2.9709,2.5744 2.8312,2.6021ZM2.8029,2.5032C2.8008,2.5128 2.7917,2.5643 2.8093,2.5867C2.8145,2.5932 2.8224,2.5969 2.8307,2.5968C2.9549,2.5723 3.0528,2.4504 3.0707,2.4264L3.0605,2.4264C3.0032,2.5025 2.9247,2.56 2.8349,2.5917C2.8288,2.5936 2.8221,2.5921 2.8173,2.5877C2.7997,2.5717 2.8045,2.5181 2.8064,2.5027L2.8029,2.5032Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.1176,3.1243C3.1084,3.1301 3.0967,3.1301 3.0875,3.1243C3.0811,3.1117 3.0687,3.1034 3.0547,3.1024C3.0547,3.1024 3.0395,3.0581 3.0152,3.0709C3.0115,3.048 2.9851,3.06 2.9851,3.06C2.9851,3.06 2.9851,3.0269 2.9536,3.0315C2.964,2.9933 2.9112,2.9957 2.9112,2.9957C2.9112,2.9957 2.9096,2.9531 2.8312,2.9616C2.9981,2.8869 3.1304,3.0792 3.1304,3.0792" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.1029,3.1312C3.097,3.1311 3.0913,3.1296 3.0861,3.1267L3.0861,3.1267L3.0861,3.1267C3.0802,3.1151 3.0687,3.1074 3.0557,3.1064L3.0539,3.1064L3.0539,3.1045C3.0539,3.1045 3.0448,3.0779 3.0307,3.0736C3.0266,3.0718 3.0219,3.0718 3.0179,3.0736L3.0147,3.0755L3.0147,3.0717C3.0143,3.0674 3.012,3.0636 3.0083,3.0613C3.0018,3.0589 2.9947,3.0589 2.9883,3.0613L2.9845,3.0632L2.9845,3.0589C2.9842,3.0508 2.9808,3.0432 2.9752,3.0373C2.9699,3.0331 2.9629,3.0315 2.9563,3.0331L2.952,3.0331L2.952,3.0291C2.9546,3.0222 2.9536,3.0145 2.9493,3.0085C2.9392,2.996 2.9128,2.9971 2.9125,2.9968L2.9099,2.9968L2.9099,2.9941C2.909,2.9863 2.9049,2.9792 2.8987,2.9744C2.8794,2.9619 2.856,2.9576 2.8336,2.9624L2.8336,2.9573C3.0008,2.8824 3.1349,3.0739 3.1363,3.0757L3.1317,3.0789C3.1075,3.0459 3.0784,3.0168 3.0453,2.9925C2.98,2.9459 2.9149,2.9333 2.8515,2.956C2.8704,2.9539 2.8895,2.959 2.9048,2.9704C2.9112,2.9757 2.9157,2.983 2.9173,2.9912C2.9316,2.9904 2.9457,2.9954 2.9563,3.0051C2.961,3.0111 2.9626,3.019 2.9608,3.0264C2.9678,3.0257 2.9748,3.0278 2.9803,3.0323C2.9864,3.0382 2.9902,3.046 2.9912,3.0544C2.9981,3.0517 3.0057,3.0517 3.0125,3.0544C3.0135,3.0592 3.0167,3.0632 3.021,3.0654C3.0254,3.0676 3.0305,3.0677 3.0349,3.0656C3.0491,3.0712 3.0581,3.0923 3.0616,3.0981C3.0756,3.0995 3.088,3.108 3.0944,3.1205C3.1027,3.1253 3.1128,3.1253 3.1211,3.1205L3.1243,3.1248C3.1183,3.1297 3.1106,3.132 3.1029,3.1312Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.1968,3.1405C3.1968,3.1405 3.2355,3.2042 3.2555,3.2046C3.2755,3.205 3.2773,3.1425 3.2773,3.1425C3.2773,3.1425 3.284,3.1695 3.2939,3.1624C3.2935,3.1737 3.2986,3.1839 3.3061,3.1866C3.3061,3.1866 3.2712,3.3039 3.1728,3.1925" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.2488,3.2387C3.2198,3.2353 3.1923,3.2191 3.1707,3.1925L3.1733,3.1859C3.208,3.2223 3.2381,3.2368 3.2632,3.2278C3.2798,3.2214 3.2938,3.2061 3.3019,3.1852C3.2958,3.182 3.2915,3.1744 3.2907,3.1656C3.2892,3.1661 3.2876,3.1661 3.2861,3.1656C3.2831,3.1633 3.2805,3.1601 3.2787,3.1561C3.2768,3.1739 3.2712,3.2045 3.2552,3.2045L3.2552,3.2045C3.2341,3.2045 3.196,3.1463 3.1944,3.1438L3.1987,3.1387C3.2091,3.155 3.2397,3.1968 3.2552,3.1972L3.2552,3.1972C3.2693,3.1972 3.2739,3.1579 3.2741,3.143L3.2795,3.143C3.2795,3.1467 3.284,3.1572 3.2883,3.1598C3.2894,3.1607 3.2908,3.1607 3.292,3.1598L3.2963,3.1572L3.2963,3.1634C3.296,3.1722 3.3004,3.18 3.3067,3.1819L3.3096,3.1819L3.3083,3.1859C3.2997,3.2103 3.284,3.2285 3.2651,3.2361C3.2597,3.2379 3.2543,3.2387 3.2488,3.2387L3.2488,3.2387Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8947,3.1585L2.8811,3.226C2.8811,3.226 2.8635,3.245 2.8688,3.2492C2.8741,3.2534 2.9016,3.2424 2.9016,3.2424C2.9213,3.2403 2.9404,3.233 2.9576,3.2212C2.9627,3.2353 2.9735,3.2453 2.9861,3.2476C2.9874,3.2421 2.9874,3.2363 2.9861,3.2309C2.992,3.2327 2.9981,3.2327 3.004,3.2309C3.004,3.2309 3.0093,3.2119 2.9971,3.2045C2.9971,3.1907 3.0043,3.1781 2.9835,3.1797C2.968,3.1997 2.9301,3.2222 2.9205,3.2144C2.9109,3.2067 2.9581,3.1823 2.9451,3.1501" + android:strokeWidth="1" + android:fillColor="#96877D" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M2.8731,3.2462C2.8711,3.2468 2.8691,3.2468 2.8672,3.2462C2.8659,3.2454 2.8651,3.2438 2.8651,3.2421C2.8651,3.2358 2.8747,3.2248 2.8787,3.2209L2.892,3.1592L2.8973,3.1592L2.8835,3.2227L2.8835,3.2227C2.8768,3.2292 2.8707,3.2373 2.8709,3.2397C2.8812,3.2393 2.8914,3.237 2.9011,3.2328C2.9205,3.2307 2.9393,3.2241 2.9563,3.2134L2.9589,3.2105L2.9605,3.2146C2.965,3.2257 2.9737,3.2339 2.9843,3.2367C2.9851,3.2333 2.9851,3.2297 2.9843,3.2263L2.9816,3.2209L2.9872,3.2209C2.9922,3.2222 2.9974,3.2222 3.0024,3.2209C3.0047,3.2137 3.0023,3.2057 2.9965,3.2015L2.9947,3.2015L2.9947,3.1994L2.9947,3.1932C2.9947,3.1884 2.9963,3.1839 2.9947,3.1821C2.9931,3.1804 2.9912,3.1795 2.9843,3.1798C2.9688,3.1973 2.9309,3.2203 2.9187,3.2117C2.9173,3.2106 2.9164,3.209 2.916,3.2072C2.916,3.2027 2.9197,3.1982 2.9259,3.1917C2.932,3.1851 2.9493,3.166 2.9421,3.1491L2.9472,3.1467C2.956,3.1672 2.94,3.1845 2.9296,3.1962C2.9261,3.1997 2.9216,3.2048 2.9216,3.2066C2.9285,3.2119 2.9648,3.1941 2.9811,3.175L2.9811,3.175L2.9811,3.175C2.9896,3.175 2.9944,3.175 2.9971,3.1792C2.9997,3.1833 2.9995,3.1893 2.9971,3.1956C2.9972,3.1968 2.9972,3.1981 2.9971,3.1994C3.0045,3.2058 3.0071,3.2169 3.0035,3.2266L3.0035,3.2266L3.0021,3.2266C2.9974,3.2282 2.9924,3.2289 2.9875,3.2286C2.9882,3.2327 2.9882,3.2368 2.9875,3.2409L2.9875,3.2438L2.9867,3.2438C2.9742,3.242 2.9633,3.2336 2.9573,3.2212C2.9403,3.2311 2.9218,3.2371 2.9027,3.2391C2.8931,3.2429 2.8832,3.2453 2.8731,3.2462L2.8731,3.2462Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_nl.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_nl.xml new file mode 100644 index 0000000000000000000000000000000000000000..bc872e80f0e390d41674aec201b6cbb04535c898 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_nl.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,10.9091l24,0l0,5l-24,0z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.4545l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_no.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_no.xml new file mode 100644 index 0000000000000000000000000000000000000000..f51735c2ea4e24a0c476bad9ec49dcbeb93fd137 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_no.xml @@ -0,0 +1,40 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,6l24,0l0,4.3636l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0909,0l4.3636,0l0,16l-4.3636,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1818,0l2.1818,0l0,16l-2.1818,0z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,7.0909l24,0l0,2.1818l-24,0z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_pl.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_pl.xml new file mode 100644 index 0000000000000000000000000000000000000000..009984d349b65cceecdd0301004b21265402cf3d --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_pl.xml @@ -0,0 +1,22 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,8l24,0l0,8l-24,0z" + android:strokeWidth="1" + android:fillColor="#F44336" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0l24,0l0,8l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_pt.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_pt.xml new file mode 100644 index 0000000000000000000000000000000000000000..821daa5667b574be948b2bc7c75eba54dd9fd65d --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_pt.xml @@ -0,0 +1,550 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l0,8l0,8l24,0l0,-8l0,-8z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,0l0,8l0,8l9.8182,0l0,-8l0,-8z" + android:strokeWidth="1" + android:fillColor="#2E7D32" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.2191,10.8573C11.9078,10.818 5.8942,7.0789 5.8527,6.4833L6.1849,5.9318C6.7816,6.7953 12.9295,10.4313 13.5333,10.3025L13.2191,10.8573" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.2191,10.8693C13.2191,10.8693 13.2191,10.8693 13.2191,10.8693C12.5198,10.8485 10.5382,9.7893 9.0529,8.8893C7.5213,7.9609 5.8625,6.8122 5.8402,6.4838C5.8402,6.4811 5.8407,6.4789 5.8418,6.4767L6.174,5.9253C6.1762,5.9215 6.18,5.9193 6.1844,5.9193C6.1887,5.9193 6.1925,5.9209 6.1947,5.9247C6.5002,6.3671 8.2571,7.5262 9.8624,8.4785C11.7562,9.6022 13.2627,10.3467 13.53,10.2905C13.5349,10.2895 13.5398,10.2916 13.5425,10.2955C13.5453,10.2993 13.5458,10.3047 13.5436,10.3091L13.2305,10.8622C13.2289,10.866 13.2245,10.8693 13.2191,10.8693ZM5.8653,6.486C5.8958,6.7604 7.2382,7.7596 9.066,8.868C10.5431,9.7636 12.5111,10.8158 13.212,10.8442L13.5104,10.3173C13.1318,10.3358 11.4164,9.4287 9.8504,8.4993C8.2615,7.5562 6.5231,6.4102 6.1865,5.9536L5.8653,6.486Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1151,5.8565C5.9973,6.1718 7.6844,7.2109 9.714,8.4404C11.7436,9.6698 13.4935,10.4296 13.6233,10.3205C13.6315,10.3064 13.6871,10.2109 13.6822,10.2115C13.6576,10.248 13.5987,10.2595 13.5065,10.2327C12.9584,10.0751 11.5282,9.4211 9.7571,8.3515C7.986,7.2813 6.4451,6.2956 6.2056,5.8767C6.1887,5.8478 6.1773,5.7949 6.1795,5.7535L6.1735,5.7535L6.1227,5.8424L6.1151,5.8565L6.1151,5.8565L6.1151,5.8565ZM13.2502,10.8742C13.2278,10.9145 13.1864,10.9156 13.1078,10.9069C12.6175,10.8529 11.1289,10.1318 9.3676,9.0818C7.3184,7.86 5.6258,6.7462 5.8091,6.4555L5.8593,6.3676L5.8691,6.3709C5.7038,6.864 9.2095,8.8609 9.4156,8.988C11.4442,10.2398 13.1542,10.9707 13.3053,10.7809L13.2502,10.8742L13.2502,10.8742L13.2502,10.8742Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.1695,10.9244C13.1509,10.9244 13.1296,10.9222 13.1062,10.92C12.606,10.8649 11.1011,10.1307 9.3611,9.0927C7.0358,7.7062 5.8669,6.8716 5.7878,6.5411C5.7791,6.5051 5.7829,6.474 5.7987,6.4489L5.8484,6.3616C5.8511,6.3567 5.8571,6.354 5.8631,6.3562L5.8729,6.3595C5.8762,6.3605 5.8789,6.3627 5.88,6.3655C5.8816,6.3682 5.8816,6.372 5.8805,6.3753C5.826,6.5389 6.1953,7.0838 9.2847,8.8969C9.3551,8.9384 9.4031,8.9662 9.4222,8.9782C11.4245,10.2136 13.1487,10.9582 13.2955,10.7738C13.2993,10.7689 13.3069,10.7673 13.3124,10.7711C13.3179,10.7749 13.3195,10.782 13.3162,10.7875L13.2611,10.8818L13.26,10.8818C13.2409,10.9145 13.2109,10.9244 13.1695,10.9244ZM5.8505,6.4069L5.8195,6.4615C5.8069,6.4816 5.8042,6.5056 5.8113,6.5351C5.8893,6.8585 7.0544,7.6882 9.3736,9.0709C11.1109,10.1067 12.612,10.8398 13.1089,10.8944C13.1858,10.9025 13.2207,10.9009 13.2393,10.8676L13.2398,10.8665L13.2715,10.812C13.2545,10.8164 13.2338,10.8185 13.2098,10.8185C12.7822,10.8185 11.2315,10.1215 9.4091,8.9967C9.39,8.9847 9.3425,8.9569 9.2722,8.916C7.002,7.5851 5.8522,6.7418 5.8505,6.4069ZM13.5835,10.3418C13.2627,10.3418 11.6144,9.6065 9.7075,8.4513C7.5235,7.128 5.9858,6.1669 6.1036,5.8527C6.1036,5.8522 6.1042,5.8516 6.1042,5.8516L6.1113,5.8375L6.1625,5.748C6.1647,5.7442 6.1691,5.742 6.1735,5.742L6.1795,5.742C6.1827,5.742 6.186,5.7436 6.1882,5.7458C6.1904,5.7485 6.1915,5.7518 6.1915,5.7551C6.1893,5.7927 6.2002,5.8435 6.216,5.8713C6.4696,6.3147 8.2445,7.4242 9.7631,8.3416C11.4284,9.3475 12.9082,10.0489 13.5098,10.2218C13.5905,10.2447 13.6495,10.2393 13.6718,10.2055C13.6735,10.2027 13.6767,10.2005 13.68,10.2C13.6849,10.1995 13.6898,10.2016 13.6925,10.2055C13.698,10.2136 13.6991,10.2147 13.6407,10.3162L13.6342,10.3276C13.6336,10.3287 13.6325,10.3298 13.6315,10.3309C13.6222,10.338 13.6058,10.3418 13.5835,10.3418ZM6.126,5.862C6.0115,6.1833 7.9816,7.3767 9.72,8.43C11.8053,9.6933 13.4842,10.4035 13.6135,10.3129L13.6189,10.3036C13.6304,10.2835 13.6402,10.266 13.6478,10.2524C13.6124,10.2649 13.5627,10.2627 13.5022,10.2458C12.8995,10.0724 11.4169,9.3704 9.7495,8.3635C8.2287,7.4449 6.45,6.3327 6.1936,5.8844C6.18,5.8609 6.1702,5.8244 6.1669,5.79L6.126,5.862Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8302,6.8438C11.1425,6.8335 12.7625,6.6649 13.6947,6.2951L13.494,5.97C12.9431,6.2738 11.3144,6.4735 9.8193,6.5035C8.0509,6.4871 6.8029,6.3235 6.1773,5.9051L5.9875,6.2515C7.1373,6.7358 8.3149,6.8389 9.8302,6.8438" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8302,6.8564L9.8302,6.8564C8.3122,6.8515 7.1389,6.7505 5.9825,6.2629C5.9793,6.2618 5.9771,6.2591 5.9755,6.2558C5.9744,6.2525 5.9744,6.2487 5.9765,6.246L6.1664,5.8996C6.168,5.8964 6.1707,5.8942 6.1745,5.8936C6.1778,5.8925 6.1816,5.8936 6.1844,5.8953C6.7669,6.2847 7.9222,6.474 9.8198,6.4915C11.1709,6.4642 12.8956,6.2864 13.4885,5.9596C13.4945,5.9564 13.5016,5.9585 13.5049,5.964L13.7056,6.2891C13.7073,6.2924 13.7078,6.2962 13.7067,6.2995C13.7056,6.3027 13.7029,6.3055 13.6996,6.3071C12.7162,6.6976 11.0569,6.8471 9.8313,6.8569L9.8302,6.8564ZM6.0049,6.2455C7.1531,6.7265 8.3204,6.8269 9.8296,6.8318C9.8296,6.8318 9.8302,6.8318 9.8302,6.8318C11.0476,6.822 12.6944,6.6747 13.6767,6.2896L13.4896,5.9875C12.8836,6.3125 11.166,6.4898 9.8193,6.5165C7.9282,6.4991 6.7718,6.3109 6.1816,5.9236L6.0049,6.2455Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.7487,6.3027C13.7165,6.354 13.1089,6.5629 12.2133,6.7167C11.6062,6.8089 10.8142,6.888 9.8253,6.8885C8.886,6.8896 8.1191,6.8231 7.5382,6.7445C6.5978,6.5978 6.1129,6.3933 5.9335,6.3213C5.9504,6.2875 5.9618,6.2635 5.9782,6.2318C6.4947,6.4364 6.9818,6.5602 7.5529,6.6475C8.13,6.7255 8.8876,6.7931 9.822,6.792C10.806,6.7909 11.5893,6.7064 12.1931,6.6169C13.1116,6.4691 13.6129,6.2793 13.6838,6.1915L13.7487,6.3027L13.7487,6.3027L13.7487,6.3027ZM13.5725,5.9727C13.4733,6.0524 12.9769,6.2275 12.1042,6.3665C11.5216,6.4495 10.7815,6.5242 9.8351,6.5253C8.9362,6.5264 8.202,6.4658 7.6435,6.3845C6.7571,6.2695 6.2858,6.0611 6.1156,6.0005C6.1325,5.9716 6.15,5.9427 6.1675,5.9133C6.3,5.9798 6.7549,6.1636 7.6533,6.2902C8.2053,6.3682 8.9411,6.4265 9.8351,6.4255C10.7765,6.4244 11.5085,6.3485 12.0873,6.2662C12.9644,6.1462 13.4362,5.9225 13.5082,5.8664L13.5725,5.9727L13.5725,5.9727L13.5725,5.9727Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8067,6.9011C9.0093,6.9011 8.2456,6.8525 7.5365,6.7571C6.6267,6.6153 6.1336,6.4156 5.9482,6.3409L5.9291,6.3327C5.9258,6.3316 5.9231,6.3289 5.922,6.3256C5.9209,6.3224 5.9209,6.3185 5.9225,6.3158C5.9296,6.3022 5.9356,6.2902 5.9411,6.2782C5.9493,6.2613 5.9575,6.2449 5.9673,6.2258C5.97,6.2204 5.9771,6.2176 5.9831,6.2198C6.4778,6.4162 6.9627,6.5438 7.5551,6.6349C8.2653,6.7309 9.0224,6.7795 9.8051,6.7795C9.8111,6.7795 9.8165,6.7795 9.8225,6.7795C10.6265,6.7789 11.4016,6.7211 12.1915,6.6044C13.0985,6.4587 13.6042,6.2705 13.674,6.1833C13.6767,6.18 13.68,6.1784 13.6849,6.1784C13.6887,6.1789 13.6925,6.1811 13.6947,6.1844L13.7596,6.2956C13.7618,6.2995 13.7618,6.3044 13.7596,6.3082C13.7591,6.3093 13.7585,6.3098 13.758,6.3104C13.7084,6.372 13.0822,6.5787 12.2155,6.7282C11.4687,6.8416 10.6647,6.8995 9.8258,6.9005C9.8193,6.9011 9.8127,6.9011 9.8067,6.9011ZM5.9509,6.3147L5.958,6.3175C6.1429,6.3922 6.6338,6.5907 7.5404,6.732C8.2478,6.8275 9.0109,6.876 9.8067,6.876C9.8127,6.876 9.8193,6.876 9.8253,6.876C10.6631,6.8755 11.4655,6.8176 12.2111,6.7042C13.098,6.5515 13.6713,6.3513 13.7335,6.3005L13.6816,6.2111C13.5813,6.3005 13.1149,6.4811 12.1958,6.6284C11.4044,6.7456 10.6282,6.8029 9.8231,6.804C9.0316,6.8051 8.2691,6.756 7.5518,6.6595C6.9616,6.5689 6.4778,6.4418 5.9847,6.2471C5.9771,6.2618 5.9705,6.2749 5.964,6.2885C5.9596,6.2973 5.9553,6.3055 5.9509,6.3147ZM9.8171,6.5373C9.0284,6.5373 8.2767,6.4887 7.6424,6.3965C6.858,6.2945 6.4025,6.1216 6.1838,6.0387C6.156,6.0278 6.132,6.0191 6.1124,6.012C6.1091,6.0109 6.1064,6.0082 6.1047,6.0044C6.1031,6.0005 6.1036,5.9973 6.1058,5.994C6.1227,5.9645 6.1402,5.9356 6.1576,5.9067C6.1609,5.9013 6.168,5.8991 6.174,5.9018C6.2515,5.9405 6.6862,6.1407 7.656,6.2776C8.0935,6.3393 8.8216,6.4129 9.8155,6.4129C9.8225,6.4129 9.8291,6.4129 9.8362,6.4129C10.8611,6.4118 11.6111,6.3213 12.0867,6.2536C12.9256,6.1385 13.4171,5.9225 13.5016,5.8565C13.5044,5.8544 13.5082,5.8533 13.5115,5.8544C13.5147,5.8549 13.518,5.8571 13.5196,5.8604L13.5835,5.9662C13.5845,5.9684 13.5851,5.9705 13.5851,5.9705C13.5851,5.9765 13.5835,5.9804 13.5802,5.9825C13.4825,6.0605 12.996,6.2373 12.1064,6.3785C11.364,6.4844 10.6211,6.5362 9.8356,6.5373C9.8291,6.5373 9.8231,6.5373 9.8171,6.5373ZM6.1342,5.994C6.1511,6 6.1702,6.0076 6.1925,6.0158C6.4107,6.0987 6.864,6.2705 7.6456,6.372C8.2789,6.4636 9.0295,6.5122 9.8171,6.5122C9.8231,6.5122 9.8296,6.5122 9.8356,6.5122C10.62,6.5116 11.3618,6.4598 12.1025,6.354C12.9638,6.2171 13.4427,6.0485 13.5562,5.9695L13.5049,5.8844C13.4095,5.9471 12.9562,6.1598 12.0895,6.2782C11.6133,6.3464 10.8616,6.4369 9.8356,6.438C9.8285,6.438 9.822,6.438 9.8149,6.438C8.8195,6.438 8.0896,6.3644 7.6516,6.3027C6.7145,6.1707 6.2738,5.9787 6.1724,5.9296C6.1598,5.9509 6.1467,5.9727 6.1342,5.994Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.52,8.4191C6.3273,8.8516 8.1207,9.0698 9.8176,9.0845C11.3629,9.0867 13.3756,8.8467 14.1284,8.4491L14.1076,8.016C13.872,8.3825 11.7153,8.7344 9.8013,8.7196C7.8873,8.7055 6.1096,8.4109 5.5173,8.0296L5.52,8.4191" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.84,9.0971C9.8324,9.0971 9.8247,9.0971 9.8171,9.0971C8.3138,9.084 6.3938,8.9018 5.514,8.43C5.5096,8.4278 5.5075,8.4229 5.5075,8.4185L5.5042,8.0302C5.5042,8.0258 5.5064,8.0215 5.5107,8.0193C5.5145,8.0171 5.5195,8.0171 5.5233,8.0198C6.1211,8.4044 7.92,8.694 9.8007,8.7082C11.6973,8.7213 13.8655,8.37 14.0967,8.01C14.0995,8.0056 14.1055,8.0035 14.1104,8.0045C14.1158,8.0062 14.1191,8.0105 14.1196,8.016L14.1404,8.4491C14.1404,8.454 14.1382,8.4584 14.1338,8.4605C13.3767,8.8598 11.3618,9.0971 9.84,9.0971ZM5.532,8.412C6.4113,8.8789 8.3204,9.0595 9.8171,9.0725C11.3329,9.0747 13.3522,8.8402 14.1147,8.4425L14.0962,8.0515C13.7722,8.4136 11.6902,8.7475 9.8002,8.7333C7.9353,8.7191 6.1489,8.4344 5.5287,8.0536L5.532,8.412Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M14.1687,8.3569L14.1687,8.46C14.0558,8.5947 13.3462,8.7982 12.4565,8.9416C11.7796,9.0453 10.8971,9.1233 9.7969,9.1233C8.7518,9.1233 7.9189,9.0491 7.2725,8.9504C6.2509,8.802 5.598,8.5429 5.4665,8.4655L5.4671,8.3449C5.8609,8.6056 6.9284,8.7965 7.2867,8.8549C7.9287,8.9531 8.7567,9.0267 9.7964,9.0267C10.8911,9.0267 11.7687,8.9493 12.4413,8.8467C13.0805,8.7545 13.9898,8.5162 14.1687,8.3569L14.1687,8.3569L14.1687,8.3569ZM14.1693,7.9898L14.1693,8.0929C14.0564,8.2276 13.3467,8.4311 12.4571,8.5745C11.7802,8.6782 10.8976,8.7562 9.7975,8.7562C8.7524,8.7562 7.9195,8.682 7.2731,8.5833C6.2515,8.4355 5.5985,8.1758 5.4671,8.0984L5.4676,7.9778C5.8615,8.2385 6.9289,8.4295 7.2873,8.4878C7.9293,8.586 8.7573,8.6596 9.7969,8.6596C10.8916,8.6596 11.7693,8.5822 12.4418,8.4791C13.0811,8.3875 13.9904,8.1485 14.1693,7.9898L14.1693,7.9898L14.1693,7.9898Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.7975,9.1358C8.8729,9.1358 8.0231,9.0775 7.2715,8.9629C6.2935,8.8211 5.6187,8.5691 5.4611,8.4764C5.4573,8.4742 5.4551,8.4698 5.4551,8.4655L5.4556,8.3449C5.4556,8.3405 5.4584,8.3362 5.4622,8.334C5.466,8.3318 5.4709,8.3318 5.4747,8.3345C5.8696,8.5964 6.9638,8.7895 7.2895,8.8429C8.034,8.9569 8.8778,9.0147 9.7975,9.0147C10.7689,9.0147 11.658,8.9542 12.4407,8.8347C13.074,8.7436 13.9816,8.5064 14.1605,8.3482C14.1638,8.3455 14.1676,8.3444 14.172,8.3449C14.1775,8.346 14.1818,8.3515 14.1818,8.3569L14.1818,8.46C14.1818,8.4627 14.1807,8.4655 14.1791,8.4682C14.0618,8.6084 13.3385,8.8124 12.4593,8.9542C11.67,9.0747 10.7749,9.1358 9.7975,9.1358ZM5.4796,8.4584C5.5964,8.5233 6.2242,8.7856 7.2747,8.9384C8.0253,9.0529 8.8735,9.1113 9.7969,9.1113C10.7727,9.1113 11.6673,9.0502 12.4544,8.9302C13.3069,8.7927 14.0345,8.5898 14.1556,8.4562L14.1556,8.3836C13.9342,8.544 13.0587,8.7715 12.4435,8.8598C11.6596,8.9793 10.7689,9.0404 9.7964,9.0404C8.8756,9.0404 8.0307,8.9825 7.2845,8.8685C6.9622,8.8162 5.8931,8.6269 5.4791,8.3689L5.4796,8.4584ZM9.798,8.7682C8.8724,8.7682 8.0225,8.7098 7.272,8.5953C6.294,8.4535 5.6193,8.202 5.4616,8.1087C5.4578,8.1065 5.4556,8.1022 5.4556,8.1022L5.4562,7.9773C5.4562,7.9729 5.4589,7.9685 5.4627,7.9664C5.4665,7.9642 5.4715,7.9642 5.4753,7.9669C5.8707,8.2287 6.9644,8.4218 7.29,8.4753C8.0345,8.5893 8.8784,8.6471 9.798,8.6471C10.7695,8.6471 11.6591,8.5865 12.4413,8.4671C13.0751,8.376 13.9833,8.1387 14.1611,7.9805C14.1638,7.9778 14.1682,7.9767 14.1715,7.9778C14.1753,7.9784 14.1785,7.9811 14.1802,7.9844C14.1813,7.986 14.1818,7.9876 14.1818,7.9898L14.1818,8.0929C14.1818,8.0929 14.1807,8.0984 14.1791,8.1011C14.0618,8.2407 13.3385,8.4453 12.4598,8.5871C11.6711,8.7071 10.7755,8.7682 9.798,8.7682ZM5.4802,8.0907C5.5969,8.1556 6.2247,8.418 7.2753,8.5707C8.0247,8.6853 8.8735,8.7436 9.7975,8.7436C10.7738,8.7436 11.6678,8.6825 12.4549,8.5625C13.3075,8.4251 14.0351,8.2222 14.1562,8.0885L14.1562,8.0155C13.9347,8.1758 13.0593,8.4033 12.444,8.4916C11.6607,8.6111 10.77,8.6722 9.7969,8.6722C8.8762,8.6722 8.0313,8.6144 7.2851,8.5004C6.9633,8.448 5.8942,8.2593 5.4796,8.0007L5.4802,8.0907Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8133,10.7825C7.9565,10.7716 6.3655,10.2785 6.0295,10.1967L6.2744,10.5785C6.8678,10.8273 8.4196,11.1976 9.8307,11.1567C11.2418,11.1158 12.4751,11.0067 13.344,10.5856L13.5955,10.1896C13.0036,10.4678 10.9882,10.7798 9.8133,10.7825" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6142,11.1725C8.2827,11.1725 6.8531,10.8344 6.2705,10.59C6.2684,10.5889 6.2662,10.5873 6.2651,10.5851L6.0202,10.2033C6.0175,10.1989 6.0175,10.1935 6.0207,10.1896C6.0235,10.1853 6.0289,10.1836 6.0338,10.1847C6.0736,10.1945 6.1315,10.2098 6.2045,10.2295C6.7445,10.3745 8.1791,10.7602 9.8144,10.77C10.9964,10.7673 13.008,10.452 13.5911,10.1787C13.596,10.1765 13.602,10.1776 13.6058,10.1815C13.6096,10.1858 13.6102,10.1918 13.6069,10.1962L13.356,10.5922C13.3549,10.5944 13.3527,10.5955 13.3511,10.5965C12.4445,11.0362 11.1245,11.1316 9.8329,11.1693C9.7598,11.172 9.6867,11.1725 9.6142,11.1725ZM6.2831,10.5693C6.8978,10.8256 8.4464,11.1845 9.8307,11.1453C11.118,11.1076 12.4331,11.0133 13.3358,10.5769L13.5633,10.2185C12.9333,10.4891 10.974,10.7924 9.8138,10.7951C9.8138,10.7951 9.8138,10.7951 9.8138,10.7951C8.1753,10.7853 6.738,10.3991 6.1975,10.254C6.1413,10.2387 6.0944,10.2262 6.0578,10.2169L6.2831,10.5693Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.4389,10.4973C13.4018,10.5535 13.3642,10.6091 13.326,10.6631C12.9164,10.8071 12.2705,10.9582 11.9978,11.0024C11.4409,11.1164 10.5796,11.2009 9.8155,11.2015C8.1704,11.1775 6.8242,10.8567 6.1909,10.5829L6.1396,10.4956L6.1478,10.4825L6.2345,10.5158C7.3609,10.9173 8.6258,11.0776 9.8247,11.106C10.5862,11.1087 11.3482,11.0193 11.9645,10.9091C12.9098,10.7204 13.2916,10.5785 13.4089,10.5136L13.4389,10.4973L13.4389,10.4973L13.4389,10.4973ZM13.6565,10.1395C13.6576,10.1405 13.6587,10.1416 13.6593,10.1427C13.6315,10.1891 13.6031,10.2365 13.5742,10.284C13.3555,10.362 12.7625,10.5349 11.8958,10.6555C11.3253,10.7329 10.9702,10.8082 9.8345,10.83C7.7067,10.776 6.3289,10.3615 6.0016,10.2595L5.9531,10.1667C7.1864,10.4875 8.4458,10.7111 9.8345,10.734C10.8736,10.7122 11.3155,10.6358 11.8816,10.5589C12.8918,10.4024 13.4007,10.2365 13.5535,10.1891C13.5513,10.1864 13.5491,10.1836 13.5469,10.1804L13.6565,10.1395L13.6565,10.1395L13.6565,10.1395Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8155,11.2129C8.1382,11.1884 6.8122,10.8638 6.186,10.5938C6.1838,10.5927 6.1816,10.5911 6.1805,10.5889L6.1293,10.5016C6.1271,10.4978 6.1271,10.4929 6.1293,10.4891L6.1375,10.476C6.1407,10.4711 6.1467,10.4695 6.1516,10.4711L6.2384,10.5044C7.2436,10.8627 8.4502,11.0607 9.8242,11.094C10.6615,11.0978 11.4491,10.9887 11.9618,10.8976C13.0167,10.6871 13.3315,10.5431 13.4029,10.5038L13.4324,10.4875C13.4373,10.4847 13.4433,10.4858 13.4471,10.4896C13.4509,10.4935 13.4515,10.4995 13.4482,10.5044C13.41,10.5627 13.3718,10.6184 13.3353,10.6702C13.3336,10.6724 13.332,10.674 13.3293,10.6745C12.9218,10.8175 12.2798,10.9685 11.9989,11.0144C11.4213,11.1327 10.5431,11.2129 9.8155,11.2129ZM6.1991,10.5736C6.8738,10.8638 8.2522,11.1665 9.8155,11.1895C10.542,11.1889 11.418,11.1093 11.9951,10.9909C12.2749,10.9456 12.912,10.7956 13.3184,10.6533C13.3456,10.6145 13.3735,10.5736 13.4018,10.5316C13.3091,10.5791 12.972,10.7209 11.9667,10.9216C11.4529,11.0133 10.6647,11.1207 9.8247,11.1185C8.4475,11.0853 7.2387,10.8867 6.2307,10.5273L6.1549,10.4978L6.1991,10.5736ZM9.8351,10.8415C7.9336,10.7935 6.6153,10.4629 5.9984,10.2704C5.9951,10.2693 5.9929,10.2671 5.9913,10.2644L5.9427,10.1716C5.9405,10.1673 5.9411,10.1624 5.9438,10.1585C5.9465,10.1547 5.9515,10.1531 5.9564,10.1547C7.3658,10.5213 8.598,10.7013 9.8345,10.7215C10.7607,10.7018 11.2167,10.6385 11.7005,10.5715C11.7595,10.5633 11.8189,10.5551 11.88,10.5469C12.8553,10.3958 13.3658,10.2355 13.5333,10.1825L13.5349,10.182C13.5349,10.1804 13.5349,10.1787 13.5349,10.1771C13.536,10.1733 13.5387,10.1705 13.542,10.1689L13.6516,10.128C13.6571,10.1258 13.6631,10.128 13.6658,10.1329L13.6658,10.1329L13.6658,10.1329L13.6675,10.1351C13.6707,10.1389 13.6707,10.1444 13.6685,10.1487C13.6407,10.1951 13.6124,10.2425 13.5835,10.29C13.5818,10.2922 13.5796,10.2944 13.5775,10.2949C13.284,10.3996 12.6682,10.5595 11.8969,10.6669C11.8129,10.6784 11.7333,10.6898 11.6553,10.7007C11.1987,10.7667 10.8038,10.8229 9.8351,10.8415ZM6.0104,10.2491C6.6278,10.4416 7.9418,10.7695 9.8351,10.8175C10.8022,10.7989 11.196,10.7422 11.6525,10.6773C11.7305,10.6664 11.8102,10.6549 11.8942,10.6435C12.66,10.5365 13.272,10.3784 13.566,10.2742C13.5895,10.236 13.6124,10.1978 13.6353,10.1602L13.5655,10.1864C13.566,10.1885 13.566,10.1907 13.5649,10.1929C13.5638,10.1967 13.5611,10.1995 13.5573,10.2005L13.5409,10.206C13.3729,10.2589 12.8607,10.4198 11.8838,10.5709C11.8227,10.5791 11.7633,10.5873 11.7044,10.5955C11.2205,10.6625 10.7629,10.7264 9.8356,10.746C8.604,10.7258 7.3773,10.5475 5.9771,10.1847L6.0104,10.2491Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8073,3.9115C7.4422,3.9115 5.5129,5.8287 5.5129,8.1796C5.5129,10.5305 7.4422,12.4478 9.8073,12.4478C12.1724,12.4478 14.118,10.5305 14.118,8.1796C14.1175,5.8287 12.1724,3.9115 9.8073,3.9115ZM12.5564,10.8676C11.844,11.5489 10.8998,11.9875 9.7969,12.0076C8.5653,12.03 7.404,11.2304 7.0925,10.8791C6.4838,10.1924 5.988,9.3202 5.9716,8.1442C6.0469,6.8165 6.5705,5.8915 7.3287,5.2571C8.0875,4.6227 9.0976,4.314 9.9387,4.3358C10.9091,4.3615 12.0431,4.8355 12.8264,5.7769C13.3396,6.3938 13.5616,7.0631 13.6784,8.0771C13.6849,9.294 13.0598,10.386 12.5564,10.8676Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8187,12.4729C7.4416,12.4729 5.508,10.5464 5.508,8.1785C5.508,5.8107 7.4416,3.8842 9.8187,3.8842C12.1958,3.8842 14.1295,5.8107 14.1295,8.1785C14.1295,10.5464 12.1958,12.4729 9.8187,12.4729ZM9.8187,3.9093C7.4558,3.9093 5.5331,5.8244 5.5331,8.1785C5.5331,10.5327 7.4558,12.4478 9.8187,12.4478C12.1816,12.4478 14.1044,10.5327 14.1044,8.1785C14.1044,5.8244 12.1816,3.9093 9.8187,3.9093ZM9.8187,12.3791C8.7,12.3791 7.6435,11.9411 6.8438,11.1453C6.0436,10.3489 5.6029,9.2956 5.6029,8.1791C5.6029,7.0625 6.0436,6.0093 6.8438,5.2129C7.6435,4.4171 8.7,3.9791 9.8187,3.9791C10.9375,3.9791 11.994,4.4171 12.7936,5.2129C13.5938,6.0093 14.0345,7.0625 14.0345,8.1791C14.0345,9.2956 13.5938,10.3489 12.7936,11.1453C11.994,11.9405 10.9375,12.3791 9.8187,12.3791ZM9.8187,4.0036C7.5076,4.0036 5.6275,5.8767 5.6275,8.1791C5.6275,10.4815 7.5076,12.3545 9.8187,12.3545C12.1298,12.3545 14.01,10.4815 14.01,8.1791C14.01,5.8767 12.1298,4.0036 9.8187,4.0036Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.822,12.1096C8.7736,12.1096 7.7842,11.6989 7.0353,10.9538C6.2853,10.2076 5.8729,9.2209 5.8729,8.1753C5.8729,7.1296 6.2858,6.1424 7.0353,5.3967C7.7842,4.6516 8.7742,4.2409 9.822,4.2409C10.8704,4.2409 11.8598,4.6516 12.6087,5.3967C13.3582,6.1429 13.7711,7.1296 13.7711,8.1753C13.7711,9.2209 13.3582,10.2082 12.6087,10.9538C11.8598,11.6989 10.8704,12.1096 9.822,12.1096ZM9.822,4.2655C7.6582,4.2655 5.8975,6.0196 5.8975,8.1753C5.8975,10.3309 7.6582,12.0851 9.822,12.0851C11.9858,12.0851 13.7465,10.3309 13.7465,8.1753C13.7471,6.0191 11.9864,4.2655 9.822,4.2655ZM9.822,12.0153C8.7987,12.0153 7.8327,11.6149 7.1018,10.8873C6.3698,10.1591 5.9673,9.1958 5.9673,8.1753C5.9673,7.1542 6.3704,6.1915 7.1018,5.4633C7.8327,4.7356 8.7987,4.3353 9.822,4.3353C10.8453,4.3353 11.8113,4.7362 12.5422,5.4633C13.2742,6.1915 13.6767,7.1547 13.6767,8.1753C13.6767,9.1958 13.2736,10.1591 12.5422,10.8873C11.8113,11.6149 10.8453,12.0153 9.822,12.0153ZM9.822,4.3593C7.71,4.3593 5.9918,6.0709 5.9918,8.1747C5.9918,10.2785 7.71,11.9902 9.822,11.9902C11.934,11.9902 13.6522,10.2785 13.6522,8.1747C13.6522,6.0709 11.934,4.3593 9.822,4.3593Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9955,3.8798l-0.3682,0l0.0005,8.6035l0.3698,0z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9971,12.4953L9.6273,12.4953C9.6202,12.4953 9.6147,12.4898 9.6147,12.4827L9.6142,3.8793C9.6142,3.8793 9.6153,3.8727 9.618,3.8705C9.6207,3.8684 9.6235,3.8667 9.6267,3.8667L9.9949,3.8667C10.002,3.8667 10.0075,3.8722 10.0075,3.8793L10.0091,12.4827C10.0091,12.4827 10.008,12.4893 10.0053,12.4915C10.0036,12.4942 10.0004,12.4953 9.9971,12.4953ZM9.6398,12.4707L9.9845,12.4707L9.9829,3.8924L9.6393,3.8924L9.6398,12.4707Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9584,3.8307L10.0522,3.8307L10.0527,12.5329L9.9589,12.5329L9.9584,3.8307L9.9584,3.8307ZM9.5929,3.8307L9.6873,3.8307L9.6873,12.5329L9.5929,12.5329L9.5929,3.8307L9.5929,3.8307Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6878,12.5455L9.5935,12.5455C9.5864,12.5455 9.5809,12.54 9.5809,12.5329L9.5809,3.8318L9.5809,3.8307C9.5809,3.8236 9.5869,3.8165 9.5935,3.8182L9.6878,3.8182C9.6949,3.8182 9.7004,3.8236 9.7004,3.8307L9.7004,12.5329C9.7004,12.5329 9.6993,12.5395 9.6965,12.5416C9.6938,12.5444 9.6911,12.5455 9.6878,12.5455ZM9.6055,12.5209L9.6753,12.5209L9.6753,3.8433L9.6055,3.8433L9.6055,12.5209ZM10.0533,12.5455L9.9595,12.5455C9.9524,12.5455 9.9469,12.54 9.9469,12.5329L9.9464,3.8307C9.9464,3.8307 9.9475,3.8242 9.9502,3.822C9.9518,3.8198 9.9551,3.8182 9.9584,3.8182L10.0522,3.8182C10.0593,3.8182 10.0647,3.8236 10.0647,3.8307L10.0653,12.5329C10.0653,12.5329 10.0642,12.5395 10.0615,12.5416C10.0593,12.5438 10.0565,12.5455 10.0533,12.5455ZM9.9715,12.5204L10.0402,12.5204L10.0396,3.8427L9.9709,3.8427L9.9715,12.5204Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M14.1196,8.3444l0,-0.318l-0.2602,-0.2411l-1.476,-0.3889l-2.1273,-0.216l-2.5615,0.1298l-1.8235,0.4325l-0.3682,0.2716l0,0.318l0.9327,-0.4167l2.214,-0.3458l2.1273,0l1.5627,0.1729l1.0855,0.2596z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M14.1196,8.3569C14.118,8.3569 14.1158,8.3564 14.1142,8.3558L13.4198,8.0127L12.3371,7.7542L10.776,7.5813L8.6504,7.5813L6.4402,7.9265L5.5091,8.3433C5.5053,8.3449 5.5009,8.3449 5.4971,8.3422C5.4938,8.34 5.4916,8.3362 5.4916,8.3318L5.4916,8.0138C5.4916,8.01 5.4933,8.0062 5.4965,8.004L5.8647,7.7324C5.8658,7.7313 5.8675,7.7307 5.8691,7.7302L7.6925,7.2976L10.2562,7.1678L12.3851,7.3838L13.8627,7.7733C13.8649,7.7738 13.8665,7.7749 13.8682,7.776L14.1284,8.0171C14.1311,8.0193 14.1322,8.0225 14.1322,8.0264L14.1322,8.3444C14.1322,8.3487 14.13,8.3525 14.1262,8.3547C14.1245,8.3564 14.1224,8.3569 14.1196,8.3569ZM10.7776,7.5567L12.342,7.7296L13.4285,7.9893L14.1076,8.3247L14.1076,8.0318L13.854,7.7962L12.3813,7.4078L10.2562,7.1918L7.6969,7.3216L5.8784,7.7531L5.5173,8.0193L5.5173,8.3122L6.432,7.9031C6.4331,7.9025 6.4342,7.9025 6.4353,7.902L8.6493,7.5562L10.7776,7.5567Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8204,7.5158C10.8355,7.5142 11.8205,7.6118 12.6016,7.7629C13.4078,7.9233 13.9751,8.124 14.1687,8.3498L14.1687,8.4616C13.9347,8.1807 13.1716,7.9751 12.5836,7.8578C11.8085,7.7078 10.83,7.6107 9.8209,7.6124C8.7556,7.6145 7.764,7.7149 6.9998,7.8633C6.3867,7.9844 5.5696,8.2249 5.4671,8.4627L5.4671,8.3465C5.5233,8.1824 6.132,7.9369 6.9856,7.7662C7.7553,7.6167 8.7491,7.518 9.8204,7.5158L9.8204,7.5158ZM9.8209,7.1487C10.836,7.1471 11.8211,7.2447 12.6022,7.3958C13.4084,7.5562 13.9756,7.7569 14.1693,7.9827L14.1693,8.0945C13.9353,7.8142 13.1722,7.608 12.5842,7.4907C11.8091,7.3402 10.8305,7.2436 9.8215,7.2453C8.7562,7.2469 7.7689,7.3478 7.0053,7.4962C6.414,7.608 5.5631,7.8584 5.4682,8.0956L5.4682,7.9795C5.5244,7.8169 6.1451,7.5627 6.9867,7.3991C7.7558,7.2496 8.7496,7.1509 9.8209,7.1487L9.8209,7.1487Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.4671,8.4747C5.466,8.4747 5.4655,8.4747 5.4644,8.4747C5.4589,8.4736 5.4545,8.4682 5.4545,8.4627L5.4545,8.3465C5.4545,8.3465 5.4545,8.3438 5.4551,8.3427C5.5151,8.1665 6.1576,7.9189 6.9829,7.7542C7.8049,7.5944 8.8124,7.5055 9.8204,7.5038L9.8204,7.5164L9.8204,7.5038C9.8296,7.5038 9.8395,7.5038 9.8493,7.5038C10.8033,7.5038 11.7802,7.5916 12.6038,7.7515C13.4455,7.9189 13.9898,8.1235 14.178,8.3422C14.1796,8.3444 14.1813,8.3471 14.1807,8.3504L14.1807,8.4622C14.1807,8.4676 14.1775,8.472 14.1725,8.4736C14.1676,8.4753 14.1622,8.4736 14.1589,8.4698C13.9118,8.1731 13.0642,7.9669 12.5809,7.8698C11.7644,7.7116 10.7951,7.6249 9.8487,7.6249C9.8395,7.6249 9.8296,7.6249 9.8204,7.6249C8.8249,7.6265 7.824,7.716 7.0015,7.8758C6.3338,8.0078 5.5718,8.2495 5.478,8.4676C5.4764,8.472 5.472,8.4747 5.4671,8.4747ZM9.8487,7.5998C10.7967,7.5998 11.7676,7.6871 12.5858,7.8453C13.0593,7.9402 13.8796,8.1398 14.1562,8.4289L14.1562,8.3542C13.9685,8.1409 13.4302,7.9407 12.5989,7.7749C11.7682,7.614 10.7804,7.5251 9.8204,7.5278C8.8145,7.5295 7.8082,7.6184 6.9878,7.7776C6.0758,7.9593 5.5315,8.2064 5.4791,8.3476L5.4791,8.4164C5.6613,8.1715 6.504,7.9478 6.9965,7.8502C7.8207,7.6898 8.8233,7.6009 9.8198,7.5993C9.8302,7.5998 9.8395,7.5998 9.8487,7.5998ZM5.4676,8.1076C5.4671,8.1076 5.466,8.1076 5.4655,8.1076C5.4595,8.1065 5.4551,8.1016 5.4551,8.0956L5.4551,7.9795C5.4551,7.9795 5.4551,7.9767 5.4556,7.9756C5.5173,7.7973 6.174,7.5442 6.984,7.3871C7.8055,7.2273 8.8135,7.1384 9.8209,7.1367L9.8209,7.1367C10.7831,7.1356 11.772,7.2229 12.6044,7.3844C13.446,7.5518 13.9904,7.7564 14.1785,7.9751C14.1807,7.9767 14.1818,7.98 14.1818,7.9827L14.1818,8.0945C14.1818,8.1 14.1785,8.1044 14.1736,8.106C14.1687,8.1076 14.1633,8.1065 14.16,8.1022C13.9124,7.8055 13.0653,7.5993 12.582,7.5027C11.7573,7.3429 10.7776,7.2551 9.8215,7.2578C8.8298,7.2595 7.8305,7.3484 7.0075,7.5087C6.33,7.6364 5.5647,7.8873 5.4796,8.1005C5.4769,8.1049 5.4725,8.1076 5.4676,8.1076ZM9.8504,7.2327C10.7978,7.2327 11.7682,7.32 12.5858,7.4782C13.0593,7.5725 13.8796,7.7727 14.1562,8.0618L14.1562,7.9871C13.9685,7.7738 13.4307,7.5736 12.5989,7.4078C11.7682,7.2469 10.7809,7.1575 9.8204,7.1607L9.8204,7.1607C8.814,7.1624 7.8082,7.2513 6.9878,7.4105C6.1113,7.5807 5.5342,7.8333 5.4791,7.9805L5.4791,8.0482C5.6525,7.8125 6.4664,7.5845 7.0015,7.4831C7.8256,7.3227 8.8271,7.2338 9.8198,7.2322C9.8307,7.2327 9.8405,7.2327 9.8504,7.2327Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8002,5.2756C11.4,5.2675 12.7953,5.4982 13.4335,5.8244L13.6664,6.2258C13.1116,5.928 11.6062,5.6182 9.8024,5.6645C8.3329,5.6738 6.7625,5.8255 5.9744,6.2444L6.2525,5.7813C6.8995,5.4469 8.424,5.2773 9.8002,5.2756" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.9744,6.2564C5.9711,6.2564 5.9678,6.2553 5.9651,6.2525C5.9613,6.2487 5.9607,6.2422 5.9635,6.2378L6.2416,5.7747C6.2427,5.7725 6.2444,5.7709 6.2465,5.7698C6.9196,5.4224 8.5151,5.2647 9.7985,5.2631C9.7991,5.2631 9.7996,5.2631 9.8002,5.2631C11.3416,5.2565 12.7696,5.4715 13.4389,5.8129C13.4411,5.814 13.4427,5.8156 13.4438,5.8178L13.6767,6.2193C13.6795,6.2242 13.6789,6.2302 13.6751,6.234C13.6713,6.2378 13.6653,6.2389 13.6604,6.2362C13.0784,5.9236 11.5669,5.6307 9.8029,5.6765C8.7698,5.6831 6.9,5.7665 5.9809,6.2547C5.9787,6.2558 5.9765,6.2564 5.9744,6.2564ZM6.2613,5.79L6.0076,6.2127C6.9442,5.7398 8.7813,5.658 9.8024,5.6515C11.5331,5.6073 13.0233,5.8882 13.6342,6.1942L13.4247,5.8331C12.7571,5.4944 11.3367,5.2805 9.8018,5.2876C9.8013,5.2876 9.8007,5.2876 9.8002,5.2876C8.5216,5.2898 6.9327,5.4458 6.2613,5.79Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8215,5.6067C10.734,5.6045 11.6155,5.6558 12.3164,5.7818C12.9693,5.9029 13.5922,6.0845 13.6811,6.1822L13.7504,6.3038C13.5338,6.1631 12.9949,6.006 12.3033,5.8756C11.6084,5.7458 10.7275,5.7027 9.8204,5.7049C8.7905,5.7016 7.9904,5.7556 7.3036,5.8745C6.5776,6.0098 6.0736,6.2035 5.9493,6.2951L6.0169,6.1669C6.2585,6.0442 6.6415,5.8964 7.2856,5.7807C7.9953,5.6509 8.8036,5.6122 9.8215,5.6067L9.8215,5.6067L9.8215,5.6067ZM9.8209,5.2396C10.6942,5.2375 11.556,5.286 12.228,5.406C12.7582,5.5085 13.2824,5.6695 13.4738,5.8118L13.5747,5.9716C13.4029,5.7818 12.7571,5.6013 12.1865,5.5009C11.5195,5.3864 10.6936,5.3411 9.8204,5.334C8.904,5.3367 8.0575,5.3924 7.4002,5.5118C6.7735,5.6307 6.3687,5.7715 6.1975,5.8811L6.2864,5.7475C6.5225,5.6236 6.9044,5.5096 7.3849,5.4169C8.0471,5.2969 8.8991,5.2424 9.8209,5.2396L9.8209,5.2396Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.7498,6.3158C13.7476,6.3158 13.7449,6.3153 13.7433,6.3136C13.5311,6.1756 13.0053,6.0202 12.3005,5.8871C11.6815,5.7715 10.8464,5.7136 9.8198,5.7164C8.7911,5.7125 7.992,5.7665 7.3053,5.886C6.5831,6.0207 6.0818,6.2116 5.9564,6.3044C5.9515,6.3076 5.9455,6.3076 5.9411,6.3038C5.9367,6.3 5.9356,6.294 5.9384,6.2885L6.006,6.1598C6.0071,6.1576 6.0093,6.1555 6.0115,6.1544C6.3371,5.9891 6.7533,5.862 7.2835,5.7671C7.9265,5.6498 8.6618,5.5996 9.822,5.5936L9.822,5.5936L9.822,5.5936C10.8044,5.5915 11.6678,5.6515 12.3191,5.7687C12.9845,5.892 13.5998,6.0736 13.6909,6.1729L13.7613,6.2967C13.764,6.3016 13.7629,6.3082 13.7591,6.312C13.7564,6.3147 13.7531,6.3158 13.7498,6.3158ZM9.888,5.6918C10.8856,5.6918 11.6984,5.7491 12.3049,5.8631C12.9715,5.9891 13.4793,6.1353 13.7155,6.2684L13.6696,6.1882C13.5851,6.096 12.9633,5.9144 12.3136,5.7938C11.6635,5.6771 10.8011,5.616 9.8209,5.6193L9.8209,5.6193C8.6629,5.6258 7.9287,5.676 7.2867,5.7927C6.7609,5.8871 6.348,6.0125 6.0251,6.1762L5.9815,6.2596C6.1555,6.1593 6.6355,5.9869 7.3004,5.8625C7.9887,5.7431 8.7889,5.6891 9.8193,5.6924C9.8427,5.6918 9.8656,5.6918 9.888,5.6918ZM13.5753,5.9847C13.572,5.9847 13.5687,5.9831 13.566,5.9804C13.3893,5.7845 12.7118,5.6062 12.1849,5.5135C11.5784,5.4093 10.8055,5.3547 9.8209,5.3465C8.8647,5.3493 8.0285,5.4104 7.4029,5.5238C6.8471,5.6291 6.3993,5.7665 6.2045,5.8915C6.1996,5.8947 6.1931,5.8936 6.1887,5.8898C6.1844,5.8855 6.1838,5.8789 6.1871,5.8745L6.276,5.7409C6.2771,5.7393 6.2787,5.7376 6.2804,5.7365C6.5149,5.6138 6.8956,5.4987 7.3822,5.4049C8.0067,5.2915 8.85,5.2304 9.8204,5.2276L9.8204,5.2276L9.8204,5.2276C10.7738,5.2255 11.6067,5.2827 12.2296,5.3945C12.798,5.5047 13.3009,5.6689 13.4809,5.8031C13.482,5.8042 13.4831,5.8053 13.4842,5.8064L13.5851,5.9662C13.5884,5.9716 13.5873,5.9787 13.5818,5.9825C13.5802,5.9836 13.578,5.9847 13.5753,5.9847ZM9.8209,5.3215C10.8071,5.3296 11.5816,5.3842 12.1893,5.4889C12.6693,5.574 13.2742,5.7295 13.5191,5.9067L13.4645,5.8205C13.2856,5.6891 12.7882,5.5271 12.2253,5.418C11.604,5.3067 10.7711,5.2489 9.8204,5.2516L9.8204,5.2516C8.8516,5.2544 8.01,5.3155 7.3871,5.4284C6.9055,5.5216 6.5275,5.6351 6.2951,5.7562L6.2378,5.8418C6.4544,5.7229 6.8798,5.5969 7.3975,5.4987C8.0253,5.3858 8.8631,5.3242 9.8209,5.3215Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.9564,9.9584C11.1655,9.8111 10.3735,9.7898 9.8198,9.7964C7.1542,9.8275 6.2929,10.3418 6.1876,10.4973L5.9885,10.1738C6.6671,9.684 8.1191,9.4091 9.834,9.4369C10.7247,9.4516 11.4933,9.5105 12.1402,9.6349L11.9564,9.9584" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1876,10.5098L6.1876,10.5098C6.1833,10.5098 6.1795,10.5076 6.1773,10.5038L5.9782,10.1804C5.9749,10.1749 5.976,10.1678 5.9815,10.164C6.6616,9.6731 8.1027,9.3965 9.8345,9.4249C10.7749,9.4402 11.5304,9.5051 12.1429,9.6235C12.1467,9.624 12.15,9.6267 12.1516,9.6305C12.1533,9.6344 12.1533,9.6382 12.1511,9.642L11.9673,9.9649C11.9645,9.9698 11.958,9.9725 11.9525,9.9704C11.3258,9.8542 10.6085,9.7996 9.8198,9.8089C7.2262,9.8395 6.3131,10.3336 6.198,10.5044C6.1958,10.5076 6.192,10.5098 6.1876,10.5098ZM6.0055,10.1776L6.1893,10.476C6.3464,10.29 7.2867,9.8144 9.8198,9.7844C10.6069,9.7751 11.3236,9.8291 11.9498,9.9447L12.1205,9.6442C11.5124,9.5285 10.764,9.4647 9.834,9.4495C8.1147,9.4216 6.6851,9.6933 6.0055,10.1776Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8045,9.7511C10.5458,9.762 11.274,9.7925 11.9765,9.9229L11.9258,10.0124C11.2735,9.8924 10.5775,9.8465 9.8073,9.8504C8.8233,9.8427 7.8284,9.9344 6.9622,10.182C6.6889,10.2578 6.2362,10.4329 6.1904,10.5775L6.1396,10.4945C6.1544,10.4089 6.4276,10.2316 6.9393,10.0887C7.9309,9.8051 8.8587,9.7576 9.8045,9.7511L9.8045,9.7511L9.8045,9.7511ZM9.8378,9.3791C10.6064,9.3933 11.3995,9.4287 12.1707,9.5809L12.1178,9.6742C11.4213,9.5367 10.7558,9.4904 9.8422,9.4767C8.8555,9.4784 7.8082,9.5487 6.8564,9.8242C6.5493,9.9131 6.0185,10.1062 6.0011,10.2589L5.9504,10.1695C5.9618,10.0309 6.4211,9.8498 6.834,9.7304C7.794,9.4527 8.8435,9.3813 9.8378,9.3791L9.8378,9.3791Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M6.1898,10.5895C6.1855,10.5895 6.1816,10.5873 6.1795,10.5835L6.1287,10.5005C6.1271,10.4984 6.1265,10.4951 6.1265,10.4951C6.1435,10.3958 6.432,10.2175 6.9349,10.0767C7.8829,9.8062 8.7676,9.7462 9.804,9.7391C9.8051,9.7391 9.8051,9.7391 9.8056,9.7391C10.5093,9.7495 11.2587,9.7778 11.9782,9.9115C11.982,9.912 11.9853,9.9147 11.9869,9.918C11.9885,9.9213 11.9885,9.9256 11.9864,9.9289L11.9356,10.0184C11.9329,10.0227 11.928,10.0249 11.9231,10.0244C11.3089,9.9115 10.6173,9.8575 9.8067,9.8624C8.7185,9.8531 7.7629,9.9655 6.9649,10.1935C6.6731,10.2742 6.2433,10.4482 6.2007,10.5813C6.1991,10.5856 6.1953,10.5889 6.1909,10.5895C6.1909,10.5895 6.1904,10.5895 6.1898,10.5895ZM6.1516,10.4924L6.1882,10.5518C6.27,10.4073 6.6955,10.2431 6.9584,10.1705C7.7585,9.942 8.7169,9.8296 9.8067,9.8384C10.6145,9.8345 11.3056,9.8869 11.9193,9.9993L11.9575,9.9316C11.2445,9.8007 10.5011,9.7735 9.804,9.7631C9.804,9.7631 9.8035,9.7631 9.8029,9.7631C8.7693,9.7702 7.8867,9.8302 6.9415,10.0996C6.4331,10.242 6.1729,10.4155 6.1516,10.4924ZM6.0016,10.2709C5.9973,10.2709 5.9935,10.2687 5.9913,10.2649L5.9405,10.1755C5.9395,10.1733 5.9389,10.1711 5.9389,10.1689C5.9542,9.9873 6.6256,9.7789 6.8313,9.7195C7.6516,9.4816 8.6067,9.3704 9.8378,9.3676L9.8378,9.3676C10.5895,9.3818 11.3929,9.4156 12.1729,9.57C12.1767,9.5705 12.18,9.5733 12.1816,9.5765C12.1833,9.5798 12.1833,9.5842 12.1811,9.5875L12.1282,9.6807C12.1255,9.6851 12.1205,9.6878 12.1156,9.6867C11.376,9.5405 10.6718,9.5018 9.8422,9.4893C8.6176,9.4915 7.6702,9.6016 6.8602,9.8362C6.4625,9.9518 6.0278,10.1335 6.0131,10.2605C6.0125,10.2655 6.0087,10.2698 6.0038,10.2709C6.0033,10.2704 6.0022,10.2709 6.0016,10.2709ZM5.9635,10.1667L5.9984,10.2284C6.0851,10.0407 6.7718,9.8362 6.8536,9.8127C7.6658,9.5776 8.6155,9.4669 9.8427,9.4647C10.6707,9.4773 11.3733,9.5155 12.1118,9.6611L12.1522,9.5896C11.3793,9.4385 10.5829,9.4053 9.8378,9.3911C8.6089,9.3933 7.656,9.5045 6.8378,9.7418C6.3207,9.8918 5.9793,10.0576 5.9635,10.1667Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.6244,10.2235l-0.3202,0.4953l-0.9202,-0.8144l-2.3875,-1.5998l-2.6913,-1.47l-1.3975,-0.4762l0.2978,-0.5498l0.1009,-0.0551l0.8684,0.216l2.8653,1.47l1.6495,1.038l1.3893,0.9944l0.5645,0.6485z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.3042,10.7307C13.3009,10.7307 13.2982,10.7296 13.296,10.7275L12.3758,9.9131L9.9895,8.3144L7.2987,6.8449L5.9035,6.3698C5.9002,6.3687 5.8975,6.366 5.8958,6.3627C5.8947,6.3595 5.8947,6.3556 5.8964,6.3524L6.1942,5.8025C6.1953,5.8004 6.1969,5.7987 6.1991,5.7976L6.3,5.7425C6.3027,5.7409 6.306,5.7409 6.3087,5.7415L7.1771,5.9575L10.0451,7.4285L11.6956,8.4671L13.0855,9.462L13.6522,10.1127C13.6549,10.1155 13.6555,10.1193 13.6549,10.1231L13.6369,10.2262C13.6364,10.2278 13.6358,10.2295 13.6353,10.2305L13.3151,10.7258C13.3129,10.7291 13.3102,10.7307 13.3064,10.7313C13.3053,10.7307 13.3047,10.7307 13.3042,10.7307ZM5.9253,6.3507L7.3085,6.822L10.002,8.2931L12.3905,9.8935L13.3015,10.6991L13.6124,10.2185L13.6293,10.1242L13.0691,9.48L11.682,8.4873L10.0331,7.4498L7.1689,5.9804L6.3082,5.7665L6.2144,5.8173L5.9253,6.3507Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M5.8571,6.3709C6.102,6.2051 7.9036,7.0047 9.7882,8.1365C11.6678,9.2716 13.464,10.5545 13.302,10.7945L13.2485,10.878L13.224,10.8971C13.2295,10.8933 13.2562,10.8605 13.2213,10.7716C13.1411,10.5093 11.8669,9.4964 9.7533,8.2249C7.6925,7.0009 5.9749,6.2629 5.8031,6.474L5.8571,6.3709L5.8571,6.3709L5.8571,6.3709ZM13.6904,10.2164C13.8453,9.9115 12.1745,8.658 10.1035,7.4373C7.9844,6.2411 6.4571,5.5369 6.1784,5.7469L6.1161,5.8593C6.1156,5.8653 6.1184,5.8516 6.1315,5.8413C6.1822,5.7971 6.2662,5.8004 6.3044,5.7993C6.7849,5.8064 8.1567,6.4353 10.0811,7.5344C10.9244,8.0236 13.644,9.7609 13.6336,10.2496C13.6342,10.2916 13.6369,10.3004 13.6211,10.3211L13.6904,10.2164L13.6904,10.2164L13.6904,10.2164Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.224,10.9096C13.2202,10.9096 13.2164,10.908 13.2142,10.9047C13.2104,10.8993 13.2109,10.8916 13.2164,10.8873L13.2169,10.8867C13.218,10.8851 13.242,10.8578 13.2098,10.776C13.1275,10.506 11.7802,9.4582 9.7467,8.2353C7.5851,6.9513 5.9673,6.2918 5.8124,6.4816C5.8085,6.4865 5.8009,6.4876 5.796,6.4844C5.7905,6.4811 5.7889,6.474 5.7916,6.4685L5.8456,6.3655C5.8467,6.3638 5.8478,6.3622 5.8495,6.3611C6.1064,6.1882 7.9124,6.9965 9.7942,8.1267C11.4862,9.1489 13.2415,10.3724 13.3211,10.734C13.3271,10.7613 13.3238,10.7842 13.3118,10.8022L13.2589,10.8856C13.2584,10.8867 13.2573,10.8878 13.2562,10.8889L13.2316,10.908L13.2316,10.908L13.2311,10.9085C13.2289,10.9091 13.2267,10.9096 13.224,10.9096ZM5.9193,6.4276C6.3922,6.4276 7.9882,7.1624 9.7598,8.2145C11.8255,9.4571 13.1482,10.4885 13.2338,10.7684C13.2475,10.8033 13.2518,10.83 13.2518,10.8507L13.2916,10.788C13.3004,10.7755 13.302,10.7591 13.2976,10.7384C13.2202,10.3876 11.4284,9.1413 9.7822,8.1469C7.9467,7.0445 6.1222,6.2204 5.8669,6.3791L5.8358,6.4385C5.8576,6.4315 5.8855,6.4276 5.9193,6.4276ZM13.6211,10.3336C13.6184,10.3336 13.6162,10.3331 13.614,10.3315C13.6085,10.3276 13.6069,10.32 13.6107,10.3145L13.6178,10.3042C13.6222,10.2955 13.6222,10.2867 13.6216,10.2655L13.6211,10.2502C13.6315,9.7636 10.86,8.0013 10.0751,7.5458C8.1584,6.4511 6.7838,5.8195 6.3044,5.8124L6.2945,5.8124C6.2558,5.8129 6.1833,5.8135 6.1396,5.8511C6.1331,5.856 6.1298,5.862 6.1282,5.8653C6.1255,5.8707 6.1178,5.8745 6.1124,5.8729C6.1069,5.8713 6.1031,5.8642 6.1036,5.8582C6.1036,5.8582 6.1042,5.8549 6.1053,5.8533L6.1675,5.7409C6.1685,5.7393 6.1696,5.7382 6.1707,5.7371C6.5056,5.4851 8.4976,6.5165 10.1095,7.4269C11.9798,8.5287 13.8742,9.8831 13.7013,10.2224C13.7013,10.2229 13.7007,10.2229 13.7007,10.2229L13.6385,10.3167C13.6364,10.3205 13.6342,10.3244 13.6309,10.3287C13.6282,10.3315 13.6249,10.3336 13.6211,10.3336ZM6.3038,5.7867C6.7882,5.7938 8.1671,6.4271 10.0871,7.5235C10.6424,7.8458 13.6571,9.7167 13.6456,10.2496L13.6456,10.2605L13.6789,10.2104C13.8202,9.9284 12.2471,8.7153 10.0964,7.4476C7.8333,6.1702 6.4456,5.5691 6.1871,5.7545L6.1565,5.8096C6.2035,5.7878 6.2596,5.7873 6.2935,5.7867L6.3038,5.7867Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.2442,8.6504C7.2442,9.354 7.5333,9.9905 8.0018,10.4553C8.4715,10.9211 9.1091,11.2156 9.8165,11.2156C10.5278,11.2156 11.1731,10.9282 11.6405,10.4635C12.108,9.9993 12.3976,9.3584 12.3976,8.6525L12.3976,8.6525L12.3976,5.2282L7.2431,5.2222L7.2442,8.6504L7.2442,8.6504L7.2442,8.6504Z" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.3402,8.6553L7.3402,8.6575C7.3402,9.33 7.62,9.9425 8.0684,10.3876C8.5178,10.8333 9.1369,11.1104 9.8138,11.1104C10.4945,11.1104 11.1125,10.8355 11.5598,10.3915C12.0071,9.9475 12.2847,9.3349 12.2847,8.6596L12.2847,8.6596L12.2847,5.3378L7.3429,5.3373L7.3402,8.6553M11.2915,6.3311L11.2915,8.4453L11.2898,8.6689L11.2898,8.6689C11.2898,8.7278 11.286,8.7949 11.2795,8.8522C11.2391,9.1865 11.0847,9.4778 10.8562,9.7042C10.5884,9.9693 10.2191,10.134 9.8122,10.134C9.4075,10.134 9.0464,9.9638 8.778,9.6971C8.5025,9.4238 8.3427,9.0491 8.3427,8.6618L8.3422,6.3256L11.2915,6.3311L11.2915,6.3311L11.2915,6.3311Z" + android:strokeWidth="1" + android:fillColor="#FF0000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.5713,9.6316C8.5593,9.6196 8.5407,9.6185 8.5304,9.6295L8.0335,10.128C8.0231,10.1384 8.0242,10.1569 8.0362,10.1684C8.0482,10.1804 8.0667,10.1815 8.0771,10.1705L8.574,9.672C8.5844,9.6622 8.5833,9.6436 8.5713,9.6316ZM7.9527,9.6464L7.9151,9.684L7.9151,9.684L7.9151,9.684L7.9762,9.7445C7.9849,9.7533 8.0007,9.7522 8.01,9.7429L8.1447,9.6076C8.154,9.5984 8.1551,9.5847 8.1453,9.5749L8.0831,9.5138L8.0444,9.5525L8.0716,9.5798L8.0444,9.6076L8.0171,9.5804L7.9784,9.6185L8.0056,9.6458L7.9784,9.6731L7.9527,9.6464ZM8.3465,9.8122L8.1393,9.6245L8.0242,9.7385L8.2145,9.9442L8.3465,9.8122ZM8.2358,8.2249C8.2358,8.2064 8.2233,8.1911 8.2075,8.1911L8.0171,8.1911C8.0165,8.1758 8.0116,8.1655 8.0095,8.1524C8.0116,8.166 8.0176,8.1753 8.0182,8.1905L8.1982,8.1905L8.1665,7.9238L8.1764,7.9238C8.1905,7.9238 8.202,7.9102 8.202,7.8933C8.202,7.8764 8.1905,7.8627 8.1764,7.8627L7.5016,7.8627C7.4875,7.8627 7.476,7.8764 7.476,7.8933C7.476,7.9102 7.4875,7.9238 7.5016,7.9238L7.512,7.9238L7.4831,8.19L7.6631,8.1905L7.6631,8.1911L7.4716,8.1911C7.4564,8.1911 7.4433,8.2064 7.4433,8.2249C7.4433,8.2435 7.4558,8.2587 7.4716,8.2587L8.2075,8.2587C8.2233,8.2587 8.2358,8.2435 8.2358,8.2249ZM7.7253,8.0073C7.6958,8.0476 7.6718,8.1033 7.6653,8.1824C7.668,8.0989 7.6942,8.046 7.7253,8.0073ZM7.4607,7.8316C7.4607,7.8485 7.4727,7.8622 7.488,7.8622L8.1933,7.8622C8.208,7.8622 8.2205,7.8485 8.2205,7.8316C8.2205,7.8147 8.2085,7.8011 8.1933,7.8011L7.488,7.8011C7.4727,7.8011 7.4607,7.8147 7.4607,7.8316ZM7.7204,7.4045L7.7204,7.4045L7.7204,7.4045L7.7204,7.4907C7.7204,7.5033 7.7324,7.5136 7.7449,7.5136L7.9364,7.5136C7.9489,7.5136 7.9604,7.5049 7.9604,7.4913L7.9604,7.404L7.9058,7.404L7.9058,7.4427L7.8671,7.4427L7.8671,7.4045L7.8125,7.4045L7.8125,7.4433L7.7738,7.4433L7.7738,7.4056L7.7204,7.4045ZM7.746,7.7995L7.9331,7.8L7.9205,7.5213L7.7585,7.5202L7.746,7.7995ZM7.5196,7.8005L7.6985,7.8005L7.6931,7.6505L7.5245,7.6505L7.5196,7.8005ZM7.98,7.8005L8.1589,7.8005L8.1535,7.6505L7.9849,7.6505L7.98,7.8005Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.4913,7.5415L7.4913,7.5415L7.4913,7.5415L7.4913,7.6276C7.4913,7.6402 7.5027,7.6505 7.5158,7.6505L7.7035,7.6505C7.716,7.6505 7.7269,7.6418 7.7269,7.6282L7.7269,7.5415L7.6735,7.5415L7.6735,7.5802L7.6353,7.5802L7.6353,7.542L7.5818,7.542L7.5818,7.5807L7.5436,7.5807L7.5436,7.5431L7.4913,7.5415ZM7.9522,7.5415L7.9522,7.5415L7.9522,7.5415L7.9522,7.6276C7.9522,7.6402 7.9636,7.6505 7.9767,7.6505L8.1644,7.6505C8.1769,7.6505 8.1878,7.6418 8.1878,7.6282L8.1878,7.5415L8.1344,7.5415L8.1344,7.5802L8.0962,7.5802L8.0962,7.542L8.0427,7.542L8.0427,7.5807L8.0045,7.5807L8.0045,7.5431L7.9522,7.5415ZM8.0558,10.1051L8.1818,9.9785L8.0711,9.8765L7.9522,9.9955L8.0558,10.1051ZM8.5064,9.6529L8.3956,9.5509L8.2767,9.6698L8.3804,9.7795L8.5064,9.6529ZM8.0782,9.8367L8.0165,9.7751L7.9789,9.8127L8.0062,9.84L7.9795,9.8667L7.9522,9.8395L7.9145,9.8771L7.9418,9.9044L7.9151,9.9311L7.8884,9.9044L7.8518,9.9409L7.8518,9.9409L7.8518,9.9409L7.9129,10.0015C7.9216,10.0102 7.9375,10.0091 7.9462,10.0004L8.0782,9.8678C8.0869,9.8602 8.088,9.8465 8.0782,9.8367ZM8.2396,9.6065L8.2129,9.5798L8.1764,9.6164L8.1764,9.6164L8.1764,9.6164L8.2375,9.6769C8.2462,9.6856 8.262,9.6845 8.2707,9.6758L8.4027,9.5433C8.4115,9.5345 8.4125,9.5204 8.4033,9.5111L8.3416,9.45L8.304,9.4876L8.3313,9.5149L8.3045,9.5416L8.2773,9.5144L8.2396,9.552L8.2669,9.5793L8.2396,9.6065ZM8.8184,9.8935L8.6842,10.0282C8.6727,10.0178 8.6624,10.014 8.6509,10.0058C8.6624,10.014 8.6727,10.0162 8.6842,10.0271L8.8113,9.8995L8.5991,9.7336L8.6062,9.7265C8.616,9.7167 8.6144,9.6987 8.6029,9.6867C8.5909,9.6747 8.5729,9.6736 8.5631,9.6835L8.088,10.1602C8.0782,10.17 8.0798,10.188 8.0913,10.2C8.1033,10.212 8.1213,10.2131 8.1311,10.2033L8.1382,10.1962L8.3078,10.404L8.4349,10.2775C8.4349,10.2775 8.4349,10.278 8.4355,10.278L8.3002,10.4133C8.2893,10.4242 8.2909,10.4438 8.3045,10.4569C8.3176,10.47 8.3373,10.4716 8.3482,10.4607L8.8664,9.9409C8.8773,9.93 8.8756,9.9104 8.862,9.8973C8.8495,9.8842 8.8293,9.8825 8.8184,9.8935ZM8.3482,10.1051C8.3558,10.1531 8.3787,10.2076 8.4273,10.266C8.3727,10.2076 8.3536,10.1531 8.3482,10.1051ZM7.9522,5.5385L7.9522,5.5385L7.9522,5.5385L7.9522,5.6247C7.9522,5.6373 7.9636,5.6476 7.9767,5.6476L8.1644,5.6476C8.1769,5.6476 8.1878,5.6389 8.1878,5.6253L8.1878,5.538L8.1344,5.538L8.1344,5.5767L8.0962,5.5767L8.0962,5.538L8.0427,5.538L8.0427,5.5767L8.0045,5.5767L8.0045,5.5391L7.9522,5.5385ZM7.5158,5.6471L7.7035,5.6471C7.716,5.6471 7.7269,5.6384 7.7269,5.6247L7.7269,5.5375L7.6735,5.5375L7.6735,5.5762L7.6353,5.5762L7.6353,5.5375L7.5818,5.5375L7.5818,5.5762L7.5436,5.5762L7.5436,5.5385L7.4918,5.5385L7.4918,5.5385L7.4918,5.5385L7.4918,5.6247C7.4918,5.6373 7.5033,5.6471 7.5158,5.6471Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1535,5.6476L7.9849,5.6476L7.98,5.7976L8.1589,5.7976L8.1535,5.6476ZM7.6931,5.6476L7.5245,5.6476L7.5196,5.7976L7.6985,5.7976L7.6931,5.6476ZM7.746,5.7965L7.9331,5.7971L7.9205,5.5178L7.7585,5.5173L7.746,5.7965ZM7.7449,5.5107L7.9364,5.5107C7.9489,5.5107 7.9604,5.502 7.9604,5.4884L7.9604,5.4016L7.9058,5.4016L7.9058,5.4404L7.8671,5.4404L7.8671,5.4022L7.8125,5.4022L7.8125,5.4409L7.7738,5.4409L7.7738,5.4033L7.7204,5.4033L7.7204,5.4033L7.7204,5.4033L7.7204,5.4895C7.7204,5.5004 7.7324,5.5107 7.7449,5.5107ZM8.1927,5.8593C8.2075,5.8593 8.22,5.8456 8.22,5.8287C8.22,5.8118 8.208,5.7982 8.1927,5.7982L7.4875,5.7982C7.4727,5.7982 7.4602,5.8118 7.4602,5.8287C7.4602,5.8456 7.4722,5.8593 7.4875,5.8593L8.1927,5.8593Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.2075,6.2558C8.2227,6.2558 8.2358,6.2405 8.2358,6.222C8.2358,6.2035 8.2233,6.1882 8.2075,6.1882L8.0171,6.1882C8.0165,6.1729 8.0116,6.1625 8.0095,6.1489C8.0116,6.1625 8.0176,6.1718 8.0182,6.1871L8.1982,6.1871L8.1665,5.9204L8.1764,5.9204C8.1905,5.9204 8.202,5.9067 8.202,5.8898C8.202,5.8729 8.1905,5.8593 8.1764,5.8593L7.5016,5.8593C7.4875,5.8593 7.476,5.8729 7.476,5.8898C7.476,5.9067 7.4875,5.9204 7.5016,5.9204L7.512,5.9204L7.4831,6.1865L7.6631,6.1871L7.6631,6.1876L7.4716,6.1876C7.4564,6.1876 7.4433,6.2029 7.4433,6.2215C7.4433,6.24 7.4558,6.2553 7.4716,6.2553L8.2075,6.2553L8.2075,6.2558ZM7.7253,6.0044C7.6958,6.0447 7.6718,6.1004 7.6653,6.1795C7.668,6.0955 7.6942,6.0431 7.7253,6.0044ZM10.1378,5.6476L9.9698,5.6476L9.9644,5.7976L10.1438,5.7976L10.1378,5.6476ZM9.5002,5.6471L9.6878,5.6471C9.7004,5.6471 9.7113,5.6384 9.7113,5.6247L9.7113,5.5375L9.6578,5.5375L9.6578,5.5762L9.6196,5.5762L9.6196,5.5375L9.5662,5.5375L9.5662,5.5762L9.528,5.5762L9.528,5.5385L9.4762,5.5385L9.4762,5.5385L9.4762,5.5385L9.4762,5.6247C9.4762,5.6373 9.4876,5.6471 9.5002,5.6471Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9365,5.5385L9.9365,5.5385L9.9365,5.5385L9.9365,5.6247C9.9365,5.6373 9.948,5.6476 9.9605,5.6476L10.1482,5.6476C10.1607,5.6476 10.1716,5.6389 10.1716,5.6253L10.1716,5.538L10.1182,5.538L10.1182,5.5767L10.08,5.5767L10.08,5.538L10.0265,5.538L10.0265,5.5767L9.9884,5.5767L9.9884,5.5391L9.9365,5.5385ZM9.6775,5.6476L9.5089,5.6476L9.504,5.7976L9.6829,5.7976L9.6775,5.6476ZM9.7304,5.7965L9.9175,5.7971L9.9055,5.5178L9.7429,5.5173L9.7304,5.7965ZM9.7298,5.5107L9.9213,5.5107C9.9338,5.5107 9.9453,5.502 9.9453,5.4884L9.9453,5.4016L9.8907,5.4016L9.8907,5.4404L9.852,5.4404L9.852,5.4022L9.7975,5.4022L9.7975,5.4409L9.7582,5.4409L9.7582,5.4033L9.7047,5.4033L9.7047,5.4033L9.7047,5.4033L9.7047,5.4895C9.7047,5.5004 9.7167,5.5107 9.7298,5.5107ZM10.1771,5.8593C10.1918,5.8593 10.2044,5.8456 10.2044,5.8287C10.2044,5.8118 10.1924,5.7982 10.1771,5.7982L9.4718,5.7982C9.4571,5.7982 9.4445,5.8118 9.4445,5.8287C9.4445,5.8456 9.4565,5.8593 9.4718,5.8593L10.1771,5.8593Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M10.0015,6.1882C10.0009,6.1729 9.996,6.1625 9.9938,6.1489C9.996,6.1625 10.002,6.1718 10.0025,6.1871L10.1825,6.1871L10.1509,5.9204L10.1607,5.9204C10.1749,5.9204 10.1864,5.9067 10.1864,5.8898C10.1864,5.8729 10.1749,5.8593 10.1607,5.8593L9.486,5.8593C9.4718,5.8593 9.4604,5.8729 9.4604,5.8898C9.4604,5.9067 9.4718,5.9204 9.486,5.9204L9.4964,5.9204L9.4675,6.1865L9.6475,6.1871L9.6475,6.1876L9.456,6.1876C9.4407,6.1876 9.4276,6.2029 9.4276,6.2215C9.4276,6.24 9.4402,6.2553 9.456,6.2553L10.1918,6.2553C10.2071,6.2553 10.2202,6.24 10.2202,6.2215C10.2202,6.2029 10.2076,6.1876 10.1918,6.1876L10.0015,6.1876L10.0015,6.1882ZM9.7096,6.0044C9.6802,6.0447 9.6562,6.1004 9.6496,6.1795C9.6524,6.0955 9.6785,6.0431 9.7096,6.0044ZM11.3656,9.6758C11.3744,9.6845 11.3902,9.6856 11.3989,9.6769L11.4605,9.6164L11.4605,9.6164L11.4605,9.6164L11.424,9.5798L11.3973,9.6065L11.3705,9.5798L11.3978,9.5525L11.3602,9.5149L11.3329,9.5422L11.3062,9.5155L11.3335,9.4882L11.2958,9.4505L11.2342,9.5116C11.2244,9.5215 11.226,9.5351 11.2347,9.5438L11.3656,9.6758ZM11.7213,9.9322L11.6945,9.9055L11.7218,9.8782L11.6842,9.8405L11.6569,9.8678L11.6302,9.8411L11.6575,9.8138L11.6198,9.7762L11.5582,9.8378C11.5484,9.8476 11.55,9.8613 11.5587,9.87L11.6907,10.0025C11.6995,10.0113 11.7153,10.0124 11.724,10.0036L11.7851,9.9431L11.7851,9.9431L11.7851,9.9431L11.7485,9.9065L11.7213,9.9322ZM11.3596,9.6698L11.2407,9.5509L11.13,9.6529L11.256,9.7795L11.3596,9.6698Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.454,9.9785L11.5805,10.1051L11.6842,9.9955L11.5653,9.8765L11.454,9.9785ZM11.0335,9.6873C11.0215,9.6993 11.0198,9.7167 11.0302,9.7271L11.0373,9.7342L10.8251,9.9L10.9522,10.0276C10.9636,10.0167 10.974,10.0151 10.9855,10.0064C10.9745,10.0145 10.9636,10.0184 10.9522,10.0287L10.818,9.894C10.8071,9.8831 10.7875,9.8847 10.7738,9.8978C10.7607,9.9109 10.7585,9.9305 10.7695,9.9415L11.2876,10.4613C11.2985,10.4722 11.3182,10.4705 11.3318,10.4575C11.3449,10.4444 11.3471,10.4247 11.3362,10.4138L11.2009,10.2785C11.2009,10.2785 11.2009,10.278 11.2015,10.278L11.3285,10.4045L11.4982,10.1967L11.5053,10.2038C11.5151,10.2136 11.5331,10.2125 11.5451,10.2005C11.5571,10.1885 11.5587,10.1711 11.5484,10.1607L11.0733,9.684C11.0629,9.6742 11.0449,9.6753 11.0335,9.6873ZM11.2882,10.1056C11.2827,10.1536 11.2636,10.2076 11.2091,10.2665C11.2576,10.2076 11.28,10.1536 11.2882,10.1056ZM11.5522,9.5138L11.4905,9.5749C11.4807,9.5847 11.4824,9.5984 11.4911,9.6076L11.6258,9.7429C11.6351,9.7522 11.6504,9.7533 11.6596,9.7445L11.7207,9.684L11.7207,9.684L11.7207,9.684L11.6831,9.6464L11.6564,9.6731L11.6291,9.6458L11.6564,9.6185L11.6176,9.5804L11.5904,9.6076L11.5631,9.5798L11.5904,9.5525L11.5522,9.5138ZM11.4218,9.9442L11.6116,9.7385L11.4971,9.6245L11.2898,9.8122L11.4218,9.9442ZM11.0651,9.6316C11.0531,9.6436 11.052,9.6616 11.0624,9.672L11.5593,10.1705C11.5696,10.1809 11.5882,10.1798 11.6002,10.1684C11.6122,10.1564 11.6133,10.1384 11.6029,10.128L11.106,9.6295C11.0951,9.6191 11.0765,9.6202 11.0651,9.6316ZM11.4491,7.5409L11.4491,7.6276C11.4491,7.6413 11.46,7.65 11.4725,7.65L11.6602,7.65C11.6727,7.65 11.6842,7.6396 11.6847,7.6271L11.6847,7.5409L11.6847,7.5409L11.6847,7.5409L11.6329,7.5409L11.6329,7.5785L11.5947,7.5785L11.5947,7.5398L11.5413,7.5398L11.5413,7.578L11.5031,7.578L11.5031,7.5393L11.4491,7.5409ZM11.9095,7.5409L11.9095,7.6276C11.9095,7.6413 11.9204,7.65 11.9329,7.65L12.1205,7.65C12.1331,7.65 12.1445,7.6396 12.1451,7.6271L12.1451,7.5409L12.1451,7.5409L12.1451,7.5409L12.0933,7.5409L12.0933,7.5785L12.0545,7.5785L12.0545,7.5398L12.0011,7.5398L12.0011,7.578L11.9629,7.578L11.9629,7.5393L11.9095,7.5409ZM11.6564,7.8005L11.6509,7.6505L11.4829,7.6505L11.4769,7.8005L11.6564,7.8005ZM12.1167,7.8005L12.1118,7.6505L11.9433,7.6505L11.9378,7.8005L12.1167,7.8005ZM11.7033,7.8L11.8904,7.7995L11.8778,7.5202L11.7153,7.5213L11.7033,7.8ZM11.676,7.404L11.676,7.4913C11.676,7.5049 11.6869,7.5136 11.7,7.5136L11.8909,7.5136C11.904,7.5136 11.9155,7.5033 11.9155,7.4907L11.9155,7.4045L11.9155,7.4045L11.9155,7.4045L11.862,7.4045L11.862,7.4422L11.8233,7.4422L11.8233,7.4035L11.7687,7.4035L11.7687,7.4416L11.73,7.4416L11.73,7.4029L11.676,7.4029L11.676,7.404ZM11.4164,7.8316C11.4164,7.8485 11.4284,7.8622 11.4436,7.8622L12.1489,7.8622C12.1636,7.8622 12.1762,7.8485 12.1762,7.8316C12.1762,7.8147 12.1642,7.8011 12.1489,7.8011L11.4436,7.8011C11.4284,7.8011 11.4164,7.8147 11.4164,7.8316ZM11.9727,8.1911L11.9727,8.1905L12.1527,8.19L12.1238,7.9238L12.1342,7.9238C12.1484,7.9238 12.1598,7.9102 12.1598,7.8933C12.1598,7.8764 12.1484,7.8627 12.1342,7.8627L11.4595,7.8627C11.4453,7.8627 11.4338,7.8764 11.4338,7.8933C11.4338,7.9102 11.4453,7.9238 11.4595,7.9238L11.4693,7.9238L11.4376,8.1905L11.6176,8.1905C11.6182,8.1747 11.6242,8.166 11.6264,8.1518C11.6242,8.1655 11.6193,8.1764 11.6187,8.1911L11.4284,8.1911C11.4131,8.1911 11.4,8.2064 11.4,8.2249C11.4,8.2435 11.4125,8.2587 11.4284,8.2587L12.1642,8.2587C12.1795,8.2587 12.1925,8.2435 12.1925,8.2249C12.1925,8.2064 12.18,8.1911 12.1642,8.1911L11.9727,8.1911L11.9727,8.1911ZM11.9111,8.0078C11.9422,8.046 11.9678,8.0984 11.9705,8.1813C11.964,8.1027 11.9405,8.0476 11.9111,8.0078ZM11.4725,5.6471L11.6602,5.6471C11.6727,5.6471 11.6842,5.6367 11.6847,5.6242L11.6847,5.538L11.6847,5.538L11.6847,5.538L11.6329,5.538L11.6329,5.5756L11.5947,5.5756L11.5947,5.5369L11.5413,5.5369L11.5413,5.5756L11.5031,5.5756L11.5031,5.5369L11.4496,5.5369L11.4496,5.6242C11.4491,5.6384 11.46,5.6471 11.4725,5.6471ZM11.6564,5.7976L11.6509,5.6476L11.4829,5.6476L11.4829,5.6476L11.4769,5.7976L11.6564,5.7976ZM11.9095,5.538L11.9095,5.6253C11.9095,5.6389 11.9204,5.6476 11.9329,5.6476L12.1205,5.6476C12.1331,5.6476 12.1445,5.6373 12.1451,5.6247L12.1451,5.5385L12.1451,5.5385L12.1451,5.5385L12.0933,5.5385L12.0933,5.5762L12.0545,5.5762L12.0545,5.5375L12.0011,5.5375L12.0011,5.5762L11.9629,5.5762L11.9629,5.5375L11.9095,5.538ZM12.1167,5.7976L12.1118,5.6476L11.9433,5.6476L11.9433,5.6476L11.9378,5.7976L12.1167,5.7976ZM11.7033,5.7971L11.8904,5.7965L11.8778,5.5173L11.7153,5.5178L11.7033,5.7971ZM11.6995,5.5107L11.8909,5.5107C11.904,5.5107 11.9155,5.5004 11.9155,5.4878L11.9155,5.4016L11.9155,5.4016L11.9155,5.4016L11.862,5.4016L11.862,5.4393L11.8233,5.4393L11.8233,5.4005L11.7687,5.4005L11.7687,5.4387L11.73,5.4387L11.73,5.4L11.6755,5.4L11.6755,5.4867C11.676,5.5015 11.6869,5.5107 11.6995,5.5107ZM12.1489,5.8593C12.1636,5.8593 12.1762,5.8456 12.1762,5.8287C12.1762,5.8118 12.1642,5.7982 12.1489,5.7982L11.4436,5.7982C11.4289,5.7982 11.4164,5.8118 11.4164,5.8287C11.4164,5.8456 11.4284,5.8593 11.4436,5.8593L12.1489,5.8593ZM12.1642,6.2558C12.1795,6.2558 12.1925,6.2405 12.1925,6.222C12.1925,6.2035 12.18,6.1882 12.1642,6.1882L11.9727,6.1882L11.9727,6.1876L12.1527,6.1871L12.1238,5.9209L12.1342,5.9209C12.1484,5.9209 12.1598,5.9073 12.1598,5.8904C12.1598,5.8735 12.1484,5.8598 12.1342,5.8598L11.4595,5.8598C11.4453,5.8598 11.4338,5.8735 11.4338,5.8904C11.4338,5.9073 11.4453,5.9209 11.4595,5.9209L11.4693,5.9209L11.4376,6.1876L11.6176,6.1876C11.6182,6.1718 11.6242,6.1631 11.6264,6.1489C11.6242,6.1625 11.6193,6.1735 11.6187,6.1882L11.4284,6.1882C11.4131,6.1882 11.4,6.2035 11.4,6.222C11.4,6.2405 11.4125,6.2558 11.4284,6.2558L12.1642,6.2558L12.1642,6.2558ZM11.9111,6.0049C11.9422,6.0431 11.9678,6.0955 11.9705,6.1784C11.964,6.0998 11.9405,6.0447 11.9111,6.0049Z" + android:strokeWidth="1" + android:fillColor="#FFFF00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0558,10.1209L7.9375,9.9955L8.0711,9.8618L8.1982,9.9785L8.0558,10.1209ZM7.9675,9.996L8.0564,10.0898L8.1665,9.9791L8.0716,9.8918L7.9675,9.996ZM8.3804,9.7953L8.262,9.6698L8.3956,9.5362L8.5227,9.6529L8.3804,9.7953ZM8.292,9.6704L8.3809,9.7642L8.4911,9.6535L8.3962,9.5662L8.292,9.6704Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9282,10.0195C7.9195,10.0195 7.9113,10.0162 7.9047,10.0102L7.8355,9.942L7.8431,9.9344L7.8507,9.942L7.8431,9.9344L7.8873,9.8902L7.914,9.9169L7.9255,9.9055L7.8982,9.8782L7.9511,9.8253L7.9784,9.8525L7.9898,9.8411L7.9625,9.8138L8.0155,9.7609L8.0853,9.8302C8.0989,9.8433 8.0984,9.864 8.0847,9.8776L7.9527,10.0102C7.9467,10.0162 7.9375,10.0195 7.9282,10.0195ZM7.8665,9.942L7.92,9.9949C7.9244,9.9993 7.9331,9.9987 7.938,9.9938L8.07,9.8613C8.0744,9.8569 8.076,9.8498 8.0705,9.8444L8.0165,9.7904L7.9942,9.8127L8.0215,9.84L7.9795,9.8825L7.9522,9.8553L7.9298,9.8776L7.9571,9.9049L7.9151,9.9469L7.8884,9.9202L7.8665,9.942ZM8.2527,9.6944C8.244,9.6944 8.2358,9.6911 8.2293,9.6851L8.1649,9.6213L8.1649,9.6125L8.2124,9.5651L8.2391,9.5918L8.2505,9.5804L8.2233,9.5531L8.2762,9.5002L8.3035,9.5275L8.3149,9.516L8.2876,9.4887L8.3405,9.4358L8.4104,9.5045C8.424,9.5182 8.4235,9.5384 8.4098,9.552L8.2778,9.6845C8.2713,9.6905 8.262,9.6944 8.2527,9.6944ZM8.1911,9.6164L8.2445,9.6693C8.2489,9.6736 8.2576,9.6731 8.2625,9.6682L8.3945,9.5356C8.3989,9.5313 8.4005,9.5242 8.3951,9.5187L8.3411,9.4653L8.3187,9.4876L8.346,9.5149L8.304,9.5575L8.2767,9.5302L8.2544,9.5525L8.2816,9.5798L8.2396,9.6218L8.2129,9.5951L8.1911,9.6164ZM8.1322,9.7565C8.112,9.738 8.1393,9.7102 8.1589,9.7298L8.2064,9.7767L8.1796,9.8035L8.1322,9.7565M8.0378,9.9884C8.0193,9.9698 8.0444,9.9436 8.0629,9.9633L8.0995,9.9993L8.0744,10.0244L8.0378,9.9884M8.3635,9.6616C8.3449,9.6431 8.37,9.6169 8.3885,9.6365L8.4251,9.6725L8.4,9.6982L8.3635,9.6616M7.6745,8.2009L7.4722,8.2004L7.5038,7.9118L7.5065,7.9042L8.1764,7.9025L8.2113,8.2004L8.0073,8.2004L8.0073,8.19C8.0029,7.9827 7.8404,7.9369 7.8387,7.9364C7.8393,7.9369 7.6762,7.9685 7.6745,8.1895L7.6745,8.2009ZM8.0285,8.1791L8.1862,8.1791L8.1562,7.9244L7.8693,7.9249C7.8884,7.9336 7.914,7.9489 7.9385,7.9713C7.9773,8.0073 8.0236,8.0722 8.0285,8.1791ZM7.4962,8.1791L7.6533,8.1796C7.6571,8.0602 7.7078,7.9942 7.7504,7.9598C7.77,7.944 7.7902,7.9331 7.8071,7.926L7.5235,7.9265L7.4962,8.1791Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.2075,8.2691L7.4716,8.2691C7.4504,8.2691 7.4324,8.2489 7.4324,8.2244C7.4324,8.1998 7.4498,8.1796 7.4716,8.1796L8.2075,8.1796C8.2287,8.1796 8.2467,8.1998 8.2467,8.2244C8.2467,8.2495 8.2293,8.2691 8.2075,8.2691ZM7.4722,8.2015C7.4629,8.2015 7.4547,8.2118 7.4547,8.2244C7.4547,8.2369 7.4629,8.2473 7.4722,8.2473L8.208,8.2473C8.2173,8.2473 8.2255,8.2369 8.2255,8.2244C8.2255,8.2118 8.2173,8.2015 8.208,8.2015L7.4722,8.2015Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9516,8.2004L7.7395,8.2004L7.7395,8.1895L7.7285,8.1895C7.7291,8.0967 7.7684,8.0444 7.8005,8.0171C7.8011,8.0171 7.8295,7.9936 7.8398,7.9953C7.8458,7.9953 7.9505,8.0444 7.9516,8.1895L7.9516,8.2004ZM7.7504,8.1785L7.9293,8.1785C7.9244,8.0684 7.8556,8.0269 7.8382,8.0176C7.8218,8.0264 7.7553,8.0684 7.7504,8.1785ZM8.1927,7.8731L7.4875,7.8731C7.4667,7.8731 7.4498,7.8545 7.4498,7.8316C7.4498,7.8087 7.4667,7.7902 7.4875,7.7902L8.1927,7.7902C8.2135,7.7902 8.2304,7.8087 8.2304,7.8316C8.2309,7.8545 8.2135,7.8731 8.1927,7.8731ZM7.4875,7.812C7.4787,7.812 7.4711,7.8213 7.4711,7.8316C7.4711,7.842 7.4787,7.8513 7.4875,7.8513L8.1927,7.8513C8.2015,7.8513 8.2091,7.8425 8.2091,7.8316C8.2091,7.8207 8.2015,7.812 8.1927,7.812L7.4875,7.812ZM7.9364,7.5245L7.7449,7.5245C7.7258,7.5245 7.7095,7.5093 7.7095,7.4913L7.7095,7.3996L7.7171,7.3947L7.7204,7.3947L7.7847,7.3947L7.7847,7.4324L7.8016,7.4324L7.8016,7.3936L7.878,7.3936L7.878,7.4318L7.8955,7.4318L7.8955,7.3931L7.9718,7.3931L7.9718,7.4907C7.9713,7.5098 7.9565,7.5245 7.9364,7.5245ZM7.7313,7.4155L7.7313,7.4907C7.7313,7.4967 7.7378,7.5027 7.7455,7.5027L7.9369,7.5027C7.9429,7.5027 7.95,7.4989 7.95,7.4913L7.95,7.4149L7.9173,7.4149L7.9173,7.4536L7.8567,7.4536L7.8567,7.4155L7.824,7.4155L7.824,7.4542L7.7635,7.4542L7.7635,7.4165L7.7313,7.4155Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1769,7.9342L7.5022,7.9342C7.482,7.9342 7.4656,7.9156 7.4656,7.8927C7.4656,7.8698 7.482,7.8513 7.5022,7.8513L8.1769,7.8513C8.1971,7.8513 8.2135,7.8698 8.2135,7.8927C8.2135,7.9156 8.1971,7.9342 8.1769,7.9342ZM7.5022,7.8736C7.494,7.8736 7.4875,7.8824 7.4875,7.8933C7.4875,7.9042 7.4945,7.9129 7.5022,7.9129L8.1769,7.9129C8.1851,7.9129 8.1916,7.9042 8.1916,7.8933C8.1916,7.8824 8.1845,7.8736 8.1769,7.8736L7.5022,7.8736ZM7.944,7.8109L7.7345,7.8104L7.7476,7.5098L7.9309,7.5104L7.944,7.8109ZM7.7575,7.7885L7.9216,7.7891L7.9107,7.5316L7.7689,7.5311L7.7575,7.7885ZM7.5082,7.8115L7.5142,7.6396L7.7035,7.6396L7.71,7.8115L7.5082,7.8115ZM7.5349,7.6609L7.5305,7.7896L7.6871,7.7896L7.6822,7.6609L7.5349,7.6609ZM7.9691,7.8115L7.9751,7.6396L8.1644,7.6396L8.1709,7.8115L7.9691,7.8115ZM7.9958,7.6609L7.9915,7.7896L8.148,7.7896L8.1431,7.6609L7.9958,7.6609Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.7035,7.6609L7.5158,7.6609C7.4967,7.6609 7.4809,7.6456 7.4809,7.6276L7.4809,7.536L7.4885,7.5311L7.4918,7.5311L7.5545,7.5311L7.5545,7.5687L7.5709,7.5687L7.5709,7.53L7.6462,7.5305L7.6462,7.5687L7.6625,7.5687L7.6625,7.53L7.7378,7.53L7.7378,7.6276C7.7373,7.6462 7.7225,7.6609 7.7035,7.6609ZM7.5022,7.5524L7.5022,7.6276C7.5022,7.6336 7.5087,7.6396 7.5158,7.6396L7.7035,7.6396C7.7095,7.6396 7.716,7.6358 7.716,7.6282L7.716,7.5518L7.6844,7.5518L7.6844,7.5905L7.6244,7.5905L7.6244,7.5518L7.5927,7.5518L7.5927,7.5905L7.5327,7.5905L7.5327,7.5529L7.5022,7.5524ZM8.1638,7.6609L7.9762,7.6609C7.9571,7.6609 7.9413,7.6456 7.9413,7.6276L7.9413,7.536L7.9489,7.5311L7.9522,7.5311L8.0149,7.5311L8.0149,7.5687L8.0313,7.5687L8.0313,7.53L8.1065,7.5305L8.1065,7.5687L8.1229,7.5687L8.1229,7.53L8.1982,7.53L8.1982,7.6276C8.1976,7.6467 8.1835,7.6609 8.1638,7.6609ZM7.9631,7.5524L7.9631,7.6276C7.9631,7.6336 7.9696,7.6396 7.9767,7.6396L8.1644,7.6396C8.1704,7.6396 8.1769,7.6358 8.1769,7.6282L8.1769,7.5518L8.1453,7.5518L8.1453,7.5905L8.0853,7.5905L8.0853,7.5518L8.0536,7.5518L8.0536,7.5905L7.9936,7.5905L7.9936,7.5529L7.9631,7.5524ZM7.8213,7.6091C7.8202,7.5818 7.8595,7.5818 7.8589,7.6091L7.8589,7.6756L7.8213,7.6756L7.8213,7.6091M7.59,7.7056C7.59,7.6795 7.6265,7.6789 7.626,7.7056L7.626,7.7569L7.59,7.7569L7.59,7.7056M8.052,7.7056C8.052,7.6795 8.0885,7.6789 8.088,7.7056L8.088,7.7569L8.052,7.7569L8.052,7.7056M8.0591,10.1891C8.0482,10.1891 8.0373,10.1847 8.0291,10.1765C8.0127,10.1607 8.0116,10.1356 8.0264,10.1209L8.5233,9.6224C8.5298,9.6158 8.5391,9.612 8.5489,9.612C8.5489,9.612 8.5489,9.612 8.5489,9.612C8.5598,9.612 8.5713,9.6169 8.5795,9.6245C8.5958,9.6404 8.5969,9.6655 8.5822,9.6802L8.0853,10.1787C8.0776,10.1853 8.0684,10.1891 8.0591,10.1891ZM8.0416,10.1356C8.0356,10.1416 8.0367,10.1536 8.0444,10.1607C8.052,10.1684 8.0635,10.1695 8.07,10.1629L8.5669,9.6644C8.5729,9.6584 8.5718,9.6464 8.5642,9.6393C8.5598,9.6349 8.5544,9.6327 8.5495,9.6327C8.5467,9.6316 8.5424,9.6333 8.5391,9.6365L8.0416,10.1356Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1142,10.2213C8.1033,10.2213 8.0924,10.2169 8.0836,10.2082C8.0673,10.1924 8.0656,10.1673 8.0804,10.1531L8.5555,9.6764C8.5696,9.6622 8.5947,9.6633 8.6105,9.6796C8.6187,9.6878 8.6236,9.6993 8.6236,9.7102C8.6236,9.7195 8.6204,9.7282 8.6138,9.7347L8.1387,10.2115C8.1322,10.218 8.1235,10.2213 8.1142,10.2213ZM8.58,9.6884C8.5762,9.6884 8.5729,9.6895 8.5707,9.6916L8.0956,10.1684C8.0902,10.1744 8.0913,10.1853 8.0989,10.1929C8.1065,10.2005 8.118,10.2016 8.1235,10.1962L8.5985,9.7195C8.6013,9.7167 8.6018,9.7129 8.6018,9.7102C8.6018,9.7047 8.5991,9.6993 8.5947,9.6949C8.5909,9.6905 8.5855,9.6884 8.58,9.6884ZM7.992,9.7615C7.9833,9.7615 7.9751,9.7582 7.9691,9.7522L7.8998,9.684L7.9075,9.6764L7.9151,9.684L7.9075,9.6764L7.9527,9.6311L7.9795,9.6578L7.9915,9.6458L7.9642,9.6185L8.0182,9.5645L8.0455,9.5913L8.0575,9.5793L8.0302,9.552L8.0842,9.498L8.154,9.5673C8.1605,9.5733 8.1638,9.5815 8.1638,9.5902C8.1638,9.5995 8.16,9.6082 8.1535,9.6153L8.0187,9.7505C8.0105,9.7582 8.0013,9.7615 7.992,9.7615ZM7.9304,9.684L7.9838,9.7369C7.9882,9.7413 7.9969,9.7407 8.0024,9.7353L8.1371,9.6C8.1398,9.5973 8.1415,9.594 8.1415,9.5902C8.1415,9.5902 8.1404,9.5847 8.1382,9.5825L8.0842,9.5285L8.0613,9.552L8.0885,9.5793L8.046,9.6224L8.0187,9.5951L7.9953,9.6185L8.0225,9.6458L7.98,9.6889L7.9533,9.6622L7.9304,9.684Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.214,9.9595L8.0095,9.738L8.1393,9.6093L8.3624,9.8116L8.214,9.9595ZM8.0395,9.7391L8.2145,9.9284L8.3307,9.8127L8.1398,9.6393L8.0395,9.7391ZM8.4878,10.2393L8.4802,10.2316C8.4169,10.1684 8.406,10.1067 8.4076,10.0658C8.4087,10.0462 8.4136,10.0211 8.4191,10.0162L8.4218,10.0145C8.4262,10.0129 8.532,9.9715 8.6367,10.074L8.6444,10.0816L8.4878,10.2393ZM8.4349,10.0331C8.4295,10.0511 8.4115,10.1264 8.4878,10.2082L8.6138,10.0816C8.5325,10.008 8.454,10.0265 8.4349,10.0331Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.3302,10.4793C8.3187,10.4793 8.3062,10.4744 8.2969,10.4651C8.2795,10.4476 8.2773,10.4209 8.2925,10.4062L8.8107,9.8864C8.8184,9.8787 8.8293,9.8749 8.8407,9.876C8.8516,9.8771 8.862,9.882 8.8702,9.8902C8.8876,9.9076 8.8898,9.9338 8.8745,9.9491L8.3564,10.4689C8.3493,10.476 8.34,10.4793 8.3302,10.4793ZM8.3078,10.4209C8.3013,10.4275 8.3029,10.4405 8.3122,10.4493C8.3209,10.458 8.334,10.4596 8.3405,10.4531L8.8587,9.9333C8.8653,9.9267 8.8636,9.9136 8.8544,9.9049C8.85,9.9005 8.844,9.8973 8.838,9.8967C8.8331,9.8962 8.8287,9.8978 8.8255,9.9005L8.3078,10.4209Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.3073,10.4204L8.124,10.1945L8.1207,10.1875L8.1262,10.182L8.5915,9.7129L8.8287,9.8984L8.6858,10.0418L8.6782,10.0347C8.5271,9.8918 8.3804,9.9742 8.3787,9.9753L8.3787,9.9753C8.3793,9.9753 8.2871,10.1127 8.4436,10.2698L8.4513,10.2775L8.3073,10.4204ZM8.148,10.1907L8.3089,10.3882L8.4196,10.2775C8.3367,10.1902 8.3258,10.1078 8.3313,10.0533C8.334,10.0287 8.34,10.0069 8.3465,9.99L8.148,10.1907ZM8.4835,9.9295C8.5364,9.9295 8.61,9.9453 8.6842,10.0124L8.7949,9.9011L8.592,9.7429L8.3902,9.9464C8.4098,9.9393 8.4382,9.9316 8.4709,9.93C8.4753,9.9295 8.4796,9.9295 8.4835,9.9295ZM7.8213,5.6062C7.8202,5.5789 7.8595,5.5789 7.8589,5.6062L7.8589,5.6727L7.8213,5.6727L7.8213,5.6062M7.59,5.7027C7.59,5.6765 7.6265,5.676 7.626,5.7027L7.626,5.754L7.59,5.754L7.59,5.7027M8.052,5.7027C8.052,5.6765 8.0885,5.676 8.088,5.7027L8.088,5.754L8.052,5.754L8.052,5.7027M8.1638,5.658L7.9762,5.658C7.9571,5.658 7.9413,5.6427 7.9413,5.6247L7.9413,5.5331L7.9489,5.5282L7.9522,5.5282L8.0149,5.5282L8.0149,5.5658L8.0313,5.5658L8.0313,5.5271L8.1065,5.5276L8.1065,5.5658L8.1229,5.5658L8.1229,5.5271L8.1982,5.5271L8.1982,5.6247C8.1976,5.6433 8.1829,5.658 8.1638,5.658ZM7.9631,5.5495L7.9631,5.6247C7.9631,5.6307 7.9696,5.6367 7.9767,5.6367L8.1644,5.6367C8.1704,5.6367 8.1769,5.6329 8.1769,5.6253L8.1769,5.5489L8.1453,5.5489L8.1453,5.5876L8.0853,5.5876L8.0853,5.5489L8.0536,5.5489L8.0536,5.5876L7.9936,5.5876L7.9936,5.55L7.9631,5.5495ZM7.7035,5.658L7.5158,5.658C7.4967,5.658 7.4809,5.6427 7.4809,5.6247L7.4809,5.5331L7.4885,5.5282L7.4918,5.5282L7.5545,5.5282L7.5545,5.5658L7.5709,5.5658L7.5709,5.5271L7.6462,5.5276L7.6462,5.5658L7.6625,5.5658L7.6625,5.5271L7.7378,5.5271L7.7378,5.6247C7.7373,5.6433 7.7225,5.658 7.7035,5.658ZM7.5022,5.5495L7.5022,5.6247C7.5022,5.6307 7.5087,5.6367 7.5158,5.6367L7.7035,5.6367C7.7095,5.6367 7.716,5.6329 7.716,5.6253L7.716,5.5489L7.6844,5.5489L7.6844,5.5876L7.6244,5.5876L7.6244,5.5489L7.5927,5.5489L7.5927,5.5876L7.5327,5.5876L7.5327,5.55L7.5022,5.5495Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9691,5.8085L7.9751,5.6367L8.1644,5.6367L8.1709,5.8085L7.9691,5.8085ZM7.9958,5.658L7.9915,5.7867L8.148,5.7867L8.1431,5.658L7.9958,5.658ZM7.5082,5.8085L7.5142,5.6367L7.7035,5.6367L7.71,5.8085L7.5082,5.8085ZM7.5349,5.658L7.5305,5.7867L7.6871,5.7867L7.6822,5.658L7.5349,5.658ZM7.944,5.808L7.7345,5.8075L7.7476,5.5069L7.9309,5.5075L7.944,5.808ZM7.7575,5.7856L7.9216,5.7862L7.9107,5.5287L7.7689,5.5282L7.7575,5.7856Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.9364,5.5211L7.7449,5.5211C7.7258,5.5211 7.7095,5.5058 7.7095,5.4878L7.7095,5.3962L7.7171,5.3913L7.7204,5.3913L7.7847,5.3913L7.7847,5.4289L7.8016,5.4289L7.8016,5.3902L7.878,5.3902L7.878,5.4284L7.8955,5.4284L7.8955,5.3896L7.9718,5.3896L7.9718,5.4873C7.9713,5.5069 7.9565,5.5211 7.9364,5.5211ZM7.7313,5.4125L7.7313,5.4878C7.7313,5.4938 7.7378,5.4998 7.7455,5.4998L7.9369,5.4998C7.9429,5.4998 7.95,5.496 7.95,5.4884L7.95,5.412L7.9173,5.412L7.9173,5.4507L7.8567,5.4507L7.8567,5.4125L7.824,5.4125L7.824,5.4513L7.7635,5.4513L7.7635,5.4136L7.7313,5.4125ZM8.1769,5.9313L7.5022,5.9313C7.482,5.9313 7.4656,5.9127 7.4656,5.8898C7.4656,5.8669 7.482,5.8484 7.5022,5.8484L8.1769,5.8484C8.1971,5.8484 8.2135,5.8669 8.2135,5.8898C8.2135,5.9127 8.1971,5.9313 8.1769,5.9313ZM7.5022,5.8707C7.494,5.8707 7.4875,5.8795 7.4875,5.8904C7.4875,5.9013 7.4945,5.91 7.5022,5.91L8.1769,5.91C8.1851,5.91 8.1916,5.9013 8.1916,5.8904C8.1916,5.8795 8.1845,5.8707 8.1769,5.8707L7.5022,5.8707Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1927,5.8702L7.4875,5.8702C7.4667,5.8702 7.4498,5.8516 7.4498,5.8287C7.4498,5.8058 7.4667,5.7873 7.4875,5.7873L8.1927,5.7873C8.2135,5.7873 8.2304,5.8058 8.2304,5.8287C8.2309,5.8516 8.2135,5.8702 8.1927,5.8702ZM7.4875,5.8091C7.4787,5.8091 7.4711,5.8184 7.4711,5.8287C7.4711,5.8391 7.4787,5.8484 7.4875,5.8484L8.1927,5.8484C8.2015,5.8484 8.2091,5.8396 8.2091,5.8287C8.2091,5.8178 8.2015,5.8091 8.1927,5.8091L7.4875,5.8091ZM7.9516,6.1975L7.7395,6.1975L7.7395,6.1865L7.7285,6.1865C7.7291,6.0938 7.7684,6.0415 7.8005,6.0142C7.8011,6.0142 7.8295,5.9907 7.8398,5.9924C7.8458,5.9918 7.9505,6.0415 7.9516,6.1865L7.9516,6.1975ZM7.7504,6.1756L7.9293,6.1756C7.9244,6.0655 7.8556,6.024 7.8382,6.0147C7.8218,6.0235 7.7553,6.0655 7.7504,6.1756Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.2075,6.2662L7.4716,6.2662C7.4504,6.2662 7.4324,6.246 7.4324,6.2215C7.4324,6.1969 7.4498,6.1767 7.4716,6.1767L8.2075,6.1767C8.2287,6.1767 8.2467,6.1969 8.2467,6.2215C8.2467,6.2465 8.2293,6.2662 8.2075,6.2662ZM7.4722,6.1985C7.4629,6.1985 7.4547,6.2089 7.4547,6.2215C7.4547,6.234 7.4629,6.2444 7.4722,6.2444L8.208,6.2444C8.2173,6.2444 8.2255,6.234 8.2255,6.2215C8.2255,6.2089 8.2173,6.1985 8.208,6.1985L7.4722,6.1985Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6745,6.198L7.4722,6.1975L7.5038,5.9089L7.5065,5.9013L8.1764,5.8996L8.2113,6.198L8.0073,6.198L8.0073,6.1876C8.0029,5.9804 7.8404,5.9345 7.8387,5.934C7.8393,5.9345 7.6762,5.9662 7.6745,6.1871L7.6745,6.198ZM8.0285,6.1762L8.1862,6.1762L8.1562,5.9215L7.8693,5.922C7.8884,5.9307 7.914,5.946 7.9385,5.9684C7.9773,6.0044 8.0236,6.0693 8.0285,6.1762ZM7.4962,6.1762L7.6533,6.1767C7.6571,6.0573 7.7078,5.9913 7.7504,5.9569C7.77,5.9411 7.7902,5.9302 7.8071,5.9231L7.5235,5.9236L7.4962,6.1762Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8144,11.1207C9.156,11.1207 8.5331,10.8627 8.0607,10.3947C7.5889,9.9273 7.3293,9.3098 7.3293,8.6569L7.3511,8.6547L7.3511,8.6569C7.3511,9.3038 7.6085,9.9158 8.076,10.3789C8.544,10.8431 9.1615,11.0984 9.8138,11.0984C10.4695,11.0984 11.0869,10.8442 11.5522,10.3827C12.0153,9.9235 12.2716,9.3147 12.2738,8.6678L12.2738,8.6591L12.2738,5.3482L7.3538,5.3476L7.3505,8.6553L7.3287,8.6553L7.332,5.3258L12.2956,5.3269L12.2956,8.6602C12.2956,9.3164 12.0371,9.9338 11.5675,10.3996C11.0989,10.8644 10.476,11.1207 9.8144,11.1207ZM9.8127,10.1449C9.4265,10.1449 9.0567,9.9889 8.7704,9.7047C8.4916,9.4282 8.3318,9.048 8.3318,8.6613L8.3313,6.3142L8.3422,6.3142L11.2958,6.3196L11.3024,6.3262L11.3024,6.3305L11.3024,8.4447L11.3007,8.6684C11.3007,8.73 11.2969,8.7971 11.2904,8.8527C11.2516,9.1767 11.1038,9.4735 10.8644,9.7113C10.5829,9.9911 10.2093,10.1449 9.8127,10.1449ZM8.3531,6.3365L8.3536,8.6618C8.3536,9.0425 8.5113,9.4173 8.7856,9.6895C9.0676,9.9693 9.432,10.1231 9.8122,10.1231C10.2027,10.1231 10.5709,9.9715 10.8485,9.6965C11.0847,9.462 11.2304,9.1696 11.2685,8.8505C11.2751,8.796 11.2789,8.7295 11.2789,8.6689L11.2805,8.4453L11.2805,6.342L8.3531,6.3365Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8171,11.2304C9.1364,11.2304 8.4884,10.9587 7.992,10.4662C7.5038,9.9818 7.2338,9.3431 7.23,8.6656L7.23,8.6656L7.2295,5.2085L12.4129,5.2145L12.4129,8.6531C12.4129,9.3398 12.1424,9.9867 11.6515,10.4744C11.16,10.9615 10.5087,11.2304 9.8171,11.2304ZM7.2584,8.6362L7.2584,8.6509C7.2584,9.3262 7.5262,9.9633 8.0122,10.4455C8.5031,10.9331 9.144,11.2015 9.8171,11.2015C10.5011,11.2015 11.1453,10.9358 11.6307,10.4536C12.114,9.9742 12.3807,9.3387 12.384,8.6635L12.384,8.6531L12.384,5.2435L7.2584,5.2375L7.2584,8.6362Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9535,5.8085L9.9595,5.6367L10.1487,5.6367L10.1553,5.8085L9.9535,5.8085ZM9.9802,5.658L9.9758,5.7867L10.1324,5.7867L10.1275,5.658L9.9802,5.658Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M10.1482,5.658L9.9605,5.658C9.9415,5.658 9.9256,5.6427 9.9256,5.6247L9.9256,5.5331L9.9333,5.5282L9.9365,5.5282L9.9993,5.5282L9.9993,5.5658L10.0156,5.5658L10.0156,5.5271L10.0909,5.5276L10.0909,5.5658L10.1073,5.5658L10.1073,5.5271L10.1825,5.5271L10.1825,5.6247C10.1825,5.6433 10.1673,5.658 10.1482,5.658ZM9.9475,5.5495L9.9475,5.6247C9.9475,5.6307 9.954,5.6367 9.9611,5.6367L10.1487,5.6367C10.1547,5.6367 10.1613,5.6329 10.1613,5.6253L10.1613,5.5489L10.1296,5.5489L10.1296,5.5876L10.0696,5.5876L10.0696,5.5489L10.038,5.5489L10.038,5.5876L9.978,5.5876L9.978,5.55L9.9475,5.5495ZM9.6878,5.658L9.5002,5.658C9.4811,5.658 9.4653,5.6427 9.4653,5.6247L9.4653,5.5331L9.4729,5.5282L9.4762,5.5282L9.5389,5.5282L9.5389,5.5658L9.5553,5.5658L9.5553,5.5271L9.6305,5.5276L9.6305,5.5658L9.6469,5.5658L9.6469,5.5271L9.7222,5.5271L9.7222,5.6247C9.7216,5.6433 9.7069,5.658 9.6878,5.658ZM9.4865,5.5495L9.4865,5.6247C9.4865,5.6307 9.4931,5.6367 9.5002,5.6367L9.6878,5.6367C9.6938,5.6367 9.7004,5.6329 9.7004,5.6253L9.7004,5.5489L9.6687,5.5489L9.6687,5.5876L9.6087,5.5876L9.6087,5.5489L9.5771,5.5489L9.5771,5.5876L9.5171,5.5876L9.5171,5.55L9.4865,5.5495ZM9.8056,5.6062C9.8045,5.5789 9.8438,5.5789 9.8433,5.6062L9.8433,5.6727L9.8056,5.6727L9.8056,5.6062M9.5744,5.7027C9.5744,5.6765 9.6109,5.676 9.6104,5.7027L9.6104,5.754L9.5744,5.754L9.5744,5.7027M10.0364,5.7027C10.0364,5.6765 10.0729,5.676 10.0724,5.7027L10.0724,5.754L10.0364,5.754L10.0364,5.7027" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.4925,5.8085L9.4985,5.6367L9.6878,5.6367L9.6944,5.8085L9.4925,5.8085ZM9.5193,5.658L9.5149,5.7867L9.6715,5.7867L9.6665,5.658L9.5193,5.658ZM9.9289,5.808L9.7195,5.8075L9.7325,5.5069L9.9158,5.5075L9.9289,5.808ZM9.7418,5.7856L9.906,5.7862L9.8951,5.5287L9.7533,5.5282L9.7418,5.7856Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.9213,5.5211L9.7298,5.5211C9.7107,5.5211 9.6944,5.5058 9.6944,5.4878L9.6944,5.3962L9.702,5.3913L9.7053,5.3913L9.7696,5.3913L9.7696,5.4289L9.7865,5.4289L9.7865,5.3902L9.8629,5.3902L9.8629,5.4284L9.8804,5.4284L9.8804,5.3896L9.9567,5.3896L9.9567,5.4873C9.9556,5.5069 9.9409,5.5211 9.9213,5.5211ZM9.7156,5.4125L9.7156,5.4878C9.7156,5.4938 9.7222,5.4998 9.7298,5.4998L9.9213,5.4998C9.9273,5.4998 9.9344,5.496 9.9344,5.4884L9.9344,5.412L9.9016,5.412L9.9016,5.4507L9.8411,5.4507L9.8411,5.4125L9.8084,5.4125L9.8084,5.4513L9.7473,5.4513L9.7473,5.4136L9.7156,5.4125ZM10.1613,5.9313L9.4865,5.9313C9.4664,5.9313 9.45,5.9127 9.45,5.8898C9.45,5.8669 9.4664,5.8484 9.4865,5.8484L10.1613,5.8484C10.1815,5.8484 10.1978,5.8669 10.1978,5.8898C10.1978,5.9127 10.1815,5.9313 10.1613,5.9313ZM9.4865,5.8707C9.4784,5.8707 9.4718,5.8795 9.4718,5.8904C9.4718,5.9013 9.4789,5.91 9.4865,5.91L10.1613,5.91C10.1695,5.91 10.176,5.9013 10.176,5.8904C10.176,5.8795 10.1689,5.8707 10.1613,5.8707L9.4865,5.8707Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M10.1771,5.8702L9.4718,5.8702C9.4511,5.8702 9.4342,5.8516 9.4342,5.8287C9.4342,5.8058 9.4511,5.7873 9.4718,5.7873L10.1771,5.7873C10.1978,5.7873 10.2147,5.8058 10.2147,5.8287C10.2153,5.8516 10.1984,5.8702 10.1771,5.8702ZM9.4718,5.8091C9.4631,5.8091 9.4555,5.8184 9.4555,5.8287C9.4555,5.8391 9.4631,5.8484 9.4718,5.8484L10.1771,5.8484C10.1858,5.8484 10.1935,5.8396 10.1935,5.8287C10.1935,5.8178 10.1858,5.8091 10.1771,5.8091L9.4718,5.8091ZM9.936,6.1975L9.7238,6.1975L9.7238,6.1865L9.7129,6.1865C9.7135,6.0938 9.7527,6.0415 9.7849,6.0142C9.7855,6.0142 9.8138,5.9907 9.8242,5.9924L9.8242,5.9924C9.8318,5.9924 9.9349,6.042 9.9355,6.1865L9.936,6.1975ZM9.7347,6.1756L9.9136,6.1756C9.9087,6.0655 9.84,6.024 9.8225,6.0147C9.8062,6.0235 9.7396,6.0655 9.7347,6.1756Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M10.1918,6.2662L9.456,6.2662C9.4347,6.2662 9.4167,6.246 9.4167,6.2215C9.4167,6.1969 9.4342,6.1767 9.456,6.1767L10.1918,6.1767C10.2131,6.1767 10.2311,6.1969 10.2311,6.2215C10.2311,6.2465 10.2136,6.2662 10.1918,6.2662ZM9.4565,6.1985C9.4473,6.1985 9.4391,6.2089 9.4391,6.2215C9.4391,6.234 9.4473,6.2444 9.4565,6.2444L10.1924,6.2444C10.2016,6.2444 10.2098,6.234 10.2098,6.2215C10.2098,6.2089 10.2016,6.1985 10.1924,6.1985L9.4565,6.1985Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.6589,6.198L9.4565,6.1975L9.4876,5.9013L10.1602,5.8996L10.1951,6.198L9.9922,6.198L9.9922,6.1876C9.9878,5.9804 9.8253,5.9345 9.8236,5.934C9.8242,5.9345 9.6611,5.9662 9.6595,6.1871L9.6589,6.198ZM10.0129,6.1762L10.1705,6.1762L10.1405,5.9215L9.8536,5.922C9.8727,5.9307 9.8984,5.946 9.9229,5.9684C9.9616,6.0044 10.008,6.0693 10.0129,6.1762ZM9.4805,6.1762L9.6376,6.1767C9.6415,6.0573 9.6922,5.9913 9.7347,5.9569C9.7544,5.9411 9.7745,5.9302 9.7915,5.9231L9.5078,5.9236L9.4805,6.1762ZM11.2729,9.6616C11.2915,9.6431 11.2664,9.6169 11.2478,9.6365L11.2113,9.6725L11.2364,9.6982L11.2729,9.6616M11.5042,9.7565C11.5244,9.738 11.4971,9.7102 11.4775,9.7298L11.43,9.7767L11.4567,9.8035L11.5042,9.7565M11.5985,9.9884C11.6171,9.9698 11.592,9.9436 11.5735,9.9633L11.5369,9.9993L11.562,10.0244L11.5985,9.9884M11.3836,9.6944C11.3744,9.6944 11.3651,9.6911 11.3585,9.684L11.2265,9.5515C11.2129,9.5378 11.2129,9.5171 11.226,9.504L11.2958,9.4353L11.3487,9.4882L11.3215,9.5155L11.3329,9.5269L11.3602,9.4996L11.4131,9.5525L11.3858,9.5798L11.3973,9.5913L11.424,9.5645L11.4725,9.6131L11.4704,9.6218L11.4071,9.6845C11.4005,9.6911 11.3918,9.6944 11.3836,9.6944ZM11.2953,9.4653L11.2413,9.5187C11.2358,9.5242 11.2375,9.5313 11.2418,9.5356L11.3738,9.6682C11.3787,9.6731 11.3875,9.6736 11.3918,9.6693L11.4453,9.6164L11.424,9.5951L11.3973,9.6218L11.3553,9.5798L11.3825,9.5525L11.3602,9.5302L11.3329,9.5575L11.2909,9.5149L11.3182,9.4876L11.2953,9.4653ZM11.7082,10.0195C11.6989,10.0195 11.6896,10.0162 11.6825,10.0091L11.5505,9.8765C11.5369,9.8629 11.5369,9.8422 11.55,9.8291L11.6198,9.7604L11.6727,9.8133L11.6455,9.8405L11.6569,9.852L11.6842,9.8247L11.7371,9.8776L11.7098,9.9049L11.7213,9.9164L11.748,9.8896L11.7955,9.9371L11.7955,9.9464L11.7311,10.0102C11.7251,10.0167 11.7164,10.0195 11.7082,10.0195ZM11.6198,9.7909L11.5658,9.8444C11.5604,9.8498 11.562,9.8569 11.5664,9.8613L11.6984,9.9938C11.7033,9.9987 11.712,9.9993 11.7164,9.9949L11.7698,9.942L11.7485,9.9207L11.7218,9.9475L11.6798,9.9055L11.7071,9.8782L11.6847,9.8558L11.6575,9.8831L11.6155,9.8405L11.6427,9.8133L11.6198,9.7909Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.256,9.7953L11.1142,9.6529L11.2413,9.5362L11.3744,9.6698L11.256,9.7953ZM11.1453,9.6535L11.2555,9.7642L11.3444,9.6704L11.2407,9.5662L11.1453,9.6535ZM11.5805,10.1209L11.4387,9.9785L11.5582,9.8689L11.5653,9.8765L11.5729,9.8689L11.5729,9.8689L11.5805,9.8765L11.5805,9.8765L11.6984,9.9949L11.5805,10.1209ZM11.4698,9.9785L11.58,10.0893L11.6689,9.9955L11.5653,9.8913L11.4698,9.9785ZM11.4224,9.9595L11.274,9.8122L11.4971,9.6098L11.6269,9.7385L11.4224,9.9595ZM11.3056,9.8127L11.4218,9.9284L11.5969,9.7391L11.4965,9.6393L11.3056,9.8127Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.6444,9.7615C11.6351,9.7615 11.6258,9.7576 11.6187,9.7505L11.484,9.6153C11.4775,9.6087 11.4736,9.5995 11.4736,9.5902C11.4736,9.5815 11.4775,9.5733 11.4835,9.5673L11.5533,9.4985L11.6073,9.5525L11.58,9.5798L11.592,9.5918L11.6193,9.5645L11.6733,9.6185L11.646,9.6458L11.658,9.6578L11.6847,9.6311L11.7322,9.6791L11.7355,9.6862L11.6684,9.7522C11.6613,9.7587 11.6525,9.7615 11.6444,9.7615ZM11.5522,9.5291L11.4982,9.5825C11.496,9.5847 11.4949,9.5875 11.4949,9.5875C11.4949,9.594 11.4965,9.5973 11.4993,9.6L11.634,9.7353C11.6389,9.7402 11.6482,9.7407 11.6525,9.7369L11.706,9.684L11.6836,9.6616L11.6569,9.6884L11.6144,9.6453L11.6416,9.618L11.6182,9.5951L11.5909,9.6224L11.5484,9.5793L11.5756,9.552L11.5522,9.5291ZM11.5222,10.2213C11.5129,10.2213 11.5042,10.218 11.4976,10.2115L11.0225,9.7347C11.016,9.7282 11.0127,9.72 11.0127,9.7102C11.0127,9.6993 11.0176,9.6878 11.0258,9.6796C11.0335,9.672 11.0433,9.6676 11.0531,9.6665C11.064,9.666 11.0738,9.6693 11.0809,9.6764L11.556,10.1531C11.5702,10.1673 11.5685,10.1918 11.5527,10.2082C11.544,10.2169 11.5325,10.2213 11.5222,10.2213ZM11.0564,9.6884C11.0558,9.6884 11.0553,9.6884 11.0547,9.6884C11.0498,9.6889 11.0449,9.6911 11.0411,9.6949C11.0367,9.6993 11.034,9.7047 11.034,9.7102C11.034,9.7129 11.0345,9.7167 11.0373,9.7195L11.5124,10.1962C11.5178,10.2016 11.5293,10.2005 11.5369,10.1929C11.5445,10.1853 11.5462,10.1744 11.5402,10.1684L11.0651,9.6916C11.0624,9.6889 11.0585,9.6884 11.0564,9.6884Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.5773,10.1891C11.5675,10.1891 11.5582,10.1858 11.5516,10.1787L11.0547,9.6802C11.04,9.6655 11.0411,9.6404 11.0575,9.6245C11.0656,9.6164 11.0765,9.612 11.0875,9.612L11.0875,9.612C11.0973,9.612 11.1065,9.6158 11.1131,9.6224L11.61,10.1209C11.6247,10.1356 11.6236,10.1607 11.6073,10.1765C11.5991,10.1847 11.5882,10.1891 11.5773,10.1891ZM11.0875,9.6333C11.082,9.6333 11.0765,9.6355 11.0727,9.6398C11.0651,9.6475 11.064,9.6589 11.07,9.6649L11.5669,10.1635C11.5729,10.1695 11.5849,10.1684 11.5925,10.1613C11.6002,10.1536 11.6013,10.1422 11.5953,10.1362L11.0984,9.6376C11.0945,9.6338 11.0907,9.6333 11.0875,9.6333L11.0875,9.6333ZM11.1485,10.2393L10.9915,10.0816L10.9991,10.074C11.1038,9.9715 11.2096,10.0129 11.214,10.0145L11.2167,10.0162C11.2222,10.0211 11.2276,10.0462 11.2282,10.0658C11.2298,10.1067 11.2189,10.1684 11.1556,10.2316L11.1485,10.2393ZM11.0225,10.0816L11.1485,10.2082C11.2249,10.1264 11.2075,10.0505 11.2015,10.0331C11.1824,10.0265 11.1038,10.008 11.0225,10.0816Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.3062,10.4793C11.2964,10.4793 11.2871,10.476 11.28,10.4689L10.7618,9.9491C10.7465,9.9338 10.7487,9.9076 10.7662,9.8902C10.7744,9.882 10.7847,9.8771 10.7956,9.876C10.8071,9.8749 10.818,9.8787 10.8256,9.8864L11.3438,10.4062C11.3591,10.4215 11.3569,10.4476 11.3395,10.4651C11.3296,10.4744 11.3176,10.4793 11.3062,10.4793ZM10.7995,9.8973C10.7989,9.8973 10.7984,9.8973 10.7978,9.8973C10.7918,9.8978 10.7864,9.9005 10.7815,9.9055C10.7727,9.9142 10.7705,9.9273 10.7771,9.9338L11.2953,10.4536C11.3018,10.4602 11.3149,10.4585 11.3236,10.4498C11.3324,10.4411 11.3345,10.428 11.328,10.4215L10.8098,9.9016C10.8076,9.8989 10.8038,9.8973 10.7995,9.8973Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.3291,10.4204L11.1862,10.2775L11.1938,10.2698C11.3498,10.1127 11.2582,9.9753 11.2571,9.9736L11.2571,9.9736C11.2565,9.9736 11.1098,9.8918 10.9593,10.0347L10.9516,10.0418L10.8087,9.8984L11.046,9.7129L11.5178,10.1885L11.5118,10.1962L11.3291,10.4204ZM11.2167,10.2775L11.3275,10.3882L11.4884,10.1907L11.2893,9.99C11.2958,10.0069 11.3024,10.0287 11.3051,10.0533C11.31,10.1078 11.2991,10.1902 11.2167,10.2775ZM10.8409,9.9005L10.9516,10.0118C11.0318,9.9398 11.1115,9.9273 11.1644,9.9295C11.1971,9.9311 11.2255,9.9382 11.2451,9.9458L11.0433,9.7424L10.8409,9.9005ZM11.5844,7.7056C11.5844,7.6795 11.5478,7.6789 11.5484,7.7056L11.5484,7.7569L11.5844,7.7569L11.5844,7.7056M12.0464,7.7056C12.0464,7.6795 12.0098,7.6789 12.0104,7.7056L12.0104,7.7569L12.0464,7.7569L12.0464,7.7056M11.8151,7.6091C11.8162,7.5818 11.7769,7.5818 11.7775,7.6091L11.7775,7.6756L11.8151,7.6756L11.8151,7.6091M11.6596,7.6609L11.472,7.6609C11.4524,7.6609 11.4376,7.6467 11.4376,7.6276L11.4376,7.53L11.5129,7.53L11.5129,7.5687L11.5293,7.5687L11.5293,7.5305L11.6045,7.53L11.6045,7.5687L11.6209,7.5687L11.6209,7.5311L11.6869,7.5311L11.6945,7.536L11.6945,7.6276C11.6951,7.6456 11.6787,7.6609 11.6596,7.6609ZM11.46,7.5513L11.46,7.6276C11.46,7.6358 11.4665,7.6391 11.4725,7.6391L11.6602,7.6391C11.6673,7.6391 11.6738,7.6336 11.6738,7.6271L11.6738,7.5518L11.6433,7.5518L11.6433,7.5895L11.5833,7.5895L11.5833,7.5507L11.5516,7.5507L11.5516,7.5895L11.4916,7.5895L11.4916,7.5507L11.46,7.5513ZM12.1205,7.6609L11.9329,7.6609C11.9138,7.6609 11.8985,7.6462 11.8985,7.6276L11.8985,7.53L11.9738,7.53L11.9738,7.5687L11.9902,7.5687L11.9902,7.5305L12.0655,7.53L12.0655,7.5687L12.0818,7.5687L12.0818,7.5311L12.1478,7.5311L12.1555,7.536L12.1555,7.6276C12.1555,7.6456 12.1396,7.6609 12.1205,7.6609ZM11.9204,7.5513L11.9204,7.6276C11.9204,7.6358 11.9269,7.6391 11.9329,7.6391L12.1205,7.6391C12.1276,7.6391 12.1342,7.6336 12.1342,7.6271L12.1342,7.5518L12.1036,7.5518L12.1036,7.5895L12.0436,7.5895L12.0436,7.5507L12.012,7.5507L12.012,7.5895L11.952,7.5895L11.952,7.5507L11.9204,7.5513Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.6673,7.8115L11.4655,7.8115L11.472,7.6396L11.6613,7.6396L11.6673,7.8115ZM11.4884,7.7896L11.6449,7.7896L11.6405,7.6609L11.4933,7.6609L11.4884,7.7896ZM12.1282,7.8115L11.9264,7.8115L11.9329,7.6396L12.1222,7.6396L12.1282,7.8115ZM11.9487,7.7896L12.1053,7.7896L12.1009,7.6609L11.9536,7.6609L11.9487,7.7896ZM11.6918,7.8109L11.7049,7.5104L11.8882,7.5098L11.9013,7.8104L11.6918,7.8109ZM11.7256,7.5316L11.7147,7.7891L11.8789,7.7885L11.8675,7.5311L11.7256,7.5316Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.8909,7.5245L11.6995,7.5245C11.6798,7.5245 11.6645,7.5104 11.6645,7.4913L11.6645,7.3936L11.7409,7.3936L11.7409,7.4324L11.7584,7.4324L11.7584,7.3942L11.8347,7.3942L11.8347,7.4329L11.8516,7.4329L11.8516,7.3953L11.9193,7.3953L11.9269,7.4002L11.9269,7.4918C11.9269,7.5087 11.9105,7.5245 11.8909,7.5245ZM11.6864,7.4149L11.6864,7.4913C11.6864,7.4995 11.6929,7.5027 11.6995,7.5027L11.8909,7.5027C11.898,7.5027 11.9045,7.4967 11.9051,7.4907L11.9051,7.4155L11.8735,7.4155L11.8735,7.4531L11.8129,7.4531L11.8129,7.4144L11.7802,7.4144L11.7802,7.4525L11.7196,7.4525L11.7196,7.4138L11.6864,7.4138L11.6864,7.4149ZM12.1342,7.9342L11.4595,7.9342C11.4393,7.9342 11.4229,7.9156 11.4229,7.8927C11.4229,7.8698 11.4393,7.8513 11.4595,7.8513L12.1342,7.8513C12.1544,7.8513 12.1707,7.8698 12.1707,7.8927C12.1707,7.9156 12.1544,7.9342 12.1342,7.9342ZM11.4595,7.8736C11.4513,7.8736 11.4447,7.8824 11.4447,7.8933C11.4447,7.9042 11.4518,7.9129 11.4595,7.9129L12.1342,7.9129C12.1424,7.9129 12.1489,7.9042 12.1489,7.8933C12.1489,7.8824 12.1418,7.8736 12.1342,7.8736L11.4595,7.8736Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M12.1489,7.8731L11.4436,7.8731C11.4229,7.8731 11.406,7.8545 11.406,7.8316C11.406,7.8087 11.4229,7.7902 11.4436,7.7902L12.1489,7.7902C12.1696,7.7902 12.1865,7.8087 12.1865,7.8316C12.1865,7.8545 12.1696,7.8731 12.1489,7.8731ZM11.4436,7.812C11.4349,7.812 11.4273,7.8213 11.4273,7.8316C11.4273,7.842 11.4349,7.8513 11.4436,7.8513L12.1489,7.8513C12.1576,7.8513 12.1653,7.8425 12.1653,7.8316C12.1653,7.8207 12.1576,7.812 12.1489,7.812L11.4436,7.812ZM11.9078,8.2004L11.6847,8.2004L11.6847,8.1895C11.6858,8.0444 11.7889,7.9947 11.7982,7.9947C11.8069,7.9936 11.8353,8.0165 11.8358,8.0171C11.8685,8.0444 11.9073,8.0967 11.9078,8.1895L11.9078,8.2004ZM11.7071,8.1785L11.886,8.1785C11.8811,8.0673 11.814,8.0258 11.7982,8.0176C11.784,8.0247 11.712,8.0656 11.7071,8.1785Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M12.1642,8.2691L11.4284,8.2691C11.4071,8.2691 11.3891,8.2489 11.3891,8.2244C11.3891,8.1998 11.4065,8.1796 11.4284,8.1796L12.1642,8.1796C12.1855,8.1796 12.2035,8.1998 12.2035,8.2244C12.2035,8.2495 12.186,8.2691 12.1642,8.2691ZM11.4289,8.2015C11.4196,8.2015 11.4115,8.2118 11.4115,8.2244C11.4115,8.2369 11.4196,8.2473 11.4289,8.2473L12.1647,8.2473C12.174,8.2473 12.1822,8.2369 12.1822,8.2244C12.1822,8.2118 12.174,8.2015 12.1647,8.2015L11.4289,8.2015Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.9618,8.2009L11.9618,8.19C11.9602,7.9691 11.7971,7.9369 11.7955,7.9369C11.796,7.9369 11.6335,7.9827 11.6291,8.19L11.6291,8.2004L11.4262,8.2004L11.4611,7.9025L12.1336,7.9042L12.1336,7.914L12.1647,8.1998L11.9618,8.2009ZM11.4502,8.1791L11.6078,8.1791C11.6127,8.0722 11.6591,8.0073 11.6984,7.9713C11.7229,7.9489 11.7485,7.9336 11.7676,7.9249L11.4807,7.9244L11.4502,8.1791ZM11.8293,7.9255C11.8462,7.9325 11.8664,7.9435 11.886,7.9593C11.9285,7.9936 11.9793,8.0596 11.9831,8.1791L12.1402,8.1785L12.1129,7.9255L11.8293,7.9255ZM11.5844,5.7027C11.5844,5.6765 11.5478,5.676 11.5484,5.7027L11.5484,5.754L11.5844,5.754L11.5844,5.7027M11.8151,5.6062C11.8162,5.5789 11.7769,5.5789 11.7775,5.6062L11.7775,5.6727L11.8151,5.6727L11.8151,5.6062M12.0464,5.7027C12.0464,5.6765 12.0098,5.676 12.0104,5.7027L12.0104,5.754L12.0464,5.754L12.0464,5.7027M11.6596,5.658L11.472,5.658C11.4529,5.658 11.4376,5.6433 11.4376,5.6247L11.4376,5.5271L11.5129,5.5271L11.5129,5.5658L11.5293,5.5658L11.5293,5.5276L11.6045,5.5271L11.6045,5.5658L11.6209,5.5658L11.6209,5.5282L11.6869,5.5282L11.6945,5.5331L11.6945,5.6247C11.6951,5.6427 11.6787,5.658 11.6596,5.658ZM11.46,5.5484L11.46,5.6247C11.46,5.6329 11.4665,5.6362 11.4725,5.6362L11.6602,5.6362C11.6673,5.6362 11.6738,5.6307 11.6738,5.6242L11.6738,5.5489L11.6433,5.5489L11.6433,5.5865L11.5833,5.5865L11.5833,5.5478L11.5516,5.5478L11.5516,5.5865L11.4916,5.5865L11.4916,5.5478L11.46,5.5484ZM12.1205,5.658L11.9329,5.658C11.9138,5.658 11.8985,5.6433 11.8985,5.6247L11.8985,5.5271L11.9738,5.5271L11.9738,5.5658L11.9902,5.5658L11.9902,5.5276L12.0655,5.5271L12.0655,5.5658L12.0818,5.5658L12.0818,5.5282L12.1478,5.5282L12.1555,5.5331L12.1555,5.6247C12.1555,5.6427 12.1396,5.658 12.1205,5.658ZM11.9204,5.5484L11.9204,5.6247C11.9204,5.6329 11.9269,5.6362 11.9329,5.6362L12.1205,5.6362C12.1276,5.6362 12.1342,5.6307 12.1342,5.6242L12.1342,5.5489L12.1036,5.5489L12.1036,5.5865L12.0436,5.5865L12.0436,5.5478L12.012,5.5478L12.012,5.5865L11.952,5.5865L11.952,5.5478L11.9204,5.5484Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.6673,5.8085L11.4655,5.8085L11.472,5.6367L11.6613,5.6367L11.6673,5.8085ZM11.4884,5.7867L11.6449,5.7867L11.6405,5.658L11.4933,5.658L11.4884,5.7867ZM12.1282,5.8085L11.9264,5.8085L11.9329,5.6367L12.1222,5.6367L12.1282,5.8085ZM11.9487,5.7867L12.1053,5.7867L12.1009,5.658L11.9536,5.658L11.9487,5.7867ZM11.6918,5.808L11.7049,5.5075L11.8882,5.5069L11.9013,5.8075L11.6918,5.808ZM11.7256,5.5287L11.7147,5.7862L11.8789,5.7856L11.8675,5.5282L11.7256,5.5287Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.8909,5.5211L11.6995,5.5211C11.6798,5.5211 11.6645,5.5069 11.6645,5.4878L11.6645,5.3902L11.7409,5.3902L11.7409,5.4289L11.7584,5.4289L11.7584,5.3907L11.8347,5.3907L11.8347,5.4295L11.8516,5.4295L11.8516,5.3918L11.9193,5.3918L11.9269,5.3967L11.9269,5.4884C11.9269,5.5058 11.9105,5.5211 11.8909,5.5211ZM11.6864,5.412L11.6864,5.4884C11.6864,5.4965 11.6929,5.4998 11.6995,5.4998L11.8909,5.4998C11.898,5.4998 11.9045,5.4938 11.9051,5.4878L11.9051,5.4125L11.8735,5.4125L11.8735,5.4502L11.8129,5.4502L11.8129,5.4115L11.7802,5.4115L11.7802,5.4496L11.7196,5.4496L11.7196,5.4109L11.6864,5.4109L11.6864,5.412ZM12.1489,5.8702L11.4436,5.8702C11.4229,5.8702 11.406,5.8516 11.406,5.8287C11.406,5.8058 11.4229,5.7873 11.4436,5.7873L12.1489,5.7873C12.1696,5.7873 12.1865,5.8058 12.1865,5.8287C12.1865,5.8516 12.1696,5.8702 12.1489,5.8702ZM11.4436,5.8091C11.4349,5.8091 11.4273,5.8184 11.4273,5.8287C11.4273,5.8391 11.4349,5.8484 11.4436,5.8484L12.1489,5.8484C12.1576,5.8484 12.1653,5.8396 12.1653,5.8287C12.1653,5.8178 12.1576,5.8091 12.1489,5.8091L11.4436,5.8091Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M12.1342,5.9313L11.4595,5.9313C11.4393,5.9313 11.4229,5.9127 11.4229,5.8898C11.4229,5.8669 11.4393,5.8484 11.4595,5.8484L12.1342,5.8484C12.1544,5.8484 12.1707,5.8669 12.1707,5.8898C12.1707,5.9127 12.1544,5.9313 12.1342,5.9313ZM11.4595,5.8707C11.4513,5.8707 11.4447,5.8795 11.4447,5.8904C11.4447,5.9013 11.4518,5.91 11.4595,5.91L12.1342,5.91C12.1424,5.91 12.1489,5.9013 12.1489,5.8904C12.1489,5.8795 12.1418,5.8707 12.1342,5.8707L11.4595,5.8707ZM11.9078,6.1975L11.6847,6.1975L11.6847,6.1865C11.6858,6.0415 11.7889,5.9924 11.7982,5.9924C11.8069,5.9913 11.8353,6.0142 11.8358,6.0147C11.8685,6.042 11.9073,6.0944 11.9078,6.1871L11.9078,6.1975ZM11.7071,6.1756L11.886,6.1756C11.8811,6.0644 11.814,6.0229 11.7982,6.0147C11.784,6.0218 11.712,6.0627 11.7071,6.1756Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M12.1642,6.2662L11.4284,6.2662C11.4071,6.2662 11.3891,6.246 11.3891,6.2215C11.3891,6.1969 11.4065,6.1767 11.4284,6.1767L12.1642,6.1767C12.1855,6.1767 12.2035,6.1969 12.2035,6.2215C12.2035,6.2465 12.186,6.2662 12.1642,6.2662ZM11.4289,6.1985C11.4196,6.1985 11.4115,6.2089 11.4115,6.2215C11.4115,6.234 11.4196,6.2444 11.4289,6.2444L12.1647,6.2444C12.174,6.2444 12.1822,6.234 12.1822,6.2215C12.1822,6.2089 12.174,6.1985 12.1647,6.1985L11.4289,6.1985Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M11.9618,6.198L11.9618,6.1871C11.9602,5.9662 11.7971,5.934 11.7955,5.934C11.796,5.934 11.6335,5.9798 11.6291,6.1876L11.6291,6.198L11.4262,6.198L11.4611,5.8996L12.1336,5.9013L12.1336,5.9111L12.1647,6.1969L11.9618,6.198ZM11.4502,6.1762L11.6078,6.1762C11.6127,6.0693 11.6596,6.0044 11.6984,5.9684C11.7229,5.946 11.7485,5.9307 11.7676,5.922L11.4807,5.9215L11.4502,6.1762ZM11.8293,5.9225C11.8462,5.9296 11.8664,5.9405 11.886,5.9564C11.9285,5.9907 11.9793,6.0567 11.9831,6.1762L12.1402,6.1756L12.1129,5.9225L11.8293,5.9225Z" + android:strokeWidth="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.504,7.8131L9.5029,8.2784L9.5029,8.2784L9.5029,8.2784C9.5029,8.3738 9.54,8.4611 9.5989,8.5244C9.6584,8.5876 9.7396,8.6269 9.8291,8.6269C9.9191,8.6269 10.0004,8.5876 10.0593,8.5244C10.1182,8.4611 10.1547,8.3744 10.1547,8.2784L10.1547,7.8125L9.504,7.8131ZM9.6524,8.4082C9.6169,8.4082 9.588,8.3793 9.588,8.3438C9.588,8.3084 9.6169,8.2795 9.6524,8.2795C9.6878,8.2795 9.7167,8.3084 9.7167,8.3438C9.7167,8.3793 9.6878,8.4082 9.6524,8.4082ZM9.6524,8.0542C9.6169,8.0542 9.588,8.0253 9.588,7.9898C9.588,7.9544 9.6169,7.9255 9.6524,7.9255C9.6878,7.9255 9.7167,7.9544 9.7167,7.9898C9.7167,8.0253 9.6878,8.0542 9.6524,8.0542ZM9.8324,8.2271C9.7969,8.2271 9.768,8.1982 9.768,8.1627C9.768,8.1273 9.7969,8.0984 9.8324,8.0984C9.8678,8.0984 9.8967,8.1273 9.8967,8.1627C9.8967,8.1982 9.8678,8.2271 9.8324,8.2271ZM10.0129,8.4076C9.9775,8.4076 9.9485,8.3787 9.9485,8.3433C9.9485,8.3078 9.9775,8.2789 10.0129,8.2789C10.0484,8.2789 10.0773,8.3078 10.0773,8.3433C10.0773,8.3787 10.0484,8.4076 10.0129,8.4076ZM10.0135,8.0547C9.978,8.0547 9.9491,8.0258 9.9491,7.9904C9.9491,7.9549 9.978,7.926 10.0135,7.926C10.0489,7.926 10.0778,7.9549 10.0778,7.9904C10.0778,8.0258 10.0489,8.0547 10.0135,8.0547ZM9.504,6.6878L9.5029,7.1536L9.5029,7.1536L9.5029,7.1536C9.5029,7.2491 9.54,7.3364 9.5989,7.3996C9.6584,7.4629 9.7396,7.5027 9.8291,7.5027C9.9191,7.5027 10.0004,7.4635 10.0593,7.4002C10.1182,7.3369 10.1547,7.2502 10.1547,7.1542L10.1547,6.6884L9.504,6.6878ZM9.6524,7.2829C9.6169,7.2829 9.588,7.254 9.588,7.2185C9.588,7.1831 9.6169,7.1542 9.6524,7.1542C9.6878,7.1542 9.7167,7.1831 9.7167,7.2185C9.7167,7.2545 9.6878,7.2829 9.6524,7.2829ZM9.6524,6.9295C9.6169,6.9295 9.588,6.9005 9.588,6.8651C9.588,6.8296 9.6169,6.8007 9.6524,6.8007C9.6878,6.8007 9.7167,6.8296 9.7167,6.8651C9.7167,6.9005 9.6878,6.9295 9.6524,6.9295ZM9.8324,7.1024C9.7969,7.1024 9.768,7.0735 9.768,7.038C9.768,7.0025 9.7969,6.9736 9.8324,6.9736C9.8678,6.9736 9.8967,7.0025 9.8967,7.038C9.8967,7.0735 9.8678,7.1024 9.8324,7.1024ZM10.0129,7.2824C9.9775,7.2824 9.9485,7.2535 9.9485,7.218C9.9485,7.1825 9.9775,7.1536 10.0129,7.1536C10.0484,7.1536 10.0773,7.1825 10.0773,7.218C10.0773,7.254 10.0484,7.2824 10.0129,7.2824ZM10.0135,6.9295C9.978,6.9295 9.9491,6.9005 9.9491,6.8651C9.9491,6.8296 9.978,6.8007 10.0135,6.8007C10.0489,6.8007 10.0778,6.8296 10.0778,6.8651C10.0778,6.9005 10.0489,6.9295 10.0135,6.9295ZM8.6013,7.8131L8.6002,8.2784L8.6002,8.2784L8.6002,8.2784C8.6002,8.3738 8.6373,8.4611 8.6962,8.5244C8.7556,8.5876 8.8369,8.6269 8.9264,8.6269C9.0158,8.6269 9.0976,8.5876 9.1565,8.5244C9.2155,8.4611 9.252,8.3744 9.252,8.2784L9.252,7.8125L8.6013,7.8131ZM8.7491,8.4082C8.7136,8.4082 8.6847,8.3793 8.6847,8.3438C8.6847,8.3084 8.7136,8.2795 8.7491,8.2795C8.7845,8.2795 8.8135,8.3084 8.8135,8.3438C8.8135,8.3793 8.7851,8.4082 8.7491,8.4082ZM8.7491,8.0542C8.7136,8.0542 8.6847,8.0253 8.6847,7.9898C8.6847,7.9544 8.7136,7.9255 8.7491,7.9255C8.7845,7.9255 8.8135,7.9544 8.8135,7.9898C8.814,8.0253 8.7851,8.0542 8.7491,8.0542ZM8.9296,8.2271C8.8942,8.2271 8.8653,8.1982 8.8653,8.1627C8.8653,8.1273 8.8942,8.0984 8.9296,8.0984C8.9651,8.0984 8.994,8.1273 8.994,8.1627C8.994,8.1982 8.9651,8.2271 8.9296,8.2271ZM9.1102,8.4076C9.0747,8.4076 9.0458,8.3787 9.0458,8.3433C9.0458,8.3078 9.0747,8.2789 9.1102,8.2789C9.1456,8.2789 9.1745,8.3078 9.1745,8.3433C9.1745,8.3787 9.1456,8.4076 9.1102,8.4076ZM9.1102,8.0547C9.0747,8.0547 9.0458,8.0258 9.0458,7.9904C9.0458,7.9549 9.0747,7.926 9.1102,7.926C9.1456,7.926 9.1745,7.9549 9.1745,7.9904C9.1751,8.0258 9.1462,8.0547 9.1102,8.0547ZM10.4045,7.8131L10.4035,8.2784L10.4035,8.2784L10.4035,8.2784C10.4035,8.3738 10.4405,8.4611 10.4995,8.5244C10.5589,8.5876 10.6402,8.6269 10.7296,8.6269C10.8196,8.6269 10.9009,8.5876 10.9598,8.5244C11.0187,8.4611 11.0553,8.3744 11.0553,8.2784L11.0553,7.8125L10.4045,7.8131ZM10.5529,8.4082C10.5175,8.4082 10.4885,8.3793 10.4885,8.3438C10.4885,8.3084 10.5175,8.2795 10.5529,8.2795C10.5884,8.2795 10.6173,8.3084 10.6173,8.3438C10.6173,8.3793 10.5884,8.4082 10.5529,8.4082ZM10.5529,8.0542C10.5175,8.0542 10.4885,8.0253 10.4885,7.9898C10.4885,7.9544 10.5175,7.9255 10.5529,7.9255C10.5884,7.9255 10.6173,7.9544 10.6173,7.9898C10.6173,8.0253 10.5884,8.0542 10.5529,8.0542ZM10.7329,8.2271C10.6975,8.2271 10.6685,8.1982 10.6685,8.1627C10.6685,8.1273 10.6975,8.0984 10.7329,8.0984C10.7684,8.0984 10.7973,8.1273 10.7973,8.1627C10.7973,8.1982 10.7684,8.2271 10.7329,8.2271ZM10.9135,8.4076C10.878,8.4076 10.8491,8.3787 10.8491,8.3433C10.8491,8.3078 10.878,8.2789 10.9135,8.2789C10.9489,8.2789 10.9778,8.3078 10.9778,8.3433C10.9778,8.3787 10.9489,8.4076 10.9135,8.4076ZM10.914,8.0547C10.8785,8.0547 10.8496,8.0258 10.8496,7.9904C10.8496,7.9549 10.8785,7.926 10.914,7.926C10.9495,7.926 10.9784,7.9549 10.9784,7.9904C10.9784,8.0258 10.9495,8.0547 10.914,8.0547ZM9.504,8.928L9.5029,9.3938L9.5029,9.3938L9.5029,9.3938C9.5029,9.4893 9.54,9.5765 9.5989,9.6398C9.6584,9.7031 9.7396,9.7429 9.8291,9.7429C9.9191,9.7429 10.0004,9.7036 10.0593,9.6404C10.1182,9.5771 10.1547,9.4904 10.1547,9.3944L10.1547,8.9285L9.504,8.928ZM9.6524,9.5231C9.6169,9.5231 9.588,9.4942 9.588,9.4587C9.588,9.4233 9.6169,9.3944 9.6524,9.3944C9.6878,9.3944 9.7167,9.4233 9.7167,9.4587C9.7167,9.4942 9.6878,9.5231 9.6524,9.5231ZM9.6524,9.1691C9.6169,9.1691 9.588,9.1402 9.588,9.1047C9.588,9.0693 9.6169,9.0404 9.6524,9.0404C9.6878,9.0404 9.7167,9.0693 9.7167,9.1047C9.7167,9.1402 9.6878,9.1691 9.6524,9.1691ZM9.8324,9.342C9.7969,9.342 9.768,9.3131 9.768,9.2776C9.768,9.2422 9.7969,9.2133 9.8324,9.2133C9.8678,9.2133 9.8967,9.2422 9.8967,9.2776C9.8967,9.3131 9.8678,9.342 9.8324,9.342ZM10.0129,9.5225C9.9775,9.5225 9.9485,9.4936 9.9485,9.4582C9.9485,9.4227 9.9775,9.3938 10.0129,9.3938C10.0484,9.3938 10.0773,9.4227 10.0773,9.4582C10.0773,9.4936 10.0484,9.5225 10.0129,9.5225ZM10.0135,9.1696C9.978,9.1696 9.9491,9.1407 9.9491,9.1053C9.9491,9.0698 9.978,9.0409 10.0135,9.0409C10.0489,9.0409 10.0778,9.0698 10.0778,9.1053C10.0778,9.1407 10.0489,9.1696 10.0135,9.1696Z" + android:strokeWidth="1" + android:fillColor="#003399" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_ro.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_ro.xml new file mode 100644 index 0000000000000000000000000000000000000000..f8feec1e7119fa7fcce5aa81926f798f97cbae4e --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_ro.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M7.6364,0l8.7273,0l0,16l-8.7273,0z" + android:strokeWidth="1" + android:fillColor="#FFCA28" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M16.3636,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#D50000" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M-0,0l7.6364,0l0,16l-7.6364,0z" + android:strokeWidth="1" + android:fillColor="#1A237E" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_se.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_se.xml new file mode 100644 index 0000000000000000000000000000000000000000..0ce3b524fa789a57623a180309a861dba238cc07 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_se.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24,0l0,16l-24,0z" + android:strokeWidth="1" + android:fillColor="#1976D2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,6.5455l24,0l0,3.2727l-24,0z" + android:strokeWidth="1" + android:fillColor="#FFC107" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.6364,0l3.2727,0l0,16l-3.2727,0z" + android:strokeWidth="1" + android:fillColor="#FFC107" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_si.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_si.xml new file mode 100644 index 0000000000000000000000000000000000000000..7f0537242748973398610f1a485c2d86d281f3c8 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_si.xml @@ -0,0 +1,46 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,10.66l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.33l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#1976D2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,-0l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.8182,2.7273L3.8182,3.8182C3.8182,7.6364 6,8.1818 6,8.1818C6,8.1818 8.1818,7.6364 8.1818,3.8182L8.1818,2.7273L3.8182,2.7273Z" + android:strokeWidth="1" + android:fillColor="#1976D2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.1818,2.7273L8.1818,3.8182C8.1818,7.6364 6,8.1818 6,8.1818C6,8.1818 3.8182,7.6364 3.8182,3.8182L3.8182,2.7273L3.2727,2.7273L3.2727,3.8182C3.2727,8.0138 5.7616,8.6847 5.868,8.7115L6,8.7442L6.132,8.7109C6.2384,8.6847 8.7273,8.0138 8.7273,3.8182L8.7273,2.7273L8.1818,2.7273Z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0909,4.9091L6.5455,5.4545L6,4.3636L5.4545,5.4545L4.9091,4.9091L4.056,5.7622C4.62,7.83 6,8.1818 6,8.1818C6,8.1818 7.38,7.83 7.944,5.7622L7.0909,4.9091Z" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_sk.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_sk.xml new file mode 100644 index 0000000000000000000000000000000000000000..901f8f843fc269a67532e10f30ab2d1b35ad848e --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_sk.xml @@ -0,0 +1,48 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <path + android:pathData="M0,10.66l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.33l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#1976D2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,-0l24,0l0,5.33l-24,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.0909,12C5.7753,11.3667 3.8182,10.6702 3.8182,8.1818C3.8182,5.694 3.8182,4.3636 3.8182,4.3636L10.3636,4.3636C10.3636,4.3636 10.3636,5.718 10.3636,8.1818C10.3636,10.6707 8.4065,11.3667 7.0909,12" + android:strokeWidth="1" + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M3.2727,3.8182C3.2727,3.8182 3.2727,5.4693 3.2727,8.1818C3.2727,10.8955 5.5467,11.8549 7.0909,12.5455C8.6356,11.8549 10.9091,10.8955 10.9091,8.1818C10.9091,5.4693 10.9091,3.8182 10.9091,3.8182L3.2727,3.8182ZM10.3636,8.1818C10.3636,10.6707 8.4065,11.3667 7.0909,12C5.7753,11.3667 3.8182,10.6702 3.8182,8.1818C3.8182,5.694 3.8182,4.3636 3.8182,4.3636L10.3636,4.3636C10.3636,4.3636 10.3636,5.718 10.3636,8.1818Z" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M7.4056,7.9025C7.8038,7.9091 8.5811,7.9249 9.2727,7.6931C9.2727,7.6931 9.2547,7.9407 9.2547,8.2282C9.2547,8.5167 9.2727,8.7644 9.2727,8.7644C8.6378,8.5516 7.8545,8.5478 7.4056,8.5527L7.4056,10.0909L6.7767,10.0909L6.7767,8.5538C6.3273,8.5484 5.544,8.5527 4.9091,8.7655C4.9091,8.7655 4.9271,8.5178 4.9271,8.2293C4.9271,7.9418 4.9091,7.6942 4.9091,7.6942C5.6007,7.926 6.3791,7.9102 6.7767,7.9036L6.7767,6.9382C6.4135,6.9349 6.0464,6.8836 5.4545,7.0827C5.4545,7.0827 5.4545,6.8351 5.4545,6.5465C5.4545,6.258 5.4545,6.0115 5.4545,6.0115C6.0453,6.2078 6.4124,6.2935 6.7751,6.2913C6.7565,5.6793 6.5776,4.9091 6.5776,4.9091C6.5776,4.9091 6.9453,4.9369 7.0909,4.9369C7.2365,4.9369 7.6036,4.9091 7.6036,4.9091C7.6036,4.9091 7.4253,5.6793 7.4073,6.2896C7.77,6.2918 8.1371,6.2155 8.7273,6.0191C8.7273,6.0191 8.7093,6.2656 8.7093,6.5542C8.7093,6.8427 8.7273,7.0909 8.7273,7.0909C8.1365,6.8924 7.7684,6.9344 7.4056,6.9376L7.4056,7.9025Z" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.0875,10.1727C8.0875,10.1727 7.74,9.2727 7.0909,9.2727C6.4424,9.2727 6.0944,10.1727 6.0944,10.1727C6.0944,10.1727 5.9013,9.7456 5.3722,9.7456C5.0455,9.7456 4.7029,10.0816 4.5349,10.3511C5.2244,11.2025 6.3164,11.6269 7.0909,12C7.8655,11.6269 8.9264,11.2407 9.6153,10.3893C9.4478,10.1204 9.1369,9.7456 8.8107,9.7456C8.2811,9.7456 8.0875,10.1727 8.0875,10.1727Z" + android:strokeWidth="1" + android:fillColor="#1976D2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_country_uk.xml b/Corona-Warn-App/src/main/res/drawable/ic_country_uk.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e4825fd11130b6b62a66490f52fe4ef01350e74 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_country_uk.xml @@ -0,0 +1,64 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="16"> + <group> + <clip-path + android:pathData="M0,0h24v16h-24z"/> + <path + android:pathData="M0,0l24.1758,0l0,16l-24.1758,0z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,2.4091l11.4341,7.268l1.7192,-2.9257l-10.6214,-6.7514l-2.5319,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M24.1758,0l-1.983,0l-10.6209,6.7509l1.7187,2.9263l10.8852,-6.9194z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M13.2907,5.8691l-1.7187,2.9257l11.3352,7.2051l1.2687,0l0,-3.212z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,13.1377l0,2.8623l1.8187,0l11.3346,-7.2046l-1.7187,-2.9263z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M0,5.7143l24.1758,0l0,4.5714l-24.1758,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M9.8901,0l4.3956,0l0,16l-4.3956,0z" + android:strokeWidth="1" + android:fillColor="#EDF0F2" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M8.3615,5.7143L0,0.3994L0,1.7389L6.2538,5.7143L8.3615,5.7143ZM23.2467,0L14.2566,5.7143L16.3637,5.7143L24.1758,0.7491L24.1758,0L23.2467,0ZM17.078,10.2857L24.1758,14.7971L24.1758,13.4577L19.1852,10.2857L17.078,10.2857ZM7.6473,10.2857L0,15.1463L0,16L0.7648,16L9.7544,10.2857L7.6473,10.2857ZM0,6.8571L24.1758,6.8571L24.1758,9.1429L0,9.1429L0,6.8571Z" + android:strokeWidth="1" + android:fillColor="#E53935" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M10.989,0l2.1978,0l0,16l-2.1978,0z" + android:strokeWidth="1" + android:fillColor="#E53935" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_illustration_interoperability.xml b/Corona-Warn-App/src/main/res/drawable/ic_illustration_interoperability.xml new file mode 100644 index 0000000000000000000000000000000000000000..9000e1ab170b30f045442c7ac041f45085ccc2e8 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_illustration_interoperability.xml @@ -0,0 +1,134 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="360dp" + android:height="220dp" + android:viewportWidth="360" + android:viewportHeight="220"> + <group> + <clip-path + android:pathData="M0,0h360v220h-360z"/> + <path + android:pathData="M253.634,-1.772L246.507,0.715L248.993,9.699L244.965,8.771L240.009,17.142L237.207,13.429L232.251,22.711L232.881,27.667L228.853,30.469L227.295,26.126L224.195,22.413L220.167,23.026L222.636,31.082L225.754,32.01L226.367,36.669L222.339,34.497L218.311,42.553L222.339,48.438L212.724,45.968L212.111,48.438L217.067,51.853L214.598,53.394L209.624,51.853L206.524,47.194L204.353,43.166L198.784,42.553L197.855,39.138L210.255,41.012L217.067,36.966L215.526,31.397L203.74,27.054L189.799,26.441L187.926,21.783L179.887,19.926L163.775,32.01L147.961,58.665L129.677,70.434L127.803,87.807L130.605,93.061L136.192,92.448L142.076,89.348L145.789,83.148L149.204,107.947L153.53,109.803L156.017,105.145L161.288,104.532L163.145,91.204L168.416,83.464L163.46,78.805L163.46,70.136L169.957,63.008L173.372,49.681L178.941,48.14L182.356,53.394L174.3,64.549L173.985,76.949L182.672,81.59L197.855,74.777L200.342,80.679L185.141,85.635L185.456,96.791L179.257,93.989L178.328,107.316L169.957,114.129L154.773,119.103L143.32,116.616L141.446,98.647L135.246,100.188L134.318,119.103L131.849,116.931L121.936,120.031L116.963,129.015L108.294,130.258L102.392,137.684L94.353,134.584L80.098,139.54L88.452,147.614L92.182,153.183L91.551,159.085L84.424,165.897L67.068,164.969L61.814,161.239L57.471,160.626L54.686,160.941L56.228,163.41L55.299,167.438L50.641,179.225L47.559,181.379L46.613,185.109L49.1,186.65L46,194.409L50.028,197.193L53.741,195.652L57.769,199.049L55.912,202.465L59.012,204.934L64.897,201.834L76.07,203.393L88.767,196.265L86.91,190.381L95.895,184.181L105.509,180.468L105.509,175.197L109.222,172.395L119.765,176.423L129.362,168.997L134.318,169.61L141.148,182.64L155.386,192.85L160.658,196.58L159.117,205.564L161.288,206.493L166.244,199.365L163.775,196.878L165.631,192.85L172.129,195.021L170.272,190.065L160.658,186.965L161.603,184.496L156.945,183.55L152.602,180.153L149.204,173.025L145.789,170.854L143.618,164.969L151.061,162.798L176.157,183.253L176.472,192.237L193.827,212.062L201.27,202.78L190.097,190.065L196.612,191.309L195.369,188.209L201.883,185.722L207.768,189.137L217.995,182.64L210.868,173.34L215.824,152.57L222.023,148.542L224.808,151.642L237.207,147.614L249.309,139.243L246.191,152.885L288.03,173.025L294.545,172.71L298.888,167.438L301.357,171.782L306.629,169.925L305.403,157.211L290.517,150.714L289.886,146.37L287.417,143.883L283.704,143.586L284.632,135.53L288.66,130.258L283.704,124.374L277.505,124.672L274.405,113.218L284.93,98.647L297.014,97.404L314.387,89.348L315,81.905L302.916,81.59L297.329,70.434L291.76,74.777L293.617,67.649L287.102,67.649L284.632,64.252L284.632,54.952L262.619,23.341L265.736,5.355L253.634,-1.772ZM74.038,25.548L68.171,28.105L71.481,30.206L69.975,33.219L65.457,38.49L72.83,45.408L81.096,44.952L88.171,42.693L88.924,39.243L87.121,32.921L81.096,34.129L80.501,31.555L73.741,32.623L74.932,27.492L74.038,25.548ZM97.05,84.076L91.184,89.786L91.937,98.21L94.336,98.525L90.431,103.183L90.728,105.285L96.157,104.689L95.247,108.595L95.842,114.304L92.69,112.658L87.874,115.652L91.184,116.721L88.767,119.278L85.317,118.822L84.861,121.082L92.094,124.391L90.273,125.145L86.823,124.234L81.096,127.701L82.147,129.505L86.21,128.454L87.716,129.961L90.431,127.544L94.494,129.208L101.569,129.208L104.126,129.961L108.189,127.999L104.721,125.74L110.448,122.132L110.133,119.278L104.879,118.367L106.683,116.406L105.176,108.297L102.917,107.089L103.215,102.43L100.501,99.12L99.747,97.019L103.81,94.602L105.176,90.837L100.22,90.399L97.646,91.134L97.804,89.33L103.057,86.178L102.164,84.672L97.05,84.076ZM83.058,98.963L77.646,100.924L79.292,102.728L77.191,104.532L73.741,102.273L71.026,106.791L73.741,109.19L67.716,112.815L68.014,116.265L70.273,117.474L79.292,116.406L82.147,115.968L84.108,111.747L85.159,108.139L88.171,105.74L87.121,101.222L83.058,98.963ZM132.724,178.682L129.012,180.118L129.152,183.761L131.078,185.967L132.287,183.113L132.497,182.044L133.075,180.836L132.724,178.682ZM131.411,187.123L125.089,189.4L127.348,199.768L132.707,198.944L133.022,190.853L131.411,187.123ZM145.737,203.778L144.196,206.457L155.281,212.972L157.558,211.344L157.103,207.911L158.276,205.564L158.241,203.971L152.006,205.477L145.737,203.778Z" + android:strokeWidth="1" + android:fillColor="#DBE1E5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> + <group> + <clip-path + android:pathData="M0,0h360v220h-360z"/> + <path + android:pathData="M16,8l80,0l0,54.545l-80,0z" + android:strokeWidth="1" + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + <path + android:pathData="M56,13.455L56.995,15.484L59.216,15.807L57.609,17.385L57.989,19.616L56,18.564L54.013,19.616L54.393,17.385L52.785,15.807L55.007,15.484L56,13.455ZM46.447,16.331L47.442,18.36L49.664,18.685L48.056,20.264L48.436,22.495L46.449,21.442L44.462,22.495L44.84,20.264L43.233,18.685L45.456,18.36L46.447,16.331ZM39.66,22.635L40.655,24.664L42.878,24.987L41.271,26.565L41.649,28.796L39.662,27.744L37.675,28.796L38.055,26.565L36.447,24.987L38.669,24.664L39.66,22.635ZM65.553,16.331L64.558,18.36L62.336,18.685L63.944,20.264L63.564,22.495L65.551,21.442L67.538,22.495L67.16,20.264L68.767,18.685L66.544,18.36L65.553,16.331ZM46.447,46.991L47.442,49.02L49.664,49.345L48.056,50.924L48.436,53.155L46.449,52.102L44.462,53.155L44.84,50.924L43.233,49.345L45.456,49.02L46.447,46.991ZM65.553,46.991L64.558,49.02L62.336,49.345L63.944,50.924L63.564,53.155L65.551,52.102L67.538,53.155L67.16,50.924L68.767,49.345L66.544,49.02L65.553,46.991ZM72.34,22.635L71.345,24.664L69.122,24.987L70.729,26.565L70.351,28.796L72.338,27.744L74.325,28.796L73.945,26.565L75.553,24.987L73.331,24.664L72.34,22.635ZM39.66,40.596L40.655,42.625L42.878,42.951L41.271,44.529L41.649,46.76L39.662,45.707L37.675,46.76L38.055,44.529L36.447,42.951L38.669,42.625L39.66,40.596ZM72.34,40.596L71.345,42.625L69.122,42.951L70.729,44.529L70.351,46.76L72.338,45.707L74.325,46.76L73.945,44.529L75.553,42.951L73.331,42.625L72.34,40.596ZM74.602,32.191L75.596,34.22L77.818,34.545L76.211,36.124L76.591,38.355L74.604,37.302L72.616,38.355L72.996,36.124L71.384,34.545L73.607,34.22L74.602,32.191ZM37.398,32.191L38.393,34.22L40.616,34.545L39.007,36.124L39.387,38.355L37.4,37.302L35.413,38.355L35.793,36.124L34.182,34.545L36.404,34.22L37.398,32.191ZM56,50.927L56.995,52.956L59.216,53.282L57.609,54.86L57.987,57.091L56,56.038L54.013,57.091L54.393,54.86L52.785,53.282L55.007,52.956L56,50.927Z" + android:strokeWidth="1" + android:fillColor="#FFEB3B" + android:fillType="nonZero" + android:strokeColor="#00000000"/> + </group> + <group> + <clip-path + android:pathData="M0,0h360v220h-360z"/> + <path + android:pathData="M212.567,107.982C212.172,114.249 206.767,118.941 200.593,118.569C194.418,118.198 189.645,112.894 190.041,106.626C190.436,100.359 195.841,95.668 202.016,96.039C208.19,96.41 212.963,101.715 212.567,107.982Z" + android:strokeWidth="5.643" + android:fillColor="#00000000" + android:strokeColor="#C2D6E1" + android:fillType="evenOdd"/> + <path + android:pathData="M263.252,112.042C261.097,146.822 231.577,173.236 197.407,171.142C163.235,169.047 137.2,139.226 139.356,104.446C141.511,69.667 171.031,43.253 205.201,45.347C239.372,47.442 265.408,77.263 263.252,112.042Z" + android:strokeAlpha="0.35999998" + android:strokeWidth="5.643" + android:fillColor="#00000000" + android:strokeColor="#C2D6E1" + android:fillType="evenOdd" + android:fillAlpha="0.35999998"/> + <path + android:pathData="M280.147,112.065C277.405,155.67 239.833,188.786 196.344,186.16C152.853,183.534 119.717,146.146 122.461,102.542C125.203,58.938 162.775,25.822 206.264,28.448C249.754,31.074 282.891,68.462 280.147,112.065Z" + android:strokeAlpha="0.14" + android:strokeWidth="5.643" + android:fillColor="#00000000" + android:strokeColor="#C2D6E1" + android:fillType="evenOdd" + android:fillAlpha="0.14"/> + <path + android:pathData="M296.416,113.048C293.108,165.651 247.783,205.6 195.32,202.432C142.855,199.263 102.882,154.162 106.192,101.559C109.5,48.957 154.825,9.008 207.288,12.176C259.751,15.345 299.726,60.446 296.416,113.048Z" + android:strokeAlpha="0.04" + android:strokeWidth="5.643" + android:fillColor="#00000000" + android:strokeColor="#C2D6E1" + android:fillType="evenOdd" + android:fillAlpha="0.04"/> + <path + android:pathData="M246.357,111.022C244.788,136.471 223.307,155.775 198.468,154.244C173.63,152.713 154.682,130.917 156.251,105.468C157.82,80.018 179.302,60.714 204.14,62.245C228.978,63.777 247.926,85.573 246.357,111.022Z" + android:strokeAlpha="0.5" + android:strokeWidth="5.643" + android:fillColor="#00000000" + android:strokeColor="#C2D6E1" + android:fillType="evenOdd" + android:fillAlpha="0.5"/> + <path + android:pathData="M229.274,108.903C228.294,124.45 214.896,136.211 199.443,135.278C183.988,134.346 172.166,121.063 173.146,105.516C174.125,89.969 187.523,78.208 202.977,79.141C218.431,80.073 230.252,93.356 229.274,108.903Z" + android:strokeWidth="5.643" + android:fillColor="#00000000" + android:strokeColor="#C2D6E1" + android:fillType="evenOdd"/> + </group> + <group> + <clip-path + android:pathData="M0,0h360v220h-360z"/> + <path + android:pathData="M187.66,203.46C186.84,194.26 186.26,185.05 185.15,175.86C182.83,156.73 179.65,137.72 176.86,118.65C167.15,117.4 160.39,116.57 160.39,116.57C160.39,116.57 142.52,113.72 142.27,121.91C142.02,130.1 162.17,134.25 162.17,134.25L163.8,134.25L165.24,146.16C165.24,146.16 149.51,165.16 150.64,171.5C151.77,177.84 161.64,175.08 161.64,175.08C161.64,175.08 155.84,192.37 160.29,196.93C163.55,200.28 166.84,198.81 166.84,198.81C166.84,198.81 158.59,206.29 162.31,212.95C163.94,215.88 173.55,216.73 173.55,216.73L189.08,216.24C188.055,212.06 187.585,207.763 187.68,203.46" + android:strokeWidth="1" + android:fillColor="#F7B994" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M193,251.3C187.134,252.12 181.711,248.035 180.88,242.17L160.68,98.44C159.86,92.574 163.945,87.151 169.81,86.32L227.42,78.23C233.288,77.405 238.714,81.492 239.54,87.36L259.74,231.08C260.559,236.95 256.469,242.374 250.6,243.2L193,251.3Z" + android:strokeWidth="1" + android:fillColor="#F8F8F8" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M251,243.15L193.39,251.25C187.522,252.069 182.101,247.978 181.28,242.11L161.08,98.39C160.681,95.572 161.419,92.71 163.132,90.437C164.844,88.163 167.391,86.664 170.21,86.27L227.81,78.17C233.676,77.35 239.099,81.435 239.93,87.3L260.12,231C260.525,233.821 259.791,236.688 258.08,238.967C256.37,241.246 253.822,242.751 251,243.15Z" + android:strokeWidth="4.03" + android:fillColor="#00000000" + android:strokeColor="#4A4A4A" + android:fillType="evenOdd"/> + <path + android:pathData="M304.33,189.85C304.33,189.85 296.68,187.85 288.87,176.19C281.06,164.53 273.87,136.56 268.72,133.57C268.72,133.57 266.83,109.14 254.29,107.3C254.29,107.3 250.29,89.61 248.99,89.57C247.69,89.53 240.85,89.36 238.79,97.99C236.73,106.62 239.39,122.47 247.58,127.07C247.58,127.07 261.93,228.29 261.95,228.59C262.35,236.74 261.54,236.32 260.44,239.1C270.2,241.56 322.22,257.25 365,270.25L365,203.48L304.33,189.85Z" + android:strokeWidth="1" + android:fillColor="#F7B994" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + </group> + <group> + <clip-path + android:pathData="M0,0h360v220h-360z"/> + <path + android:pathData="M209.945,163.41m-12.581,1.768a12.705,12.705 127,1 1,25.163 -3.536a12.705,12.705 127,1 1,-25.163 3.536" + android:strokeWidth="3.388" + android:fillColor="#00000000" + android:strokeColor="#007FAD" + android:fillType="evenOdd"/> + <group> + <clip-path + android:pathData="M178.376,139.621l31.569,23.789l23.789,-31.569l7.78,55.358l-31.569,-23.789l-23.789,31.569z"/> + <path + android:pathData="M209.945,163.41m-19.291,2.711a19.481,19.481 127,1 1,38.583 -5.422a19.481,19.481 127,1 1,-38.583 5.422" + android:strokeWidth="3.388" + android:fillColor="#00000000" + android:strokeColor="#C2D6E1" + android:fillType="evenOdd"/> + <path + android:pathData="M209.945,163.41m-26.001,3.654a26.257,26.257 127,1 1,52.003 -7.309a26.257,26.257 127,1 1,-52.003 7.309" + android:strokeWidth="3.388" + android:fillColor="#00000000" + android:strokeColor="#E9F0F4" + android:fillType="evenOdd"/> + </group> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_interop_no_network.xml b/Corona-Warn-App/src/main/res/drawable/ic_interop_no_network.xml new file mode 100644 index 0000000000000000000000000000000000000000..85e7eb1cc86ecf5bdcf84712f374eefbd83898f7 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_interop_no_network.xml @@ -0,0 +1,18 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <path + android:pathData="M20,0L20,0A20,20 0,0 1,40 20L40,20A20,20 0,0 1,20 40L20,40A20,20 0,0 1,0 20L0,20A20,20 0,0 1,20 0z" + android:strokeWidth="1" + android:fillColor="#2296F3" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M20.001,12.5C15.859,12.5 12.1086,14.1786 9.3936,16.8926L11.3369,18.8359C13.6399,16.7699 16.671,15.5 20.001,15.5C23.331,15.5 26.363,16.7689 28.665,18.8359L30.6064,16.8945C27.8924,14.1795 24.143,12.5 20.001,12.5ZM20.001,17.5C17.222,17.5 14.688,18.543 12.749,20.248L14.8701,22.3691C16.2611,21.2041 18.05,20.5 20.001,20.5C21.952,20.5 23.7418,21.2031 25.1318,22.3691L27.251,20.25C25.313,18.544 22.78,17.5 20.001,17.5ZM20.001,22.5C18.601,22.5 17.3159,22.987 16.2939,23.793L20.001,27.5L23.708,23.793C22.686,22.987 21.401,22.5 20.001,22.5Z" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:strokeColor="#00000000"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_austria.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_austria.xml new file mode 100644 index 0000000000000000000000000000000000000000..c482c612083bdd250fca67780986c4f2484fb41b --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_austria.xml @@ -0,0 +1,21 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:pathData="M0,4l24,0l0,16.3636l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#ECEFF1" + android:fillType="nonZero" + android:pathData="M0,9.4545l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_czech.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_czech.xml new file mode 100644 index 0000000000000000000000000000000000000000..217ac4302e07ee2c5cee4045f6cdc41392c72ea1 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_czech.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:pathData="M0,12.1818l24,0l0,8.1818l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#D7DFE2" + android:fillType="nonZero" + android:pathData="M0,4l24,0l0,8.1818l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:pathData="M0,4l0,16.3636l12.5455,-8.1807z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_denmark.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_denmark.xml new file mode 100644 index 0000000000000000000000000000000000000000..e5ef321061e8849f24d77660e1761735bd8f99d6 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_denmark.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:pathData="M0,4l24,0l0,16.3636l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#ECEFF1" + android:fillType="nonZero" + android:pathData="M0,10.5455l24,0l0,3.2727l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#ECEFF1" + android:fillType="nonZero" + android:pathData="M7.6364,4l3.2727,0l0,16.3636l-3.2727,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_estonia.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_estonia.xml new file mode 100644 index 0000000000000000000000000000000000000000..8a2e44085873bbac059522f6bb995f91e199fa81 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_estonia.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#E0E1E2" + android:fillType="nonZero" + android:pathData="M0,14.9091l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#424242" + android:fillType="nonZero" + android:pathData="M0,9.4545l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#2196F3" + android:fillType="nonZero" + android:pathData="M0,4l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_ireland.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_ireland.xml new file mode 100644 index 0000000000000000000000000000000000000000..be665a5c47b4d34e9feab27c485f6d15ae2ee419 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_ireland.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#ECEFF1" + android:fillType="nonZero" + android:pathData="M7.6364,4l8.7273,0l0,16.3636l-8.7273,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FF9800" + android:fillType="nonZero" + android:pathData="M16.3636,4l7.6364,0l0,16.3636l-7.6364,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#689F38" + android:fillType="nonZero" + android:pathData="M0,4l7.6364,0l0,16.3636l-7.6364,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_italy.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_italy.xml new file mode 100644 index 0000000000000000000000000000000000000000..1796ae7b2bd69509438fcc68219bcb1c21b6563e --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_italy.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#ECEFF1" + android:fillType="nonZero" + android:pathData="M7.6364,4l8.7273,0l0,16.3636l-8.7273,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:pathData="M16.3636,4l7.6364,0l0,16.3636l-7.6364,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#689F38" + android:fillType="nonZero" + android:pathData="M0,4l7.6364,0l0,16.3636l-7.6364,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_latvia.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_latvia.xml new file mode 100644 index 0000000000000000000000000000000000000000..8ababc21154290e55af96cc63b05ee649b645b41 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_latvia.xml @@ -0,0 +1,21 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#B71C1C" + android:fillType="nonZero" + android:pathData="M0,4l24,0l0,16.3636l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#ECEFF1" + android:fillType="nonZero" + android:pathData="M0,10l24,0l0,4.3636l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_netherlands.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_netherlands.xml new file mode 100644 index 0000000000000000000000000000000000000000..51d206f57adce6e8c8f334cced0fa5ebb7402d70 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_netherlands.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#3F51B5" + android:fillType="nonZero" + android:pathData="M0,14.9091l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#ECEFF1" + android:fillType="nonZero" + android:pathData="M0,9.4545l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FF3D00" + android:fillType="nonZero" + android:pathData="M0,4l24,0l0,5.4545l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_poland.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_poland.xml new file mode 100644 index 0000000000000000000000000000000000000000..6815a430b6d75c3e0f5ff365a0b732e99c4b2077 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_poland.xml @@ -0,0 +1,21 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#F44336" + android:fillType="nonZero" + android:pathData="M0,12.1818l24,0l0,8.1818l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#ECEFF1" + android:fillType="nonZero" + android:pathData="M0,4l24,0l0,8.1818l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_spain.xml b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_spain.xml new file mode 100644 index 0000000000000000000000000000000000000000..b6fc02d1bf3f785294b7c816a72ea723f8355a8d --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_submission_country_flag_spain.xml @@ -0,0 +1,3411 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24h-24z" /> + <path + android:fillColor="#DD2C00" + android:fillType="nonZero" + android:pathData="M0,4l24,0l0,16.3636l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFC107" + android:fillType="nonZero" + android:pathData="M0,8.3636l24,0l0,7.6364l-24,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M4.2436,11.2207C4.2436,11.2207 4.2256,11.2207 4.2164,11.2158C4.2065,11.2098 4.1782,11.1815 4.1782,11.1815L4.1536,11.1656L4.1324,11.1367C4.1324,11.1367 4.1078,11.0964 4.1182,11.0631C4.1296,11.0331 4.1487,11.0216 4.1678,11.0118C4.1842,11.0009 4.2224,10.9905 4.2224,10.9905C4.2224,10.9905 4.2507,10.978 4.2605,10.9747C4.2698,10.9747 4.3053,10.9649 4.3053,10.9649C4.3053,10.9649 4.3151,10.96 4.3244,10.9573C4.3347,10.9518 4.3484,10.9518 4.3565,10.9485C4.3642,10.9485 4.3844,10.9431 4.3953,10.942C4.4144,10.9409 4.4427,10.9442 4.4525,10.9442C4.4618,10.9442 4.4956,10.9469 4.5098,10.9469C4.5224,10.9469 4.5709,10.9442 4.5856,10.9442C4.5993,10.9442 4.6085,10.9409 4.6249,10.9442C4.6407,10.9442 4.6669,10.954 4.6762,10.9567C4.6827,10.9611 4.7302,10.9769 4.7476,10.9824C4.7656,10.9867 4.8082,10.9949 4.8278,11.0058C4.8475,11.0135 4.8589,11.0304 4.8687,11.044C4.8791,11.0565 4.8807,11.0718 4.884,11.0789C4.8878,11.0887 4.8884,11.11 4.884,11.1171C4.8802,11.1269 4.8676,11.1471 4.8676,11.1471L4.8447,11.1804L4.8175,11.2027C4.8175,11.2027 4.7973,11.2218 4.7825,11.2196C4.7667,11.2164 4.6085,11.1896 4.506,11.1896C4.4051,11.1913 4.2431,11.2207 4.2436,11.2207" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.9723,11.4685C4.9723,11.4685 4.9709,11.4685 4.9688,11.4685C4.9654,11.4685 4.9563,11.4665 4.9403,11.4605C4.8747,11.4445 4.7227,11.4115 4.6168,11.4115C4.4941,11.4115 4.2947,11.4645 4.2821,11.4685C4.2821,11.4685 4.2814,11.4685 4.2807,11.4685L4.2807,11.4685C4.28,11.4685 4.2793,11.4685 4.2793,11.4685C4.2723,11.4685 4.2542,11.4685 4.2424,11.4525C4.2298,11.4445 4.1929,11.3975 4.1929,11.3955L4.1622,11.3615C4.1615,11.3615 4.1608,11.3595 4.1601,11.3595L4.1336,11.3075C4.1315,11.3045 4.0987,11.2305 4.1148,11.1685C4.1308,11.1085 4.1559,11.0875 4.1803,11.0695C4.2033,11.0505 4.2493,11.0305 4.2514,11.0305C4.2528,11.0285 4.2898,11.0055 4.303,11.0025C4.3135,10.9995 4.3518,10.9835 4.3588,10.9815C4.3609,10.9805 4.372,10.9735 4.3839,10.9635C4.393,10.9595 4.4013,10.9595 4.4104,10.9575C4.4167,10.9565 4.4215,10.9565 4.425,10.9545C4.4264,10.9515 4.4299,10.9515 4.4341,10.9515C4.4459,10.9455 4.4634,10.9355 4.4752,10.9355C4.4913,10.9355 4.5115,10.9355 4.5268,10.9395C4.5359,10.9415 4.5442,10.9435 4.5484,10.9435C4.554,10.9435 4.5659,10.9445 4.5798,10.9455C4.5944,10.9475 4.6112,10.9495 4.6223,10.9495C4.6307,10.9495 4.6509,10.9455 4.6697,10.9435C4.6907,10.9395 4.7095,10.9375 4.7192,10.9375C4.7241,10.9375 4.7297,10.9375 4.7353,10.9355C4.7464,10.9355 4.7569,10.9355 4.7694,10.9375C4.7897,10.9435 4.8266,10.9585 4.8357,10.9685C4.8468,10.9745 4.9047,11.0035 4.9284,11.0155C4.9361,11.0215 4.9472,11.0215 4.9605,11.0275C4.9856,11.0335 5.0149,11.0455 5.0309,11.0525C5.0588,11.0735 5.0748,11.1035 5.086,11.1265C5.0964,11.1465 5.0999,11.1645 5.1027,11.1815C5.1041,11.1855 5.1041,11.1915 5.1062,11.1935C5.1118,11.2145 5.1118,11.2565 5.1062,11.2735C5.0999,11.2875 5.0825,11.3265 5.0825,11.3265L5.0539,11.3905C5.0539,11.3925 5.0539,11.3945 5.0539,11.3945L5.0176,11.4315C5.0169,11.4355 4.9946,11.4685 4.9723,11.4685L4.9723,11.4685ZM4.6168,11.3985C4.7227,11.3985 4.8775,11.4295 4.943,11.4455C4.957,11.4485 4.9674,11.4515 4.9709,11.4515C4.9723,11.4515 4.9723,11.4515 4.9723,11.4515C4.987,11.4515 5.0051,11.4305 5.0107,11.4225L5.0455,11.3835L5.0727,11.3195C5.0734,11.3195 5.0902,11.2855 5.095,11.2665C5.0985,11.2565 5.0985,11.2195 5.095,11.2055C5.0936,11.1975 5.0915,11.1935 5.0909,11.1875C5.0874,11.1715 5.0832,11.1545 5.0755,11.1405C5.0637,11.1175 5.0504,11.0915 5.026,11.0735C5.01,11.0625 4.9814,11.0525 4.957,11.0475C4.9444,11.0415 4.9326,11.0355 4.9242,11.0315C4.9033,11.0235 4.8426,10.9925 4.8301,10.9845C4.8217,10.9765 4.7862,10.9615 4.768,10.9595C4.7562,10.9565 4.7457,10.9585 4.7353,10.9585C4.7297,10.9585 4.7234,10.9595 4.7185,10.9595C4.7095,10.9595 4.6893,10.9615 4.6697,10.9615C4.6495,10.9615 4.63,10.9635 4.6216,10.9635C4.6105,10.9635 4.5938,10.9615 4.5784,10.9615C4.5652,10.9615 4.5533,10.9615 4.5477,10.9615C4.5436,10.9615 4.5352,10.9615 4.524,10.9595C4.5094,10.9585 4.4906,10.9535 4.4745,10.9565C4.4655,10.9565 4.448,10.9615 4.4369,10.9675C4.4334,10.9705 4.4285,10.9715 4.4257,10.9735C4.4215,10.9755 4.4167,10.9775 4.4118,10.9775C4.4034,10.9775 4.3937,10.9775 4.3874,10.9835C4.3755,10.9875 4.363,11.0015 4.363,11.0015C4.363,11.0015 4.3623,11.0015 4.3616,11.0015C4.3595,11.0015 4.3156,11.0175 4.303,11.0225C4.294,11.0245 4.2654,11.0405 4.2542,11.0475C4.2535,11.0475 4.2082,11.0685 4.1845,11.0825C4.1594,11.1025 4.1385,11.1225 4.1259,11.1725C4.1113,11.2275 4.142,11.2995 4.142,11.2995L4.1685,11.3525L4.1977,11.3815C4.2082,11.3995 4.2368,11.4325 4.2472,11.4455C4.2563,11.4505 4.2709,11.4515 4.2786,11.4515C4.287,11.4495 4.4892,11.3985 4.6168,11.3985Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.4613,10.9949C4.4613,10.9464 4.482,10.9065 4.5087,10.9065C4.5355,10.9065 4.5562,10.9464 4.5562,10.9949C4.5562,11.0407 4.5355,11.08 4.5087,11.08C4.482,11.08 4.4613,11.0407 4.4613,10.9949" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.5528,11.2373C4.4978,11.2373 4.4558,11.1653 4.4558,11.0713C4.4558,10.9793 4.4978,10.9033 4.5528,10.9033C4.6078,10.9033 4.6488,10.9793 4.6488,11.0713C4.6488,11.1653 4.6078,11.2373 4.5528,11.2373ZM4.5528,10.9173C4.5088,10.9173 4.4728,10.9873 4.4728,11.0713C4.4728,11.1513 4.5078,11.2193 4.5528,11.2193C4.5958,11.2193 4.6308,11.1513 4.6308,11.0713C4.6308,10.9873 4.5958,10.9173 4.5528,10.9173Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.4875,10.9949C4.4875,10.9491 4.4973,10.9142 4.5104,10.9142C4.5224,10.9142 4.5322,10.9491 4.5322,10.9949C4.5322,11.0375 4.5224,11.0729 4.5104,11.0729C4.4973,11.0729 4.4875,11.0375 4.4875,10.9949" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.5326,11.2164C4.4996,11.2164 4.4836,11.1414 4.4836,11.0664C4.4836,10.9864 4.4996,10.9104 4.5326,10.9104C4.5646,10.9104 4.5796,10.9904 4.5796,11.0664C4.5786,11.1404 4.5616,11.2164 4.5326,11.2164ZM4.5326,10.9274C4.5206,10.9274 4.4986,10.9744 4.4986,11.0664C4.4986,11.1524 4.5206,11.2024 4.5326,11.2024C4.5426,11.2024 4.5626,11.1524 4.5626,11.0664C4.5616,10.9734 4.5426,10.9274 4.5326,10.9274Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.4782,10.9033C4.4782,10.8853 4.4907,10.8722 4.5104,10.8722C4.5267,10.8722 4.5425,10.8847 4.5425,10.9033C4.5425,10.9191 4.5267,10.9322 4.5104,10.9322C4.4907,10.9322 4.4782,10.9196 4.4782,10.9033" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.5322,10.894l0,0.0169l-0.0502,0l0,-0.0169l0.0164,0l0,-0.0469l-0.0213,0l0,-0.0191l0.0213,0l0,-0.0207l0.0213,0l0,0.0202l0.0218,0l0,0.0191l-0.0218,0l0,0.0469l0.0125,0" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.5911,11.0149L4.4821,11.0149L4.4821,10.9539L4.5121,10.9539L4.5121,10.8929L4.4711,10.8929L4.4711,10.8359L4.5121,10.8359L4.5121,10.8029L4.5691,10.8029L4.5691,10.8359L4.6071,10.8359L4.6071,10.8929L4.5691,10.8929L4.5691,10.9539L4.5901,10.9539L4.5901,11.0149L4.5911,11.0149ZM4.5011,10.9929L4.5711,10.9929L4.5711,10.9749L4.5501,10.9749L4.5501,10.8749L4.5901,10.8749L4.5901,10.8559L4.5501,10.8559L4.5501,10.8179L4.5311,10.8179L4.5311,10.8559L4.4911,10.8559L4.4911,10.8749L4.5311,10.8749L4.5311,10.9749L4.5011,10.9749L4.5011,10.9929Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.554,10.894l0,0.0169l-0.0884,0l0,-0.0169l0.0327,0l0,-0.0469l-0.0213,0l0,-0.0191l0.0213,0l0,-0.0207l0.0213,0l0,0.0202l0.0218,0l0,0.0191l-0.0218,0l0,0.0469l0.0344,0" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.6393,11.0149L4.4613,11.0149L4.4613,10.9539L4.5213,10.9539L4.5213,10.8929L4.4803,10.8929L4.4803,10.8359L4.5213,10.8359L4.5213,10.8029L4.5783,10.8029L4.5783,10.8359L4.6163,10.8359L4.6163,10.8929L4.5783,10.8929L4.5783,10.9539L4.6403,10.9539L4.6403,11.0149L4.6393,11.0149ZM4.4803,10.9929L4.6213,10.9929L4.6213,10.9749L4.5583,10.9749L4.5583,10.8749L4.5983,10.8749L4.5983,10.8559L4.5583,10.8559L4.5583,10.8179L4.5393,10.8179L4.5393,10.8559L4.4993,10.8559L4.4993,10.8749L4.5393,10.8749L4.5393,10.9749L4.4803,10.9749L4.4803,10.9929Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.5104,10.9365C4.4891,10.9365 4.4727,10.9224 4.4727,10.9033C4.4727,10.8853 4.4847,10.8722 4.5005,10.8684L4.5022,10.8793C4.4913,10.8815 4.4815,10.8918 4.4815,10.9038C4.4815,10.9185 4.494,10.9295 4.5104,10.9295C4.5245,10.9295 4.5365,10.9185 4.5365,10.9038C4.5365,10.8929 4.5295,10.8815 4.5169,10.8793L4.5196,10.87C4.536,10.8727 4.5453,10.8864 4.5453,10.9038C4.5453,10.9218 4.5295,10.9365 4.5104,10.9365Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.5104,11.2158L4.344,11.2158L4.3396,11.1749L4.3309,11.1324L4.3227,11.0778C4.2764,11.0195 4.2349,10.9785 4.2207,10.9873C4.224,10.9747 4.2284,10.9682 4.2371,10.9616C4.2769,10.9371 4.362,10.996 4.4247,11.0904C4.4296,11.1007 4.4362,11.1105 4.4405,11.1171L4.5775,11.1171C4.5824,11.1105 4.5884,11.1013 4.5938,11.0904C4.6565,10.9955 4.7411,10.9371 4.7809,10.9616C4.7907,10.9682 4.794,10.9742 4.7978,10.9873C4.7842,10.9785 4.7422,11.0195 4.6953,11.0778L4.6882,11.1324L4.6789,11.1749L4.6751,11.2158L4.5104,11.2158" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.9997,11.4408L4.4254,11.4408L4.4171,11.3608L4.4061,11.2848L4.3905,11.1868C4.3116,11.0758 4.2557,11.0228 4.2346,11.0228C4.2336,11.0228 4.2318,11.0228 4.23,11.0228L4.2125,11.0358L4.2181,11.0148C4.2245,10.9918 4.2336,10.9738 4.2502,10.9648C4.2612,10.9578 4.2749,10.9518 4.2887,10.9518C4.3676,10.9518 4.4859,11.0558 4.5758,11.2038C4.5859,11.2198 4.5942,11.2348 4.5997,11.2488L4.8236,11.2488C4.8309,11.2348 4.8382,11.2198 4.8474,11.2038C4.9382,11.0558 5.0566,10.9518 5.1346,10.9518C5.1492,10.9518 5.1648,10.9578 5.1749,10.9648C5.1905,10.9738 5.1988,10.9908 5.2061,11.0148L5.2125,11.0358L5.1951,11.0228C5.1942,11.0228 5.1914,11.0228 5.1914,11.0228C5.1703,11.0228 5.1144,11.0758 5.0346,11.1888L5.019,11.2838L5.008,11.3608L4.9997,11.4408ZM4.4382,11.4298L4.9869,11.4298L4.9924,11.3618L5.0043,11.2798L5.019,11.1798C5.0474,11.1408 5.1392,11.0148 5.1859,11.0098C5.1823,10.9938 5.1758,10.9868 5.1667,10.9798C5.1584,10.9708 5.1474,10.9708 5.1336,10.9708C5.0612,10.9708 4.9483,11.0708 4.8612,11.2148C4.8502,11.2308 4.8419,11.2468 4.8346,11.2618L4.8309,11.2678L4.5924,11.2678L4.5887,11.2618C4.5832,11.2468 4.574,11.2308 4.5621,11.2148C4.4758,11.0698 4.3621,10.9708 4.2887,10.9708C4.2758,10.9708 4.2658,10.9708 4.2566,10.9798C4.2474,10.9868 4.241,10.9948 4.2373,11.0098C4.2841,11.0148 4.3758,11.1408 4.4043,11.1798L4.4052,11.1818L4.419,11.2818L4.4327,11.3618L4.4382,11.4298Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.9387,11.2311L4.9262,11.2241C5.0335,11.0551 5.1638,10.9481 5.2251,10.9871L5.2155,10.9971C5.1705,10.9711 5.0498,11.0571 4.9387,11.2311ZM4.5124,11.2311C4.4004,11.0571 4.2797,10.9711 4.2347,10.9971L4.2251,10.9871C4.2854,10.9481 4.4157,11.0551 4.523,11.2241L4.5124,11.2311Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.2638,11.29C4.2573,11.2687 4.2442,11.2535 4.2442,11.2535C4.3113,11.2327 4.4045,11.2196 4.5093,11.2196C4.6129,11.2196 4.7084,11.2322 4.7749,11.2535C4.7749,11.2535 4.7673,11.266 4.7564,11.284C4.7509,11.2949 4.7427,11.314 4.7433,11.314C4.6822,11.2949 4.6047,11.284 4.5082,11.284C4.4116,11.284 4.3189,11.2949 4.2704,11.3162C4.272,11.3156 4.2676,11.3031 4.2638,11.29L4.2638,11.29" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.3055,11.4038L4.2995,11.3988L4.2935,11.3988C4.2935,11.3948 4.2875,11.3758 4.2785,11.3568L4.2755,11.3438L4.2755,11.3438C4.2635,11.3128 4.2445,11.2888 4.2435,11.2888L4.2355,11.2808L4.2465,11.2768C4.3765,11.2368 4.5505,11.2158 4.7365,11.2158C4.9225,11.2158 5.0955,11.2368 5.2255,11.2768L5.2355,11.2808L5.2305,11.2868C5.2305,11.2868 5.2185,11.3118 5.1985,11.3478C5.1885,11.3618 5.1775,11.3918 5.1755,11.3968L5.1685,11.3948L5.1655,11.4018C5.0545,11.3678 4.9085,11.3518 4.7355,11.3518C4.6615,11.3518 4.5875,11.3518 4.5205,11.3598C4.5205,11.3598 4.5185,11.3598 4.5165,11.3598C4.4295,11.3718 4.3535,11.3828 4.3055,11.4038ZM4.2995,11.3598C4.3035,11.3738 4.3055,11.3808 4.3075,11.3828C4.3995,11.3518 4.5665,11.3338 4.7375,11.3338C4.9095,11.3338 5.0515,11.3518 5.1635,11.3828C5.1675,11.3748 5.1735,11.3598 5.1855,11.3358C5.1975,11.3148 5.2085,11.2988 5.2145,11.2888C5.0885,11.2558 4.9165,11.2338 4.7385,11.2338C4.5585,11.2338 4.3925,11.2538 4.2645,11.2888C4.2725,11.3028 4.2875,11.3258 4.2945,11.3518L4.2995,11.3598L4.2995,11.3598Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.5093,11.3762C4.5933,11.3762 4.6855,11.3636 4.7204,11.3538C4.7433,11.3462 4.7558,11.338 4.7536,11.326C4.7531,11.3195 4.7476,11.3151 4.7411,11.3124C4.6915,11.2944 4.6004,11.2835 4.5098,11.2835C4.4176,11.2835 4.3276,11.2944 4.2769,11.3124C4.2704,11.3156 4.2655,11.32 4.2644,11.326C4.2616,11.3375 4.2753,11.3462 4.2987,11.3538C4.3315,11.3636 4.4247,11.3762 4.5093,11.3762" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.7176,11.4622L4.7176,11.4622C4.5636,11.4622 4.3906,11.4392 4.3266,11.4232C4.2626,11.4032 4.2556,11.3762 4.2606,11.3622C4.2626,11.3492 4.2746,11.3372 4.2876,11.3292C4.3846,11.2982 4.5536,11.2802 4.7176,11.2802C4.8816,11.2802 5.0486,11.2982 5.1466,11.3292C5.1606,11.3372 5.1706,11.3502 5.1746,11.3622C5.1756,11.3762 5.1726,11.4032 5.1056,11.4232C5.0406,11.4392 4.8716,11.4622 4.7176,11.4622ZM4.7176,11.2982C4.5546,11.2982 4.3886,11.3182 4.2936,11.3452C4.2856,11.3512 4.2776,11.3552 4.2756,11.3662C4.2746,11.3782 4.2936,11.3972 4.3326,11.4082C4.3966,11.4232 4.5656,11.4462 4.7176,11.4462C4.8696,11.4462 5.0386,11.4232 5.1016,11.4082C5.1416,11.3972 5.1616,11.3782 5.1586,11.3662C5.1576,11.3542 5.1496,11.3502 5.1416,11.3452C5.0456,11.3182 4.8786,11.2982 4.7176,11.2982Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.7787,11.2158L4.7591,11.1973C4.7591,11.1973 4.7389,11.2087 4.7144,11.2049C4.6898,11.2005 4.6822,11.1727 4.6822,11.1727C4.6822,11.1727 4.6544,11.194 4.632,11.1918C4.6091,11.1907 4.596,11.1727 4.596,11.1727C4.596,11.1727 4.5704,11.1891 4.5491,11.1875C4.5284,11.1864 4.5065,11.1585 4.5065,11.1585C4.5065,11.1585 4.4853,11.1875 4.4651,11.1875C4.4422,11.1907 4.4247,11.1695 4.4247,11.1695C4.4247,11.1695 4.4149,11.1907 4.3882,11.194C4.3598,11.2005 4.3369,11.1749 4.3369,11.1749C4.3369,11.1749 4.3205,11.2005 4.3025,11.2049C4.2845,11.2136 4.2605,11.1951 4.2605,11.1951C4.2605,11.1951 4.2562,11.2049 4.2535,11.2109C4.2507,11.2164 4.242,11.2175 4.242,11.2175L4.248,11.2333C4.3151,11.2131 4.4067,11.2016 4.5098,11.2016C4.6124,11.2016 4.7045,11.2131 4.7716,11.2333L4.7787,11.2158" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.2186,11.3115L5.2137,11.3115C5.0853,11.2725 4.9161,11.2505 4.736,11.2485C4.555,11.2505 4.3878,11.2715 4.2624,11.3115L4.2535,11.3115L4.2365,11.2645L4.2465,11.2645C4.2505,11.2645 4.2584,11.2625 4.2604,11.2545C4.2644,11.2465 4.2724,11.2275 4.2724,11.2275L4.2744,11.2205L4.2843,11.2255C4.2843,11.2255 4.3132,11.2445 4.339,11.2445C4.344,11.2445 4.351,11.2445 4.3559,11.2415C4.3858,11.2295 4.4147,11.1885 4.4147,11.1885L4.4206,11.1785L4.4256,11.1865C4.4256,11.1865 4.4674,11.2295 4.5112,11.2235C4.555,11.2175 4.5719,11.1805 4.5719,11.1785L4.5768,11.1705L4.5868,11.1785C4.5868,11.1785 4.6137,11.2115 4.6475,11.2115C4.6475,11.2115 4.6495,11.2115 4.6525,11.2115C4.6873,11.2055 4.7241,11.1585 4.7241,11.1565L4.7301,11.1515L4.737,11.1565C4.738,11.1585 4.7739,11.2035 4.8087,11.2095C4.8107,11.2095 4.8107,11.2095 4.8127,11.2095C4.8475,11.2095 4.8873,11.1785 4.8873,11.1785L4.8923,11.1765L4.8982,11.1825C4.8982,11.1825 4.9211,11.2175 4.9589,11.2175C4.9609,11.2175 4.9619,11.2175 4.9619,11.2175C4.9987,11.2175 5.0435,11.1805 5.0435,11.1805L5.0555,11.1735L5.0564,11.1865C5.0564,11.1875 5.0714,11.2375 5.1082,11.2415C5.15,11.2475 5.1828,11.2255 5.1828,11.2255L5.1888,11.2235L5.2296,11.2625L5.2365,11.2625L5.2346,11.2705L5.2186,11.3115ZM4.736,11.2375C4.9142,11.2375 5.0823,11.2575 5.2097,11.2935L5.2186,11.2715L5.1888,11.2455C5.1788,11.2505 5.1559,11.2625 5.1261,11.2625C5.1211,11.2625 5.1142,11.2625 5.1092,11.2605C5.0724,11.2505 5.0535,11.2225 5.0455,11.2035C5.0286,11.2195 4.9928,11.2425 4.9579,11.2385C4.9241,11.2345 4.8992,11.2125 4.8903,11.2015C4.8763,11.2095 4.8415,11.2265 4.8067,11.2265C4.7758,11.2245 4.744,11.1955 4.7301,11.1795C4.7181,11.1955 4.6863,11.2245 4.6545,11.2265C4.6525,11.2265 4.6495,11.2265 4.6485,11.2265C4.6196,11.2265 4.5967,11.2085 4.5848,11.2005C4.5729,11.2135 4.553,11.2325 4.5152,11.2425C4.4734,11.2485 4.4385,11.2195 4.4216,11.2035C4.4117,11.2195 4.3888,11.2485 4.3629,11.2595C4.3559,11.2625 4.348,11.2645 4.34,11.2645C4.3181,11.2645 4.2962,11.2505 4.2843,11.2455C4.2823,11.2505 4.2783,11.2605 4.2754,11.2665C4.2694,11.2705 4.2624,11.2725 4.2574,11.2765L4.2624,11.2935C4.3908,11.2575 4.5579,11.2375 4.736,11.2375Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.5104,11.1264L4.5196,11.128C4.518,11.1313 4.5175,11.1367 4.5175,11.1405C4.5175,11.1618 4.5355,11.1771 4.5562,11.1771C4.5742,11.1771 4.5873,11.1656 4.5933,11.1515C4.5933,11.152 4.596,11.1378 4.5982,11.1389C4.5998,11.1389 4.5998,11.152 4.5998,11.152C4.6025,11.17 4.6189,11.1831 4.638,11.1831C4.6593,11.1831 4.6762,11.1662 4.6762,11.1482C4.6762,11.1455 4.6762,11.1427 4.6762,11.1405L4.6882,11.1291L4.6953,11.146C4.692,11.1493 4.6909,11.1547 4.6909,11.1618C4.6909,11.1787 4.7078,11.1962 4.7269,11.1962C4.7395,11.1962 4.7515,11.1902 4.758,11.1787L4.7651,11.1711L4.7651,11.1825C4.7651,11.194 4.7705,11.2038 4.782,11.2071C4.782,11.2071 4.7956,11.2082 4.8131,11.1935C4.8316,11.1787 4.8415,11.1667 4.8415,11.1667L4.842,11.1825C4.842,11.1825 4.8251,11.2125 4.8093,11.2207C4.7995,11.2251 4.7864,11.2295 4.7755,11.2295C4.7645,11.2278 4.7564,11.218 4.752,11.2082C4.7449,11.2125 4.7356,11.2158 4.7253,11.2158C4.704,11.2158 4.6838,11.2044 4.6756,11.1869C4.6658,11.1978 4.6527,11.2027 4.6364,11.2027C4.6184,11.2027 4.602,11.1951 4.5927,11.1836C4.5829,11.1913 4.5698,11.1995 4.5545,11.1995C4.5355,11.1995 4.5191,11.188 4.5098,11.1738C4.5,11.188 4.482,11.1995 4.4629,11.1995C4.4493,11.1995 4.4351,11.1907 4.4253,11.1836C4.4149,11.1951 4.3991,11.2027 4.3822,11.2027C4.3658,11.2027 4.3516,11.1973 4.3413,11.1869C4.3342,11.2049 4.3151,11.2164 4.2927,11.2164C4.2829,11.2164 4.2736,11.2131 4.2649,11.2087C4.2611,11.2185 4.2535,11.2284 4.242,11.23C4.2322,11.23 4.2185,11.2256 4.2098,11.2213C4.1935,11.2125 4.1744,11.1831 4.1744,11.1831L4.1765,11.1673C4.1765,11.1673 4.1875,11.1787 4.2038,11.194C4.2229,11.2087 4.2355,11.2076 4.2355,11.2076C4.248,11.2044 4.2529,11.1951 4.2529,11.1831L4.2529,11.1716L4.2616,11.1793C4.2682,11.1907 4.2785,11.1967 4.2916,11.1967C4.3129,11.1967 4.3287,11.1793 4.3287,11.1624C4.3287,11.1547 4.3282,11.1498 4.326,11.1465L4.3309,11.1291L4.3424,11.1405C4.3424,11.1427 4.3418,11.1455 4.3418,11.1482C4.3418,11.1662 4.3593,11.1831 4.3805,11.1831C4.3996,11.1831 4.4165,11.1705 4.4187,11.152C4.4193,11.152 4.4193,11.1389 4.4204,11.1389C4.422,11.1378 4.4253,11.152 4.4258,11.1515C4.4302,11.1656 4.446,11.1771 4.4613,11.1771C4.4842,11.1771 4.5,11.1618 4.5,11.1405C4.5,11.1362 4.4995,11.1307 4.4989,11.128L4.5104,11.1264" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.0658,11.3301C5.0626,11.3301 5.0618,11.3301 5.057,11.3281C5.0426,11.3241 5.0291,11.3121 5.0219,11.2941C5.0099,11.2971 4.9971,11.3031 4.9851,11.3031C4.9539,11.3031 4.9259,11.2851 4.9124,11.2521C4.8956,11.2721 4.8748,11.2811 4.8548,11.2811C4.83,11.2811 4.806,11.2681 4.7908,11.2481C4.7749,11.2661 4.7557,11.2711 4.7349,11.2711C4.7101,11.2711 4.6837,11.2551 4.6693,11.2321C4.651,11.2551 4.627,11.2711 4.6006,11.2711C4.5806,11.2711 4.5614,11.2651 4.5462,11.2481C4.5295,11.2691 4.5055,11.2811 4.4823,11.2811C4.4599,11.2811 4.4399,11.2711 4.4247,11.2521C4.4104,11.2851 4.3816,11.3031 4.3512,11.3031C4.3368,11.3031 4.3248,11.2971 4.3136,11.2941C4.3048,11.3131 4.292,11.3241 4.2769,11.3281C4.2769,11.3301 4.2721,11.3301 4.2705,11.3301C4.2529,11.3301 4.2337,11.3171 4.2249,11.3121C4.2017,11.2941 4.1737,11.2421 4.1729,11.2421L4.1705,11.2361L4.1785,11.1891L4.1873,11.2031C4.1881,11.2031 4.2025,11.2241 4.2257,11.2481C4.2497,11.2701 4.2641,11.2711 4.2681,11.2711C4.2865,11.2681 4.2865,11.2421 4.2865,11.2341L4.2865,11.1871L4.3096,11.2241C4.3192,11.2421 4.3336,11.2491 4.3488,11.2491C4.3752,11.2491 4.3968,11.2241 4.3968,11.1941C4.3968,11.1801 4.3944,11.1751 4.3928,11.1711L4.3904,11.1651L4.4056,11.1241L4.4319,11.1551L4.4319,11.1571C4.4319,11.1611 4.4319,11.1651 4.4319,11.1691C4.4319,11.1991 4.4543,11.2261 4.4823,11.2261C4.5071,11.2261 4.5287,11.2031 4.5311,11.1771L4.5311,11.1711C4.5311,11.1711 4.5311,11.1711 4.5311,11.1711C4.5319,11.1521 4.5327,11.1461 4.5399,11.1461L4.5399,11.1461C4.5446,11.1461 4.5478,11.1511 4.551,11.1621L4.551,11.1621L4.5534,11.1721C4.5606,11.1981 4.5798,11.2171 4.6006,11.2171C4.6286,11.2171 4.6526,11.1881 4.6526,11.1561C4.6526,11.1481 4.6526,11.1401 4.6486,11.1331L4.647,11.1251L4.6717,11.1231L4.6949,11.1251L4.6909,11.1331C4.6909,11.1411 4.6901,11.1491 4.6901,11.1561C4.6901,11.1871 4.7125,11.2171 4.7397,11.2171C4.7613,11.2171 4.7797,11.1981 4.7877,11.1721L4.7893,11.1641L4.7893,11.1641C4.794,11.1511 4.794,11.1461 4.8012,11.1461C4.8076,11.1461 4.8076,11.1531 4.8084,11.1691C4.8084,11.1711 4.8084,11.1711 4.8084,11.1711L4.8092,11.1771C4.8124,11.2021 4.834,11.2261 4.8596,11.2261C4.8876,11.2261 4.9092,11.2001 4.9092,11.1691C4.9092,11.1651 4.9092,11.1611 4.9092,11.1571L4.9084,11.1551L4.9347,11.1241L4.9499,11.1651L4.9491,11.1711C4.9459,11.1761 4.9451,11.1811 4.9451,11.1941C4.9451,11.2231 4.9667,11.2491 4.9923,11.2491C5.0083,11.2491 5.0235,11.2411 5.0323,11.2241L5.0562,11.1871L5.0554,11.2341C5.0554,11.2421 5.0578,11.2681 5.0754,11.2711C5.077,11.2711 5.0946,11.2701 5.1162,11.2481C5.1426,11.2251 5.1562,11.2031 5.1562,11.2031L5.1657,11.1871L5.1705,11.2361L5.1681,11.2401C5.1665,11.2421 5.1426,11.2951 5.1162,11.3121C5.1042,11.3151 5.085,11.3301 5.0658,11.3301ZM5.0283,11.2701L5.0307,11.2771C5.0331,11.2891 5.0426,11.3101 5.0602,11.3121C5.061,11.3121 5.0634,11.3121 5.0658,11.3121C5.0786,11.3121 5.0938,11.3041 5.1034,11.2961C5.1218,11.2841 5.1458,11.2411 5.1506,11.2301L5.1506,11.2261C5.1418,11.2361 5.1322,11.2471 5.1178,11.2631C5.0938,11.2881 5.0754,11.2881 5.069,11.2881L5.0658,11.2881C5.0482,11.2841 5.0379,11.2651 5.0371,11.2351C5.0243,11.2531 5.0059,11.2641 4.9867,11.2641C4.9531,11.2641 4.9259,11.2331 4.9259,11.1941C4.9259,11.1781 4.9283,11.1711 4.9307,11.1651L4.9259,11.1501L4.9179,11.1611C4.9179,11.1631 4.9179,11.1651 4.9179,11.1691C4.9179,11.2061 4.89,11.2411 4.8556,11.2411C4.8252,11.2411 4.7996,11.2181 4.794,11.1821C4.7845,11.2111 4.7613,11.2271 4.7349,11.2271C4.7005,11.2271 4.6717,11.1941 4.6717,11.1551C4.6717,11.1471 4.6717,11.1451 4.6717,11.1351L4.6677,11.1331L4.6598,11.1351C4.6614,11.1451 4.6614,11.1471 4.6614,11.1551C4.6614,11.1941 4.6326,11.2271 4.5966,11.2271C4.5726,11.2271 4.5494,11.2111 4.5406,11.1821C4.5335,11.2171 4.5079,11.2411 4.4783,11.2411C4.4431,11.2411 4.4144,11.2061 4.4144,11.1691C4.4144,11.1651 4.4144,11.1631 4.4144,11.1611L4.4064,11.1501L4.4016,11.1651C4.4048,11.1711 4.4056,11.1791 4.4056,11.1941C4.4056,11.2331 4.3792,11.2641 4.3456,11.2641C4.3256,11.2641 4.3072,11.2521 4.2968,11.2351C4.2968,11.2641 4.2841,11.2841 4.2657,11.2881L4.2657,11.2881C4.2609,11.2881 4.2409,11.2881 4.2153,11.2631C4.2009,11.2471 4.1905,11.2341 4.1833,11.2261L4.1817,11.2301C4.1881,11.2421 4.2105,11.2851 4.2297,11.2961C4.2465,11.3101 4.2617,11.3151 4.2745,11.3121C4.2912,11.3101 4.2992,11.2891 4.3024,11.2771L4.3056,11.2701L4.3112,11.2731C4.3224,11.2831 4.3344,11.2891 4.3488,11.2891C4.3768,11.2891 4.4048,11.2661 4.4144,11.2381L4.4183,11.2261L4.4247,11.2351C4.4391,11.2521 4.4575,11.2651 4.4799,11.2651C4.5031,11.2651 4.5239,11.2491 4.5375,11.2281L4.5414,11.2241L4.547,11.2261C4.5606,11.2451 4.5782,11.2511 4.5974,11.2511C4.623,11.2511 4.647,11.2411 4.6598,11.2161L4.6661,11.2021L4.6701,11.2161C4.6845,11.2411 4.7077,11.2511 4.7317,11.2511C4.7509,11.2511 4.7693,11.2441 4.7829,11.2261L4.7877,11.2241L4.7916,11.2281C4.806,11.2491 4.8292,11.2651 4.8516,11.2651C4.8716,11.2651 4.8908,11.2511 4.9044,11.2351L4.9124,11.2261L4.9155,11.2381C4.9267,11.2651 4.9523,11.2891 4.9819,11.2891C4.9947,11.2891 5.0067,11.2831 5.0187,11.2731L5.0283,11.2701Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.5093,11.2196C4.4045,11.2196 4.3113,11.2322 4.2447,11.2535C4.2387,11.2551 4.2338,11.2518 4.2322,11.2475C4.2316,11.2431 4.2349,11.2387 4.2387,11.2365C4.3064,11.2158 4.4024,11.2022 4.5098,11.2022C4.6156,11.2022 4.7127,11.2158 4.7804,11.2365C4.7853,11.2387 4.7885,11.2431 4.7864,11.2475C4.7853,11.2518 4.7787,11.2551 4.7755,11.2535C4.7084,11.2327 4.6129,11.2196 4.5093,11.2196" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.2013,11.3068C5.1984,11.3068 5.1984,11.3048 5.1945,11.3048C5.0718,11.2718 4.9036,11.2498 4.7267,11.2498C4.5479,11.2498 4.3826,11.2708 4.2579,11.3048C4.2473,11.3108 4.2328,11.3028 4.2299,11.2928C4.227,11.2828 4.227,11.2788 4.2299,11.2728C4.2328,11.2668 4.2386,11.2588 4.2453,11.2568C4.371,11.2198 4.5411,11.1978 4.7277,11.1978C4.9103,11.1978 5.0853,11.2208 5.21,11.2568C5.2216,11.2628 5.2293,11.2778 5.2274,11.2918C5.2206,11.3018 5.211,11.3068 5.2013,11.3068ZM4.7267,11.2318C4.9055,11.2318 5.0727,11.2528 5.1984,11.2928L5.2003,11.2928C5.2032,11.2928 5.2081,11.2888 5.2081,11.2828C5.209,11.2808 5.2071,11.2778 5.2032,11.2758C5.0795,11.2338 4.9065,11.2128 4.7257,11.2108C4.5459,11.2128 4.37,11.2338 4.2482,11.2758C4.2453,11.2758 4.2453,11.2788 4.2434,11.2808C4.2424,11.2808 4.2424,11.2808 4.2424,11.2828C4.2434,11.2888 4.2473,11.2928 4.2521,11.2928C4.3787,11.2528 4.5469,11.2318 4.7267,11.2318Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M4.4078,11.2562C4.4078,11.2518 4.4144,11.2436 4.4236,11.2436C4.4318,11.2436 4.4384,11.2524 4.4384,11.2562C4.4384,11.2665 4.4313,11.2709 4.4236,11.2709C4.4144,11.2709 4.4078,11.266 4.4078,11.2562" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M4.5104,11.2644L4.4771,11.2644C4.4711,11.2644 4.4656,11.2578 4.4656,11.2529C4.4656,11.2469 4.4711,11.2415 4.4771,11.2415L4.5453,11.2415C4.5518,11.2415 4.5556,11.2469 4.5556,11.2529C4.5556,11.2578 4.5518,11.2644 4.5453,11.2644L4.5104,11.2644" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.6153,11.2933L4.4903,11.2933C4.4743,11.2933 4.4613,11.2813 4.4613,11.2653C4.4613,11.2463 4.4743,11.2393 4.4893,11.2393L4.6143,11.2393C4.6293,11.2393 4.6423,11.2473 4.6423,11.2653C4.6433,11.2813 4.6293,11.2933 4.6153,11.2933ZM4.4893,11.2523C4.4823,11.2523 4.4773,11.2603 4.4773,11.2653C4.4773,11.2703 4.4823,11.2763 4.4903,11.2763L4.6153,11.2763C4.6213,11.2763 4.6273,11.2703 4.6273,11.2653C4.6273,11.2603 4.6223,11.2523 4.6153,11.2523L4.4893,11.2523Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M4.3424,11.2775L4.3184,11.2791C4.3118,11.2802 4.3058,11.2775 4.3058,11.2687C4.3053,11.2644 4.3085,11.2578 4.3151,11.2573L4.3385,11.2551L4.3631,11.2518C4.3696,11.2518 4.3756,11.2535 4.3756,11.2595C4.3762,11.2649 4.3724,11.2693 4.3658,11.2709L4.3424,11.2775" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.3297,11.3143C4.3147,11.3143 4.3037,11.3043 4.3017,11.2893C4.2997,11.2863 4.3027,11.2813 4.3057,11.2713C4.3097,11.2653 4.3167,11.2623 4.3257,11.2603L4.4147,11.2453C4.4147,11.2453 4.4157,11.2453 4.4187,11.2453C4.4317,11.2453 4.4437,11.2573 4.4467,11.2683C4.4497,11.2863 4.4377,11.3013 4.4217,11.3033L4.3327,11.3123C4.3327,11.3123 4.3317,11.3143 4.3297,11.3143ZM4.4187,11.2633L4.3267,11.2793C4.3247,11.2813 4.3217,11.2813 4.3197,11.2813C4.3167,11.2843 4.3157,11.2873 4.3167,11.2893C4.3177,11.2953 4.3247,11.3033 4.3327,11.3013L4.4197,11.2873C4.4257,11.2863 4.4317,11.2813 4.4317,11.2733C4.4297,11.2653 4.4247,11.2633 4.4187,11.2633Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M4.2447,11.2927l0.0115,-0.0164l0.0229,0.0038l-0.0136,0.0185l-0.0207,-0.006" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M4.5802,11.2562C4.5802,11.2518 4.5867,11.2436 4.5949,11.2436C4.6025,11.2436 4.6091,11.2524 4.6091,11.2562C4.6091,11.2665 4.602,11.2709 4.5949,11.2709C4.5867,11.2709 4.5802,11.266 4.5802,11.2562" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M4.6762,11.2775L4.7002,11.2791C4.7062,11.2802 4.7116,11.2775 4.7127,11.2687C4.7144,11.2644 4.71,11.2578 4.7035,11.2573L4.6789,11.2551L4.6544,11.2518C4.6484,11.2518 4.6429,11.2535 4.6418,11.2595C4.6407,11.2649 4.6451,11.2693 4.6511,11.2709L4.6762,11.2775" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.755,11.3146C4.755,11.3146 4.753,11.3126 4.75,11.3126L4.661,11.3046C4.655,11.3046 4.647,11.2966 4.643,11.2886C4.638,11.2836 4.638,11.2786 4.638,11.2686C4.639,11.2566 4.655,11.2416 4.67,11.2456L4.76,11.2606C4.766,11.2626 4.773,11.2656 4.778,11.2716C4.783,11.2816 4.783,11.2866 4.783,11.2896C4.781,11.3046 4.769,11.3146 4.755,11.3146ZM4.667,11.2636C4.662,11.2636 4.655,11.2656 4.655,11.2736C4.654,11.2776 4.655,11.2816 4.655,11.2816C4.657,11.2846 4.661,11.2866 4.664,11.2876L4.755,11.3016C4.76,11.3016 4.767,11.2956 4.767,11.2896C4.767,11.2876 4.767,11.2846 4.767,11.2816C4.764,11.2816 4.761,11.2816 4.757,11.2796L4.667,11.2636L4.667,11.2636Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M4.7716,11.2933l-0.0093,-0.0169l-0.0229,0.0011l0.0104,0.0191l0.0218,-0.0033" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M4.5093,11.3571C4.4247,11.3565 4.3489,11.3484 4.2905,11.3325C4.3484,11.3189 4.4247,11.3091 4.5093,11.3091C4.5933,11.3091 4.6702,11.3189 4.7275,11.3325C4.6702,11.3489 4.5933,11.3565 4.5093,11.3571" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.6947,11.4063L4.6947,11.4063C4.5347,11.4063 4.3977,11.3943 4.2917,11.3673C4.2877,11.3653 4.2867,11.3613 4.2867,11.3553C4.2867,11.3533 4.2877,11.3503 4.2917,11.3503C4.4037,11.3243 4.5447,11.3063 4.6947,11.3053C4.8427,11.3053 4.9857,11.3243 5.0967,11.3503C5.0997,11.3503 5.1027,11.3533 5.1027,11.3553C5.1027,11.3613 5.0997,11.3653 5.0967,11.3673C4.9927,11.3943 4.8537,11.4063 4.6947,11.4063ZM4.3287,11.3553C4.4267,11.3783 4.5527,11.3923 4.6937,11.3943C4.8367,11.3923 4.9587,11.3783 5.0587,11.3553C4.9537,11.3323 4.8247,11.3243 4.6937,11.3243C4.5607,11.3243 4.4327,11.3323 4.3287,11.3553Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.7749,11.1749C4.776,11.1662 4.7749,11.1624 4.7695,11.1602C4.7656,11.158 4.7591,11.1624 4.7569,11.1678C4.7553,11.1755 4.7564,11.1804 4.7624,11.1836C4.7656,11.1847 4.7722,11.1793 4.7749,11.1749" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.6064,11.1411C4.6075,11.1367 4.6047,11.1285 4.5998,11.1285C4.5944,11.1285 4.59,11.1335 4.59,11.14C4.5884,11.1476 4.5916,11.1525 4.5965,11.1525C4.6015,11.1536 4.6058,11.1493 4.6064,11.1411" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.4116,11.1411C4.4105,11.1367 4.4138,11.1285 4.4198,11.1285C4.4236,11.1285 4.4296,11.1335 4.4302,11.14C4.4302,11.1476 4.4275,11.1525 4.4231,11.1525C4.4171,11.1536 4.4133,11.1493 4.4116,11.1411" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.2447,11.1749C4.242,11.1662 4.2447,11.1624 4.2485,11.1602C4.2545,11.158 4.2595,11.1624 4.2611,11.1678C4.2638,11.1755 4.2616,11.1804 4.2573,11.1836C4.2518,11.1847 4.2469,11.1793 4.2447,11.1749" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.5093,11.0462l-0.0305,0.0169l0.0224,0.048l0.0082,0.0044l0.0076,-0.0044l0.0224,-0.048l-0.03,-0.0169" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.5388,11.1915L4.5178,11.1765L4.4738,11.0775L4.5388,11.0385L4.6048,11.0775L4.5578,11.1765L4.5388,11.1915ZM4.5298,11.1655L4.5378,11.1715L4.5448,11.1655L4.5798,11.0855L4.5378,11.0605L4.4928,11.0855L4.5298,11.1655Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.4433,11.1155l0.0142,0.0213l0.0464,-0.0125l0.0049,-0.0087l-0.0049,-0.0044l-0.0464,-0.0147l-0.0142,0.0191" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.4694,11.1838L4.4384,11.1368L4.4694,11.0898L4.5634,11.1168L4.5764,11.1368L4.5634,11.1578L4.4694,11.1838ZM4.4584,11.1368L4.4764,11.1658L4.5524,11.1408L4.5584,11.1368L4.5524,11.1338L4.4764,11.1118L4.4584,11.1368Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.5742,11.1155l-0.0125,0.0213l-0.0475,-0.0125l-0.0038,-0.0087l0.0038,-0.0044l0.0469,-0.0147l0.0131,0.0191" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.6118,11.1838l-0.094,-0.026l-0.014,-0.021l0.015,-0.02l0.094,-0.027l0.032,0.047z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.3151,11.0642l-0.0224,0.024l0.0289,0.0387l0.0093,0.0022l0.0049,-0.0055l0.0109,-0.0469l-0.0316,-0.0125" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.3682,11.2008l-0.022,-0.012l-0.06,-0.077l0.052,-0.052l0.067,0.026l-0.021,0.097z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.2671,11.1455l0.0169,0.0169l0.0425,-0.024l0.0033,-0.0082l-0.0055,-0.0049l-0.0491,-0.0027l-0.0082,0.0229" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.3011,11.2095l-0.04,-0.037l0.021,-0.057l0.097,0.012l0.018,0.012l-0.009,0.023z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.3953,11.1187l-0.0098,0.0224l-0.0475,-0.0044l-0.0071,-0.0065l0.0027,-0.0065l0.042,-0.0224l0.0196,0.0175" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.4424,11.1884l-0.099,-0.01l-0.019,-0.016l0.012,-0.021l0.085,-0.045l0.041,0.039z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.2196,11.1509l-0.0038,0.024l-0.048,0.0044l-0.0071,-0.0044l0.0005,-0.0087l0.0371,-0.03l0.0213,0.0147" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.1773,11.2277l-0.022,-0.011l0.006,-0.023l0.073,-0.063l0.05,0.035l-0.01,0.053z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.314,11.1302C4.314,11.1236 4.3216,11.1155 4.3315,11.1155C4.3407,11.1155 4.3473,11.1242 4.3473,11.1302C4.3473,11.14 4.3407,11.1482 4.3315,11.1482C4.3211,11.1482 4.314,11.14 4.314,11.1302" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.7024,11.0642l0.024,0.024l-0.0305,0.0387l-0.0065,0.0022l-0.0065,-0.0055l-0.0098,-0.0469l0.0295,-0.0125" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.7034,11.2008l-0.014,-0.018l-0.023,-0.097l0.069,-0.026l0.051,0.052l-0.062,0.077z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.7515,11.1455l-0.018,0.0169l-0.042,-0.024l-0.0027,-0.0082l0.0065,-0.0049l0.0475,-0.0027l0.0087,0.0229" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.7777,11.2095l-0.083,-0.047l-0.012,-0.023l0.018,-0.012l0.1,-0.012l0.018,0.057z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.6244,11.1187l0.0087,0.0224l0.0485,-0.0044l0.0065,-0.0065l-0.0038,-0.0065l-0.0431,-0.0224l-0.0169,0.0175" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.6399,11.1884l-0.021,-0.053l0.041,-0.039l0.085,0.045l0.01,0.021l-0.019,0.016z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.7913,11.1509l0.0038,0.024l0.0485,0.0044l0.0076,-0.0044l-0.0027,-0.0087l-0.0355,-0.03l-0.0218,0.0147" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.8939,11.2282l-0.099,-0.01l-0.008,-0.053l0.049,-0.035l0.074,0.063l0.004,0.023z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.4918,11.1155C4.4918,11.1067 4.5,11.1002 4.5093,11.1002C4.5191,11.1002 4.5256,11.1073 4.5256,11.1155C4.5256,11.1236 4.5185,11.1324 4.5093,11.1324C4.5,11.1324 4.4918,11.1242 4.4918,11.1155" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.6713,11.1302C4.6713,11.1236 4.6795,11.1155 4.6893,11.1155C4.6985,11.1155 4.7051,11.1242 4.7051,11.1302C4.7051,11.14 4.6985,11.1482 4.6893,11.1482C4.6795,11.1482 4.6713,11.14 4.6713,11.1302" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.1553,11.1782C4.1553,11.1782 4.1427,11.1624 4.1329,11.1525C4.1253,11.1471 4.1089,11.1411 4.1089,11.1411C4.1089,11.1384 4.1187,11.1313 4.1296,11.1313C4.1356,11.1313 4.1411,11.1345 4.1444,11.1384L4.1455,11.1313C4.1455,11.1313 4.1542,11.1335 4.158,11.1411C4.1607,11.1525 4.1585,11.1667 4.1585,11.1667C4.1585,11.1667 4.1585,11.1749 4.1553,11.1782" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.198,11.2269C4.193,11.2269 4.193,11.2249 4.182,11.2149C4.174,11.2049 4.161,11.1919 4.151,11.1779C4.14,11.1729 4.118,11.1659 4.11,11.1619L4.104,11.1579L4.104,11.1519C4.104,11.1419 4.127,11.1269 4.151,11.1269C4.157,11.1269 4.166,11.1289 4.173,11.1309L4.174,11.1269L4.181,11.1269C4.182,11.1269 4.202,11.1289 4.209,11.1519C4.218,11.1729 4.215,11.1989 4.214,11.1989C4.214,11.2029 4.209,11.2179 4.204,11.2219L4.201,11.2259L4.198,11.2259L4.198,11.2269Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.1553,11.1689C4.1591,11.1656 4.1678,11.1667 4.1744,11.1722C4.1809,11.1771 4.182,11.1847 4.1776,11.188C4.1744,11.1924 4.1651,11.1924 4.1591,11.188C4.1531,11.1804 4.152,11.1749 4.1553,11.1689" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.8573,11.1782C4.8578,11.1782 4.8709,11.1624 4.8802,11.1525C4.8873,11.1471 4.9031,11.1411 4.9031,11.1411C4.9031,11.1384 4.8938,11.1313 4.8835,11.1313C4.8775,11.1313 4.8715,11.1345 4.8682,11.1384L4.866,11.1313C4.866,11.1313 4.8584,11.1335 4.854,11.1411C4.8496,11.1525 4.8518,11.1667 4.8518,11.1667C4.8518,11.1667 4.854,11.1749 4.8573,11.1782" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.8654,11.2265L4.8654,11.2265L4.8614,11.2265L4.8594,11.2225C4.8514,11.2175 4.8504,11.2025 4.8504,11.1995C4.8494,11.1995 4.8444,11.1745 4.8504,11.1525C4.8614,11.1295 4.8784,11.1275 4.8784,11.1275L4.8874,11.1275L4.8894,11.1315C4.8954,11.1295 4.9024,11.1275 4.9114,11.1275C4.9314,11.1275 4.9554,11.1435 4.9554,11.1525L4.9554,11.1585L4.9494,11.1625C4.9414,11.1665 4.9184,11.1735 4.9104,11.1785C4.8994,11.1925 4.8844,11.2075 4.8764,11.2155C4.8704,11.2245 4.8694,11.2265 4.8654,11.2265Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.8584,11.1689C4.8535,11.1656 4.8458,11.1667 4.8393,11.1722C4.8327,11.1771 4.8311,11.1847 4.8355,11.188C4.8393,11.1924 4.8475,11.1924 4.8535,11.188C4.8595,11.1804 4.8616,11.1749 4.8584,11.1689" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.1258,11.5715l0.7707,0l0,-0.2018l-0.7707,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.1187,11.7555L4.1187,11.7555L4.1187,11.3625L5.1187,11.3625L5.1187,11.7555ZM4.1368,11.7295L5.102,11.7295L5.102,11.3875L4.1368,11.3875L4.1368,11.7295Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.206,11.7045C4.2109,11.7035 4.2147,11.7035 4.2202,11.7035L4.7978,11.7035C4.8044,11.7035 4.8093,11.7035 4.8136,11.7056C4.7945,11.6991 4.7793,11.6822 4.7793,11.6609C4.7793,11.6396 4.7945,11.6227 4.8147,11.614C4.8104,11.6151 4.8038,11.6173 4.7973,11.6173L4.2202,11.6173C4.2147,11.6173 4.2093,11.6162 4.2038,11.614L4.2071,11.6151C4.2289,11.6227 4.2398,11.6396 4.2398,11.6609C4.2398,11.6789 4.2267,11.6991 4.206,11.7045" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.1833,11.8014C5.1833,11.8014 5.1816,11.8014 5.1798,11.7984L5.1772,11.7984C5.1711,11.7984 5.1641,11.7984 5.158,11.7984L4.234,11.7984C4.227,11.7984 4.2235,11.7984 4.22,11.7984C4.2165,11.7984 4.2165,11.7984 4.2148,11.7984C4.2087,11.8014 4.2026,11.7984 4.2008,11.7914C4.1999,11.7824 4.2008,11.7774 4.206,11.7744C4.2087,11.7744 4.2104,11.7744 4.2113,11.7744C4.2366,11.7584 4.2532,11.7334 4.2532,11.7044C4.2532,11.6734 4.2375,11.6434 4.2139,11.6344C4.2113,11.6344 4.2069,11.6344 4.2052,11.6344C4.1999,11.6344 4.1965,11.6244 4.1973,11.6184C4.1991,11.6104 4.2043,11.6104 4.2113,11.6104L4.2191,11.6104C4.2235,11.6104 4.2287,11.6104 4.234,11.6104L5.158,11.6104C5.1667,11.6104 5.1763,11.6104 5.1833,11.6104C5.1886,11.6064 5.1938,11.6104 5.1964,11.6164C5.199,11.6184 5.1947,11.6304 5.1894,11.6344C5.1606,11.6424 5.1406,11.6734 5.1406,11.7044C5.1406,11.7354 5.1589,11.7614 5.1833,11.7744C5.1842,11.7744 5.1868,11.7744 5.1886,11.7744C5.1929,11.7794 5.1947,11.7824 5.1929,11.7944C5.192,11.7984 5.1886,11.8014 5.1833,11.8014ZM4.2523,11.7724L5.1414,11.7724C5.1275,11.7514 5.1179,11.7274 5.1179,11.7044C5.1179,11.6814 5.1275,11.6574 5.1423,11.6374L4.2532,11.6374C4.2689,11.6584 4.2767,11.6814 4.2767,11.7044C4.2767,11.7274 4.268,11.7514 4.2523,11.7724Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.2202,11.7035L4.7978,11.7035C4.8169,11.7035 4.8327,11.716 4.8327,11.7291C4.8327,11.746 4.8169,11.758 4.7978,11.758L4.2202,11.758C4.2005,11.758 4.1847,11.7465 4.1847,11.7291C4.1847,11.716 4.2005,11.7035 4.2202,11.7035" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.1142,11.82L4.2419,11.82C4.2065,11.82 4.1776,11.794 4.1776,11.755C4.1776,11.724 4.2065,11.698 4.2419,11.698L5.1142,11.698C5.1488,11.698 5.1776,11.723 5.1776,11.755C5.1776,11.794 5.1488,11.82 5.1142,11.82ZM4.2419,11.724C4.2188,11.724 4.1991,11.738 4.1991,11.755C4.1991,11.778 4.2188,11.794 4.2419,11.794L5.1142,11.794C5.1381,11.794 5.157,11.778 5.157,11.755C5.157,11.737 5.1381,11.724 5.1142,11.724L4.2419,11.724Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.2202,11.5715L4.7978,11.5715C4.8175,11.5715 4.8333,11.5829 4.8333,11.5949C4.8333,11.6075 4.8175,11.6173 4.7978,11.6173L4.2202,11.6173C4.2005,11.6173 4.1847,11.6075 4.1847,11.5949C4.1847,11.5829 4.2005,11.5715 4.2202,11.5715" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.1134,11.6757L4.2418,11.6757C4.2064,11.6757 4.1776,11.6527 4.1776,11.6217C4.1776,11.5887 4.2064,11.5627 4.2418,11.5627L5.1134,11.5627C5.1505,11.5627 5.1776,11.5877 5.1776,11.6217C5.1776,11.6517 5.1505,11.6757 5.1134,11.6757ZM4.2418,11.5887C4.2163,11.5887 4.199,11.6077 4.199,11.6217C4.199,11.6337 4.2163,11.6487 4.2418,11.6487L5.1134,11.6487C5.1398,11.6487 5.1571,11.6327 5.1571,11.6217C5.1571,11.6067 5.1398,11.5887 5.1134,11.5887L4.2418,11.5887Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#005BBF" + android:fillType="nonZero" + android:pathData="M5.0498,14.9718C4.9958,14.9718 4.9478,14.9615 4.9129,14.9429C4.8785,14.9249 4.8316,14.9129 4.7793,14.9129C4.7275,14.9129 4.6789,14.9244 4.644,14.9429C4.6085,14.9615 4.5611,14.9718 4.5082,14.9718C4.4547,14.9718 4.4073,14.9593 4.3718,14.9407C4.3375,14.9249 4.2922,14.9129 4.2409,14.9129C4.1885,14.9129 4.1416,14.9238 4.1067,14.9418C4.0718,14.9604 4.0238,14.9718 3.9704,14.9718L3.9704,15.0558C4.0238,15.0558 4.0718,15.0444 4.1067,15.0253C4.1416,15.0078 4.1885,14.9969 4.2409,14.9969C4.2922,14.9969 4.3369,15.0084 4.3718,15.0253C4.4073,15.0427 4.4547,15.0558 4.5082,15.0558C4.5605,15.0558 4.6085,15.0444 4.644,15.0258C4.6789,15.01 4.7269,14.9969 4.7793,14.9969C4.8316,14.9969 4.878,15.0095 4.9129,15.0258C4.9478,15.0449 4.9958,15.0558 5.0487,15.0558L5.0498,14.9718" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.0558,15.1925L5.0487,15.1925C4.9958,15.1925 4.9478,15.1715 4.9096,15.1365C4.8747,15.1035 4.8295,15.0815 4.7798,15.0815C4.7307,15.0815 4.6833,15.1025 4.6478,15.1365C4.6096,15.1715 4.5616,15.1925 4.5093,15.1925C4.4585,15.1925 4.4084,15.1715 4.3702,15.1325C4.3347,15.1015 4.29,15.0815 4.2425,15.0815C4.1913,15.0815 4.1465,15.1015 4.1111,15.1345C4.0729,15.1715 4.0238,15.1925 3.972,15.1925L3.9644,15.1925L3.9644,15.0115L3.9709,15.0115C4.0205,15.0115 4.0691,14.9955 4.104,14.9605C4.1411,14.9255 4.188,14.9075 4.2415,14.9075C4.2916,14.9075 4.3391,14.9255 4.3756,14.9595C4.4122,14.9935 4.4591,15.0115 4.5087,15.0115C4.5578,15.0115 4.6058,14.9955 4.6407,14.9605C4.6778,14.9295 4.728,14.9075 4.7793,14.9075C4.8305,14.9075 4.8796,14.9275 4.9156,14.9605C4.9511,14.9955 4.9991,15.0115 5.0498,15.0115L5.0569,15.0115L5.0558,15.1925ZM4.2415,15.0565C4.2911,15.0565 4.3385,15.0775 4.3756,15.1115C4.4127,15.1485 4.4591,15.1665 4.5087,15.1665C4.5578,15.1665 4.6058,15.1485 4.6407,15.1155C4.6784,15.0805 4.7275,15.0565 4.7793,15.0565C4.83,15.0565 4.8791,15.0795 4.9156,15.1155C4.9511,15.1485 4.9936,15.1665 5.0416,15.1665L5.0427,15.0375C4.9925,15.0355 4.9451,15.0175 4.9091,14.9835C4.8742,14.9515 4.8289,14.9315 4.7793,14.9315C4.7302,14.9315 4.6827,14.9525 4.6473,14.9845C4.6102,15.0195 4.5611,15.0375 4.5087,15.0375C4.4575,15.0375 4.4078,15.0185 4.3696,14.9815C4.3347,14.9515 4.2895,14.9315 4.242,14.9315C4.1907,14.9315 4.146,14.9515 4.1105,14.9815C4.0756,15.0175 4.0276,15.0355 3.978,15.0375L3.978,15.1665C4.0244,15.1665 4.0702,15.1455 4.104,15.1135C4.1416,15.0785 4.1885,15.0565 4.2415,15.0565Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:pathData="M5.0498,15.0564C4.9958,15.0564 4.9478,15.0455 4.9129,15.0264C4.8785,15.0105 4.8316,14.9975 4.7793,14.9975C4.7275,14.9975 4.6789,15.01 4.644,15.0264C4.6085,15.0444 4.5611,15.0564 4.5082,15.0564C4.4547,15.0564 4.4073,15.0438 4.3718,15.0258C4.3375,15.0095 4.2922,14.9975 4.2409,14.9975C4.1885,14.9975 4.1416,15.0084 4.1067,15.0258C4.0718,15.0444 4.0238,15.0564 3.9704,15.0564L3.9704,15.1398C4.0238,15.1398 4.0718,15.1284 4.1067,15.1093C4.1416,15.0913 4.1885,15.0793 4.2409,15.0793C4.2922,15.0793 4.3369,15.0907 4.3718,15.1082C4.4073,15.1267 4.4547,15.1398 4.5082,15.1398C4.5605,15.1398 4.6085,15.1284 4.644,15.1104C4.6789,15.0913 4.7269,15.0793 4.7793,15.0793C4.8316,15.0793 4.878,15.0907 4.9129,15.1104C4.9478,15.1284 4.9958,15.1398 5.0487,15.1398L5.0498,15.0564" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.0558,15.2767L5.0487,15.2767C4.9958,15.2767 4.9478,15.2607 4.9096,15.2217C4.8747,15.1907 4.8295,15.1687 4.7798,15.1687C4.7307,15.1687 4.6833,15.1917 4.6478,15.2217C4.6096,15.2587 4.5616,15.2767 4.5093,15.2767C4.4585,15.2767 4.4084,15.2567 4.3702,15.2187C4.3347,15.1887 4.29,15.1687 4.2425,15.1687C4.1913,15.1687 4.1465,15.1887 4.1111,15.2207C4.0735,15.2587 4.0244,15.2767 3.972,15.2767L3.9644,15.2767L3.9644,15.0987L3.9709,15.0987C4.0205,15.0987 4.0691,15.0807 4.104,15.0457C4.1416,15.0107 4.1885,14.9887 4.2415,14.9887C4.2916,14.9887 4.3391,15.0097 4.3756,15.0437C4.4127,15.0807 4.4596,15.0987 4.5087,15.0987C4.5578,15.0987 4.6058,15.0807 4.6407,15.0477C4.6784,15.0127 4.7275,14.9887 4.7793,14.9887C4.83,14.9887 4.8791,15.0117 4.9156,15.0477C4.9511,15.0807 4.9991,15.0987 5.0498,15.0987L5.0569,15.0987L5.0558,15.2767ZM4.2415,15.1457C4.2911,15.1457 4.3385,15.1657 4.3756,15.1987C4.4122,15.2337 4.4591,15.2517 4.5087,15.2517C4.5578,15.2517 4.6058,15.2357 4.6407,15.2007C4.6784,15.1677 4.7275,15.1457 4.7793,15.1457C4.83,15.1457 4.8791,15.1667 4.9156,15.2007C4.9511,15.2337 4.9936,15.2497 5.0416,15.2517L5.0427,15.1257C4.9925,15.1227 4.9451,15.1047 4.9091,15.0697C4.8742,15.0367 4.8289,15.0147 4.7793,15.0147C4.7302,15.0147 4.6827,15.0357 4.6473,15.0697C4.6091,15.1047 4.5611,15.1257 4.5087,15.1257C4.458,15.1257 4.4078,15.1047 4.3696,15.0657C4.3347,15.0347 4.2895,15.0147 4.242,15.0147C4.1907,15.0147 4.146,15.0347 4.1105,15.0677C4.0751,15.1037 4.0276,15.1227 3.978,15.1257L3.978,15.2517C4.0244,15.2497 4.0707,15.2317 4.104,15.1987C4.1411,15.1647 4.188,15.1457 4.2415,15.1457Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#005BBF" + android:fillType="nonZero" + android:pathData="M5.0498,15.1398C4.9958,15.1398 4.9478,15.1284 4.9129,15.1104C4.8785,15.0913 4.8316,15.0793 4.7793,15.0793C4.7275,15.0793 4.6789,15.0907 4.644,15.1104C4.6085,15.1284 4.5611,15.1398 4.5082,15.1398C4.4547,15.1398 4.4073,15.1273 4.3718,15.1082C4.3375,15.0913 4.2922,15.0793 4.2409,15.0793C4.1885,15.0793 4.1416,15.0907 4.1067,15.1093C4.0718,15.1278 4.0238,15.1398 3.9704,15.1398L3.9704,15.2222C4.0238,15.2222 4.0718,15.2107 4.1067,15.1922C4.1416,15.1753 4.1885,15.1633 4.2409,15.1633C4.2922,15.1633 4.3369,15.1758 4.3718,15.1916C4.4073,15.2102 4.4547,15.2222 4.5082,15.2222C4.5605,15.2222 4.6085,15.2113 4.644,15.1933C4.6789,15.1764 4.7269,15.1633 4.7793,15.1633C4.8316,15.1633 4.878,15.1758 4.9129,15.1933C4.9478,15.2124 4.9958,15.2222 5.0487,15.2222L5.0498,15.1398" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.0558,15.3588L5.0487,15.3588C4.9958,15.3588 4.9478,15.3398 4.9096,15.3048C4.8753,15.2698 4.83,15.2498 4.7798,15.2498C4.7307,15.2498 4.6833,15.2698 4.6478,15.3048C4.6102,15.3398 4.5616,15.3588 4.5093,15.3588C4.458,15.3588 4.4084,15.3378 4.3702,15.3008C4.3347,15.2698 4.29,15.2498 4.2425,15.2498C4.1913,15.2498 4.1465,15.2698 4.1111,15.3028C4.0735,15.3378 4.0249,15.3588 3.972,15.3588L3.9644,15.3588L3.9644,15.1798L3.9709,15.1798C4.0205,15.1798 4.0691,15.1618 4.104,15.1268C4.1411,15.0938 4.188,15.0738 4.2415,15.0738C4.2916,15.0738 4.3391,15.0938 4.3756,15.1268C4.4127,15.1618 4.4591,15.1798 4.5087,15.1798C4.5578,15.1798 4.6058,15.1638 4.6407,15.1288C4.6784,15.0958 4.7275,15.0738 4.7793,15.0738C4.83,15.0738 4.8791,15.0948 4.9156,15.1288C4.9516,15.1638 4.9991,15.1798 5.0498,15.1798L5.0569,15.1798L5.0558,15.3588ZM4.2415,15.2248C4.2905,15.2248 4.3385,15.2458 4.3756,15.2798C4.4122,15.3148 4.4585,15.3358 4.5087,15.3358C4.5578,15.3358 4.6058,15.3168 4.6407,15.2838C4.6784,15.2468 4.7275,15.2248 4.7793,15.2248C4.8305,15.2248 4.8796,15.2458 4.9156,15.2838C4.9511,15.3148 4.9931,15.3328 5.0416,15.3328L5.0427,15.2058C4.9925,15.2038 4.9456,15.1858 4.9091,15.1508C4.8742,15.1198 4.8289,15.0978 4.7793,15.0978C4.7302,15.0978 4.6827,15.1208 4.6473,15.1508C4.6091,15.1878 4.5611,15.2058 4.5087,15.2058C4.458,15.2058 4.4078,15.1858 4.3696,15.1478C4.3347,15.1178 4.2895,15.0978 4.242,15.0978C4.1907,15.0978 4.146,15.1178 4.1105,15.1498C4.0756,15.1858 4.0276,15.2038 3.978,15.2058L3.978,15.3328C4.0244,15.3328 4.0707,15.3138 4.104,15.2818C4.1416,15.2468 4.1885,15.2248 4.2415,15.2248Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:pathData="M5.0487,15.3062C4.9958,15.3062 4.9478,15.2947 4.9129,15.2778C4.8785,15.2576 4.8316,15.2467 4.7793,15.2467C4.7275,15.2467 4.6789,15.2576 4.644,15.2778C4.6085,15.2947 4.5611,15.3062 4.5082,15.3062C4.4547,15.3062 4.4073,15.2947 4.3718,15.2756C4.3375,15.2576 4.2922,15.2467 4.2409,15.2467C4.1885,15.2467 4.1416,15.2576 4.1067,15.2767C4.0718,15.2947 4.0238,15.3062 3.9704,15.3062L3.9704,15.2238C4.0238,15.2238 4.0718,15.2113 4.1067,15.1927C4.1416,15.1758 4.1885,15.1638 4.2409,15.1638C4.2922,15.1638 4.3369,15.1764 4.3718,15.1922C4.4073,15.2107 4.4547,15.2227 4.5082,15.2227C4.5605,15.2227 4.6085,15.2118 4.644,15.1938C4.6789,15.1769 4.7269,15.1638 4.7793,15.1638C4.8316,15.1638 4.878,15.1764 4.9129,15.1938C4.9478,15.2129 4.9958,15.2227 5.0498,15.2227L5.0487,15.3062" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.0558,15.4436L5.0487,15.4436C4.9958,15.4436 4.9478,15.4256 4.9096,15.3866C4.8747,15.3576 4.8295,15.3366 4.7798,15.3366C4.7307,15.3366 4.6833,15.3576 4.6478,15.3886C4.6102,15.4256 4.5616,15.4436 4.5093,15.4436C4.4585,15.4436 4.4084,15.4236 4.3702,15.3856C4.3353,15.3556 4.29,15.3366 4.2425,15.3366C4.1913,15.3366 4.1465,15.3556 4.1111,15.3866C4.0729,15.4266 4.0244,15.4436 3.9709,15.4436L3.9644,15.4436L3.9644,15.2666L3.9709,15.2666C4.02,15.2666 4.0691,15.2456 4.104,15.2126C4.1416,15.1776 4.188,15.1556 4.2415,15.1556C4.2905,15.1556 4.3385,15.1766 4.3756,15.2106C4.4122,15.2456 4.4585,15.2666 4.5087,15.2666C4.5578,15.2666 4.6058,15.2476 4.6407,15.2146C4.6784,15.1776 4.7275,15.1556 4.7793,15.1556C4.8305,15.1556 4.8796,15.1766 4.9156,15.2146C4.9511,15.2456 4.9991,15.2666 5.0498,15.2666L5.0569,15.2666L5.0558,15.4436ZM4.2415,15.3106C4.2911,15.3106 4.3391,15.3316 4.3756,15.3636C4.4127,15.4006 4.4591,15.4186 4.5087,15.4186C4.5578,15.4186 4.6058,15.4026 4.6407,15.3656C4.6784,15.3346 4.7275,15.3106 4.7793,15.3106C4.83,15.3106 4.8791,15.3336 4.9156,15.3656C4.9511,15.4006 4.9936,15.4166 5.0416,15.4186L5.0427,15.2906C4.9925,15.2876 4.9445,15.2696 4.9091,15.2366C4.8747,15.2016 4.8295,15.1816 4.7793,15.1816C4.7302,15.1816 4.6827,15.2016 4.6473,15.2366C4.6096,15.2716 4.5611,15.2906 4.5087,15.2906C4.4575,15.2906 4.4078,15.2696 4.3696,15.2326C4.3342,15.2016 4.2895,15.1816 4.242,15.1816C4.1907,15.1816 4.146,15.2016 4.1105,15.2346C4.0745,15.2696 4.0276,15.2906 3.978,15.2926L3.978,15.4186C4.0255,15.4166 4.0702,15.3986 4.104,15.3656C4.1416,15.3326 4.1885,15.3106 4.2415,15.3106Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#005BBF" + android:fillType="nonZero" + android:pathData="M5.0487,15.3896C4.9958,15.3896 4.9478,15.3787 4.9129,15.3596C4.8785,15.3427 4.8316,15.3296 4.7793,15.3296C4.7275,15.3296 4.6789,15.3422 4.644,15.3596C4.6085,15.3787 4.5611,15.3896 4.5082,15.3896C4.4547,15.3896 4.4073,15.3771 4.3718,15.3585C4.3375,15.3427 4.2922,15.3296 4.2409,15.3296C4.1885,15.3296 4.1416,15.3422 4.1067,15.3596C4.0718,15.3776 4.0238,15.3896 3.9704,15.3896L3.9704,15.3078C4.0238,15.3078 4.0718,15.2953 4.1067,15.2767C4.1416,15.2576 4.1885,15.2467 4.2409,15.2467C4.2922,15.2467 4.3369,15.2576 4.3718,15.2756C4.4073,15.2942 4.4547,15.3062 4.5082,15.3062C4.5605,15.3062 4.6085,15.2947 4.644,15.2778C4.6789,15.2576 4.7269,15.2467 4.7793,15.2467C4.8316,15.2467 4.878,15.2576 4.9129,15.2778C4.9478,15.2947 4.9958,15.3062 5.0493,15.3062L5.0487,15.3896" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.0558,15.5282L5.0487,15.5282C4.9958,15.5282 4.9478,15.5072 4.9096,15.4732C4.8747,15.4362 4.8289,15.4182 4.7793,15.4182C4.7302,15.4182 4.6827,15.4362 4.6473,15.4732C4.6091,15.5062 4.5611,15.5282 4.5087,15.5282C4.458,15.5282 4.4078,15.5072 4.3696,15.4682C4.3342,15.4362 4.2895,15.4182 4.242,15.4182C4.1907,15.4182 4.146,15.4362 4.1105,15.4712C4.0724,15.5062 4.0238,15.5282 3.9715,15.5282L3.9644,15.5282L3.9644,15.3502L3.9709,15.3502C4.0195,15.3502 4.0691,15.3322 4.104,15.2952C4.1411,15.2622 4.188,15.2402 4.2415,15.2402C4.2911,15.2402 4.3385,15.2612 4.3756,15.2932C4.4127,15.3302 4.4591,15.3482 4.5087,15.3482C4.5578,15.3482 4.6058,15.3322 4.6407,15.2952C4.6778,15.2642 4.7275,15.2402 4.7793,15.2402C4.8305,15.2402 4.8796,15.2632 4.9156,15.2952C4.9511,15.3322 4.9991,15.3482 5.0493,15.3482L5.0569,15.3482L5.0558,15.5282ZM4.2415,15.3932C4.2911,15.3932 4.3385,15.4132 4.3756,15.4482C4.4133,15.4832 4.4596,15.5022 4.5087,15.5022C4.5578,15.5022 4.6058,15.4832 4.6407,15.4522C4.6784,15.4132 4.7275,15.3932 4.7793,15.3932C4.8305,15.3932 4.8796,15.4132 4.9156,15.4522C4.9511,15.4832 4.9942,15.4992 5.0416,15.5022L5.0422,15.3742C4.9925,15.3722 4.9456,15.3542 4.9091,15.3172C4.8747,15.2882 4.8295,15.2672 4.7793,15.2672C4.7302,15.2672 4.6827,15.2882 4.6473,15.3192C4.6096,15.3562 4.5611,15.3742 4.5087,15.3742C4.458,15.3742 4.4078,15.3542 4.3696,15.3162C4.3342,15.2862 4.2895,15.2672 4.242,15.2672C4.1907,15.2672 4.146,15.2862 4.1105,15.3172C4.0745,15.3542 4.0276,15.3742 3.978,15.3762L3.978,15.5022C4.0244,15.4992 4.0707,15.4812 4.104,15.4502C4.1416,15.4122 4.1885,15.3932 4.2415,15.3932Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.206,14.6298C4.2082,14.6385 4.2104,14.6435 4.2104,14.6522C4.2104,14.7035 4.1673,14.7416 4.1138,14.7416L4.9069,14.7416C4.854,14.7416 4.8109,14.7035 4.8109,14.6522C4.8109,14.6435 4.8109,14.6385 4.8136,14.6298C4.8087,14.6309 4.8033,14.6309 4.7978,14.6309L4.2202,14.6309C4.2158,14.6309 4.2098,14.6309 4.206,14.6298" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.0985,14.8537L4.1154,14.8537C4.1113,14.8537 4.1073,14.8477 4.1073,14.8397C4.1073,14.8357 4.1107,14.8257 4.1154,14.8257C4.1769,14.8257 4.2269,14.7577 4.2269,14.6757C4.2269,14.6637 4.2269,14.6567 4.2236,14.6487L4.2222,14.6367C4.2222,14.6347 4.2222,14.6287 4.2242,14.6287C4.2263,14.6247 4.2297,14.6227 4.233,14.6247C4.2364,14.6287 4.2425,14.6287 4.2472,14.6287L4.9633,14.6287C4.9687,14.6287 4.9748,14.6287 4.9788,14.6247C4.9822,14.6227 4.9856,14.6247 4.9869,14.6287C4.9903,14.6287 4.9903,14.6347 4.9903,14.6367C4.9883,14.6527 4.9869,14.6597 4.9869,14.6757C4.9869,14.7577 5.0376,14.8257 5.0985,14.8257C5.1032,14.8257 5.1073,14.8357 5.1073,14.8397C5.1066,14.8477 5.1032,14.8537 5.0985,14.8537ZM4.1803,14.8267L5.0349,14.8267C4.995,14.7997 4.9707,14.7427 4.9707,14.6767C4.9707,14.6667 4.9714,14.6587 4.9714,14.6537C4.9687,14.6537 4.9673,14.6537 4.9633,14.6537L4.2472,14.6537C4.2459,14.6537 4.2439,14.6537 4.2418,14.6537C4.2418,14.6597 4.2432,14.6677 4.2432,14.6767C4.2439,14.7427 4.2182,14.7987 4.1803,14.8267Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.2202,14.5785L4.7978,14.5785C4.8169,14.5785 4.8327,14.59 4.8327,14.6058C4.8327,14.6184 4.8169,14.6315 4.7978,14.6315L4.2202,14.6315C4.2005,14.6315 4.1847,14.6189 4.1847,14.6058C4.1847,14.59 4.2005,14.5785 4.2202,14.5785" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.1142,14.6969L4.2419,14.6969C4.2065,14.6969 4.1776,14.6699 4.1776,14.6339C4.1776,14.6009 4.2065,14.5709 4.2419,14.5709L5.1142,14.5709C5.1488,14.5709 5.1776,14.5999 5.1776,14.6339C5.1776,14.6699 5.1488,14.6969 5.1142,14.6969ZM4.2419,14.5969C4.2188,14.5969 4.1991,14.6109 4.1991,14.6339C4.1991,14.6549 4.2188,14.6729 4.2419,14.6729L5.1142,14.6729C5.1381,14.6729 5.157,14.6539 5.157,14.6339C5.157,14.6109 5.1381,14.5969 5.1142,14.5969L4.2419,14.5969Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.1138,14.9462l0.7925,0l0,-0.2045l-0.7925,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.1073,15.1305L4.1073,15.1305L4.1073,14.7345L5.1073,14.7345L5.1073,15.1305ZM4.1242,15.1075L5.091,15.1075L5.091,14.7615L4.1242,14.7615L4.1242,15.1075Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M4.0527,13.864C3.9742,13.9098 3.9218,13.9535 3.9295,13.978C3.9344,14.0004 3.9589,14.0156 3.9949,14.0385C4.0495,14.0767 4.0844,14.146 4.0576,14.1793C4.1035,14.1411 4.1329,14.0865 4.1329,14.026C4.1329,13.96 4.1029,13.9011 4.0527,13.864" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.1795,14.4573L4.1614,14.4413C4.1765,14.4253 4.1765,14.4023 4.1734,14.3813C4.1665,14.3193 4.1144,14.2453 4.0484,14.1983L4.0415,14.1973C3.9795,14.1523 3.9345,14.1263 3.9245,14.0823C3.8995,14.0123 4.0954,13.8943 4.1565,13.8613L4.1614,13.8553L4.1674,13.8633C4.2664,13.9333 4.3205,14.0453 4.3205,14.1683C4.3215,14.2793 4.2695,14.3853 4.1795,14.4573ZM4.1614,13.8873C4.0075,13.9753 3.9385,14.0513 3.9475,14.0753C3.9555,14.1103 3.9975,14.1393 4.0554,14.1773L4.0615,14.1813C4.1335,14.2343 4.1905,14.3133 4.1975,14.3803C4.1995,14.3883 4.1995,14.4003 4.1985,14.4063C4.2605,14.3413 4.2955,14.2563 4.2955,14.1693C4.2965,14.0563 4.2485,13.9553 4.1614,13.8873Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:pathData="M4.2289,14.5447l0.5618,0l0,-2.7545l-0.5618,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.7622,14.5415L4.7382,14.5415L4.7382,11.7929L4.7612,11.7929L4.7612,14.5415L4.7622,14.5415ZM4.6462,14.5415L4.6222,14.5415L4.6222,11.7929L4.6462,11.7929L4.6462,14.5415Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.2218,14.5529L4.2218,14.5529L4.2218,11.7825L5.2218,11.7825L5.2218,14.5529ZM4.2455,14.5387L5.1981,14.5387L5.1981,11.7962L4.2455,11.7962L4.2455,14.5387Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M5.3651,12.8211C5.2418,12.7698 5.0345,12.7338 4.7945,12.7245C4.7116,12.7251 4.6195,12.7338 4.5251,12.7491C4.188,12.8031 3.9316,12.9395 3.9529,13.0469C3.9535,13.0513 3.954,13.0562 3.954,13.0578C3.954,13.0578 3.8285,12.7736 3.8264,12.7633C3.8035,12.6411 4.0882,12.4922 4.4624,12.43C4.5785,12.4104 4.6925,12.4027 4.7918,12.4044C5.0313,12.4044 5.2391,12.4338 5.364,12.4813L5.3651,12.8211" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M3.954,13.3948C3.9513,13.3948 3.9491,13.3916 3.9475,13.385C3.9267,13.3166 3.8215,12.9608 3.8198,12.9445C3.8144,12.9079 3.8225,12.8679 3.8416,12.8272C3.9164,12.6676 4.1651,12.5064 4.4602,12.4355C4.5638,12.4103 4.6735,12.3956 4.7755,12.3956L4.7918,12.3956C5.0215,12.3956 5.2358,12.4421 5.3667,12.5121C5.3689,12.5153 5.3705,12.5202 5.3705,12.5227L5.3727,13.0308C5.3727,13.0357 5.3705,13.0357 5.3695,13.0398C5.3673,13.0406 5.3645,13.0406 5.3629,13.0406C5.2364,12.9616 5.0236,12.9087 4.7945,12.8973C4.7089,12.8989 4.6162,12.9087 4.5262,12.9323C4.2644,12.9974 4.0429,13.1359 3.9764,13.2759C3.9611,13.3093 3.9556,13.3411 3.9595,13.3663C3.9595,13.3712 3.9605,13.3793 3.9605,13.3818C3.9611,13.3859 3.9605,13.3924 3.9573,13.3956C3.9556,13.3948 3.9545,13.3948 3.954,13.3948ZM4.7749,12.4168C4.6724,12.4168 4.5638,12.4315 4.4618,12.4567C4.1711,12.5267 3.9251,12.6807 3.8515,12.8403C3.8351,12.8753 3.8285,12.9087 3.8324,12.9404C3.8351,12.9567 3.8962,13.1693 3.9458,13.3289C3.948,13.3101 3.9545,13.289 3.9655,13.2653C4.0336,13.1188 4.2573,12.9787 4.5229,12.9119C4.6151,12.8899 4.7084,12.8785 4.7945,12.8769C5.0198,12.8883 5.2293,12.9404 5.358,13.017L5.3575,12.5284C5.2271,12.4616 5.0165,12.4168 4.7918,12.4168L4.7749,12.4168Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M4.2273,13.1675C4.0718,13.1565 3.9649,13.1129 3.9529,13.0469C3.9431,12.9945 3.9955,12.9395 4.0898,12.8882C4.1324,12.8915 4.1793,12.8975 4.2289,12.8975L4.2273,13.1675" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.4749,13.4189L4.4609,13.4189C4.1569,13.3959 3.9689,13.3149 3.9469,13.1899C3.9279,13.0899 4.0209,12.9849 4.2049,12.8789L4.2079,12.8789L4.2369,12.8789C4.3069,12.8909 4.3839,12.8999 4.4659,12.8999L4.4779,12.8999L4.4749,13.4189ZM4.2129,12.9039C4.0409,12.9999 3.9549,13.1029 3.9709,13.1849C3.9899,13.2939 4.1689,13.3709 4.4489,13.3939L4.4509,12.9249C4.3739,12.9239 4.3009,12.9169 4.2329,12.9049L4.2129,12.9039Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M4.7913,12.9564C4.8889,12.9689 4.962,12.9945 4.9991,13.0245L5.0024,13.0305C5.0187,13.0671 4.9336,13.144 4.7913,13.2247L4.7913,12.9564" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M4.7842,13.4792L4.7862,12.9482L4.7992,12.9522C4.9792,12.9792 5.1182,13.0262 5.1842,13.0792L5.1892,13.0812L5.1952,13.0972C5.2432,13.1962 4.9372,13.3902 4.8032,13.4722L4.7842,13.4792ZM4.8092,12.9792L4.8092,13.4362C5.1082,13.2602 5.1922,13.1462 5.1722,13.1042L5.1662,13.0962C5.1032,13.0492 4.9782,13.0022 4.8092,12.9792Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M3.8771,13.6976C3.8629,13.6551 4.014,13.5656 4.2295,13.4855C4.3276,13.4505 4.4089,13.4135 4.5098,13.3693C4.8076,13.2373 5.028,13.084 5.0018,13.0311L4.9985,13.0251C5.0144,13.0376 5.0389,13.3093 5.0389,13.3093C5.0656,13.3605 4.8638,13.5095 4.5889,13.6415C4.5005,13.6829 4.3151,13.7511 4.2278,13.7822C4.0707,13.8367 3.9147,13.9387 3.9289,13.9769L3.8771,13.6976" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M3.93,14.0176C3.9278,14.0176 3.9251,14.0153 3.924,14.0108C3.9229,14.0108 3.9224,14.008 3.9224,14.0063L3.8711,13.7201C3.8525,13.6654 4.0375,13.5674 4.2278,13.4947C4.3173,13.4614 4.3925,13.4271 4.4809,13.3859L4.5065,13.3752C4.7656,13.2569 4.9702,13.1217 4.9958,13.0524C4.998,13.045 4.998,13.0394 4.9958,13.0338L4.9925,13.0293C4.9915,13.0259 4.9925,13.0202 4.9947,13.0202C4.9964,13.0174 5.0007,13.0174 5.0024,13.0202C5.0045,13.0202 5.0056,13.0214 5.0067,13.027L5.0084,13.0293C5.0089,13.031 5.01,13.0338 5.0111,13.0372C5.0247,13.0912 5.0405,13.2451 5.0465,13.32C5.0504,13.3245 5.0504,13.333 5.0471,13.3454C5.0247,13.4124 4.8333,13.5488 4.5933,13.6677C4.5076,13.7094 4.3249,13.782 4.2305,13.8142C4.0784,13.8694 3.936,13.9669 3.9349,14.0057L3.936,14.0097C3.9371,14.0114 3.9344,14.0164 3.9305,14.0181C3.9316,14.0176 3.9311,14.0176 3.93,14.0176ZM5.0035,13.0687C4.9642,13.1414 4.7662,13.271 4.5131,13.3871L4.4864,13.3989C4.398,13.4383 4.3216,13.475 4.2322,13.5076C3.9927,13.5984 3.8744,13.684 3.8842,13.7184C3.8842,13.7189 3.8842,13.7201 3.8842,13.7201L3.9316,13.9798C3.9676,13.9269 4.1073,13.8446 4.2256,13.8006C4.3216,13.7685 4.5033,13.697 4.5873,13.6541C4.8213,13.5398 5.0133,13.4034 5.0345,13.338C5.0356,13.3324 5.0356,13.3262 5.034,13.3228C5.0335,13.3223 5.0329,13.3211 5.0329,13.3194C5.0247,13.2259 5.0122,13.1217 5.0035,13.0687Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M4.1938,12.8807C4.2646,12.8337 4.3111,12.7817 4.2884,12.6857C4.2748,12.6207 4.238,12.6077 4.1818,12.6437L4.0849,12.7067L4.1722,13.0887C4.1818,13.0817 4.1915,13.0697 4.2017,13.0667C4.2113,13.0607 4.2215,13.0567 4.2317,13.0467L4.1938,12.8807L4.1938,12.8807ZM4.1512,12.6947L4.175,12.6827C4.196,12.6667 4.2193,12.6847 4.2295,12.7317C4.2374,12.7627 4.2346,12.8017 4.2108,12.8307C4.204,12.8357 4.1943,12.8457 4.1864,12.8497L4.1512,12.6947M4.4216,12.5367C4.4114,12.5447 4.4007,12.5477 4.3905,12.5507C4.3808,12.5527 4.3706,12.5547 4.3593,12.5587L4.4103,12.9547L4.5668,12.9017C4.5656,12.8957 4.5628,12.8817 4.5628,12.8777C4.5605,12.8707 4.5611,12.8567 4.5605,12.8497C4.5333,12.8657 4.5033,12.8807 4.467,12.8947L4.4216,12.5367M4.7374,12.8807C4.7669,12.7367 4.8026,12.5977 4.8394,12.4567C4.8326,12.4587 4.8264,12.4587 4.8196,12.4587C4.8128,12.4587 4.8066,12.4587 4.7998,12.4587C4.7811,12.5637 4.7578,12.6647 4.7334,12.7637C4.7034,12.6697 4.6699,12.5757 4.6461,12.4807C4.6337,12.4827 4.6206,12.4827 4.6087,12.4867C4.5968,12.4887 4.5838,12.4887 4.5707,12.4887C4.6172,12.6207 4.6603,12.7507 4.7023,12.8817C4.7074,12.8817 4.7136,12.8817 4.7198,12.8797C4.7261,12.8787 4.7317,12.8787 4.7374,12.8807M5.0673,12.5737C5.0724,12.5527 5.0787,12.5347 5.0849,12.5187C5.0753,12.5027 5.0492,12.4817 5.0186,12.4767C4.9557,12.4657 4.9188,12.5167 4.9137,12.5847C4.9046,12.7297 5.0322,12.7157 5.0277,12.8097C5.0254,12.8517 4.9999,12.8707 4.9738,12.8627C4.9449,12.8567 4.9228,12.8307 4.9188,12.7867L4.9114,12.7867C4.9069,12.8097 4.9012,12.8337 4.8944,12.8567C4.9126,12.8797 4.9381,12.8957 4.9613,12.8957C5.0265,12.9077 5.0764,12.8607 5.0821,12.7867C5.09,12.6477 4.9602,12.6427 4.9659,12.5637C4.9681,12.5287 4.9823,12.5047 5.0157,12.5107C5.0396,12.5187 5.0554,12.5397 5.0617,12.5727L5.0673,12.5737" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M9.6709,11.158C9.6709,11.158 9.6458,11.1858 9.6273,11.188C9.6082,11.1924 9.5853,11.1733 9.5853,11.1733C9.5853,11.1733 9.5684,11.1896 9.5476,11.1935C9.5275,11.2011 9.4996,11.1711 9.4996,11.1711C9.4996,11.1711 9.4795,11.2011 9.4615,11.2055C9.4445,11.2142 9.4233,11.1978 9.4233,11.1978C9.4233,11.1978 9.4151,11.2115 9.4009,11.218C9.3944,11.2213 9.384,11.2169 9.384,11.2169L9.3622,11.2044L9.3393,11.1787L9.3169,11.17C9.3169,11.17 9.3071,11.1384 9.3071,11.134C9.306,11.1275 9.3044,11.1144 9.3044,11.1144C9.2995,11.0904 9.3338,11.0647 9.384,11.0533C9.4124,11.0478 9.4364,11.0478 9.4544,11.0522C9.474,11.038 9.516,11.0255 9.5667,11.0255C9.6109,11.0255 9.6496,11.0353 9.6709,11.0495C9.6916,11.0353 9.7309,11.0255 9.7756,11.0255C9.8253,11.0255 9.8667,11.0375 9.8864,11.0522C9.9049,11.0478 9.9289,11.0478 9.9573,11.0533C10.0075,11.0647 10.0418,11.0904 10.0369,11.1144C10.0369,11.1144 10.0358,11.1275 10.0342,11.134C10.0336,11.1389 10.0233,11.17 10.0233,11.17L10.0015,11.1787L9.9785,11.2044L9.9578,11.2169C9.9578,11.2169 9.9469,11.2213 9.9409,11.218C9.9273,11.2115 9.918,11.1978 9.918,11.1978C9.918,11.1978 9.8967,11.2136 9.8793,11.2055C9.8618,11.2011 9.8422,11.1711 9.8422,11.1711C9.8422,11.1711 9.8144,11.2011 9.7931,11.1935C9.7735,11.1896 9.7565,11.1733 9.7565,11.1733C9.7565,11.1733 9.7331,11.1924 9.7145,11.188C9.696,11.1858 9.6709,11.158 9.6709,11.158" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.1701,11.3946C10.1664,11.3946 10.1627,11.3926 10.1613,11.3906C10.1452,11.3786 10.1356,11.3636 10.1312,11.3556C10.1224,11.3576 10.1085,11.3736 10.0924,11.3736C10.0887,11.3736 10.0828,11.3716 10.0777,11.3676C10.0579,11.3556 10.0367,11.3266 10.0286,11.3086C10.0191,11.3226 9.9941,11.3496 9.9714,11.3496C9.9685,11.3496 9.9656,11.3496 9.9641,11.3476C9.9414,11.3376 9.9216,11.3186 9.9142,11.3086C9.904,11.3196 9.8783,11.3416 9.8571,11.3336C9.8351,11.3306 9.8094,11.2986 9.7999,11.2836C9.7882,11.2986 9.7625,11.3306 9.7405,11.3336C9.7193,11.3416 9.6936,11.3186 9.6848,11.3086C9.676,11.3186 9.6569,11.3376 9.6342,11.3476C9.6335,11.3496 9.6284,11.3496 9.6262,11.3496C9.6034,11.3496 9.5785,11.3226 9.5682,11.3086C9.5595,11.3266 9.5382,11.3556 9.5199,11.3676C9.5147,11.3716 9.5089,11.3736 9.5045,11.3736C9.4891,11.3736 9.4737,11.3576 9.4664,11.3556C9.4612,11.3636 9.4524,11.3786 9.4378,11.3906C9.4268,11.3966 9.4106,11.3866 9.4099,11.3846L9.3791,11.3576L9.3491,11.3146L9.3183,11.3026L9.3183,11.2966C9.3161,11.2866 9.3044,11.2376 9.3022,11.2286C9.3014,11.2166 9.2985,11.1916 9.2985,11.1916C9.2926,11.1446 9.3403,11.0916 9.4106,11.0736C9.4473,11.0606 9.481,11.0606 9.5074,11.0686C9.5367,11.0396 9.5932,11.0216 9.6584,11.0216C9.7141,11.0216 9.7662,11.0336 9.7984,11.0616C9.8299,11.0336 9.8813,11.0216 9.9392,11.0216C10.0015,11.0216 10.0594,11.0396 10.0887,11.0686C10.1151,11.0606 10.1488,11.0606 10.1855,11.0736C10.2551,11.0926 10.3028,11.1446 10.2976,11.1916L10.294,11.2286C10.2918,11.2386 10.2808,11.2876 10.2778,11.2966L10.2771,11.3026L10.2463,11.3146L10.2155,11.3596L10.1869,11.3826C10.1869,11.3846 10.1789,11.3946 10.1701,11.3946ZM10.1356,11.3316L10.1378,11.3366C10.1378,11.3386 10.1488,11.3596 10.1657,11.3736C10.1657,11.3736 10.1671,11.3766 10.1693,11.3766C10.1737,11.3766 10.1803,11.3736 10.1825,11.3736L10.2082,11.3506L10.2412,11.3036L10.2683,11.2876C10.272,11.2676 10.28,11.2326 10.2808,11.2246L10.2852,11.1886C10.2888,11.1506 10.2434,11.1076 10.1818,11.0916C10.1474,11.0756 10.1129,11.0756 10.0887,11.0896L10.0865,11.0916L10.0828,11.0876C10.0572,11.0526 10.0015,11.0346 9.9392,11.0346C9.8813,11.0346 9.8299,11.0526 9.8014,11.0756L9.7984,11.0796L9.7955,11.0756C9.7647,11.0526 9.7134,11.0346 9.6577,11.0346C9.5946,11.0346 9.5375,11.0526 9.5118,11.0876L9.5096,11.0916L9.5067,11.0896C9.4817,11.0756 9.448,11.0756 9.4128,11.0916C9.3527,11.1076 9.3058,11.1506 9.3102,11.1886C9.3102,11.1886 9.3139,11.2146 9.3139,11.2246C9.3153,11.2326 9.3234,11.2676 9.3278,11.2876L9.3571,11.3036L9.3872,11.3506L9.415,11.3736C9.4172,11.3736 9.4268,11.3786 9.4304,11.3736C9.448,11.3596 9.459,11.3386 9.459,11.3366L9.462,11.3316L9.4678,11.3346C9.4686,11.3346 9.4861,11.3536 9.503,11.3536C9.5067,11.3536 9.5118,11.3536 9.514,11.3506C9.5353,11.3386 9.5602,11.2896 9.5609,11.2876L9.5646,11.2826L9.5704,11.2876C9.5712,11.2876 9.6012,11.3316 9.6247,11.3316C9.6269,11.3316 9.6276,11.3316 9.6306,11.3296C9.6555,11.3226 9.6767,11.2896 9.6775,11.2896L9.6811,11.2856L9.6855,11.2876C9.6863,11.2896 9.7149,11.3266 9.7361,11.3206C9.7552,11.3106 9.7823,11.2796 9.7918,11.2636L9.794,11.2636L9.7984,11.2636L9.8014,11.2636C9.8021,11.2636 9.8329,11.3106 9.8571,11.3206C9.8798,11.3266 9.9076,11.2896 9.9076,11.2876L9.912,11.2856L9.9157,11.2896C9.9157,11.2896 9.937,11.3226 9.9619,11.3296C9.9648,11.3316 9.9648,11.3316 9.9678,11.3316C9.9905,11.3316 10.0213,11.2876 10.022,11.2876L10.0279,11.2826L10.0323,11.2876C10.0323,11.2896 10.0572,11.3386 10.0792,11.3506C10.0814,11.3536 10.085,11.3536 10.0894,11.3536C10.107,11.3536 10.1254,11.3346 10.1261,11.3346L10.1356,11.3316Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6224,11.0118C9.6224,10.9747 9.6436,10.9447 9.6693,10.9447C9.696,10.9447 9.7167,10.9747 9.7167,11.0118C9.7167,11.0495 9.696,11.0789 9.6693,11.0789C9.6436,11.0795 9.6224,11.05 9.6224,11.0118" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.713,11.2082C9.66,11.2082 9.618,11.1452 9.618,11.0732C9.618,11.0002 9.66,10.9382 9.713,10.9382C9.766,10.9382 9.81,11.0002 9.81,11.0732C9.81,11.1462 9.766,11.2082 9.713,11.2082ZM9.713,10.9562C9.671,10.9562 9.635,11.0072 9.635,11.0732C9.635,11.1372 9.67,11.1902 9.713,11.1902C9.759,11.1902 9.794,11.1372 9.794,11.0732C9.794,11.0072 9.758,10.9562 9.713,10.9562Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6496,11.0118C9.6496,10.9769 9.6589,10.9491 9.6709,10.9491C9.6824,10.9491 9.6927,10.9769 9.6927,11.0118C9.6927,11.0467 9.6829,11.074 9.6709,11.074C9.6589,11.0745 9.6496,11.0473 9.6496,11.0118" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.6932,11.1873C9.6602,11.1873 9.6442,11.1283 9.6442,11.0683C9.6442,11.0093 9.6612,10.9453 9.6932,10.9453C9.7242,10.9453 9.7412,11.0063 9.7412,11.0683C9.7412,11.1303 9.7252,11.1873 9.6932,11.1873ZM9.6932,10.9623C9.6792,10.9623 9.6592,10.9993 9.6592,11.0673C9.6592,11.1313 9.6792,11.1743 9.6932,11.1743C9.7062,11.1743 9.7242,11.1313 9.7242,11.0673C9.7252,10.9993 9.7072,10.9623 9.6932,10.9623Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.4255,11.29C9.4184,11.2687 9.4047,11.2535 9.4047,11.2535C9.4724,11.2327 9.5667,11.2196 9.6704,11.2196C9.774,11.2196 9.8695,11.2322 9.9376,11.2535C9.9376,11.2535 9.9289,11.266 9.9185,11.284C9.9125,11.2949 9.906,11.314 9.906,11.314C9.8449,11.2949 9.7669,11.284 9.6704,11.284C9.5738,11.284 9.4811,11.2949 9.4331,11.3162C9.4331,11.3156 9.4293,11.3031 9.4255,11.29L9.4255,11.29" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.4619,11.4048L9.4619,11.3988L9.4619,11.3988L9.4559,11.3988C9.4549,11.3948 9.4509,11.3798 9.439,11.3568L9.436,11.3438L9.437,11.3438C9.424,11.3128 9.4051,11.2888 9.4041,11.2888L9.3971,11.2808L9.4091,11.2768C9.5377,11.2368 9.7131,11.2158 9.8966,11.2158C10.082,11.2158 10.2565,11.2368 10.3851,11.2768L10.3971,11.2808L10.3572,11.3468C10.3492,11.3588 10.3363,11.3898 10.3353,11.3958L10.3283,11.3938L10.3253,11.4008C10.2146,11.3668 10.0701,11.3508 9.8966,11.3508C9.7251,11.3508 9.5566,11.3718 9.4679,11.4028L9.4669,11.4038L9.4619,11.4038L9.4619,11.4048ZM9.4599,11.3598C9.4629,11.3738 9.4669,11.3808 9.4669,11.3828C9.5606,11.3518 9.7251,11.3338 9.8956,11.3338C10.0671,11.3338 10.2097,11.3518 10.3203,11.3828C10.3243,11.3748 10.3323,11.3598 10.3433,11.3358L10.3712,11.2888C10.2445,11.2538 10.0741,11.2338 9.8956,11.2338C9.7181,11.2338 9.5506,11.2538 9.424,11.2888C9.431,11.3028 9.4459,11.3258 9.4539,11.3518L9.4599,11.3598L9.4599,11.3598Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6704,11.3762C9.7549,11.3762 9.8482,11.3636 9.882,11.3538C9.9049,11.3462 9.9185,11.338 9.9153,11.326C9.9153,11.3195 9.9087,11.3151 9.9027,11.3124C9.8525,11.2944 9.762,11.2835 9.6709,11.2835C9.5798,11.2835 9.4893,11.2944 9.4396,11.3124C9.4325,11.3156 9.4271,11.32 9.4271,11.326C9.4238,11.3375 9.4369,11.3462 9.4598,11.3538C9.4931,11.3636 9.5858,11.3762 9.6704,11.3762" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.8783,11.4622L9.8783,11.4622C9.7233,11.4622 9.5533,11.4392 9.4893,11.4232C9.4233,11.4032 9.4193,11.3762 9.4213,11.3622C9.4243,11.3492 9.4353,11.3372 9.4483,11.3292C9.5483,11.2982 9.7153,11.2802 9.8793,11.2802C10.0433,11.2802 10.2103,11.2982 10.3073,11.3292C10.3223,11.3372 10.3333,11.3502 10.3363,11.3622C10.3393,11.3762 10.3343,11.4032 10.2693,11.4232C10.2043,11.4392 10.0323,11.4622 9.8783,11.4622ZM9.8783,11.2982C9.7173,11.2982 9.5493,11.3182 9.4543,11.3452C9.4463,11.3512 9.4383,11.3552 9.4363,11.3662C9.4353,11.3782 9.4543,11.3972 9.4953,11.4082C9.5583,11.4232 9.7263,11.4462 9.8793,11.4462C10.0313,11.4462 10.2003,11.4232 10.2633,11.4082C10.3043,11.3972 10.3223,11.3782 10.3203,11.3662C10.3183,11.3542 10.3103,11.3502 10.3013,11.3452C10.2073,11.3182 10.0403,11.2982 9.8783,11.2982Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M9.8744,11.0418C9.8744,11.0342 9.882,11.026 9.8896,11.026C9.8995,11.026 9.9055,11.0347 9.9055,11.0418C9.9055,11.0505 9.8989,11.0576 9.8896,11.0576C9.882,11.0576 9.8744,11.0505 9.8744,11.0418" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.293,11.3C10.291,11.3 10.289,11.3 10.288,11.3C10.285,11.296 10.282,11.288 10.284,11.286C10.293,11.263 10.298,11.241 10.298,11.22C10.298,11.122 10.221,11.047 10.127,11.047C10.098,11.047 10.07,11.052 10.043,11.068C10.041,11.073 10.036,11.071 10.032,11.068C10.03,11.064 10.031,11.056 10.035,11.052C10.063,11.04 10.094,11.029 10.126,11.029C10.229,11.029 10.314,11.115 10.314,11.22C10.314,11.245 10.31,11.269 10.299,11.292C10.3,11.299 10.294,11.3 10.293,11.3ZM9.98,11.167L9.965,11.16C9.975,11.141 9.981,11.123 9.981,11.107C9.981,11.039 9.909,10.982 9.821,10.982C9.784,10.982 9.749,10.994 9.721,11.009L9.714,10.997C9.743,10.976 9.782,10.966 9.821,10.966C9.919,10.966 9.997,11.029 9.997,11.107C9.996,11.123 9.99,11.146 9.98,11.167Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.9404,11.2158L9.9202,11.1973C9.9202,11.1973 9.9005,11.2087 9.876,11.2049C9.8509,11.2005 9.8438,11.1727 9.8438,11.1727C9.8438,11.1727 9.8155,11.194 9.7925,11.1918C9.7702,11.1907 9.7565,11.1727 9.7565,11.1727C9.7565,11.1727 9.7325,11.1891 9.7096,11.1875C9.6884,11.1864 9.6682,11.1585 9.6682,11.1585C9.6682,11.1585 9.6458,11.1875 9.6251,11.1875C9.6044,11.1907 9.5858,11.1695 9.5858,11.1695C9.5858,11.1695 9.5755,11.1907 9.5493,11.194C9.5215,11.2005 9.4985,11.1749 9.4985,11.1749C9.4985,11.1749 9.4827,11.2005 9.4636,11.2049C9.4445,11.2136 9.4211,11.1951 9.4211,11.1951C9.4211,11.1951 9.4167,11.2049 9.414,11.2109C9.4113,11.2164 9.4025,11.2175 9.4025,11.2175L9.4091,11.2333C9.4767,11.2131 9.5673,11.2016 9.6704,11.2016C9.7735,11.2016 9.8667,11.2131 9.9333,11.2333L9.9404,11.2158" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.3832,11.3115L10.3742,11.3115C10.2488,11.2725 10.0797,11.2505 9.8966,11.2485C9.7185,11.2505 9.5483,11.2715 9.423,11.3115L9.415,11.3115L9.3971,11.2645L9.409,11.2645C9.411,11.2645 9.421,11.2625 9.422,11.2545C9.4269,11.2465 9.4349,11.2275 9.4349,11.2275L9.4389,11.2205L9.4468,11.2255C9.4468,11.2255 9.4757,11.2445 9.5026,11.2445C9.5085,11.2445 9.5145,11.2445 9.5185,11.2415C9.5493,11.2295 9.5762,11.1885 9.5762,11.1885L9.5812,11.1785L9.5901,11.1865C9.5901,11.1865 9.6309,11.2275 9.6737,11.2235C9.7185,11.2175 9.7354,11.1785 9.7354,11.1785L9.7414,11.1705L9.7483,11.1785C9.7483,11.1785 9.7782,11.2155 9.813,11.2115C9.8488,11.2055 9.8866,11.1585 9.8866,11.1565L9.8926,11.1515L9.8976,11.1565C9.8976,11.1585 9.9334,11.2035 9.9682,11.2095C9.9712,11.2095 9.9732,11.2095 9.9732,11.2095C10.008,11.2095 10.0478,11.1785 10.0488,11.1785L10.0548,11.1765L10.0588,11.1825C10.0598,11.1825 10.0827,11.2175 10.1195,11.2175C10.1205,11.2175 10.1225,11.2175 10.1245,11.2175C10.1593,11.2175 10.206,11.1805 10.206,11.1805L10.215,11.1735L10.217,11.1865C10.217,11.1875 10.2309,11.2375 10.2687,11.2415C10.3105,11.2475 10.3453,11.2255 10.3453,11.2255L10.3503,11.2235L10.3891,11.2625L10.3971,11.2625L10.3832,11.3115ZM9.8966,11.2375C10.0757,11.2375 10.2439,11.2575 10.3712,11.2935L10.3792,11.2715L10.3503,11.2455C10.3414,11.2505 10.3185,11.2625 10.2896,11.2625C10.2837,11.2625 10.2767,11.2625 10.2697,11.2605C10.2329,11.2505 10.214,11.2225 10.207,11.2035C10.1891,11.2195 10.1543,11.2425 10.1195,11.2385C10.0856,11.2345 10.0608,11.2125 10.0508,11.2015C10.0379,11.2095 10.0021,11.2265 9.9682,11.2265C9.9354,11.2245 9.9046,11.1955 9.8926,11.1795C9.8797,11.1955 9.8468,11.2245 9.815,11.2265C9.812,11.2265 9.811,11.2265 9.809,11.2265C9.7812,11.2265 9.7553,11.2085 9.7444,11.2005C9.7344,11.2135 9.7135,11.2325 9.6767,11.2425C9.6359,11.2475 9.5991,11.2195 9.5832,11.2035C9.5722,11.2195 9.5493,11.2485 9.5225,11.2595C9.5165,11.2625 9.5085,11.2645 9.5016,11.2645C9.4787,11.2645 9.4568,11.2505 9.4449,11.2455C9.4439,11.2505 9.4389,11.2605 9.4369,11.2665C9.4319,11.2725 9.4269,11.2745 9.42,11.2785L9.4259,11.2955C9.5553,11.2575 9.7195,11.2375 9.8966,11.2375Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M9.4325,11.0418C9.4325,11.0342 9.4396,11.026 9.4484,11.026C9.4582,11.026 9.4647,11.0347 9.4647,11.0418C9.4647,11.0505 9.4582,11.0576 9.4484,11.0576C9.4396,11.0576 9.4325,11.0505 9.4325,11.0418" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.3194,11.3C9.3154,11.3 9.3134,11.298 9.3104,11.292C9.3024,11.269 9.2984,11.243 9.2984,11.22C9.2984,11.115 9.3804,11.029 9.4864,11.029C9.5154,11.029 9.5494,11.041 9.5764,11.052C9.5804,11.056 9.5814,11.064 9.5804,11.068C9.5784,11.071 9.5734,11.073 9.5684,11.068C9.5434,11.052 9.5154,11.047 9.4864,11.047C9.3914,11.047 9.3144,11.122 9.3144,11.22C9.3144,11.241 9.3184,11.263 9.3274,11.286C9.3274,11.29 9.3274,11.296 9.3224,11.3C9.3214,11.3 9.3214,11.3 9.3194,11.3ZM9.6324,11.165C9.6234,11.146 9.6144,11.125 9.6144,11.107C9.6144,11.029 9.6924,10.966 9.7904,10.966C9.8304,10.966 9.8664,10.977 9.8984,10.997L9.8894,11.009C9.8604,10.993 9.8254,10.982 9.7904,10.982C9.7024,10.982 9.6314,11.039 9.6314,11.107C9.6314,11.123 9.6374,11.138 9.6484,11.156L9.6324,11.165Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6715,11.1264L9.6813,11.128C9.6791,11.1313 9.6785,11.1367 9.6785,11.1405C9.6785,11.1618 9.6965,11.1771 9.7167,11.1771C9.7347,11.1771 9.7489,11.1656 9.7544,11.1515C9.7549,11.152 9.7582,11.1378 9.7587,11.1389C9.7609,11.1389 9.7604,11.152 9.7609,11.152C9.7631,11.17 9.78,11.1831 9.7991,11.1831C9.8198,11.1831 9.8373,11.1662 9.8373,11.1482C9.8373,11.1455 9.8373,11.1427 9.8373,11.1405L9.8487,11.1291L9.8553,11.146C9.8531,11.1493 9.8515,11.1547 9.8515,11.1618C9.8515,11.1787 9.8684,11.1962 9.8885,11.1962C9.9011,11.1962 9.9125,11.1902 9.9191,11.1787L9.9273,11.1711L9.9273,11.1825C9.9273,11.194 9.9322,11.2038 9.9436,11.2071C9.9436,11.2071 9.9573,11.2082 9.9758,11.1935C9.9944,11.1787 10.0042,11.1667 10.0042,11.1667L10.0042,11.1825C10.0042,11.1825 9.9873,11.2125 9.9709,11.2207C9.9627,11.2251 9.9485,11.2295 9.9376,11.2295C9.9273,11.2278 9.9185,11.218 9.9147,11.2082C9.9065,11.2125 9.8973,11.2158 9.8869,11.2158C9.8656,11.2158 9.8455,11.2044 9.8378,11.1869C9.8285,11.1978 9.8144,11.2027 9.7975,11.2027C9.7805,11.2027 9.7647,11.1951 9.7549,11.1836C9.7456,11.1913 9.7315,11.1995 9.7167,11.1995C9.6976,11.1995 9.6807,11.188 9.6709,11.1738C9.6611,11.188 9.6436,11.1995 9.6245,11.1995C9.6104,11.1995 9.5967,11.1907 9.5864,11.1836C9.576,11.1951 9.5607,11.2027 9.5444,11.2027C9.5275,11.2027 9.5127,11.1973 9.5029,11.1869C9.4958,11.2038 9.4762,11.2158 9.4549,11.2158C9.4445,11.2158 9.4358,11.2125 9.4265,11.2082C9.4233,11.218 9.4145,11.2278 9.4036,11.2295C9.3927,11.2295 9.3791,11.2251 9.3709,11.2207C9.3545,11.212 9.336,11.1825 9.336,11.1825L9.3376,11.1667C9.3376,11.1667 9.348,11.1782 9.3655,11.1935C9.3845,11.2082 9.3976,11.2071 9.3976,11.2071C9.4096,11.2038 9.414,11.1945 9.414,11.1825L9.414,11.1711L9.4227,11.1787C9.4298,11.1902 9.4396,11.1962 9.4522,11.1962C9.4735,11.1962 9.4904,11.1787 9.4904,11.1618C9.4904,11.1542 9.4882,11.1493 9.486,11.146L9.4925,11.1291L9.504,11.1405C9.5035,11.1427 9.5035,11.1455 9.5035,11.1482C9.5035,11.1662 9.5215,11.1831 9.5416,11.1831C9.5607,11.1831 9.5776,11.1705 9.5798,11.152C9.5809,11.152 9.5804,11.1389 9.5825,11.1389C9.5836,11.1378 9.5864,11.152 9.5875,11.1515C9.5924,11.1656 9.6076,11.1771 9.6245,11.1771C9.6458,11.1771 9.6627,11.1618 9.6627,11.1405C9.6627,11.1362 9.6627,11.1307 9.6611,11.128L9.6715,11.1264" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.2323,11.3301C10.2283,11.3301 10.2275,11.3301 10.2243,11.3281C10.2098,11.3241 10.1962,11.3121 10.1881,11.2941C10.1777,11.2971 10.1632,11.3031 10.1504,11.3031C10.1206,11.3031 10.0917,11.2851 10.0773,11.2521C10.0604,11.2721 10.0411,11.2811 10.0186,11.2811C9.9937,11.2811 9.9704,11.2681 9.956,11.2481C9.9391,11.2661 9.9198,11.2711 9.8998,11.2711C9.8733,11.2711 9.8484,11.2551 9.8323,11.2321C9.8154,11.2551 9.7921,11.2711 9.764,11.2711C9.7455,11.2711 9.7255,11.2651 9.7094,11.2481C9.6933,11.2691 9.67,11.2811 9.646,11.2811C9.6227,11.2811 9.6042,11.2711 9.5873,11.2521C9.5721,11.2851 9.5439,11.3031 9.5142,11.3031C9.5006,11.3031 9.4869,11.2971 9.4765,11.2941C9.4668,11.3131 9.454,11.3241 9.4387,11.3281C9.4371,11.3301 9.4347,11.3301 9.4315,11.3301C9.413,11.3301 9.3937,11.3171 9.3873,11.3121C9.3624,11.2941 9.3343,11.2421 9.3327,11.2421L9.3311,11.2361L9.3383,11.1891L9.3472,11.2031C9.3472,11.2031 9.3616,11.2241 9.3873,11.2481C9.409,11.2701 9.4251,11.2711 9.4291,11.2711C9.4451,11.2681 9.4476,11.2421 9.4476,11.2341L9.4476,11.1871L9.4717,11.2241C9.4797,11.2421 9.4949,11.2491 9.5094,11.2491C9.5375,11.2491 9.5576,11.2241 9.5576,11.1941C9.5576,11.1801 9.5568,11.1751 9.5528,11.1711L9.5512,11.1651L9.5656,11.1241L9.5937,11.1551L9.5937,11.1571C9.5929,11.1611 9.5937,11.1651 9.5937,11.1691C9.5937,11.1991 9.6146,11.2261 9.6419,11.2261C9.6692,11.2261 9.6885,11.2031 9.6925,11.1771L9.6925,11.1711L9.6925,11.1711C9.6925,11.1521 9.6925,11.1461 9.7022,11.1461L9.7022,11.1461C9.707,11.1461 9.7102,11.1511 9.7126,11.1641L9.7166,11.1721C9.7215,11.1981 9.7407,11.2171 9.764,11.2171C9.7921,11.2171 9.8146,11.1881 9.8146,11.1561C9.8146,11.1481 9.8138,11.1401 9.8114,11.1331L9.8074,11.1251L9.8331,11.1231L9.8556,11.1251L9.8524,11.1331C9.8516,11.1421 9.8508,11.1491 9.8508,11.1561C9.8508,11.1871 9.8725,11.2171 9.8998,11.2171C9.9239,11.2171 9.9423,11.1981 9.948,11.1721L9.952,11.1641L9.952,11.1641C9.9544,11.1511 9.956,11.1461 9.9616,11.1461C9.9704,11.1461 9.9704,11.1541 9.9704,11.1711L9.9704,11.1741L9.9704,11.1771C9.9745,11.2021 9.9945,11.2261 10.0219,11.2261C10.0492,11.2261 10.0709,11.2001 10.0709,11.1691C10.0709,11.1651 10.0709,11.1611 10.07,11.1571L10.0692,11.1551L10.0974,11.1241L10.1118,11.1651L10.1118,11.1711C10.107,11.1761 10.107,11.1811 10.107,11.1941C10.107,11.2231 10.1271,11.2491 10.1544,11.2491C10.1696,11.2491 10.1849,11.2411 10.1929,11.2241L10.217,11.1871L10.2162,11.2341C10.2162,11.2421 10.2186,11.2651 10.2363,11.2711C10.2387,11.2711 10.2564,11.2701 10.2765,11.2481C10.3038,11.2251 10.3182,11.2031 10.3182,11.2031L10.3287,11.1851L10.3311,11.2381L10.3295,11.2401C10.3295,11.2421 10.303,11.2951 10.2781,11.3121C10.27,11.3171 10.2508,11.3301 10.2323,11.3301ZM10.1945,11.2701L10.1962,11.2771C10.1994,11.2891 10.209,11.3101 10.2259,11.3121C10.2275,11.3121 10.2291,11.3121 10.2315,11.3121C10.2419,11.3121 10.2556,11.3081 10.27,11.2961C10.2885,11.2841 10.3102,11.2411 10.3158,11.2301L10.3158,11.2261C10.3078,11.2361 10.299,11.2471 10.2837,11.2631C10.2596,11.2881 10.2395,11.2881 10.2331,11.2881L10.2331,11.2881C10.2146,11.2841 10.2026,11.2651 10.2018,11.2351C10.1897,11.2531 10.1713,11.2641 10.152,11.2641C10.119,11.2641 10.0909,11.2331 10.0909,11.1941C10.0909,11.1781 10.0917,11.1711 10.0949,11.1651L10.0909,11.1501L10.0813,11.1611C10.0813,11.1631 10.0813,11.1651 10.0813,11.1691C10.0813,11.2061 10.0532,11.2411 10.0194,11.2411C9.9873,11.2411 9.9632,11.2181 9.9568,11.1821C9.9472,11.2111 9.9247,11.2271 9.8974,11.2271C9.8644,11.2271 9.8355,11.1941 9.8355,11.1551C9.8355,11.1471 9.8363,11.1451 9.8363,11.1351L9.8315,11.1341L9.8235,11.1361C9.8243,11.1461 9.8251,11.1481 9.8251,11.1561C9.8251,11.1951 9.7962,11.2281 9.7624,11.2281C9.7359,11.2281 9.7134,11.2121 9.7038,11.1831C9.6974,11.2181 9.6725,11.2421 9.6411,11.2421C9.6074,11.2421 9.5785,11.2071 9.5785,11.1701C9.5785,11.1661 9.5785,11.1641 9.5785,11.1621L9.5688,11.1511L9.5648,11.1661C9.5688,11.1721 9.5688,11.1801 9.5688,11.1951C9.5688,11.2341 9.5423,11.2651 9.5078,11.2651C9.4893,11.2651 9.47,11.2531 9.4596,11.2361C9.4588,11.2651 9.446,11.2851 9.4275,11.2891L9.4275,11.2891C9.4219,11.2891 9.4018,11.2891 9.3761,11.2641C9.3616,11.2481 9.352,11.2351 9.3431,11.2271L9.3423,11.2311C9.3488,11.2431 9.3713,11.2861 9.3905,11.2971C9.4074,11.3111 9.4227,11.3161 9.4355,11.3131C9.4524,11.3111 9.4604,11.2901 9.4644,11.2781L9.4668,11.2711L9.4741,11.2741C9.4845,11.2841 9.4982,11.2901 9.5118,11.2901C9.5399,11.2901 9.5672,11.2671 9.5777,11.2391L9.5817,11.2271L9.5873,11.2361C9.6018,11.2531 9.6211,11.2661 9.6435,11.2661C9.6652,11.2661 9.6869,11.2501 9.6998,11.2291L9.7046,11.2251L9.7094,11.2271C9.7239,11.2461 9.7423,11.2521 9.7608,11.2521C9.7865,11.2521 9.8098,11.2421 9.8235,11.2171L9.8291,11.2031L9.8347,11.2171C9.8484,11.2421 9.8725,11.2521 9.8966,11.2521C9.915,11.2521 9.9343,11.2451 9.9488,11.2271L9.9528,11.2251L9.9576,11.2291C9.9713,11.2501 9.9929,11.2661 10.0154,11.2661C10.0371,11.2661 10.0564,11.2521 10.0709,11.2361L10.0773,11.2271L10.0805,11.2391C10.0917,11.2661 10.1174,11.2901 10.1472,11.2901C10.16,11.2901 10.1745,11.2841 10.1841,11.2741L10.1945,11.2701Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6704,11.2196C9.5667,11.2196 9.4729,11.2322 9.4053,11.2535C9.4009,11.2551 9.3949,11.2518 9.3944,11.2475C9.3922,11.2431 9.3955,11.2387 9.4009,11.2365C9.468,11.2158 9.5635,11.2022 9.6709,11.2022C9.7784,11.2022 9.8744,11.2158 9.9415,11.2365C9.9469,11.2387 9.9502,11.2431 9.9475,11.2475C9.9475,11.2518 9.9409,11.2551 9.9365,11.2535C9.8689,11.2327 9.774,11.2196 9.6704,11.2196" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.3632,11.3064C10.3622,11.3064 10.3603,11.3044 10.3564,11.3044C10.2335,11.2714 10.0679,11.2494 9.8889,11.2494C9.7098,11.2494 9.5462,11.2704 9.4213,11.3044C9.4097,11.3104 9.3942,11.3024 9.3904,11.2924C9.3875,11.2784 9.3923,11.2634 9.4058,11.2574C9.5346,11.2204 9.7049,11.1984 9.8889,11.1984C10.0718,11.1984 10.248,11.2214 10.3728,11.2574C10.3787,11.2594 10.3835,11.2674 10.3854,11.2734C10.3903,11.2794 10.3903,11.2834 10.3883,11.2934C10.3845,11.3014 10.3728,11.3064 10.3632,11.3064ZM9.8879,11.2314C10.067,11.2314 10.2373,11.2524 10.3622,11.2924L10.3632,11.2924C10.367,11.2924 10.3738,11.2884 10.3738,11.2824C10.3738,11.2804 10.3738,11.2804 10.3728,11.2804C10.3719,11.2784 10.368,11.2754 10.368,11.2754C10.2431,11.2334 10.0689,11.2124 9.8889,11.2104C9.7059,11.2124 9.5356,11.2334 9.4097,11.2754C9.4078,11.2774 9.4039,11.2804 9.4039,11.2824C9.4049,11.2884 9.4097,11.2924 9.4146,11.2924C9.5404,11.2524 9.7088,11.2314 9.8879,11.2314Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M9.5695,11.2562C9.5695,11.2518 9.576,11.2436 9.5847,11.2436C9.5924,11.2436 9.5989,11.2524 9.5989,11.2562C9.5989,11.2665 9.5918,11.2709 9.5847,11.2709C9.576,11.2709 9.5695,11.266 9.5695,11.2562" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M9.672,11.2644L9.6382,11.2644C9.6316,11.2644 9.6273,11.2578 9.6273,11.2529C9.6273,11.2469 9.6316,11.2415 9.6382,11.2415L9.7064,11.2415C9.7124,11.2415 9.7173,11.2469 9.7173,11.2529C9.7173,11.2578 9.7124,11.2644 9.7064,11.2644L9.672,11.2644" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.7754,11.2933L9.6514,11.2933C9.6354,11.2933 9.6224,11.2813 9.6224,11.2653C9.6224,11.2463 9.6364,11.2393 9.6514,11.2393L9.7764,11.2393C9.7914,11.2393 9.8044,11.2473 9.8044,11.2653C9.8044,11.2813 9.7904,11.2933 9.7754,11.2933ZM9.6504,11.2523C9.6424,11.2523 9.6374,11.2603 9.6374,11.2653C9.6374,11.2703 9.6434,11.2763 9.6514,11.2763L9.7764,11.2763C9.7834,11.2763 9.7894,11.2703 9.7894,11.2653C9.7894,11.2603 9.7844,11.2523 9.7764,11.2523L9.6504,11.2523Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M9.5035,11.2775L9.4805,11.2791C9.474,11.2802 9.468,11.2775 9.468,11.2687C9.4664,11.2644 9.4707,11.2578 9.4773,11.2573L9.5002,11.2551L9.5258,11.2518C9.5324,11.2518 9.5378,11.2535 9.5384,11.2595C9.5384,11.2649 9.5356,11.2693 9.5291,11.2709L9.5035,11.2775" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.4903,11.3143C9.4783,11.3143 9.4663,11.3043 9.4623,11.2893C9.4603,11.2863 9.4633,11.2813 9.4663,11.2713C9.4713,11.2653 9.4783,11.2623 9.4863,11.2603L9.5763,11.2453C9.5773,11.2453 9.5773,11.2453 9.5793,11.2453C9.5953,11.2453 9.6073,11.2573 9.6083,11.2683C9.6103,11.2803 9.6073,11.2853 9.6043,11.2883C9.6003,11.2963 9.5923,11.3043 9.5843,11.3043L9.4953,11.3123C9.4953,11.3123 9.4933,11.3143 9.4903,11.3143ZM9.5793,11.2633L9.4903,11.2793C9.4853,11.2813 9.4843,11.2813 9.4813,11.2813C9.4793,11.2843 9.4793,11.2873 9.4793,11.2893C9.4803,11.2953 9.4873,11.3033 9.4943,11.3013L9.5843,11.2873C9.5853,11.2863 9.5893,11.2843 9.5893,11.2813C9.5923,11.2813 9.5933,11.2773 9.5933,11.2733C9.5913,11.2653 9.5863,11.2633 9.5793,11.2633Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M9.4069,11.2927l0.0104,-0.0164l0.0229,0.0038l-0.0136,0.0185l-0.0196,-0.006" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M9.7418,11.2562C9.7418,11.2518 9.7489,11.2436 9.7565,11.2436C9.7653,11.2436 9.7713,11.2524 9.7713,11.2562C9.7713,11.2665 9.7647,11.2709 9.7565,11.2709C9.7489,11.2709 9.7418,11.266 9.7418,11.2562" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M9.8384,11.2775L9.8613,11.2791C9.8673,11.2802 9.8733,11.2775 9.8738,11.2687C9.8749,11.2644 9.8705,11.2578 9.8645,11.2573L9.8411,11.2551L9.8155,11.2518C9.8089,11.2518 9.804,11.2535 9.8029,11.2595C9.8029,11.2649 9.8062,11.2693 9.8122,11.2709L9.8384,11.2775" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.917,11.3146C9.915,11.3146 9.913,11.3126 9.912,11.3126L9.824,11.3046C9.816,11.3046 9.808,11.2966 9.804,11.2886C9.8,11.2836 9.798,11.2786 9.8,11.2686C9.8,11.2566 9.816,11.2416 9.831,11.2456L9.922,11.2606C9.929,11.2626 9.935,11.2656 9.941,11.2716C9.945,11.2816 9.947,11.2866 9.946,11.2896C9.942,11.3046 9.93,11.3146 9.917,11.3146ZM9.83,11.2636C9.822,11.2636 9.817,11.2656 9.815,11.2736C9.815,11.2776 9.815,11.2816 9.818,11.2816C9.818,11.2846 9.823,11.2866 9.825,11.2876L9.917,11.3016C9.923,11.3016 9.929,11.2956 9.929,11.2896C9.929,11.2876 9.929,11.2846 9.927,11.2816C9.924,11.2816 9.924,11.2816 9.918,11.2796L9.83,11.2636L9.83,11.2636Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M9.9322,11.2933l-0.0076,-0.0169l-0.024,0.0011l0.0115,0.0191l0.0202,-0.0033" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M9.6704,11.3571C9.5858,11.3565 9.5095,11.3484 9.4516,11.3325C9.5095,11.3189 9.5858,11.3091 9.6704,11.3091C9.7549,11.3091 9.8318,11.3189 9.8891,11.3325C9.8318,11.3489 9.7549,11.3565 9.6704,11.3571" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.8554,11.4063L9.8554,11.4063C9.6954,11.4063 9.5574,11.3943 9.4544,11.3673C9.4484,11.3653 9.4484,11.3613 9.4484,11.3553C9.4484,11.3533 9.4484,11.3503 9.4544,11.3503C9.5654,11.3243 9.7054,11.3063 9.8554,11.3053C10.0054,11.3053 10.1464,11.3243 10.2564,11.3503C10.2624,11.3503 10.2634,11.3533 10.2634,11.3553C10.2634,11.3613 10.2634,11.3653 10.2564,11.3673C10.1544,11.3943 10.0154,11.4063 9.8554,11.4063ZM9.4894,11.3553C9.5884,11.3783 9.7134,11.3923 9.8554,11.3943C9.9974,11.3923 10.1224,11.3783 10.2214,11.3553C10.1164,11.3323 9.9874,11.3243 9.8554,11.3243C9.7244,11.3243 9.5954,11.3323 9.4894,11.3553Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.936,11.1749C9.9376,11.1662 9.936,11.1624 9.9311,11.1602C9.9267,11.158 9.9213,11.1624 9.9185,11.1678C9.9169,11.1755 9.9185,11.1804 9.9235,11.1836C9.9278,11.1847 9.9338,11.1793 9.936,11.1749" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.768,11.1411C9.7691,11.1367 9.7653,11.1285 9.7615,11.1285C9.7555,11.1285 9.7511,11.1335 9.7505,11.14C9.7489,11.1476 9.7522,11.1525 9.7587,11.1525C9.762,11.1536 9.768,11.1493 9.768,11.1411" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.5733,11.1411C9.5733,11.1367 9.576,11.1285 9.5809,11.1285C9.5858,11.1285 9.5907,11.1335 9.5918,11.14C9.5924,11.1476 9.5891,11.1525 9.5842,11.1525C9.5798,11.1536 9.5744,11.1493 9.5733,11.1411" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.4064,11.1749C9.4036,11.1662 9.4064,11.1624 9.4102,11.1602C9.4156,11.158 9.4211,11.1624 9.4227,11.1678C9.4255,11.1755 9.4227,11.1804 9.4189,11.1836C9.4135,11.1847 9.408,11.1793 9.4064,11.1749" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6704,11.0462l-0.0305,0.0169l0.0229,0.048l0.0076,0.0044l0.0082,-0.0044l0.0229,-0.048l-0.0311,-0.0169" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.7004,11.1915L9.6794,11.1765L9.6344,11.0775L9.6994,11.0385L9.7644,11.0775L9.7204,11.1765L9.7004,11.1915ZM9.6914,11.1655L9.7004,11.1715L9.7084,11.1655L9.7454,11.0855L9.7014,11.0605L9.6574,11.0855L9.6914,11.1655Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6049,11.1155l0.0131,0.0213l0.0469,-0.0125l0.0038,-0.0087l-0.0038,-0.0044l-0.0469,-0.0147l-0.0131,0.0191" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.6315,11.1838l-0.032,-0.047l0.032,-0.047l0.094,0.027l0.013,0.02l-0.014,0.021z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.7358,11.1155l-0.0131,0.0213l-0.0469,-0.0125l-0.0044,-0.0087l0.0044,-0.0044l0.0469,-0.0147l0.0131,0.0191" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.7715,11.1838L9.6785,11.1578L9.6655,11.1368L9.6785,11.1168L9.7715,11.0898L9.8045,11.1368L9.7715,11.1838ZM9.6895,11.1408L9.7665,11.1658L9.7845,11.1368L9.7655,11.1118L9.6885,11.1338L9.6845,11.1368L9.6895,11.1408Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.4773,11.0642l-0.0229,0.024l0.0289,0.0387l0.0082,0.0022l0.0055,-0.0055l0.0109,-0.0469l-0.0305,-0.0125" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.5304,11.2008l-0.023,-0.012l-0.059,-0.077l0.052,-0.052l0.066,0.026l-0.02,0.097z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.4293,11.1455l0.0164,0.0169l0.0425,-0.024l0.0033,-0.0082l-0.0055,-0.0049l-0.0485,-0.0027l-0.0082,0.0229" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.4642,11.2095l-0.042,-0.037l0.021,-0.057l0.097,0.012l0.018,0.012l-0.009,0.023z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.5564,11.1187l-0.0087,0.0224l-0.048,-0.0044l-0.0065,-0.0065l0.0033,-0.0065l0.0415,-0.0224l0.0185,0.0175" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.6035,11.1884l-0.099,-0.01l-0.018,-0.016l0.011,-0.021l0.084,-0.045l0.041,0.039z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.3813,11.1509l-0.0033,0.024l-0.0485,0.0044l-0.0076,-0.0044l0.0022,-0.0087l0.036,-0.03l0.0213,0.0147" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.3375,11.2277l-0.02,-0.011l0.005,-0.023l0.072,-0.063l0.05,0.035l-0.01,0.053z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.4745,11.1302C9.4745,11.1236 9.4827,11.1155 9.4925,11.1155C9.5018,11.1155 9.5095,11.1242 9.5095,11.1302C9.5095,11.14 9.5018,11.1482 9.4925,11.1482C9.4827,11.1482 9.4745,11.14 9.4745,11.1302" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.8635,11.0642l0.0235,0.024l-0.03,0.0387l-0.0076,0.0022l-0.0055,-0.0055l-0.0115,-0.0469l0.0311,-0.0125" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.8641,11.2008l-0.015,-0.018l-0.02,-0.097l0.066,-0.026l0.051,0.052l-0.059,0.077z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.9131,11.1455l-0.0175,0.0169l-0.042,-0.024l-0.0033,-0.0082l0.006,-0.0049l0.0485,-0.0027l0.0082,0.0229" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.9379,11.2095l-0.083,-0.047l-0.01,-0.023l0.018,-0.012l0.098,-0.012l0.019,0.057z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.7855,11.1187l0.0087,0.0224l0.0485,-0.0044l0.006,-0.0065l-0.0033,-0.0065l-0.0425,-0.0224l-0.0175,0.0175" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.8005,11.1884l-0.02,-0.053l0.042,-0.039l0.084,0.045l0.01,0.021l-0.018,0.016z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.9535,11.1509l0.0033,0.024l0.048,0.0044l0.0082,-0.0044l-0.0022,-0.0087l-0.036,-0.03l-0.0213,0.0147" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.0555,11.2282l-0.098,-0.01l-0.01,-0.053l0.05,-0.035l0.072,0.063l0.005,0.023z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6529,11.1155C9.6529,11.1067 9.6611,11.1002 9.6704,11.1002C9.6796,11.1002 9.6878,11.1073 9.6878,11.1155C9.6878,11.1236 9.6796,11.1324 9.6704,11.1324C9.6611,11.1324 9.6529,11.1242 9.6529,11.1155" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.8318,11.1302C9.8318,11.1236 9.8405,11.1155 9.8498,11.1155C9.8591,11.1155 9.8673,11.1242 9.8673,11.1302C9.8673,11.14 9.8591,11.1482 9.8498,11.1482C9.8405,11.1482 9.8318,11.14 9.8318,11.1302" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6387,10.9349C9.6387,10.9196 9.6524,10.9055 9.6704,10.9055C9.6878,10.9055 9.7025,10.9191 9.7025,10.9349C9.7025,10.9491 9.6878,10.9633 9.6704,10.9633C9.6529,10.9633 9.6387,10.9491 9.6387,10.9349" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.6933,10.9235l0,0.0213l-0.0496,0l0,-0.0213l0.0158,0l0,-0.0447l-0.0207,0l0,-0.0202l0.0207,0l0,-0.0202l0.0224,0l0,0.0202l0.0202,0l0,0.0202l-0.0202,0l0,0.0447l0.0115,0" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.7513,11.0459L9.6433,11.0459L9.6433,10.9909L9.6723,10.9909L9.6723,10.9259L9.6333,10.9259L9.6333,10.8719L9.6723,10.8719L9.6723,10.8329L9.7303,10.8329L9.7303,10.8719L9.7693,10.8719L9.7693,10.9259L9.7303,10.9259L9.7303,10.9909L9.7513,10.9909L9.7513,11.0459ZM9.6633,11.0249L9.7333,11.0249L9.7333,11.0089L9.7103,11.0089L9.7103,10.9059L9.7513,10.9059L9.7513,10.8879L9.7103,10.8879L9.7103,10.8509L9.6923,10.8509L9.6923,10.8879L9.6523,10.8879L9.6523,10.9059L9.6933,10.9059L9.6933,11.0099L9.6643,11.0099L9.6643,11.0249L9.6633,11.0249Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.7156,10.9235l0,0.0213l-0.0884,0l0,-0.0213l0.0322,0l0,-0.0447l-0.0207,0l0,-0.0202l0.0207,0l0,-0.0202l0.0224,0l0,0.0202l0.0202,0l0,0.0202l-0.0202,0l0,0.0447l0.0338,0" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.6704,10.9704C9.6496,10.9704 9.6333,10.9535 9.6333,10.9349C9.6333,10.9196 9.6453,10.9065 9.6611,10.8995L9.6627,10.9104C9.6513,10.9115 9.6431,10.9229 9.6431,10.9355C9.6431,10.9485 9.6556,10.9611 9.6704,10.9611C9.6851,10.9611 9.6971,10.9491 9.6971,10.9355C9.6971,10.9235 9.69,10.9115 9.678,10.9104L9.6813,10.9005C9.696,10.9071 9.7069,10.9196 9.7069,10.9349C9.7075,10.9535 9.6911,10.9704 9.6704,10.9704Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.3169,11.1782C9.3164,11.1782 9.3033,11.1624 9.294,11.1525C9.2869,11.1471 9.27,11.1411 9.27,11.1411C9.27,11.1384 9.2798,11.1313 9.2907,11.1313C9.2967,11.1313 9.3022,11.1345 9.3055,11.1384L9.3076,11.1313C9.3076,11.1313 9.3158,11.1335 9.3196,11.1411C9.324,11.1525 9.3202,11.1667 9.3202,11.1667C9.3202,11.1667 9.3191,11.1749 9.3169,11.1782" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.3592,11.2269C9.3542,11.2269 9.3542,11.2249 9.3432,11.2149C9.3372,11.2069 9.3222,11.1919 9.3112,11.1779C9.3012,11.1729 9.2782,11.1659 9.2712,11.1619L9.2662,11.1579L9.2662,11.1519C9.2662,11.1419 9.2892,11.1269 9.3102,11.1269C9.3182,11.1269 9.3252,11.1289 9.3322,11.1289L9.3342,11.1269L9.3412,11.1269C9.3412,11.1269 9.3622,11.1289 9.3712,11.1519C9.3772,11.1729 9.3732,11.1989 9.3732,11.1989C9.3722,11.2029 9.3712,11.2179 9.3642,11.2219L9.3592,11.2259L9.3592,11.2259L9.3592,11.2269Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.3175,11.1689C9.3202,11.1656 9.3295,11.1667 9.3355,11.1722C9.3415,11.1771 9.3431,11.1847 9.3393,11.188C9.3355,11.1924 9.3267,11.1924 9.3202,11.188C9.3142,11.1804 9.3131,11.1749 9.3175,11.1689" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M10.0184,11.1782C10.0195,11.1782 10.0315,11.1624 10.0413,11.1525C10.0478,11.1471 10.0653,11.1411 10.0653,11.1411C10.0653,11.1384 10.0555,11.1313 10.044,11.1313C10.038,11.1313 10.0325,11.1345 10.0293,11.1384L10.0271,11.1313C10.0271,11.1313 10.0189,11.1335 10.0151,11.1411C10.0107,11.1525 10.0145,11.1667 10.0145,11.1667C10.0145,11.1667 10.0151,11.1749 10.0184,11.1782" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.0266,11.2265L10.0266,11.2265L10.0246,11.2265L10.0206,11.2225C10.0126,11.2175 10.0116,11.2025 10.0106,11.2015C10.0096,11.2005 10.0056,11.1745 10.0126,11.1525C10.0216,11.1295 10.0426,11.1275 10.0426,11.1275L10.0496,11.1275L10.0516,11.1315C10.0596,11.1295 10.0656,11.1275 10.0736,11.1275C10.0946,11.1275 10.1176,11.1435 10.1176,11.1525L10.1176,11.1585L10.1116,11.1625C10.1056,11.1665 10.0816,11.1735 10.0726,11.1785C10.0626,11.1925 10.0476,11.2055 10.0416,11.2155C10.0316,11.2245 10.0306,11.2265 10.0266,11.2265Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M10.0189,11.1689C10.0145,11.1656 10.0069,11.1667 10.0004,11.1722C9.9949,11.1771 9.9916,11.1847 9.996,11.188C10.0004,11.1924 10.008,11.1924 10.014,11.188C10.0205,11.1804 10.0233,11.1749 10.0189,11.1689" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.2853,11.5715l0.7707,0l0,-0.2018l-0.7707,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.2787,11.7555L9.2787,11.7555L9.2787,11.3625L10.2787,11.3625L10.2787,11.7555ZM9.2954,11.7295L10.2613,11.7295L10.2613,11.3875L9.2954,11.3875L9.2954,11.7295Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.9758,11.7045C9.9709,11.7035 9.9671,11.7035 9.9616,11.7035L9.384,11.7035C9.3775,11.7035 9.3725,11.7035 9.3682,11.7056C9.3873,11.6991 9.402,11.6822 9.402,11.6609C9.402,11.6396 9.3867,11.6227 9.366,11.614C9.3709,11.6151 9.3775,11.6173 9.384,11.6173L9.9616,11.6173C9.9671,11.6173 9.9725,11.6162 9.978,11.614L9.9747,11.6151C9.9529,11.6227 9.942,11.6396 9.942,11.6609C9.942,11.6789 9.9551,11.6991 9.9758,11.7045" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.3742,11.8014C9.369,11.8014 9.3638,11.7984 9.3638,11.7924C9.3612,11.7824 9.3638,11.7794 9.3681,11.7744L9.3725,11.7744C9.3986,11.7604 9.4169,11.7354 9.4169,11.7044C9.4169,11.6734 9.3969,11.6414 9.3681,11.6344C9.362,11.6304 9.3577,11.6184 9.3603,11.6164C9.3638,11.6104 9.3681,11.6064 9.3742,11.6104C9.3829,11.6104 9.3916,11.6104 9.3995,11.6104L10.3219,11.6104C10.3263,11.6104 10.3315,11.6104 10.3359,11.6104L10.3454,11.6104C10.3524,11.6104 10.3568,11.6104 10.3594,11.6184C10.3603,11.6244 10.3568,11.6344 10.3507,11.6344C10.3489,11.6344 10.3454,11.6344 10.342,11.6344C10.3176,11.6444 10.3028,11.6734 10.3028,11.7044C10.3028,11.7334 10.3202,11.7594 10.3446,11.7744C10.3454,11.7744 10.3472,11.7744 10.3507,11.7744C10.3559,11.7774 10.3576,11.7824 10.3559,11.7914C10.3542,11.7984 10.3481,11.8014 10.342,11.7984C10.3402,11.7984 10.3402,11.7984 10.3367,11.7984C10.3333,11.7984 10.3298,11.7984 10.3228,11.7984L9.4004,11.7984C9.3934,11.7984 9.3855,11.7984 9.3803,11.7984L9.3786,11.7984C9.3751,11.8014 9.3742,11.8014 9.3742,11.8014ZM9.4152,11.7724L10.3028,11.7724C10.2871,11.7514 10.2784,11.7274 10.2784,11.7044C10.2784,11.6814 10.2871,11.6574 10.3019,11.6374L9.4152,11.6374C9.43,11.6584 9.4396,11.6814 9.4396,11.7044C9.4396,11.7274 9.43,11.7514 9.4152,11.7724Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.3845,11.7035L9.9622,11.7035C9.9818,11.7035 9.9971,11.716 9.9971,11.7291C9.9971,11.746 9.9813,11.758 9.9622,11.758L9.3845,11.758C9.3655,11.758 9.3496,11.7465 9.3496,11.7291C9.3496,11.716 9.3649,11.7035 9.3845,11.7035" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.2785,11.82L9.4055,11.82C9.37,11.82 9.342,11.794 9.342,11.755C9.342,11.724 9.37,11.698 9.4055,11.698L10.2785,11.698C10.314,11.698 10.342,11.723 10.342,11.755C10.342,11.794 10.314,11.82 10.2785,11.82ZM9.4063,11.724C9.3824,11.724 9.3634,11.738 9.3634,11.755C9.3634,11.778 9.3824,11.794 9.4063,11.794L10.2793,11.794C10.3016,11.794 10.3222,11.778 10.3222,11.755C10.3222,11.737 10.3024,11.724 10.2793,11.724L9.4063,11.724Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.3845,11.5715L9.9622,11.5715C9.9818,11.5715 9.9971,11.5829 9.9971,11.5949C9.9971,11.6075 9.9813,11.6173 9.9622,11.6173L9.3845,11.6173C9.3644,11.6173 9.3491,11.6075 9.3491,11.5949C9.3485,11.5829 9.3644,11.5715 9.3845,11.5715" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.278,11.6757L9.4057,11.6757C9.3686,11.6757 9.3415,11.6527 9.3415,11.6217C9.3415,11.5887 9.3686,11.5627 9.4057,11.5627L10.278,11.5627C10.3134,11.5627 10.3415,11.5877 10.3415,11.6217C10.3415,11.6517 10.3134,11.6757 10.278,11.6757ZM9.4065,11.5887C9.3802,11.5887 9.3637,11.6077 9.3637,11.6217C9.3637,11.6337 9.3802,11.6487 9.4065,11.6487L10.2789,11.6487C10.3011,11.6487 10.3217,11.6327 10.3217,11.6217C10.3217,11.6067 10.3044,11.5887 10.2789,11.5887L9.4065,11.5887Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#005BBF" + android:fillType="nonZero" + android:pathData="M9.1325,14.9718C9.1865,14.9718 9.2345,14.9615 9.2695,14.9429C9.3038,14.9249 9.3507,14.9129 9.4031,14.9129C9.4549,14.9129 9.5035,14.9244 9.5384,14.9429C9.5738,14.9615 9.6213,14.9718 9.6736,14.9718C9.7271,14.9718 9.7751,14.9593 9.81,14.9407C9.8449,14.9249 9.8896,14.9129 9.9409,14.9129C9.9933,14.9129 10.0402,14.9238 10.0751,14.9418C10.1095,14.9604 10.158,14.9718 10.2115,14.9718L10.2115,15.0558C10.158,15.0558 10.1095,15.0444 10.0751,15.0253C10.0402,15.0078 9.9933,14.9969 9.9409,14.9969C9.8896,14.9969 9.8449,15.0084 9.81,15.0253C9.7745,15.0427 9.7271,15.0558 9.6736,15.0558C9.6213,15.0558 9.5738,15.0444 9.5384,15.0258C9.5035,15.01 9.4555,14.9969 9.4031,14.9969C9.3507,14.9969 9.3044,15.0095 9.2695,15.0258C9.2345,15.0449 9.1865,15.0558 9.1336,15.0558L9.1325,14.9718" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.218,15.1925L10.2109,15.1925C10.1596,15.1925 10.1084,15.1715 10.0718,15.1345C10.0364,15.1015 9.9916,15.0815 9.9404,15.0815C9.8929,15.0815 9.8482,15.1015 9.8127,15.1325C9.7745,15.1715 9.7238,15.1925 9.6731,15.1925C9.6207,15.1925 9.5733,15.1715 9.5351,15.1365C9.4996,15.1035 9.4522,15.0815 9.4031,15.0815C9.3535,15.0815 9.3082,15.1025 9.2722,15.1365C9.2345,15.1715 9.1865,15.1925 9.1342,15.1925L9.1271,15.1925L9.126,15.0115L9.1325,15.0115C9.1833,15.0115 9.2313,14.9955 9.2667,14.9605C9.3033,14.9275 9.3524,14.9075 9.4031,14.9075C9.4544,14.9075 9.5045,14.9285 9.5416,14.9605C9.5765,14.9955 9.624,15.0115 9.6736,15.0115C9.7238,15.0115 9.7702,14.9935 9.8067,14.9595C9.8433,14.9255 9.8907,14.9075 9.9409,14.9075C9.9944,14.9075 10.0413,14.9255 10.0778,14.9605C10.1133,14.9935 10.1618,15.0115 10.2115,15.0115L10.2185,15.0115L10.2185,15.1925L10.218,15.1925ZM9.4025,15.0565C9.4544,15.0565 9.5035,15.0795 9.5411,15.1155C9.576,15.1485 9.624,15.1665 9.6731,15.1665C9.7227,15.1665 9.7691,15.1485 9.8062,15.1115C9.8427,15.0785 9.8902,15.0565 9.9404,15.0565C9.9933,15.0565 10.0402,15.0775 10.0773,15.1135C10.1116,15.1455 10.1575,15.1665 10.2038,15.1665L10.2038,15.0375C10.1547,15.0355 10.1062,15.0175 10.0713,14.9815C10.0358,14.9515 9.9911,14.9315 9.9398,14.9315C9.8924,14.9315 9.8476,14.9515 9.8122,14.9815C9.774,15.0185 9.7238,15.0375 9.6725,15.0375C9.6202,15.0375 9.5711,15.0195 9.5345,14.9845C9.4991,14.9535 9.4516,14.9315 9.4025,14.9315C9.3529,14.9315 9.3076,14.9515 9.2716,14.9835C9.2367,15.0175 9.1893,15.0355 9.1391,15.0375L9.1402,15.1665C9.1871,15.1665 9.2313,15.1475 9.2662,15.1155C9.3027,15.0805 9.3518,15.0565 9.4025,15.0565Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:pathData="M9.1325,15.0564C9.1865,15.0564 9.2345,15.0455 9.2695,15.0264C9.3038,15.0105 9.3507,14.9975 9.4031,14.9975C9.4549,14.9975 9.5035,15.01 9.5384,15.0264C9.5738,15.0444 9.6213,15.0564 9.6736,15.0564C9.7271,15.0564 9.7751,15.0438 9.81,15.0258C9.8449,15.0095 9.8896,14.9975 9.9409,14.9975C9.9933,14.9975 10.0402,15.0084 10.0751,15.0258C10.1095,15.0444 10.158,15.0564 10.2115,15.0564L10.2115,15.1398C10.158,15.1398 10.1095,15.1284 10.0751,15.1093C10.0402,15.0913 9.9933,15.0793 9.9409,15.0793C9.8896,15.0793 9.8449,15.0907 9.81,15.1082C9.7745,15.1267 9.7271,15.1398 9.6736,15.1398C9.6213,15.1398 9.5738,15.1284 9.5384,15.1104C9.5035,15.0913 9.4555,15.0793 9.4031,15.0793C9.3507,15.0793 9.3044,15.0907 9.2695,15.1104C9.2345,15.1284 9.1865,15.1398 9.1336,15.1398L9.1325,15.0564" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.218,15.2767L10.2109,15.2767C10.1591,15.2767 10.1084,15.2567 10.0718,15.2207C10.0364,15.1887 9.9916,15.1687 9.9404,15.1687C9.8929,15.1687 9.8482,15.1887 9.8127,15.2187C9.7745,15.2567 9.7244,15.2767 9.6731,15.2767C9.6207,15.2767 9.5733,15.2587 9.5351,15.2217C9.4996,15.1927 9.4522,15.1687 9.4031,15.1687C9.3535,15.1687 9.3082,15.1897 9.2722,15.2217C9.2345,15.2607 9.1865,15.2767 9.1342,15.2767L9.1271,15.2767L9.126,15.0987L9.1325,15.0987C9.1833,15.0987 9.2313,15.0807 9.2667,15.0477C9.3033,15.0127 9.3524,14.9887 9.4031,14.9887C9.4549,14.9887 9.5051,15.0117 9.5416,15.0477C9.5765,15.0807 9.6245,15.0987 9.6736,15.0987C9.7227,15.0987 9.7696,15.0807 9.8067,15.0437C9.8433,15.0107 9.8907,14.9887 9.9409,14.9887C9.9938,14.9887 10.0407,15.0097 10.0778,15.0457C10.1133,15.0807 10.1618,15.0987 10.2115,15.0987L10.2185,15.0987L10.2185,15.2767L10.218,15.2767ZM9.4025,15.1457C9.4544,15.1457 9.5035,15.1667 9.5411,15.2007C9.576,15.2357 9.624,15.2517 9.6731,15.2517C9.7227,15.2517 9.7696,15.2337 9.8062,15.1987C9.8427,15.1657 9.8902,15.1457 9.9404,15.1457C9.9938,15.1457 10.0407,15.1657 10.0778,15.1987C10.1105,15.2317 10.1575,15.2497 10.2038,15.2517L10.2038,15.1257C10.1547,15.1227 10.1062,15.1047 10.0713,15.0677C10.0358,15.0347 9.9911,15.0147 9.9398,15.0147C9.8924,15.0147 9.8476,15.0347 9.8122,15.0657C9.774,15.1047 9.7233,15.1257 9.6725,15.1257C9.6202,15.1257 9.5716,15.1047 9.5345,15.0697C9.4991,15.0367 9.4516,15.0147 9.4025,15.0147C9.3529,15.0147 9.3076,15.0357 9.2716,15.0697C9.2362,15.1037 9.1893,15.1227 9.1391,15.1257L9.1402,15.2517C9.1871,15.2497 9.2313,15.2337 9.2662,15.2007C9.3027,15.1667 9.3518,15.1457 9.4025,15.1457Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#005BBF" + android:fillType="nonZero" + android:pathData="M9.1325,15.1398C9.1865,15.1398 9.2345,15.1284 9.2695,15.1104C9.3038,15.0913 9.3507,15.0793 9.4031,15.0793C9.4549,15.0793 9.5035,15.0907 9.5384,15.1104C9.5738,15.1284 9.6213,15.1398 9.6736,15.1398C9.7271,15.1398 9.7751,15.1273 9.81,15.1082C9.8449,15.0913 9.8896,15.0793 9.9409,15.0793C9.9933,15.0793 10.0402,15.0907 10.0751,15.1093C10.1095,15.1278 10.158,15.1398 10.2115,15.1398L10.2115,15.2222C10.158,15.2222 10.1095,15.2107 10.0751,15.1922C10.0402,15.1753 9.9933,15.1633 9.9409,15.1633C9.8896,15.1633 9.8449,15.1758 9.81,15.1916C9.7745,15.2102 9.7271,15.2222 9.6736,15.2222C9.6213,15.2222 9.5738,15.2113 9.5384,15.1933C9.5035,15.1764 9.4555,15.1633 9.4031,15.1633C9.3507,15.1633 9.3044,15.1758 9.2695,15.1933C9.2345,15.2124 9.1865,15.2222 9.1336,15.2222L9.1325,15.1398" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.218,15.3588L10.2109,15.3588C10.1591,15.3588 10.1084,15.3378 10.0718,15.3028C10.0364,15.2698 9.9916,15.2498 9.9404,15.2498C9.8929,15.2498 9.8482,15.2698 9.8127,15.3008C9.7745,15.3378 9.7249,15.3588 9.6731,15.3588C9.6207,15.3588 9.5722,15.3398 9.5351,15.3048C9.4996,15.2698 9.4522,15.2498 9.4031,15.2498C9.3529,15.2498 9.3082,15.2698 9.2722,15.3048C9.2345,15.3398 9.1865,15.3588 9.1342,15.3588L9.1271,15.3588L9.126,15.1798L9.1325,15.1798C9.1833,15.1798 9.2313,15.1638 9.2667,15.1288C9.3033,15.0958 9.3524,15.0738 9.4031,15.0738C9.4549,15.0738 9.5045,15.0948 9.5416,15.1288C9.5765,15.1638 9.6245,15.1798 9.6736,15.1798C9.7233,15.1798 9.7696,15.1618 9.8067,15.1268C9.8433,15.0938 9.8907,15.0738 9.9409,15.0738C9.9944,15.0738 10.0413,15.0938 10.0784,15.1268C10.1133,15.1618 10.1613,15.1798 10.2115,15.1798L10.2185,15.1798L10.2185,15.3588L10.218,15.3588ZM9.4025,15.2248C9.4544,15.2248 9.5035,15.2458 9.5411,15.2838C9.576,15.3148 9.624,15.3358 9.6731,15.3358C9.7233,15.3358 9.7696,15.3148 9.8062,15.2798C9.8433,15.2468 9.8907,15.2248 9.9404,15.2248C9.9933,15.2248 10.0402,15.2458 10.0773,15.2818C10.1111,15.3138 10.1575,15.3328 10.2038,15.3328L10.2038,15.2058C10.1547,15.2038 10.1062,15.1848 10.0713,15.1498C10.0358,15.1178 9.9911,15.0978 9.9398,15.0978C9.8924,15.0978 9.8476,15.1178 9.8122,15.1478C9.774,15.1858 9.7233,15.2058 9.6725,15.2058C9.6202,15.2058 9.5716,15.1878 9.5345,15.1508C9.4991,15.1218 9.4516,15.0978 9.4025,15.0978C9.3529,15.0978 9.3076,15.1188 9.2716,15.1508C9.2362,15.1858 9.1893,15.2038 9.1391,15.2058L9.1402,15.3328C9.1887,15.3328 9.2307,15.3148 9.2662,15.2838C9.3022,15.2468 9.3513,15.2248 9.4025,15.2248Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:pathData="M9.1336,15.3062C9.186,15.3062 9.2345,15.2947 9.2695,15.2778C9.3038,15.2576 9.3507,15.2467 9.4031,15.2467C9.4549,15.2467 9.5035,15.2576 9.5384,15.2778C9.5738,15.2947 9.6213,15.3062 9.6736,15.3062C9.7271,15.3062 9.7751,15.2947 9.81,15.2756C9.8449,15.2576 9.8896,15.2467 9.9409,15.2467C9.9933,15.2467 10.0402,15.2576 10.0751,15.2767C10.1095,15.2947 10.158,15.3062 10.2115,15.3062L10.2115,15.2238C10.158,15.2238 10.1095,15.2113 10.0751,15.1927C10.0402,15.1758 9.9933,15.1638 9.9409,15.1638C9.8896,15.1638 9.8449,15.1764 9.81,15.1922C9.7745,15.2107 9.7271,15.2227 9.6736,15.2227C9.6213,15.2227 9.5738,15.2118 9.5384,15.1938C9.5035,15.1769 9.4555,15.1638 9.4031,15.1638C9.3507,15.1638 9.3044,15.1764 9.2695,15.1938C9.2345,15.2129 9.1865,15.2227 9.1325,15.2227L9.1336,15.3062" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.218,15.4436L10.2109,15.4436C10.1591,15.4436 10.1078,15.4236 10.0718,15.3866C10.0364,15.3556 9.9916,15.3366 9.9404,15.3366C9.8929,15.3366 9.8482,15.3556 9.8127,15.3856C9.7745,15.4236 9.7244,15.4436 9.6731,15.4436C9.6207,15.4436 9.5722,15.4256 9.5351,15.3886C9.4996,15.3576 9.4522,15.3366 9.4031,15.3366C9.3535,15.3366 9.3082,15.3576 9.2722,15.3866C9.2345,15.4256 9.1865,15.4436 9.1342,15.4436L9.1271,15.4436L9.126,15.2666L9.1325,15.2666C9.1833,15.2666 9.2313,15.2456 9.2667,15.2146C9.3027,15.1776 9.3518,15.1556 9.4031,15.1556C9.4549,15.1556 9.504,15.1766 9.5416,15.2146C9.5765,15.2456 9.6245,15.2666 9.6736,15.2666C9.7238,15.2666 9.7702,15.2456 9.8067,15.2106C9.8438,15.1776 9.8913,15.1556 9.9409,15.1556C9.9938,15.1556 10.0407,15.1766 10.0778,15.2126C10.1133,15.2456 10.1624,15.2666 10.2115,15.2666L10.2185,15.2666L10.2185,15.4436L10.218,15.4436ZM9.4025,15.3106C9.4544,15.3106 9.5045,15.3336 9.5411,15.3656C9.576,15.4006 9.624,15.4186 9.6731,15.4186C9.7227,15.4186 9.7691,15.4006 9.8062,15.3636C9.8427,15.3326 9.8907,15.3106 9.9404,15.3106C9.9933,15.3106 10.0402,15.3316 10.0773,15.3656C10.1105,15.3986 10.1569,15.4166 10.2038,15.4186L10.2038,15.2926C10.1547,15.2906 10.1062,15.2706 10.0713,15.2346C10.0358,15.2016 9.9911,15.1816 9.9398,15.1816C9.8924,15.1816 9.8476,15.2016 9.8122,15.2326C9.774,15.2696 9.7244,15.2906 9.6725,15.2906C9.6202,15.2906 9.5716,15.2716 9.5345,15.2366C9.4991,15.2016 9.4516,15.1816 9.4025,15.1816C9.3524,15.1816 9.3076,15.2016 9.2716,15.2366C9.2373,15.2696 9.1893,15.2876 9.1391,15.2906L9.1402,15.4186C9.1871,15.4166 9.2313,15.3986 9.2662,15.3656C9.3027,15.3346 9.3518,15.3106 9.4025,15.3106Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#005BBF" + android:fillType="nonZero" + android:pathData="M9.1336,15.3896C9.186,15.3896 9.2345,15.3787 9.2695,15.3596C9.3038,15.3427 9.3507,15.3296 9.4031,15.3296C9.4549,15.3296 9.5035,15.3422 9.5384,15.3596C9.5738,15.3787 9.6213,15.3896 9.6736,15.3896C9.7271,15.3896 9.7751,15.3771 9.81,15.3585C9.8449,15.3427 9.8896,15.3296 9.9409,15.3296C9.9933,15.3296 10.0402,15.3422 10.0751,15.3596C10.1095,15.3776 10.158,15.3896 10.2115,15.3896L10.2115,15.3078C10.158,15.3078 10.1095,15.2953 10.0751,15.2767C10.0402,15.2576 9.9933,15.2467 9.9409,15.2467C9.8896,15.2467 9.8449,15.2576 9.81,15.2756C9.7745,15.2942 9.7271,15.3062 9.6736,15.3062C9.6213,15.3062 9.5738,15.2947 9.5384,15.2778C9.5035,15.2576 9.4555,15.2467 9.4031,15.2467C9.3507,15.2467 9.3044,15.2576 9.2695,15.2778C9.2345,15.2947 9.1865,15.3062 9.1331,15.3062L9.1336,15.3896" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.218,15.5282L10.2109,15.5282C10.1596,15.5282 10.1084,15.5072 10.0718,15.4712C10.0364,15.4362 9.9916,15.4182 9.9404,15.4182C9.8929,15.4182 9.8482,15.4362 9.8127,15.4692C9.774,15.5062 9.7238,15.5282 9.6731,15.5282C9.6207,15.5282 9.5722,15.5072 9.5351,15.4732C9.4996,15.4362 9.4522,15.4182 9.4031,15.4182C9.3535,15.4182 9.3082,15.4362 9.2733,15.4732C9.2351,15.5062 9.1865,15.5282 9.1342,15.5282L9.1271,15.5282L9.126,15.3482L9.1331,15.3482C9.1838,15.3482 9.2313,15.3322 9.2667,15.2952C9.3027,15.2642 9.3518,15.2402 9.4031,15.2402C9.4549,15.2402 9.5045,15.2632 9.5416,15.2952C9.5765,15.3302 9.6245,15.3482 9.6736,15.3482C9.7233,15.3482 9.7696,15.3302 9.8067,15.2932C9.8433,15.2622 9.8907,15.2402 9.9409,15.2402C9.9938,15.2402 10.0407,15.2612 10.0778,15.2952C10.1133,15.3322 10.1624,15.3502 10.2115,15.3502L10.2185,15.3502L10.2185,15.5282L10.218,15.5282ZM9.4025,15.3932C9.4538,15.3932 9.504,15.4132 9.5411,15.4522C9.576,15.4832 9.624,15.5022 9.6731,15.5022C9.7222,15.5022 9.7685,15.4832 9.8062,15.4482C9.8427,15.4132 9.8907,15.3932 9.9404,15.3932C9.9933,15.3932 10.0402,15.4132 10.0773,15.4502C10.1111,15.4812 10.1575,15.4992 10.2038,15.5022L10.2038,15.3762C10.1547,15.3742 10.1067,15.3532 10.0713,15.3172C10.0358,15.2862 9.9911,15.2672 9.9398,15.2672C9.8924,15.2672 9.8476,15.2862 9.8122,15.3162C9.774,15.3542 9.7238,15.3742 9.6725,15.3742C9.6202,15.3742 9.5716,15.3562 9.5345,15.3192C9.4996,15.2882 9.4516,15.2672 9.4025,15.2672C9.3524,15.2672 9.3076,15.2882 9.2716,15.3172C9.2362,15.3542 9.1893,15.3722 9.1396,15.3742L9.1402,15.5022C9.1865,15.4992 9.2307,15.4812 9.2656,15.4522C9.3027,15.4122 9.3518,15.3932 9.4025,15.3932Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.9758,14.6298C9.9736,14.6385 9.9715,14.6435 9.9715,14.6522C9.9715,14.7035 10.0145,14.7416 10.068,14.7416L9.2755,14.7416C9.3278,14.7416 9.3715,14.7035 9.3715,14.6522C9.3715,14.6435 9.3709,14.6385 9.3687,14.6298C9.3731,14.6309 9.378,14.6309 9.3845,14.6309L9.9616,14.6309C9.966,14.6309 9.972,14.6309 9.9758,14.6298" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.2602,14.8537L9.2772,14.8537C9.2717,14.8537 9.2684,14.8477 9.2684,14.8397C9.2684,14.8357 9.2717,14.8257 9.2772,14.8257C9.3374,14.8257 9.3881,14.7577 9.3881,14.6757C9.3881,14.6597 9.3868,14.6527 9.3847,14.6367C9.3847,14.6347 9.3847,14.6287 9.3881,14.6287C9.3888,14.6247 9.3922,14.6227 9.3962,14.6247C9.4003,14.6287 9.4064,14.6287 9.4118,14.6287L10.1276,14.6287C10.133,14.6287 10.1385,14.6287 10.1418,14.6247C10.1452,14.6227 10.1493,14.6247 10.152,14.6287C10.1533,14.6287 10.1533,14.6347 10.1533,14.6367L10.152,14.6487C10.1493,14.6577 10.1493,14.6647 10.1493,14.6757C10.1493,14.7577 10.1987,14.8257 10.2602,14.8257C10.2643,14.8257 10.2684,14.8357 10.2684,14.8397C10.2684,14.8477 10.265,14.8537 10.2602,14.8537ZM9.3408,14.8267L10.1953,14.8267C10.1574,14.7997 10.1317,14.7427 10.1317,14.6767C10.1317,14.6667 10.133,14.6587 10.133,14.6537C10.131,14.6537 10.1297,14.6537 10.1276,14.6537L9.4118,14.6537C9.4084,14.6537 9.4057,14.6537 9.4037,14.6537C9.4037,14.6597 9.4037,14.6677 9.4037,14.6767C9.4044,14.7427 9.3807,14.7987 9.3408,14.8267Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.3845,14.5785L9.9622,14.5785C9.9818,14.5785 9.9971,14.59 9.9971,14.6058C9.9971,14.6184 9.9813,14.6315 9.9622,14.6315L9.3845,14.6315C9.3655,14.6315 9.3496,14.6189 9.3496,14.6058C9.3496,14.59 9.3649,14.5785 9.3845,14.5785" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.2785,14.6969L9.4055,14.6969C9.37,14.6969 9.342,14.6699 9.342,14.6339C9.342,14.6009 9.37,14.5709 9.4055,14.5709L10.2785,14.5709C10.314,14.5709 10.342,14.5999 10.342,14.6339C10.342,14.6699 10.314,14.6969 10.2785,14.6969ZM9.4063,14.5969C9.3824,14.5969 9.3634,14.6109 9.3634,14.6339C9.3634,14.6549 9.3824,14.6729 9.4063,14.6729L10.2793,14.6729C10.3016,14.6729 10.3222,14.6539 10.3222,14.6339C10.3222,14.6109 10.3024,14.5969 10.2793,14.5969L9.4063,14.5969Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.2755,14.9462l0.792,0l0,-0.2045l-0.792,0l0,0.2045z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.2689,15.1305L9.2689,15.1305L9.2689,14.7345L10.2689,14.7345L10.2689,15.1305ZM9.2852,15.1075L10.252,15.1075L10.252,14.7615L9.2852,14.7615L9.2852,15.1075Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M10.1291,13.864C10.2076,13.9098 10.26,13.9535 10.2524,13.978C10.2475,14.0004 10.2229,14.0156 10.1869,14.0385C10.1318,14.0767 10.0969,14.146 10.1236,14.1793C10.0778,14.1411 10.0489,14.0865 10.0489,14.026C10.0489,13.96 10.0795,13.9011 10.1291,13.864" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.1834,14.4573C10.0934,14.3853 10.0424,14.2793 10.0424,14.1683C10.0424,14.0453 10.0954,13.9343 10.1944,13.8633L10.2004,13.8553L10.2054,13.8613C10.2834,13.9063 10.4634,14.0133 10.4364,14.0823C10.4274,14.1263 10.3824,14.1523 10.3204,14.1973L10.3124,14.1993C10.2464,14.2463 10.1934,14.3203 10.1874,14.3823C10.1834,14.4033 10.1844,14.4263 10.1994,14.4423L10.1834,14.4573ZM10.2014,13.8873C10.1154,13.9553 10.0664,14.0563 10.0664,14.1683C10.0664,14.2553 10.1014,14.3403 10.1634,14.4053C10.1624,14.3983 10.1634,14.3863 10.1644,14.3793C10.1714,14.3123 10.2284,14.2333 10.3004,14.1803L10.3074,14.1763C10.3654,14.1393 10.4074,14.1103 10.4144,14.0793C10.4244,14.0513 10.3554,13.9753 10.2014,13.8873Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:pathData="M9.3911,14.5447l0.5624,0l0,-2.7545l-0.5624,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.9336,14.5371L9.9076,14.5371L9.9076,11.7885L9.9336,11.7885L9.9336,14.5371ZM9.8166,14.5371L9.7936,14.5371L9.7936,11.7885L9.8166,11.7885L9.8166,14.5371Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.3845,14.5529L9.3845,14.5529L9.3845,11.7825L10.3845,11.7825L10.3845,14.5529ZM9.4082,14.5387L10.3609,14.5387L10.3609,11.7962L9.4082,11.7962L9.4082,14.5387Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M8.8173,12.8211C8.9405,12.7698 9.1478,12.7338 9.3878,12.7245C9.4707,12.7251 9.5629,12.7338 9.6573,12.7491C9.9944,12.8031 10.2507,12.9395 10.2295,13.0469C10.2289,13.0513 10.2284,13.0562 10.2284,13.0578C10.2284,13.0578 10.3538,12.7736 10.356,12.7633C10.3789,12.6411 10.0942,12.4922 9.7205,12.43C9.6044,12.4104 9.4904,12.4027 9.3911,12.4044C9.1516,12.4044 8.9433,12.4338 8.8195,12.4813L8.8173,12.8211" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.2278,13.3951C10.2273,13.3951 10.2256,13.3951 10.2251,13.3935C10.2218,13.3918 10.2202,13.3853 10.2218,13.3812C10.2218,13.3788 10.2218,13.3755 10.2218,13.3707L10.2224,13.3658C10.2262,13.3405 10.2207,13.3088 10.206,13.2754C10.1389,13.1353 9.9185,12.9969 9.6562,12.9317C9.5656,12.9081 9.4735,12.8983 9.3878,12.8967C9.1593,12.9081 8.9465,12.9611 8.8195,13.04C8.8178,13.04 8.8151,13.04 8.8129,13.0392C8.8113,13.0352 8.8096,13.0352 8.8096,13.0303L8.8124,12.5221C8.8124,12.5197 8.8135,12.5148 8.8156,12.5115C8.9465,12.4415 9.1609,12.3951 9.3905,12.3951L9.4069,12.3951C9.5095,12.3951 9.6185,12.4097 9.7222,12.435C10.0173,12.5067 10.2665,12.6671 10.3402,12.8267C10.3593,12.8674 10.3669,12.9073 10.3625,12.944C10.3609,12.9611 10.2551,13.3161 10.2349,13.3845C10.2327,13.3918 10.2305,13.3951 10.2278,13.3951ZM9.3878,12.8764C9.474,12.878 9.5667,12.8894 9.6595,12.9114C9.9251,12.9782 10.1487,13.1182 10.2164,13.2648C10.2273,13.2884 10.2338,13.3096 10.236,13.3283C10.2856,13.1695 10.3467,12.9578 10.3495,12.9399C10.3527,12.9081 10.3467,12.8747 10.3304,12.8397C10.2573,12.6809 10.0107,12.5262 9.72,12.4562C9.6175,12.4309 9.5089,12.4163 9.4069,12.4163L9.3905,12.4163C9.1653,12.4163 8.9553,12.4611 8.8249,12.5278L8.8238,13.0164C8.9531,12.9407 9.1625,12.8878 9.3878,12.8764Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M9.9551,13.1675C10.1105,13.1565 10.2175,13.1129 10.2295,13.0469C10.2393,12.9945 10.1869,12.9395 10.0925,12.8882C10.05,12.8915 10.0031,12.8975 9.9535,12.8975L9.9551,13.1675" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.9489,13.4185L9.9469,12.9005L9.9589,12.9005C10.0409,12.9005 10.1179,12.8935 10.1879,12.8795L10.2169,12.8795L10.2199,12.8795C10.4039,12.9845 10.4959,13.0905 10.4769,13.1905C10.4549,13.3155 10.2679,13.3955 9.9629,13.4195L9.9489,13.4195L9.9489,13.4185ZM9.9719,12.9245L9.9749,13.3935C10.2549,13.3705 10.4339,13.2935 10.4529,13.1845C10.4699,13.1025 10.3839,12.9985 10.2119,12.9035L10.1909,12.9055C10.1229,12.9165 10.0479,12.9235 9.9719,12.9245Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M9.3905,12.9564C9.2929,12.9689 9.2198,12.9945 9.1833,13.0245L9.18,13.0305C9.1631,13.0671 9.2487,13.144 9.3911,13.2247L9.3911,12.9564" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.5871,13.4796L9.5681,13.4716C9.4331,13.3896 9.1281,13.1956 9.1751,13.0966L9.1861,13.0786C9.2551,13.0256 9.3871,12.9786 9.5711,12.9516L9.5841,12.9476L9.5871,13.4796ZM9.2061,13.0966L9.2001,13.1046C9.1801,13.1466 9.2651,13.2606 9.5631,13.4366L9.5631,12.9796C9.3941,13.0026 9.2691,13.0476 9.2061,13.0966Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M10.3047,13.6976C10.3184,13.6551 10.1678,13.5656 9.9524,13.4855C9.8547,13.4505 9.7729,13.4135 9.672,13.3693C9.3742,13.2373 9.1533,13.084 9.18,13.0311L9.1833,13.0251C9.1669,13.0376 9.1429,13.3093 9.1429,13.3093C9.1162,13.3605 9.3175,13.5095 9.5924,13.6415C9.6802,13.6829 9.8662,13.7511 9.9535,13.7822C10.1105,13.8367 10.2665,13.9387 10.2524,13.9769L10.3047,13.6976" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M10.2524,14.0176C10.2513,14.0176 10.2507,14.0176 10.2507,14.0176C10.2475,14.0159 10.2442,14.0108 10.2453,14.0091L10.2464,14.0052C10.2458,13.9669 10.1035,13.8688 9.9507,13.8136C9.8825,13.7894 9.684,13.7156 9.588,13.6671C9.348,13.5482 9.1565,13.4119 9.1347,13.3448C9.1315,13.333 9.132,13.324 9.1353,13.3195C9.1418,13.2445 9.1571,13.0907 9.1702,13.0366C9.1707,13.0332 9.1724,13.0304 9.1729,13.0287L9.174,13.0265C9.1756,13.022 9.1762,13.0197 9.1784,13.0197C9.18,13.0169 9.1838,13.0169 9.186,13.0197C9.1882,13.0197 9.1893,13.0253 9.1882,13.0287L9.1849,13.0332C9.1827,13.0389 9.1827,13.0451 9.1849,13.0529C9.2105,13.1211 9.4151,13.2564 9.6742,13.3747L9.6998,13.3854C9.7882,13.4265 9.8635,13.4615 9.9529,13.4941C10.1438,13.5668 10.3282,13.6654 10.3102,13.7206L10.3102,13.7206L10.2589,14.0058C10.2589,14.0074 10.2589,14.0103 10.2573,14.0103C10.2573,14.0153 10.2545,14.0176 10.2524,14.0176ZM9.1789,13.0687C9.1702,13.1217 9.1576,13.2248 9.1495,13.3195C9.1495,13.3212 9.1489,13.3223 9.1484,13.3228C9.1473,13.3262 9.1473,13.333 9.1484,13.3381C9.1696,13.4029 9.3611,13.5392 9.5951,13.6542C9.6785,13.697 9.8607,13.7685 9.9567,13.8007C10.0745,13.8446 10.2142,13.9274 10.2507,13.9798L10.2982,13.719C10.308,13.6835 10.1896,13.5984 9.9502,13.5077C9.8607,13.4744 9.7838,13.4384 9.6955,13.3989L9.6687,13.3871C9.4156,13.271 9.2182,13.1414 9.1789,13.0687Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M9.1669,12.8976C9.1898,12.7516 9.216,12.6106 9.2438,12.4616C9.2373,12.4676 9.2313,12.4696 9.2247,12.4696C9.2187,12.4696 9.2122,12.4726 9.2056,12.4726C9.1931,12.5756 9.1767,12.6806 9.1576,12.7826C9.1238,12.6926 9.0873,12.6066 9.0584,12.5146C9.0475,12.5166 9.036,12.5226 9.0235,12.5246C9.0125,12.5266 9.0005,12.5286 8.988,12.5326C9.0387,12.6576 9.0873,12.7796 9.1331,12.9076C9.1385,12.9036 9.1445,12.8996 9.1511,12.8996C9.156,12.8976 9.1615,12.8996 9.1669,12.8976M9.3813,12.4686C9.3715,12.4686 9.3611,12.4706 9.3502,12.4706C9.3398,12.4706 9.33,12.4666 9.3202,12.4646L9.3164,12.8686L9.4713,12.8746C9.4713,12.8686 9.4696,12.8566 9.4702,12.8506C9.4702,12.8436 9.4713,12.8296 9.4713,12.8256C9.444,12.8286 9.414,12.8306 9.3785,12.8306L9.3813,12.4686M9.6245,12.5326C9.6496,12.5386 9.6736,12.5456 9.6976,12.5506C9.6976,12.5436 9.6971,12.5366 9.6976,12.5256C9.6976,12.5176 9.6987,12.5096 9.7009,12.5026L9.4898,12.4716C9.4898,12.4796 9.4909,12.4876 9.4904,12.4946C9.4898,12.5026 9.4893,12.5146 9.4871,12.5206C9.5095,12.5176 9.5345,12.5176 9.5635,12.5236L9.5455,12.8916C9.5564,12.8916 9.5667,12.8916 9.576,12.8916C9.5858,12.8916 9.5962,12.8966 9.6065,12.8976L9.6245,12.5326M9.7102,12.9346C9.7205,12.9386 9.7315,12.9386 9.7418,12.9436C9.7522,12.9466 9.7615,12.9506 9.7713,12.9586L9.7958,12.7726L9.798,12.7746C9.8035,12.7976 9.8122,12.8296 9.8155,12.8446L9.8465,12.9886C9.858,12.9916 9.87,12.9936 9.882,12.9976C9.8945,13.0056 9.9065,13.0096 9.9175,13.0176L9.9071,12.9726C9.8907,12.9116 9.8722,12.8456 9.858,12.7836C9.8967,12.7836 9.9262,12.7606 9.9338,12.7056C9.9387,12.6646 9.9305,12.6356 9.9104,12.6076C9.8951,12.5876 9.8656,12.5746 9.8471,12.5696L9.7636,12.5356L9.7102,12.9346M9.8187,12.5876C9.8444,12.5976 9.8744,12.6086 9.8744,12.6576C9.8744,12.6676 9.8738,12.6806 9.8727,12.6866C9.864,12.7496 9.84,12.7676 9.7991,12.7456L9.8187,12.5876M10.1105,13.0556C10.1095,13.1006 10.1045,13.1416 10.1002,13.1886C10.1105,13.1966 10.1215,13.2046 10.1324,13.2176C10.1422,13.2256 10.1515,13.2386 10.1613,13.2486L10.182,12.7896C10.1771,12.7836 10.1727,12.7816 10.1678,12.7786C10.164,12.7736 10.1591,12.7696 10.1553,12.7596L9.9344,13.0176C9.9409,13.0256 9.9469,13.0316 9.9524,13.0366C9.9578,13.0396 9.9638,13.0476 9.9687,13.0556C9.9867,13.0266 10.0064,13.0026 10.0287,12.9696L10.1105,13.0556L10.1105,13.0556ZM10.0489,12.9486L10.1225,12.8646L10.1127,13.0146L10.0489,12.9486" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.36,10.6589C6.283,10.6589 6.222,10.5999 6.222,10.5259C6.222,10.4519 6.283,10.3949 6.36,10.3949C6.437,10.3949 6.499,10.4519 6.499,10.5259C6.499,10.5999 6.438,10.6589 6.36,10.6589ZM6.36,10.3989C6.286,10.3989 6.224,10.4549 6.224,10.5269C6.224,10.5989 6.286,10.6569 6.36,10.6569C6.435,10.6569 6.497,10.5989 6.497,10.5269C6.497,10.4549 6.436,10.3989 6.36,10.3989Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M7.0691,9.8538C7.2987,9.8538 7.5033,9.8882 7.6364,9.9389C7.7133,9.9744 7.8153,10 7.9271,10.0158C8.0138,10.0273 8.0935,10.0284 8.1644,10.0245C8.2598,10.0235 8.3956,10.0502 8.532,10.1096C8.6455,10.1587 8.7393,10.2204 8.8025,10.2804L8.748,10.3284L8.7327,10.4636L8.5833,10.636L8.5091,10.6987L8.3335,10.8395L8.244,10.8471L8.2156,10.924L7.0773,10.792L5.9345,10.924L5.9073,10.8471L5.8178,10.8395L5.6416,10.6987L5.5669,10.636L5.4191,10.4636L5.4027,10.3284L5.3482,10.2804C5.4115,10.2209 5.5053,10.1587 5.6182,10.1096C5.754,10.0502 5.8915,10.0235 5.9853,10.0245C6.0562,10.0289 6.1375,10.0273 6.2225,10.0158C6.3349,10.0005 6.4375,9.9749 6.5133,9.9389C6.6453,9.8882 6.8395,9.8538 7.0691,9.8538Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2178,10.93L8.2145,10.9289L7.0767,10.7958L5.9313,10.93L5.904,10.8509L5.8145,10.8422L5.8145,10.8422L5.6384,10.7015L5.5631,10.6376L5.4131,10.4664L5.4131,10.4642L5.3984,10.3311L5.3416,10.2798L5.3449,10.2765C5.4115,10.216 5.508,10.1533 5.6171,10.1053C5.7393,10.0513 5.874,10.018 5.9771,10.018C5.9798,10.018 5.9831,10.0191 5.9858,10.0191C6.0589,10.0245 6.1407,10.0235 6.2225,10.0115C6.3387,9.9956 6.4385,9.97 6.5127,9.9362C6.654,9.88 6.8525,9.8495 7.0707,9.8495C7.2927,9.8495 7.5,9.8816 7.6402,9.9362C7.7144,9.97 7.8131,9.9951 7.9293,10.0115C8.0116,10.0229 8.0935,10.024 8.1649,10.0191C8.1682,10.0191 8.1715,10.018 8.1747,10.018C8.2773,10.018 8.412,10.0518 8.5358,10.1053C8.6444,10.1538 8.7404,10.216 8.8069,10.2765L8.8107,10.2798L8.7535,10.3311L8.7382,10.4664L8.5887,10.6376L8.5145,10.7015L8.3367,10.8422L8.3356,10.8422L8.2489,10.8509L8.2178,10.93ZM5.8178,10.834L5.91,10.8427L5.9367,10.9196L7.0762,10.7865L8.2113,10.9196L8.2396,10.8427L8.3302,10.834L8.5053,10.6933L8.5795,10.6305L8.7273,10.4636L8.7425,10.3251L8.7949,10.2804C8.73,10.2198 8.6362,10.1609 8.5304,10.114C8.4082,10.0605 8.2756,10.0289 8.1731,10.0289C8.1698,10.0289 8.1665,10.0289 8.1638,10.0289C8.1409,10.0289 8.1153,10.03 8.0896,10.03C8.0362,10.03 7.9811,10.0278 7.9265,10.0202C7.8098,10.0033 7.7095,9.9776 7.6347,9.9455C7.4956,9.8882 7.29,9.8582 7.0691,9.8582C6.8531,9.8582 6.6545,9.8882 6.5138,9.9455C6.4407,9.9776 6.3387,10.0027 6.2225,10.0202C6.1402,10.03 6.0573,10.0338 5.9836,10.0289C5.9815,10.0289 5.9787,10.0289 5.9755,10.0289C5.874,10.0289 5.7398,10.0611 5.6187,10.114C5.5135,10.1609 5.4185,10.2193 5.3536,10.2804L5.406,10.3251L5.4065,10.3284L5.4213,10.4636L5.5696,10.6322L5.6438,10.6938L5.8178,10.834Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0865,11.3571C6.6616,11.3571 6.2815,11.3058 6.0109,11.2262C5.9907,11.2175 5.9809,11.2005 5.9814,11.1804C5.9809,11.164 5.9918,11.1471 6.0109,11.1411C6.282,11.0604 6.6616,11.0091 7.0865,11.0091C7.5115,11.0091 7.8911,11.0604 8.1616,11.1411C8.1807,11.1476 8.1911,11.164 8.1905,11.1804C8.1922,11.2005 8.1818,11.2175 8.1616,11.2262C7.8905,11.3064 7.5115,11.3571 7.0865,11.3571" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.0865,11.6684L7.0865,11.6684C6.6742,11.6664 6.2907,11.5784 6.0093,11.4224C5.9869,11.4144 5.9744,11.3754 5.9749,11.3284C5.9749,11.2934 5.9875,11.2584 6.0093,11.2484C6.2913,11.0914 6.6742,11.0024 7.0865,11.0004C7.4984,11.0024 7.8818,11.0914 8.1633,11.2484C8.1851,11.2584 8.1987,11.2934 8.1976,11.3304C8.1987,11.3754 8.1862,11.4144 8.1633,11.4224C7.8818,11.5784 7.4984,11.6664 7.0865,11.6684ZM7.0865,11.0254C6.6753,11.0274 6.294,11.1154 6.0125,11.2714C5.9967,11.2794 5.988,11.3024 5.9885,11.3304C5.9875,11.3674 5.9967,11.3914 6.0125,11.3984C6.294,11.5544 6.6747,11.6404 7.0865,11.6424C7.4978,11.6404 7.8791,11.5544 8.1605,11.3984C8.1764,11.3904 8.1851,11.3674 8.184,11.3324C8.1845,11.3034 8.1753,11.2794 8.1605,11.2714C7.8791,11.1154 7.4973,11.0274 7.0865,11.0254Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M7.0855,11.3031C6.7025,11.3031 6.3562,11.2562 6.0922,11.188C6.3562,11.1209 6.7031,11.0773 7.0855,11.0773C7.4678,11.0773 7.8158,11.1209 8.0798,11.188C7.8158,11.2562 7.4678,11.3031 7.0855,11.3031" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.1211,11.1782l0.0322,0l0,0.0224l-0.0322,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0827,11.0091C6.6545,11.0091 6.2678,11.0636 5.9967,11.1476C6.0196,11.1367 6.018,11.1095 5.9896,11.0364C5.9553,10.9485 5.9035,10.9518 5.9035,10.9518C6.2029,10.8645 6.6196,10.8089 7.0855,10.8078C7.5496,10.8089 7.9713,10.8645 8.2707,10.9518C8.2707,10.9518 8.2173,10.9485 8.184,11.0364C8.1567,11.1095 8.1535,11.1373 8.1758,11.1476C7.9047,11.0631 7.5125,11.0091 7.0827,11.0091" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.1747,11.4457C7.8922,11.2837 7.4956,11.1937 7.0833,11.1897C6.6775,11.1937 6.2815,11.2837 6,11.4457L5.9945,11.4227C6.0093,11.4107 6.0131,11.3757 5.9836,11.2367C5.9542,11.0937 5.9095,11.0907 5.904,11.0907L5.9007,11.0647C6.216,10.8967 6.6355,10.8027 7.0855,10.8007C7.5365,10.8027 7.9587,10.8967 8.2718,11.0647L8.2702,11.0907L8.2702,11.0907C8.2653,11.0907 8.2205,11.0937 8.1905,11.2367C8.1605,11.3757 8.1638,11.4107 8.1796,11.4227L8.1747,11.4457ZM7.0827,11.1667C7.4853,11.1667 7.8753,11.2587 8.1567,11.4107C8.1502,11.3747 8.16,11.3127 8.178,11.2287C8.1987,11.1347 8.2244,11.0937 8.244,11.0747C7.9331,10.9147 7.524,10.8287 7.0855,10.8267C6.648,10.8287 6.2389,10.9147 5.9291,11.0747C5.9493,11.0947 5.976,11.1357 5.9962,11.2287C6.0147,11.3127 6.024,11.3747 6.018,11.4107C6.2995,11.2587 6.6862,11.1667 7.0827,11.1667Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0855,10.8073C6.6196,10.8084 6.2035,10.864 5.9035,10.9513C5.8827,10.9578 5.8615,10.9491 5.8555,10.9322C5.8489,10.9109 5.8593,10.8918 5.8795,10.8853C6.1811,10.7915 6.6093,10.7342 7.0849,10.732C7.5611,10.7331 7.9898,10.7915 8.2915,10.8853C8.3122,10.8918 8.322,10.9109 8.3155,10.9322C8.3089,10.9491 8.2876,10.9578 8.268,10.9513C7.9685,10.864 7.5496,10.8084 7.0855,10.8073" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2822,11.1552C8.2778,11.1552 8.2718,11.1552 8.2675,11.1522C7.9549,10.9852 7.5349,10.8912 7.0855,10.8872C6.636,10.8912 6.2171,10.9852 5.9045,11.1522C5.9002,11.1552 5.8942,11.1552 5.8898,11.1552C5.8707,11.1552 5.8549,11.1342 5.8489,11.1052C5.8462,11.0842 5.8462,11.0632 5.8516,11.0422C5.8565,11.0242 5.8658,11.0092 5.8778,11.0052C6.1936,10.8272 6.6224,10.7282 7.0849,10.7282C7.542,10.7282 7.9827,10.8302 8.2936,11.0052C8.3051,11.0092 8.3144,11.0252 8.3193,11.0422C8.3258,11.0632 8.3258,11.0852 8.322,11.1052C8.3171,11.1332 8.3013,11.1552 8.2822,11.1552ZM7.0855,10.8622C7.5365,10.8642 7.9576,10.9602 8.2718,11.1262C8.2882,11.1342 8.3056,11.1262 8.31,11.0992C8.3133,11.0852 8.3122,11.0682 8.3084,11.0562C8.304,11.0402 8.2975,11.0332 8.2909,11.0312C7.9805,10.8532 7.5404,10.7522 7.0855,10.7522C6.6229,10.7522 6.1964,10.8522 5.8811,11.0312C5.874,11.0332 5.868,11.0412 5.8636,11.0562C5.8598,11.0682 5.8593,11.0852 5.862,11.0992C5.8669,11.1262 5.8849,11.1342 5.9007,11.1262C6.2149,10.9592 6.6355,10.8642 7.0855,10.8622Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.7538,10.912C6.7538,10.894 6.7702,10.8776 6.792,10.8776C6.8122,10.8776 6.8296,10.8935 6.8296,10.912C6.8296,10.9322 6.8122,10.9491 6.792,10.9491C6.7702,10.9491 6.7538,10.9322 6.7538,10.912" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.8298,11.0301C6.7828,11.0301 6.7478,10.9911 6.7478,10.9461C6.7478,10.9051 6.7828,10.8711 6.8298,10.8711C6.8738,10.8711 6.9118,10.9051 6.9118,10.9461C6.9118,10.9911 6.8738,11.0301 6.8298,11.0301ZM6.8298,10.8951C6.7968,10.8951 6.7708,10.9181 6.7708,10.9461C6.7708,10.9791 6.7968,11.0051 6.8298,11.0051C6.8588,11.0051 6.8868,10.9801 6.8868,10.9461C6.8858,10.9191 6.8588,10.8951 6.8298,10.8951Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M7.0865,10.942L6.9725,10.942C6.9524,10.942 6.9344,10.924 6.9344,10.9071C6.9344,10.8858 6.9518,10.8705 6.972,10.8705L7.2022,10.8705C7.224,10.8705 7.2404,10.8858 7.2404,10.9071C7.2404,10.924 7.2229,10.942 7.2022,10.942L7.0865,10.942" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.4303,11.0198L7.0103,11.0198C6.9653,11.0198 6.9273,10.9868 6.9273,10.9438C6.9273,10.8968 6.9653,10.8618 7.0093,10.8618L7.4313,10.8618C7.4783,10.8618 7.5133,10.8968 7.5133,10.9438C7.5123,10.9868 7.4773,11.0198 7.4303,11.0198ZM7.0083,10.8888C6.9783,10.8888 6.9523,10.9118 6.9523,10.9438C6.9523,10.9718 6.9783,10.9968 7.0103,10.9968L7.4303,10.9968C7.4623,10.9968 7.4893,10.9728 7.4893,10.9438C7.4893,10.9128 7.4633,10.8888 7.4303,10.8888L7.0083,10.8888Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M6.5144,10.9731L6.4336,10.9835C6.4118,10.9851 6.3927,10.9709 6.39,10.9502C6.3878,10.9322 6.4025,10.9131 6.4238,10.9109L6.5056,10.9011L6.5896,10.8935C6.6104,10.8891 6.6295,10.9033 6.6327,10.9235C6.6344,10.9436 6.6202,10.9605 6.5978,10.9616L6.5144,10.9731" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.4655,11.0731C6.4235,11.0731 6.3885,11.0481 6.3835,11.0071C6.3825,10.9881 6.3875,10.9701 6.4005,10.9511C6.4125,10.9321 6.4335,10.9251 6.4555,10.9231L6.7595,10.8861C6.8055,10.8811 6.8465,10.9091 6.8525,10.9541C6.8525,10.9721 6.8475,10.9951 6.8345,11.0091C6.8225,11.0271 6.8005,11.0401 6.7795,11.0421L6.4775,11.0731C6.4725,11.0731 6.4705,11.0731 6.4655,11.0731ZM6.7695,10.9081C6.7675,10.9081 6.7635,10.9081 6.7635,10.9081L6.4585,10.9471C6.4415,10.9471 6.4295,10.9531 6.4175,10.9671C6.4105,10.9771 6.4055,10.9921 6.4075,11.0021C6.4115,11.0331 6.4415,11.0531 6.4715,11.0491L6.7745,11.0181C6.7915,11.0161 6.8045,11.0021 6.8165,10.9951C6.8225,10.9811 6.8285,10.9721 6.8265,10.9561C6.8225,10.9301 6.7985,10.9081 6.7695,10.9081Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.1822,10.9802C6.1822,10.9605 6.1996,10.9453 6.2198,10.9453C6.2416,10.9453 6.258,10.9605 6.258,10.9802C6.258,11.0004 6.2416,11.0151 6.2198,11.0151C6.1996,11.0151 6.1822,11.0004 6.1822,10.9802" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.2571,11.0925C6.2131,11.0925 6.1751,11.0575 6.1751,11.0165C6.1751,10.9755 6.2131,10.9365 6.2571,10.9365C6.3041,10.9365 6.3391,10.9755 6.3391,11.0165C6.3391,11.0575 6.3041,11.0925 6.2571,11.0925ZM6.2571,10.9595C6.2271,10.9595 6.2001,10.9825 6.2001,11.0165C6.2001,11.0455 6.2261,11.0695 6.2571,11.0695C6.2891,11.0695 6.3161,11.0465 6.3161,11.0165C6.3161,10.9835 6.2901,10.9595 6.2571,10.9595Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M5.9296,11.0473l0.042,-0.0584l0.1178,0.0164l-0.0938,0.0676l-0.066,-0.0256" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.0603,11.1609L5.9193,11.0999L6.0093,10.9829L6.2603,11.0139L6.0603,11.1609ZM5.9583,11.0909L6.0573,11.1319L6.1973,11.0299L6.0213,11.0089L5.9583,11.0909Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M7.6582,10.9731L7.7384,10.9835C7.7602,10.9851 7.7793,10.9709 7.782,10.9502C7.7836,10.9322 7.77,10.9131 7.7482,10.9109L7.6664,10.9011L7.5824,10.8935C7.5616,10.8891 7.5425,10.9033 7.5398,10.9235C7.5376,10.9436 7.5524,10.9605 7.5742,10.9616L7.6582,10.9731" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.921,11.0731L7.921,11.0731C7.915,11.0731 7.913,11.0731 7.909,11.0731L7.606,11.0421C7.584,11.0401 7.563,11.0261 7.551,11.0091C7.537,10.9951 7.532,10.9721 7.534,10.9541C7.539,10.9091 7.581,10.8811 7.626,10.8861L7.93,10.9231C7.951,10.9251 7.972,10.9331 7.985,10.9511C7.997,10.9701 8.003,10.9871 8.003,11.0071C7.996,11.0471 7.961,11.0731 7.921,11.0731ZM7.616,10.9081C7.586,10.9081 7.563,10.9291 7.558,10.9551C7.558,10.9711 7.561,10.9801 7.569,10.9941C7.579,11.0021 7.592,11.0151 7.61,11.0171L7.912,11.0481C7.944,11.0521 7.973,11.0301 7.977,11.0011C7.979,10.9911 7.973,10.9761 7.966,10.9661C7.956,10.9521 7.943,10.9461 7.926,10.9461L7.621,10.9071C7.621,10.9081 7.617,10.9081 7.616,10.9081Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.3418,10.912C7.3418,10.894 7.3598,10.8776 7.38,10.8776C7.4018,10.8776 7.4182,10.8935 7.4182,10.912C7.4182,10.9322 7.4013,10.9491 7.38,10.9491C7.3598,10.9491 7.3418,10.9322 7.3418,10.912" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.4178,11.0301C7.3728,11.0301 7.3358,10.9911 7.3358,10.9461C7.3358,10.9051 7.3728,10.8711 7.4178,10.8711C7.4648,10.8711 7.4998,10.9051 7.4998,10.9461C7.4998,10.9911 7.4648,11.0301 7.4178,11.0301ZM7.4178,10.8951C7.3878,10.8951 7.3598,10.9181 7.3598,10.9461C7.3598,10.9791 7.3878,11.0051 7.4178,11.0051C7.4498,11.0051 7.4768,10.9801 7.4768,10.9461C7.4758,10.9191 7.4498,10.8951 7.4178,10.8951Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.914,10.9802C7.914,10.9605 7.9304,10.9453 7.9522,10.9453C7.9724,10.9453 7.9904,10.9605 7.9904,10.9802C7.9904,11.0004 7.9724,11.0151 7.9522,11.0151C7.9304,11.0151 7.914,11.0004 7.914,10.9802" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.9895,11.0925C7.9425,11.0925 7.9075,11.0575 7.9075,11.0165C7.9075,10.9755 7.9425,10.9365 7.9895,10.9365C8.0335,10.9365 8.0715,10.9755 8.0715,11.0165C8.0715,11.0575 8.0345,11.0925 7.9895,11.0925ZM7.9895,10.9595C7.9565,10.9595 7.9305,10.9825 7.9305,11.0165C7.9305,11.0455 7.9565,11.0695 7.9895,11.0695C8.0195,11.0695 8.0465,11.0465 8.0465,11.0165C8.0465,10.9835 8.0195,10.9595 7.9895,10.9595Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M8.2435,11.0473l-0.0425,-0.0584l-0.1173,0.0164l0.0933,0.0676l0.0665,-0.0256" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.1758,11.1605L8.0662,11.0145L8.2031,10.9835L8.2522,11.1005L8.1758,11.1605ZM8.1022,11.0305L8.1785,11.1325L8.2325,11.0915L8.1982,11.0105L8.1022,11.0305ZM8.124,11.3915C7.8447,11.2485 7.4765,11.1705 7.086,11.1705C6.6971,11.1705 6.3284,11.2485 6.0491,11.3915L6.0453,11.3685C6.3262,11.2255 6.6949,11.1475 7.086,11.1475C7.4771,11.1475 7.8475,11.2255 8.1278,11.3685L8.124,11.3915Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.2275,10.1549L6.2755,10.1931L6.348,10.0753C6.2695,10.0273 6.2165,9.9455 6.2165,9.8495C6.2165,9.838 6.2171,9.8293 6.2176,9.8195C6.2258,9.6689 6.4091,9.5424 6.6404,9.5424C6.7604,9.5424 6.8689,9.5767 6.9458,9.6302C6.9485,9.6062 6.9502,9.5882 6.9535,9.5653C6.8695,9.5167 6.7604,9.4867 6.6404,9.4867C6.3736,9.4867 6.1653,9.6389 6.1549,9.8189C6.1533,9.8287 6.1533,9.8369 6.1533,9.8489C6.1533,9.946 6.1975,10.0311 6.2656,10.0905L6.2275,10.1549" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.3074,10.4791L6.2358,10.4143L6.2826,10.3262C6.1956,10.2381 6.1467,10.1161 6.1467,9.9911C6.1467,9.9753 6.1467,9.9618 6.1481,9.9482C6.1621,9.6847 6.4265,9.4791 6.7525,9.4791C6.8957,9.4791 7.0329,9.5205 7.1407,9.5913L7.1467,9.5966L7.1454,9.6011C7.142,9.6259 7.1394,9.6515 7.1353,9.6892L7.1353,9.705L7.1233,9.6952C7.0276,9.6199 6.8924,9.5792 6.7525,9.5792C6.476,9.5792 6.2525,9.7419 6.2424,9.9497C6.2411,9.9633 6.2411,9.9746 6.2411,9.9911C6.2411,10.1131 6.2993,10.2268 6.3977,10.2938L6.4058,10.3014L6.3074,10.4791ZM6.2565,10.4083L6.3034,10.4497L6.3817,10.3067C6.2826,10.2344 6.2237,10.1146 6.2237,9.9911C6.2237,9.9738 6.225,9.9618 6.225,9.9482C6.2358,9.7291 6.4673,9.5612 6.7525,9.5612C6.8917,9.5612 7.0216,9.6003 7.12,9.6711C7.1226,9.6448 7.1246,9.6229 7.1273,9.6018C7.0222,9.5356 6.8897,9.4972 6.7525,9.4972C6.4359,9.4972 6.1782,9.696 6.1655,9.949C6.1635,9.9625 6.1628,9.9753 6.1628,9.9904C6.1628,10.1139 6.2137,10.2336 6.3,10.3202L6.304,10.324L6.2565,10.4083Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.2302,10.1555C6.1402,10.0884 6.0824,9.9956 6.0824,9.8942C6.0824,9.7758 6.1593,9.6705 6.276,9.6024C6.204,9.6591 6.1604,9.7344 6.1544,9.8195C6.1527,9.8293 6.1527,9.8375 6.1527,9.8495C6.1527,9.9465 6.1969,10.0316 6.2651,10.0911L6.2302,10.1555" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.3634,10.5964L6.3514,10.5906C6.1754,10.4612 6.0764,10.2943 6.0764,10.1208C6.0764,9.9204 6.2074,9.7277 6.4364,9.5964L6.4514,9.6155C6.3184,9.72 6.2434,9.8476 6.2324,9.9904C6.2294,10.0077 6.2284,10.024 6.2284,10.0432C6.2284,10.2004 6.3044,10.3528 6.4334,10.4631L6.4394,10.4679L6.3634,10.5964ZM6.3284,9.6999C6.1824,9.8169 6.1004,9.9664 6.1004,10.1199C6.1004,10.2838 6.1924,10.441 6.3564,10.5599L6.4094,10.4679C6.2794,10.3557 6.2054,10.2004 6.2054,10.0412C6.2054,10.0211 6.2054,10.0038 6.2074,9.9866C6.2174,9.883 6.2574,9.7872 6.3284,9.6999Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M5.4273,10.2738C5.376,10.2176 5.3449,10.144 5.3449,10.0627C5.3449,10.0147 5.3569,9.9667 5.3765,9.9264C5.4502,9.7731 5.682,9.6651 5.9564,9.6651C6.0316,9.6651 6.1025,9.6705 6.1691,9.6875C6.1544,9.7044 6.1435,9.7207 6.1315,9.7387C6.0764,9.7289 6.018,9.7218 5.9564,9.7218C5.706,9.7218 5.4949,9.82 5.4338,9.952C5.418,9.9864 5.4082,10.0245 5.4082,10.0627C5.4082,10.1435 5.4464,10.216 5.5042,10.2651L5.4142,10.4124L5.3645,10.3742L5.4273,10.2738" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.4289,10.6575L5.3591,10.5941L5.4334,10.463C5.3714,10.3868 5.3378,10.2864 5.3378,10.1859C5.3378,10.1226 5.3514,10.0592 5.3766,10.0022C5.4683,9.7963 5.7467,9.6575 6.0704,9.6575C6.1589,9.6575 6.2429,9.6688 6.3243,9.6874L6.3378,9.6909L6.3288,9.7023C6.3113,9.723 6.2991,9.7443 6.2848,9.7693L6.2823,9.7736L6.2777,9.7728C6.2112,9.7579 6.1414,9.7529 6.0717,9.7529C5.7842,9.7529 5.5329,9.8733 5.4606,10.0449C5.4412,10.0905 5.4302,10.1368 5.4302,10.1867C5.4302,10.2871 5.4722,10.3761 5.542,10.4424L5.5478,10.4481L5.4289,10.6575ZM5.3798,10.5919L5.425,10.6311L5.5245,10.4545C5.4535,10.3847 5.4134,10.2878 5.4134,10.1874C5.4134,10.1375 5.4237,10.0869 5.4438,10.0392C5.5193,9.859 5.7771,9.7351 6.0704,9.7351C6.1401,9.7351 6.2086,9.7408 6.2739,9.7529C6.2842,9.7365 6.2958,9.7194 6.3068,9.703C6.2312,9.6867 6.1518,9.6753 6.0704,9.6753C5.7584,9.6753 5.478,9.8141 5.3908,10.0122C5.3669,10.0691 5.354,10.1261 5.354,10.1874C5.354,10.2878 5.3876,10.3818 5.4496,10.4587L5.4509,10.4602L5.4509,10.4673L5.4509,10.4716L5.3798,10.5919Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M5.5205,9.7753C5.4545,9.8189 5.4055,9.8702 5.3765,9.9264C5.3575,9.9667 5.3449,10.0147 5.3449,10.0627C5.3449,10.1435 5.3765,10.2176 5.4273,10.2738L5.3722,10.3633C5.3182,10.2962 5.2882,10.216 5.2882,10.1309C5.2882,9.988 5.3809,9.8609 5.5205,9.7753" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.4496,10.7704L5.4376,10.7613C5.3356,10.6414 5.2816,10.508 5.2816,10.3664C5.2816,10.1356 5.4376,9.92 5.7136,9.7704L5.7266,9.7893C5.6066,9.8578 5.5166,9.9426 5.4676,10.0328C5.4306,10.1049 5.4106,10.177 5.4106,10.2546C5.4106,10.3817 5.4626,10.5008 5.5586,10.5981L5.5646,10.6017L5.4496,10.7704ZM5.4646,9.9877C5.3606,10.1058 5.3066,10.232 5.3066,10.3664C5.3066,10.4935 5.3556,10.6198 5.4466,10.7325L5.5336,10.6035C5.4376,10.5071 5.3856,10.3799 5.3856,10.2528C5.3856,10.1725 5.4066,10.0923 5.4456,10.0201C5.4506,10.0111 5.4566,10.0003 5.4646,9.9877Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0827,9.4578C7.1438,9.4578 7.1951,9.4982 7.2076,9.5516C7.2169,9.6007 7.2207,9.6542 7.2229,9.7115C7.2229,9.718 7.2224,9.7224 7.2224,9.7305C7.2224,9.7349 7.2235,9.7431 7.2235,9.7507C7.2262,9.8729 7.2425,9.9787 7.2682,10.0458L7.0827,10.2225L6.8945,10.0458C6.9202,9.9787 6.936,9.8729 6.9393,9.7507C6.9393,9.7431 6.9398,9.7349 6.9398,9.7305C6.9398,9.7218 6.9393,9.718 6.9393,9.7115C6.9409,9.6542 6.9453,9.6007 6.9545,9.5516C6.9671,9.4982 7.0216,9.4578 7.0827,9.4578" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.2464,10.4496L6.8864,10.2144L6.8894,10.2047C6.9364,10.1219 6.9654,9.9827 6.9714,9.8338C6.9714,9.8296 6.9714,9.824 6.9714,9.8212C6.9714,9.8143 6.9714,9.8115 6.9714,9.8073C6.9714,9.8045 6.9714,9.799 6.9714,9.7962C6.9714,9.7927 6.9714,9.7892 6.9714,9.7823C6.9734,9.7106 6.9834,9.6438 6.9994,9.5784C7.0234,9.5025 7.1294,9.4496 7.2464,9.4496C7.3624,9.4496 7.4634,9.5018 7.4874,9.5784C7.5044,9.6424 7.5124,9.7092 7.5164,9.7823C7.5164,9.7892 7.5164,9.7906 7.5154,9.7962C7.5154,9.799 7.5154,9.8032 7.5154,9.8073C7.5154,9.8108 7.5164,9.8129 7.5164,9.8192C7.5164,9.824 7.5164,9.8296 7.5164,9.8338C7.5224,9.9806 7.5514,10.1212 7.5984,10.2047L7.5994,10.2144L7.2464,10.4496ZM6.9154,10.2061L7.2464,10.426L7.5704,10.2061C7.5254,10.1198 7.4954,9.9792 7.4924,9.8338C7.4924,9.8296 7.4924,9.824 7.4914,9.8212C7.4904,9.8143 7.4894,9.8115 7.4894,9.8073C7.4894,9.8032 7.4894,9.7976 7.4894,9.7962C7.4894,9.7906 7.4904,9.7892 7.4894,9.7823C7.4864,9.7106 7.4794,9.6438 7.4634,9.5805C7.4414,9.5151 7.3504,9.4677 7.2464,9.4677C7.1414,9.4677 7.0434,9.5164 7.0234,9.5805C7.0064,9.6438 6.9994,9.7127 6.9964,9.7823C6.9964,9.7892 6.9964,9.7927 6.9964,9.7962C6.9964,9.799 6.9964,9.8032 6.9964,9.8073C6.9964,9.8115 6.9954,9.8157 6.9944,9.8233C6.9944,9.8254 6.9944,9.8289 6.9944,9.8331C6.9904,9.9806 6.9604,10.1212 6.9154,10.2061Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0827,9.5156C7.1144,9.5156 7.14,9.5353 7.1465,9.5642C7.1547,9.6067 7.1591,9.6591 7.1602,9.7153C7.1602,9.7207 7.1596,9.7262 7.1596,9.73C7.1596,9.7376 7.1618,9.7442 7.1618,9.7513C7.1629,9.8664 7.1798,9.9667 7.2038,10.0284L7.0805,10.1445L6.9578,10.0284C6.9813,9.9678 6.9982,9.8664 6.9998,9.7513C6.9998,9.7442 7.002,9.7376 7.002,9.73C7.002,9.7256 7.0015,9.7202 7.0015,9.7153C7.0025,9.6585 7.0069,9.6067 7.0156,9.5642C7.0227,9.5353 7.0511,9.5156 7.0827,9.5156" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1893,10.508L6.9513,10.3168L6.9523,10.31C6.9973,10.2115 7.0253,10.0531 7.0283,9.8837C7.0283,9.877 7.0293,9.8728 7.0303,9.8686C7.0313,9.8601 7.0323,9.8568 7.0323,9.8509C7.0323,9.8509 7.0323,9.8441 7.0323,9.8374C7.0323,9.8357 7.0323,9.8307 7.0323,9.8273C7.0353,9.743 7.0423,9.6613 7.0593,9.5922C7.0713,9.5409 7.1293,9.508 7.1933,9.508C7.2563,9.508 7.3103,9.5409 7.3223,9.5922C7.3383,9.6613 7.3453,9.7456 7.3483,9.8273C7.3483,9.8307 7.3483,9.8357 7.3483,9.8374C7.3483,9.8441 7.3483,9.8509 7.3483,9.8509C7.3483,9.8576 7.3493,9.8627 7.3503,9.8703C7.3503,9.8728 7.3513,9.877 7.3523,9.8837C7.3533,10.0531 7.3813,10.2115 7.4283,10.31L7.4293,10.3168L7.1893,10.508ZM6.9793,10.3125L7.1893,10.4819L7.3983,10.3125C7.3563,10.2115 7.3273,10.0531 7.3243,9.8854C7.3243,9.8778 7.3233,9.8762 7.3223,9.8711C7.3213,9.8644 7.3213,9.8576 7.3213,9.8517C7.3213,9.8517 7.3213,9.845 7.3213,9.8382C7.3213,9.8366 7.3213,9.8315 7.3213,9.8281C7.3213,9.7473 7.3113,9.6672 7.2973,9.5948C7.2853,9.5552 7.2433,9.5299 7.1923,9.5299C7.1403,9.5299 7.0913,9.5577 7.0813,9.5948C7.0663,9.6655 7.0583,9.7473 7.0563,9.8281C7.0563,9.8315 7.0563,9.8366 7.0573,9.8382C7.0573,9.845 7.0573,9.8517 7.0573,9.8517C7.0573,9.8585 7.0563,9.8652 7.0553,9.8711C7.0543,9.8753 7.0533,9.8778 7.0533,9.8854C7.0523,10.0531 7.0233,10.2123 6.9793,10.3125Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.9358,10.1549L7.8884,10.1931L7.8153,10.0753C7.8944,10.0273 7.9473,9.9455 7.9473,9.8495C7.9473,9.838 7.9462,9.8293 7.9462,9.8195C7.938,9.6689 7.7542,9.5424 7.524,9.5424C7.4029,9.5424 7.2944,9.5767 7.2175,9.6302C7.2153,9.6062 7.2136,9.5882 7.2104,9.5653C7.2944,9.5167 7.4035,9.4867 7.524,9.4867C7.7902,9.4867 7.9991,9.6389 8.0095,9.8189C8.01,9.8287 8.01,9.8369 8.01,9.8489C8.01,9.946 7.9664,10.0311 7.8982,10.0905L7.9358,10.1549" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.042,10.4791L7.9441,10.3014L7.9515,10.2938C8.05,10.2268 8.109,10.1131 8.109,9.9911C8.109,9.9753 8.1083,9.9633 8.1077,9.9497C8.0976,9.7419 7.8731,9.5792 7.597,9.5792C7.4542,9.5792 7.3228,9.6207 7.225,9.6952L7.2129,9.705L7.2129,9.6892C7.2096,9.6553 7.2082,9.632 7.2035,9.6011L7.2022,9.5966L7.2075,9.5913C7.3148,9.5198 7.4535,9.4791 7.597,9.4791C7.9227,9.4791 8.1881,9.6847 8.2022,9.9497C8.2022,9.9633 8.2022,9.9761 8.2022,9.9911C8.2022,10.1161 8.1539,10.2381 8.0668,10.3262L8.1144,10.4143L8.042,10.4791ZM7.9669,10.3067L8.046,10.4497L8.0923,10.4083L8.0453,10.324L8.0507,10.3202C8.1372,10.2344 8.1868,10.1146 8.1868,9.9904C8.1868,9.9768 8.1868,9.964 8.1854,9.949C8.172,9.696 7.914,9.4972 7.5976,9.4972C7.4596,9.4972 7.3268,9.5356 7.2209,9.6018C7.225,9.6259 7.2256,9.6493 7.229,9.6711C7.3275,9.5996 7.4569,9.5612 7.5976,9.5612C7.8831,9.5612 8.1144,9.7291 8.1244,9.9497C8.1251,9.9618 8.1264,9.9731 8.1264,9.9911C8.1258,10.1146 8.0668,10.2321 7.9669,10.3067Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.9331,10.1555C8.0231,10.0884 8.0804,9.9956 8.0804,9.8942C8.0804,9.7758 8.0035,9.6705 7.8873,9.6024C7.9587,9.6591 8.0024,9.7344 8.0089,9.8195C8.0095,9.8293 8.0095,9.8375 8.0095,9.8495C8.0095,9.9465 7.9658,10.0316 7.8976,10.0911L7.9331,10.1555" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.9704,10.5953L7.8934,10.4651L7.9014,10.4603C8.0304,10.3513 8.1044,10.1991 8.1044,10.0412C8.1044,10.024 8.1044,10.0077 8.1024,9.9886C8.0914,9.8469 8.0164,9.7197 7.8824,9.6144L7.8984,9.5953C8.1274,9.7264 8.2574,9.9187 8.2574,10.1187C8.2574,10.2929 8.1594,10.4584 7.9824,10.5876L7.9704,10.5953ZM7.9254,10.468L7.9784,10.5599C8.1434,10.4412 8.2334,10.2843 8.2334,10.1206C8.2334,9.9675 8.1514,9.8182 8.0054,9.7015C8.0754,9.7886 8.1174,9.8833 8.1284,9.9886C8.1284,10.0077 8.1284,10.024 8.1284,10.0431C8.1274,10.201 8.0554,10.356 7.9254,10.468Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.736,10.2738C8.7873,10.2176 8.8189,10.144 8.8189,10.0627C8.8189,10.0147 8.8069,9.9667 8.7867,9.9264C8.7125,9.7731 8.4813,9.6651 8.2069,9.6651C8.1311,9.6651 8.0607,9.6705 7.9942,9.6875C8.01,9.7044 8.0198,9.7207 8.0324,9.7387C8.0864,9.7289 8.1458,9.7218 8.2069,9.7218C8.4578,9.7218 8.6684,9.82 8.7295,9.952C8.7453,9.9864 8.7551,10.0245 8.7551,10.0627C8.7551,10.1435 8.7175,10.216 8.6591,10.2651L8.7491,10.4124L8.7987,10.3742L8.736,10.2738" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.8905,10.6575L8.7722,10.4481L8.7787,10.4424C8.8485,10.3754 8.8905,10.2864 8.8905,10.1867C8.8905,10.1368 8.8795,10.0905 8.8601,10.0449C8.7877,9.8733 8.5369,9.7529 8.2486,9.7529C8.1781,9.7529 8.1083,9.7586 8.0418,9.7728L8.0379,9.7736L8.0346,9.7693C8.0198,9.7415 8.0075,9.723 7.9913,9.7023L7.9816,9.6909L7.9952,9.6874C8.076,9.6688 8.1607,9.6575 8.2486,9.6575C8.5718,9.6575 8.8517,9.7963 8.9435,10.0022C8.9681,10.0592 8.9816,10.1226 8.9816,10.1859C8.9816,10.2864 8.9467,10.3861 8.8866,10.463L8.9603,10.5941L8.8905,10.6575ZM8.7948,10.4538L8.8937,10.6304L8.939,10.5912L8.8659,10.4616L8.8692,10.4573C8.9319,10.3811 8.9648,10.2864 8.9648,10.1859C8.9648,10.1247 8.9525,10.0677 8.928,10.0107C8.8401,9.8134 8.5602,9.6738 8.248,9.6738C8.1659,9.6738 8.0864,9.6852 8.0107,9.7016C8.0224,9.718 8.0333,9.7351 8.0443,9.7515C8.109,9.7387 8.1775,9.7337 8.2473,9.7337C8.5408,9.7337 8.7987,9.8576 8.8743,10.0378C8.8944,10.0855 8.9047,10.1361 8.9047,10.1859C8.906,10.2871 8.8653,10.3847 8.7948,10.4538Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.6427,9.7753C8.7093,9.8189 8.7589,9.8702 8.7873,9.9264C8.8064,9.9667 8.8195,10.0147 8.8195,10.0627C8.8195,10.1435 8.7873,10.2176 8.7365,10.2738L8.7922,10.3633C8.8456,10.2962 8.8756,10.216 8.8756,10.1309C8.8751,9.988 8.7829,9.8609 8.6427,9.7753" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.9155,10.7698L8.8015,10.6004L8.8075,10.5968C8.9035,10.5004 8.9545,10.3806 8.9545,10.2536C8.9545,10.1761 8.9355,10.1041 8.8975,10.032C8.8505,9.9419 8.7585,9.8581 8.6395,9.7887L8.6515,9.7698C8.9255,9.9194 9.0835,10.1347 9.0835,10.3653C9.0835,10.5059 9.0285,10.6401 8.9265,10.7599L8.9155,10.7698ZM8.8325,10.6041L8.9195,10.7329C9.0095,10.6203 9.0585,10.4932 9.0585,10.3671C9.0585,10.2356 9.0035,10.1068 8.9035,9.9923C8.9105,10.0014 8.9155,10.0113 8.9225,10.0221C8.9605,10.0941 8.9815,10.1752 8.9815,10.2545C8.9805,10.3806 8.9265,10.5068 8.8325,10.6041Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.0162,10.0671C7.0162,10.0349 7.0456,10.0065 7.0833,10.0065C7.1187,10.0065 7.1482,10.0355 7.1482,10.0671C7.1482,10.1036 7.1187,10.1309 7.0833,10.1309C7.0456,10.1309 7.0162,10.1036 7.0162,10.0671" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1436,10.2569C7.0676,10.2569 7.0096,10.1939 7.0096,10.1239C7.0096,10.0539 7.0686,9.9989 7.1436,9.9989C7.2146,9.9989 7.2756,10.0539 7.2756,10.1239C7.2756,10.1939 7.2156,10.2569 7.1436,10.2569ZM7.1436,10.0249C7.0826,10.0249 7.0326,10.0689 7.0326,10.1239C7.0326,10.1869 7.0826,10.2309 7.1436,10.2309C7.2026,10.2309 7.2496,10.1859 7.2496,10.1239C7.2506,10.0689 7.2026,10.0249 7.1436,10.0249Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.0162,9.9476C7.0162,9.9127 7.0456,9.8838 7.0833,9.8838C7.1187,9.8838 7.1482,9.9127 7.1482,9.9476C7.1482,9.9798 7.1187,10.0093 7.0833,10.0093C7.0456,10.0098 7.0162,9.9798 7.0162,9.9476" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1436,10.1311C7.0676,10.1311 7.0096,10.0781 7.0096,10.0081C7.0096,9.9381 7.0686,9.8751 7.1436,9.8751C7.2146,9.8751 7.2756,9.9381 7.2756,10.0081C7.2756,10.0781 7.2156,10.1311 7.1436,10.1311ZM7.1436,9.9011C7.0826,9.9011 7.0326,9.9481 7.0326,10.0081C7.0326,10.0611 7.0826,10.1081 7.1436,10.1081C7.2026,10.1081 7.2496,10.0611 7.2496,10.0081C7.2506,9.9481 7.2026,9.9011 7.1436,9.9011Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.0293,9.8145C7.0293,9.7856 7.0538,9.7655 7.0833,9.7655C7.1122,9.7655 7.1345,9.7856 7.1345,9.8145C7.1345,9.8435 7.1122,9.8636 7.0833,9.8636C7.0538,9.8636 7.0293,9.8435 7.0293,9.8145" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1332,9.9654C7.0712,9.9654 7.0222,9.9184 7.0222,9.8614C7.0222,9.8054 7.0712,9.7584 7.1332,9.7584C7.1922,9.7584 7.2392,9.8054 7.2392,9.8614C7.2402,9.9184 7.1922,9.9654 7.1332,9.9654ZM7.1332,9.7834C7.0862,9.7834 7.0472,9.8184 7.0472,9.8614C7.0472,9.9024 7.0862,9.9414 7.1332,9.9414C7.1782,9.9414 7.2152,9.9024 7.2152,9.8614C7.2152,9.8184 7.1792,9.7834 7.1332,9.7834Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.0445,9.6962C7.0445,9.6771 7.0609,9.6591 7.0827,9.6591C7.1029,9.6591 7.1198,9.6771 7.1198,9.6962C7.1198,9.7175 7.1024,9.7327 7.0827,9.7327C7.0609,9.7333 7.0445,9.7175 7.0445,9.6962" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.12,9.8096C7.073,9.8096 7.038,9.7756 7.038,9.7316C7.038,9.6866 7.073,9.6536 7.12,9.6536C7.163,9.6536 7.201,9.6866 7.201,9.7316C7.201,9.7756 7.164,9.8096 7.12,9.8096ZM7.12,9.6776C7.087,9.6776 7.061,9.7006 7.061,9.7326C7.061,9.7616 7.086,9.7856 7.12,9.7856C7.15,9.7856 7.176,9.7626 7.176,9.7326C7.176,9.7006 7.15,9.6776 7.12,9.6776Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.0511,9.5931C7.0511,9.5773 7.0653,9.5642 7.0827,9.5642C7.0991,9.5642 7.1116,9.5767 7.1116,9.5931C7.1116,9.6067 7.0991,9.6198 7.0827,9.6198C7.0653,9.6198 7.0511,9.6067 7.0511,9.5931" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1145,9.688C7.0745,9.688 7.0445,9.661 7.0445,9.624C7.0445,9.588 7.0755,9.556 7.1145,9.556C7.1495,9.556 7.1805,9.588 7.1805,9.624C7.1815,9.661 7.1505,9.688 7.1145,9.688Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0876,10.444L7.1313,10.4505C7.1242,10.4696 7.122,10.4876 7.122,10.5089C7.122,10.5973 7.1984,10.6676 7.2927,10.6676C7.368,10.6676 7.4318,10.6229 7.4536,10.558C7.4569,10.5602 7.47,10.5002 7.4771,10.5007C7.4825,10.5007 7.4825,10.5613 7.4853,10.5613C7.4951,10.642 7.5693,10.6976 7.6533,10.6976C7.7471,10.6976 7.8235,10.6251 7.8235,10.5356C7.8235,10.5291 7.8229,10.5231 7.8213,10.5155L7.8753,10.4631L7.9042,10.5313C7.8922,10.5525 7.8878,10.5765 7.8878,10.6022C7.8878,10.6878 7.9609,10.7555 8.0504,10.7555C8.106,10.7555 8.1562,10.7271 8.1856,10.6878L8.22,10.642L8.22,10.6965C8.22,10.7511 8.2429,10.7969 8.2947,10.8067C8.2947,10.8067 8.3547,10.8084 8.4333,10.7478C8.5129,10.6862 8.5571,10.6344 8.5571,10.6344L8.5636,10.6955C8.5636,10.6955 8.4976,10.798 8.4256,10.8405C8.3875,10.8618 8.3269,10.8853 8.2795,10.8809C8.2298,10.8711 8.1944,10.8296 8.1764,10.7827C8.1404,10.8056 8.0978,10.8171 8.0525,10.8171C7.956,10.8171 7.8693,10.7658 7.8349,10.684C7.7902,10.732 7.7275,10.7631 7.6549,10.7631C7.5769,10.7631 7.5055,10.7282 7.4613,10.6747C7.4182,10.7151 7.3587,10.7396 7.2933,10.7396C7.2076,10.7396 7.1318,10.6949 7.0871,10.6322C7.0445,10.6949 6.9687,10.7396 6.8825,10.7396C6.8165,10.7396 6.7576,10.7151 6.7129,10.6747C6.6687,10.7282 6.5978,10.7631 6.5209,10.7631C6.4478,10.7631 6.3851,10.732 6.3409,10.684C6.3071,10.7658 6.2187,10.8171 6.1216,10.8171C6.0769,10.8171 6.0349,10.8056 5.9995,10.7827C5.9809,10.8296 5.9455,10.8711 5.8947,10.8809C5.8473,10.8853 5.7889,10.8618 5.7485,10.8405C5.6771,10.798 5.6111,10.6955 5.6111,10.6955L5.6182,10.6344C5.6182,10.6344 5.6618,10.6862 5.7415,10.7478C5.8216,10.8084 5.8805,10.8067 5.8805,10.8067C5.9329,10.7964 5.9558,10.7505 5.9558,10.6965L5.9558,10.642L5.9891,10.6878C6.0185,10.7271 6.0676,10.7555 6.1249,10.7555C6.2144,10.7555 6.2864,10.6878 6.2864,10.6022C6.2864,10.5765 6.2815,10.5525 6.2705,10.5313L6.2989,10.4631L6.3518,10.5155C6.3518,10.5231 6.3518,10.5291 6.3518,10.5356C6.3518,10.6251 6.4271,10.6976 6.5209,10.6976C6.6038,10.6976 6.678,10.642 6.69,10.5613C6.6916,10.5613 6.6905,10.5007 6.6971,10.5007C6.7036,10.5002 6.7184,10.5602 6.72,10.558C6.7424,10.6229 6.8062,10.6676 6.8825,10.6676C6.9758,10.6676 7.0516,10.5973 7.0516,10.5089C7.0516,10.4876 7.0516,10.4696 7.044,10.4505L7.0876,10.444" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2985,11.2614C8.2909,11.2614 8.2849,11.2594 8.2784,11.2594C8.2336,11.2474 8.1955,11.1864 8.1731,11.0934C8.1355,11.1304 8.0945,11.1464 8.052,11.1464C7.9571,11.1464 7.8693,11.0524 7.8311,10.9124C7.7847,11.0004 7.722,11.0474 7.6544,11.0474C7.5791,11.0474 7.5082,10.9884 7.4602,10.8894C7.4149,10.9634 7.3549,11.0024 7.2927,11.0024C7.2109,11.0024 7.134,10.9324 7.0865,10.8164C7.0402,10.9314 6.9644,11.0024 6.882,11.0024C6.8187,11.0024 6.7604,10.9634 6.7129,10.8894C6.6665,10.9894 6.594,11.0474 6.5204,11.0474C6.4522,11.0474 6.3895,11.0004 6.3415,10.9124C6.3038,11.0534 6.2171,11.1464 6.1211,11.1464C6.0791,11.1464 6.0382,11.1304 6.0027,11.0934C5.9798,11.1864 5.9411,11.2474 5.8953,11.2594C5.8887,11.2594 5.8822,11.2614 5.8745,11.2614C5.8216,11.2614 5.766,11.2104 5.7442,11.1874C5.6727,11.1114 5.6073,10.9284 5.6051,10.9234L5.6035,10.9174L5.6127,10.7674L5.6225,10.7904C5.6225,10.7904 5.6673,10.8844 5.7442,10.9984C5.814,11.0954 5.8685,11.1024 5.8784,11.1024C5.9225,11.0894 5.9487,11.0194 5.9487,10.9134L5.9482,10.7824L5.9935,10.8864C6.0224,10.9644 6.0715,11.0094 6.1244,11.0094C6.2095,11.0094 6.2793,10.8864 6.2793,10.7404C6.2793,10.6914 6.2749,10.6494 6.2645,10.6184L6.2624,10.6104L6.2973,10.4624L6.3589,10.5794L6.3584,10.5854C6.3584,10.5984 6.3584,10.6084 6.3584,10.6184C6.3584,10.7764 6.4315,10.9024 6.5209,10.9024C6.6038,10.9024 6.6725,10.8034 6.6829,10.6654L6.684,10.6474L6.684,10.6474C6.684,10.6414 6.684,10.6334 6.684,10.6264C6.6867,10.5564 6.6867,10.5444 6.6965,10.5414L6.6965,10.5414C6.7053,10.5414 6.7091,10.5564 6.7189,10.6214C6.7205,10.6264 6.7222,10.6344 6.7222,10.6424L6.7227,10.6424L6.7255,10.6524C6.7473,10.7694 6.8105,10.8534 6.8815,10.8534C6.9709,10.8534 7.044,10.7204 7.044,10.5704C7.044,10.5334 7.044,10.5024 7.0369,10.4684L7.0342,10.4544L7.0876,10.4364L7.1405,10.4544L7.1378,10.4684C7.1307,10.5014 7.1291,10.5344 7.1291,10.5704C7.1291,10.7204 7.2022,10.8534 7.2927,10.8534C7.3642,10.8534 7.4258,10.7694 7.4476,10.6544L7.4509,10.6424L7.4509,10.6424C7.4525,10.6344 7.4536,10.6264 7.4542,10.6194C7.4656,10.5564 7.47,10.5414 7.4771,10.5414C7.4864,10.5454 7.4885,10.5574 7.4896,10.6274C7.4896,10.6374 7.4902,10.6434 7.4902,10.6484L7.4918,10.6664C7.5016,10.8054 7.5698,10.9034 7.6533,10.9034C7.7438,10.9034 7.8164,10.7774 7.8164,10.6194C7.8164,10.6074 7.8158,10.5964 7.8147,10.5864L7.8147,10.5804L7.878,10.4634L7.9107,10.6114L7.9107,10.6194C7.8998,10.6504 7.8944,10.6924 7.8944,10.7414C7.8944,10.8874 7.9647,11.0104 8.0504,11.0104C8.1022,11.0104 8.1502,10.9654 8.1791,10.8874L8.2265,10.7834L8.226,10.9144C8.226,11.0204 8.2522,11.0914 8.2942,11.1034C8.3056,11.1034 8.3591,11.0954 8.4284,10.9994C8.5069,10.8854 8.55,10.7914 8.5505,10.7914L8.5615,10.7684L8.5702,10.9184L8.5696,10.9244C8.5658,10.9294 8.502,11.1124 8.4289,11.1884C8.4076,11.2104 8.352,11.2614 8.2985,11.2614ZM8.1796,11.0564L8.1824,11.0704C8.2015,11.1644 8.2375,11.2244 8.2811,11.2364C8.2865,11.2364 8.2925,11.2364 8.2985,11.2364C8.3504,11.2364 8.406,11.1814 8.4224,11.1664C8.4862,11.0964 8.5467,10.9364 8.5571,10.9084L8.5516,10.8304C8.5342,10.8614 8.4955,10.9344 8.4382,11.0184C8.3651,11.1224 8.3073,11.1294 8.2964,11.1294L8.2947,11.1294C8.2435,11.1114 8.2129,11.0334 8.2129,10.9144L8.2129,10.8534L8.1911,10.9054C8.16,10.9844 8.1065,11.0354 8.0509,11.0354C7.9576,11.0354 7.8818,10.9004 7.8818,10.7414C7.8818,10.6894 7.8862,10.6484 7.8965,10.6114L7.8725,10.5094L7.8289,10.5894C7.83,10.5984 7.8305,10.6094 7.8305,10.6184C7.8305,10.7904 7.7509,10.9284 7.6533,10.9284C7.5627,10.9284 7.4896,10.8184 7.4787,10.6704C7.4765,10.6654 7.476,10.6494 7.476,10.6284C7.476,10.6184 7.476,10.6014 7.4749,10.5854C7.4727,10.6014 7.4695,10.6184 7.4667,10.6264C7.4629,10.6494 7.4618,10.6634 7.4596,10.6654C7.4345,10.7904 7.368,10.8764 7.2922,10.8764C7.1945,10.8764 7.1144,10.7354 7.1144,10.5694C7.1144,10.5364 7.1155,10.5064 7.1209,10.4754L7.0871,10.4614L7.0516,10.4754C7.0565,10.5034 7.0571,10.5344 7.0571,10.5694C7.0571,10.7354 6.978,10.8764 6.8809,10.8764C6.804,10.8764 6.7369,10.7904 6.7135,10.6654C6.7113,10.6634 6.7091,10.6494 6.7047,10.6264C6.7042,10.6184 6.7009,10.6014 6.6982,10.5854C6.6976,10.6014 6.6965,10.6184 6.696,10.6264C6.6955,10.6494 6.6955,10.6654 6.6944,10.6714C6.6824,10.8174 6.6087,10.9284 6.5193,10.9284C6.4216,10.9284 6.3431,10.7904 6.3431,10.6184C6.3431,10.6104 6.3436,10.5994 6.3436,10.5894L6.2989,10.5094L6.276,10.6114C6.2858,10.6484 6.2913,10.6894 6.2913,10.7414C6.2913,10.9004 6.2155,11.0354 6.1227,11.0354C6.0655,11.0354 6.0131,10.9844 5.982,10.9034L5.9596,10.8534L5.9596,10.9144C5.9596,11.0334 5.9296,11.1114 5.8795,11.1294L5.8767,11.1294C5.8653,11.1294 5.8075,11.1214 5.7355,11.0184C5.6787,10.9344 5.6384,10.8624 5.6215,10.8304L5.6165,10.9084C5.6264,10.9354 5.6864,11.0964 5.7507,11.1664C5.8009,11.2194 5.8549,11.2484 5.8931,11.2364C5.9351,11.2244 5.9711,11.1644 5.9918,11.0704L5.9945,11.0564L6.0016,11.0644C6.0371,11.1034 6.0785,11.1214 6.12,11.1214C6.2138,11.1214 6.2989,11.0254 6.3333,10.8854L6.3376,10.8694L6.3442,10.8834C6.3889,10.9714 6.4522,11.0234 6.5198,11.0234C6.5924,11.0234 6.6627,10.9634 6.7069,10.8624L6.7118,10.8544L6.7173,10.8624C6.7615,10.9364 6.8198,10.9794 6.8815,10.9794C6.9622,10.9794 7.038,10.9094 7.0811,10.7904L7.086,10.7764L7.0925,10.7904C7.1367,10.9094 7.2104,10.9794 7.2922,10.9794C7.3544,10.9794 7.4122,10.9364 7.4569,10.8624L7.4618,10.8544L7.4662,10.8624C7.5109,10.9644 7.5813,11.0234 7.6544,11.0234C7.722,11.0234 7.7831,10.9714 7.8284,10.8834L7.836,10.8694L7.8409,10.8854C7.8731,11.0264 7.9587,11.1214 8.0525,11.1214C8.0951,11.1214 8.1365,11.1034 8.1725,11.0644L8.1796,11.0564Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.256,10.6551C8.2653,10.6278 8.256,10.5995 8.2369,10.5913C8.2145,10.5869 8.1905,10.6038 8.1802,10.6327C8.1698,10.6627 8.1791,10.6895 8.2004,10.6955C8.2205,10.702 8.2462,10.6851 8.256,10.6551" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2404,10.8046L8.2404,10.8046C8.2344,10.8046 8.2284,10.8046 8.2224,10.7996C8.2044,10.7976 8.1894,10.7836 8.1804,10.7626C8.1664,10.7376 8.1654,10.7056 8.1774,10.6666C8.1984,10.6116 8.2514,10.5726 8.2944,10.5886C8.3114,10.5936 8.3274,10.6046 8.3354,10.6196C8.3494,10.6466 8.3514,10.6846 8.3394,10.7176C8.3224,10.7706 8.2814,10.8046 8.2404,10.8046ZM8.2754,10.6126C8.2464,10.6126 8.2164,10.6356 8.2014,10.6786C8.1934,10.7056 8.1934,10.7346 8.2034,10.7526C8.2094,10.7646 8.2174,10.7756 8.2284,10.7756C8.2344,10.7786 8.2374,10.7786 8.2404,10.7786C8.2704,10.7786 8.3034,10.7526 8.3164,10.7116C8.3254,10.6826 8.3244,10.6566 8.3154,10.6356C8.3104,10.6236 8.3024,10.6146 8.2874,10.6126C8.2844,10.6126 8.2814,10.6126 8.2754,10.6126Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.5164,10.5133C7.5207,10.4833 7.5049,10.4565 7.4836,10.4538C7.4624,10.4511 7.4405,10.4735 7.4378,10.5018C7.4345,10.5351 7.4476,10.5613 7.47,10.5629C7.4924,10.5645 7.512,10.5422 7.5164,10.5133" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.5079,10.6712L7.5079,10.6712C7.5069,10.6712 7.5029,10.6712 7.5029,10.6712C7.4829,10.6672 7.4679,10.6602 7.4539,10.6422C7.4349,10.6192 7.4259,10.5872 7.4329,10.5482C7.4389,10.4892 7.4839,10.4442 7.5319,10.4462C7.5499,10.4512 7.5669,10.4582 7.5789,10.4752C7.5969,10.4982 7.6049,10.5342 7.6009,10.5692C7.5919,10.6302 7.5539,10.6712 7.5079,10.6712ZM7.5219,10.4732C7.4909,10.4732 7.4609,10.5072 7.4559,10.5522C7.4529,10.5832 7.4589,10.6112 7.4729,10.6302C7.4809,10.6402 7.4919,10.6442 7.5039,10.6462C7.5369,10.6522 7.5689,10.6162 7.5759,10.5672C7.5789,10.5412 7.5739,10.5112 7.5589,10.4942C7.5499,10.4782 7.5379,10.4752 7.5259,10.4732C7.5259,10.4732 7.5249,10.4732 7.5219,10.4732Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.6584,10.5133C6.6545,10.4833 6.6682,10.4565 6.6905,10.4538C6.7129,10.4505 6.732,10.4735 6.7364,10.5018C6.7402,10.5351 6.7249,10.5613 6.7036,10.5629C6.6824,10.5645 6.6611,10.5422 6.6584,10.5133" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.7418,10.6712C6.6998,10.6712 6.6578,10.6302 6.6528,10.5692C6.6468,10.5342 6.6538,10.5012 6.6738,10.4752C6.6868,10.4572 6.7028,10.4512 6.7218,10.4462C6.7688,10.4462 6.8108,10.4892 6.8198,10.5482C6.8238,10.5872 6.8168,10.6182 6.7988,10.6422C6.7848,10.6612 6.7698,10.6672 6.7508,10.6712C6.7468,10.6712 6.7468,10.6712 6.7418,10.6712ZM6.7288,10.4732C6.7288,10.4732 6.7258,10.4732 6.7238,10.4732C6.7118,10.4752 6.7018,10.4782 6.6938,10.4942C6.6788,10.5122 6.6718,10.5412 6.6768,10.5672C6.6818,10.6162 6.7148,10.6522 6.7468,10.6462C6.7588,10.6442 6.7698,10.6402 6.7778,10.6302C6.7938,10.6102 6.7988,10.5832 6.7948,10.5522C6.7888,10.5072 6.7598,10.4732 6.7288,10.4732Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.9182,10.6551C5.9078,10.6278 5.9165,10.5995 5.9384,10.5913C5.958,10.5869 5.9836,10.6038 5.9935,10.6327C6.0027,10.6627 5.994,10.6895 5.9744,10.6955C5.9525,10.702 5.9285,10.6851 5.9182,10.6551" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.0117,10.8047C5.9717,10.8047 5.9327,10.7707 5.9157,10.7177C5.9037,10.6857 5.9067,10.6477 5.9177,10.6197C5.9277,10.6037 5.9407,10.5937 5.9597,10.5887C5.9647,10.5867 5.9717,10.5847 5.9797,10.5847C6.0197,10.5847 6.0597,10.6197 6.0777,10.6667C6.0897,10.7057 6.0897,10.7367 6.0747,10.7627C6.0667,10.7837 6.0517,10.7977 6.0337,10.7997C6.0257,10.8047 6.0187,10.8047 6.0117,10.8047ZM5.9787,10.6127C5.9767,10.6127 5.9707,10.6127 5.9657,10.6127C5.9527,10.6157 5.9447,10.6247 5.9407,10.6357C5.9287,10.6567 5.9287,10.6827 5.9387,10.7117C5.9527,10.7577 5.9947,10.7837 6.0237,10.7757C6.0347,10.7757 6.0447,10.7637 6.0507,10.7527C6.0607,10.7337 6.0617,10.7057 6.0517,10.6787C6.0397,10.6357 6.0077,10.6127 5.9787,10.6127Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.2389,10.1642C6.276,10.1855 6.3076,10.2236 6.3191,10.2673C6.3191,10.2673 6.3229,10.2585 6.3436,10.246C6.3638,10.2345 6.3807,10.2351 6.3807,10.2351C6.3807,10.2351 6.3753,10.2695 6.3725,10.2815C6.3698,10.2929 6.3687,10.33 6.3605,10.3611C6.3535,10.3955 6.3387,10.4205 6.3387,10.4205C6.3251,10.408 6.3055,10.4015 6.2842,10.4069C6.264,10.4096 6.2482,10.4205 6.2384,10.4369C6.2384,10.4369 6.216,10.4178 6.1969,10.3878C6.1778,10.3611 6.1647,10.3284 6.1576,10.3185C6.15,10.3071 6.1331,10.2782 6.1331,10.2782C6.1331,10.2782 6.1489,10.2716 6.1718,10.276C6.1953,10.2804 6.2035,10.2858 6.2035,10.2858C6.198,10.2416 6.2138,10.1947 6.2389,10.1642" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.3384,10.6898L6.3274,10.6818C6.3244,10.6778 6.2834,10.6428 6.2474,10.5938C6.2264,10.5568 6.2084,10.5258 6.1954,10.4978C6.1884,10.4808 6.1824,10.4648 6.1764,10.4608C6.1634,10.4398 6.1314,10.3878 6.1294,10.3848L6.1244,10.3718L6.1364,10.3678C6.1374,10.3678 6.1554,10.3618 6.1824,10.3618C6.1944,10.3618 6.2054,10.3618 6.2164,10.3648C6.2334,10.3678 6.2474,10.3698 6.2554,10.3758C6.2524,10.2998 6.2774,10.2218 6.3244,10.1588L6.3314,10.1538L6.3404,10.1588C6.4104,10.2028 6.4634,10.2678 6.4864,10.3388C6.4924,10.3308 6.5044,10.3228 6.5204,10.3158C6.5574,10.2928 6.5884,10.2928 6.5944,10.2928L6.6104,10.2928L6.6074,10.3068C6.6074,10.3108 6.5974,10.3698 6.5924,10.3928C6.5894,10.3988 6.5874,10.4148 6.5874,10.4338C6.5844,10.4618 6.5814,10.5038 6.5714,10.5378C6.5574,10.5988 6.5314,10.6478 6.5294,10.6498L6.5224,10.6648L6.5104,10.6528C6.4874,10.6318 6.4534,10.6248 6.4214,10.6298C6.3884,10.6338 6.3614,10.6528 6.3464,10.6788L6.3384,10.6898ZM6.1604,10.3888C6.1714,10.4098 6.1894,10.4328 6.1974,10.4468C6.2034,10.4568 6.2104,10.4678 6.2184,10.4878C6.2324,10.5128 6.2484,10.5508 6.2704,10.5798C6.2934,10.6128 6.3184,10.6438 6.3344,10.6518C6.3534,10.6288 6.3824,10.6088 6.4174,10.6048C6.4524,10.5968 6.4874,10.6048 6.5164,10.6258C6.5234,10.6048 6.5394,10.5738 6.5474,10.5328C6.5584,10.4978 6.5594,10.4568 6.5644,10.4308C6.5644,10.4098 6.5654,10.3938 6.5684,10.3858C6.5704,10.3698 6.5764,10.3388 6.5814,10.3188C6.5694,10.3218 6.5524,10.3238 6.5344,10.3398C6.5004,10.3558 6.4934,10.3688 6.4934,10.3688L6.4764,10.3938L6.4694,10.3658C6.4514,10.2988 6.4034,10.2298 6.3374,10.1848C6.2934,10.2478 6.2734,10.3238 6.2814,10.3938L6.2844,10.4328L6.2594,10.4098L6.2594,10.4098C6.2594,10.4098 6.2464,10.3938 6.2114,10.3908C6.1944,10.3858 6.1724,10.3858 6.1604,10.3888Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.2553,10.5144C6.2427,10.5067 6.234,10.4942 6.2318,10.4773C6.2291,10.4636 6.2329,10.4489 6.2395,10.4364C6.2395,10.4364 6.2095,10.4211 6.1762,10.4124C6.1516,10.4069 6.1085,10.4058 6.0949,10.4058C6.0813,10.4047 6.054,10.4042 6.054,10.4042C6.054,10.4042 6.0573,10.4107 6.0638,10.4233C6.0731,10.4375 6.0818,10.4495 6.0818,10.4495C6.0382,10.4593 6,10.4876 5.9776,10.5231C6.0115,10.5455 6.0578,10.5602 6.102,10.5531C6.102,10.5531 6.0982,10.5656 6.0955,10.5864C6.0927,10.6 6.0927,10.6044 6.0927,10.6044C6.0927,10.6044 6.1178,10.5978 6.1298,10.5918C6.1418,10.5875 6.1827,10.5749 6.2051,10.5607C6.2313,10.54 6.2553,10.5144 6.2553,10.5144" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.1838,10.799L6.1838,10.779C6.1838,10.777 6.1838,10.769 6.1878,10.742C6.1898,10.722 6.1928,10.707 6.1958,10.699C6.1198,10.705 6.0428,10.681 5.9768,10.636L5.9678,10.628L5.9728,10.616C6.0198,10.555 6.0848,10.507 6.1548,10.487C6.1488,10.473 6.1428,10.464 6.1328,10.448C6.1198,10.425 6.1138,10.417 6.1138,10.417L6.1078,10.396L6.1258,10.398C6.1258,10.398 6.1758,10.399 6.2008,10.399L6.2058,10.399C6.2378,10.399 6.3088,10.401 6.3548,10.415C6.4138,10.425 6.4708,10.456 6.4718,10.458L6.4838,10.464L6.4778,10.472C6.4648,10.495 6.4608,10.519 6.4648,10.542C6.4678,10.565 6.4828,10.589 6.5018,10.605L6.4958,10.613L6.5038,10.627C6.5018,10.629 6.4608,10.672 6.4078,10.705C6.3728,10.73 6.3088,10.754 6.2778,10.766L6.1838,10.799ZM6.2308,10.676L6.2258,10.692C6.2248,10.692 6.2178,10.712 6.2128,10.747C6.2118,10.753 6.2098,10.755 6.2098,10.764L6.2668,10.743C6.2968,10.731 6.3608,10.708 6.3948,10.684C6.4308,10.661 6.4608,10.629 6.4778,10.614C6.4578,10.598 6.4438,10.575 6.4398,10.55C6.4358,10.523 6.4378,10.497 6.4488,10.474C6.4308,10.466 6.3898,10.451 6.3488,10.441C6.3068,10.427 6.2318,10.427 6.2058,10.427L6.2008,10.427C6.1848,10.425 6.1628,10.425 6.1478,10.425C6.1498,10.427 6.1528,10.435 6.1558,10.443C6.1728,10.469 6.1848,10.49 6.1848,10.49L6.1978,10.5L6.1788,10.508C6.1108,10.522 6.0468,10.566 6.0028,10.625C6.0658,10.662 6.1398,10.684 6.2108,10.678L6.2308,10.678L6.2308,10.676Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.3535,10.4991C6.3605,10.4876 6.3638,10.4718 6.3611,10.4582C6.3584,10.4413 6.3507,10.4282 6.3382,10.4211C6.3382,10.4211 6.3611,10.3955 6.3895,10.3753C6.4107,10.3616 6.4516,10.3475 6.4636,10.3442C6.4756,10.3376 6.5007,10.3316 6.5007,10.3316C6.5007,10.3316 6.5007,10.336 6.498,10.3496C6.4958,10.3698 6.4915,10.3818 6.4915,10.3818C6.5362,10.3742 6.582,10.3916 6.6158,10.414C6.5935,10.4484 6.5553,10.4767 6.5111,10.4871C6.5111,10.4871 6.5198,10.4985 6.5291,10.5127C6.5362,10.5264 6.5395,10.5324 6.5395,10.5324C6.5395,10.5324 6.5122,10.5313 6.4985,10.5302C6.4855,10.5302 6.4418,10.5302 6.4173,10.5236C6.384,10.5149 6.3535,10.5007 6.3535,10.5007" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.7338,10.7211L6.7148,10.7211C6.7148,10.7211 6.6648,10.7191 6.6408,10.7191L6.6338,10.7191C6.6048,10.7161 6.5318,10.7161 6.4878,10.7041C6.4288,10.6901 6.3708,10.6611 6.3688,10.6591L6.3748,10.6481L6.3638,10.6451C6.3758,10.6221 6.3818,10.5981 6.3758,10.5751C6.3728,10.5521 6.3588,10.5281 6.3398,10.5121L6.3278,10.5041L6.3378,10.4901C6.3388,10.4881 6.3808,10.4451 6.4328,10.4101C6.4708,10.3871 6.5418,10.3631 6.5678,10.3471C6.5938,10.3391 6.6378,10.3241 6.6378,10.3241L6.6548,10.3191L6.6548,10.3381C6.6548,10.3401 6.6548,10.3481 6.6508,10.3771C6.6498,10.3931 6.6458,10.4081 6.6438,10.4161C6.7208,10.4131 6.7958,10.4371 6.8628,10.4801L6.8728,10.4881L6.8668,10.5021C6.8198,10.5611 6.7558,10.6091 6.6858,10.6291C6.6908,10.6411 6.6978,10.6501 6.7058,10.6681C6.7208,10.6911 6.7258,10.6991 6.7258,10.6991L6.7338,10.7211ZM6.3918,10.6461C6.4118,10.6521 6.4528,10.6691 6.4938,10.6791C6.5358,10.6931 6.6058,10.6931 6.6348,10.6931L6.6418,10.6931C6.6578,10.6931 6.6798,10.6931 6.6948,10.6961C6.6938,10.6931 6.6898,10.6851 6.6878,10.6771C6.6698,10.6521 6.6568,10.6301 6.6568,10.6301L6.6438,10.6201L6.6638,10.6121C6.7308,10.5981 6.7948,10.5541 6.8398,10.4971C6.7748,10.4581 6.6998,10.4341 6.6298,10.4421L6.6108,10.4421L6.6168,10.4261C6.6168,10.4261 6.6238,10.4061 6.6288,10.3711C6.6298,10.3661 6.6308,10.3631 6.6318,10.3551C6.6168,10.3631 6.5948,10.3691 6.5818,10.3711L6.5798,10.3711C6.5568,10.3851 6.4838,10.4101 6.4478,10.4341C6.4118,10.4571 6.3838,10.4871 6.3658,10.5041C6.3858,10.5201 6.3988,10.5431 6.4028,10.5681C6.4058,10.5951 6.4038,10.6231 6.3918,10.6461Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M6.2236,10.4664C6.2236,10.4271 6.2564,10.3949 6.2978,10.3949C6.3387,10.3949 6.3736,10.4271 6.3736,10.4664C6.3736,10.5056 6.3393,10.5384 6.2978,10.5384C6.2564,10.5384 6.2236,10.5062 6.2236,10.4664" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.3641,10.6763C6.2811,10.6763 6.2171,10.6133 6.2171,10.5323C6.2171,10.4543 6.2811,10.3873 6.3641,10.3873C6.4471,10.3873 6.5151,10.4533 6.5151,10.5323C6.5151,10.6133 6.4471,10.6763 6.3641,10.6763ZM6.3641,10.4133C6.2961,10.4133 6.2401,10.4703 6.2401,10.5323C6.2401,10.5963 6.2961,10.6513 6.3641,10.6513C6.4331,10.6513 6.4901,10.5963 6.4901,10.5323C6.4911,10.4703 6.4331,10.4133 6.3641,10.4133Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0849,10.0502C7.1209,10.0802 7.1487,10.1309 7.1525,10.1811C7.1525,10.1811 7.1591,10.1702 7.1836,10.1642C7.2082,10.1538 7.2278,10.1565 7.2278,10.1565C7.2278,10.1565 7.2142,10.1936 7.2087,10.2067C7.2033,10.2198 7.1951,10.2591 7.1793,10.2929C7.1651,10.3289 7.1438,10.3556 7.1438,10.3556C7.1302,10.3387 7.1084,10.3289 7.0865,10.3289C7.0631,10.3289 7.0418,10.3387 7.0293,10.3556C7.0293,10.3556 7.0064,10.3289 6.9916,10.2929C6.9764,10.2585 6.9682,10.2193 6.9627,10.2067C6.9573,10.1942 6.9431,10.1565 6.9431,10.1565C6.9431,10.1565 6.9627,10.1538 6.9873,10.1642C7.0129,10.1707 7.0195,10.1811 7.0195,10.1811C7.0227,10.1309 7.0489,10.0796 7.0849,10.0502" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.3179,10.6364L7.3079,10.6254C7.2829,10.5974 7.2479,10.5814 7.2129,10.5814C7.1739,10.5814 7.1389,10.5974 7.1149,10.6254L7.1059,10.6364L7.0959,10.6254C7.0959,10.6204 7.0549,10.5734 7.0279,10.5094C7.0099,10.4684 6.9969,10.4254 6.9889,10.3924C6.9839,10.3714 6.9789,10.3594 6.9749,10.3474C6.9649,10.3244 6.9399,10.2614 6.9389,10.2574L6.9349,10.2454L6.9499,10.2454C6.9499,10.2454 6.9859,10.2314 7.0379,10.2534C7.0559,10.2594 7.0719,10.2694 7.0799,10.2744C7.0919,10.1884 7.1369,10.1044 7.2019,10.0444L7.2109,10.0404L7.2189,10.0444C7.2859,10.1074 7.3309,10.1904 7.3439,10.2734C7.3549,10.2684 7.3679,10.2584 7.3899,10.2524C7.4389,10.2314 7.4769,10.2424 7.4769,10.2444L7.4889,10.2444L7.4849,10.2564C7.4839,10.2604 7.4609,10.3224 7.4489,10.3464C7.4469,10.3584 7.4419,10.3694 7.4369,10.3914C7.4269,10.4244 7.4149,10.4674 7.3959,10.5084C7.3689,10.5724 7.3319,10.6194 7.3289,10.6244L7.3179,10.6364ZM6.9669,10.2674C6.9759,10.2874 6.9899,10.3244 6.9959,10.3394C7.0009,10.3474 7.0069,10.3654 7.0129,10.3864C7.0189,10.4174 7.0319,10.4614 7.0489,10.5014C7.0699,10.5444 7.0949,10.5794 7.1069,10.5974C7.1359,10.5744 7.1709,10.5564 7.2119,10.5564C7.2509,10.5564 7.2879,10.5744 7.3159,10.5974C7.3289,10.5794 7.3529,10.5444 7.3719,10.5014C7.3889,10.4624 7.4009,10.4174 7.4119,10.3864C7.4169,10.3654 7.4219,10.3474 7.4259,10.3394C7.4339,10.3234 7.4469,10.2864 7.4549,10.2674C7.4409,10.2694 7.4199,10.2694 7.3949,10.2774C7.3539,10.2934 7.3429,10.3024 7.3429,10.3044L7.3229,10.3294L7.3209,10.2984C7.3149,10.2204 7.2739,10.1344 7.2099,10.0734C7.1469,10.1344 7.1069,10.2184 7.1009,10.2984L7.1009,10.3324L7.0799,10.3024L7.0799,10.3024C7.0799,10.3024 7.0679,10.2924 7.0279,10.2774C7.0019,10.2694 6.9829,10.2674 6.9669,10.2674Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0287,10.4462C7.0178,10.4336 7.0102,10.4173 7.0102,10.3993C7.0102,10.3824 7.0173,10.366 7.0287,10.3545C7.0287,10.3545 6.9971,10.3311 6.9622,10.3153C6.9355,10.3038 6.888,10.2945 6.8722,10.2929C6.858,10.2896 6.8285,10.2831 6.8285,10.2831C6.8285,10.2831 6.8302,10.2918 6.8356,10.3055C6.8433,10.3256 6.8493,10.3387 6.8493,10.3387C6.798,10.3431 6.75,10.3687 6.7173,10.3993C6.75,10.4336 6.798,10.4587 6.8493,10.4604C6.8493,10.4604 6.8427,10.4729 6.8356,10.492C6.8302,10.51 6.8285,10.5144 6.8285,10.5144C6.8285,10.5144 6.858,10.51 6.8722,10.5078C6.888,10.5035 6.9355,10.4969 6.9622,10.4844C6.9971,10.4685 7.0287,10.4462 7.0287,10.4462" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.9145,10.7304L6.9165,10.7144C6.9165,10.7144 6.9205,10.7004 6.9305,10.6674C6.9375,10.6514 6.9445,10.6364 6.9485,10.6244C6.8625,10.6154 6.7805,10.5734 6.7155,10.5154L6.7085,10.5034L6.7155,10.4954C6.7805,10.4324 6.8635,10.3904 6.9485,10.3814C6.9445,10.3704 6.9375,10.3554 6.9305,10.3374C6.9205,10.3084 6.9165,10.2924 6.9165,10.2924L6.9145,10.2744L7.0195,10.2924C7.0545,10.3024 7.1335,10.3154 7.1785,10.3374C7.2425,10.3644 7.3005,10.4074 7.3005,10.4094L7.3125,10.4194L7.3035,10.4284C7.2835,10.4494 7.2745,10.4774 7.2745,10.5034C7.2745,10.5284 7.2845,10.5584 7.3055,10.5794L7.2955,10.5894L7.3025,10.5974C7.3015,10.5974 7.2425,10.6424 7.1785,10.6674C7.1365,10.6904 7.0605,10.7064 7.0255,10.7114L6.9145,10.7304ZM6.7435,10.5034C6.8055,10.5644 6.8865,10.5974 6.9675,10.6034L6.9865,10.6054L6.9795,10.6214C6.9795,10.6214 6.9665,10.6444 6.9545,10.6824C6.9505,10.6894 6.9485,10.6944 6.9455,10.7034L7.0215,10.6884C7.0565,10.6834 7.1305,10.6664 7.1705,10.6444C7.2155,10.6264 7.2595,10.5974 7.2785,10.5874C7.2615,10.5644 7.2505,10.5304 7.2505,10.5034C7.2505,10.4754 7.2615,10.4484 7.2785,10.4254C7.2595,10.4094 7.2155,10.3814 7.1705,10.3614C7.1265,10.3404 7.0505,10.3284 7.0155,10.3184L6.9465,10.3084C6.9495,10.3144 6.9505,10.3184 6.9555,10.3314C6.9675,10.3624 6.9805,10.3864 6.9805,10.3864L6.9875,10.4024L6.9685,10.4054C6.8895,10.4104 6.8055,10.4494 6.7435,10.5034Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.1422,10.4462C7.1536,10.4336 7.1596,10.4173 7.1596,10.3993C7.1596,10.3824 7.1531,10.366 7.1427,10.3545C7.1427,10.3545 7.1727,10.3311 7.2076,10.3153C7.2344,10.3038 7.2835,10.2945 7.2976,10.2929C7.3129,10.2896 7.3418,10.2831 7.3418,10.2831C7.3418,10.2831 7.3413,10.2918 7.3353,10.3055C7.3282,10.3256 7.3216,10.3387 7.3216,10.3387C7.3724,10.3431 7.4204,10.3687 7.4536,10.3993C7.4204,10.4336 7.3729,10.4587 7.3216,10.4604C7.3216,10.4604 7.3282,10.4729 7.3353,10.492C7.3407,10.51 7.3418,10.5144 7.3418,10.5144C7.3418,10.5144 7.3129,10.51 7.2976,10.5078C7.2835,10.5035 7.2344,10.4969 7.2076,10.4844C7.1727,10.4685 7.1422,10.4462 7.1422,10.4462" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.5324,10.7304L7.4204,10.7114C7.3834,10.7064 7.3104,10.6904 7.2654,10.6674C7.2014,10.6424 7.1454,10.5974 7.1414,10.5974L7.1494,10.5894L7.1414,10.5794C7.1594,10.5584 7.1704,10.5284 7.1704,10.5034C7.1704,10.4774 7.1594,10.4484 7.1414,10.4284L7.1324,10.4194L7.1434,10.4094C7.1474,10.4074 7.2014,10.3644 7.2654,10.3374C7.3114,10.3164 7.3934,10.3024 7.4274,10.2924L7.5314,10.2744L7.5284,10.2924C7.5284,10.2924 7.5274,10.3084 7.5164,10.3374C7.5104,10.3554 7.5034,10.3714 7.4984,10.3814C7.5804,10.3904 7.6654,10.4334 7.7284,10.4954L7.7394,10.5034L7.7284,10.5154C7.6654,10.5744 7.5814,10.6164 7.4984,10.6244C7.5034,10.6364 7.5104,10.6514 7.5164,10.6674C7.5264,10.7004 7.5284,10.7144 7.5284,10.7144L7.5324,10.7304ZM7.1684,10.5874C7.1894,10.5974 7.2294,10.6264 7.2764,10.6444C7.3184,10.6654 7.3894,10.6834 7.4234,10.6884L7.4984,10.7034C7.4984,10.6934 7.4954,10.6884 7.4934,10.6824C7.4814,10.6454 7.4704,10.6214 7.4704,10.6214L7.4584,10.6054L7.4784,10.6034C7.5584,10.5974 7.6394,10.5644 7.7044,10.5034C7.6394,10.4484 7.5574,10.4094 7.4784,10.4044L7.4584,10.4014L7.4704,10.3854C7.4704,10.3854 7.4824,10.3624 7.4934,10.3304C7.4954,10.3164 7.4984,10.3124 7.4984,10.3074L7.4304,10.3174C7.3974,10.3274 7.3194,10.3384 7.2754,10.3604C7.2284,10.3814 7.1884,10.4094 7.1694,10.4244C7.1874,10.4474 7.1944,10.4744 7.1944,10.5024C7.1954,10.5334 7.1864,10.5644 7.1684,10.5874Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.9342,10.1642C7.8982,10.1855 7.866,10.2236 7.8545,10.2673C7.8545,10.2673 7.8496,10.2585 7.8305,10.246C7.8093,10.2345 7.7924,10.2351 7.7924,10.2351C7.7924,10.2351 7.7989,10.2695 7.8016,10.2815C7.8049,10.2929 7.8055,10.33 7.812,10.3611C7.8207,10.3955 7.8349,10.4205 7.8349,10.4205C7.8491,10.408 7.8698,10.4015 7.8889,10.4069C7.9091,10.4096 7.9255,10.4205 7.9353,10.4369C7.9353,10.4369 7.9582,10.4178 7.9767,10.3878C7.9953,10.3611 8.0089,10.3284 8.016,10.3185C8.0231,10.3071 8.0405,10.2782 8.0405,10.2782C8.0405,10.2782 8.0242,10.2716 8.0007,10.276C7.9778,10.2804 7.9707,10.2858 7.9707,10.2858C7.9751,10.2416 7.9609,10.1947 7.9342,10.1642" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.0572,10.6912L8.0502,10.6772C8.0342,10.6522 8.0052,10.6322 7.9742,10.6282C7.9402,10.6232 7.9092,10.6302 7.8832,10.6512L7.8712,10.6632L7.8642,10.6482C7.8642,10.6462 7.8382,10.5962 7.8222,10.5362C7.8142,10.5032 7.8102,10.4622 7.8082,10.4322C7.8052,10.4142 7.8052,10.3972 7.8042,10.3912C7.7992,10.3682 7.7872,10.3092 7.7872,10.3052L7.7842,10.2912L7.7992,10.2912L7.7992,10.2912C7.8052,10.2912 7.8372,10.2912 7.8762,10.3142C7.8892,10.3222 7.8992,10.3302 7.9082,10.3372C7.9332,10.2672 7.9862,10.2012 8.0522,10.1572L8.0632,10.1522L8.0682,10.1572C8.1152,10.2202 8.1412,10.2982 8.1382,10.3742C8.1482,10.3682 8.1612,10.3662 8.1782,10.3632C8.1892,10.3602 8.1992,10.3602 8.2102,10.3602C8.2382,10.3602 8.2552,10.3662 8.2552,10.3662L8.2712,10.3702L8.2622,10.3842C8.2622,10.3872 8.2312,10.4392 8.2172,10.4602C8.2142,10.4622 8.2072,10.4782 8.1982,10.4952C8.1852,10.5242 8.1682,10.5562 8.1452,10.5932C8.1102,10.6422 8.0682,10.6772 8.0682,10.6812L8.0572,10.6912ZM7.9552,10.6032C7.9632,10.6032 7.9702,10.6032 7.9772,10.6052C8.0102,10.6092 8.0412,10.6282 8.0632,10.6522C8.0752,10.6442 8.1042,10.6132 8.1272,10.5802C8.1462,10.5512 8.1632,10.5122 8.1772,10.4862C8.1862,10.4662 8.1922,10.4572 8.1982,10.4472C8.2062,10.4332 8.2232,10.4102 8.2332,10.3892C8.2212,10.3862 8.2022,10.3862 8.1832,10.3912C8.1452,10.3942 8.1342,10.4102 8.1342,10.4102L8.1112,10.4312L8.1132,10.3942C8.1222,10.3242 8.1002,10.2482 8.0572,10.1852C7.9932,10.2302 7.9432,10.2982 7.9252,10.3662L7.9162,10.3962L7.9022,10.3692L7.9022,10.3692C7.9022,10.3692 7.8922,10.3552 7.8622,10.3402C7.8422,10.3242 7.8252,10.3222 7.8142,10.3192C7.8172,10.3402 7.8222,10.3712 7.8292,10.3862C7.8292,10.3942 7.8312,10.4092 7.8342,10.4332C7.8342,10.4612 7.8392,10.4972 7.8462,10.5332C7.8582,10.5742 7.8712,10.6052 7.8812,10.6262C7.9022,10.6092 7.9282,10.6032 7.9552,10.6032Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.9195,10.5144C7.9304,10.5067 7.9396,10.4942 7.9429,10.4773C7.9456,10.4636 7.9429,10.4489 7.9342,10.4364C7.9342,10.4364 7.9653,10.4211 7.9969,10.4124C8.0225,10.4069 8.0673,10.4058 8.0798,10.4058C8.0924,10.4047 8.1185,10.4042 8.1185,10.4042C8.1185,10.4042 8.1169,10.4107 8.1087,10.4233C8.1,10.4375 8.0924,10.4495 8.0924,10.4495C8.136,10.4593 8.1725,10.4876 8.1971,10.5231C8.1627,10.5455 8.1175,10.5602 8.0722,10.5531C8.0722,10.5531 8.076,10.5656 8.0793,10.5864C8.0809,10.6 8.0804,10.6044 8.0804,10.6044C8.0804,10.6044 8.0564,10.5978 8.0444,10.5918C8.0318,10.5875 7.9898,10.5749 7.9696,10.5607C7.9429,10.54 7.9195,10.5144 7.9195,10.5144" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.233,10.799L8.143,10.766C8.111,10.754 8.047,10.731 8.01,10.705C7.961,10.672 7.916,10.629 7.914,10.627L7.924,10.613L7.915,10.605C7.937,10.589 7.949,10.566 7.956,10.542C7.959,10.519 7.956,10.495 7.942,10.472L7.934,10.464L7.946,10.458C7.949,10.456 8.003,10.425 8.065,10.415C8.108,10.401 8.181,10.399 8.213,10.399L8.218,10.399C8.241,10.399 8.288,10.398 8.288,10.398L8.306,10.396L8.3,10.417C8.3,10.417 8.297,10.425 8.282,10.448C8.275,10.464 8.266,10.473 8.26,10.487C8.331,10.507 8.397,10.555 8.442,10.616L8.45,10.628L8.44,10.636C8.376,10.681 8.294,10.703 8.221,10.699C8.224,10.709 8.226,10.722 8.229,10.742C8.233,10.769 8.233,10.777 8.232,10.779L8.233,10.799ZM7.942,10.613C7.955,10.629 7.989,10.66 8.025,10.683C8.057,10.706 8.122,10.73 8.149,10.742L8.207,10.763C8.207,10.754 8.207,10.752 8.207,10.746C8.202,10.711 8.194,10.691 8.194,10.691L8.188,10.675L8.207,10.675C8.277,10.681 8.354,10.659 8.416,10.622C8.371,10.563 8.307,10.518 8.238,10.505L8.218,10.497L8.23,10.487C8.23,10.487 8.246,10.466 8.261,10.44C8.265,10.432 8.268,10.424 8.271,10.422C8.253,10.422 8.231,10.422 8.218,10.424L8.213,10.424C8.183,10.424 8.113,10.424 8.071,10.438C8.028,10.448 7.988,10.463 7.967,10.471C7.978,10.494 7.984,10.52 7.978,10.547C7.972,10.574 7.961,10.598 7.942,10.613Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.8213,10.4991C7.8125,10.4876 7.8087,10.4718 7.8115,10.4582C7.8147,10.4413 7.8235,10.4282 7.8344,10.4211C7.8344,10.4211 7.8115,10.3955 7.7836,10.3753C7.7635,10.3616 7.7215,10.3475 7.7089,10.3442C7.6964,10.3376 7.6724,10.3316 7.6724,10.3316C7.6724,10.3316 7.6724,10.336 7.674,10.3496C7.6767,10.3698 7.6805,10.3818 7.6805,10.3818C7.6358,10.3742 7.5905,10.3916 7.5562,10.414C7.5807,10.4484 7.6178,10.4767 7.6609,10.4871C7.6609,10.4871 7.6538,10.4985 7.6445,10.5127C7.6369,10.5258 7.6364,10.5318 7.6364,10.5318C7.6364,10.5318 7.662,10.5307 7.6745,10.5296C7.6876,10.5296 7.7318,10.5296 7.7575,10.5231C7.7896,10.5144 7.8207,10.5002 7.8207,10.5002" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.6919,10.7206L7.6979,10.6996C7.6979,10.6996 7.7009,10.6916 7.7149,10.6686C7.7219,10.6506 7.7309,10.6416 7.7369,10.6296C7.6649,10.6096 7.5989,10.5616 7.5549,10.5026L7.5469,10.4886L7.5569,10.4806C7.6219,10.4366 7.7029,10.4136 7.7759,10.4166C7.7729,10.4086 7.7709,10.3936 7.7679,10.3776C7.7639,10.3486 7.7639,10.3406 7.7639,10.3386L7.7639,10.3196L7.7799,10.3246C7.7799,10.3246 7.8259,10.3406 7.8499,10.3476L7.8509,10.3476C7.8779,10.3636 7.9489,10.3866 7.9879,10.4106C8.0379,10.4456 8.0809,10.4886 8.0839,10.4906L8.0919,10.5046L8.0819,10.5126C8.0609,10.5286 8.0489,10.5516 8.0419,10.5756C8.0389,10.5986 8.0429,10.6226 8.0579,10.6456L8.0469,10.6486L8.0529,10.6596C8.0489,10.6616 7.9939,10.6906 7.9319,10.7046C7.8899,10.7166 7.8179,10.7166 7.7859,10.7196L7.7809,10.7196C7.7579,10.7196 7.7109,10.7216 7.7109,10.7216L7.6919,10.7216L7.6919,10.7206ZM7.5829,10.4976C7.6289,10.5556 7.6929,10.5996 7.7619,10.6126L7.7819,10.6206L7.7699,10.6306C7.7699,10.6306 7.7539,10.6516 7.7389,10.6776C7.7349,10.6856 7.7319,10.6936 7.7289,10.6966C7.7469,10.6936 7.7689,10.6936 7.7819,10.6936L7.7889,10.6936C7.8189,10.6936 7.8889,10.6936 7.9289,10.6796C7.9719,10.6696 8.0129,10.6526 8.0329,10.6466C8.0209,10.6236 8.0159,10.5976 8.0209,10.5706C8.0269,10.5456 8.0389,10.5216 8.0569,10.5066C8.0439,10.4886 8.0109,10.4596 7.9749,10.4366C7.9389,10.4136 7.8709,10.3896 7.8459,10.3736L7.8409,10.3736C7.8279,10.3716 7.8069,10.3656 7.7929,10.3576C7.7929,10.3656 7.7929,10.3686 7.7939,10.3736C7.7979,10.4086 7.8049,10.4286 7.8059,10.4286L7.8119,10.4446L7.7929,10.4446C7.7219,10.4346 7.6459,10.4586 7.5829,10.4976Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M7.8016,10.4664C7.8016,10.4271 7.8344,10.3949 7.8758,10.3949C7.9178,10.3949 7.9516,10.4271 7.9516,10.4664C7.9516,10.5056 7.9173,10.5384 7.8758,10.5384C7.8344,10.5384 7.8016,10.5062 7.8016,10.4664" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.943,10.6763C7.861,10.6763 7.794,10.6133 7.794,10.5323C7.794,10.4543 7.861,10.3873 7.943,10.3873C8.026,10.3873 8.095,10.4533 8.095,10.5323C8.096,10.6133 8.026,10.6763 7.943,10.6763ZM7.943,10.4133C7.874,10.4133 7.82,10.4703 7.82,10.5323C7.82,10.5963 7.874,10.6513 7.943,10.6513C8.013,10.6513 8.069,10.5963 8.069,10.5323C8.069,10.4703 8.014,10.4133 7.943,10.4133Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M8.64,10.6251C8.6225,10.6049 8.5849,10.6115 8.5587,10.6327C8.5315,10.6551 8.5233,10.6905 8.5407,10.7085C8.5587,10.7276 8.5958,10.7244 8.6225,10.702C8.6487,10.6764 8.6575,10.6425 8.64,10.6251" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.6099,10.8299L8.6099,10.8299C8.5839,10.8299 8.5599,10.8199 8.5449,10.8069C8.5299,10.7889 8.5249,10.7679 8.5249,10.7439C8.5249,10.7129 8.5459,10.6739 8.5769,10.6479C8.6069,10.6219 8.6449,10.6049 8.6799,10.6049C8.7059,10.6049 8.7299,10.6189 8.7449,10.6319C8.7599,10.6479 8.7659,10.6679 8.7649,10.6919C8.7649,10.7239 8.7439,10.7619 8.7129,10.7909C8.6819,10.8139 8.6439,10.8299 8.6099,10.8299ZM8.6789,10.6309C8.6509,10.6309 8.6179,10.6459 8.5949,10.6659C8.5669,10.6889 8.5499,10.7189 8.5479,10.7439C8.5479,10.7649 8.5529,10.7789 8.5629,10.7889C8.5879,10.8139 8.6519,10.8069 8.6939,10.7689C8.7239,10.7459 8.7399,10.7179 8.7409,10.6889C8.7409,10.6729 8.7359,10.6619 8.7269,10.6499C8.7159,10.6409 8.7009,10.6309 8.6789,10.6309Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.5342,10.6693C8.538,10.6567 8.5456,10.6425 8.5587,10.6333C8.5855,10.612 8.6225,10.6055 8.64,10.6256C8.6427,10.6284 8.6449,10.63 8.6465,10.6333C8.6465,10.6333 8.6847,10.5618 8.7295,10.5378C8.7742,10.5138 8.8511,10.5204 8.8511,10.5204C8.8511,10.4636 8.8053,10.4211 8.7469,10.4211C8.7131,10.4211 8.6804,10.4336 8.6613,10.4593L8.6531,10.4211C8.6531,10.4211 8.6062,10.4309 8.5849,10.4849C8.5636,10.5378 8.586,10.6158 8.586,10.6158C8.586,10.6158 8.5751,10.5815 8.5571,10.5613C8.5402,10.5373 8.4949,10.5133 8.4704,10.5018C8.448,10.4904 8.4235,10.4751 8.4235,10.4751C8.4235,10.4751 8.4229,10.4811 8.4229,10.4975C8.4213,10.5133 8.4229,10.5247 8.4229,10.5247C8.3793,10.5187 8.3302,10.5264 8.2898,10.54C8.3067,10.5744 8.3389,10.6038 8.3809,10.6207C8.3809,10.6207 8.3651,10.6322 8.3515,10.6464C8.3395,10.6573 8.3362,10.6633 8.3362,10.6633C8.3362,10.6633 8.3656,10.6676 8.3809,10.6687C8.3951,10.672 8.4447,10.6796 8.4736,10.678C8.4949,10.6764 8.5184,10.6731 8.5342,10.6693" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.5965,10.9128L8.5965,10.9128C8.5512,10.9128 8.4917,10.9028 8.4624,10.8968L8.3566,10.8808L8.3661,10.8668C8.367,10.8648 8.3746,10.8548 8.3935,10.8338C8.4076,10.8198 8.4208,10.8078 8.4322,10.7988C8.368,10.7658 8.316,10.7168 8.2868,10.6538L8.2811,10.6408L8.2934,10.6378C8.3595,10.6108 8.4435,10.5968 8.5143,10.6008C8.5134,10.5938 8.5134,10.5778 8.5143,10.5658C8.5162,10.5368 8.5162,10.5258 8.5162,10.5238L8.5209,10.5048L8.536,10.5168C8.536,10.5188 8.5767,10.5438 8.6154,10.5678C8.6352,10.5758 8.7315,10.6228 8.7712,10.6718C8.775,10.6818 8.7787,10.6858 8.7825,10.6928C8.7778,10.6458 8.7778,10.5888 8.7986,10.5388C8.8382,10.4348 8.9204,10.4138 8.9251,10.4118L8.9383,10.4118L8.9496,10.4708C8.9827,10.4338 9.0356,10.4118 9.0894,10.4118C9.197,10.4118 9.2811,10.4978 9.2811,10.6088L9.2811,10.6208L9.2679,10.6208C9.2679,10.6208 9.2518,10.6198 9.2301,10.6198C9.1904,10.6198 9.1149,10.6228 9.0639,10.6518C8.9903,10.6928 8.926,10.8238 8.926,10.8258L8.9147,10.8468L8.9024,10.8268C8.9024,10.8208 8.8958,10.8128 8.893,10.8108C8.8835,10.8008 8.8694,10.7908 8.8486,10.7908C8.8222,10.7908 8.791,10.8058 8.7693,10.8258C8.7485,10.8458 8.7362,10.8668 8.7296,10.8888L8.7259,10.8968L8.7183,10.8968C8.6937,10.9028 8.6522,10.9068 8.6135,10.9108C8.6078,10.9128 8.6031,10.9128 8.5965,10.9128ZM8.3982,10.8638L8.4643,10.8738C8.4926,10.8798 8.553,10.8878 8.5965,10.8878L8.5965,10.8878C8.6031,10.8878 8.6088,10.8878 8.6144,10.8858C8.6465,10.8818 8.6843,10.8798 8.7079,10.8738C8.7183,10.8508 8.7325,10.8268 8.7523,10.8098C8.7674,10.7978 8.7806,10.7888 8.7967,10.7808C8.7901,10.7628 8.7731,10.7178 8.7495,10.6918C8.7259,10.6568 8.655,10.6168 8.604,10.5908C8.5795,10.5768 8.553,10.5598 8.537,10.5488C8.537,10.5538 8.537,10.5598 8.537,10.5698C8.5351,10.5988 8.537,10.6168 8.537,10.6168L8.5379,10.6348L8.5238,10.6308C8.4596,10.6228 8.3765,10.6328 8.3123,10.6558C8.3425,10.7138 8.3972,10.7598 8.4567,10.7838L8.4756,10.7888L8.4596,10.8048C8.4596,10.8048 8.4341,10.8278 8.4095,10.8518C8.4048,10.8558 8.4029,10.8578 8.3982,10.8638ZM8.8486,10.7658C8.8732,10.7658 8.8958,10.7798 8.91,10.7928C8.9109,10.7928 8.9109,10.7928 8.9128,10.7948C8.9326,10.7558 8.9865,10.6668 9.0507,10.6308C9.1026,10.5998 9.1772,10.5948 9.2282,10.5948C9.2395,10.5948 9.248,10.5948 9.2547,10.5948C9.248,10.5058 9.1772,10.4358 9.0866,10.4358C9.029,10.4358 8.9799,10.4588 8.9468,10.5038L8.9317,10.5248L8.9157,10.4438C8.8939,10.4518 8.8429,10.4778 8.8174,10.5478C8.7863,10.6248 8.8108,10.7398 8.8184,10.7718C8.8297,10.7678 8.8392,10.7658 8.8486,10.7658Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M5.6411,10.6693C5.6373,10.6567 5.6291,10.6425 5.6165,10.6333C5.5887,10.612 5.5527,10.6055 5.5342,10.6256C5.5325,10.6284 5.5298,10.63 5.5282,10.6333C5.5282,10.6333 5.49,10.5618 5.4453,10.5378C5.4005,10.5138 5.3242,10.5204 5.3242,10.5204C5.3242,10.4636 5.37,10.4211 5.4273,10.4211C5.4627,10.4211 5.4949,10.4336 5.514,10.4593L5.5211,10.4211C5.5211,10.4211 5.568,10.4309 5.5909,10.4849C5.6116,10.5378 5.5876,10.6158 5.5876,10.6158C5.5876,10.6158 5.6002,10.5815 5.6171,10.5613C5.6356,10.5373 5.6804,10.5133 5.7033,10.5018C5.7273,10.4904 5.7507,10.4751 5.7507,10.4751C5.7507,10.4751 5.7518,10.4811 5.7529,10.4975C5.7535,10.5133 5.7524,10.5247 5.7524,10.5247C5.7955,10.5187 5.8456,10.5264 5.8849,10.54C5.8685,10.5744 5.8369,10.6038 5.7944,10.6207C5.7944,10.6207 5.8085,10.6322 5.8233,10.6464C5.8342,10.6573 5.838,10.6633 5.838,10.6633C5.838,10.6633 5.808,10.6676 5.7944,10.6687C5.7791,10.672 5.7305,10.6796 5.7016,10.678C5.6804,10.6764 5.6547,10.6731 5.6411,10.6693" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.0016,10.9128C5.9941,10.9128 5.9875,10.9128 5.9818,10.9108C5.942,10.9068 5.9014,10.9028 5.8758,10.8968L5.8692,10.8968L5.8683,10.8888C5.8616,10.8678 5.8474,10.8458 5.8285,10.8258C5.7869,10.7868 5.7282,10.7818 5.7036,10.8098C5.6989,10.8098 5.698,10.8188 5.6942,10.8258L5.6847,10.8468L5.6743,10.8258C5.6734,10.8238 5.609,10.6928 5.5343,10.6518C5.4832,10.6228 5.4094,10.6198 5.3668,10.6198C5.3451,10.6198 5.3318,10.6208 5.3318,10.6208L5.3176,10.6208L5.3176,10.6088C5.3176,10.4978 5.4018,10.4118 5.5087,10.4118C5.5646,10.4118 5.6147,10.4328 5.6516,10.4708L5.663,10.4118L5.6753,10.4118C5.6771,10.4138 5.7623,10.4348 5.802,10.5388C5.82,10.5898 5.82,10.6458 5.8143,10.6928C5.8191,10.6848 5.8257,10.6808 5.8295,10.6718C5.8654,10.6228 5.9638,10.5758 5.9818,10.5678C6.0215,10.5448 6.0631,10.5188 6.0631,10.5168L6.0792,10.5048L6.0802,10.5238C6.0802,10.5238 6.0821,10.5348 6.0849,10.5658C6.0849,10.5778 6.0849,10.5938 6.0849,10.6008C6.1549,10.5968 6.2401,10.6108 6.3063,10.6378L6.3176,10.6408L6.312,10.6548C6.2807,10.7178 6.2287,10.7658 6.1663,10.7998C6.1748,10.8088 6.1899,10.8208 6.2013,10.8348C6.223,10.8558 6.2287,10.8658 6.2287,10.8678L6.2401,10.8818L6.135,10.9008C6.1019,10.9028 6.0461,10.9128 6.0016,10.9128ZM5.8862,10.8738C5.9127,10.8798 5.9515,10.8818 5.9846,10.8858C6.0262,10.8918 6.0953,10.8798 6.1284,10.8738L6.1965,10.8638C6.1946,10.8578 6.1899,10.8558 6.1833,10.8498C6.1615,10.8268 6.135,10.8028 6.135,10.8028L6.1199,10.7868L6.1388,10.7818C6.2003,10.7588 6.2514,10.7118 6.2826,10.6538C6.2164,10.6308 6.136,10.6208 6.0717,10.6288L6.0556,10.6328L6.0575,10.6148C6.0575,10.6148 6.0603,10.5968 6.0584,10.5678C6.0584,10.5578 6.0575,10.5518 6.0565,10.5468C6.0404,10.5578 6.0158,10.5748 5.9884,10.5888C5.9383,10.6138 5.8711,10.6538 5.8446,10.6898C5.8228,10.7158 5.8049,10.7608 5.7992,10.7788C5.8124,10.7868 5.8276,10.7968 5.8399,10.8078C5.8626,10.8268 5.8796,10.8498 5.8862,10.8738ZM5.3659,10.5948C5.4198,10.5948 5.4917,10.5998 5.5437,10.6308C5.6071,10.6668 5.663,10.7558 5.6838,10.7948C5.6847,10.7928 5.6847,10.7928 5.6847,10.7928C5.7055,10.7698 5.7405,10.7618 5.7765,10.7718C5.7841,10.7408 5.8068,10.6258 5.7793,10.5478C5.7509,10.4778 5.7017,10.4508 5.68,10.4438L5.663,10.5248L5.6469,10.5038C5.6175,10.4588 5.5636,10.4358 5.5078,10.4358C5.4189,10.4358 5.347,10.5058 5.3413,10.5948C5.347,10.5948 5.3555,10.5948 5.3659,10.5948Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M5.5342,10.6251C5.5527,10.6049 5.5887,10.6115 5.6165,10.6327C5.6438,10.6551 5.6515,10.6905 5.6335,10.7085C5.6165,10.7276 5.5795,10.7244 5.5527,10.702C5.5238,10.6764 5.5167,10.6425 5.5342,10.6251" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.675,10.8283C5.64,10.8283 5.603,10.8123 5.572,10.7893C5.539,10.7613 5.52,10.7233 5.518,10.6903C5.516,10.6673 5.524,10.6463 5.539,10.6303C5.574,10.5933 5.651,10.6013 5.704,10.6463C5.738,10.6713 5.756,10.7103 5.759,10.7423C5.761,10.7653 5.753,10.7873 5.738,10.8053C5.723,10.8183 5.7,10.8283 5.675,10.8283ZM5.605,10.6293C5.585,10.6293 5.57,10.6393 5.558,10.6493C5.546,10.6613 5.542,10.6723 5.544,10.6883C5.546,10.7173 5.563,10.7453 5.588,10.7683C5.634,10.8053 5.694,10.8133 5.722,10.7883C5.731,10.7783 5.736,10.7643 5.734,10.7433C5.734,10.7183 5.715,10.6883 5.69,10.6653C5.663,10.6433 5.633,10.6293 5.605,10.6293Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M7.0107,10.3993C7.0107,10.36 7.0451,10.3289 7.0865,10.3289C7.128,10.3289 7.1607,10.36 7.1607,10.3993C7.1607,10.4375 7.128,10.4718 7.0865,10.4718C7.0445,10.4718 7.0107,10.438 7.0107,10.3993" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1556,10.6053C7.0726,10.6053 7.0036,10.5443 7.0036,10.4643C7.0036,10.3863 7.0716,10.3213 7.1556,10.3213C7.2376,10.3213 7.3036,10.3853 7.3036,10.4643C7.3036,10.5453 7.2376,10.6053 7.1556,10.6053ZM7.1556,10.3473C7.0856,10.3473 7.0296,10.3983 7.0296,10.4643C7.0296,10.5293 7.0856,10.5813 7.1556,10.5813C7.2236,10.5813 7.2786,10.5293 7.2786,10.4643C7.2786,10.3983 7.2236,10.3473 7.1556,10.3473Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#005BBF" + android:fillType="nonZero" + android:pathData="M6.9295,9.3215C6.9295,9.2396 6.9982,9.1742 7.0827,9.1742C7.1673,9.1742 7.236,9.2391 7.236,9.3215C7.236,9.4011 7.1673,9.4655 7.0827,9.4655C6.9982,9.4655 6.9295,9.4005 6.9295,9.3215" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.2141,9.7179C7.0551,9.7179 6.9251,9.5949 6.9251,9.4469C6.9251,9.2909 7.0551,9.1709 7.2141,9.1709C7.3731,9.1709 7.5021,9.2909 7.5021,9.4469C7.5021,9.5949 7.3731,9.7179 7.2141,9.7179ZM7.2141,9.1889C7.0631,9.1889 6.9411,9.3039 6.9411,9.4469C6.9411,9.5879 7.0631,9.7049 7.2141,9.7049C7.3641,9.7049 7.4861,9.5879 7.4861,9.4469C7.4871,9.3039 7.3651,9.1889 7.2141,9.1889Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0424,8.9124L7.0424,8.992L6.9584,8.992L6.9584,9.0705L7.0424,9.0705L7.0424,9.1813L7.0424,9.3007L6.9365,9.3007C6.936,9.3095 6.9295,9.3133 6.9295,9.322C6.9295,9.3389 6.9333,9.3602 6.942,9.3776L6.942,9.3776L7.2235,9.3776C7.2235,9.3776 7.2235,9.3776 7.224,9.3776C7.2327,9.3607 7.236,9.3395 7.236,9.322C7.236,9.3133 7.2295,9.3095 7.2289,9.3007L7.1264,9.3007L7.1264,9.1813L7.1264,9.0705L7.2104,9.0705L7.2104,8.992L7.1264,8.992L7.1264,8.9124L7.0424,8.9124Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.4786,9.7781L6.9516,9.7781L6.9516,9.7741C6.9506,9.7721 6.9486,9.7701 6.9476,9.7681C6.9336,9.7351 6.9256,9.6981 6.9256,9.6641C6.9256,9.6501 6.9286,9.6451 6.9336,9.6411C6.9356,9.6331 6.9396,9.6251 6.9396,9.6231L6.9396,9.6171L7.1326,9.6171L7.1326,9.2151L6.9806,9.2151L6.9806,9.0531L7.1326,9.0531L7.1326,8.9091L7.3026,8.9091L7.3026,9.0541L7.4556,9.0541L7.4556,9.2161L7.3026,9.2161L7.3026,9.6181L7.4906,9.6181L7.4906,9.6241C7.4906,9.6261 7.4936,9.6341 7.4956,9.6421C7.5006,9.6471 7.5036,9.6521 7.5036,9.6651C7.5036,9.6981 7.4956,9.7351 7.4816,9.7691L7.4786,9.7781ZM6.9626,9.7591L7.4666,9.7591C7.4806,9.7321 7.4876,9.6961 7.4876,9.6651C7.4876,9.6571 7.4836,9.6491 7.4816,9.6461C7.4786,9.6411 7.4786,9.6391 7.4756,9.6331L7.2846,9.6331L7.2846,9.1951L7.4386,9.1951L7.4386,9.0661L7.2846,9.0661L7.2846,8.9211L7.1496,8.9211L7.1496,9.0661L6.9946,9.0661L6.9946,9.1951L7.1496,9.1951L7.1496,9.6331L6.9526,9.6331C6.9506,9.6391 6.9506,9.6411 6.9466,9.6461C6.9446,9.6491 6.9406,9.6571 6.9406,9.6651C6.9406,9.6961 6.9476,9.7311 6.9626,9.7591Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:pathData="M7.0985,15.4447C6.6453,15.4447 6.1975,15.334 5.82,15.1507C5.5424,15.0116 5.3569,14.7329 5.3569,14.4155L5.3569,13.2629L8.8315,13.2629L8.8315,14.4155C8.8315,14.7329 8.6476,15.0116 8.3695,15.1507C7.9925,15.334 7.5502,15.4447 7.0985,15.4447" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.0985,15.4545C6.6611,15.4545 6.2067,15.3471 5.8156,15.1562C5.5271,15.0144 5.3482,14.7318 5.3482,14.416L5.3482,13.2558L8.8407,13.2558L8.8407,14.416C8.8407,14.7318 8.6618,15.0149 8.3744,15.1562C7.9778,15.3525 7.5365,15.4545 7.0985,15.4545ZM5.3667,13.2733L5.3667,14.416C5.3667,14.7236 5.5418,15.0018 5.8238,15.1415C6.2116,15.3318 6.6649,15.4365 7.0985,15.4365C7.5338,15.4365 7.9718,15.334 8.3651,15.1415C8.6482,15.0018 8.8227,14.7236 8.8227,14.416L8.8227,13.2733L5.3667,13.2733L5.3667,13.2733Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#CCCCCC" + android:fillType="nonZero" + android:pathData="M7.0904,13.2618l1.7411,0l0,-1.9282l-1.7411,0l0,1.9282z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.8407,13.2716L7.0816,13.2716L7.0816,11.3276L8.8407,11.3276L8.8407,13.2716ZM7.0991,13.2525L8.8227,13.2525L8.8227,11.3445L7.0991,11.3445L7.0991,13.2525Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M7.0925,14.4138C7.0925,14.8698 6.7058,15.2407 6.2258,15.2407C5.7442,15.2407 5.3542,14.8698 5.3542,14.4138L5.3542,13.2618L7.0925,13.2618L7.0925,14.4138" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M5.7344,15.0956C5.7889,15.1256 5.8631,15.1725 5.9427,15.1922L5.9384,13.2209L5.7344,13.2209L5.7344,15.0956Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.1401,15.202L6.1211,15.202C6.0001,15.184 5.8891,15.1507 5.7971,15.1229C5.7761,15.1153 5.7541,15.1093 5.7351,15.1038L5.7251,15.1011L5.7251,13.2116L6.1321,13.2116L6.1321,13.2204L6.1401,15.202ZM5.7601,15.0902C5.7771,15.0956 5.7951,15.1 5.8121,15.1049C5.8971,15.1305 6.0001,15.1633 6.1081,15.1796L6.1001,13.2302L5.7601,13.2302L5.7601,15.0902Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M5.352,14.3996C5.3575,14.6424 5.454,14.8224 5.5505,14.9418L5.5505,13.2307L5.3542,13.2307L5.352,14.3996Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.7224,14.9505C5.7184,14.9505 5.7144,14.9495 5.7094,14.9478C5.5494,14.8387 5.3534,14.6565 5.3444,14.3996L5.3474,13.2307C5.3474,13.2242 5.3564,13.2215 5.3624,13.2215L5.7224,13.2215C5.7314,13.2215 5.7374,13.2242 5.7374,13.2307L5.7374,14.9418C5.7374,14.9462 5.7344,14.9495 5.7274,14.9505C5.7254,14.9505 5.7254,14.9505 5.7224,14.9505ZM5.3794,13.2378L5.3734,14.4002C5.3854,14.6369 5.5554,14.8093 5.7074,14.9178L5.7074,13.2378L5.3794,13.2378Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C7B500" + android:fillType="nonZero" + android:pathData="M6.1211,15.2342C6.2007,15.2435 6.2607,15.2407 6.3256,15.2342L6.3256,13.2209L6.1211,13.2209L6.1211,15.2342Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.3164,15.2489L6.3164,15.2489C6.2574,15.2489 6.1954,15.2467 6.1284,15.2435L6.1124,15.2429L6.1124,13.2116L6.5194,13.2116L6.5194,15.2429L6.5034,15.2435C6.4354,15.2467 6.3754,15.2489 6.3164,15.2489ZM6.1454,15.2276C6.2054,15.2304 6.2624,15.2309 6.3154,15.2309L6.3154,15.2309C6.3694,15.2309 6.4244,15.2304 6.4844,15.2276L6.4844,13.2302L6.1444,13.2302L6.1444,15.2276L6.1454,15.2276Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.5045,15.1922C6.5842,15.1769 6.6736,15.1256 6.7118,15.1L6.7118,13.2209L6.5084,13.2209L6.5045,15.1922Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.4947,15.202L6.5047,13.2122L6.9107,13.2122L6.9107,15.1044L6.9027,15.1076C6.8287,15.1355 6.6617,15.1845 6.5137,15.2025L6.4947,15.2025L6.4947,15.202ZM6.5367,13.2302L6.5287,15.1807C6.6597,15.1638 6.8057,15.1213 6.8767,15.0956L6.8767,13.2302L6.5367,13.2302L6.5367,13.2302Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M5.3547,13.2618l1.7367,0l0,-1.9282l-1.7367,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1002,13.2716L5.3465,13.2716L5.3465,11.3276L7.1002,11.3276L7.1002,13.2716ZM5.3635,13.2525L7.0827,13.2525L7.0827,11.3445L5.3635,11.3445L5.3635,13.2525L5.3635,13.2525Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.9011,14.9233C6.9873,14.8469 7.0664,14.6778 7.0953,14.4804L7.0996,13.2198L6.8967,13.2198L6.9011,14.9233Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.896,14.9435L6.888,13.2122L7.292,13.2122L7.292,13.2209L7.283,14.4815C7.231,14.6745 7.09,14.8491 6.923,14.9298L6.896,14.9435ZM6.92,13.2302L6.929,14.9009C7.076,14.8191 7.205,14.6527 7.252,14.4793L7.26,13.2302L6.92,13.2302Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.2258,15.2489C5.7404,15.2489 5.346,14.8736 5.346,14.4138L5.346,13.2515L7.1013,13.2515L7.1013,14.4138C7.1013,14.8742 6.7085,15.2489 6.2258,15.2489ZM5.3635,13.2716L5.3635,14.4138C5.3635,14.8644 5.7502,15.2309 6.2258,15.2309C6.6987,15.2309 7.0827,14.8644 7.0827,14.4138L7.0827,13.2716L5.3635,13.2716Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M8.8336,13.2613L8.8336,14.4133C8.8336,14.8693 8.4431,15.2402 7.962,15.2402C7.4825,15.2402 7.0925,14.8693 7.0925,14.4133L7.0925,13.2613L8.8336,13.2613" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.962,15.2489C7.4771,15.2489 7.0827,14.8736 7.0827,14.4138L7.0827,13.2515L8.8424,13.2515L8.8424,14.4138C8.8424,14.8742 8.448,15.2489 7.962,15.2489ZM7.1013,13.2716L7.1013,14.4138C7.1013,14.8644 7.4875,15.2309 7.9625,15.2309C8.4387,15.2309 8.826,14.8644 8.826,14.4138L8.826,13.2716L7.1013,13.2716Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.4089,14.1324C7.4122,14.1395 7.4127,14.1448 7.4127,14.1519C7.4127,14.1738 7.3953,14.1932 7.3729,14.1932C7.3505,14.1932 7.3325,14.1738 7.3325,14.1519C7.3325,14.1448 7.3336,14.1395 7.3364,14.1324L7.2802,14.1324C7.2785,14.1395 7.2785,14.1448 7.2785,14.1519C7.2785,14.1968 7.3064,14.2305 7.3445,14.2429L7.3445,14.3941L7.4029,14.3953L7.4029,14.2429C7.4318,14.2334 7.4531,14.2104 7.4624,14.1826L7.6211,14.1826L7.6211,14.1318L7.4089,14.1318M8.1895,14.1324L8.1895,14.1832L8.0465,14.1832C8.0449,14.1891 8.0416,14.1968 8.0373,14.2015L8.2036,14.4077L8.1589,14.4461L7.9936,14.2417C7.9904,14.2417 7.9887,14.2429 7.9855,14.2429L7.9849,14.5843L7.9265,14.5843L7.9265,14.2429C7.9238,14.2429 7.9222,14.2411 7.92,14.2399L7.7476,14.4461L7.7029,14.4077L7.8753,14.2003C7.8725,14.1968 7.8693,14.1879 7.8676,14.1832L7.7193,14.1832L7.7193,14.1324L8.1895,14.1324L8.1895,14.1324ZM8.2844,14.1324L8.2844,14.1832L8.4442,14.1832C8.454,14.211 8.4764,14.234 8.5025,14.2435L8.5025,14.3958L8.5625,14.3947L8.5625,14.2435C8.6007,14.2311 8.628,14.1974 8.628,14.1525C8.628,14.1454 8.6269,14.1401 8.6264,14.133L8.5691,14.133C8.5718,14.1401 8.574,14.1454 8.574,14.1525C8.574,14.1743 8.5565,14.1938 8.5336,14.1938C8.5118,14.1938 8.4927,14.1743 8.4927,14.1525C8.4927,14.1454 8.4949,14.1401 8.4976,14.133L8.2844,14.133M8.0455,14.9954C8.0907,14.9877 8.1349,14.9741 8.1764,14.9552L8.2053,15.0072C8.1573,15.0314 8.1044,15.0462 8.0498,15.0556C8.0411,15.0999 8.004,15.1318 7.9582,15.1318C7.9124,15.1318 7.8753,15.1005 7.866,15.0556C7.8082,15.0462 7.7531,15.0326 7.7018,15.0072L7.7313,14.9552C7.7755,14.9753 7.8224,14.9895 7.8731,14.996C7.8824,14.9723 7.9015,14.9517 7.9271,14.9446L7.9271,14.6817L7.9849,14.6817L7.986,14.9446C8.0116,14.9493 8.0335,14.9723 8.0455,14.9954L8.0455,14.9954ZM7.6467,14.908L7.6178,14.9623C7.5687,14.9298 7.524,14.8885 7.4864,14.84C7.4569,14.8518 7.422,14.8459 7.3964,14.8235C7.3576,14.788 7.3516,14.7272 7.3865,14.687L7.3909,14.6823C7.3675,14.6221 7.3511,14.5595 7.3445,14.4933L7.4045,14.4933C7.4084,14.5488 7.4209,14.6044 7.4422,14.6546C7.4596,14.651 7.476,14.6546 7.4918,14.6593L7.6402,14.4815L7.6849,14.5205L7.5376,14.6989C7.5578,14.7296 7.5567,14.7721 7.5338,14.807C7.5682,14.8442 7.6047,14.879 7.6467,14.908ZM7.428,14.7231C7.4416,14.7036 7.4673,14.7 7.4847,14.716C7.5016,14.7308 7.5038,14.7562 7.4891,14.7762C7.4749,14.7922 7.4493,14.7951 7.4318,14.7804C7.4155,14.7644 7.4127,14.739 7.428,14.7231ZM7.3527,14.5465L7.2922,14.5323L7.284,14.3651L7.3445,14.3427L7.3445,14.4372C7.344,14.4756 7.3473,14.511 7.3527,14.5465ZM7.4029,14.3391L7.4635,14.3539C7.4635,14.3539 7.4662,14.462 7.4662,14.4372C7.4635,14.4094 7.4727,14.5205 7.4727,14.5205L7.4116,14.5435C7.4062,14.5087 7.4024,14.4744 7.4024,14.4372L7.4029,14.3391L7.4029,14.3391ZM7.6031,14.8743C7.6544,14.9168 7.7127,14.9493 7.7765,14.9723L7.7907,14.9091C7.7378,14.8926 7.6898,14.8666 7.6456,14.8329L7.6031,14.8743M7.5742,14.9286C7.6265,14.9712 7.6844,15.0036 7.7476,15.0279L7.7029,15.0728C7.6516,15.0544 7.6042,15.0279 7.56,14.993L7.5742,14.9286M7.6522,14.5606L7.71,14.5878L7.8164,14.4602L7.782,14.4047L7.6522,14.5606M7.6075,14.5199L7.5731,14.4644L7.6795,14.3386L7.7373,14.3663L7.6075,14.5199M8.2593,14.908L8.2882,14.9623C8.3384,14.9298 8.382,14.8885 8.4196,14.84C8.4507,14.8518 8.484,14.8459 8.5096,14.8235C8.5505,14.788 8.5538,14.7272 8.5211,14.687L8.5151,14.6823C8.5396,14.6221 8.556,14.5595 8.5609,14.4933L8.5025,14.4933C8.4976,14.5488 8.4845,14.6044 8.4644,14.6546C8.4485,14.651 8.43,14.6546 8.4136,14.6593L8.2658,14.4815L8.2211,14.5205L8.3684,14.6989C8.3493,14.7296 8.3493,14.7721 8.3716,14.807C8.3395,14.8442 8.3007,14.879 8.2593,14.908ZM8.4796,14.7231C8.4638,14.7036 8.4382,14.7 8.4224,14.716C8.4055,14.7308 8.4033,14.7562 8.4175,14.7762C8.4316,14.7922 8.4573,14.7951 8.4742,14.7804C8.4916,14.7644 8.4933,14.739 8.4796,14.7231ZM8.5533,14.5465L8.6144,14.5323L8.6236,14.3651L8.5636,14.3427L8.5636,14.4372C8.5631,14.4756 8.5593,14.511 8.5533,14.5465ZM8.5031,14.3391L8.4425,14.3539C8.4425,14.3539 8.4393,14.462 8.4415,14.4372C8.442,14.4094 8.4344,14.5205 8.4344,14.5205L8.4955,14.5435C8.502,14.5087 8.5031,14.4744 8.5031,14.4372L8.5031,14.3391M8.304,14.8743C8.2527,14.9168 8.1927,14.9493 8.1289,14.9723L8.1158,14.9091C8.1687,14.8926 8.2184,14.8666 8.2598,14.8329L8.304,14.8743M8.3329,14.9286C8.2816,14.9712 8.2216,15.0036 8.1584,15.0279L8.2036,15.0728C8.2544,15.0544 8.3024,15.0279 8.3455,14.993L8.3329,14.9286M8.2533,14.5606L8.1955,14.5878L8.0902,14.4602L8.1251,14.4047L8.2533,14.5606M8.298,14.5199L8.3324,14.4644L8.2265,14.3386L8.1693,14.3663L8.298,14.5199M7.5742,14.1832L7.5911,14.2446L7.7536,14.2446L7.7722,14.1832L7.5742,14.1832M8.3356,14.1832L8.3176,14.2446L8.1545,14.2446L8.1376,14.1832L8.3356,14.1832M7.9173,15.0349C7.9173,15.0143 7.9353,14.9936 7.9576,14.9936C7.98,14.9936 7.9969,15.0143 7.9969,15.0349C7.9969,15.0592 7.9795,15.0763 7.9576,15.0763C7.9353,15.0763 7.9173,15.0592 7.9173,15.0349ZM7.9855,14.7337L8.046,14.7142L8.046,14.5482L7.9855,14.5299L7.9855,14.7337M7.9265,14.7337L7.866,14.7142L7.866,14.5482L7.9265,14.5299L7.9265,14.7337" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.2802,14.422C7.2878,14.3797 7.3129,14.3436 7.3451,14.3283L7.3445,14.0602L7.4029,14.0602L7.4029,14.3298C7.4318,14.3444 7.4542,14.3713 7.464,14.4112L7.6216,14.4127L7.6216,14.422L7.4095,14.422C7.4029,14.4058 7.3887,14.3966 7.3735,14.3966C7.3582,14.3966 7.3435,14.4058 7.3369,14.422L7.2802,14.422M7.7193,14.422L7.7193,14.4127L7.8665,14.4127C7.8693,14.4035 7.8709,14.3974 7.8731,14.392L7.692,14.1101L7.7367,14.0564L7.9162,14.3352C7.9189,14.3321 7.9222,14.3321 7.9255,14.3306L7.9255,13.9573L7.9844,13.9573L7.9844,14.3283C7.9871,14.3306 7.9909,14.3306 7.9936,14.3321L8.1682,14.0518L8.2135,14.1001L8.0378,14.3805C8.0422,14.3897 8.0455,14.4005 8.0487,14.4135L8.19,14.4135L8.19,14.4227L7.7193,14.4227L7.7193,14.422ZM8.4982,14.422C8.5053,14.4058 8.5184,14.3966 8.5336,14.3966C8.55,14.3966 8.5631,14.4058 8.5691,14.422L8.6264,14.422C8.6187,14.3797 8.5942,14.3436 8.5625,14.3283L8.5625,14.0602L8.5036,14.0602L8.5036,14.3306C8.4747,14.3444 8.4524,14.3713 8.4442,14.4112L8.2844,14.4127L8.2844,14.422L8.4982,14.422M7.4122,13.6662L7.6293,14.0095L7.674,13.9604L7.4553,13.617C7.4596,13.6086 7.4629,13.5978 7.4662,13.5886L7.6255,13.5886L7.6255,13.5087L7.4656,13.5087C7.4536,13.4596 7.4176,13.4235 7.3751,13.4235C7.3227,13.4235 7.2807,13.4803 7.2807,13.5495C7.2807,13.6048 7.3064,13.6485 7.3445,13.6662L7.344,13.9342L7.4018,13.9342L7.4018,13.6677C7.4062,13.6662 7.4089,13.6662 7.4122,13.6662ZM8.5631,13.6662L8.5631,13.9342L8.5042,13.9342L8.5042,13.6662C8.4993,13.6662 8.4955,13.6639 8.4911,13.6601L8.2745,14.0057L8.2298,13.9542L8.4513,13.6048C8.4485,13.5971 8.4469,13.5925 8.4447,13.5886L8.2849,13.5886L8.2849,13.5087L8.4447,13.5087C8.4573,13.4596 8.4927,13.4235 8.5342,13.4235C8.5871,13.4235 8.6296,13.4803 8.6296,13.5495C8.6291,13.6063 8.6018,13.6508 8.5631,13.6662ZM7.9844,13.6662L7.9844,13.8283L7.9255,13.8283L7.9255,13.6677C7.896,13.6585 7.8725,13.6263 7.8633,13.5879L7.7204,13.5879L7.7204,13.508L7.8633,13.508C7.8753,13.4588 7.9107,13.4227 7.9527,13.4227C7.9953,13.4227 8.0313,13.4588 8.0433,13.508L8.1889,13.508L8.1889,13.5879L8.0427,13.5879C8.0335,13.624 8.0133,13.6554 7.9844,13.6662ZM7.3451,13.8644L7.2845,13.8897L7.2845,14.1086L7.3451,14.1301L7.3451,13.8644M7.4035,13.8644L7.464,13.8897L7.464,14.1086L7.4035,14.1301L7.4035,13.8644M8.5031,13.8644L8.4425,13.8897L8.4425,14.1086L8.5031,14.1301L8.5031,13.8644M8.5631,13.8644L8.6231,13.8897L8.6231,14.1086L8.5631,14.1301L8.5631,13.8644M7.6424,13.9089L7.6996,13.8759L7.8049,14.0379L7.77,14.1101L7.6424,13.9089M7.5976,13.9588L7.5622,14.0295L7.668,14.1977L7.7253,14.1631L7.5976,13.9588M8.2625,13.8997L8.2042,13.8667L8.0995,14.0364L8.1349,14.1055L8.2625,13.8997M8.3073,13.9527L8.3422,14.0241L8.2369,14.1885L8.1796,14.1539L8.3073,13.9527M7.5742,14.412L7.5911,14.3313L7.7536,14.3313L7.7722,14.412L7.5742,14.412M7.3358,13.5487C7.3358,13.518 7.3533,13.4949 7.3756,13.4949C7.398,13.4949 7.4155,13.518 7.4155,13.5487C7.4155,13.5756 7.398,13.6025 7.3756,13.6025C7.3533,13.6025 7.3358,13.5763 7.3358,13.5487ZM7.7705,13.5879L7.7536,13.6677L7.5905,13.6677L7.572,13.5879L7.7705,13.5879M7.7705,13.5072L7.7536,13.4266L7.5905,13.4266L7.572,13.5072L7.7705,13.5072M8.3356,14.412L8.3176,14.3313L8.1545,14.3313L8.1376,14.412L8.3356,14.412M8.4938,13.5487C8.4938,13.518 8.5124,13.4949 8.5342,13.4949C8.5571,13.4949 8.5751,13.518 8.5751,13.5487C8.5751,13.5756 8.5571,13.6025 8.5342,13.6025C8.5118,13.6032 8.4938,13.5763 8.4938,13.5487ZM7.9129,13.5487C7.9129,13.518 7.9304,13.4949 7.9527,13.4949C7.9751,13.4949 7.9942,13.518 7.9942,13.5487C7.9942,13.5756 7.9751,13.6025 7.9527,13.6025C7.9309,13.6032 7.9129,13.5763 7.9129,13.5487ZM8.1382,13.5879L8.1567,13.6677L8.3198,13.6677L8.3367,13.5879L8.1382,13.5879M8.1382,13.5072L8.1567,13.4266L8.3198,13.4266L8.3367,13.5072L8.1382,13.5072M7.926,13.7637L7.8655,13.786L7.8655,14.0041L7.926,14.0256L7.926,13.7637M7.9844,13.7637L8.0455,13.786L8.0455,14.0041L7.9844,14.0256L7.9844,13.7637" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.9968,15.0613C7.949,15.0613 7.9069,15.0302 7.8953,14.9887C7.8544,14.9844 7.8146,14.9762 7.7765,14.9631L7.7287,15.0062L7.7263,15.0045C7.6739,14.9871 7.6225,14.962 7.5747,14.9331L7.5724,14.9298L7.5856,14.8693C7.5545,14.8464 7.5251,14.8196 7.498,14.7924C7.4639,14.7989 7.427,14.7924 7.4011,14.7711C7.3803,14.7558 7.3665,14.7329 7.3648,14.7073C7.363,14.6816 7.3717,14.6571 7.3901,14.6391L7.3936,14.638C7.3746,14.5987 7.3619,14.5584 7.3532,14.5164L7.2886,14.5027L7.2788,14.3451L7.3428,14.3238L7.3428,14.2387C7.3019,14.2262 7.2736,14.1907 7.2736,14.1504C7.2736,14.11 7.3019,14.0745 7.3434,14.062L7.3428,13.8711L7.4149,13.8711L7.4149,14.0631C7.4443,14.0718 7.468,14.0931 7.4778,14.1187L7.6468,14.1198L7.6468,14.1836L7.4766,14.1836C7.4657,14.2093 7.4443,14.2305 7.4161,14.2382L7.4161,14.32L7.4801,14.3342L7.4801,14.3369C7.4801,14.3369 7.4812,14.4007 7.4818,14.4138C7.4847,14.4329 7.4882,14.4907 7.4882,14.4907L7.4887,14.4962L7.4247,14.5153C7.4311,14.5475 7.4415,14.5785 7.4553,14.608C7.4709,14.6058 7.4887,14.608 7.5049,14.6145L7.6618,14.4482L7.7165,14.4907L7.5597,14.6555C7.5793,14.686 7.5787,14.7231 7.5562,14.7553C7.5764,14.7733 7.5995,14.7935 7.6225,14.8109L7.6681,14.7727L7.671,14.7749C7.716,14.8071 7.7667,14.8322 7.8227,14.848L7.8261,14.8485L7.8129,14.908C7.8417,14.9135 7.8728,14.9216 7.904,14.926C7.9155,14.9036 7.9345,14.8878 7.9593,14.8791L7.9599,14.6353L8.0314,14.6353L8.032,14.878C8.0591,14.8867 8.0793,14.9036 8.092,14.926C8.137,14.9184 8.1808,14.9069 8.2263,14.8878L8.2304,14.8867L8.2656,14.9451L8.2615,14.9473C8.2096,14.9664 8.1543,14.9816 8.0989,14.9898C8.0856,15.0307 8.0447,15.0613 7.9968,15.0613ZM7.7852,14.9582C7.8215,14.9685 7.8596,14.9762 7.8999,14.9816L7.9028,14.9827L7.9028,14.9849C7.9132,15.0231 7.9513,15.052 7.9962,15.052C8.0406,15.052 8.0793,15.0231 8.0891,14.9849L8.0891,14.9816L8.092,14.9805C8.1479,14.9718 8.2004,14.9593 8.2511,14.938L8.2252,14.8982C8.1796,14.9145 8.1364,14.9255 8.0891,14.9336L8.0856,14.9336L8.0845,14.9325C8.0729,14.9096 8.0516,14.8933 8.0245,14.8856L8.0216,14.884L8.0216,14.644L7.9686,14.644L7.968,14.8851L7.9651,14.8856C7.9409,14.8955 7.9207,14.9096 7.9103,14.9325L7.9092,14.9336L7.9057,14.9336C7.8734,14.9304 7.84,14.9233 7.8094,14.9135L7.8094,14.9135L7.8054,14.9124C7.795,14.9107 7.7869,14.908 7.7782,14.9047C7.7713,14.9015 7.765,14.8993 7.7581,14.8976L7.7327,14.9375C7.7477,14.9451 7.7609,14.9489 7.7771,14.9544L7.7852,14.9582L7.7852,14.9582ZM7.5827,14.9249C7.6277,14.9549 7.6768,14.9762 7.7269,14.9975L7.7661,14.9609C7.7517,14.9571 7.7379,14.9505 7.7246,14.9467L7.7188,14.9445L7.7188,14.9435C7.6912,14.9325 7.6646,14.92 7.6393,14.9042L7.6393,14.9042L7.6352,14.9009C7.6208,14.8955 7.607,14.8856 7.5931,14.8742L7.5827,14.9249ZM7.6445,14.8955C7.6704,14.9107 7.6975,14.9244 7.7246,14.9353L7.75,14.8955C7.7223,14.8829 7.6958,14.8698 7.6704,14.8551L7.6445,14.8955ZM7.63,14.8175C7.6768,14.8485 7.7275,14.8758 7.7817,14.8955C7.7886,14.8987 7.795,14.8998 7.8025,14.9031L7.8152,14.854C7.7609,14.836 7.7114,14.8136 7.6681,14.7836L7.63,14.8175ZM7.5891,14.86L7.5937,14.8622C7.6075,14.8731 7.622,14.8824 7.6364,14.8911L7.6618,14.8485C7.6191,14.8229 7.5804,14.7929 7.5458,14.7564L7.5435,14.7547L7.5453,14.7504C7.5689,14.7215 7.5695,14.6855 7.5493,14.6565L7.5487,14.6538L7.7027,14.4902L7.6641,14.4602L7.5078,14.6244L7.5049,14.6227C7.4882,14.6167 7.4703,14.6151 7.4536,14.6167L7.4501,14.6178L7.4478,14.6135C7.4345,14.5824 7.4236,14.5496 7.4167,14.5153L7.4167,14.5153L7.4149,14.5125C7.4144,14.5022 7.412,14.4951 7.4109,14.4853C7.4109,14.4787 7.4097,14.4738 7.4092,14.4695L7.3573,14.4689C7.3578,14.4842 7.3607,14.4984 7.3642,14.5136L7.3642,14.5196L7.3642,14.5196C7.3734,14.5589 7.3867,14.5987 7.4045,14.6358L7.4045,14.6391L7.3976,14.6445C7.3809,14.6647 7.374,14.6838 7.3746,14.7073C7.3769,14.7302 7.3878,14.7509 7.408,14.7667C7.4322,14.7836 7.468,14.7924 7.4991,14.782L7.5026,14.7809L7.5032,14.7825C7.5285,14.8098 7.5585,14.8355 7.5891,14.86ZM7.2984,14.4989L7.3509,14.5098C7.3486,14.494 7.3457,14.4787 7.3457,14.4651L7.3446,14.4607L7.3457,14.4607C7.3434,14.4471 7.3423,14.4307 7.3423,14.4138L7.3423,14.3745L7.3423,14.3456L7.3423,14.3331L7.2881,14.35L7.2984,14.4989ZM7.4201,14.4864C7.4201,14.4907 7.4213,14.4989 7.423,14.5055L7.4778,14.4896C7.4772,14.4771 7.4738,14.4378 7.4726,14.4204C7.472,14.4182 7.4714,14.416 7.4714,14.4138C7.4709,14.4111 7.4709,14.4095 7.4714,14.4095C7.4709,14.3893 7.4703,14.3522 7.4703,14.3413L7.4149,14.3298L7.4149,14.4138C7.4155,14.4395 7.4167,14.464 7.4201,14.4864L7.4201,14.4864L7.4201,14.4864ZM7.355,14.4607L7.4069,14.4607C7.4069,14.4482 7.4069,14.4318 7.4069,14.4138L7.4069,14.3795L7.3526,14.3784L7.3526,14.4133C7.3526,14.4307 7.3526,14.4465 7.355,14.4607ZM7.3526,14.3713L7.4069,14.3713L7.4069,14.2322L7.4097,14.2305C7.4368,14.2218 7.4582,14.2038 7.4674,14.1793L7.4691,14.1749L7.6364,14.1749L7.6364,14.128L7.4703,14.128L7.4691,14.1247C7.4605,14.0985 7.4374,14.0784 7.4092,14.068L7.4057,14.068L7.4057,13.8771L7.3532,13.8771L7.3532,14.0669L7.3498,14.068C7.3111,14.0795 7.2834,14.1149 7.2834,14.1498C7.2834,14.1858 7.3111,14.2202 7.3498,14.2295L7.3532,14.2322L7.3532,14.3713L7.3526,14.3713ZM7.4686,14.7444C7.457,14.7444 7.4472,14.7416 7.4374,14.7329C7.4276,14.7264 7.4224,14.716 7.4207,14.7029C7.4201,14.6925 7.4236,14.6816 7.4328,14.6729C7.442,14.6642 7.4547,14.656 7.4686,14.656C7.4807,14.656 7.4911,14.6625 7.4997,14.6675C7.5095,14.6773 7.5147,14.686 7.5164,14.6975C7.5182,14.7073 7.5135,14.7198 7.5043,14.7285C7.4957,14.7395 7.483,14.7444 7.4686,14.7444ZM7.4686,14.668C7.457,14.668 7.4472,14.6707 7.4403,14.6795C7.4334,14.6865 7.4299,14.6947 7.4299,14.7035C7.4311,14.7133 7.4368,14.7204 7.4432,14.728C7.4501,14.7324 7.4593,14.7335 7.468,14.7335C7.4795,14.7335 7.4905,14.7307 7.4968,14.7225C7.5037,14.716 7.5072,14.7078 7.5066,14.6991C7.5055,14.6904 7.5009,14.6822 7.4939,14.6767C7.487,14.6696 7.4772,14.668 7.4686,14.668ZM8.0314,14.5535L7.9593,14.5535L7.9593,14.2382C7.9588,14.2371 7.9576,14.2371 7.9576,14.2371L7.7754,14.428L7.7212,14.3876L7.9034,14.1951C7.9022,14.1924 7.9005,14.188 7.8988,14.1836L7.7413,14.1836L7.7413,14.1198L7.8976,14.1198C7.8999,14.1155 7.9005,14.1144 7.9022,14.11L7.709,13.9076L7.7638,13.864L7.9547,14.0642C7.9547,14.0642 7.957,14.0642 7.9576,14.0642L7.9576,13.7975L8.0291,13.7975L8.0291,14.062C8.0291,14.062 8.0291,14.062 8.0297,14.062C8.0314,14.062 8.032,14.0631 8.0326,14.0631L8.2183,13.8624L8.2736,13.9022L8.0868,14.1024C8.0897,14.1067 8.0926,14.1133 8.0954,14.1193L8.2477,14.1193L8.2477,14.1831L8.0943,14.1831C8.0926,14.1885 8.0897,14.1918 8.0868,14.1956L8.2644,14.3865L8.2096,14.4269L8.0337,14.2371L8.0337,14.2371C8.0326,14.2382 8.032,14.2382 8.032,14.2393L8.032,14.5535L8.0314,14.5535ZM7.9686,14.5436L8.0216,14.5436L8.0216,14.2333L8.0245,14.2322C8.0268,14.2305 8.028,14.2305 8.0285,14.2305C8.0303,14.2305 8.0308,14.2305 8.0326,14.2305L8.0355,14.2284L8.0378,14.2305L8.2102,14.4149L8.25,14.3855L8.0753,14.1962L8.0764,14.1951C8.0804,14.1896 8.0839,14.1836 8.0851,14.1793L8.0868,14.1749L8.2373,14.1749L8.2373,14.128L8.0879,14.128L8.0862,14.1258C8.0839,14.1149 8.0804,14.1089 8.0764,14.104L8.0753,14.1024L8.077,14.0991L8.2592,13.9033L8.2194,13.8749L8.0349,14.0713L8.032,14.0702C8.0314,14.0691 8.0285,14.0691 8.0274,14.068C8.0251,14.068 8.0245,14.068 8.0228,14.068L8.0193,14.068L8.0193,13.8073L7.9674,13.8073L7.9674,14.0685L7.9639,14.0696C7.9611,14.0718 7.957,14.0729 7.9541,14.0751L7.9507,14.0773L7.7621,13.8771L7.7229,13.9104L7.9144,14.1084L7.9126,14.1127C7.9109,14.116 7.908,14.1204 7.9063,14.1264L7.9045,14.1285L7.7511,14.1285L7.7511,14.1755L7.9063,14.1755L7.9074,14.1798C7.9092,14.1842 7.9109,14.1896 7.9144,14.1924L7.9161,14.1956L7.735,14.3871L7.7754,14.4155L7.9559,14.2267L7.9616,14.2311C7.9628,14.2311 7.9645,14.2311 7.9657,14.2311L7.9691,14.2327L7.9686,14.5436ZM7.6502,13.8471L7.6468,13.8427L7.4184,13.6011C7.4167,13.6011 7.4167,13.6022 7.4155,13.6022C7.4155,13.6022 7.4149,13.6022 7.4149,13.6022L7.4149,13.7876L7.3428,13.7876L7.3434,13.5989C7.303,13.5853 7.2765,13.552 7.2765,13.5127C7.2765,13.4604 7.3232,13.4167 7.3815,13.4167C7.4265,13.4167 7.4651,13.4424 7.4807,13.4795L7.6502,13.4795L7.6502,13.5433L7.4807,13.5433C7.4778,13.5509 7.4749,13.5553 7.472,13.5591L7.7044,13.804L7.6502,13.8471ZM7.4213,13.5913L7.4236,13.5929L7.6514,13.834L7.6912,13.8018L7.4616,13.5602L7.4622,13.5569C7.4668,13.5525 7.4697,13.5444 7.4726,13.5389L7.4743,13.5335L7.641,13.5335L7.641,13.4887L7.4743,13.4887L7.4726,13.4855C7.4605,13.4505 7.4242,13.4265 7.3821,13.4265C7.3296,13.4265 7.2863,13.4647 7.2863,13.5122C7.2863,13.5471 7.3129,13.5798 7.3503,13.5913L7.3538,13.5929L7.3538,13.5956L7.3538,13.7811L7.4069,13.7811L7.4069,13.5945L7.4103,13.5929C7.4109,13.5929 7.4138,13.5913 7.4149,13.5913C7.4172,13.5913 7.4184,13.5913 7.4195,13.5913L7.4213,13.5913Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.2025,15.0067L8.1507,14.9582L8.1573,14.9549C8.202,14.938 8.244,14.9205 8.2822,14.8955L8.2576,14.8545C8.2178,14.8791 8.1742,14.8993 8.1311,14.9118L8.1251,14.9129L8.1098,14.8469L8.1142,14.8464C8.166,14.8311 8.2145,14.8055 8.2565,14.7733L8.2593,14.7711L8.3035,14.8093C8.3264,14.7924 8.346,14.7722 8.3651,14.7536C8.3455,14.7215 8.3433,14.6844 8.3618,14.6538L8.214,14.4891L8.2653,14.4465L8.4147,14.6129C8.4289,14.6064 8.4453,14.6042 8.46,14.6064C8.4725,14.5769 8.4824,14.5458 8.4889,14.5136L8.4284,14.4945L8.4289,14.4891C8.4289,14.4891 8.4349,14.4335 8.4349,14.4122C8.4349,14.3996 8.4376,14.3375 8.4376,14.3353L8.4376,14.3325L8.4987,14.3184L8.4987,14.2365C8.4725,14.2289 8.4513,14.2076 8.4415,14.182L8.2816,14.182L8.2816,14.1182L8.4409,14.1171C8.4513,14.0915 8.4715,14.0702 8.4993,14.0615L8.4993,13.9262L8.4382,13.9109L8.4382,13.7489L8.4993,13.732L8.4993,13.6C8.4971,13.5978 8.4949,13.5967 8.4927,13.5956L8.2756,13.8405L8.2227,13.8002L8.226,13.7958L8.4447,13.5509C8.4447,13.5476 8.4431,13.5444 8.442,13.5433L8.2811,13.5433L8.2811,13.4795L8.442,13.4795C8.4562,13.4424 8.4933,13.4167 8.5342,13.4167C8.5893,13.4167 8.634,13.4604 8.634,13.5127C8.634,13.5531 8.6084,13.5875 8.5685,13.6011L8.5675,13.7876L8.5091,13.7876L8.5091,13.8716L8.5675,13.8716L8.5669,14.0625C8.6067,14.0762 8.634,14.1105 8.634,14.1509C8.634,14.1924 8.6084,14.2267 8.5675,14.2393L8.5675,14.3233L8.6275,14.3456L8.6187,14.5033L8.5582,14.5169C8.5505,14.5573 8.538,14.5987 8.5216,14.6385L8.5244,14.6396C8.5407,14.6587 8.55,14.6822 8.5473,14.7078C8.5456,14.7335 8.5342,14.7564 8.5129,14.7716C8.4889,14.7929 8.454,14.7995 8.4229,14.7929C8.3973,14.8202 8.3684,14.8469 8.3389,14.8698L8.3525,14.9304L8.3493,14.9336C8.3045,14.9625 8.2571,14.9876 8.2058,15.0051L8.2025,15.0067ZM8.1665,14.9609L8.2047,14.9975C8.2522,14.9762 8.2975,14.9549 8.3411,14.9249L8.3291,14.8736C8.3165,14.8851 8.3035,14.8949 8.2909,14.9004L8.2871,14.9047L8.2865,14.9036C8.25,14.9249 8.208,14.9462 8.1665,14.9609ZM8.1213,14.8535L8.1322,14.9025C8.19,14.884 8.2462,14.8545 8.2969,14.8175L8.2593,14.7831C8.2178,14.8131 8.172,14.8355 8.1213,14.8535ZM8.2653,14.8485L8.2898,14.8911C8.3035,14.8824 8.3165,14.8731 8.3291,14.8622L8.3356,14.8595L8.3356,14.86C8.3645,14.8355 8.3918,14.8098 8.4158,14.7831L8.4185,14.7815L8.4213,14.7825C8.4507,14.7929 8.4829,14.7842 8.5064,14.7673C8.5244,14.7515 8.5364,14.7307 8.5375,14.7078C8.5402,14.6844 8.532,14.6653 8.5173,14.6451L8.5096,14.6396L8.5118,14.6364C8.5271,14.5982 8.5402,14.5584 8.5478,14.5191L8.5489,14.5142C8.5516,14.4989 8.5533,14.4847 8.5555,14.4695L8.5053,14.47C8.5015,14.5191 8.4884,14.5671 8.4676,14.614L8.4671,14.6184L8.4638,14.6173C8.448,14.6156 8.4305,14.6173 8.4164,14.6233L8.4131,14.6249L8.2658,14.4607L8.2276,14.4907L8.3749,14.6544L8.3722,14.6571C8.3531,14.686 8.3553,14.722 8.3755,14.7509L8.3782,14.7553L8.3749,14.7569C8.3422,14.7929 8.3056,14.8229 8.2653,14.8485ZM8.5658,14.4607L8.5658,14.4651C8.5636,14.4787 8.5631,14.494 8.5593,14.5098L8.6105,14.4989L8.6182,14.35L8.5669,14.3331L8.5669,14.3456L8.5669,14.3789L8.5669,14.3789L8.5669,14.4138C8.5669,14.4307 8.5658,14.4465 8.5658,14.4607L8.5658,14.4607L8.5658,14.4607ZM8.4382,14.4891L8.4927,14.5049C8.496,14.4771 8.4993,14.4498 8.4993,14.4133L8.4993,14.3293L8.448,14.3407C8.4475,14.3516 8.4453,14.3887 8.4447,14.4089C8.4453,14.4089 8.4453,14.4105 8.4447,14.4133C8.4447,14.4155 8.4447,14.4176 8.4447,14.4198C8.4431,14.4378 8.4398,14.4765 8.4382,14.4891ZM8.5085,14.3795L8.5085,14.4138C8.5085,14.4318 8.508,14.4482 8.5064,14.4607L8.5571,14.4607C8.5576,14.4471 8.5587,14.4307 8.5587,14.4138L8.5587,14.3789L8.5085,14.3795ZM8.2898,14.1749L8.448,14.1749L8.4485,14.1793C8.4573,14.2049 8.4785,14.2218 8.5053,14.2305L8.508,14.2322L8.508,14.3713L8.5582,14.3713L8.5582,14.3456L8.5582,14.2333L8.5615,14.2305C8.598,14.2207 8.6231,14.188 8.6231,14.1509C8.6231,14.116 8.5975,14.0805 8.5609,14.0691L8.5576,14.068L8.5576,14.0647L8.5582,13.8782L8.508,13.8782L8.508,14.0691L8.5053,14.0691C8.4764,14.0795 8.4573,14.0996 8.448,14.1258L8.4475,14.1291L8.2904,14.1291L8.2904,14.1749L8.2898,14.1749ZM8.448,13.9033L8.4993,13.918L8.4993,13.7435L8.448,13.7571L8.448,13.9033ZM8.2358,13.7991L8.2729,13.8291L8.4889,13.5842L8.4922,13.5875C8.4965,13.5907 8.5015,13.5918 8.5047,13.5918L8.5075,13.5935L8.5075,13.7816L8.5576,13.7816L8.5587,13.5945L8.5615,13.5935C8.5985,13.582 8.6231,13.5493 8.6231,13.5133C8.6231,13.4658 8.5838,13.4276 8.5331,13.4276C8.4949,13.4276 8.46,13.4516 8.448,13.4865L8.4475,13.4898L8.2882,13.4898L8.2882,13.5345L8.4475,13.5345L8.4485,13.54C8.4502,13.5411 8.4513,13.5455 8.4535,13.5476L8.4545,13.5509L8.4545,13.5531L8.2358,13.7991ZM8.448,14.7444C8.4355,14.7444 8.4224,14.7395 8.4142,14.7291C8.406,14.7204 8.4033,14.7078 8.4033,14.698C8.4044,14.6865 8.4098,14.6778 8.4191,14.668C8.4278,14.6625 8.4382,14.6565 8.448,14.6565C8.4611,14.6565 8.4736,14.6653 8.4829,14.6735C8.49,14.6822 8.4944,14.6931 8.4927,14.7035C8.4927,14.716 8.4862,14.7269 8.4769,14.7335C8.4698,14.7416 8.4589,14.7444 8.448,14.7444ZM8.448,14.668C8.4398,14.668 8.4316,14.6696 8.4251,14.6773C8.4175,14.6827 8.4125,14.6909 8.4125,14.6996C8.4125,14.7084 8.4153,14.7165 8.4213,14.7231C8.4333,14.7367 8.4573,14.74 8.472,14.7285C8.4802,14.7209 8.4835,14.7138 8.484,14.704C8.4851,14.6953 8.4824,14.6871 8.4764,14.68C8.4687,14.6707 8.4589,14.668 8.448,14.668ZM7.7127,14.5567L7.6451,14.5289L7.7825,14.3756L7.8213,14.4351L7.7127,14.5567ZM7.6609,14.5262L7.7095,14.5469L7.812,14.4351L7.7815,14.3915L7.6609,14.5262ZM7.6069,14.4989L7.5676,14.4395L7.6773,14.32L7.7449,14.3456L7.6069,14.4989ZM7.5785,14.4405L7.6085,14.4853L7.7291,14.35L7.6811,14.3293L7.5785,14.4405ZM7.3729,14.1924C7.3489,14.1924 7.3276,14.1733 7.3276,14.1509C7.3276,14.1285 7.3484,14.1073 7.3729,14.1073C7.3975,14.1073 7.4182,14.1285 7.4182,14.1509C7.4182,14.1733 7.3969,14.1924 7.3729,14.1924ZM7.3729,14.1155C7.3527,14.1155 7.3364,14.1313 7.3364,14.1504C7.3364,14.1689 7.3527,14.1836 7.3729,14.1836C7.3936,14.1836 7.4089,14.1695 7.4089,14.1504C7.4089,14.1313 7.3931,14.1155 7.3729,14.1155ZM7.3996,13.9289L7.3996,13.732L7.4689,13.7489L7.4689,13.9109L7.3996,13.9289ZM7.4089,13.7435L7.4089,13.918L7.4602,13.9033L7.4602,13.7571L7.4089,13.7435ZM7.3489,13.9289L7.2796,13.9109L7.2796,13.7489L7.3489,13.732L7.3489,13.9289ZM7.2878,13.9022L7.3402,13.918L7.3402,13.7435L7.2878,13.7571L7.2878,13.9022ZM7.9882,13.7167L7.9205,13.7167L7.9205,13.6005C7.8933,13.5907 7.8709,13.5695 7.8605,13.5433L7.716,13.5433L7.716,13.4795L7.8605,13.4795C7.8758,13.4424 7.9113,13.4167 7.9533,13.4167C7.9953,13.4167 8.0329,13.4424 8.0465,13.4795L8.1938,13.4795L8.1938,13.5433L8.0455,13.5433C8.0351,13.57 8.016,13.5913 7.9887,13.5989L7.9882,13.7167ZM7.9304,13.7064L7.9795,13.7064L7.98,13.5929L7.9833,13.5913C8.0095,13.5825 8.0285,13.5645 8.0389,13.5389L8.0395,13.5335L8.1851,13.5335L8.1851,13.4887L8.04,13.4887L8.0389,13.4855C8.0269,13.4505 7.9931,13.4265 7.9527,13.4265C7.914,13.4265 7.8796,13.4505 7.8682,13.4855L7.8665,13.4887L7.7258,13.4887L7.7258,13.5335L7.8665,13.5335L7.8682,13.5389C7.8769,13.5656 7.8987,13.5825 7.9265,13.5929L7.9298,13.5945L7.9298,13.7064L7.9304,13.7064Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.9576,15.0105C7.9331,15.0105 7.9124,14.9893 7.9124,14.9658C7.9124,14.9435 7.9331,14.9244 7.9576,14.9244C7.9816,14.9244 8.0024,14.9435 8.0024,14.9658C8.0024,14.9887 7.9816,15.0105 7.9576,15.0105ZM7.9576,14.9336C7.9375,14.9336 7.9211,14.9478 7.9211,14.9658C7.9211,14.9849 7.9375,15.0007 7.9576,15.0007C7.9778,15.0007 7.9942,14.9849 7.9942,14.9658C7.9942,14.9478 7.9778,14.9336 7.9576,14.9336ZM7.9309,14.6931L7.8616,14.6735L7.8616,14.5115L7.9309,14.4924L7.9309,14.6931ZM7.8698,14.6669L7.9216,14.6811L7.9216,14.5033L7.8698,14.518L7.8698,14.6669ZM7.9811,14.6931L7.9811,14.4924L8.0515,14.5115L8.0515,14.6735L7.9811,14.6931ZM7.9904,14.5033L7.9904,14.6811L8.0416,14.6669L8.0416,14.5185L7.9904,14.5033ZM8.1949,14.5567L8.1922,14.5545L8.0836,14.4351L8.1245,14.3756L8.2615,14.5289L8.1949,14.5567ZM8.0962,14.4351L8.1971,14.5469L8.2462,14.5262L8.1245,14.3915L8.0962,14.4351ZM8.2991,14.4989L8.1627,14.3456L8.2287,14.32L8.3395,14.4395L8.2991,14.4989ZM8.1769,14.35L8.2975,14.4853L8.3275,14.4405L8.2265,14.3293L8.1769,14.35ZM8.3209,14.2431L8.1513,14.2431L8.1311,14.1749L8.3422,14.1749L8.3209,14.2431ZM8.1584,14.2333L8.3144,14.2333L8.3296,14.1836L8.1442,14.1836L8.1584,14.2333ZM7.7575,14.2431L7.5878,14.2431L7.5687,14.1749L7.7787,14.1749L7.7575,14.2431ZM7.5944,14.2333L7.7509,14.2333L7.7667,14.1836L7.5802,14.1836L7.5944,14.2333ZM8.5342,14.1924C8.5091,14.1924 8.4895,14.1733 8.4895,14.1509C8.4895,14.1285 8.5091,14.1073 8.5342,14.1073C8.5598,14.1073 8.5789,14.1285 8.5789,14.1509C8.5789,14.1733 8.5593,14.1924 8.5342,14.1924ZM8.5342,14.1155C8.5151,14.1155 8.4987,14.1313 8.4987,14.1504C8.4987,14.1689 8.5151,14.1836 8.5342,14.1836C8.5538,14.1836 8.5696,14.17 8.5696,14.1504C8.5696,14.1307 8.5533,14.1155 8.5342,14.1155ZM8.3422,14.128L8.1311,14.128L8.1513,14.062L8.3209,14.062L8.3422,14.128ZM8.1442,14.1198L8.3296,14.1198L8.3144,14.0685L8.1584,14.0685L8.1442,14.1198ZM7.7787,14.128L7.5687,14.128L7.5878,14.062L7.7575,14.062L7.7787,14.128ZM7.5802,14.1198L7.7667,14.1198L7.7509,14.0685L7.5944,14.0685L7.5802,14.1198ZM7.6675,13.9764L7.5562,13.8531L7.5971,13.7958L7.7335,13.9491L7.6675,13.9764ZM7.5687,13.8515L7.6696,13.9655L7.7193,13.9442L7.5976,13.8105L7.5687,13.8515ZM8.2385,13.9725L8.1725,13.9436L8.3078,13.7904L8.3487,13.8482L8.2385,13.9725ZM8.1867,13.9409L8.2364,13.9622L8.3362,13.8471L8.3078,13.8067L8.1867,13.9409ZM8.5576,13.9289L8.5576,13.732L8.6275,13.7489L8.6275,13.9109L8.5576,13.9289ZM8.5669,13.7435L8.5669,13.918L8.6193,13.9022L8.6193,13.7571L8.5669,13.7435ZM7.7711,13.9153L7.6347,13.7653L7.7013,13.7364L7.7035,13.7385L7.812,13.8602L7.7711,13.9153ZM7.6489,13.7702L7.7705,13.9022L7.7995,13.8596L7.6985,13.7478L7.6489,13.7702ZM8.1338,13.9142L8.0929,13.8569L8.202,13.732L8.2691,13.7609L8.2658,13.7653L8.1338,13.9142ZM8.1049,13.8575L8.1349,13.8978L8.2544,13.7625L8.2053,13.7445L8.1049,13.8575ZM8.3231,13.6027L8.154,13.6027L8.1322,13.5345L8.3427,13.5345L8.3231,13.6027ZM8.16,13.5929L8.3165,13.5929L8.3307,13.5444L8.1436,13.5444L8.16,13.5929ZM7.7569,13.6027L7.5873,13.6027L7.566,13.5345L7.7765,13.5345L7.7569,13.6027ZM7.5944,13.5929L7.7504,13.5929L7.7651,13.5444L7.5791,13.5444L7.5944,13.5929ZM8.5342,13.5547C8.5096,13.5547 8.4895,13.5351 8.4895,13.5127C8.4895,13.4893 8.5096,13.468 8.5342,13.468C8.5598,13.468 8.5789,13.4893 8.5789,13.5127C8.5789,13.5345 8.5593,13.5547 8.5342,13.5547ZM8.5342,13.4778C8.5151,13.4778 8.4993,13.4931 8.4993,13.5122C8.4993,13.5302 8.5151,13.5444 8.5342,13.5444C8.5538,13.5444 8.5702,13.5307 8.5702,13.5122C8.5702,13.4931 8.5538,13.4778 8.5342,13.4778ZM7.9527,13.5547C7.9287,13.5547 7.9075,13.5351 7.9075,13.5127C7.9075,13.4893 7.9282,13.468 7.9527,13.468C7.9778,13.468 7.998,13.4893 7.998,13.5127C7.998,13.5345 7.9778,13.5547 7.9527,13.5547ZM7.9527,13.4778C7.9331,13.4778 7.9173,13.4931 7.9173,13.5122C7.9173,13.5302 7.9331,13.5444 7.9527,13.5444C7.9729,13.5444 7.9893,13.5307 7.9893,13.5122C7.9893,13.4931 7.9729,13.4778 7.9527,13.4778ZM7.3751,13.5547C7.3511,13.5547 7.3298,13.5351 7.3298,13.5127C7.3298,13.4893 7.3511,13.468 7.3751,13.468C7.3991,13.468 7.4204,13.4893 7.4204,13.5127C7.4204,13.5345 7.3996,13.5547 7.3751,13.5547ZM7.3751,13.4778C7.3549,13.4778 7.3385,13.4931 7.3385,13.5122C7.3385,13.5302 7.3549,13.5444 7.3751,13.5444C7.3953,13.5444 7.4111,13.5307 7.4111,13.5122C7.4116,13.4931 7.3958,13.4778 7.3751,13.4778ZM8.3427,13.4887L8.1322,13.4887L8.154,13.4216L8.3231,13.4216L8.3427,13.4887ZM8.1442,13.4795L8.3307,13.4795L8.3165,13.4293L8.16,13.4293L8.1442,13.4795ZM7.7765,13.4887L7.566,13.4887L7.5873,13.4216L7.7569,13.4216L7.7765,13.4887ZM7.5785,13.4795L7.7645,13.4795L7.7498,13.4293L7.5938,13.4293L7.5785,13.4795ZM7.98,13.8585L7.98,13.6584L8.0493,13.6775L8.0493,13.8384L7.98,13.8585ZM7.9887,13.6698L7.9887,13.8471L8.0405,13.8335L8.0405,13.6845L7.9887,13.6698ZM7.9304,13.8585L7.8605,13.8384L7.8605,13.6775L7.9304,13.6584L7.9304,13.8585ZM7.8693,13.8329L7.9211,13.8465L7.9211,13.6693L7.8693,13.6835L7.8693,13.8329Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M7.8627,14.1525C7.8627,14.1024 7.9047,14.062 7.9576,14.062C8.01,14.062 8.0515,14.1024 8.0515,14.1525C8.0515,14.2005 8.0095,14.242 7.9576,14.242C7.9047,14.242 7.8627,14.2005 7.8627,14.1525" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.9778,11.8098L7.9805,11.7885L7.9833,11.776C7.9833,11.776 7.9265,11.7804 7.8982,11.7738C7.8693,11.7645 7.842,11.7531 7.8153,11.7291C7.7875,11.7056 7.7771,11.6909 7.758,11.6893C7.71,11.6811 7.6751,11.7024 7.6751,11.7024C7.6751,11.7024 7.71,11.7149 7.7356,11.7493C7.7624,11.7804 7.7913,11.7962 7.8033,11.8016C7.8251,11.806 7.8955,11.8016 7.9145,11.8033C7.9336,11.8049 7.9778,11.8098 7.9778,11.8098" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2557,11.9334L8.2437,11.9324C8.2427,11.9324 8.1617,11.9214 8.1267,11.9194C8.1167,11.9194 8.0977,11.9194 8.0747,11.9204C8.0557,11.9214 8.0327,11.9214 8.0097,11.9214C7.9627,11.9214 7.9347,11.9194 7.9207,11.9114C7.8987,11.9064 7.8407,11.8804 7.7907,11.8124C7.7467,11.7584 7.6827,11.7354 7.6817,11.7354L7.6587,11.7234L7.6817,11.7134C7.6817,11.7114 7.7327,11.6784 7.8027,11.6784C7.8177,11.6784 7.8287,11.6804 7.8407,11.6844C7.8727,11.6924 7.8927,11.7054 7.9227,11.7354C7.9317,11.7424 7.9407,11.7494 7.9527,11.7624C7.9977,11.7974 8.0417,11.8194 8.1007,11.8384C8.1217,11.8424 8.1507,11.8464 8.1917,11.8464C8.2247,11.8464 8.2517,11.8424 8.2527,11.8424L8.2697,11.8404L8.2617,11.8824L8.2557,11.9334ZM8.1157,11.8944C8.1207,11.8944 8.1257,11.8944 8.1267,11.8944C8.1557,11.8964 8.2087,11.9044 8.2317,11.9044L8.2377,11.8714C8.2257,11.8734 8.2077,11.8734 8.1907,11.8734C8.1487,11.8734 8.1147,11.8694 8.0927,11.8634C8.0317,11.8434 7.9827,11.8184 7.9367,11.7834C7.9237,11.7714 7.9147,11.7634 7.9037,11.7524C7.8757,11.7254 7.8607,11.7174 7.8377,11.7114C7.8257,11.7074 7.8147,11.7054 7.8017,11.7054C7.7657,11.7054 7.7347,11.7174 7.7167,11.7234C7.7397,11.7394 7.7787,11.7624 7.8107,11.7954C7.8537,11.8564 7.9047,11.8844 7.9277,11.8894C7.9397,11.8954 7.9677,11.8974 8.0097,11.8974C8.0317,11.8974 8.0557,11.8974 8.0747,11.8974C8.0917,11.8944 8.1047,11.8944 8.1157,11.8944Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#ED72AA" + android:fillType="nonZero" + android:pathData="M8.2385,11.7302C8.2385,11.7302 8.2385,11.7547 8.2407,11.7804C8.2429,11.8033 8.2331,11.8235 8.2369,11.836C8.2407,11.8485 8.2429,11.8573 8.2478,11.8687C8.2522,11.8791 8.256,11.9015 8.256,11.9015C8.256,11.9015 8.2424,11.8916 8.2304,11.8824C8.2178,11.8725 8.208,11.8682 8.208,11.8682C8.208,11.8682 8.2113,11.8922 8.2118,11.9047C8.214,11.9145 8.2205,11.9347 8.2304,11.9462C8.2396,11.9576 8.2593,11.9773 8.2653,11.9931C8.2718,12.0067 8.2718,12.0422 8.2718,12.0422C8.2718,12.0422 8.2555,12.016 8.2407,12.0111C8.2271,12.0067 8.1976,11.9898 8.1976,11.9898C8.1976,11.9898 8.2244,12.0176 8.2244,12.0444C8.2244,12.0711 8.214,12.0995 8.214,12.0995C8.214,12.0995 8.2015,12.0755 8.1856,12.0602C8.1687,12.046 8.1464,12.0296 8.1464,12.0296C8.1464,12.0296 8.1633,12.0711 8.1633,12.0967C8.1633,12.124 8.1589,12.1818 8.1589,12.1818C8.1589,12.1818 8.1447,12.1605 8.1311,12.1475C8.118,12.1376 8.1011,12.1273 8.0962,12.1218C8.0913,12.1131 8.112,12.1436 8.1153,12.1616C8.1169,12.1769 8.1251,12.2413 8.1813,12.3242C8.214,12.37 8.2636,12.454 8.3711,12.4284C8.4796,12.3995 8.4387,12.2538 8.4158,12.1873C8.3929,12.1218 8.3831,12.0449 8.3836,12.0193C8.3847,11.9936 8.4033,11.9167 8.4011,11.902C8.3995,11.8873 8.3929,11.8316 8.4055,11.7891C8.4196,11.7411 8.4311,11.7253 8.4382,11.704C8.4464,11.6871 8.4524,11.674 8.4545,11.6593C8.4567,11.6402 8.4567,11.6102 8.4567,11.6102C8.4567,11.6102 8.4769,11.6484 8.4824,11.6615C8.4873,11.674 8.4873,11.7127 8.4873,11.7127C8.4873,11.7127 8.4916,11.6745 8.5211,11.6544C8.5522,11.6364 8.5865,11.6151 8.5953,11.6053C8.6045,11.5955 8.6067,11.5884 8.6067,11.5884C8.6067,11.5884 8.604,11.6533 8.5849,11.6789C8.5724,11.698 8.5249,11.7531 8.5249,11.7531C8.5249,11.7531 8.5495,11.7427 8.5658,11.7416C8.5844,11.7411 8.5969,11.7416 8.5969,11.7416C8.5969,11.7416 8.5762,11.7575 8.5478,11.7989C8.5211,11.8404 8.5315,11.8431 8.5124,11.8758C8.4922,11.9091 8.4758,11.9091 8.4513,11.9304C8.4131,11.9604 8.4327,12.0815 8.4387,12.0995C8.4431,12.1158 8.5091,12.2631 8.5091,12.3002C8.5113,12.3345 8.5178,12.4153 8.4551,12.4665C8.4142,12.4976 8.3487,12.4976 8.3335,12.5085C8.3176,12.5189 8.2887,12.5473 8.2887,12.6084C8.2887,12.6722 8.3111,12.6798 8.328,12.6967C8.3465,12.7104 8.3684,12.7022 8.3733,12.7147C8.3782,12.7262 8.3815,12.7338 8.3875,12.7404C8.3962,12.7491 8.4,12.7551 8.3978,12.7682C8.3962,12.7807 8.3667,12.8129 8.3569,12.832C8.346,12.8544 8.3269,12.91 8.3269,12.9182C8.3269,12.928 8.3242,12.9531 8.3335,12.9662C8.3335,12.9662 8.3645,13.0033 8.3427,13.0087C8.3302,13.0142 8.316,13.0011 8.3095,13.0033C8.2909,13.0076 8.2811,13.0185 8.2756,13.0169C8.2631,13.0169 8.2631,13.0082 8.262,12.9913C8.2604,12.9733 8.2615,12.9656 8.256,12.9656C8.2478,12.9656 8.244,12.9711 8.244,12.9815C8.2418,12.9913 8.2418,13.0125 8.2336,13.0125C8.2249,13.0125 8.2118,12.9956 8.2047,12.994C8.1965,12.9913 8.1758,12.9858 8.1742,12.9787C8.1742,12.9684 8.1867,12.9465 8.2009,12.9444C8.2151,12.94 8.2276,12.9318 8.2189,12.9275C8.2091,12.9187 8.2009,12.9187 8.1927,12.9275C8.1835,12.9318 8.1644,12.9275 8.1665,12.9171C8.1682,12.9056 8.1704,12.8931 8.1682,12.8876C8.1682,12.88 8.1518,12.8675 8.172,12.8576C8.1922,12.8478 8.2009,12.8675 8.2211,12.8647C8.2407,12.862 8.2505,12.8533 8.2582,12.8418C8.2664,12.8293 8.2642,12.8036 8.2505,12.7895C8.238,12.7736 8.2233,12.7736 8.2184,12.7622C8.2124,12.7518 8.2058,12.7295 8.2058,12.7295C8.2058,12.7295 8.2085,12.7731 8.2064,12.7775C8.2042,12.784 8.2058,12.8085 8.2058,12.8085C8.2058,12.8085 8.1922,12.7916 8.1802,12.7807C8.1698,12.7693 8.1573,12.7349 8.1573,12.7349C8.1573,12.7349 8.1573,12.766 8.1573,12.7785C8.1573,12.7911 8.1715,12.8031 8.1671,12.8107C8.1611,12.8145 8.1382,12.7862 8.1316,12.7785C8.1251,12.7747 8.106,12.7605 8.0967,12.7425C8.0869,12.7267 8.0809,12.7022 8.0787,12.6956C8.0765,12.6864 8.0722,12.6498 8.0765,12.6389C8.0825,12.6242 8.0929,12.5996 8.0929,12.5996C8.0929,12.5996 8.07,12.5996 8.0438,12.5996C8.0171,12.5996 7.9985,12.5942 7.9882,12.6105C7.9778,12.6275 7.9844,12.6629 7.9964,12.7098C8.0089,12.7567 8.0165,12.778 8.0127,12.7867C8.0089,12.7965 7.9925,12.8151 7.9865,12.8167C7.98,12.8233 7.9625,12.8211 7.9555,12.8167C7.9473,12.814 7.9353,12.808 7.9113,12.808C7.8873,12.808 7.8731,12.8091 7.8633,12.8058C7.8551,12.8036 7.8349,12.7922 7.824,12.796C7.8136,12.7993 7.7967,12.8069 7.8011,12.8205C7.8093,12.8418 7.7929,12.8473 7.7836,12.8451C7.7738,12.8429 7.7645,12.8407 7.752,12.8375C7.74,12.8331 7.7209,12.8375 7.7231,12.8238C7.7258,12.8091 7.7313,12.808 7.7373,12.7982C7.7433,12.7867 7.7455,12.778 7.7384,12.778C7.7291,12.778 7.7209,12.7769 7.7138,12.7824C7.7067,12.7884 7.6964,12.7993 7.6871,12.7955C7.6784,12.7905 7.6713,12.7791 7.6713,12.7589C7.6713,12.7355 7.6484,12.7153 7.6702,12.7175C7.6915,12.7185 7.7187,12.7355 7.7236,12.7229C7.728,12.7104 7.7253,12.7049 7.7138,12.6973C7.7024,12.6858 7.6871,12.6815 7.7024,12.6695C7.7187,12.658 7.722,12.658 7.728,12.6504C7.7345,12.6449 7.7427,12.6231 7.7536,12.6269C7.7755,12.6378 7.7542,12.6525 7.7765,12.676C7.7989,12.7016 7.8115,12.7104 7.8475,12.706C7.8845,12.7016 7.8944,12.6973 7.8944,12.688C7.8944,12.6765 7.8916,12.6591 7.8895,12.6509C7.8878,12.6455 7.8944,12.6176 7.8944,12.6176C7.8944,12.6176 7.8785,12.6264 7.8725,12.6378C7.8687,12.6482 7.8589,12.6635 7.8589,12.6635C7.8589,12.6635 7.8545,12.6455 7.8562,12.6264C7.8562,12.6176 7.8595,12.5996 7.8595,12.5969C7.8589,12.5865 7.8518,12.5631 7.8518,12.5631C7.8518,12.5631 7.8469,12.5876 7.842,12.5969C7.8376,12.604 7.8365,12.6335 7.8365,12.6335C7.8365,12.6335 7.8131,12.6122 7.8191,12.5811C7.8235,12.5544 7.8147,12.52 7.8235,12.5085C7.83,12.4971 7.8491,12.4529 7.8938,12.4502C7.9385,12.4475 7.974,12.4535 7.9898,12.4513C8.0062,12.4502 8.0613,12.4415 8.0613,12.4415C8.0613,12.4415 7.9582,12.3869 7.9358,12.37C7.9124,12.3564 7.8753,12.3149 7.8638,12.2964C7.8524,12.2778 7.8415,12.2407 7.8415,12.2407C7.8415,12.2407 7.8235,12.2407 7.8065,12.2522C7.7896,12.2625 7.7727,12.2751 7.7635,12.2865C7.7536,12.2975 7.7378,12.3215 7.7378,12.3215C7.7378,12.3215 7.7405,12.2887 7.7405,12.2789C7.7405,12.268 7.7389,12.2489 7.7389,12.2489C7.7389,12.2489 7.728,12.2925 7.704,12.3105C7.6805,12.3269 7.6533,12.3509 7.6533,12.3509C7.6533,12.3509 7.656,12.3253 7.656,12.3176C7.656,12.3138 7.6615,12.2855 7.6615,12.2855C7.6615,12.2855 7.6451,12.31 7.6195,12.3149C7.5938,12.3176 7.5573,12.3165 7.5545,12.334C7.5518,12.3504 7.5622,12.3695 7.5556,12.3804C7.5491,12.3929 7.5365,12.4016 7.5365,12.4016C7.5365,12.4016 7.5224,12.3891 7.5098,12.3891C7.4973,12.388 7.4858,12.3935 7.4858,12.3935C7.4858,12.3935 7.4744,12.3798 7.4787,12.3689C7.4825,12.3613 7.5016,12.3471 7.4973,12.3411C7.4924,12.3367 7.4765,12.3422 7.4667,12.3487C7.4575,12.3525 7.4367,12.3553 7.4384,12.3411C7.4411,12.3253 7.4449,12.3165 7.4411,12.304C7.4351,12.2931 7.4384,12.2871 7.4465,12.2849C7.4536,12.2805 7.4858,12.286 7.4891,12.2773C7.4913,12.2702 7.4798,12.2615 7.4602,12.256C7.4395,12.2516 7.4291,12.2402 7.4411,12.2282C7.4509,12.2195 7.4536,12.2156 7.4591,12.208C7.4635,12.1971 7.4667,12.1813 7.4847,12.1889C7.5027,12.1976 7.4984,12.2178 7.5185,12.2244C7.5382,12.2315 7.5845,12.2227 7.5949,12.2151C7.6047,12.2096 7.6358,12.1873 7.6462,12.1829C7.6571,12.1753 7.7018,12.1436 7.7018,12.1436C7.7018,12.1436 7.6751,12.1245 7.6653,12.1147C7.656,12.1071 7.6385,12.0831 7.6304,12.0798C7.6205,12.0733 7.578,12.058 7.5627,12.0564C7.5485,12.0564 7.5033,12.0405 7.5033,12.0405C7.5033,12.0405 7.5245,12.034 7.5311,12.0291C7.5376,12.0225 7.554,12.0089 7.5611,12.01C7.5693,12.01 7.5709,12.01 7.5709,12.01C7.5709,12.01 7.5289,12.0089 7.5207,12.0056C7.512,12.0045 7.4864,11.9876 7.4771,11.9876C7.4673,11.9876 7.4471,11.9931 7.4471,11.9931C7.4471,11.9931 7.4733,11.9751 7.4951,11.9718C7.5158,11.9675 7.5333,11.9675 7.5333,11.9675C7.5333,11.9675 7.4989,11.9587 7.4924,11.9473C7.4836,11.9364 7.4771,11.9205 7.4705,11.9129C7.464,11.9058 7.4607,11.8938 7.4498,11.8933C7.4384,11.8905 7.4198,11.9058 7.4095,11.9047C7.3991,11.9031 7.3904,11.8955 7.3904,11.8807C7.3898,11.8649 7.3904,11.8693 7.3865,11.8638C7.3822,11.8545 7.3669,11.8349 7.3811,11.8305C7.3969,11.8262 7.4275,11.8316 7.4302,11.8262C7.4329,11.8218 7.4133,11.8049 7.4007,11.7995C7.3882,11.7918 7.3685,11.7793 7.3778,11.7716C7.3893,11.7618 7.4002,11.7591 7.4067,11.7493C7.4122,11.7405 7.4193,11.7182 7.4324,11.7264C7.4444,11.7345 7.4613,11.7695 7.4711,11.7662C7.4809,11.7645 7.4825,11.7378 7.4798,11.7269C7.4782,11.7155 7.4798,11.698 7.4896,11.698C7.4989,11.7007 7.5076,11.7133 7.5235,11.7138C7.5387,11.7149 7.5633,11.7105 7.56,11.7225C7.5584,11.7329 7.5502,11.7471 7.5382,11.7585C7.5278,11.77 7.5229,11.7935 7.53,11.8109C7.5371,11.8256 7.5535,11.8513 7.5687,11.8622C7.5851,11.8709 7.614,11.8785 7.6325,11.89C7.6516,11.9025 7.6942,11.9375 7.7095,11.9413C7.7242,11.9445 7.7384,11.9538 7.7384,11.9538C7.7384,11.9538 7.7547,11.944 7.7776,11.944C7.8005,11.944 7.8524,11.9473 7.872,11.9407C7.8922,11.9309 7.9173,11.9178 7.9085,11.9004C7.9009,11.8813 7.8578,11.8665 7.8622,11.8529C7.866,11.8387 7.8818,11.8387 7.9075,11.8387C7.9336,11.8376 7.9707,11.842 7.9778,11.8044C7.9844,11.7662 7.986,11.7471 7.9495,11.7378C7.9113,11.7275 7.8845,11.7275 7.878,11.7024C7.8709,11.6756 7.8638,11.6691 7.872,11.6615C7.8791,11.6533 7.8933,11.65 7.9205,11.6489C7.9484,11.6473 7.9789,11.6473 7.9882,11.6385C7.9975,11.6342 7.9991,11.6151 8.0105,11.6085C8.0204,11.5998 8.0629,11.596 8.0629,11.596C8.0629,11.596 8.1131,11.6205 8.1605,11.6527C8.2025,11.686 8.2402,11.7307 8.2402,11.7307" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2751,13.0224C8.2751,13.0224 8.2751,13.0224 8.274,13.0224C8.256,13.0202 8.256,13.0076 8.2549,12.9929L8.2538,12.9815C8.2538,12.9787 8.2533,12.976 8.2527,12.9716C8.2522,12.9727 8.25,12.976 8.25,12.9815C8.25,12.9815 8.2495,12.9847 8.2495,12.9891C8.2473,13.0016 8.2467,13.0185 8.2336,13.0185C8.2249,13.0185 8.2184,13.0115 8.2107,13.006C8.2075,13.0033 8.2036,13 8.2025,12.9989C8.1998,12.9978 8.1971,12.9956 8.1944,12.9945C8.1835,12.9929 8.1698,12.9891 8.1676,12.9776C8.1665,12.9651 8.1824,12.9411 8.1998,12.9373C8.2075,12.934 8.2124,12.9307 8.214,12.9307C8.2075,12.9264 8.2025,12.9264 8.1965,12.9307C8.1889,12.9384 8.1775,12.9362 8.1693,12.9307C8.1622,12.928 8.1578,12.9209 8.1595,12.9155L8.1605,12.9051C8.1611,12.9007 8.1622,12.8915 8.1611,12.8882C8.1611,12.8882 8.1611,12.8871 8.1605,12.8849C8.1578,12.8795 8.154,12.8751 8.1551,12.8658C8.1578,12.8615 8.1611,12.8544 8.1682,12.8527C8.1829,12.8435 8.1927,12.85 8.202,12.8533C8.2075,12.8544 8.2124,12.8587 8.2189,12.8565C8.2385,12.8544 8.2473,12.8478 8.2533,12.8375C8.2593,12.8287 8.2571,12.8064 8.2462,12.7938C8.2396,12.7862 8.2336,12.7829 8.2282,12.778C8.2222,12.7764 8.2189,12.7736 8.2156,12.7682C8.2151,12.7736 8.2145,12.778 8.2135,12.7791C8.2129,12.7845 8.2129,12.7982 8.2129,12.8085L8.214,12.8276L8.2015,12.8124C8.2015,12.8124 8.1878,12.7998 8.1769,12.7867C8.172,12.7813 8.1682,12.7742 8.1649,12.7655C8.1649,12.7742 8.1649,12.7769 8.1649,12.7791C8.1649,12.7867 8.1682,12.79 8.1715,12.7938C8.1747,12.8009 8.1785,12.8085 8.1725,12.8151C8.1649,12.8238 8.1524,12.8118 8.1382,12.7938C8.1344,12.7905 8.1305,12.7862 8.1295,12.7862C8.1175,12.7764 8.1005,12.7622 8.0918,12.748C8.0831,12.73 8.0771,12.7087 8.0744,12.6984C8.0716,12.688 8.0662,12.6498 8.0716,12.6373C8.0755,12.6285 8.0809,12.6165 8.0842,12.6073L8.0455,12.6073C8.0378,12.6073 8.0313,12.6073 8.0253,12.6073C8.0084,12.6062 8.0013,12.6062 7.9958,12.6127C7.9887,12.6275 7.9909,12.6585 8.0045,12.7098L8.0095,12.7267C8.0204,12.7649 8.0242,12.7802 8.0209,12.7895C8.0165,12.7993 7.9991,12.8184 7.9915,12.8244C7.9833,12.8287 7.962,12.8271 7.9544,12.8244C7.9473,12.8189 7.9353,12.814 7.9129,12.814C7.9064,12.814 7.9004,12.814 7.8944,12.814C7.8807,12.814 7.8709,12.8145 7.8638,12.8113C7.8616,12.8113 7.8573,12.8113 7.8524,12.8091C7.8453,12.8036 7.8322,12.7998 7.8262,12.8015C7.8196,12.8025 7.812,12.8075 7.8098,12.8113C7.8082,12.8145 7.8076,12.8156 7.8093,12.8167C7.8136,12.8304 7.8109,12.8396 7.8076,12.8424C7.8011,12.85 7.7918,12.8533 7.7853,12.8516C7.7771,12.85 7.7711,12.85 7.7629,12.8467C7.7596,12.8456 7.7558,12.8435 7.752,12.8413C7.7487,12.8413 7.7449,12.8413 7.7411,12.8413C7.7335,12.8402 7.7247,12.8402 7.7209,12.8336C7.7176,12.8282 7.7176,12.8255 7.7176,12.8222C7.7209,12.8113 7.7242,12.8042 7.7275,12.8004C7.7296,12.7987 7.7302,12.7976 7.7329,12.7922C7.7351,12.7889 7.7367,12.7856 7.7367,12.7856C7.7302,12.7845 7.7242,12.7845 7.7209,12.7873L7.7176,12.79C7.7095,12.7976 7.6985,12.8058 7.686,12.8015C7.6729,12.7933 7.6664,12.7785 7.6664,12.7584C7.6664,12.7502 7.6636,12.7425 7.6598,12.7349C7.6571,12.7262 7.6533,12.7224 7.6571,12.7136C7.6609,12.7093 7.6675,12.7093 7.6724,12.7093C7.6811,12.7109 7.6904,12.7136 7.698,12.7147C7.7051,12.718 7.7171,12.7224 7.7193,12.7202C7.7225,12.7109 7.722,12.7093 7.7105,12.7C7.7095,12.6995 7.7078,12.6967 7.7051,12.6967C7.698,12.6902 7.6915,12.6864 7.6915,12.6776C7.6915,12.6727 7.6947,12.6678 7.7013,12.6629C7.7078,12.6585 7.7133,12.6542 7.7171,12.6504C7.7204,12.6493 7.7236,12.6487 7.7253,12.646C7.7269,12.6449 7.7275,12.6416 7.7296,12.6373C7.7356,12.6307 7.7449,12.6149 7.7585,12.622C7.7722,12.6291 7.7727,12.6373 7.7733,12.646C7.7738,12.6547 7.7744,12.6618 7.7831,12.6716C7.8038,12.6973 7.8164,12.7016 7.8485,12.6989C7.8835,12.6973 7.8889,12.6896 7.8889,12.6875C7.8889,12.6776 7.8867,12.6629 7.8856,12.6575L7.8845,12.6498C7.884,12.6471 7.8851,12.6389 7.8867,12.6329C7.8835,12.6356 7.8818,12.6373 7.8802,12.6384C7.8769,12.6498 7.8665,12.6673 7.866,12.6684L7.8573,12.6842L7.8535,12.6651C7.8535,12.664 7.8485,12.646 7.8507,12.6247C7.8507,12.6204 7.8507,12.6138 7.8524,12.6078C7.8535,12.6045 7.854,12.598 7.854,12.5975C7.854,12.5947 7.8535,12.5936 7.8529,12.5893C7.8507,12.5947 7.8507,12.5975 7.8491,12.5991C7.848,12.6035 7.8447,12.6204 7.8447,12.6335L7.8436,12.6476L7.8327,12.6373C7.8322,12.6373 7.8071,12.6149 7.8142,12.5789C7.8158,12.568 7.8158,12.5544 7.8153,12.544C7.8142,12.5249 7.8131,12.5118 7.8191,12.5058C7.8196,12.5047 7.8218,12.5015 7.8224,12.4971C7.8322,12.4802 7.8535,12.4447 7.8955,12.4431C7.9233,12.4415 7.9467,12.4431 7.9658,12.4442C7.9762,12.4447 7.9849,12.4447 7.9915,12.4447C8.0013,12.4442 8.0247,12.4415 8.0427,12.436C8.0111,12.4202 7.9505,12.3902 7.9342,12.3776C7.9085,12.3613 7.8725,12.3182 7.8611,12.3007C7.8513,12.286 7.842,12.2615 7.8382,12.2495C7.8316,12.2495 7.8218,12.2522 7.8115,12.2571C7.7935,12.2669 7.7776,12.2795 7.7705,12.2909C7.7613,12.3013 7.746,12.3264 7.746,12.3264L7.7335,12.3209C7.7335,12.3209 7.7362,12.292 7.7362,12.2805C7.7296,12.2931 7.7204,12.3073 7.71,12.3165C7.6865,12.3313 7.6598,12.3558 7.6598,12.3558L7.6473,12.3673L7.6484,12.3509C7.6505,12.3395 7.6511,12.3253 7.6511,12.3187C7.6511,12.3176 7.6522,12.3133 7.6533,12.3062C7.6451,12.3138 7.6347,12.3187 7.6227,12.322C7.6162,12.3242 7.6085,12.3253 7.602,12.3264C7.5862,12.3264 7.5638,12.3296 7.5627,12.3373C7.5611,12.3427 7.5627,12.352 7.5633,12.3564C7.5655,12.3678 7.5665,12.3776 7.5633,12.3869C7.5562,12.3989 7.5415,12.4076 7.5409,12.4076L7.5376,12.4098L7.5338,12.4076C7.5305,12.4033 7.5185,12.3951 7.5098,12.3951C7.4989,12.3951 7.4896,12.4016 7.4896,12.4016L7.4836,12.4038L7.4798,12.3995C7.4798,12.3962 7.4673,12.3815 7.4733,12.3695C7.4744,12.3651 7.4798,12.3585 7.4831,12.3553C7.4858,12.3525 7.488,12.3504 7.4896,12.3471C7.4847,12.3493 7.4744,12.3525 7.4705,12.3558C7.4629,12.358 7.4476,12.3656 7.4384,12.3569C7.4351,12.3558 7.4313,12.3525 7.4318,12.3427C7.4318,12.3389 7.4335,12.3313 7.4345,12.3302C7.4351,12.3198 7.4373,12.3165 7.4345,12.3105C7.4302,12.3018 7.4318,12.2936 7.4324,12.2893C7.4345,12.2855 7.4384,12.2805 7.4444,12.2795C7.4471,12.2789 7.4536,12.2789 7.4618,12.2778C7.4667,12.2778 7.4771,12.2778 7.482,12.2762C7.4793,12.274 7.4727,12.2675 7.4585,12.2647C7.4433,12.2631 7.4324,12.2533 7.4302,12.2429C7.4285,12.2375 7.4307,12.2304 7.4356,12.2265C7.4471,12.2162 7.4487,12.2151 7.4542,12.2047C7.4542,12.2036 7.4542,12.2025 7.4553,12.2009C7.4575,12.1938 7.4607,12.1867 7.4695,12.1845C7.4738,12.1813 7.4798,12.1824 7.4875,12.1867C7.4989,12.1911 7.5022,12.1993 7.5071,12.2047C7.5109,12.2124 7.5136,12.2162 7.5218,12.2195C7.5382,12.2265 7.5824,12.2162 7.5911,12.2118C7.5949,12.2107 7.6036,12.2031 7.6129,12.1993C7.6244,12.1895 7.6369,12.1813 7.6435,12.178C7.65,12.1736 7.6756,12.1567 7.6909,12.1458C7.6816,12.1382 7.6685,12.1267 7.6615,12.1224C7.6576,12.1191 7.6522,12.1136 7.6484,12.1098C7.6407,12.1 7.6309,12.0885 7.6271,12.0875C7.6178,12.0842 7.5758,12.0662 7.5633,12.0651C7.5475,12.0629 7.506,12.0504 7.5022,12.0493L7.4831,12.0427L7.5022,12.0362C7.5093,12.0329 7.5224,12.0285 7.5273,12.0247L7.5305,12.0231C7.5316,12.0204 7.5349,12.0204 7.5371,12.0182C7.5284,12.0171 7.5224,12.016 7.5185,12.0138C7.5158,12.0116 7.5093,12.0105 7.5027,12.0073C7.4951,12.0029 7.4804,11.9958 7.4771,11.9958C7.4689,11.9958 7.4542,11.9985 7.4482,11.9985L7.4438,11.986C7.4455,11.986 7.4711,11.9691 7.4935,11.9669C7.4962,11.9658 7.4995,11.9658 7.5016,11.9653C7.4956,11.9604 7.4902,11.9576 7.4864,11.9549C7.4836,11.9473 7.4787,11.9424 7.4749,11.9347C7.4711,11.9293 7.4673,11.9222 7.4645,11.9178C7.4645,11.9178 7.4613,11.9145 7.4607,11.9102C7.4564,11.9047 7.4536,11.9015 7.4493,11.9004C7.4455,11.9004 7.4389,11.9047 7.4324,11.9064C7.4242,11.9091 7.416,11.9135 7.4095,11.9124C7.3936,11.9102 7.3838,11.9009 7.3838,11.8835L7.3833,11.8791C7.3833,11.8747 7.3827,11.8715 7.3827,11.8704C7.3811,11.8704 7.3811,11.8693 7.3811,11.866C7.38,11.866 7.3778,11.8638 7.3778,11.8605C7.3718,11.8529 7.3664,11.8431 7.3696,11.8316C7.3713,11.8305 7.3735,11.8273 7.38,11.8251C7.3882,11.8218 7.4007,11.8229 7.4105,11.8229C7.4144,11.824 7.4193,11.824 7.422,11.824C7.4165,11.8185 7.4073,11.8104 7.398,11.806C7.3816,11.7973 7.3707,11.7891 7.3685,11.7804C7.3685,11.776 7.3685,11.7716 7.3751,11.7678C7.3789,11.7635 7.3844,11.7613 7.3876,11.7569C7.3942,11.7536 7.3975,11.7504 7.4002,11.7482C7.4013,11.7449 7.4029,11.7416 7.4035,11.7405C7.4089,11.7307 7.4133,11.7225 7.422,11.7193C7.4253,11.7171 7.4285,11.7171 7.4345,11.7215C7.4411,11.7247 7.4471,11.734 7.4542,11.7416C7.4596,11.7504 7.4667,11.7607 7.47,11.7629C7.4727,11.7596 7.4755,11.7416 7.4727,11.7285C7.4711,11.7187 7.4716,11.7029 7.4793,11.6964C7.4825,11.6909 7.4858,11.6898 7.4907,11.6909C7.4956,11.692 7.5016,11.6975 7.5049,11.7002C7.5115,11.7029 7.5158,11.7078 7.5235,11.7084C7.5273,11.7084 7.5305,11.7084 7.5355,11.7084C7.5475,11.7078 7.5589,11.7073 7.5633,11.7133C7.5655,11.716 7.5665,11.7193 7.5655,11.7247C7.5627,11.7389 7.5496,11.7547 7.5425,11.7629C7.5338,11.7744 7.53,11.7929 7.5349,11.8076C7.542,11.8245 7.5584,11.8469 7.572,11.8567C7.5796,11.8611 7.5905,11.8655 7.6004,11.8693C7.6124,11.8747 7.6255,11.8796 7.6353,11.8851C7.6418,11.8905 7.6489,11.8949 7.6576,11.902C7.6767,11.9156 7.7018,11.9331 7.7105,11.9331C7.722,11.9385 7.7335,11.9435 7.7378,11.9445C7.7444,11.9429 7.7596,11.9391 7.7771,11.9391C7.7825,11.9391 7.7885,11.9391 7.7956,11.9391C7.818,11.9402 7.8545,11.9413 7.8687,11.9325C7.8878,11.926 7.8998,11.9173 7.9025,11.9091C7.9042,11.9069 7.9042,11.9058 7.9025,11.9025C7.9004,11.8949 7.8889,11.89 7.8796,11.8813C7.8665,11.8725 7.8524,11.8644 7.8562,11.8513C7.8605,11.83 7.8824,11.83 7.908,11.83C7.9113,11.83 7.9145,11.83 7.9189,11.83C7.9473,11.83 7.9658,11.8284 7.9718,11.8033C7.9789,11.7651 7.9789,11.7515 7.9484,11.7449C7.9429,11.7427 7.9375,11.7405 7.9315,11.7405C7.902,11.7362 7.8785,11.7291 7.872,11.7024C7.8704,11.6958 7.8671,11.6898 7.8665,11.6855C7.8622,11.6729 7.86,11.6642 7.8676,11.6565C7.8775,11.6467 7.8927,11.644 7.9216,11.6407C7.9282,11.6407 7.9336,11.6396 7.9396,11.6396C7.9571,11.6385 7.9795,11.6385 7.9855,11.6342C7.9887,11.6342 7.9904,11.6255 7.992,11.6227C7.9953,11.6145 7.9991,11.6085 8.0067,11.602C8.0176,11.5955 8.058,11.5873 8.0618,11.5873L8.0645,11.5873L8.0656,11.5873C8.0662,11.5873 8.1169,11.6129 8.1638,11.6484C8.2058,11.6789 8.2435,11.7236 8.244,11.7269L8.2407,11.7291L8.2473,11.7291C8.2473,11.7302 8.2473,11.7536 8.2489,11.7782C8.2505,11.7907 8.2478,11.8033 8.2473,11.8131C8.2445,11.8207 8.2445,11.8284 8.2445,11.8311C8.2462,11.8365 8.2473,11.8387 8.2473,11.842C8.2505,11.8518 8.2511,11.8556 8.2549,11.8644C8.2604,11.8742 8.2636,11.8944 8.2636,11.8987L8.2647,11.9156L8.2527,11.9053C8.2527,11.9053 8.2391,11.8938 8.2265,11.8862C8.2233,11.8824 8.2205,11.8813 8.2189,11.8796C8.2189,11.8878 8.2189,11.8938 8.22,11.9015C8.2216,11.9091 8.2276,11.9282 8.2364,11.9407C8.238,11.9424 8.2413,11.9451 8.2445,11.9473C8.2549,11.9587 8.2685,11.974 8.2729,11.9876C8.28,12.0045 8.2795,12.0378 8.2795,12.04L8.2789,12.0602L8.2669,12.0433C8.2604,12.0335 8.2484,12.0176 8.2407,12.0165C8.2347,12.0138 8.2287,12.0089 8.2222,12.0078C8.2287,12.0176 8.2331,12.0302 8.2331,12.0422C8.2331,12.0689 8.2222,12.0978 8.2222,12.0989L8.2156,12.1115L8.2091,12.0989C8.2091,12.0989 8.1965,12.0776 8.1813,12.0618C8.1753,12.0564 8.1682,12.0509 8.1616,12.0471C8.1671,12.0607 8.1715,12.0804 8.1715,12.0951C8.1715,12.1224 8.1682,12.1769 8.1676,12.1813L8.1649,12.2015L8.1556,12.1845C8.1556,12.1845 8.142,12.1622 8.1295,12.1502C8.1262,12.1491 8.1229,12.1475 8.1191,12.1458C8.1207,12.1502 8.1235,12.1567 8.1235,12.1584C8.13,12.2129 8.1518,12.2647 8.1884,12.3171L8.1938,12.3247C8.226,12.3727 8.2735,12.4442 8.3716,12.4185C8.3951,12.4142 8.4142,12.4005 8.424,12.3804C8.4464,12.3411 8.4415,12.2773 8.4115,12.1884C8.3885,12.1202 8.3776,12.0433 8.3793,12.0176C8.3793,12.0051 8.3836,11.9827 8.3885,11.9582C8.3918,11.9358 8.3984,11.9069 8.3967,11.9025C8.3935,11.8824 8.3885,11.8289 8.4016,11.7842C8.4115,11.7515 8.4207,11.7329 8.4273,11.7171C8.4305,11.7105 8.4333,11.7062 8.4344,11.7013C8.4371,11.6958 8.4387,11.6898 8.4398,11.6871C8.4453,11.6756 8.4491,11.6664 8.4502,11.656C8.4529,11.6385 8.4529,11.6085 8.4529,11.6085L8.4655,11.6075C8.4655,11.6085 8.4856,11.6435 8.4911,11.6576C8.4922,11.6615 8.4944,11.6675 8.4944,11.6751C8.5009,11.6636 8.5075,11.6555 8.52,11.6467C8.5265,11.6429 8.5342,11.638 8.5418,11.6342C8.5636,11.6216 8.5865,11.6075 8.592,11.5993C8.5996,11.5884 8.6035,11.5835 8.6035,11.5835L8.616,11.5867C8.616,11.5878 8.6122,11.6549 8.5931,11.6838C8.5838,11.6936 8.5615,11.7198 8.5467,11.7373C8.5544,11.7373 8.5609,11.7351 8.5675,11.7351C8.586,11.7329 8.5991,11.7351 8.5996,11.7351L8.616,11.7373L8.6035,11.7465C8.6035,11.7471 8.5816,11.7629 8.5549,11.8016C8.5407,11.824 8.5375,11.8327 8.5342,11.8442C8.5315,11.8529 8.5287,11.8644 8.5205,11.8785C8.5042,11.9042 8.4911,11.9107 8.4769,11.9211C8.4704,11.9244 8.4638,11.9298 8.4562,11.9336C8.4235,11.9604 8.4398,12.0744 8.4464,12.0956C8.4469,12.1 8.454,12.118 8.4627,12.1371C8.4845,12.1895 8.5167,12.2724 8.5173,12.2991L8.5178,12.3035C8.5205,12.3411 8.5227,12.4185 8.46,12.4698C8.4322,12.4922 8.3935,12.4998 8.3656,12.5047C8.3542,12.508 8.3422,12.5091 8.3378,12.5124C8.3313,12.5178 8.2964,12.5435 8.2964,12.6073C8.2964,12.6585 8.3122,12.6711 8.3269,12.6842C8.3285,12.6858 8.3313,12.6875 8.3345,12.6885C8.3411,12.6973 8.3504,12.6973 8.358,12.7C8.3667,12.7005 8.376,12.7016 8.3804,12.7115L8.382,12.7142C8.3853,12.7245 8.3885,12.7289 8.394,12.7355C8.4011,12.7398 8.4093,12.7513 8.4055,12.7698C8.4049,12.7785 8.3945,12.79 8.3853,12.8031C8.3765,12.8145 8.3689,12.8255 8.3635,12.8375C8.3531,12.8565 8.334,12.9122 8.334,12.9182L8.334,12.9225C8.334,12.9324 8.334,12.9536 8.3395,12.9618C8.3433,12.9662 8.3618,12.9896 8.3564,13.0044C8.3558,13.0087 8.3531,13.0131 8.3455,13.0169C8.334,13.0196 8.3236,13.0158 8.3171,13.0104C8.3144,13.0082 8.3105,13.0082 8.3105,13.0082C8.3013,13.0093 8.2947,13.0169 8.2882,13.0185C8.2844,13.0202 8.28,13.0224 8.2751,13.0224ZM8.2555,12.9575C8.2658,12.9575 8.2669,12.9689 8.2675,12.982L8.2685,12.9924C8.2685,13.0076 8.2685,13.0076 8.2756,13.0087C8.2756,13.0087 8.2784,13.0076 8.2816,13.0065C8.2882,13.0033 8.2953,12.9967 8.3073,12.9951C8.3122,12.994 8.3165,12.9951 8.322,12.9973C8.3275,13.0016 8.3345,13.0038 8.34,13.0038C8.3422,13.0027 8.3422,13.0005 8.3422,13.0005C8.3455,12.994 8.3356,12.9782 8.3269,12.9695C8.3182,12.9558 8.3193,12.9324 8.3198,12.9215L8.3198,12.9171C8.3198,12.9056 8.3405,12.85 8.3504,12.8287C8.3547,12.8173 8.3645,12.8053 8.3733,12.7944C8.3804,12.7845 8.3902,12.7731 8.3902,12.7644C8.3929,12.7578 8.3902,12.7507 8.3836,12.7442C8.3744,12.7371 8.3716,12.7295 8.3673,12.7207L8.3662,12.7142C8.3645,12.7131 8.3613,12.712 8.3547,12.7115C8.3455,12.7104 8.3329,12.7087 8.3225,12.6995C8.3198,12.6962 8.3187,12.6962 8.316,12.694C8.2996,12.6804 8.2811,12.6629 8.2811,12.6067C8.2811,12.5342 8.3198,12.5058 8.3285,12.5015C8.3351,12.496 8.3449,12.4949 8.3607,12.4916C8.3864,12.4862 8.424,12.4791 8.4491,12.4573C8.5058,12.4125 8.5036,12.3411 8.5015,12.304L8.5015,12.2996C8.5015,12.274 8.4671,12.19 8.4475,12.1409C8.4382,12.1207 8.4322,12.1049 8.4311,12.0995C8.4311,12.0984 8.3995,11.9587 8.4453,11.9238C8.454,11.9178 8.46,11.9129 8.4665,11.908C8.4813,11.9004 8.4922,11.8938 8.5047,11.8698C8.514,11.8573 8.5162,11.8496 8.5189,11.8398C8.5227,11.8295 8.5265,11.8175 8.5418,11.7929C8.5565,11.7716 8.5707,11.7558 8.5795,11.7482C8.5751,11.7482 8.5713,11.7482 8.5664,11.7493C8.55,11.7504 8.5265,11.758 8.5265,11.758L8.5178,11.7482C8.5189,11.7471 8.5675,11.6909 8.5789,11.6751C8.5898,11.6609 8.5942,11.6342 8.5969,11.6124C8.5876,11.6227 8.5685,11.6342 8.5456,11.6478C8.5391,11.6511 8.5315,11.6555 8.5238,11.6604C8.4982,11.6762 8.4938,11.7116 8.4933,11.7116L8.4796,11.7116C8.4796,11.7018 8.4791,11.6735 8.4753,11.662C8.4725,11.6571 8.4682,11.6478 8.4627,11.6364C8.4627,11.6445 8.4627,11.6516 8.4611,11.6604C8.46,11.6729 8.4551,11.6805 8.4502,11.6915C8.4485,11.698 8.4475,11.7018 8.4442,11.7051C8.4425,11.7116 8.4398,11.7165 8.4371,11.7242C8.4305,11.7384 8.4213,11.7564 8.4115,11.788C8.3989,11.8305 8.4049,11.8818 8.4076,11.8987C8.4087,11.9075 8.4055,11.9287 8.3989,11.9615C8.3951,11.9838 8.3902,12.0051 8.3896,12.0182C8.3896,12.0438 8.3989,12.1164 8.4218,12.1845C8.4535,12.2773 8.4567,12.3422 8.4344,12.3869C8.4218,12.4093 8.4005,12.4262 8.3727,12.4316C8.2647,12.4584 8.2113,12.3804 8.1791,12.3324L8.1753,12.3264C8.1371,12.2724 8.1147,12.2151 8.1082,12.1611C8.1055,12.1491 8.094,12.1295 8.0896,12.1235L8.0896,12.1235L8.0869,12.1202L8.0891,12.1136L8.0918,12.1104L8.0956,12.1115C8.0973,12.1115 8.0984,12.1115 8.1,12.1147L8.1,12.1136C8.1033,12.1202 8.1109,12.1245 8.1202,12.1316C8.124,12.1327 8.1305,12.1371 8.1338,12.1415C8.1404,12.1458 8.1469,12.1529 8.1529,12.1611C8.154,12.1415 8.1556,12.1115 8.1556,12.0945C8.1556,12.0689 8.1393,12.0307 8.1393,12.0307L8.13,12.0084L8.1491,12.0209C8.1491,12.022 8.172,12.0356 8.1878,12.0531C8.1976,12.0607 8.2053,12.0722 8.2102,12.082C8.2129,12.0695 8.2167,12.0564 8.2167,12.0427C8.2167,12.0182 8.1911,11.9925 8.1911,11.9925L8.1998,11.9822C8.2004,11.9822 8.2293,11.9964 8.2424,12.004C8.2495,12.0051 8.2582,12.0116 8.2636,12.0193C8.2631,12.0089 8.262,11.9975 8.2587,11.992C8.2555,11.9816 8.2429,11.968 8.2331,11.9576C8.2304,11.9533 8.2265,11.9511 8.2238,11.9467C8.2129,11.9331 8.2069,11.9124 8.2047,11.902C8.2047,11.8905 8.2009,11.8655 8.2009,11.8655L8.2004,11.8513L8.2118,11.86C8.2118,11.86 8.2205,11.866 8.2331,11.8769C8.2375,11.8785 8.2424,11.8813 8.2456,11.8835C8.2445,11.8785 8.2429,11.8725 8.2418,11.8687C8.2375,11.8633 8.2358,11.8551 8.2331,11.8442C8.2331,11.8431 8.232,11.8387 8.2304,11.8376C8.2287,11.8289 8.2304,11.8196 8.232,11.8109C8.2331,11.8 8.2358,11.7907 8.2336,11.7787C8.2325,11.7618 8.2315,11.7405 8.2315,11.734C8.2233,11.7231 8.1905,11.6849 8.1545,11.6593C8.1147,11.6282 8.07,11.6069 8.0602,11.5998C8.0444,11.6042 8.0187,11.6085 8.0127,11.6124C8.0095,11.6167 8.0062,11.6227 8.0029,11.6271C8.0002,11.6336 7.9964,11.6396 7.9915,11.6462C7.9838,11.6505 7.9664,11.6505 7.9391,11.6527C7.9325,11.6527 7.9265,11.6538 7.92,11.6549C7.896,11.6571 7.8824,11.6593 7.8753,11.6647C7.8742,11.6669 7.8736,11.668 7.878,11.6784C7.8791,11.6849 7.8818,11.6898 7.884,11.7002C7.8878,11.7165 7.9036,11.7231 7.9325,11.7275C7.9391,11.7275 7.944,11.7285 7.9495,11.7307C7.9947,11.7405 7.9898,11.7733 7.9838,11.8044C7.9767,11.8425 7.9424,11.8425 7.9178,11.8425C7.914,11.8425 7.9107,11.8425 7.9069,11.8425C7.8813,11.8425 7.8704,11.8447 7.8687,11.854C7.8687,11.8562 7.8802,11.866 7.8873,11.8698C7.8976,11.8791 7.9102,11.8878 7.914,11.8955C7.9167,11.902 7.9167,11.9069 7.9145,11.9145C7.9102,11.926 7.8976,11.9347 7.8736,11.9445C7.8562,11.9533 7.8207,11.9533 7.794,11.9522C7.7875,11.9522 7.782,11.9522 7.7765,11.9522C7.7564,11.9522 7.7405,11.9576 7.7405,11.9576L7.7378,11.9576L7.7345,11.9576C7.7345,11.9576 7.722,11.9511 7.7073,11.9462C7.6964,11.944 7.6767,11.9309 7.6505,11.9118C7.6424,11.9058 7.6347,11.9004 7.6293,11.8955C7.6195,11.89 7.6075,11.8862 7.5965,11.8818C7.5845,11.8775 7.5736,11.872 7.5655,11.8676C7.5491,11.8562 7.53,11.8311 7.5235,11.8136C7.5147,11.7956 7.5207,11.7678 7.5333,11.7542C7.5425,11.7416 7.5502,11.7296 7.5524,11.7231C7.5491,11.7209 7.5404,11.722 7.5355,11.722C7.5295,11.722 7.5256,11.722 7.5213,11.722C7.5104,11.7209 7.5027,11.7155 7.4967,11.7111C7.4929,11.7078 7.4902,11.7045 7.4875,11.7035C7.4853,11.7067 7.4842,11.7149 7.4847,11.7264C7.4869,11.7356 7.488,11.7673 7.4722,11.7749C7.4618,11.7765 7.4531,11.7651 7.4438,11.7509C7.4373,11.7416 7.4313,11.7356 7.4275,11.7324C7.4253,11.7313 7.4247,11.7313 7.4247,11.7313C7.4215,11.7324 7.4182,11.7411 7.4149,11.746C7.4138,11.7493 7.4122,11.7525 7.4105,11.7536C7.4056,11.7613 7.4002,11.764 7.3942,11.7662C7.3898,11.7705 7.3865,11.7749 7.3827,11.7765C7.3822,11.7782 7.3833,11.7825 7.4029,11.7918C7.4133,11.7984 7.4329,11.8131 7.4362,11.8229C7.4378,11.8262 7.4367,11.8295 7.4351,11.8305C7.4318,11.8382 7.4231,11.8382 7.4089,11.836C7.3996,11.836 7.3898,11.8349 7.3833,11.8382C7.3805,11.8393 7.3865,11.8507 7.3882,11.8535C7.3898,11.8562 7.3904,11.8562 7.392,11.8595C7.3931,11.8616 7.3931,11.8638 7.3931,11.8649C7.3958,11.8676 7.3958,11.8682 7.3958,11.8775L7.3958,11.8807C7.3964,11.8944 7.404,11.8955 7.4084,11.8965C7.4127,11.8976 7.4198,11.8944 7.4253,11.8916C7.434,11.8889 7.4416,11.8835 7.4493,11.8845C7.4602,11.8862 7.4656,11.8944 7.47,11.9025C7.4722,11.9042 7.4722,11.9058 7.4744,11.9069C7.4782,11.9135 7.482,11.9184 7.4853,11.9271C7.4885,11.9325 7.4924,11.9385 7.4962,11.9435C7.5016,11.9495 7.5207,11.9576 7.5333,11.9598L7.5316,11.9735C7.5311,11.9735 7.5153,11.9724 7.4951,11.9778C7.4902,11.9789 7.4853,11.9789 7.4809,11.9805C7.488,11.9822 7.4967,11.9865 7.5082,11.992C7.5147,11.9953 7.5185,11.9975 7.5207,11.9985C7.5256,12.0007 7.5425,12.0029 7.5556,12.004C7.5578,12.004 7.5589,12.0029 7.5611,12.004C7.5649,12.0051 7.5682,12.0051 7.5687,12.0051C7.5693,12.0051 7.5693,12.0051 7.5698,12.0051L7.5693,12.0176C7.5693,12.0176 7.5693,12.0176 7.5682,12.0176C7.5671,12.0176 7.5616,12.0176 7.5573,12.0176C7.5535,12.0176 7.5464,12.022 7.5371,12.0302L7.5338,12.0335C7.5311,12.0345 7.5273,12.0367 7.5229,12.04C7.5365,12.0433 7.5556,12.0476 7.5616,12.0487C7.578,12.0509 7.6227,12.0689 7.632,12.0733C7.6385,12.0755 7.6451,12.0847 7.6576,12.0973C7.6609,12.1011 7.6658,12.1076 7.6691,12.1104C7.6784,12.1202 7.704,12.1371 7.7045,12.1371L7.7122,12.1436L7.7051,12.1485C7.6996,12.1502 7.6587,12.1829 7.6484,12.1873C7.6418,12.1895 7.6298,12.1993 7.6195,12.2075C7.6102,12.2129 7.6009,12.2189 7.5971,12.2222C7.5851,12.2265 7.5371,12.238 7.5158,12.2309C7.5033,12.2265 7.4978,12.2162 7.4945,12.2096C7.4913,12.202 7.488,12.1982 7.4809,12.1971C7.4776,12.1938 7.4744,12.1938 7.4722,12.1949C7.4705,12.196 7.4689,12.2004 7.4662,12.2025C7.4656,12.2064 7.4656,12.2102 7.464,12.2102C7.4591,12.2216 7.4553,12.2227 7.4444,12.2347C7.4411,12.2375 7.4416,12.2391 7.4416,12.2391C7.4433,12.2413 7.4498,12.2489 7.4602,12.2505C7.4771,12.2533 7.488,12.262 7.4929,12.2669C7.4945,12.2735 7.4945,12.2773 7.4945,12.2784C7.4902,12.2887 7.4765,12.2898 7.4613,12.2898C7.4564,12.2898 7.4498,12.2898 7.4471,12.2898C7.4449,12.2909 7.4438,12.2909 7.4438,12.2909C7.4438,12.2953 7.4438,12.2996 7.4465,12.3024C7.4498,12.3122 7.4482,12.3204 7.4465,12.3291C7.446,12.3335 7.4449,12.3378 7.4438,12.3416C7.4438,12.3416 7.4438,12.3427 7.4438,12.3427C7.446,12.346 7.4558,12.3438 7.4624,12.3416C7.4765,12.3351 7.4929,12.3275 7.5005,12.3373C7.5071,12.3427 7.4995,12.3531 7.4913,12.3629C7.488,12.3656 7.4842,12.3684 7.4836,12.3727C7.482,12.376 7.4842,12.3804 7.4869,12.3842C7.4913,12.3809 7.5005,12.3798 7.5098,12.3798C7.5202,12.3798 7.5305,12.3885 7.536,12.3913C7.5398,12.388 7.5458,12.3836 7.5485,12.3782C7.5513,12.3755 7.5491,12.3662 7.5485,12.3575C7.5469,12.3498 7.5458,12.3405 7.5469,12.3318C7.5502,12.3149 7.5742,12.3116 7.5976,12.3116C7.6047,12.3095 7.6124,12.3084 7.6189,12.3073C7.6407,12.3029 7.6555,12.2795 7.6555,12.2795L7.6675,12.286C7.6647,12.2985 7.662,12.316 7.662,12.3171C7.662,12.3215 7.6615,12.3275 7.6604,12.3329C7.6707,12.3242 7.686,12.3133 7.6985,12.3029C7.7209,12.2887 7.7313,12.2473 7.7313,12.2473L7.7449,12.2473C7.7449,12.2473 7.746,12.2664 7.746,12.2773C7.746,12.2805 7.746,12.2876 7.746,12.2942C7.7493,12.2887 7.7536,12.2833 7.7575,12.2773C7.7662,12.2696 7.7836,12.2527 7.8022,12.244C7.8202,12.2342 7.8393,12.2342 7.8404,12.2331L7.8458,12.2331L7.8475,12.2375C7.8475,12.2375 7.8589,12.2724 7.8687,12.2898C7.8807,12.3089 7.9162,12.3493 7.938,12.3624C7.9609,12.3782 8.0629,12.4305 8.0635,12.4305L8.082,12.4409L8.0618,12.4436C8.0591,12.4436 8.0051,12.4551 7.9887,12.4551C7.9822,12.4562 7.9729,12.4551 7.962,12.4551C7.944,12.4545 7.9205,12.4535 7.8927,12.4545C7.8584,12.4562 7.8415,12.4862 7.8322,12.5031C7.8295,12.5058 7.8289,12.5075 7.8273,12.5085C7.8245,12.5162 7.8262,12.5287 7.8262,12.5407C7.8262,12.5533 7.8267,12.5675 7.8251,12.58C7.8229,12.5925 7.8262,12.6056 7.8289,12.6133C7.8305,12.6056 7.8322,12.5964 7.8349,12.5931C7.8371,12.5855 7.842,12.5702 7.8436,12.5587L7.8491,12.5342L7.8567,12.5587C7.8567,12.5598 7.8644,12.5844 7.8644,12.5931C7.8644,12.5964 7.8644,12.5996 7.8633,12.6089C7.8622,12.6144 7.8611,12.6209 7.8611,12.6247C7.8611,12.6313 7.8611,12.6356 7.8611,12.6416C7.8627,12.6362 7.8644,12.634 7.8655,12.6307C7.8709,12.6204 7.8878,12.6095 7.89,12.6084L7.9025,12.5996L7.8993,12.6165C7.8965,12.6291 7.8944,12.6433 7.8949,12.6476L7.896,12.652C7.896,12.6607 7.8987,12.6744 7.8987,12.6853C7.8987,12.7011 7.8818,12.7076 7.8464,12.7104C7.8071,12.7131 7.7913,12.7044 7.7689,12.6798C7.7569,12.6656 7.7564,12.6542 7.7558,12.6455C7.7553,12.6367 7.7553,12.6351 7.7487,12.6313C7.7455,12.6313 7.7395,12.6411 7.7373,12.6438C7.7362,12.6482 7.7329,12.6493 7.7318,12.6525C7.7275,12.6569 7.7247,12.6596 7.7198,12.6613C7.7171,12.6624 7.7122,12.6678 7.7051,12.6727C7.7007,12.6744 7.7007,12.6755 7.7007,12.6755C7.7007,12.6776 7.7073,12.6831 7.7105,12.6831C7.7116,12.6858 7.7133,12.6875 7.7171,12.6875C7.7296,12.6989 7.7345,12.7087 7.728,12.724C7.7236,12.7365 7.7073,12.7333 7.6915,12.7267C7.6833,12.7256 7.6751,12.724 7.668,12.7229C7.6675,12.7229 7.6664,12.7229 7.6664,12.7229C7.6669,12.7245 7.6685,12.7256 7.6691,12.7289C7.6724,12.7376 7.6767,12.7469 7.6767,12.7578C7.6767,12.7824 7.6855,12.7873 7.6882,12.7889C7.6915,12.79 7.7002,12.7845 7.7045,12.778C7.7051,12.7769 7.7073,12.7769 7.7073,12.7758C7.7171,12.7687 7.7269,12.7704 7.7362,12.7725C7.7427,12.7725 7.7455,12.7753 7.7455,12.7769C7.7487,12.7835 7.7455,12.7895 7.74,12.7998C7.7384,12.8025 7.7362,12.8058 7.734,12.8091C7.7307,12.8129 7.7296,12.8156 7.7269,12.8238C7.7269,12.8238 7.7269,12.8255 7.7269,12.8255C7.7285,12.8271 7.7362,12.8271 7.7389,12.8282C7.7422,12.8282 7.7476,12.8282 7.7515,12.8282C7.7547,12.8304 7.7591,12.8325 7.7629,12.8336C7.77,12.8369 7.7749,12.8369 7.7809,12.8385C7.7853,12.8385 7.7902,12.8369 7.7924,12.8369C7.7935,12.8325 7.7935,12.8282 7.7918,12.8233C7.7902,12.8156 7.7902,12.8118 7.7935,12.8053C7.7984,12.7976 7.8098,12.7905 7.8191,12.7895C7.8284,12.7862 7.8393,12.7905 7.854,12.7971C7.8573,12.7993 7.8605,12.7993 7.8633,12.7993C7.8682,12.802 7.8769,12.8009 7.89,12.8009C7.896,12.8009 7.902,12.8009 7.9085,12.8009C7.9342,12.8009 7.9473,12.8069 7.9555,12.8124C7.962,12.814 7.9762,12.8151 7.98,12.8124C7.9849,12.8113 8.0007,12.7911 8.004,12.7856C8.0051,12.778 7.9996,12.76 7.992,12.7322L7.9871,12.7125C7.9724,12.6585 7.9696,12.6247 7.98,12.6078C7.9893,12.5909 8.0051,12.5931 8.0236,12.5953C8.0285,12.5953 8.0345,12.5953 8.0411,12.5953L8.1,12.5953L8.0967,12.6051C8.0967,12.6051 8.0858,12.6296 8.0798,12.6444C8.0771,12.6509 8.0798,12.6847 8.082,12.6935L8.0825,12.6967C8.0847,12.7033 8.0907,12.7267 8.0995,12.7404C8.1044,12.7518 8.1153,12.7644 8.1316,12.7758C8.1344,12.7775 8.1382,12.7785 8.1431,12.7873C8.1447,12.7873 8.1475,12.7905 8.1491,12.7916C8.1475,12.7889 8.1469,12.7862 8.1469,12.7802C8.1469,12.7665 8.1475,12.7365 8.1475,12.7365L8.16,12.7333C8.1633,12.7409 8.1725,12.7682 8.1818,12.778C8.1856,12.7824 8.1905,12.7878 8.1955,12.7916C8.1955,12.7862 8.1955,12.7791 8.1965,12.7764C8.1982,12.7736 8.1965,12.7507 8.1955,12.7322L8.208,12.7278C8.208,12.7278 8.2145,12.7518 8.2205,12.7622C8.2205,12.7638 8.2249,12.7665 8.2298,12.7687C8.2364,12.7753 8.2429,12.7785 8.2516,12.7878C8.2675,12.8047 8.268,12.8315 8.2587,12.8462C8.2495,12.8609 8.2369,12.8685 8.2167,12.8718C8.2058,12.8751 8.1976,12.8685 8.1911,12.8675C8.1835,12.8642 8.1785,12.8609 8.1698,12.8642C8.166,12.8675 8.1644,12.8685 8.1633,12.8707C8.1627,12.874 8.1655,12.8773 8.166,12.88C8.1687,12.8816 8.1687,12.8838 8.1693,12.8871C8.1715,12.8931 8.1693,12.9029 8.1687,12.9105L8.1676,12.9193C8.1676,12.9204 8.1693,12.9204 8.1704,12.9215C8.1753,12.9247 8.1802,12.9247 8.1824,12.9215C8.1938,12.9138 8.2058,12.9138 8.2167,12.9215C8.2227,12.9291 8.2227,12.9324 8.2227,12.9329C8.22,12.9444 8.2069,12.9487 8.1971,12.9531C8.1862,12.9542 8.1747,12.9711 8.1753,12.9787C8.1769,12.9798 8.1889,12.9842 8.1933,12.9842C8.1971,12.9864 8.2004,12.9875 8.202,12.9896C8.2058,12.9918 8.2096,12.9945 8.2135,12.9973C8.2184,13.0016 8.2249,13.0076 8.2282,13.0076C8.2287,13.006 8.2293,12.9951 8.2304,12.9902C8.2304,12.9858 8.2309,12.9847 8.2315,12.9831C8.2385,12.9618 8.25,12.9575 8.2555,12.9575Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.8791,11.7035C7.8791,11.7035 7.8725,11.6893 7.872,11.6855C7.8709,11.6778 7.8676,11.674 7.8676,11.674C7.8676,11.674 7.8982,11.674 7.8976,11.6838C7.896,11.6915 7.8873,11.6915 7.8856,11.6964C7.8829,11.6991 7.8791,11.7035 7.8791,11.7035" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.018,11.6708L8.016,11.6418C8.016,11.6418 8.064,11.6418 8.087,11.6598C8.122,11.6848 8.146,11.7238 8.145,11.7268C8.139,11.7318 8.111,11.7078 8.091,11.7008C8.091,11.7008 8.076,11.7068 8.063,11.7068C8.047,11.7068 8.041,11.7008 8.04,11.6928C8.038,11.6848 8.041,11.6768 8.041,11.6768L8.018,11.6708" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.1414,11.7321C8.1364,11.7321 8.1284,11.7261 8.1184,11.7201C8.1084,11.7121 8.1004,11.7081 8.0924,11.7071C8.0894,11.7071 8.0774,11.7101 8.0644,11.7101C8.0484,11.7101 8.0424,11.7021 8.0384,11.6941C8.0374,11.6861 8.0394,11.6781 8.0404,11.6781L8.0184,11.6741L8.0184,11.6721L8.0144,11.6391L8.0174,11.6391C8.0184,11.6391 8.0654,11.6411 8.0884,11.6601C8.1234,11.6831 8.1474,11.7231 8.1474,11.7241C8.1474,11.7271 8.1474,11.7271 8.1474,11.7271C8.1464,11.7311 8.1434,11.7321 8.1414,11.7321ZM8.0914,11.7021L8.0914,11.7021C8.0994,11.7051 8.1104,11.7101 8.1174,11.7161C8.1294,11.7241 8.1374,11.7261 8.1404,11.7261C8.1404,11.7261 8.1414,11.7261 8.1424,11.7261C8.1404,11.7241 8.1184,11.6871 8.0874,11.6631C8.0654,11.6491 8.0264,11.6451 8.0174,11.6451L8.0214,11.6701L8.0424,11.6741L8.0414,11.6781C8.0414,11.6781 8.0394,11.6861 8.0414,11.6921C8.0414,11.7021 8.0484,11.7071 8.0634,11.7071C8.0764,11.7071 8.0904,11.7021 8.0914,11.7021L8.0914,11.7021Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.4918,11.6991C7.4918,11.6991 7.5082,11.7116 7.5207,11.7133C7.5333,11.7149 7.5475,11.7149 7.5491,11.7149C7.5513,11.7149 7.5556,11.698 7.5524,11.6849C7.5458,11.6413 7.5076,11.6336 7.5076,11.6336C7.5076,11.6336 7.5196,11.6593 7.5142,11.6696C7.5071,11.6865 7.4918,11.6991 7.4918,11.6991" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.6065,11.8082C7.5985,11.8082 7.5755,11.8062 7.5545,11.8022C7.5265,11.7942 7.4955,11.7732 7.4945,11.7712L7.4815,11.7662L7.4935,11.7552C7.4935,11.7552 7.5195,11.7322 7.5315,11.7022C7.5365,11.6922 7.5285,11.6632 7.5195,11.6452L7.5105,11.6222L7.5355,11.6302C7.5365,11.6302 7.6135,11.6512 7.6255,11.7342C7.6295,11.7552 7.6245,11.7932 7.6185,11.8002L7.6135,11.8062L7.6065,11.8082ZM7.5195,11.7632C7.5305,11.7692 7.5455,11.7732 7.5565,11.7772C7.5715,11.7812 7.5895,11.7812 7.5995,11.7812C7.6005,11.7712 7.6045,11.7502 7.6005,11.7402C7.5945,11.6982 7.5705,11.6762 7.5535,11.6662C7.5565,11.6802 7.5585,11.7012 7.5535,11.7172C7.5435,11.7362 7.5305,11.7502 7.5195,11.7632Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.4122,11.7378C7.4122,11.7378 7.398,11.71 7.3675,11.7122C7.3353,11.7165 7.3151,11.7411 7.3151,11.7411C7.3151,11.7411 7.3495,11.7395 7.3576,11.7455C7.3702,11.7542 7.374,11.7765 7.374,11.7765C7.374,11.7765 7.3931,11.764 7.3996,11.7553C7.4051,11.7504 7.4122,11.7378 7.4122,11.7378" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.4289,11.8556L7.4239,11.8356C7.4239,11.8256 7.4149,11.7966 7.4009,11.7886C7.3949,11.7886 7.3799,11.7846 7.3409,11.7846C7.3329,11.7846 7.3289,11.7846 7.3289,11.7846L7.3009,11.7846L7.3189,11.7646C7.3189,11.7626 7.3599,11.7156 7.4219,11.7036C7.4869,11.6996 7.5179,11.7506 7.5179,11.7546L7.5209,11.7646L7.5179,11.7676C7.5179,11.7696 7.5019,11.7926 7.4919,11.8076C7.4799,11.8196 7.4479,11.8406 7.4429,11.8426L7.4289,11.8556ZM7.3579,11.7606C7.3999,11.7626 7.4089,11.7666 7.4109,11.7696C7.4279,11.7806 7.4389,11.7976 7.4429,11.8166C7.4539,11.8096 7.4659,11.7976 7.4699,11.7936C7.4769,11.7866 7.4869,11.7726 7.4919,11.7676C7.4819,11.7516 7.4599,11.7286 7.4229,11.7326C7.3959,11.7366 7.3749,11.7486 7.3579,11.7606Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.374,11.8442C7.374,11.8442 7.3484,11.8475 7.3331,11.8655C7.3195,11.8813 7.3205,11.9135 7.3205,11.9135C7.3205,11.9135 7.3385,11.8944 7.3549,11.8944C7.3707,11.8944 7.3942,11.9004 7.3942,11.9004C7.3942,11.9004 7.3871,11.8813 7.3871,11.8709C7.3865,11.8655 7.374,11.8442 7.374,11.8442" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.317,12.0056L7.314,11.9766C7.314,11.9726 7.312,11.9126 7.342,11.8786C7.371,11.8466 7.422,11.8396 7.424,11.8396L7.431,11.8376L7.436,11.8416C7.441,11.8496 7.459,11.8846 7.459,11.8986C7.459,11.9126 7.467,11.9356 7.472,11.9456L7.483,11.9666L7.46,11.9646C7.46,11.9646 7.415,11.9546 7.39,11.9546C7.369,11.9546 7.343,11.9756 7.337,11.9816L7.317,12.0056Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.8709,11.8442l0.0207,-0.03l0.0191,0.0289z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.9075,11.8398l0.0136,-0.0191l0.0153,0.018l-0.0289,0.0011" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.8949,11.7547l-0.0055,-0.0365l0.0453,0.0185z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.9293,11.7367l0.0256,0.0055l-0.0213,0.0136l-0.0044,-0.0191" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.9803,12.4987L7.9693,12.4777C7.9703,12.4777 8.0363,12.4387 8.0593,12.4307C8.0913,12.4077 8.1183,12.3737 8.1243,12.3637C8.1243,12.3407 8.1183,12.2907 8.1123,12.2667C8.1063,12.2507 8.1063,12.2317 8.1063,12.2157C8.0953,12.2277 8.0833,12.2407 8.0733,12.2477C8.0583,12.2607 8.0133,12.2897 7.9583,12.2977C7.9143,12.3137 7.8953,12.3207 7.8953,12.3207L7.8783,12.3027C7.8783,12.3027 7.9113,12.2497 7.9133,12.2047C7.9133,12.1977 7.9133,12.1867 7.9093,12.1717L7.9093,12.1717C7.8953,12.1797 7.8663,12.1947 7.8593,12.1977C7.8553,12.1997 7.8373,12.2107 7.8253,12.2187C7.8113,12.2267 7.7963,12.2417 7.7833,12.2477C7.7623,12.2617 7.7363,12.2967 7.7273,12.3117L7.7073,12.2957C7.7083,12.2957 7.7383,12.2437 7.7703,12.2257C7.7843,12.2177 7.7973,12.2057 7.8123,12.1997C7.8333,12.1807 7.8443,12.1767 7.8523,12.1747C7.8583,12.1717 7.8873,12.1557 7.9073,12.1487C7.9063,12.1447 7.9063,12.1407 7.9053,12.1347C7.9043,12.1117 7.9163,12.0857 7.9273,12.0647C7.9093,12.0727 7.8923,12.0787 7.8803,12.0787C7.8603,12.0787 7.8503,12.0787 7.8273,12.0687C7.8193,12.0647 7.8073,12.0627 7.7923,12.0597C7.7423,12.0447 7.7053,12.0787 7.7053,12.0787L7.6853,12.0927L7.6833,12.0677C7.6833,12.0657 7.6823,12.0327 7.7063,11.9937C7.7283,11.9627 7.7803,11.9467 7.7833,11.9467L7.7913,11.9697C7.7773,11.9717 7.7403,11.9887 7.7283,12.0087C7.7173,12.0187 7.7133,12.0317 7.7103,12.0417C7.7303,12.0347 7.7623,12.0257 7.7983,12.0347C7.8143,12.0397 7.8273,12.0417 7.8353,12.0457C7.8573,12.0557 7.8623,12.0557 7.8783,12.0557C7.8963,12.0557 7.9393,12.0377 7.9563,12.0327L7.9983,12.0167L7.9683,12.0557C7.9563,12.0637 7.9273,12.1087 7.9303,12.1337C7.9323,12.1497 7.9333,12.1567 7.9363,12.1707C7.9383,12.1827 7.9413,12.1957 7.9403,12.2097C7.9393,12.2367 7.9273,12.2667 7.9173,12.2897C7.9273,12.2837 7.9393,12.2777 7.9553,12.2737C8.0063,12.2657 8.0453,12.2407 8.0613,12.2267C8.0843,12.2087 8.1143,12.1657 8.1143,12.1657L8.1373,12.1747C8.1343,12.1937 8.1293,12.2397 8.1373,12.2577C8.1423,12.2757 8.1493,12.3177 8.1493,12.3437C8.1613,12.3357 8.1743,12.3227 8.1873,12.3187C8.2023,12.3127 8.2313,12.2957 8.2403,12.2757C8.2453,12.2687 8.2553,12.2347 8.2593,12.2167L8.2843,12.2187C8.2843,12.2187 8.2903,12.2707 8.3073,12.2947C8.3183,12.3127 8.3303,12.3477 8.3413,12.3767C8.3483,12.3587 8.3583,12.3387 8.3683,12.3257C8.4003,12.2887 8.4093,12.2727 8.4103,12.2647C8.4123,12.2507 8.4073,12.2257 8.4053,12.2177L8.4283,12.2057L8.4533,12.2647L8.4353,12.2707C8.4303,12.2887 8.4163,12.3117 8.3873,12.3427C8.3713,12.3587 8.3553,12.4037 8.3513,12.4127L8.3393,12.4517L8.3283,12.4127C8.3203,12.3897 8.2993,12.3287 8.2833,12.3087C8.2783,12.2947 8.2713,12.2857 8.2683,12.2697C8.2663,12.2777 8.2633,12.2877 8.2593,12.2877C8.2473,12.3107 8.2143,12.3307 8.2003,12.3377C8.1763,12.3507 8.1483,12.3757 8.1463,12.3777L8.1443,12.3797C8.1353,12.3897 8.1063,12.4287 8.0713,12.4477C8.0493,12.4617 7.9833,12.4967 7.9803,12.4987Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.4635,12.1944C7.4635,12.1944 7.4487,12.1775 7.4236,12.1845C7.3985,12.1878 7.3811,12.2145 7.3811,12.2145C7.3811,12.2145 7.4024,12.2102 7.4155,12.2135C7.428,12.2145 7.4384,12.2271 7.4384,12.2271C7.4384,12.2271 7.4493,12.2184 7.4542,12.2135C7.4569,12.2096 7.4635,12.1944 7.4635,12.1944" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.493,12.2915L7.485,12.2815C7.485,12.2815 7.472,12.2615 7.454,12.2585C7.437,12.2525 7.397,12.2625 7.397,12.2625L7.368,12.2705L7.383,12.2455C7.385,12.2425 7.416,12.1865 7.467,12.1775C7.52,12.1695 7.551,12.2005 7.553,12.2005L7.573,12.2215L7.55,12.2215C7.547,12.2295 7.538,12.2445 7.533,12.2505C7.525,12.2625 7.506,12.2815 7.502,12.2855L7.493,12.2915ZM7.44,12.2315C7.447,12.2315 7.454,12.2315 7.459,12.2335C7.475,12.2395 7.489,12.2475 7.497,12.2565C7.502,12.2465 7.511,12.2415 7.514,12.2385C7.518,12.2325 7.525,12.2205 7.528,12.2155C7.52,12.2035 7.5,12.1965 7.473,12.1995C7.451,12.2035 7.433,12.2205 7.421,12.2325C7.427,12.2315 7.434,12.2315 7.44,12.2315Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.4345,12.298C7.4345,12.298 7.4122,12.2915 7.3942,12.3089C7.3762,12.3247 7.374,12.3515 7.374,12.3515C7.374,12.3515 7.3931,12.3389 7.4062,12.3389C7.4193,12.3416 7.4367,12.3498 7.4367,12.3498C7.4367,12.3498 7.4395,12.3307 7.4411,12.3264C7.4433,12.3127 7.4345,12.298 7.4345,12.298" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.3675,12.4309L7.3675,12.4019C7.3675,12.4019 7.3705,12.3409 7.4085,12.3139C7.4345,12.2929 7.4635,12.2909 7.4785,12.2909C7.4865,12.2909 7.4905,12.2909 7.4905,12.2909L7.4965,12.2929L7.5015,12.2949C7.5015,12.3009 7.5195,12.3319 7.5135,12.3579C7.5115,12.3629 7.5055,12.3999 7.5055,12.3999L7.5015,12.4119L7.4885,12.4079C7.4875,12.4079 7.4595,12.3939 7.4375,12.3899L7.4315,12.3899C7.4165,12.3899 7.3955,12.4069 7.3885,12.4099L7.3675,12.4309Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.4842,12.3924C7.4842,12.3924 7.4825,12.4196 7.4956,12.4355C7.5098,12.4535 7.5349,12.4567 7.5349,12.4567C7.5349,12.4567 7.5273,12.4387 7.5251,12.4278C7.524,12.4153 7.5365,12.4022 7.5365,12.4022C7.5365,12.4022 7.524,12.3896 7.5109,12.3896C7.4978,12.3896 7.4842,12.3924 7.4842,12.3924" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.582,12.5365L7.563,12.5325C7.563,12.5325 7.5199,12.5225 7.4976,12.4895C7.4761,12.4525 7.4769,12.4015 7.4777,12.3985L7.4777,12.3895L7.486,12.3875C7.4877,12.3875 7.5092,12.3815 7.5291,12.3815C7.5539,12.3815 7.5729,12.4065 7.5754,12.4105L7.5828,12.4185L7.5746,12.4265C7.5704,12.4345 7.558,12.4495 7.5597,12.4655C7.5613,12.4755 7.5713,12.5025 7.5737,12.5125L7.582,12.5365ZM8.4162,12.7945L8.3996,12.7765C8.4004,12.7755 8.4551,12.6905 8.4559,12.6305C8.4592,12.5835 8.3872,12.5165 8.3574,12.4955L8.3673,12.4745C8.3798,12.4835 8.4791,12.5605 8.4774,12.6305C8.4749,12.7015 8.4178,12.7885 8.4162,12.7945Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.7384,12.6356C7.7384,12.6356 7.7209,12.6111 7.6964,12.6133C7.6713,12.6144 7.6456,12.6367 7.6456,12.6367C7.6456,12.6367 7.6773,12.6356 7.6838,12.6455C7.6925,12.6569 7.6996,12.67 7.6996,12.67C7.6996,12.67 7.7133,12.6613 7.7193,12.6585C7.7258,12.6504 7.7384,12.6356 7.7384,12.6356" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.7565,12.7337L7.7505,12.7267C7.7505,12.7237 7.7375,12.7037 7.7235,12.6847C7.7195,12.6797 7.7065,12.6767 7.6795,12.6767C7.6705,12.6767 7.6645,12.6767 7.6645,12.6767L7.6265,12.6767L7.6555,12.6537C7.6555,12.6537 7.7045,12.6097 7.7545,12.6067L7.7545,12.6067C7.8065,12.6067 7.8395,12.6517 7.8415,12.6537L7.8485,12.6597L7.8435,12.6657C7.8385,12.6697 7.8175,12.7007 7.8055,12.7087C7.7935,12.7177 7.7675,12.7297 7.7665,12.7297L7.7565,12.7337ZM7.7015,12.6537C7.7205,12.6537 7.7365,12.6597 7.7435,12.6707C7.7515,12.6827 7.7615,12.6947 7.7665,12.7037C7.7735,12.7007 7.7845,12.6927 7.7895,12.6847C7.7955,12.6847 7.8075,12.6707 7.8145,12.6597C7.8045,12.6517 7.7845,12.6307 7.7565,12.6307C7.7375,12.6337 7.7155,12.6407 7.7015,12.6537Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.6631,12.7338C7.6631,12.7338 7.6304,12.7262 7.6151,12.7453C7.5998,12.76 7.6004,12.79 7.6004,12.79C7.6004,12.79 7.6195,12.7709 7.6375,12.7731C7.6549,12.7731 7.674,12.7845 7.674,12.7845C7.674,12.7845 7.6713,12.7644 7.6696,12.7567C7.668,12.7475 7.6631,12.7338 7.6631,12.7338" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.5944,12.8791L7.5944,12.8441C7.5944,12.8441 7.5924,12.7871 7.6244,12.7501C7.6454,12.7271 7.6774,12.7251 7.7014,12.7251C7.7134,12.7251 7.7234,12.7271 7.7234,12.7271L7.7294,12.7271L7.7324,12.7351C7.7324,12.7351 7.7414,12.7661 7.7454,12.7801C7.7474,12.7961 7.7534,12.8311 7.7534,12.8311L7.7584,12.8541L7.7364,12.8441C7.7364,12.8421 7.7024,12.8261 7.6724,12.8211L7.6724,12.8211C7.6494,12.8211 7.6254,12.8441 7.6154,12.8581L7.5944,12.8791ZM7.7014,12.7501C7.6874,12.7501 7.6594,12.7501 7.6414,12.7691C7.6294,12.7821 7.6244,12.7991 7.6204,12.8191C7.6354,12.8091 7.6554,12.7981 7.6764,12.7981C7.6944,12.8001 7.7114,12.8081 7.7264,12.8141C7.7234,12.8021 7.7234,12.7931 7.7214,12.7891C7.7184,12.7751 7.7134,12.7621 7.7114,12.7521C7.7084,12.7501 7.7064,12.7501 7.7014,12.7501Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M7.7324,12.8369C7.7324,12.8369 7.7165,12.8571 7.7285,12.8751C7.7405,12.892 7.7645,12.9007 7.7645,12.9007C7.7645,12.9007 7.7564,12.8882 7.7607,12.874C7.764,12.8625 7.7836,12.8451 7.7836,12.8451L7.7324,12.8369" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.8348,12.9965L7.8008,12.9825C7.7978,12.9825 7.7508,12.9685 7.7268,12.9315C7.7028,12.8925 7.7328,12.8475 7.7348,12.8435L7.7568,12.8145L7.7568,12.8395L7.8658,12.8625L7.8448,12.8785C7.8308,12.8885 7.8088,12.9095 7.8068,12.9255C7.8018,12.9485 7.8128,12.9665 7.8128,12.9665L7.8348,12.9965Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M8.1622,12.8767C8.1622,12.8767 8.1338,12.8696 8.1185,12.8795C8.1027,12.8882 8.0902,12.928 8.0902,12.928C8.0902,12.928 8.1158,12.9051 8.1344,12.9095C8.1529,12.9138 8.1671,12.9182 8.1671,12.9182C8.1671,12.9182 8.1698,12.9045 8.1671,12.8925C8.166,12.8871 8.1622,12.8767 8.1622,12.8767" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.0765,13.0164L8.0895,12.9764C8.0905,12.9664 8.1135,12.8994 8.1465,12.8824C8.1595,12.8704 8.1745,12.8664 8.1945,12.8664C8.2165,12.8664 8.2355,12.8724 8.2355,12.8724L8.2415,12.8744L8.2445,12.8824C8.2445,12.8824 8.2535,12.9004 8.2535,12.9114C8.2585,12.9344 8.2535,12.9624 8.2535,12.9644L8.2495,12.9824L8.2355,12.9764C8.2355,12.9764 8.2125,12.9604 8.1785,12.9574C8.1765,12.9574 8.1765,12.9574 8.1765,12.9574C8.1525,12.9574 8.1175,12.9784 8.1075,12.9854L8.0765,13.0164ZM8.1945,12.8904C8.1785,12.8904 8.1655,12.8964 8.1595,12.9044C8.1475,12.9064 8.1365,12.9294 8.1265,12.9474C8.1435,12.9374 8.1655,12.9294 8.1835,12.9324C8.2025,12.9354 8.2185,12.9394 8.2305,12.9464C8.2305,12.9374 8.2305,12.9274 8.2305,12.9144C8.2305,12.9114 8.2265,12.9044 8.2245,12.8964C8.2185,12.8944 8.2065,12.8904 8.1945,12.8904Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M8.1758,12.9809C8.1758,12.9809 8.1535,13.0033 8.1622,13.0202C8.1698,13.0415 8.1835,13.0584 8.1835,13.0584C8.1835,13.0584 8.1829,13.0316 8.1927,13.024C8.2047,13.0131 8.2276,13.0104 8.2276,13.0104C8.2276,13.0104 8.2091,12.9945 8.2031,12.9929C8.1976,12.9902 8.1758,12.9809 8.1758,12.9809" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2225,13.1722L8.1985,13.1402C8.1965,13.1382 8.1715,13.1022 8.1575,13.0662C8.1405,13.0292 8.1825,12.9822 8.1845,12.9822L8.1905,12.9722L8.2005,12.9782C8.2105,12.9822 8.2415,12.9942 8.2475,12.9992C8.2595,13.0042 8.2865,13.0272 8.2965,13.0352L8.3175,13.0532L8.2885,13.0582C8.2885,13.0582 8.2505,13.0612 8.2295,13.0772C8.2245,13.0852 8.2195,13.1122 8.2205,13.1322L8.2225,13.1722Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#DB4446" + android:fillType="nonZero" + android:pathData="M8.2833,13.0136C8.2833,13.0136 8.2718,13.0415 8.2931,13.0573C8.3138,13.0742 8.3313,13.0775 8.3313,13.0775C8.3313,13.0775 8.316,13.0485 8.3198,13.0327C8.3264,13.0191 8.3389,13.0082 8.3389,13.0082C8.3389,13.0082 8.3133,13.0016 8.31,13.0027C8.3062,13.0033 8.2833,13.0136 8.2833,13.0136" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.4012,13.1585L8.3772,13.1585C8.3762,13.1585 8.3402,13.1535 8.3002,13.1195C8.2582,13.0805 8.2782,13.0255 8.2802,13.0235L8.2822,13.0175L8.2862,13.0175C8.3002,13.0095 8.3282,12.9945 8.3362,12.9945L8.3402,12.9945C8.3522,12.9945 8.3872,13.0105 8.3972,13.0105L8.4192,13.0185L8.3982,13.0345C8.3982,13.0345 8.3782,13.0485 8.3692,13.0715C8.3632,13.0895 8.3812,13.1285 8.3882,13.1375L8.4012,13.1585ZM8.3002,13.0385C8.2992,13.0495 8.2942,13.0805 8.3172,13.1035C8.3312,13.1115 8.3452,13.1215 8.3562,13.1265C8.3482,13.1055 8.3402,13.0795 8.3472,13.0625C8.3522,13.0465 8.3622,13.0365 8.3702,13.0275C8.3562,13.0215 8.3452,13.0175 8.3402,13.0175C8.3382,13.0185 8.3182,13.0315 8.3002,13.0385Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFD691" + android:fillType="nonZero" + android:pathData="M7.182,14.9336C7.2535,14.956 7.2905,15.0105 7.2905,15.0744C7.2905,15.1551 7.2104,15.2178 7.1073,15.2178C7.0031,15.2178 6.9196,15.1556 6.9196,15.0744C6.9196,15.0105 6.9545,14.9402 7.0255,14.9364C7.0255,14.9364 7.0238,14.9293 7.0178,14.92C7.0096,14.9113 6.9955,14.8955 6.9955,14.8955C6.9955,14.8955 7.0222,14.8911 7.038,14.8971C7.0538,14.9031 7.0647,14.9124 7.0647,14.9124C7.0647,14.9124 7.0729,14.8987 7.0822,14.8867C7.0936,14.8742 7.1078,14.8698 7.1078,14.8698C7.1078,14.8698 7.1242,14.8824 7.1285,14.8911C7.1335,14.8998 7.1373,14.9113 7.1373,14.9113C7.1373,14.9113 7.1525,14.8987 7.1651,14.8955C7.1776,14.8878 7.1945,14.8851 7.1945,14.8851C7.1945,14.8851 7.1885,14.8993 7.1853,14.908C7.1831,14.9167 7.182,14.9336 7.182,14.9336" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.2724,15.5367C7.0694,15.5367 6.9104,15.4097 6.9104,15.2557C6.9104,15.1367 6.9754,15.0097 7.0984,14.9877C7.0984,14.9817 7.0964,14.9817 7.0934,14.9787C7.0824,14.9667 7.0564,14.9387 7.0564,14.9387L7.0344,14.9177L7.0634,14.9117C7.0654,14.9117 7.0864,14.9087 7.1104,14.9087C7.1284,14.9087 7.1414,14.9097 7.1524,14.9117C7.1694,14.9217 7.1804,14.9277 7.1924,14.9347C7.1984,14.9267 7.2054,14.9117 7.2154,14.9037C7.2384,14.8807 7.2634,14.8647 7.2654,14.8627L7.2734,14.8567L7.2834,14.8647C7.2844,14.8647 7.3144,14.8897 7.3264,14.9097C7.3284,14.9157 7.3314,14.9257 7.3344,14.9307C7.3444,14.9237 7.3584,14.9117 7.3724,14.9097C7.3974,14.9017 7.4264,14.8897 7.4264,14.8897L7.4564,14.8857L7.4474,14.9107C7.4474,14.9107 7.4384,14.9417 7.4334,14.9577C7.4304,14.9617 7.4274,14.9737 7.4274,14.9827C7.5514,15.0277 7.6264,15.1237 7.6264,15.2537C7.6254,15.4137 7.4724,15.5367 7.2724,15.5367ZM7.1044,14.9407C7.1094,14.9507 7.1164,14.9537 7.1214,14.9587C7.1334,14.9817 7.1394,14.9977 7.1394,14.9977L7.1444,15.0187L7.1234,15.0207C7.0044,15.0267 6.9444,15.1427 6.9444,15.2547C6.9444,15.3937 7.0864,15.4967 7.2714,15.4967C7.4534,15.4967 7.5894,15.3947 7.5894,15.2547C7.5894,15.1377 7.5214,15.0497 7.4014,15.0127L7.3894,15.0067L7.3894,14.9967C7.3894,14.9927 7.3934,14.9597 7.4014,14.9477C7.4014,14.9397 7.4024,14.9337 7.4044,14.9317C7.3964,14.9337 7.3894,14.9337 7.3824,14.9377C7.3604,14.9497 7.3374,14.9667 7.3374,14.9687L7.3184,14.9807L7.3104,14.9577C7.3104,14.9577 7.3044,14.9397 7.2964,14.9267C7.2914,14.9187 7.2794,14.9057 7.2704,14.8997C7.2614,14.9037 7.2494,14.9117 7.2384,14.9247C7.2214,14.9407 7.2094,14.9657 7.2094,14.9667L7.1984,14.9837L7.1834,14.9737C7.1834,14.9737 7.1664,14.9547 7.1394,14.9467C7.1334,14.9407 7.1174,14.9387 7.1044,14.9407Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M7.0925,15.3067C7.0925,15.3067 6.9551,15.2145 6.8945,15.202C6.8176,15.1851 6.7325,15.1976 6.6965,15.1944C6.6965,15.1965 6.7407,15.2276 6.7598,15.2456C6.7789,15.2658 6.8422,15.304 6.8787,15.3138C6.9895,15.3427 7.0925,15.3067 7.0925,15.3067" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.2142,15.4579L7.2142,15.4579C7.1542,15.4579 7.0962,15.4519 7.0432,15.4369C6.9782,15.4209 6.8562,15.3509 6.8192,15.3119C6.7912,15.2889 6.7342,15.2419 6.7142,15.2259C6.7072,15.2229 6.7042,15.2179 6.7042,15.2179L6.6742,15.1889L6.7162,15.1929C6.7352,15.1949 6.7632,15.1929 6.7982,15.1889C6.8332,15.1869 6.8712,15.1829 6.9132,15.1829C6.9792,15.1829 7.0332,15.1909 7.0832,15.2009C7.1942,15.2239 7.4402,15.3889 7.4492,15.3939L7.4772,15.4139L7.4472,15.4279C7.4412,15.4289 7.3462,15.4579 7.2142,15.4579ZM6.7622,15.2239C6.7892,15.2419 6.8212,15.2699 6.8432,15.2879C6.8732,15.3189 6.9882,15.3899 7.0522,15.4049C7.1022,15.4169 7.1582,15.4279 7.2152,15.4279C7.2962,15.4279 7.3642,15.4119 7.4012,15.4049C7.3312,15.3579 7.1602,15.2489 7.0762,15.2309C7.0302,15.2219 6.9762,15.2169 6.9132,15.2169C6.8722,15.2169 6.8332,15.2169 6.7982,15.2199C6.7852,15.2229 6.7732,15.2229 6.7622,15.2239Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M7.1313,15.3149C7.1313,15.3149 7.2202,15.2222 7.3124,15.2096C7.422,15.1938 7.4924,15.2195 7.5344,15.2304C7.536,15.2304 7.4995,15.2456 7.4804,15.2598C7.4613,15.2724 7.4122,15.3155 7.3375,15.3171C7.2622,15.3171 7.1787,15.3073 7.1662,15.3084C7.1515,15.3105 7.1313,15.3149 7.1313,15.3149" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1062,15.44L7.1402,15.403C7.1462,15.395 7.3082,15.231 7.4802,15.208C7.5242,15.2 7.5672,15.196 7.6092,15.196C7.7262,15.196 7.8142,15.219 7.8722,15.237L7.9062,15.245L7.9072,15.255C7.9112,15.267 7.9022,15.275 7.8872,15.281C7.8662,15.288 7.8252,15.309 7.8022,15.328L7.7902,15.335C7.7482,15.368 7.6592,15.429 7.5302,15.431L7.5062,15.431C7.4332,15.431 7.3572,15.427 7.3032,15.425C7.2602,15.422 7.2282,15.419 7.2162,15.422C7.1932,15.425 7.1552,15.427 7.1552,15.427L7.1062,15.44ZM7.2272,15.387C7.2432,15.387 7.2692,15.389 7.3042,15.393C7.3582,15.395 7.4332,15.4 7.5062,15.4L7.5292,15.4C7.6492,15.398 7.7312,15.337 7.7712,15.309L7.7852,15.301C7.8022,15.285 7.8262,15.278 7.8472,15.262C7.7892,15.248 7.7112,15.231 7.6092,15.231C7.5672,15.231 7.5272,15.231 7.4852,15.239C7.3712,15.255 7.2582,15.341 7.2022,15.391C7.2042,15.389 7.2102,15.389 7.2112,15.389C7.2162,15.388 7.2212,15.387 7.2272,15.387Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M7.1056,15.202C7.0702,15.1676 7.0484,15.124 7.0484,15.0744C7.0484,15.0231 7.0702,14.9762 7.1056,14.9456C7.14,14.9767 7.1607,15.0236 7.1607,15.0744C7.1607,15.1245 7.1395,15.1682 7.1056,15.202" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1606,15.4496L7.1486,15.4336C7.0786,15.3726 7.0396,15.2856 7.0396,15.1916C7.0396,15.0976 7.0786,15.0036 7.1486,14.9416L7.1606,14.9336L7.1726,14.9416C7.2396,15.0046 7.2776,15.0976 7.2776,15.1916C7.2776,15.2856 7.2386,15.3736 7.1726,15.4336L7.1606,15.4496ZM7.1606,14.9786C7.1036,15.0336 7.0726,15.1056 7.0726,15.1916C7.0726,15.2696 7.1026,15.3416 7.1606,15.4026C7.2136,15.3416 7.2456,15.2676 7.2456,15.1916C7.2456,15.1056 7.2136,15.0336 7.1606,14.9786Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#058E6E" + android:fillType="nonZero" + android:pathData="M7.0702,15.3885C7.0702,15.3885 7.0915,15.3351 7.0931,15.2915C7.0958,15.2533 7.0882,15.2162 7.0882,15.2162C7.0882,15.2162 7.0996,15.2162 7.1056,15.2162C7.1116,15.2162 7.1149,15.2162 7.1149,15.2162C7.1149,15.2162 7.1291,15.256 7.1291,15.2915C7.1291,15.3269 7.1225,15.3722 7.1225,15.3722C7.1225,15.3722 7.1035,15.3755 7.0975,15.3798C7.0909,15.3809 7.0702,15.3885 7.0702,15.3885" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.0544,15.5694L7.0664,15.5344C7.0664,15.5344 7.1064,15.4404 7.1084,15.3624C7.1124,15.2954 7.1014,15.2274 7.1014,15.2274L7.0954,15.2064L7.1774,15.2064L7.1834,15.2224C7.1834,15.2224 7.2074,15.2974 7.2074,15.3634C7.2074,15.4274 7.1964,15.5114 7.1954,15.5114L7.1954,15.5274L7.1834,15.5274C7.1694,15.5324 7.1484,15.5354 7.1414,15.5354C7.1294,15.5454 7.0924,15.5564 7.0904,15.5584L7.0544,15.5694ZM7.1364,15.2414C7.1384,15.2684 7.1434,15.3154 7.1414,15.3624C7.1394,15.4174 7.1224,15.4794 7.1094,15.5104C7.1174,15.5104 7.1224,15.5084 7.1244,15.5084C7.1354,15.5024 7.1524,15.5024 7.1644,15.4984C7.1674,15.4714 7.1744,15.4084 7.1744,15.3614C7.1744,15.3144 7.1584,15.2634 7.1524,15.2404L7.1364,15.2404L7.1364,15.2414Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.8113,10.4069C8.8113,10.3856 8.8276,10.3698 8.8489,10.3698C8.8696,10.3698 8.886,10.3856 8.886,10.4069C8.886,10.4249 8.8696,10.4413 8.8489,10.4413C8.8282,10.4413 8.8113,10.4249 8.8113,10.4069" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.8867,10.5192C8.8427,10.5192 8.8047,10.4852 8.8047,10.4442C8.8047,10.3992 8.8427,10.3622 8.8867,10.3622C8.9307,10.3622 8.9677,10.3992 8.9677,10.4442C8.9677,10.4852 8.9307,10.5192 8.8867,10.5192ZM8.8867,10.3872C8.8547,10.3872 8.8307,10.4102 8.8307,10.4442C8.8307,10.4692 8.8537,10.4962 8.8867,10.4962C8.9177,10.4962 8.9427,10.4702 8.9427,10.4442C8.9417,10.4112 8.9177,10.3872 8.8867,10.3872Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.8636,10.3131C8.8636,10.2929 8.8789,10.2787 8.9018,10.2787C8.9209,10.2787 8.9389,10.2924 8.9389,10.3131C8.9389,10.3338 8.9209,10.348 8.9018,10.348C8.8789,10.3485 8.8636,10.3338 8.8636,10.3131" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.9391,10.4276C8.8921,10.4276 8.8571,10.3886 8.8571,10.3476C8.8571,10.3066 8.8921,10.2716 8.9391,10.2716C8.9821,10.2716 9.0191,10.3066 9.0191,10.3476C9.0191,10.3886 8.9821,10.4276 8.9391,10.4276ZM8.9391,10.2946C8.9051,10.2946 8.8801,10.3176 8.8801,10.3476C8.8801,10.3806 8.9031,10.4046 8.9391,10.4046C8.9671,10.4046 8.9941,10.3816 8.9941,10.3476C8.9941,10.3186 8.9681,10.2946 8.9391,10.2946Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.898,10.2078C8.898,10.1887 8.9149,10.1707 8.9362,10.1707C8.9558,10.1707 8.9738,10.1887 8.9738,10.2078C8.9738,10.2291 8.9558,10.2433 8.9362,10.2433C8.9149,10.2433 8.898,10.2291 8.898,10.2078" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.9739,10.3213C8.9279,10.3213 8.8909,10.2853 8.8909,10.2433C8.8909,10.1963 8.9279,10.1653 8.9739,10.1653C9.0179,10.1653 9.0559,10.1963 9.0559,10.2433C9.0549,10.2853 9.0179,10.3213 8.9739,10.3213ZM8.9739,10.1883C8.9409,10.1883 8.9159,10.2113 8.9159,10.2433C8.9159,10.2703 8.9399,10.2963 8.9739,10.2963C9.0049,10.2963 9.0299,10.2713 9.0299,10.2433C9.0299,10.2123 9.0049,10.1883 8.9739,10.1883Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.9018,10.0927C8.9018,10.0747 8.9182,10.0567 8.94,10.0567C8.9607,10.0567 8.9782,10.0747 8.9782,10.0927C8.9782,10.114 8.9602,10.1293 8.94,10.1293C8.9187,10.1293 8.9018,10.114 8.9018,10.0927" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.9778,10.2082C8.9308,10.2082 8.8958,10.1732 8.8958,10.1282C8.8958,10.0832 8.9308,10.0502 8.9778,10.0502C9.0228,10.0502 9.0598,10.0832 9.0598,10.1282C9.0598,10.1732 9.0228,10.2082 8.9778,10.2082ZM8.9778,10.0762C8.9458,10.0762 8.9188,10.0992 8.9188,10.1282C8.9188,10.1572 8.9448,10.1832 8.9778,10.1832C9.0068,10.1832 9.0348,10.1582 9.0348,10.1282C9.0348,10.1002 9.0068,10.0762 8.9778,10.0762Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.8735,9.9798C8.8735,9.9607 8.8915,9.9455 8.9111,9.9455C8.9329,9.9455 8.9493,9.9602 8.9493,9.9798C8.9493,10.0005 8.9329,10.0158 8.9111,10.0158C8.8915,10.0158 8.8735,10.0005 8.8735,9.9798" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.9484,10.0964C8.9044,10.0964 8.8664,10.0574 8.8664,10.0144C8.8664,9.9734 8.9044,9.9384 8.9484,9.9384C8.9954,9.9384 9.0304,9.9734 9.0304,10.0144C9.0304,10.0574 8.9954,10.0964 8.9484,10.0964ZM8.9484,9.9634C8.9204,9.9634 8.8914,9.9864 8.8914,10.0144C8.8914,10.0474 8.9194,10.0734 8.9484,10.0734C8.9814,10.0734 9.0074,10.0484 9.0074,10.0144C9.0074,9.9874 8.9814,9.9634 8.9484,9.9634Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.8151,9.8784C8.8151,9.8582 8.832,9.8435 8.8533,9.8435C8.874,9.8435 8.8915,9.8582 8.8915,9.8784C8.8915,9.8991 8.874,9.9133 8.8533,9.9133C8.832,9.9138 8.8151,9.8991 8.8151,9.8784" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.8905,9.9938C8.8435,9.9938 8.8085,9.9548 8.8085,9.9138C8.8085,9.8728 8.8435,9.8358 8.8905,9.8358C8.9355,9.8358 8.9725,9.8728 8.9725,9.9138C8.9725,9.9548 8.9355,9.9938 8.8905,9.9938ZM8.8905,9.8618C8.8585,9.8618 8.8315,9.8848 8.8315,9.9148C8.8315,9.9478 8.8575,9.9718 8.8905,9.9718C8.9205,9.9718 8.9485,9.9488 8.9485,9.9148C8.9485,9.8848 8.9215,9.8618 8.8905,9.8618Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.7382,9.7944C8.7382,9.7742 8.7551,9.7595 8.7758,9.7595C8.796,9.7595 8.8129,9.7742 8.8129,9.7944C8.8129,9.8145 8.796,9.8325 8.7758,9.8325C8.7551,9.8325 8.7382,9.8145 8.7382,9.7944" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.8131,9.9069C8.7681,9.9069 8.7311,9.8759 8.7311,9.8289C8.7311,9.7879 8.7681,9.7529 8.8131,9.7529C8.8571,9.7529 8.8951,9.7879 8.8951,9.8289C8.8951,9.8759 8.8571,9.9069 8.8131,9.9069ZM8.8131,9.7779C8.7801,9.7779 8.7561,9.8009 8.7561,9.8289C8.7561,9.8599 8.7791,9.8839 8.8131,9.8839C8.8451,9.8839 8.8691,9.8609 8.8691,9.8289C8.8691,9.8019 8.8451,9.7779 8.8131,9.7779Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.6471,9.7251C8.6471,9.7049 8.6645,9.6902 8.6847,9.6902C8.7065,9.6902 8.7229,9.7049 8.7229,9.7251C8.7229,9.7447 8.7065,9.76 8.6847,9.76C8.6645,9.7605 8.6471,9.7447 8.6471,9.7251" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.722,9.8405C8.678,9.8405 8.64,9.8015 8.64,9.7605C8.64,9.7195 8.678,9.6825 8.722,9.6825C8.769,9.6825 8.804,9.7195 8.804,9.7605C8.804,9.8015 8.769,9.8405 8.722,9.8405ZM8.722,9.7075C8.692,9.7075 8.665,9.7305 8.665,9.7605C8.665,9.7935 8.691,9.8175 8.722,9.8175C8.755,9.8175 8.781,9.7945 8.781,9.7605C8.78,9.7315 8.755,9.7075 8.722,9.7075Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.5391,9.6684C8.5391,9.6476 8.5565,9.6329 8.5767,9.6329C8.5975,9.6329 8.6144,9.6476 8.6144,9.6684C8.6144,9.6885 8.5975,9.7049 8.5767,9.7049C8.5571,9.7049 8.5391,9.6885 8.5391,9.6684" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.6145,9.7775C8.5705,9.7775 8.5325,9.7465 8.5325,9.7025C8.5325,9.6605 8.5705,9.6275 8.6145,9.6275C8.6595,9.6275 8.6965,9.6605 8.6965,9.7025C8.6965,9.7465 8.6595,9.7775 8.6145,9.7775ZM8.6145,9.6525C8.5825,9.6525 8.5575,9.6755 8.5575,9.7025C8.5575,9.7305 8.5815,9.7545 8.6145,9.7545C8.6475,9.7545 8.6715,9.7315 8.6715,9.7025C8.6705,9.6755 8.6475,9.6525 8.6145,9.6525Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.4267,9.628C8.4267,9.6067 8.4442,9.5925 8.4644,9.5925C8.4862,9.5925 8.502,9.6067 8.502,9.628C8.502,9.646 8.4862,9.664 8.4644,9.664C8.4442,9.6645 8.4267,9.6465 8.4267,9.628" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.5022,9.7424C8.4582,9.7424 8.4202,9.7094 8.4202,9.6644C8.4202,9.6204 8.4582,9.5844 8.5022,9.5844C8.5472,9.5844 8.5842,9.6204 8.5842,9.6644C8.5842,9.7094 8.5462,9.7424 8.5022,9.7424ZM8.5022,9.6104C8.4712,9.6104 8.4452,9.6354 8.4452,9.6654C8.4452,9.6954 8.4712,9.7184 8.5022,9.7184C8.5352,9.7184 8.5592,9.6954 8.5592,9.6654C8.5592,9.6354 8.5352,9.6104 8.5022,9.6104Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.3013,9.6056C8.3013,9.5855 8.3187,9.5685 8.3395,9.5685C8.3618,9.5685 8.3776,9.5855 8.3776,9.6056C8.3776,9.6258 8.3613,9.6405 8.3395,9.6405C8.3187,9.6411 8.3013,9.6258 8.3013,9.6056" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.3767,9.7167C8.3317,9.7167 8.2947,9.6817 8.2947,9.6407C8.2947,9.5957 8.3317,9.5647 8.3767,9.5647C8.4237,9.5647 8.4587,9.5957 8.4587,9.6407C8.4587,9.6807 8.4227,9.7167 8.3767,9.7167ZM8.3767,9.5877C8.3467,9.5877 8.3197,9.6107 8.3197,9.6407C8.3197,9.6657 8.3467,9.6917 8.3767,9.6917C8.4087,9.6917 8.4357,9.6667 8.4357,9.6407C8.4347,9.6107 8.4087,9.5877 8.3767,9.5877Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.1824,9.5996C8.1824,9.58 8.1993,9.5647 8.2205,9.5647C8.2413,9.5647 8.2587,9.58 8.2587,9.5996C8.2587,9.6187 8.2413,9.6345 8.2205,9.6345C8.1993,9.6345 8.1824,9.6187 8.1824,9.5996" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2578,9.712C8.2118,9.712 8.1758,9.677 8.1758,9.636C8.1758,9.595 8.2118,9.556 8.2578,9.556C8.3038,9.556 8.3398,9.595 8.3398,9.636C8.3398,9.677 8.3038,9.712 8.2578,9.712ZM8.2578,9.579C8.2268,9.579 8.1988,9.602 8.1988,9.636C8.1988,9.665 8.2258,9.689 8.2578,9.689C8.2888,9.689 8.3168,9.666 8.3168,9.636C8.3168,9.602 8.2888,9.579 8.2578,9.579Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.0662,9.6024C8.0662,9.5822 8.0836,9.5675 8.1038,9.5675C8.1251,9.5675 8.1415,9.5822 8.1415,9.6024C8.1415,9.6225 8.1251,9.6405 8.1038,9.6405C8.0836,9.6411 8.0662,9.6231 8.0662,9.6024" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.1411,9.7155C8.0971,9.7155 8.0591,9.6845 8.0591,9.6375C8.0591,9.5965 8.0971,9.5615 8.1411,9.5615C8.1861,9.5615 8.2231,9.5965 8.2231,9.6375C8.2221,9.6835 8.1861,9.7155 8.1411,9.7155ZM8.1411,9.5865C8.1091,9.5865 8.0841,9.6095 8.0841,9.6375C8.0841,9.6685 8.1091,9.6925 8.1411,9.6925C8.1741,9.6925 8.1981,9.6695 8.1981,9.6375C8.1981,9.6095 8.1741,9.5865 8.1411,9.5865Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.9495,9.6024C7.9495,9.5822 7.9664,9.5675 7.9876,9.5675C8.0078,9.5675 8.0253,9.5822 8.0253,9.6024C8.0253,9.6225 8.0078,9.6405 7.9876,9.6405C7.9658,9.6411 7.9495,9.6231 7.9495,9.6024" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.0249,9.7155C7.9779,9.7155 7.9429,9.6845 7.9429,9.6375C7.9429,9.5965 7.9779,9.5615 8.0249,9.5615C8.0689,9.5615 8.1069,9.5965 8.1069,9.6375C8.1069,9.6835 8.0689,9.7155 8.0249,9.7155ZM8.0249,9.5865C7.9929,9.5865 7.9659,9.6095 7.9659,9.6375C7.9659,9.6685 7.9919,9.6925 8.0249,9.6925C8.0549,9.6925 8.0819,9.6695 8.0819,9.6375C8.0819,9.6095 8.0549,9.5865 8.0249,9.5865Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.0073,9.7049C8.0073,9.6836 8.0247,9.6667 8.0449,9.6667C8.0673,9.6667 8.0831,9.6836 8.0831,9.7049C8.0831,9.7218 8.0667,9.7393 8.0449,9.7393C8.0247,9.7387 8.0073,9.7218 8.0073,9.7049" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.0827,9.8191C8.0387,9.8191 8.0007,9.7841 8.0007,9.7431C8.0007,9.6961 8.0387,9.6591 8.0827,9.6591C8.1297,9.6591 8.1647,9.6961 8.1647,9.7431C8.1647,9.7841 8.1287,9.8191 8.0827,9.8191ZM8.0827,9.6841C8.0527,9.6841 8.0257,9.7091 8.0257,9.7431C8.0257,9.7691 8.0527,9.7951 8.0827,9.7951C8.1147,9.7951 8.1417,9.7701 8.1417,9.7431C8.1407,9.7101 8.1147,9.6841 8.0827,9.6841Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.0318,9.8124C8.0318,9.7944 8.0482,9.778 8.0695,9.778C8.0902,9.778 8.1071,9.7938 8.1071,9.8124C8.1071,9.8325 8.0896,9.8495 8.0695,9.8495C8.0482,9.85 8.0318,9.8325 8.0318,9.8124" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.1067,9.9285C8.0627,9.9285 8.0247,9.8915 8.0247,9.8465C8.0247,9.8055 8.0617,9.7715 8.1067,9.7715C8.1517,9.7715 8.1887,9.8055 8.1887,9.8465C8.1887,9.8915 8.1507,9.9285 8.1067,9.9285ZM8.1067,9.7955C8.0737,9.7955 8.0507,9.8185 8.0507,9.8465C8.0507,9.8795 8.0737,9.9035 8.1067,9.9035C8.1377,9.9035 8.1637,9.8805 8.1637,9.8465C8.1637,9.8195 8.1377,9.7955 8.1067,9.7955Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.0351,9.9236C8.0351,9.9029 8.052,9.8882 8.0733,9.8882C8.0945,9.8882 8.1115,9.9029 8.1115,9.9236C8.1115,9.9433 8.094,9.9602 8.0733,9.9602C8.0525,9.9607 8.0351,9.9433 8.0351,9.9236" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.1111,10.0342C8.0651,10.0342 8.0291,10.0032 8.0291,9.9592C8.0291,9.9172 8.0651,9.8822 8.1111,9.8822C8.1571,9.8822 8.1931,9.9172 8.1931,9.9592C8.1931,10.0022 8.1571,10.0342 8.1111,10.0342ZM8.1111,9.9092C8.0801,9.9092 8.0521,9.9322 8.0521,9.9592C8.0521,9.9872 8.0791,10.0112 8.1111,10.0112C8.1421,10.0112 8.1691,9.9882 8.1691,9.9592C8.1681,9.9322 8.1421,9.9092 8.1111,9.9092Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M8.0007,10.0245C8.0007,10.0033 8.0182,9.9891 8.0389,9.9891C8.0607,9.9891 8.0771,10.0033 8.0771,10.0245C8.0771,10.0436 8.0602,10.0605 8.0389,10.0605C8.0182,10.0605 8.0007,10.0436 8.0007,10.0245" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.0762,10.138C8.0312,10.138 7.9942,10.105 7.9942,10.06C7.9942,10.016 8.0312,9.982 8.0762,9.982C8.1232,9.982 8.1582,10.016 8.1582,10.06C8.1582,10.105 8.1232,10.138 8.0762,10.138ZM8.0762,10.006C8.0462,10.006 8.0192,10.03 8.0192,10.06C8.0192,10.09 8.0462,10.113 8.0762,10.113C8.1082,10.113 8.1352,10.09 8.1352,10.06C8.1352,10.03 8.1082,10.006 8.0762,10.006Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.9364,10.1167C7.9364,10.0971 7.9533,10.0802 7.9745,10.0802C7.9953,10.0802 8.0127,10.0971 8.0127,10.1167C8.0127,10.1364 7.9953,10.1522 7.9745,10.1522C7.9538,10.1522 7.9364,10.1364 7.9364,10.1167" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.0124,10.2267C7.9664,10.2267 7.9304,10.1937 7.9304,10.1517C7.9304,10.1077 7.9664,10.0747 8.0124,10.0747C8.0574,10.0747 8.0944,10.1077 8.0944,10.1517C8.0944,10.1937 8.0574,10.2267 8.0124,10.2267ZM8.0124,10.0997C7.9804,10.0997 7.9534,10.1227 7.9534,10.1517C7.9534,10.1777 7.9804,10.2017 8.0124,10.2017C8.0424,10.2017 8.0694,10.1787 8.0694,10.1517C8.0694,10.1237 8.0424,10.0997 8.0124,10.0997Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.8605,9.5336C7.8605,9.5135 7.878,9.4993 7.8982,9.4993C7.92,9.4993 7.9364,9.5129 7.9364,9.5336C7.9364,9.5544 7.92,9.5685 7.8982,9.5685C7.878,9.5685 7.8605,9.5544 7.8605,9.5336" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.9355,9.6491C7.8915,9.6491 7.8535,9.6101 7.8535,9.5691C7.8535,9.5281 7.8915,9.4911 7.9355,9.4911C7.9815,9.4911 8.0175,9.5281 8.0175,9.5691C8.0175,9.6101 7.9825,9.6491 7.9355,9.6491ZM7.9355,9.5161C7.9055,9.5161 7.8795,9.5391 7.8795,9.5691C7.8795,9.6021 7.9055,9.6261 7.9355,9.6261C7.9685,9.6261 7.9935,9.6031 7.9935,9.5691C7.9945,9.5391 7.9695,9.5161 7.9355,9.5161Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.7575,9.4764C7.7575,9.4556 7.7738,9.4409 7.7956,9.4409C7.8158,9.4409 7.8333,9.4556 7.8333,9.4764C7.8333,9.496 7.8158,9.5129 7.7956,9.5129C7.7738,9.5129 7.7575,9.496 7.7575,9.4764" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.8329,9.5864C7.7859,9.5864 7.7509,9.5554 7.7509,9.5114C7.7509,9.4674 7.7859,9.4344 7.8329,9.4344C7.8769,9.4344 7.9149,9.4674 7.9149,9.5114C7.9149,9.5554 7.8769,9.5864 7.8329,9.5864ZM7.8329,9.4594C7.7999,9.4594 7.7739,9.4844 7.7739,9.5114C7.7739,9.5394 7.7989,9.5634 7.8329,9.5634C7.8619,9.5634 7.8889,9.5404 7.8889,9.5114C7.8889,9.4854 7.8619,9.4594 7.8329,9.4594Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.6424,9.4409C7.6424,9.424 7.6598,9.406 7.6805,9.406C7.7018,9.406 7.7187,9.424 7.7187,9.4409C7.7187,9.4622 7.7018,9.478 7.6805,9.478C7.6598,9.478 7.6424,9.4622 7.6424,9.4409" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.7184,9.557C7.6734,9.557 7.6364,9.52 7.6364,9.475C7.6364,9.432 7.6734,9.4 7.7184,9.4C7.7654,9.4 7.8004,9.432 7.8004,9.475C7.8004,9.52 7.7644,9.557 7.7184,9.557ZM7.7184,9.425C7.6884,9.425 7.6604,9.448 7.6604,9.475C7.6604,9.506 7.6884,9.532 7.7184,9.532C7.7504,9.532 7.7774,9.507 7.7774,9.475C7.7764,9.448 7.7494,9.425 7.7184,9.425Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.524,9.4224C7.524,9.4011 7.5409,9.3853 7.5622,9.3853C7.5829,9.3853 7.6004,9.4011 7.6004,9.4224C7.6004,9.4404 7.5829,9.4567 7.5622,9.4567C7.5409,9.4567 7.524,9.4409 7.524,9.4224" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.5995,9.5372C7.5525,9.5372 7.5175,9.5012 7.5175,9.4602C7.5175,9.4152 7.5525,9.3782 7.5995,9.3782C7.6445,9.3782 7.6815,9.4152 7.6815,9.4602C7.6815,9.5002 7.6445,9.5372 7.5995,9.5372ZM7.5995,9.4032C7.5675,9.4032 7.5405,9.4262 7.5405,9.4602C7.5405,9.4852 7.5675,9.5122 7.5995,9.5122C7.6295,9.5122 7.6565,9.4862 7.6565,9.4602C7.6565,9.4262 7.6305,9.4032 7.5995,9.4032Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.4084,9.4235C7.4084,9.4022 7.4253,9.388 7.446,9.388C7.4667,9.388 7.4836,9.4022 7.4836,9.4235C7.4836,9.4425 7.4667,9.4595 7.446,9.4595C7.4253,9.46 7.4084,9.4431 7.4084,9.4235" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.4827,9.5369C7.4387,9.5369 7.4007,9.5039 7.4007,9.4589C7.4007,9.4149 7.4387,9.3809 7.4827,9.3809C7.5267,9.3809 7.5647,9.4149 7.5647,9.4589C7.5647,9.5039 7.5277,9.5369 7.4827,9.5369ZM7.4827,9.4059C7.4507,9.4059 7.4267,9.4299 7.4267,9.4599C7.4267,9.4899 7.4497,9.5129 7.4827,9.5129C7.5157,9.5129 7.5397,9.4899 7.5397,9.4599C7.5397,9.4299 7.5157,9.4059 7.4827,9.4059Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.2873,9.4431C7.2873,9.424 7.3036,9.4087 7.3249,9.4087C7.3451,9.4087 7.3625,9.4235 7.3625,9.4431C7.3625,9.4638 7.3451,9.4791 7.3249,9.4791C7.3036,9.4791 7.2873,9.4638 7.2873,9.4431" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.3622,9.5596C7.3172,9.5596 7.2802,9.5206 7.2802,9.4776C7.2802,9.4366 7.3172,9.4016 7.3622,9.4016C7.4062,9.4016 7.4442,9.4366 7.4442,9.4776C7.4442,9.5196 7.4062,9.5596 7.3622,9.5596ZM7.3622,9.4266C7.3292,9.4266 7.3052,9.4496 7.3052,9.4776C7.3052,9.5106 7.3292,9.5366 7.3622,9.5366C7.3932,9.5366 7.4182,9.5116 7.4182,9.4776C7.4182,9.4496 7.3932,9.4266 7.3622,9.4266Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M7.1749,9.4824C7.1749,9.4622 7.1913,9.4475 7.2125,9.4475C7.2333,9.4475 7.2502,9.4622 7.2502,9.4824C7.2502,9.502 7.2333,9.5173 7.2125,9.5173C7.1918,9.5173 7.1749,9.502 7.1749,9.4824" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.2498,9.5978C7.2058,9.5978 7.1678,9.5588 7.1678,9.5178C7.1678,9.4768 7.2058,9.4398 7.2498,9.4398C7.2938,9.4398 7.3318,9.4768 7.3318,9.5178C7.3318,9.5588 7.2948,9.5978 7.2498,9.5978ZM7.2498,9.4648C7.2178,9.4648 7.1938,9.4878 7.1938,9.5178C7.1938,9.5508 7.2168,9.5748 7.2498,9.5748C7.2818,9.5748 7.3068,9.5518 7.3068,9.5178C7.3068,9.4878 7.2818,9.4648 7.2498,9.4648Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.2767,10.4069C5.2767,10.3856 5.2931,10.3698 5.3144,10.3698C5.3345,10.3698 5.3515,10.3856 5.3515,10.4069C5.3515,10.4249 5.3345,10.4413 5.3144,10.4413C5.2931,10.4413 5.2767,10.4249 5.2767,10.4069" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.3516,10.5192C5.3066,10.5192 5.2696,10.4852 5.2696,10.4442C5.2696,10.3992 5.3066,10.3622 5.3516,10.3622C5.3956,10.3622 5.4326,10.3992 5.4326,10.4442C5.4326,10.4852 5.3956,10.5192 5.3516,10.5192ZM5.3516,10.3872C5.3186,10.3872 5.2946,10.4102 5.2946,10.4442C5.2946,10.4692 5.3176,10.4962 5.3516,10.4962C5.3826,10.4962 5.4076,10.4702 5.4076,10.4442C5.4076,10.4112 5.3826,10.3872 5.3516,10.3872Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.2244,10.3131C5.2244,10.2929 5.2418,10.2787 5.2615,10.2787C5.2833,10.2787 5.2991,10.2924 5.2991,10.3131C5.2991,10.3338 5.2833,10.348 5.2615,10.348C5.2418,10.3485 5.2244,10.3338 5.2244,10.3131" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.2983,10.4276C5.2543,10.4276 5.2173,10.3886 5.2173,10.3476C5.2173,10.3066 5.2543,10.2716 5.2983,10.2716C5.3443,10.2716 5.3813,10.3066 5.3813,10.3476C5.3813,10.3886 5.3443,10.4276 5.2983,10.4276ZM5.2983,10.2946C5.2683,10.2946 5.2423,10.3176 5.2423,10.3476C5.2423,10.3806 5.2673,10.4046 5.2983,10.4046C5.3323,10.4046 5.3563,10.3816 5.3563,10.3476C5.3563,10.3186 5.3333,10.2946 5.2983,10.2946Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.1905,10.2078C5.1905,10.1887 5.2069,10.1707 5.2282,10.1707C5.2484,10.1707 5.2653,10.1887 5.2653,10.2078C5.2653,10.2291 5.2484,10.2433 5.2282,10.2433C5.2069,10.2433 5.1905,10.2291 5.1905,10.2078" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.2659,10.3213C5.2209,10.3213 5.1829,10.2853 5.1829,10.2433C5.1829,10.1963 5.2209,10.1653 5.2659,10.1653C5.3099,10.1653 5.3469,10.1963 5.3469,10.2433C5.3469,10.2853 5.3099,10.3213 5.2659,10.3213ZM5.2659,10.1883C5.2329,10.1883 5.2089,10.2113 5.2089,10.2433C5.2089,10.2703 5.2319,10.2963 5.2659,10.2963C5.2969,10.2963 5.3219,10.2713 5.3219,10.2433C5.3219,10.2123 5.2969,10.1883 5.2659,10.1883Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.1851,10.0927C5.1851,10.0747 5.2025,10.0567 5.2227,10.0567C5.2445,10.0567 5.2609,10.0747 5.2609,10.0927C5.2609,10.114 5.2445,10.1293 5.2227,10.1293C5.2025,10.1293 5.1851,10.114 5.1851,10.0927" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.26,10.2082C5.216,10.2082 5.178,10.1732 5.178,10.1282C5.178,10.0832 5.216,10.0502 5.26,10.0502C5.307,10.0502 5.342,10.0832 5.342,10.1282C5.342,10.1732 5.307,10.2082 5.26,10.2082ZM5.26,10.0762C5.231,10.0762 5.203,10.0992 5.203,10.1282C5.203,10.1572 5.23,10.1832 5.26,10.1832C5.293,10.1832 5.319,10.1582 5.319,10.1282C5.319,10.1002 5.293,10.0762 5.26,10.0762Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.2135,9.9798C5.2135,9.9607 5.2304,9.9455 5.2516,9.9455C5.2724,9.9455 5.2898,9.9602 5.2898,9.9798C5.2898,10.0005 5.2724,10.0158 5.2516,10.0158C5.2304,10.0158 5.2135,10.0005 5.2135,9.9798" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.2889,10.0964C5.2429,10.0964 5.2069,10.0574 5.2069,10.0144C5.2069,9.9734 5.2429,9.9384 5.2889,9.9384C5.3349,9.9384 5.3709,9.9734 5.3709,10.0144C5.3709,10.0574 5.3349,10.0964 5.2889,10.0964ZM5.2889,9.9634C5.2579,9.9634 5.2299,9.9864 5.2299,10.0144C5.2299,10.0474 5.2569,10.0734 5.2889,10.0734C5.3189,10.0734 5.3469,10.0484 5.3469,10.0144C5.3469,9.9874 5.3189,9.9634 5.2889,9.9634Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.2713,9.8784C5.2713,9.8582 5.2893,9.8435 5.3095,9.8435C5.3313,9.8435 5.3471,9.8582 5.3471,9.8784C5.3471,9.8991 5.3313,9.9133 5.3095,9.9133C5.2893,9.9138 5.2713,9.8991 5.2713,9.8784" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.3472,9.9938C5.3022,9.9938 5.2642,9.9548 5.2642,9.9138C5.2642,9.8728 5.3022,9.8358 5.3472,9.8358C5.3932,9.8358 5.4282,9.8728 5.4282,9.9138C5.4282,9.9548 5.3932,9.9938 5.3472,9.9938ZM5.3472,9.8618C5.3172,9.8618 5.2902,9.8848 5.2902,9.9148C5.2902,9.9478 5.3162,9.9718 5.3472,9.9718C5.3792,9.9718 5.4052,9.9488 5.4052,9.9148C5.4052,9.8848 5.3802,9.8618 5.3472,9.8618Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.3509,9.7944C5.3509,9.7742 5.3667,9.7595 5.388,9.7595C5.4082,9.7595 5.4256,9.7742 5.4256,9.7944C5.4256,9.8145 5.4082,9.8325 5.388,9.8325C5.3667,9.8325 5.3509,9.8145 5.3509,9.7944" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.4253,9.9069C5.3803,9.9069 5.3433,9.8759 5.3433,9.8289C5.3433,9.7879 5.3803,9.7529 5.4253,9.7529C5.4693,9.7529 5.5073,9.7879 5.5073,9.8289C5.5073,9.8759 5.4693,9.9069 5.4253,9.9069ZM5.4253,9.7779C5.3923,9.7779 5.3683,9.8009 5.3683,9.8289C5.3683,9.8599 5.3913,9.8839 5.4253,9.8839C5.4573,9.8839 5.4813,9.8609 5.4813,9.8289C5.4813,9.8019 5.4573,9.7779 5.4253,9.7779Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.4404,9.7251C5.4404,9.7049 5.4573,9.6902 5.4785,9.6902C5.4993,9.6902 5.5167,9.7049 5.5167,9.7251C5.5167,9.7447 5.4987,9.76 5.4785,9.76C5.4567,9.7605 5.4404,9.7447 5.4404,9.7251" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.5158,9.8405C5.4688,9.8405 5.4338,9.8015 5.4338,9.7605C5.4338,9.7195 5.4688,9.6825 5.5158,9.6825C5.5608,9.6825 5.5978,9.7195 5.5978,9.7605C5.5978,9.8015 5.5608,9.8405 5.5158,9.8405ZM5.5158,9.7075C5.4838,9.7075 5.4568,9.7305 5.4568,9.7605C5.4568,9.7935 5.4828,9.8175 5.5158,9.8175C5.5458,9.8175 5.5728,9.7945 5.5728,9.7605C5.5728,9.7315 5.5458,9.7075 5.5158,9.7075Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.5489,9.6684C5.5489,9.6476 5.5653,9.6329 5.5865,9.6329C5.6067,9.6329 5.6242,9.6476 5.6242,9.6684C5.6242,9.6885 5.6062,9.7049 5.5865,9.7049C5.5653,9.7049 5.5489,9.6885 5.5489,9.6684" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.6238,9.7775C5.5778,9.7775 5.5418,9.7465 5.5418,9.7025C5.5418,9.6605 5.5778,9.6275 5.6238,9.6275C5.6678,9.6275 5.7058,9.6605 5.7058,9.7025C5.7058,9.7465 5.6678,9.7775 5.6238,9.7775ZM5.6238,9.6525C5.5908,9.6525 5.5658,9.6755 5.5658,9.7025C5.5658,9.7305 5.5908,9.7545 5.6238,9.7545C5.6548,9.7545 5.6798,9.7315 5.6798,9.7025C5.6798,9.6755 5.6548,9.6525 5.6238,9.6525Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.6607,9.628C5.6607,9.6067 5.6765,9.5925 5.6984,9.5925C5.7185,9.5925 5.7365,9.6067 5.7365,9.628C5.7365,9.646 5.7185,9.664 5.6984,9.664C5.6765,9.6645 5.6607,9.6465 5.6607,9.628" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.7352,9.7424C5.6902,9.7424 5.6542,9.7094 5.6542,9.6644C5.6542,9.6204 5.6892,9.5844 5.7352,9.5844C5.7802,9.5844 5.8172,9.6204 5.8172,9.6644C5.8172,9.7094 5.7802,9.7424 5.7352,9.7424ZM5.7352,9.6104C5.7032,9.6104 5.6782,9.6354 5.6782,9.6654C5.6782,9.6954 5.7032,9.7184 5.7352,9.7184C5.7652,9.7184 5.7922,9.6954 5.7922,9.6654C5.7922,9.6354 5.7662,9.6104 5.7352,9.6104Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.7851,9.6056C5.7851,9.5855 5.8025,9.5685 5.8233,9.5685C5.844,9.5685 5.8615,9.5855 5.8615,9.6056C5.8615,9.6258 5.844,9.6405 5.8233,9.6405C5.8025,9.6405 5.7851,9.6258 5.7851,9.6056" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.8611,9.7167C5.8151,9.7167 5.7791,9.6817 5.7791,9.6407C5.7791,9.5957 5.8151,9.5647 5.8611,9.5647C5.9071,9.5647 5.9431,9.5957 5.9431,9.6407C5.9431,9.6807 5.9071,9.7167 5.8611,9.7167ZM5.8611,9.5877C5.8301,9.5877 5.8031,9.6107 5.8031,9.6407C5.8031,9.6657 5.8301,9.6917 5.8611,9.6917C5.8921,9.6917 5.9201,9.6667 5.9201,9.6407C5.9191,9.6107 5.8921,9.5877 5.8611,9.5877Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M5.9045,9.5996C5.9045,9.58 5.922,9.5647 5.9422,9.5647C5.9645,9.5647 5.9804,9.58 5.9804,9.5996C5.9804,9.6187 5.964,9.6345 5.9422,9.6345C5.922,9.6345 5.9045,9.6187 5.9045,9.5996" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M5.9795,9.712C5.9355,9.712 5.8975,9.677 5.8975,9.636C5.8975,9.595 5.9355,9.556 5.9795,9.556C6.0265,9.556 6.0615,9.595 6.0615,9.636C6.0615,9.677 6.0265,9.712 5.9795,9.712ZM5.9795,9.579C5.9495,9.579 5.9225,9.602 5.9225,9.636C5.9225,9.665 5.9495,9.689 5.9795,9.689C6.0125,9.689 6.0385,9.666 6.0385,9.636C6.0385,9.602 6.0125,9.579 5.9795,9.579Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.0218,9.6024C6.0218,9.5822 6.0382,9.5675 6.0595,9.5675C6.0796,9.5675 6.0971,9.5822 6.0971,9.6024C6.0971,9.6225 6.0796,9.6405 6.0595,9.6405C6.0382,9.6411 6.0218,9.6231 6.0218,9.6024" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.0963,9.7155C6.0503,9.7155 6.0153,9.6845 6.0153,9.6375C6.0153,9.5965 6.0503,9.5615 6.0963,9.5615C6.1403,9.5615 6.1783,9.5965 6.1783,9.6375C6.1783,9.6835 6.1413,9.7155 6.0963,9.7155ZM6.0963,9.5865C6.0633,9.5865 6.0383,9.6095 6.0383,9.6375C6.0383,9.6685 6.0633,9.6925 6.0963,9.6925C6.1273,9.6925 6.1533,9.6695 6.1533,9.6375C6.1533,9.6095 6.1273,9.5865 6.0963,9.5865Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.138,9.6024C6.138,9.5822 6.1555,9.5675 6.1756,9.5675C6.198,9.5675 6.2138,9.5822 6.2138,9.6024C6.2138,9.6225 6.198,9.6405 6.1756,9.6405C6.1555,9.6411 6.138,9.6231 6.138,9.6024" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.2129,9.7155C6.1689,9.7155 6.1309,9.6845 6.1309,9.6375C6.1309,9.5965 6.1689,9.5615 6.2129,9.5615C6.2589,9.5615 6.2949,9.5965 6.2949,9.6375C6.2949,9.6835 6.2589,9.7155 6.2129,9.7155ZM6.2129,9.5865C6.1839,9.5865 6.1569,9.6095 6.1569,9.6375C6.1569,9.6685 6.1839,9.6925 6.2129,9.6925C6.2459,9.6925 6.2709,9.6695 6.2709,9.6375C6.2709,9.6095 6.2459,9.5865 6.2129,9.5865Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.0796,9.7049C6.0796,9.6836 6.0971,9.6667 6.1178,9.6667C6.1385,9.6667 6.156,9.6836 6.156,9.7049C6.156,9.7218 6.1385,9.7393 6.1178,9.7393C6.0971,9.7393 6.0796,9.7218 6.0796,9.7049" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.1551,9.8191C6.1091,9.8191 6.0731,9.7841 6.0731,9.7431C6.0731,9.6961 6.1091,9.6591 6.1551,9.6591C6.2011,9.6591 6.2371,9.6961 6.2371,9.7431C6.2371,9.7841 6.2011,9.8191 6.1551,9.8191ZM6.1551,9.6841C6.1241,9.6841 6.0971,9.7091 6.0971,9.7431C6.0971,9.7691 6.1241,9.7951 6.1551,9.7951C6.1861,9.7951 6.2141,9.7701 6.2141,9.7431C6.2131,9.7101 6.1861,9.6841 6.1551,9.6841Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.0567,9.8124C6.0567,9.7944 6.0731,9.778 6.0944,9.778C6.1151,9.778 6.132,9.7938 6.132,9.8124C6.132,9.8325 6.1151,9.8495 6.0944,9.8495C6.0731,9.85 6.0567,9.8325 6.0567,9.8124" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.1311,9.9285C6.0871,9.9285 6.0491,9.8915 6.0491,9.8465C6.0491,9.8055 6.0871,9.7715 6.1311,9.7715C6.1751,9.7715 6.2131,9.8055 6.2131,9.8465C6.2131,9.8915 6.1751,9.9285 6.1311,9.9285ZM6.1311,9.7955C6.0991,9.7955 6.0751,9.8185 6.0751,9.8465C6.0751,9.8795 6.0981,9.9035 6.1311,9.9035C6.1631,9.9035 6.1871,9.8805 6.1871,9.8465C6.1881,9.8195 6.1631,9.7955 6.1311,9.7955Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.0513,9.9236C6.0513,9.9029 6.0693,9.8882 6.0895,9.8882C6.1118,9.8882 6.1276,9.9029 6.1276,9.9236C6.1276,9.9433 6.1113,9.9602 6.0895,9.9602C6.0687,9.9607 6.0513,9.9433 6.0513,9.9236" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.1267,10.0342C6.0827,10.0342 6.0447,10.0032 6.0447,9.9592C6.0447,9.9172 6.0827,9.8822 6.1267,9.8822C6.1737,9.8822 6.2087,9.9172 6.2087,9.9592C6.2087,10.0022 6.1727,10.0342 6.1267,10.0342ZM6.1267,9.9092C6.0967,9.9092 6.0697,9.9322 6.0697,9.9592C6.0697,9.9872 6.0967,10.0112 6.1267,10.0112C6.1597,10.0112 6.1857,9.9882 6.1857,9.9592C6.1847,9.9322 6.1587,9.9092 6.1267,9.9092Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.0856,10.0245C6.0856,10.0033 6.1031,9.9891 6.1238,9.9891C6.1451,9.9891 6.162,10.0033 6.162,10.0245C6.162,10.0436 6.1451,10.0605 6.1238,10.0605C6.1031,10.0605 6.0856,10.0436 6.0856,10.0245" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.1616,10.138C6.1156,10.138 6.0796,10.105 6.0796,10.06C6.0796,10.016 6.1156,9.982 6.1616,9.982C6.2086,9.982 6.2436,10.016 6.2436,10.06C6.2436,10.105 6.2076,10.138 6.1616,10.138ZM6.1616,10.006C6.1306,10.006 6.1036,10.03 6.1036,10.06C6.1036,10.09 6.1306,10.113 6.1616,10.113C6.1926,10.113 6.2206,10.09 6.2206,10.06C6.2206,10.03 6.1926,10.006 6.1616,10.006Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.15,10.1167C6.15,10.0971 6.168,10.0802 6.1876,10.0802C6.2095,10.0802 6.2258,10.0971 6.2258,10.1167C6.2258,10.1364 6.2095,10.1522 6.1876,10.1522C6.168,10.1522 6.15,10.1364 6.15,10.1167" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.2255,10.2267C6.1815,10.2267 6.1435,10.1937 6.1435,10.1517C6.1435,10.1077 6.1815,10.0747 6.2255,10.0747C6.2725,10.0747 6.3075,10.1077 6.3075,10.1517C6.3075,10.1937 6.2725,10.2267 6.2255,10.2267ZM6.2255,10.0997C6.1965,10.0997 6.1685,10.1227 6.1685,10.1517C6.1685,10.1777 6.1965,10.2017 6.2255,10.2017C6.2585,10.2017 6.2845,10.1787 6.2845,10.1517C6.2835,10.1237 6.2575,10.0997 6.2255,10.0997Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.2264,9.5336C6.2264,9.5135 6.2427,9.4993 6.2645,9.4993C6.2847,9.4993 6.3027,9.5129 6.3027,9.5336C6.3027,9.5544 6.2847,9.5685 6.2645,9.5685C6.2427,9.5685 6.2264,9.5544 6.2264,9.5336" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.3018,9.6491C6.2548,9.6491 6.2198,9.6101 6.2198,9.5691C6.2198,9.5281 6.2548,9.4911 6.3018,9.4911C6.3458,9.4911 6.3838,9.5281 6.3838,9.5691C6.3838,9.6101 6.3468,9.6491 6.3018,9.6491ZM6.3018,9.5161C6.2698,9.5161 6.2428,9.5391 6.2428,9.5691C6.2428,9.6021 6.2688,9.6261 6.3018,9.6261C6.3318,9.6261 6.3588,9.6031 6.3588,9.5691C6.3588,9.5391 6.3318,9.5161 6.3018,9.5161Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.33,9.4764C6.33,9.4556 6.348,9.4409 6.3676,9.4409C6.39,9.4409 6.4053,9.4556 6.4053,9.4764C6.4053,9.496 6.3895,9.5129 6.3676,9.5129C6.348,9.5129 6.33,9.496 6.33,9.4764" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.4049,9.5864C6.3609,9.5864 6.3229,9.5554 6.3229,9.5114C6.3229,9.4674 6.3609,9.4344 6.4049,9.4344C6.4509,9.4344 6.4869,9.4674 6.4869,9.5114C6.4869,9.5554 6.4509,9.5864 6.4049,9.5864ZM6.4049,9.4594C6.3749,9.4594 6.3489,9.4844 6.3489,9.5114C6.3489,9.5394 6.3749,9.5634 6.4049,9.5634C6.4379,9.5634 6.4629,9.5404 6.4629,9.5114C6.4619,9.4854 6.4379,9.4594 6.4049,9.4594Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.4435,9.4409C6.4435,9.424 6.4609,9.406 6.4816,9.406C6.5029,9.406 6.5198,9.424 6.5198,9.4409C6.5198,9.4622 6.5029,9.478 6.4816,9.478C6.4615,9.478 6.4435,9.4622 6.4435,9.4409" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.5195,9.557C6.4745,9.557 6.4375,9.52 6.4375,9.475C6.4375,9.432 6.4745,9.4 6.5195,9.4C6.5665,9.4 6.6015,9.432 6.6015,9.475C6.6015,9.52 6.5665,9.557 6.5195,9.557ZM6.5195,9.425C6.4895,9.425 6.4615,9.448 6.4615,9.475C6.4615,9.506 6.4885,9.532 6.5195,9.532C6.5515,9.532 6.5785,9.507 6.5785,9.475C6.5775,9.448 6.5515,9.425 6.5195,9.425Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.5629,9.4224C6.5629,9.4011 6.5804,9.3853 6.6005,9.3853C6.6229,9.3853 6.6387,9.4011 6.6387,9.4224C6.6387,9.4404 6.6224,9.4567 6.6005,9.4567C6.5804,9.4567 6.5629,9.4409 6.5629,9.4224" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.6378,9.5372C6.5938,9.5372 6.5558,9.5012 6.5558,9.4602C6.5558,9.4152 6.5938,9.3782 6.6378,9.3782C6.6848,9.3782 6.7198,9.4152 6.7198,9.4602C6.7198,9.5002 6.6848,9.5372 6.6378,9.5372ZM6.6378,9.4032C6.6078,9.4032 6.5818,9.4262 6.5818,9.4602C6.5818,9.4852 6.6078,9.5122 6.6378,9.5122C6.6708,9.5122 6.6968,9.4862 6.6968,9.4602C6.6968,9.4262 6.6708,9.4032 6.6378,9.4032Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.6802,9.4235C6.6802,9.4022 6.6965,9.388 6.7178,9.388C6.738,9.388 6.7555,9.4022 6.7555,9.4235C6.7555,9.4425 6.738,9.4595 6.7178,9.4595C6.6965,9.46 6.6802,9.4431 6.6802,9.4235" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.7551,9.5369C6.7101,9.5369 6.6731,9.5039 6.6731,9.4589C6.6731,9.4149 6.7091,9.3809 6.7551,9.3809C6.7991,9.3809 6.8371,9.4149 6.8371,9.4589C6.8361,9.5039 6.7991,9.5369 6.7551,9.5369ZM6.7551,9.4059C6.7221,9.4059 6.6981,9.4299 6.6981,9.4599C6.6981,9.4899 6.7221,9.5129 6.7551,9.5129C6.7861,9.5129 6.8111,9.4899 6.8111,9.4599C6.8111,9.4299 6.7861,9.4059 6.7551,9.4059Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.8013,9.4431C6.8013,9.424 6.8182,9.4087 6.8389,9.4087C6.8596,9.4087 6.8765,9.4235 6.8765,9.4431C6.8765,9.4638 6.8596,9.4791 6.8389,9.4791C6.8182,9.4791 6.8013,9.4638 6.8013,9.4431" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.8762,9.5596C6.8322,9.5596 6.7942,9.5206 6.7942,9.4776C6.7942,9.4366 6.8312,9.4016 6.8762,9.4016C6.9202,9.4016 6.9582,9.4366 6.9582,9.4776C6.9572,9.5196 6.9202,9.5596 6.8762,9.5596ZM6.8762,9.4266C6.8432,9.4266 6.8202,9.4496 6.8202,9.4776C6.8202,9.5106 6.8432,9.5366 6.8762,9.5366C6.9082,9.5366 6.9322,9.5136 6.9322,9.4776C6.9322,9.4496 6.9082,9.4266 6.8762,9.4266Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M6.9131,9.4824C6.9131,9.4622 6.9295,9.4475 6.9507,9.4475C6.9715,9.4475 6.9884,9.4622 6.9884,9.4824C6.9884,9.502 6.9715,9.5173 6.9507,9.5173C6.9295,9.5173 6.9131,9.502 6.9131,9.4824" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.988,9.5978C6.944,9.5978 6.906,9.5588 6.906,9.5178C6.906,9.4768 6.944,9.4398 6.988,9.4398C7.032,9.4398 7.07,9.4768 7.07,9.5178C7.07,9.5588 7.032,9.5978 6.988,9.5978ZM6.988,9.4648C6.955,9.4648 6.932,9.4878 6.932,9.5178C6.932,9.5508 6.955,9.5748 6.988,9.5748C7.019,9.5748 7.044,9.5518 7.044,9.5178C7.044,9.4878 7.019,9.4648 6.988,9.4648Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M5.9515,11.7804L5.9193,11.7804L5.9193,11.7504L5.8625,11.7504L5.8625,11.878L5.9193,11.878L5.9193,11.9642L5.7982,11.9642L5.7982,12.2211L5.862,12.2211L5.862,12.7327L5.7344,12.7327L5.7344,12.9945L6.7184,12.9945L6.7184,12.7327L6.5907,12.7327L6.5907,12.2211L6.6545,12.2211L6.6545,11.9642L6.5345,11.9642L6.5345,11.878L6.5907,11.878L6.5907,11.7504L6.5345,11.7504L6.5345,11.7804L6.5024,11.7804L6.5024,11.7504L6.4473,11.7504L6.4473,11.7804L6.4064,11.7804L6.4064,11.7504L6.3513,11.7504L6.3513,11.878L6.4064,11.878L6.4064,11.9642L6.2875,11.9642L6.2875,11.686L6.3513,11.686L6.3513,11.5573L6.2875,11.5573L6.2875,11.5884L6.2553,11.5884L6.2553,11.5573L6.1985,11.5573L6.1985,11.5884L6.1664,11.5884L6.1664,11.5573L6.102,11.5573L6.102,11.686L6.1664,11.686L6.1664,11.9642L6.0469,11.9642L6.0469,11.878L6.102,11.878L6.102,11.7504L6.0469,11.7504L6.0469,11.7804L6.0147,11.7804L6.0147,11.7504L5.9509,11.7504L5.9509,11.7804L5.9515,11.7804ZM5.7349,12.9945L6.7189,12.9945M5.7349,12.9307L6.7189,12.9307M5.7349,12.8669L6.7189,12.8669M5.7349,12.8031L6.7189,12.8031M5.7349,12.7327L6.7189,12.7327M5.8625,12.6749L6.5907,12.6749M5.8625,12.6111L6.5907,12.6111M5.8625,12.5407L6.5907,12.5407M5.8625,12.4769L6.5907,12.4769M5.8625,12.4131L6.5907,12.4131M5.8625,12.3493L6.5907,12.3493M5.8625,12.2849L6.5907,12.2849M5.7987,12.2211L6.6545,12.2211M5.7987,12.1562L6.6545,12.1562M5.7987,12.0924L6.6545,12.0924M5.7987,12.0285L6.6545,12.0285M5.9198,11.9647L6.5345,11.9647M6.1669,11.9004L6.2875,11.9004M6.1669,11.8365L6.2875,11.8365M6.1669,11.7727L6.2875,11.7727M6.1669,11.7089L6.2875,11.7089M6.1025,11.6265L6.3513,11.6265M5.9198,11.9004L6.0475,11.9004M5.8625,11.8185L6.1025,11.8185M5.8625,12.9945L5.8625,12.9307M5.8625,12.8669L5.8625,12.8031M5.7987,12.8669L5.7987,12.9307M5.9198,12.9307L5.9198,12.8669M5.9836,12.9945L5.9836,12.9307M5.9836,12.8669L5.9836,12.8031M5.9836,12.7327L5.9836,12.6755M5.9836,12.6111L5.9836,12.5407M5.9198,12.8031L5.9198,12.7327M5.7987,12.8031L5.7987,12.7327M6.0475,12.7327L6.0475,12.8031M6.1025,12.7327L6.1025,12.6755M5.9198,12.6111L5.9198,12.6749M6.0475,12.6111L6.0475,12.6749M6.1669,12.6111L6.1669,12.6749M6.1025,12.6111L6.1025,12.5407M6.1669,12.4769L6.1669,12.5407M6.1669,12.3493L6.1669,12.4131M6.1025,12.2849L6.1025,12.3487M6.1669,12.2211L6.1669,12.2849M6.0475,12.2211L6.0475,12.2849M5.9198,12.2211L5.9198,12.2849M5.8625,12.1562L5.8625,12.2211M5.9836,12.1562L5.9836,12.2211M6.1025,12.1562L6.1025,12.2211M6.1669,12.0924L6.1669,12.1562M6.0475,12.0924L6.0475,12.1562M5.9198,12.0924L5.9198,12.1562M5.8625,12.0285L5.8625,12.0924M6.1025,12.0285L6.1025,12.0924M5.9836,11.9004L5.9836,11.9642M6.5345,11.9004L6.4064,11.9004M6.5907,11.8185L6.3513,11.8185M6.5907,12.9945L6.5907,12.9307M6.5907,12.8669L6.5907,12.8031M6.6545,12.8669L6.6545,12.9307M6.5345,12.9307L6.5345,12.8669M6.4702,12.9945L6.4702,12.9307M6.4702,12.8669L6.4702,12.8031M6.4702,12.7327L6.4702,12.6755M6.4702,12.6111L6.4702,12.5407M6.5345,12.8031L6.5345,12.7327M6.6545,12.8031L6.6545,12.7327M6.4064,12.7327L6.4064,12.8031M6.3513,12.7327L6.3513,12.6755M6.5345,12.6111L6.5345,12.6749M6.4064,12.6111L6.4064,12.6749M6.2875,12.6111L6.2875,12.6749M6.3513,12.6111L6.3513,12.5407M6.2875,12.4769L6.2875,12.5407M6.2875,12.3493L6.2875,12.4131M6.3513,12.2849L6.3513,12.3487M6.2875,12.2211L6.2875,12.2849M6.4064,12.2211L6.4064,12.2849M6.5345,12.2211L6.5345,12.2849M6.5907,12.1562L6.5907,12.2211M6.4702,12.1562L6.4702,12.2211M6.3513,12.1562L6.3513,12.2211M6.2875,12.0924L6.2875,12.1562M6.4064,12.0924L6.4064,12.1562M6.5345,12.0924L6.5345,12.1562M6.5907,12.0285L6.5907,12.0924M6.3513,12.0285L6.3513,12.0924M6.4702,11.9004L6.4702,11.9642M6.2236,12.6111L6.2236,12.5407M6.2236,12.3493L6.2236,12.2855M6.2236,12.4769L6.2236,12.4131M6.2236,12.2211L6.2236,12.1562M6.2236,12.0924L6.2236,12.0285M6.2236,11.9004L6.2236,11.8365M6.2236,11.7727L6.2236,11.7089M5.9198,11.878L6.0475,11.878M6.1669,11.6865L6.2875,11.6865M6.4064,11.878L6.5345,11.878" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.7278,13.0033L5.7278,13.0033L5.7278,12.7245L5.8556,12.7245L5.8556,12.2276L5.7917,12.2276L5.7917,11.9565L5.9108,11.9565L5.9108,11.8824L5.8556,11.8824L5.8556,11.7405L5.9266,11.7405L5.9266,11.7727L5.943,11.7727L5.943,11.7405L6.0227,11.7405L6.0227,11.7727L6.0386,11.7727L6.0386,11.7405L6.1112,11.7405L6.1112,11.8824L6.055,11.8824L6.055,11.9565L6.1598,11.9565L6.1598,11.6909L6.0959,11.6909L6.0959,11.5491L6.1757,11.5491L6.1757,11.5813L6.192,11.5813L6.192,11.5491L6.263,11.5491L6.263,11.5813L6.2789,11.5813L6.2789,11.5491L6.3586,11.5491L6.3586,11.6909L6.2953,11.6909L6.2953,11.9565L6.3996,11.9565L6.3996,11.8824L6.3428,11.8824L6.3428,11.7405L6.4154,11.7405L6.4154,11.7727L6.4389,11.7727L6.4389,11.7405L6.5115,11.7405L6.5115,11.7727L6.5274,11.7727L6.5274,11.7405L6.5989,11.7405L6.5989,11.8824L6.5432,11.8824L6.5432,11.9565L6.6628,11.9565L6.6628,12.2276L6.5989,12.2276L6.5989,12.7245L6.7267,12.7245L6.7267,13.0033L6.7278,13.0033ZM6.5995,12.9885L6.712,12.9885L6.712,12.9395L6.5995,12.9395L6.5995,12.9885ZM6.4799,12.9885L6.5831,12.9885L6.5831,12.9395L6.4799,12.9395L6.4799,12.9885ZM5.9911,12.9885L6.464,12.9885L6.464,12.9395L5.9911,12.9395L5.9911,12.9885ZM5.872,12.9885L5.9747,12.9885L5.9747,12.9395L5.872,12.9395L5.872,12.9885ZM5.7442,12.9885L5.8562,12.9885L5.8562,12.9395L5.7442,12.9395L5.7442,12.9885ZM6.5443,12.9242L6.6475,12.9242L6.6475,12.8751L6.5443,12.8751L6.5443,12.9242ZM5.9266,12.9242L6.5279,12.9242L6.5279,12.8751L5.9266,12.8751L5.9266,12.9242L5.9266,12.9242ZM5.8081,12.9242L5.9108,12.9242L5.9108,12.8751L5.8081,12.8751L5.8081,12.9242ZM6.5995,12.8604L6.712,12.8604L6.712,12.8113L6.5995,12.8113L6.5995,12.8604ZM6.4799,12.8604L6.5831,12.8604L6.5831,12.8113L6.4799,12.8113L6.4799,12.8604ZM5.9911,12.8604L6.464,12.8604L6.464,12.8113L5.9911,12.8113L5.9911,12.8604ZM5.872,12.8604L5.9747,12.8604L5.9747,12.8113L5.872,12.8113L5.872,12.8604ZM5.7442,12.8604L5.8562,12.8604L5.8562,12.8113L5.7442,12.8113L5.7442,12.8604ZM6.6634,12.7965L6.7114,12.7965L6.7114,12.7393L6.6634,12.7393L6.6634,12.7965ZM6.5443,12.7965L6.6475,12.7965L6.6475,12.7393L6.5443,12.7393L6.5443,12.7965ZM6.416,12.7965L6.5279,12.7965L6.5279,12.7393L6.416,12.7393L6.416,12.7965ZM6.055,12.7965L6.3996,12.7965L6.3996,12.7393L6.055,12.7393L6.055,12.7965ZM5.9266,12.7965L6.0391,12.7965L6.0391,12.7393L5.9266,12.7393L5.9266,12.7965ZM5.8081,12.7965L5.9108,12.7965L5.9108,12.7393L5.8081,12.7393L5.8081,12.7965ZM5.7442,12.7965L5.7917,12.7965L5.7917,12.7393L5.7442,12.7393L5.7442,12.7965ZM6.4799,12.7245L6.5831,12.7245L6.5831,12.6836L6.4799,12.6836L6.4799,12.7245ZM6.3592,12.7245L6.4635,12.7245L6.4635,12.6836L6.3592,12.6836L6.3592,12.7245ZM6.1118,12.7245L6.3433,12.7245L6.3433,12.6836L6.1118,12.6836L6.1118,12.7245ZM5.9911,12.7245L6.0959,12.7245L6.0959,12.6836L5.9911,12.6836L5.9911,12.7245ZM5.872,12.7245L5.9747,12.7245L5.9747,12.6836L5.872,12.6836L5.872,12.7245ZM6.416,12.6689L6.5279,12.6689L6.5279,12.6198L6.416,12.6198L6.416,12.6689ZM6.2953,12.6689L6.3996,12.6689L6.3996,12.6198L6.2953,12.6198L6.2953,12.6689ZM6.1757,12.6689L6.2789,12.6689L6.2789,12.6198L6.1757,12.6198L6.1757,12.6689ZM6.055,12.6689L6.1598,12.6689L6.1598,12.6198L6.055,12.6198L6.055,12.6689ZM5.9266,12.6689L6.0391,12.6689L6.0391,12.6198L5.9266,12.6198L5.9266,12.6689ZM6.4799,12.6045L6.5831,12.6045L6.5831,12.5473L6.4799,12.5473L6.4799,12.6045ZM6.3592,12.6045L6.4635,12.6045L6.4635,12.5473L6.3592,12.5473L6.3592,12.6045ZM6.2308,12.6045L6.3433,12.6045L6.3433,12.5473L6.2308,12.5473L6.2308,12.6045ZM6.1118,12.6045L6.215,12.6045L6.215,12.5473L6.1118,12.5473L6.1118,12.6045ZM5.9911,12.6045L6.0959,12.6045L6.0959,12.5473L5.9911,12.5473L5.9911,12.6045ZM5.872,12.6045L5.9747,12.6045L5.9747,12.5473L5.872,12.5473L5.872,12.6045ZM6.2953,12.532L6.5836,12.532L6.5836,12.4835L6.2953,12.4835L6.2953,12.532ZM6.1757,12.532L6.2789,12.532L6.2789,12.4835L6.1757,12.4835L6.1757,12.532ZM5.872,12.532L6.1598,12.532L6.1598,12.4835L5.872,12.4835L5.872,12.532ZM6.2308,12.4676L6.5836,12.4676L6.5836,12.4191L6.2308,12.4191L6.2308,12.4676ZM5.872,12.4676L6.215,12.4676L6.215,12.4191L5.872,12.4191L5.872,12.4676ZM6.2953,12.4038L6.5836,12.4038L6.5836,12.3553L6.2953,12.3553L6.2953,12.4038ZM6.1757,12.4038L6.2789,12.4038L6.2789,12.3553L6.1757,12.3553L6.1757,12.4038ZM5.872,12.4038L6.1598,12.4038L6.1598,12.3553L5.872,12.3553L5.872,12.4038ZM6.3592,12.34L6.5836,12.34L6.5836,12.2915L6.3592,12.2915L6.3592,12.34ZM6.2308,12.34L6.3433,12.34L6.3433,12.2915L6.2308,12.2915L6.2308,12.34ZM6.1118,12.34L6.215,12.34L6.215,12.2915L6.1118,12.2915L6.1118,12.34ZM5.872,12.34L6.0959,12.34L6.0959,12.2915L5.872,12.2915L5.872,12.34ZM6.416,12.2762L6.5279,12.2762L6.5279,12.2276L6.416,12.2276L6.416,12.2762ZM6.2953,12.2762L6.3996,12.2762L6.3996,12.2276L6.2953,12.2276L6.2953,12.2762ZM6.1757,12.2762L6.2789,12.2762L6.2789,12.2276L6.1757,12.2276L6.1757,12.2762ZM6.055,12.2762L6.1598,12.2762L6.1598,12.2276L6.055,12.2276L6.055,12.2762ZM5.9266,12.2762L6.0391,12.2762L6.0391,12.2276L5.9266,12.2276L5.9266,12.2762ZM6.4799,12.2124L6.5831,12.2124L6.5831,12.1638L6.4799,12.1638L6.4799,12.2124ZM6.3592,12.2124L6.4635,12.2124L6.4635,12.1638L6.3592,12.1638L6.3592,12.2124ZM6.2308,12.2124L6.3433,12.2124L6.3433,12.1638L6.2308,12.1638L6.2308,12.2124ZM6.1118,12.2124L6.215,12.2124L6.215,12.1638L6.1118,12.1638L6.1118,12.2124ZM5.9911,12.2124L6.0959,12.2124L6.0959,12.1638L5.9911,12.1638L5.9911,12.2124ZM5.872,12.2124L5.9747,12.2124L5.9747,12.1638L5.872,12.1638L5.872,12.2124ZM6.5443,12.148L6.6475,12.148L6.6475,12.1L6.5443,12.1L6.5443,12.148ZM6.416,12.148L6.5279,12.148L6.5279,12.1L6.416,12.1L6.416,12.148ZM6.2953,12.148L6.3996,12.148L6.3996,12.1L6.2953,12.1L6.2953,12.148ZM6.1757,12.148L6.2789,12.148L6.2789,12.1L6.1757,12.1L6.1757,12.148ZM6.055,12.148L6.1598,12.148L6.1598,12.1L6.055,12.1L6.055,12.148ZM5.9266,12.148L6.0391,12.148L6.0391,12.1L5.9266,12.1L5.9266,12.148ZM5.8081,12.148L5.9108,12.148L5.9108,12.1L5.8081,12.1L5.8081,12.148ZM6.3592,12.0842L6.5836,12.0842L6.5836,12.0356L6.3592,12.0356L6.3592,12.0842ZM6.2308,12.0842L6.3433,12.0842L6.3433,12.0356L6.2308,12.0356L6.2308,12.0842ZM6.1118,12.0842L6.215,12.0842L6.215,12.0356L6.1118,12.0356L6.1118,12.0842ZM5.872,12.0842L6.0959,12.0842L6.0959,12.0356L5.872,12.0356L5.872,12.0842ZM5.8081,12.0204L6.6475,12.0204L6.6475,11.9718L5.8081,11.9718L5.8081,12.0204ZM6.1757,11.9565L6.2789,11.9565L6.2789,11.908L6.1757,11.908L6.1757,11.9565ZM6.416,11.8927L6.5279,11.8927L6.5279,11.8824L6.416,11.8824L6.416,11.8927ZM5.9266,11.8927L6.0391,11.8927L6.0391,11.8824L5.9266,11.8824L5.9266,11.8927ZM6.5356,11.8687L6.5836,11.8687L6.5836,11.8289L6.3592,11.8289L6.3592,11.8687L6.5356,11.8687ZM6.0479,11.8687L6.0959,11.8687L6.0959,11.8289L5.872,11.8289L5.872,11.8687L6.0479,11.8687ZM6.1757,11.8289L6.2789,11.8289L6.2789,11.7804L6.1757,11.7804L6.1757,11.8289ZM6.3592,11.8142L6.5836,11.8142L6.5836,11.7547L6.5443,11.7547L6.5443,11.7891L6.4963,11.7891L6.4963,11.7547L6.4558,11.7547L6.4558,11.7891L6.4001,11.7891L6.4001,11.7547L6.3597,11.7547L6.3597,11.8142L6.3592,11.8142ZM5.872,11.8142L6.0959,11.8142L6.0959,11.7547L6.055,11.7547L6.055,11.7891L6.0069,11.7891L6.0069,11.7547L5.9588,11.7547L5.9588,11.7891L5.9113,11.7891L5.9113,11.7547L5.8725,11.7547L5.8725,11.8142L5.872,11.8142ZM6.1757,11.7007L6.2789,11.7007L6.2789,11.6909L6.1757,11.6909L6.1757,11.7007ZM6.2882,11.6767L6.3433,11.6767L6.3433,11.6369L6.1118,11.6369L6.1118,11.6767L6.2882,11.6767ZM6.1118,11.6227L6.3433,11.6227L6.3433,11.5633L6.2953,11.5633L6.2953,11.5976L6.2472,11.5976L6.2472,11.5633L6.2079,11.5633L6.2079,11.5976L6.1604,11.5976L6.1604,11.5633L6.1123,11.5633L6.1123,11.6227L6.1118,11.6227Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.3905,12.9945C6.3905,12.916 6.3905,12.8604 6.3905,12.8271C6.3905,12.796 6.3747,12.6995 6.2236,12.6995C6.0796,12.6995 6.0638,12.7965 6.0638,12.8271C6.0638,12.8604 6.0638,12.916 6.0638,12.9945L6.3905,12.9945Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.6855,13.2624L6.0545,13.2624L6.0545,12.9404C6.0545,12.8974 6.0715,12.6924 6.3645,12.6924C6.6695,12.6924 6.6865,12.8974 6.6865,12.9404L6.6865,13.2624L6.6855,13.2624ZM6.0835,13.2354L6.6565,13.2354L6.6565,12.9404C6.6565,12.9054 6.6415,12.7234 6.3635,12.7234C6.0975,12.7234 6.0835,12.9054 6.0835,12.9404L6.0835,13.2354L6.0835,13.2354Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.1184,12.8369L6.0387,12.8271C6.0387,12.796 6.0475,12.7475 6.0709,12.7322L6.1435,12.7884C6.1347,12.7965 6.1184,12.82 6.1184,12.8369Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.2076,12.9473L6.0316,12.9313L6.0316,12.9153C6.0316,12.8473 6.0486,12.7593 6.0956,12.7273L6.1036,12.7213L6.2576,12.8413L6.2456,12.8523C6.2296,12.8673 6.2066,12.9093 6.2066,12.9323L6.2066,12.9473L6.2076,12.9473ZM6.0606,12.9043L6.1776,12.9163C6.1836,12.8923 6.2006,12.8633 6.2136,12.8463L6.1036,12.7583C6.0766,12.7873 6.0606,12.8473 6.0606,12.9043Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.3349,12.8369L6.4151,12.8271C6.4151,12.796 6.4064,12.7475 6.3829,12.7322L6.3104,12.7884C6.3191,12.7965 6.3349,12.82 6.3349,12.8369Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.3499,12.9468L6.3499,12.9328C6.3499,12.9098 6.3249,12.8678 6.3109,12.8528L6.2989,12.8418L6.4529,12.7218L6.4589,12.7278C6.5079,12.7588 6.5239,12.8468 6.5239,12.9158L6.5239,12.9318L6.3499,12.9468ZM6.3419,12.8448C6.3549,12.8628 6.3719,12.8908 6.3769,12.9148L6.4959,12.9028C6.4939,12.8458 6.4809,12.7858 6.4539,12.7568L6.3419,12.8448Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.2553,12.7562L6.2945,12.6836C6.2787,12.6749 6.2465,12.6689 6.2236,12.6689C6.2073,12.6689 6.1756,12.6755 6.1598,12.6836L6.1991,12.7562C6.2149,12.7562 6.2389,12.7562 6.2553,12.7562Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.3518,12.8496L6.2328,12.8496L6.1478,12.6996L6.1628,12.6876C6.1928,12.6776 6.2538,12.6596 6.2868,12.6596C6.3338,12.6596 6.3928,12.6786 6.4238,12.6876L6.4388,12.6996L6.3518,12.8496ZM6.2518,12.8206L6.3358,12.8206L6.3978,12.7116C6.3688,12.7016 6.3218,12.6886 6.2868,12.6886C6.2638,12.6886 6.2178,12.7026 6.1888,12.7116L6.2518,12.8206Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.1025,12.556C6.1025,12.556 6.1025,12.4284 6.1025,12.3804C6.1025,12.3313 6.0704,12.292 6.0153,12.292C5.9585,12.292 5.9264,12.3313 5.9264,12.3804C5.9264,12.4284 5.9264,12.556 5.9264,12.556L6.1025,12.556Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.2713,12.7969L5.9193,12.7969L5.9193,12.4589C5.9193,12.3569 5.9893,12.2849 6.0953,12.2849C6.1983,12.2849 6.2713,12.3569 6.2713,12.4589L6.2713,12.7969ZM5.9493,12.7659L6.2423,12.7659L6.2423,12.4589C6.2423,12.3859 6.1953,12.3129 6.0953,12.3129C5.9933,12.3129 5.9493,12.3859 5.9493,12.4589L5.9493,12.7659L5.9493,12.7659Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.3513,12.556C6.3513,12.556 6.3513,12.4284 6.3513,12.3804C6.3513,12.3313 6.3835,12.292 6.4385,12.292C6.4953,12.292 6.5269,12.3313 6.5269,12.3804C6.5269,12.4284 6.5269,12.556 6.5269,12.556L6.3513,12.556Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.694,12.7969L6.342,12.7969L6.342,12.4589C6.342,12.3569 6.415,12.2849 6.518,12.2849C6.622,12.2849 6.694,12.3569 6.694,12.4589L6.694,12.7969ZM6.372,12.7659L6.665,12.7659L6.665,12.4589C6.665,12.3859 6.621,12.3129 6.518,12.3129C6.417,12.3129 6.372,12.3859 6.372,12.4589L6.372,12.7659L6.372,12.7659Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.2875,12.1245l0.0158,-0.1598l-0.1522,0l0.0087,0.1598z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.4195,12.2815L6.1585,12.2815L6.1435,11.9565L6.4525,11.9565L6.4195,12.2815ZM6.1845,12.2485L6.3935,12.2485L6.4185,11.9845L6.1725,11.9845L6.1845,12.2485Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.4064,12.1245l-0.0158,-0.1598l0.1598,0l-0.0158,0.1598z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.6758,12.2815L6.4128,12.2815L6.3818,11.9565L6.7058,11.9565L6.6758,12.2815ZM6.4408,12.2485L6.6478,12.2485L6.6758,11.9845L6.4128,11.9845L6.4408,12.2485Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.0475,12.1245l0.0071,-0.1598l-0.1505,0l0.0158,0.1598z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M6.1872,12.2815L5.9272,12.2815L5.8942,11.9565L6.2052,11.9565L6.1872,12.2815ZM5.9522,12.2485L6.1602,12.2485L6.1752,11.9845L5.9272,11.9845L5.9522,12.2485Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#0039F0" + android:fillType="nonZero" + android:pathData="M6.633,13.3078C6.633,13.2149 6.633,13.1339 6.633,13.1005C6.633,13.064 6.6051,12.9599 6.4361,12.9599C6.2795,12.9599 6.2516,13.064 6.2516,13.1005C6.2516,13.1339 6.2516,13.2149 6.2516,13.3078L6.633,13.3078ZM6.1959,12.647C6.1959,12.647 6.1959,12.4826 6.1959,12.427C6.1959,12.3682 6.1556,12.3078 6.071,12.3078C5.9875,12.3078 5.9433,12.3682 5.9433,12.427C5.9433,12.4826 5.9433,12.647 5.9433,12.647L6.1959,12.647ZM6.6897,12.647C6.6897,12.647 6.6897,12.4826 6.6897,12.427C6.6897,12.3682 6.731,12.3078 6.8155,12.3078C6.9,12.3078 6.9433,12.3682 6.9433,12.427C6.9433,12.4826 6.9433,12.647 6.9433,12.647L6.6897,12.647Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#AD1519" + android:fillType="nonZero" + android:pathData="M6.5335,13.2536C6.5335,12.9051 6.786,12.6215 7.0958,12.6215C7.4062,12.6215 7.6582,12.9056 7.6582,13.2536C7.6582,13.6044 7.4062,13.8869 7.0958,13.8869C6.786,13.8869 6.5335,13.6038 6.5335,13.2536" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.0958,13.8978C6.7795,13.8978 6.5231,13.6082 6.5231,13.2531C6.5231,12.9007 6.7795,12.6105 7.0958,12.6105C7.4127,12.6105 7.6685,12.9002 7.6685,13.2531C7.6685,13.6082 7.4122,13.8978 7.0958,13.8978ZM7.0958,12.6324C6.7925,12.6324 6.5438,12.9116 6.5438,13.2536C6.5438,13.5956 6.7925,13.8771 7.0958,13.8771C7.3996,13.8771 7.6484,13.5956 7.6484,13.2536C7.6484,12.9116 7.3996,12.6324 7.0958,12.6324Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#005BBF" + android:fillType="nonZero" + android:pathData="M6.6998,13.2515C6.6998,12.9945 6.8782,12.7889 7.0958,12.7889C7.3145,12.7889 7.4924,12.9945 7.4924,13.2515C7.4924,13.5095 7.3151,13.7178 7.0958,13.7178C6.8776,13.7178 6.6998,13.5095 6.6998,13.2515" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1897,13.7775C6.9143,13.7775 6.69,13.553 6.69,13.2763C6.69,13.0013 6.9136,12.7775 7.1897,12.7775C7.4657,12.7775 7.69,13.0019 7.69,13.2763C7.6893,13.553 7.465,13.7775 7.1897,13.7775ZM7.1897,12.7998C6.9291,12.7998 6.7162,13.0151 6.7162,13.2763C6.7162,13.5415 6.9291,13.7551 7.1897,13.7551C7.4516,13.7551 7.6645,13.5415 7.6645,13.2763C7.6645,13.0151 7.4516,12.7998 7.1897,12.7998Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.9093,12.9329C6.9093,12.9329 6.8629,12.9842 6.8629,13.0333C6.8629,13.0802 6.882,13.1211 6.882,13.1211C6.8755,13.1015 6.8564,13.0873 6.834,13.0873C6.8056,13.0873 6.7822,13.1096 6.7822,13.1353C6.7822,13.144 6.7865,13.1565 6.7898,13.1631L6.8073,13.198C6.8122,13.1855 6.8258,13.1784 6.8405,13.1784C6.8618,13.1784 6.8787,13.1947 6.8787,13.2122C6.8787,13.2165 6.8782,13.2209 6.8771,13.2225L6.8345,13.2225L6.8345,13.2591L6.8727,13.2591L6.8444,13.3136L6.8825,13.2995L6.9098,13.3311L6.9393,13.2995L6.9753,13.3136L6.948,13.2591L6.9851,13.2591L6.9851,13.2225L6.9431,13.2225C6.9431,13.2209 6.9431,13.2165 6.9431,13.2122C6.9431,13.1953 6.9595,13.1784 6.9785,13.1784C6.9938,13.1784 7.0069,13.1855 7.0129,13.198L7.0293,13.1631C7.0331,13.1565 7.0385,13.144 7.0385,13.1353C7.0385,13.1096 7.0156,13.0873 6.9867,13.0873C6.9638,13.0873 6.9447,13.1009 6.9371,13.1211C6.9371,13.1211 6.9573,13.0802 6.9573,13.0333C6.9573,12.9842 6.9093,12.9329 6.9093,12.9329" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.0206,13.6769L7.0206,13.6769C7.0176,13.6769 7.0146,13.6769 7.0116,13.6769L6.9656,13.6219L6.9056,13.6459C6.9006,13.6489 6.8956,13.6469 6.8936,13.6409C6.8896,13.6369 6.8886,13.6349 6.8916,13.6289L6.9346,13.5429L6.8816,13.5429C6.8756,13.5429 6.8716,13.5399 6.8716,13.5349L6.8716,13.4679C6.8716,13.4649 6.8756,13.4569 6.8816,13.4569L6.9516,13.4569C6.9516,13.4529 6.9516,13.4509 6.9516,13.4489C6.9516,13.4229 6.9256,13.3969 6.8926,13.3969C6.8696,13.3969 6.8496,13.4079 6.8406,13.4249C6.8406,13.4289 6.8356,13.4309 6.8316,13.4329C6.8286,13.4329 6.8226,13.4289 6.8226,13.4249L6.7916,13.3659C6.7866,13.3539 6.7756,13.3289 6.7756,13.3069C6.7756,13.2519 6.8226,13.2099 6.8806,13.2099C6.9006,13.2099 6.9226,13.2129 6.9396,13.2289C6.9296,13.1959 6.9226,13.1589 6.9226,13.1199C6.9226,13.0339 6.9986,12.9479 7.0096,12.9319C7.0136,12.9239 7.0226,12.9239 7.0276,12.9299C7.0376,12.9419 7.1176,13.0319 7.1176,13.1189C7.1176,13.1579 7.1096,13.1949 7.1036,13.2279C7.1196,13.2119 7.1386,13.2089 7.1616,13.2089C7.2196,13.2089 7.2666,13.2509 7.2666,13.3059C7.2666,13.3269 7.2556,13.3509 7.2506,13.3649L7.2196,13.4239C7.2166,13.4279 7.2146,13.4319 7.2096,13.4319C7.2046,13.4329 7.2016,13.4279 7.1986,13.4239C7.1926,13.4059 7.1716,13.3959 7.1456,13.3959C7.1156,13.3959 7.0906,13.4209 7.0906,13.4479C7.0906,13.4499 7.0906,13.4519 7.0906,13.4559L7.1576,13.4559C7.1636,13.4559 7.1686,13.4639 7.1686,13.4669L7.1686,13.5339C7.1686,13.5389 7.1636,13.5419 7.1576,13.5419L7.1076,13.5419L7.1506,13.6279C7.1506,13.6339 7.1506,13.6359 7.1496,13.6399C7.1456,13.6459 7.1406,13.6479 7.1376,13.6449L7.0756,13.6209L7.0286,13.6759C7.0266,13.6769 7.0226,13.6769 7.0206,13.6769ZM6.9706,13.5989C6.9716,13.5989 6.9756,13.6009 6.9766,13.6049L7.0216,13.6539L7.0656,13.6049C7.0696,13.5989 7.0746,13.5969 7.0776,13.6009L7.1196,13.6149L7.0816,13.5399C7.0796,13.5369 7.0806,13.5349 7.0816,13.5289C7.0826,13.5249 7.0876,13.5209 7.0906,13.5209L7.1486,13.5209L7.1486,13.4779L7.0816,13.4779C7.0766,13.4779 7.0736,13.4739 7.0706,13.4719C7.0696,13.4659 7.0696,13.4579 7.0696,13.4509C7.0696,13.4119 7.1046,13.3789 7.1466,13.3789C7.1736,13.3789 7.1936,13.3869 7.2096,13.4039L7.2306,13.3569C7.2386,13.3469 7.2446,13.3259 7.2446,13.3099C7.2446,13.2689 7.2076,13.2319 7.1616,13.2319C7.1276,13.2319 7.0986,13.2529 7.0866,13.2789C7.0826,13.2849 7.0806,13.2869 7.0806,13.2869C7.0796,13.2929 7.0726,13.2949 7.0676,13.2909C7.0636,13.2889 7.0586,13.2849 7.0616,13.2789C7.0626,13.2769 7.0626,13.2709 7.0656,13.2649C7.0746,13.2449 7.0966,13.1899 7.0966,13.1219C7.0966,13.0519 7.0396,12.9809 7.0196,12.9559C6.9986,12.9809 6.9446,13.0519 6.9446,13.1219C6.9446,13.1869 6.9656,13.2449 6.9746,13.2669C6.9756,13.2709 6.9786,13.2769 6.9806,13.2789C6.9806,13.2849 6.9796,13.2889 6.9746,13.2909C6.9696,13.2949 6.9626,13.2929 6.9596,13.2869C6.9596,13.2869 6.9576,13.2849 6.9556,13.2789C6.9396,13.2519 6.9116,13.2319 6.8806,13.2319C6.8336,13.2319 6.7956,13.2689 6.7956,13.3099C6.7956,13.3259 6.8036,13.3449 6.8106,13.3569L6.8336,13.4039C6.8456,13.3859 6.8686,13.3789 6.8926,13.3789C6.9376,13.3789 6.9736,13.4119 6.9736,13.4509C6.9736,13.4609 6.9726,13.4669 6.9696,13.4719C6.9696,13.4739 6.9636,13.4779 6.9596,13.4779L6.8936,13.4779L6.8936,13.5209L6.9526,13.5209C6.9566,13.5209 6.9586,13.5249 6.9616,13.5289C6.9636,13.5349 6.9636,13.5369 6.9626,13.5399L6.9236,13.6149L6.9646,13.6009C6.9656,13.5989 6.9686,13.5989 6.9706,13.5989Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M6.834,13.2591l0.1505,0l0,-0.0365l-0.1505,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.1255,13.302L6.8285,13.302L6.8285,13.216L7.1255,13.216L7.1255,13.302ZM6.8495,13.279L7.1045,13.279L7.1045,13.236L6.8495,13.236L6.8495,13.279Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.2775,12.9329C7.2775,12.9329 7.23,12.9842 7.23,13.0333C7.23,13.0802 7.2491,13.1211 7.2491,13.1211C7.2425,13.1015 7.2235,13.0873 7.2016,13.0873C7.1727,13.0873 7.1498,13.1096 7.1498,13.1353C7.1498,13.144 7.1536,13.1565 7.1575,13.1631L7.1749,13.198C7.1798,13.1855 7.1935,13.1784 7.2082,13.1784C7.2295,13.1784 7.2464,13.1947 7.2464,13.2122C7.2464,13.2165 7.2458,13.2209 7.2447,13.2225L7.2022,13.2225L7.2022,13.2591L7.2404,13.2591L7.212,13.3136L7.2496,13.2995L7.278,13.3311L7.3075,13.2995L7.3435,13.3136L7.3162,13.2591L7.3533,13.2591L7.3533,13.2225L7.3113,13.2225C7.3113,13.2209 7.3113,13.2165 7.3113,13.2122C7.3113,13.1953 7.3271,13.1784 7.3473,13.1784C7.3625,13.1784 7.3756,13.1855 7.3816,13.198L7.398,13.1631C7.4018,13.1565 7.4073,13.144 7.4073,13.1353C7.4073,13.1096 7.3844,13.0873 7.3555,13.0873C7.3331,13.0873 7.314,13.1009 7.3064,13.1211C7.3064,13.1211 7.3265,13.0802 7.3265,13.0333C7.3249,12.9842 7.2769,12.9329 7.2775,12.9329" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.3893,13.6769C7.3853,13.6769 7.3833,13.6769 7.3793,13.6769L7.3333,13.6219L7.2733,13.6459C7.2683,13.6489 7.2633,13.6469 7.2613,13.6409C7.2573,13.6369 7.2563,13.6349 7.2593,13.6289L7.3013,13.5429L7.2493,13.5429C7.2433,13.5429 7.2393,13.5399 7.2393,13.5349L7.2393,13.4679C7.2393,13.4649 7.2433,13.4569 7.2493,13.4569L7.3193,13.4569C7.3193,13.4529 7.3193,13.4509 7.3193,13.4489C7.3193,13.4229 7.2933,13.3969 7.2603,13.3969C7.2373,13.3969 7.2183,13.4079 7.2073,13.4249C7.2073,13.4289 7.2013,13.4349 7.1993,13.4329C7.1953,13.4329 7.1903,13.4289 7.1903,13.4249L7.1593,13.3659C7.1533,13.3539 7.1433,13.3289 7.1433,13.3069C7.1433,13.2519 7.1903,13.2099 7.2483,13.2099C7.2683,13.2099 7.2893,13.2129 7.3073,13.2289C7.2973,13.1959 7.2893,13.1589 7.2893,13.1199C7.2893,13.0339 7.3663,12.9459 7.3773,12.9319C7.3823,12.9239 7.3913,12.9239 7.3943,12.9299C7.4063,12.9419 7.4853,13.0319 7.4853,13.1189C7.4853,13.1579 7.4763,13.1949 7.4713,13.2279C7.4873,13.2119 7.5063,13.2089 7.5283,13.2089C7.5873,13.2089 7.6353,13.2509 7.6353,13.3059C7.6353,13.3269 7.6233,13.3509 7.6173,13.3649L7.5873,13.4239C7.5843,13.4279 7.5803,13.4319 7.5773,13.4319C7.5723,13.4319 7.5693,13.4279 7.5663,13.4239C7.5593,13.4059 7.5393,13.3959 7.5143,13.3959C7.4833,13.3959 7.4583,13.4209 7.4583,13.4479C7.4583,13.4499 7.4583,13.4519 7.4583,13.4559L7.5253,13.4559C7.5313,13.4559 7.5353,13.4639 7.5353,13.4669L7.5353,13.5339C7.5353,13.5389 7.5313,13.5419 7.5253,13.5419L7.4743,13.5419L7.5183,13.6279C7.5193,13.6339 7.5183,13.6359 7.5173,13.6399C7.5123,13.6459 7.5083,13.6479 7.5053,13.6449L7.4423,13.6209L7.3953,13.6759C7.3953,13.6769 7.3903,13.6769 7.3893,13.6769ZM7.3373,13.5989C7.3393,13.5989 7.3433,13.6009 7.3433,13.6049L7.3883,13.6539L7.4323,13.6049C7.4363,13.5989 7.4413,13.5969 7.4443,13.6009L7.4863,13.6149L7.4483,13.5399C7.4463,13.5369 7.4473,13.5349 7.4483,13.5289C7.4493,13.5249 7.4533,13.5209 7.4573,13.5209L7.5153,13.5209L7.5153,13.4779L7.4483,13.4779C7.4433,13.4779 7.4403,13.4739 7.4383,13.4719C7.4373,13.4659 7.4373,13.4599 7.4373,13.4509C7.4373,13.4119 7.4723,13.3789 7.5153,13.3789C7.5413,13.3789 7.5623,13.3869 7.5783,13.4039L7.5993,13.3569C7.6063,13.3469 7.6133,13.3259 7.6133,13.3099C7.6133,13.2689 7.5763,13.2319 7.5303,13.2319C7.4973,13.2319 7.4673,13.2529 7.4553,13.2789C7.4523,13.2849 7.4503,13.2869 7.4503,13.2869C7.4493,13.2929 7.4423,13.2949 7.4373,13.2929C7.4323,13.2889 7.4283,13.2849 7.4323,13.2789C7.4323,13.2769 7.4333,13.2709 7.4363,13.2649C7.4433,13.2449 7.4673,13.1879 7.4673,13.1219C7.4673,13.0519 7.4093,12.9809 7.3903,12.9559C7.3683,12.9809 7.3153,13.0519 7.3153,13.1219C7.3153,13.1869 7.3363,13.2449 7.3453,13.2669C7.3463,13.2709 7.3493,13.2769 7.3503,13.2789C7.3503,13.2849 7.3503,13.2889 7.3453,13.2929C7.3393,13.2949 7.3333,13.2929 7.3303,13.2869C7.3303,13.2869 7.3273,13.2849 7.3263,13.2789C7.3103,13.2519 7.2823,13.2319 7.2513,13.2319C7.2043,13.2319 7.1663,13.2689 7.1663,13.3099C7.1663,13.3259 7.1743,13.3449 7.1813,13.3569L7.2043,13.4039C7.2163,13.3859 7.2393,13.3789 7.2633,13.3789C7.3083,13.3789 7.3433,13.4119 7.3433,13.4509C7.3433,13.4609 7.3423,13.4669 7.3403,13.4719C7.3393,13.4739 7.3353,13.4779 7.3303,13.4779L7.2633,13.4779L7.2633,13.5209L7.3223,13.5209C7.3263,13.5209 7.3283,13.5249 7.3323,13.5289C7.3343,13.5349 7.3343,13.5369 7.3323,13.5399L7.2923,13.6149L7.3343,13.6009C7.3343,13.5989 7.3363,13.5989 7.3373,13.5989Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.2016,13.2591l0.1505,0l0,-0.0365l-0.1505,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.4932,13.302L7.1962,13.302L7.1962,13.216L7.4932,13.216L7.4932,13.302ZM7.2172,13.279L7.4722,13.279L7.4722,13.236L7.2172,13.236L7.2172,13.279Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0925,13.2504C7.0925,13.2504 7.0456,13.3016 7.0456,13.3485C7.0456,13.3976 7.0658,13.438 7.0658,13.438C7.0582,13.4167 7.0391,13.4036 7.0162,13.4036C6.9878,13.4036 6.9644,13.4249 6.9644,13.4533C6.9644,13.4625 6.9698,13.474 6.9736,13.4805L6.99,13.5149C6.9965,13.5024 7.0091,13.4936 7.0244,13.4936C7.044,13.4936 7.0604,13.5105 7.0604,13.5302C7.0604,13.5318 7.0604,13.5362 7.0604,13.5405L7.0184,13.5405L7.0184,13.5749L7.0555,13.5749L7.0282,13.6305L7.0636,13.618L7.092,13.648L7.1209,13.618L7.1591,13.6305L7.1307,13.5749L7.1689,13.5749L7.1689,13.54L7.1264,13.54C7.1253,13.5356 7.1247,13.5313 7.1247,13.5296C7.1247,13.51 7.1416,13.4931 7.1629,13.4931C7.1776,13.4931 7.1907,13.5018 7.1962,13.5144L7.2142,13.48C7.2169,13.4735 7.2218,13.462 7.2218,13.4527C7.2218,13.4244 7.1984,13.4031 7.1695,13.4031C7.1465,13.4031 7.1275,13.4156 7.1215,13.4375C7.1215,13.4375 7.1405,13.3971 7.1405,13.348C7.1405,13.3016 7.0925,13.2504 7.0925,13.2504" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.2044,13.9958C7.2024,13.9958 7.1984,13.9918 7.1984,13.9898L7.1514,13.9348L7.0894,13.9578C7.0864,13.9598 7.0814,13.9578 7.0774,13.9578C7.0754,13.9548 7.0754,13.9498 7.0754,13.9478L7.1194,13.8588L7.0694,13.8588C7.0624,13.8588 7.0574,13.8558 7.0574,13.8478L7.0574,13.7868C7.0574,13.7768 7.0624,13.7708 7.0694,13.7708L7.1364,13.7708C7.1364,13.7708 7.1364,13.7688 7.1364,13.7678C7.1364,13.7398 7.1104,13.7158 7.0794,13.7158C7.0544,13.7158 7.0334,13.7238 7.0264,13.7438C7.0244,13.7468 7.0204,13.7468 7.0164,13.7468C7.0114,13.7468 7.0094,13.7468 7.0064,13.7438L6.9754,13.6788C6.9704,13.6688 6.9584,13.6458 6.9584,13.6268C6.9584,13.5728 7.0064,13.5278 7.0644,13.5278C7.0864,13.5278 7.1064,13.5328 7.1224,13.5418C7.1154,13.5128 7.1074,13.4778 7.1074,13.4348C7.1074,13.3488 7.1824,13.2608 7.1944,13.2468C7.1974,13.2428 7.2094,13.2428 7.2134,13.2468C7.2224,13.2568 7.3034,13.3488 7.3034,13.4348C7.3034,13.4778 7.2964,13.5128 7.2864,13.5418C7.3034,13.5328 7.3244,13.5278 7.3444,13.5278C7.4034,13.5278 7.4504,13.5728 7.4504,13.6268C7.4504,13.6458 7.4404,13.6688 7.4344,13.6788L7.4034,13.7438C7.4034,13.7468 7.3974,13.7468 7.3944,13.7468L7.3944,13.7468C7.3924,13.7468 7.3854,13.7468 7.3854,13.7438C7.3754,13.7228 7.3564,13.7158 7.3334,13.7158C7.3004,13.7158 7.2744,13.7388 7.2744,13.7678C7.2744,13.7688 7.2744,13.7708 7.2744,13.7708L7.3444,13.7708C7.3494,13.7708 7.3544,13.7768 7.3544,13.7868L7.3544,13.8498C7.3544,13.8578 7.3494,13.8608 7.3444,13.8608L7.2914,13.8608L7.3354,13.9498C7.3384,13.9518 7.3374,13.9568 7.3334,13.9598C7.3324,13.9598 7.3274,13.9618 7.3214,13.9598L7.2614,13.9368L7.2124,13.9918C7.2104,13.9918 7.2084,13.9958 7.2044,13.9958ZM7.1534,13.9118C7.1584,13.9118 7.1594,13.9118 7.1634,13.9158L7.2054,13.9668L7.2524,13.9158C7.2534,13.9118 7.2574,13.9118 7.2644,13.9118L7.3054,13.9308L7.2664,13.8578C7.2654,13.8518 7.2654,13.8458 7.2664,13.8418C7.2694,13.8418 7.2714,13.8398 7.2764,13.8398L7.3354,13.8398L7.3354,13.7948L7.2694,13.7948C7.2654,13.7948 7.2594,13.7918 7.2594,13.7868C7.2574,13.7808 7.2564,13.7708 7.2564,13.7678C7.2564,13.7238 7.2914,13.6928 7.3364,13.6928C7.3594,13.6928 7.3834,13.7008 7.3954,13.7158L7.4184,13.6718C7.4254,13.6548 7.4334,13.6378 7.4334,13.6268C7.4334,13.5828 7.3944,13.5498 7.3484,13.5498C7.3174,13.5498 7.2884,13.5638 7.2724,13.5928C7.2714,13.5988 7.2694,13.6018 7.2694,13.6018C7.2664,13.6068 7.2594,13.6068 7.2544,13.6068C7.2494,13.6048 7.2484,13.5988 7.2484,13.5928C7.2504,13.5888 7.2534,13.5828 7.2544,13.5828C7.2634,13.5598 7.2844,13.5048 7.2844,13.4348C7.2844,13.3698 7.2294,13.2938 7.2074,13.2708C7.1864,13.2938 7.1314,13.3698 7.1314,13.4348C7.1314,13.5048 7.1534,13.5598 7.1634,13.5828C7.1654,13.5828 7.1654,13.5868 7.1674,13.5928C7.1704,13.5988 7.1664,13.6048 7.1614,13.6068C7.1564,13.6068 7.1504,13.6068 7.1484,13.6018C7.1484,13.6018 7.1474,13.5988 7.1424,13.5908C7.1304,13.5638 7.1014,13.5498 7.0674,13.5498C7.0214,13.5498 6.9844,13.5828 6.9844,13.6268C6.9844,13.6388 6.9904,13.6568 6.9974,13.6688L7.0194,13.7158C7.0354,13.6998 7.0554,13.6928 7.0824,13.6928C7.1244,13.6928 7.1604,13.7238 7.1604,13.7678C7.1604,13.7708 7.1604,13.7808 7.1594,13.7868C7.1574,13.7918 7.1544,13.7948 7.1494,13.7948L7.0824,13.7948L7.0824,13.8398L7.1404,13.8398C7.1424,13.8398 7.1494,13.8418 7.1494,13.8418C7.1514,13.8458 7.1514,13.8518 7.1494,13.8578L7.1114,13.9308L7.1534,13.9118C7.1514,13.9118 7.1514,13.9118 7.1534,13.9118Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M7.0189,13.5744l0.1505,0l0,-0.0344l-0.1505,0z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M7.3104,13.6203L7.0124,13.6203L7.0124,13.5313L7.3104,13.5313L7.3104,13.6203ZM7.0344,13.6003L7.2884,13.6003L7.2884,13.5553L7.0344,13.5553L7.0344,13.6003Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.2184,11.584L8.208,11.584C8.208,11.584 8.2042,11.5916 8.1993,11.5965C8.1905,11.6042 8.1769,11.6053 8.1698,11.5982C8.1671,11.5955 8.1638,11.5878 8.1655,11.584C8.16,11.5873 8.154,11.5873 8.148,11.584C8.1382,11.5785 8.1365,11.566 8.1431,11.5573C8.1442,11.554 8.1442,11.5496 8.1469,11.5496L8.1458,11.5371L8.1344,11.5425L8.1305,11.5491C8.1224,11.5589 8.1125,11.5589 8.106,11.5545C8.1033,11.5502 8.1016,11.5458 8.1016,11.5458C8.1016,11.5458 8.0989,11.5485 8.0956,11.5491C8.0771,11.5535 8.0695,11.512 8.0689,11.5011L8.0629,11.5109C8.0629,11.5109 8.0678,11.536 8.0651,11.5567C8.0629,11.5758 8.0547,11.5971 8.0547,11.5971C8.0809,11.6025 8.1196,11.6255 8.1578,11.6538C8.196,11.6849 8.2265,11.7155 8.2391,11.7378C8.2391,11.7378 8.2582,11.7275 8.2795,11.7209C8.3002,11.7138 8.3258,11.7138 8.3258,11.7138L8.334,11.7045C8.322,11.7078 8.2789,11.7111 8.2805,11.6909C8.2805,11.6882 8.2822,11.6865 8.2827,11.6865C8.2827,11.6865 8.2751,11.6865 8.2718,11.6833C8.2658,11.6778 8.2658,11.6675 8.2729,11.6609L8.2789,11.6533L8.2795,11.6418L8.2675,11.6451C8.2669,11.6473 8.2642,11.6484 8.2615,11.6484C8.2527,11.6582 8.2391,11.6582 8.232,11.6511C8.2282,11.6473 8.226,11.6396 8.2293,11.6358C8.2227,11.6358 8.2178,11.6358 8.2129,11.6336C8.2036,11.6271 8.2025,11.6145 8.2102,11.6047C8.2129,11.6004 8.2195,11.5949 8.2195,11.5938L8.2184,11.584" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.3934,11.9555L8.3914,11.9515C8.3684,11.9065 8.3114,11.8515 8.2454,11.8015C8.1764,11.7465 8.1064,11.7115 8.0594,11.6965L8.0504,11.6945L8.0544,11.6885C8.0544,11.6885 8.0664,11.6495 8.0714,11.6125C8.0774,11.5775 8.0664,11.5325 8.0664,11.5325L8.0664,11.5295L8.0954,11.4875L8.0954,11.5125C8.0954,11.5355 8.1084,11.5945 8.1304,11.5945C8.1304,11.5945 8.1304,11.5945 8.1324,11.5945C8.1364,11.5945 8.1364,11.5925 8.1384,11.5905L8.1484,11.5755L8.1534,11.5945L8.1534,11.5945C8.1534,11.5975 8.1574,11.6025 8.1594,11.6025C8.1604,11.6045 8.1644,11.6045 8.1664,11.6045C8.1764,11.6045 8.1844,11.6025 8.1914,11.5945L8.1994,11.5785L8.2344,11.5705L8.2344,11.6035L8.2334,11.6075C8.2314,11.6095 8.2294,11.6135 8.2294,11.6175L8.2294,11.6175C8.2234,11.6255 8.2214,11.6355 8.2234,11.6405C8.2234,11.6485 8.2294,11.6525 8.2344,11.6565C8.2414,11.6645 8.2494,11.6645 8.2584,11.6575L8.2704,11.6485L8.2704,11.6645C8.2704,11.6725 8.2704,11.6805 8.2764,11.6875C8.2864,11.6935 8.3054,11.6925 8.3184,11.6795C8.3264,11.6715 8.3334,11.6635 8.3354,11.6615L8.3354,11.6555L8.3404,11.6535L8.3614,11.6515L8.3674,11.6555L8.3704,11.6615L8.3754,11.6865L8.3704,11.6865C8.3674,11.6895 8.3584,11.6945 8.3524,11.7065C8.3474,11.7135 8.3454,11.7205 8.3474,11.7335C8.3474,11.7365 8.3524,11.7415 8.3574,11.7415C8.3644,11.7475 8.3704,11.7495 8.3784,11.7455L8.3944,11.7415L8.3884,11.7575C8.3884,11.7655 8.3884,11.7735 8.3944,11.7805C8.4064,11.7885 8.4234,11.7885 8.4374,11.7785C8.4384,11.7765 8.4414,11.7745 8.4414,11.7725C8.4424,11.7705 8.4464,11.7665 8.4464,11.7665L8.4464,11.7645L8.4814,11.7615L8.4814,11.7965L8.4684,11.8065C8.4634,11.8115 8.4584,11.8235 8.4604,11.8275C8.4614,11.8335 8.4644,11.8355 8.4644,11.8355C8.4674,11.8355 8.4744,11.8375 8.4764,11.8395L8.4994,11.8395L8.4834,11.8575L8.4794,11.8605C8.4794,11.8625 8.4804,11.8665 8.4844,11.8705C8.4914,11.8765 8.5134,11.8825 8.5424,11.8825C8.5554,11.8825 8.5654,11.8825 8.5704,11.8815L8.5964,11.8765L8.5624,11.9075L8.5574,11.9075C8.5574,11.9075 8.5104,11.9075 8.4744,11.9235C8.4374,11.9315 8.4014,11.9545 8.4014,11.9545L8.3934,11.9555ZM8.0694,11.6845C8.1204,11.6965 8.1864,11.7355 8.2524,11.7885C8.3174,11.8375 8.3744,11.8935 8.3994,11.9345C8.4124,11.9285 8.4394,11.9165 8.4674,11.9075C8.4844,11.9025 8.4994,11.8995 8.5144,11.8995C8.4974,11.8975 8.4794,11.8895 8.4724,11.8815C8.4674,11.8755 8.4634,11.8675 8.4634,11.8605C8.4634,11.8605 8.4634,11.8585 8.4644,11.8575C8.4624,11.8555 8.4554,11.8555 8.4544,11.8525C8.4474,11.8505 8.4444,11.8405 8.4424,11.8335C8.4394,11.8215 8.4434,11.8085 8.4534,11.7955L8.4554,11.7935L8.4614,11.7895L8.4614,11.7815L8.4544,11.7815C8.4524,11.7845 8.4504,11.7865 8.4504,11.7875C8.4494,11.7875 8.4474,11.7895 8.4454,11.7895C8.4264,11.8055 8.3974,11.8085 8.3804,11.7895C8.3744,11.7845 8.3684,11.7755 8.3684,11.7665C8.3624,11.7665 8.3524,11.7645 8.3454,11.7585C8.3374,11.7565 8.3314,11.7425 8.3274,11.7355C8.3274,11.7195 8.3274,11.7125 8.3374,11.6965C8.3404,11.6915 8.3494,11.6845 8.3544,11.6785L8.3514,11.6725L8.3454,11.6725C8.3414,11.6765 8.3344,11.6885 8.3284,11.6935C8.3104,11.7125 8.2804,11.7125 8.2634,11.6965C8.2574,11.6915 8.2534,11.6865 8.2514,11.6755C8.2424,11.6775 8.2334,11.6755 8.2224,11.6735C8.2144,11.6655 8.2074,11.6585 8.2044,11.6485C8.2024,11.6365 8.2044,11.6225 8.2114,11.6115L8.2124,11.6075C8.2144,11.6035 8.2154,11.6035 8.2154,11.6015L8.2154,11.5955L8.2074,11.5955L8.2034,11.6035C8.1854,11.6245 8.1584,11.6265 8.1444,11.6195C8.1424,11.6175 8.1384,11.6115 8.1384,11.6055C8.1364,11.6075 8.1334,11.6075 8.1334,11.6075C8.1314,11.6095 8.1274,11.6095 8.1274,11.6095C8.1064,11.6095 8.0924,11.5915 8.0864,11.5705C8.0864,11.5805 8.0864,11.5985 8.0864,11.6175C8.0814,11.6415 8.0764,11.6695 8.0694,11.6845Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.1409,11.6075C8.142,11.6042 8.1464,11.6042 8.1485,11.6075C8.1507,11.6096 8.1524,11.6129 8.1502,11.614C8.1491,11.6151 8.1453,11.6151 8.1425,11.614C8.1404,11.6124 8.1387,11.6096 8.1409,11.6075" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2593,11.7122C8.2576,11.7122 8.2565,11.7122 8.2538,11.7122C8.2527,11.7111 8.2511,11.7078 8.2511,11.7056C8.2511,11.7035 8.2516,11.7035 8.2527,11.7024C8.2538,11.6991 8.2587,11.6991 8.262,11.7024C8.2625,11.7035 8.2647,11.7045 8.2647,11.7078C8.2647,11.71 8.2647,11.7122 8.2631,11.7122C8.2625,11.7122 8.2609,11.7122 8.2593,11.7122Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.1671,11.5011l-0.0196,0.0011l-0.0038,0.0311l0.0011,0.0044l0.0055,0l0.0256,-0.0169l-0.0087,-0.0196" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.112,11.5202l0,0.0169l0.0322,0.0044l0.0038,-0.0044l0,-0.0044l-0.0185,-0.024l-0.0175,0.0115" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.178,11.5567l-0.0175,0.0076l-0.0185,-0.0235l-0.0005,-0.0049l0.006,-0.0027l0.0322,0.0044l-0.0016,0.0191" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.1365,11.5333C8.1393,11.5278 8.1453,11.5256 8.1502,11.53C8.1545,11.5333 8.1567,11.5376 8.1535,11.5425C8.1502,11.5458 8.1436,11.5485 8.1398,11.5458C8.1349,11.5436 8.1349,11.5371 8.1365,11.5333" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.1447,11.5502C8.1425,11.5502 8.1404,11.5502 8.1376,11.5502C8.1349,11.5475 8.1311,11.5458 8.1311,11.5404C8.1305,11.5371 8.1311,11.5327 8.1322,11.5305C8.1371,11.5229 8.1458,11.5213 8.1524,11.524C8.1556,11.5262 8.1573,11.5316 8.1589,11.5344C8.1595,11.5371 8.1595,11.5415 8.1562,11.5458C8.1545,11.5491 8.1502,11.5502 8.1447,11.5502Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.0618,11.5011C8.0607,11.5011 8.058,11.4864 8.0531,11.4765C8.0504,11.4705 8.0395,11.4607 8.0395,11.4607C8.0411,11.4607 8.0542,11.4564 8.0705,11.4662C8.0831,11.4749 8.0689,11.4951 8.0689,11.4951C8.0689,11.4951 8.0651,11.4989 8.0618,11.5011" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.0978,11.5115l-0.0142,0.0125l-0.0235,-0.0191l0.0011,-0.0055l0.0011,-0.0038l0.0322,-0.0016l0.0033,0.0175" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.058,11.4989C8.0596,11.4945 8.0645,11.4913 8.0673,11.4935C8.0711,11.4945 8.0738,11.4989 8.0705,11.5044C8.0695,11.5093 8.064,11.512 8.0607,11.5109C8.058,11.5104 8.0564,11.5055 8.058,11.4989" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.0629,11.5158C8.0613,11.5158 8.0613,11.5158 8.0613,11.5147C8.0542,11.5115 8.052,11.5071 8.0542,11.4978C8.0564,11.4913 8.064,11.4864 8.0695,11.4869C8.0755,11.4902 8.0782,11.4978 8.076,11.506C8.0738,11.5115 8.0678,11.5158 8.0629,11.5158Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.2462,11.5502l-0.0207,-0.0011l-0.0076,0.0278l0,0.0076l0.006,0l0.0284,-0.0136l-0.006,-0.0207" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.1889,11.56l-0.0027,0.0175l0.03,0.0093l0.0049,-0.0027l0,-0.0044l-0.0136,-0.0278l-0.0185,0.0082" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.2484,11.6053l-0.0175,0.0076l-0.0158,-0.0273l0.0005,-0.0049l0.0055,-0.0022l0.0311,0.0087l-0.0038,0.018" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.2113,11.5758C8.214,11.5731 8.2205,11.5731 8.2238,11.5758C8.2287,11.5791 8.2293,11.5845 8.226,11.5884C8.2222,11.5938 8.2162,11.5938 8.2113,11.5895C8.208,11.5873 8.208,11.5818 8.2113,11.5758" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.2178,11.5971C8.2145,11.5971 8.2113,11.5971 8.2091,11.5949C8.2064,11.5916 8.2047,11.5884 8.2042,11.584C8.2042,11.5807 8.2047,11.5753 8.208,11.5742C8.2113,11.5698 8.2205,11.5676 8.2271,11.5709C8.2304,11.5742 8.2325,11.5764 8.2336,11.5818C8.2336,11.584 8.2325,11.5884 8.2309,11.5916C8.2271,11.5971 8.2227,11.5971 8.2178,11.5971Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.3138,11.614l0.0038,0.0213l-0.0295,0.0087l-0.006,-0.0022l0,-0.0038l0.0125,-0.0284l0.0191,0.0044" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.3089,11.6696l-0.0196,0.0044l-0.0115,-0.0278l0.0016,-0.0065l0.0044,0l0.03,0.0115l-0.0049,0.0185" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.256,11.6151l-0.0065,0.0202l0.0295,0.0115l0.0055,-0.0011l0.0011,-0.0065l-0.0104,-0.0284l-0.0191,0.0044" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.2887,11.6495C8.2931,11.6467 8.2931,11.6391 8.2893,11.6353C8.2849,11.6331 8.2784,11.6331 8.2751,11.6353C8.2718,11.6396 8.2718,11.6462 8.2751,11.6478C8.2784,11.6522 8.2844,11.6522 8.2887,11.6495" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.3356,11.7122C8.3356,11.7122 8.3536,11.7122 8.364,11.7155C8.3711,11.7165 8.382,11.7253 8.382,11.7253C8.3842,11.7253 8.3864,11.7116 8.3722,11.6985C8.3585,11.6871 8.3422,11.704 8.3422,11.704C8.3422,11.704 8.3373,11.7089 8.3356,11.7122" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M8.4234,11.7623L8.4194,11.7603C8.4144,11.7573 8.3984,11.7463 8.3884,11.7423C8.3784,11.7383 8.3624,11.7383 8.3504,11.7383C8.3384,11.7383 8.3364,11.7383 8.3334,11.7363L8.3324,11.7303L8.3334,11.7303C8.3334,11.7183 8.3424,11.7123 8.3454,11.7113C8.3454,11.7093 8.3654,11.6893 8.3884,11.6893C8.3974,11.6893 8.4034,11.6913 8.4094,11.6953C8.4324,11.7153 8.4344,11.7383 8.4334,11.7463C8.4334,11.7523 8.4334,11.7573 8.4284,11.7603L8.4234,11.7623Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.3176,11.68l-0.0104,0.018l0.0267,0.0169l0.0033,-0.0033l0.0049,0l-0.0044,-0.0333l-0.0202,0.0016" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#C8B100" + android:fillType="nonZero" + android:pathData="M8.3395,11.7155C8.3444,11.7122 8.3465,11.7078 8.3449,11.704C8.3422,11.7024 8.3367,11.7024 8.3329,11.704C8.3269,11.7073 8.3253,11.7127 8.3264,11.7155C8.3296,11.716 8.3345,11.716 8.3395,11.7155" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + <path + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData="M9.8014,11.0459L9.6224,11.0459L9.6224,10.9909L9.6824,10.9909L9.6824,10.9259L9.6434,10.9259L9.6434,10.8719L9.6824,10.8719L9.6824,10.8329L9.7404,10.8329L9.7404,10.8719L9.7794,10.8719L9.7794,10.9259L9.7404,10.9259L9.7404,10.9909L9.8024,10.9909L9.8024,11.0459L9.8014,11.0459ZM9.6424,11.0249L9.7844,11.0249L9.7844,11.0089L9.7204,11.0089L9.7204,10.9059L9.7614,10.9059L9.7614,10.8879L9.7204,10.8879L9.7204,10.8509L9.7014,10.8509L9.7014,10.8879L9.6614,10.8879L9.6614,10.9059L9.7024,10.9059L9.7024,11.0099L9.6424,11.0099L9.6424,11.0249Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_calendar.xml b/Corona-Warn-App/src/main/res/layout/fragment_calendar.xml new file mode 100644 index 0000000000000000000000000000000000000000..73c16a8413200ca445513e7feb48b8b30d9c48e8 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_calendar.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/calendar_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/calendar_layout_background" + android:orientation="vertical"> + + <TextView + android:id="@+id/calendar_header" + android:layout_width="match_parent" + android:layout_height="@dimen/calendar_header_height" + android:padding="@dimen/spacing_normal" + android:textSize="@dimen/font_title" + android:textColor="@color/calendar_header" + android:text="@string/symptoms_calendar_exact_date_button" + android:background="@drawable/calendar_header_background" + android:focusable="true" + android:focusableInTouchMode="true" /> + + <TextView + android:id="@+id/calendar_month" + style="@style/calendarMonthText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_small" + android:layout_marginBottom="@dimen/spacing_small" + android:focusable="true" + android:focusableInTouchMode="true" /> + + <LinearLayout + android:id="@+id/calendar_day_legend" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_small" + android:layout_marginEnd="@dimen/spacing_small" + android:gravity="center" + android:orientation="horizontal" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/calendar_recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginStart="@dimen/spacing_small" + android:layout_marginEnd="@dimen/spacing_small" + android:layout_marginBottom="@dimen/spacing_small" + android:importantForAccessibility="no" + android:scrollbars="vertical" /> + +</LinearLayout> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_calendar_day.xml b/Corona-Warn-App/src/main/res/layout/fragment_calendar_day.xml new file mode 100644 index 0000000000000000000000000000000000000000..8daa8976ed087640d62f8eba9277ae3b3f084feb --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_calendar_day.xml @@ -0,0 +1,15 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="@dimen/calendar_day_size" + android:layout_height="@dimen/calendar_day_size" + android:layout_marginTop="@dimen/calendar_day_spacing" + android:layout_marginBottom="@dimen/calendar_day_spacing" > + + <TextView + android:id="@+id/dayText" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:textColor="@color/colorTextPrimary1" + android:textSize="@dimen/font_button" /> + +</LinearLayout> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_interoperability_configuration.xml b/Corona-Warn-App/src/main/res/layout/fragment_interoperability_configuration.xml new file mode 100644 index 0000000000000000000000000000000000000000..5061f03075ee26981a75e575ffb8bfa1b7d6d7ff --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_interoperability_configuration.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + <variable + name="countryData" + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <include + android:id="@+id/interoperability_configuration_header" + layout="@layout/include_header" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:title="@{@string/interoperability_title}" + app:icon="@{@drawable/ic_back}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/interoperability_configuration_country_list_container" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginBottom="10dp" + android:paddingStart="@dimen/spacing_normal" + android:paddingEnd="@dimen/spacing_normal" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interoperability_configuration_header"> + + <include + android:id="@+id/interoperability_configuration_country_list" + layout="@layout/include_interoperability" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:title="@{@string/interoperability_configuration_title}" + app:firstSection="@{@string/interoperability_configuration_first_section}" + app:secondSection="@{@string/interoperability_configuration_second_section}" + app:countryListTitle="@{@string/interoperability_configuration_list_title}" + app:fourthSection="@{@string/interoperability_configuration_information}" + app:countryData="@{countryData}" + app:isOnboarding="@{false}" + app:isRiskdetection="@{true}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/fragment_main.xml b/Corona-Warn-App/src/main/res/layout/fragment_main.xml index 25ccaf2fe0dfc525c9afec25e3175e57ddd38cdd..67452ab83b6fa53faea967a7c73e4d88f1c53fd6 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_main.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_main.xml @@ -103,8 +103,8 @@ android:layout_height="wrap_content" android:layout_marginEnd="@dimen/spacing_small" android:focusable="false" - android:contentDescription="@{FormatterSettingsHelper.formatTracingContentDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - android:text="@{FormatterSettingsHelper.formatTracingDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + android:contentDescription="@{FormatterSettingsHelper.formatTracingContentDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" + android:text="@{FormatterSettingsHelper.formatTracingDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/main_tracing_icon" app:layout_constraintStart_toStartOf="parent" @@ -115,8 +115,8 @@ android:layout_width="@dimen/icon_size_main_card" android:layout_height="@dimen/icon_size_main_card" android:importantForAccessibility="no" - app:animation="@{FormatterSettingsHelper.formatTracingIcon(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:animation_tint="@{FormatterSettingsHelper.formatTracingIconColor(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + app:animation="@{FormatterSettingsHelper.formatTracingIcon(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" + app:animation_tint="@{FormatterSettingsHelper.formatTracingIconColor(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_interoperability.xml b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_interoperability.xml new file mode 100644 index 0000000000000000000000000000000000000000..c496d23825b7e39f4018e6329be861e92fafa49a --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_interoperability.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <variable + name="countryData" + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/onboarding_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/onboarding_header" + android:layout_width="match_parent" + android:layout_height="@dimen/header" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <include + android:id="@+id/onboarding_button_back" + layout="@layout/include_button_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:icon="@{@drawable/ic_close}" + app:iconDescription="@{@string/accessibility_close}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="@id/guideline_back" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_back" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_begin="@dimen/guideline_back" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + + <include + android:id="@+id/onboarding_include" + layout="@layout/include_interoperability" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_marginBottom="@dimen/spacing_small" + android:focusable="false" + app:title="@{@string/interoperability_onboarding_delta_title}" + app:firstSection="@{@string/interoperability_onboarding_delta_subtitle}" + app:secondSection="@{@string/interoperability_onboarding_randomid_download_free}" + app:countryListTitle="@{@string/interoperability_onboarding_list_title}" + app:countryData="@{countryData}" + app:isOnboarding="@{false}" + app:isRiskdetection="@{false}" + app:showFooter="@{true}" + app:footerTitle="@{@string/interoperability_onboarding_delta_footerTitle}" + app:footerDescription="@{@string/interoperability_onboarding_delta_footerDescription}" + app:layout_constraintBottom_toTopOf="@+id/onboarding_button_next" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/guideline_top" /> + + <Button + android:id="@+id/onboarding_button_next" + style="@style/buttonPrimary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:text="@string/onboarding_button_next" + app:layout_constraintBottom_toBottomOf="@id/guideline_bottom" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_top" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_begin="@dimen/guideline_top_onboarding" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_end="@dimen/spacing_small" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_start" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_begin="@dimen/guideline_start" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_end" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_end="@dimen/guideline_end" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_tracing.xml b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_tracing.xml index 5ca28ca9cb7d674df2a84595c3b952bdeb932e5d..07f2ea6b9343f7a9d90235899e4e6fecea6a7e23 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_tracing.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_tracing.xml @@ -2,6 +2,12 @@ <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> + <data> + <variable + name="countryData" + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> + </data> + <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/onboarding_tracing_container" android:layout_width="match_parent" @@ -54,6 +60,7 @@ app:locationHeadlineCard="@{@string/onboarding_tracing_location_headline}" app:locationIconCard="@{@drawable/ic_location}" app:layout_constraintBottom_toTopOf="@+id/onboarding_button_next" + app:countryData="@{countryData}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/onboarding_button_back" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_risk_details.xml b/Corona-Warn-App/src/main/res/layout/fragment_risk_details.xml index e538e5b2b0e0729ca98020fab9f012dcb365cf56..a28df352887214d45ff666ff3f8d3e2089e1fafb 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_risk_details.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_risk_details.xml @@ -264,6 +264,20 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/risk_details_information_body" /> + <TextView + android:id="@+id/risk_details_information_lowrisk_body_url" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@string/risk_details_explanation_faq_body_with_link" + android:visibility="@{FormatterRiskHelper.formatVisibilityBehaviorLowLevelRisk(tracingViewModel.riskLevel)}" + android:focusable="true" + android:clickable="true" + android:linksClickable="true" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/risk_details_information_body_notice" /> + </androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.widget.Guideline @@ -271,7 +285,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - app:layout_constraintGuide_begin="@dimen/guideline_start" /> + app:layout_constraintGuide_begin="@dimen/guideline_top" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_end" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_settings.xml b/Corona-Warn-App/src/main/res/layout/fragment_settings.xml index 4df42821d4d0137e6cf212041570d3fa722c7090..4273c1b352aee91f8469525ac647be6567692287 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_settings.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_settings.xml @@ -54,13 +54,13 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" app:body="@{@string/settings_tracing_body_description}" - app:color="@{FormatterSettingsHelper.formatSettingsTracingIconColor(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:icon="@{FormatterSettingsHelper.formatSettingsTracingIcon(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + app:color="@{FormatterSettingsHelper.formatSettingsTracingIconColor(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(),settingsViewModel.isLocationEnabled())}" + app:icon="@{FormatterSettingsHelper.formatSettingsTracingIcon(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:showDivider="@{true}" - app:statusText="@{FormatterSettingsHelper.formatTracingStatusText(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + app:statusText="@{FormatterSettingsHelper.formatTracingStatusText(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:subtitle="@{@string/settings_tracing_title}" app:tracingViewModel="@{tracingViewModel}" /> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml b/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml index 72dcb4124161c170a68499d2a6f139d768f6ce9c..3a00e410756ca699676bce9fb8ae81a707dbf994 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_settings_tracing.xml @@ -16,14 +16,15 @@ <variable name="settingsViewModel" type="de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel" /> + </data> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/settings_tracing_container" - android:contentDescription="@string/settings_tracing_title" - android:focusable="true" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:contentDescription="@string/settings_tracing_title" + android:focusable="true"> <include android:id="@+id/settings_tracing_header" @@ -55,8 +56,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" app:headline="@{@string/settings_tracing_headline}" - app:illustration="@{FormatterSettingsHelper.formatTracingStatusImage(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:illustrationDescription="@{FormatterSettingsHelper.formatTracingIllustrationText(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + app:illustration="@{FormatterSettingsHelper.formatTracingStatusImage(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" + app:illustrationDescription="@{FormatterSettingsHelper.formatTracingIllustrationText(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -67,15 +68,27 @@ android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" - app:enabled="@{FormatterSettingsHelper.formatTracingSwitchEnabled(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + app:enabled="@{FormatterSettingsHelper.formatTracingSwitchEnabled(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/settings_tracing_header_details" app:showDivider="@{true}" - app:status="@{FormatterSettingsHelper.formatTracingSwitch(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:statusText="@{FormatterSettingsHelper.formatTracingStatusText(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + app:status="@{FormatterSettingsHelper.formatTracingSwitch(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" + app:statusText="@{FormatterSettingsHelper.formatTracingStatusText(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:subtitle="@{@string/settings_tracing_title}" /> + <include + android:id="@+id/settings_interoperability_row" + layout="@layout/include_settings_plain_row" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/settings_tracing_switch_row" + app:showDivider="@{true}" + app:statusText="@{@string/settings_interoperability_subtitle}" + app:subtitle="@{@string/settings_interoperability_title}" /> + <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/settings_tracing_status" android:layout_width="@dimen/match_constraint" @@ -83,15 +96,14 @@ android:layout_marginTop="@dimen/spacing_small" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/settings_tracing_switch_row"> + app:layout_constraintTop_toBottomOf="@id/settings_interoperability_row"> <include android:id="@+id/settings_tracing_status_location" - layout="@layout/include_tracing_status_card" + layout="@layout/include_tracing_status_card_location" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" - android:visibility="@{FormatterSettingsHelper.formatTracingStatusVisibilityLocation(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:body="@{@string/settings_tracing_status_location_body}" + android:visibility="@{FormatterSettingsHelper.formatTracingStatusVisibilityLocation(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:buttonText="@{@string/settings_tracing_status_location_button}" app:headline="@{@string/settings_tracing_status_location_headline}" app:icon="@{@drawable/ic_location}" @@ -104,7 +116,7 @@ layout="@layout/include_tracing_status_card" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" - android:visibility="@{FormatterSettingsHelper.formatTracingStatusVisibilityBluetooth(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + android:visibility="@{FormatterSettingsHelper.formatTracingStatusVisibilityBluetooth(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:body="@{@string/settings_tracing_status_bluetooth_body}" app:buttonText="@{@string/settings_tracing_status_bluetooth_button}" app:headline="@{@string/settings_tracing_status_bluetooth_headline}" @@ -113,32 +125,18 @@ app:layout_constraintStart_toStartOf="@+id/guideline_card_start" app:layout_constraintTop_toTopOf="parent" /> - <include - android:id="@+id/settings_tracing_status_connection" - layout="@layout/include_tracing_status_card" - android:layout_width="@dimen/match_constraint" - android:layout_height="wrap_content" - android:visibility="@{FormatterSettingsHelper.formatTracingStatusConnection(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" - app:body="@{@string/settings_tracing_status_connection_body}" - app:buttonText="@{@string/settings_tracing_status_connection_button}" - app:headline="@{@string/settings_tracing_status_connection_headline}" - app:icon="@{@drawable/ic_settings_tracing_connection}" - app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" - app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toTopOf="parent" /> - <include android:id="@+id/settings_tracing_status_tracing" layout="@layout/include_setting_tracing_period_logged" android:layout_width="0dp" android:layout_height="wrap_content" android:focusable="true" - android:visibility="@{FormatterSettingsHelper.formatTracingStatusVisibilityTracing(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled(), settingsViewModel.isLocationEnabled())}" + android:visibility="@{FormatterSettingsHelper.formatTracingStatusVisibilityTracing(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isLocationEnabled())}" app:layout_constraintEnd_toStartOf="@+id/guideline_end" app:layout_constraintStart_toEndOf="@+id/guideline_start" app:layout_constraintTop_toTopOf="parent" - app:tracingViewModel="@{tracingViewModel}" - app:riskLevel="@{tracingViewModel.riskLevel}" /> + app:riskLevel="@{tracingViewModel.riskLevel}" + app:tracingViewModel="@{tracingViewModel}" /> <include layout="@layout/merge_guidelines_card" /> @@ -161,8 +159,8 @@ style="@style/body1" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" - android:text="@string/settings_tracing_body_text" android:focusable="true" + android:text="@string/settings_tracing_body_text" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_contact.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_contact.xml index 40f68a4c8b468262bd4417ec7b0536945359a9d4..e19759e955cc26f042c86b9fbc2f15228dda2f08 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_contact.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_contact.xml @@ -9,7 +9,7 @@ android:layout_height="match_parent" android:contentDescription="@string/submission_contact_accessibility_title" android:fillViewport="true" - tools:context=".ui.submission.SubmissionContactFragment"> + tools:context=".ui.submission.fragment.SubmissionContactFragment"> <include android:id="@+id/submission_contact_header" @@ -23,6 +23,7 @@ app:title="@{@string/submission_contact_title}" /> <include + android:id="@+id/include_submission_contact" layout="@layout/include_submission_contact" android:layout_width="@dimen/match_constraint" android:layout_height="@dimen/match_constraint" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_country_selection.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_country_selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..59f1983446911113c3fea962ea5593f1ce40f985 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_country_selection.xml @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> + + <variable + name="submissionCountrySelectViewModel" + type="de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionCountrySelectViewModel" /> + </data> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fillViewport="true" + android:focusable="true" + tools:context=".ui.submission.fragment.SubmissionIntroFragment"> + + <include + android:id="@+id/submission_country_selection_header" + layout="@layout/include_header" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + app:icon="@{@drawable/ic_back}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:title="@{@string/submission_positive_country_selection_title}" /> + + <TextView + android:id="@+id/submission_country_selection_headline" + style="@style/headline5" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/submission_positive_country_selection_headline" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_country_selection_header" /> + + <include + android:id="@+id/submission_country_selection_selector" + layout="@layout/include_submission_country_selector" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_tiny" + android:layout_marginTop="@dimen/spacing_medium" + app:active="@{submissionCountrySelectViewModel.countriesActive}" + app:countries="@{submissionCountrySelectViewModel.countries}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/submission_country_selection_headline" /> + + <include + android:id="@+id/submission_country_selection_no_selection" + layout="@layout/include_submission_country_no_selection" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_tiny" + android:layout_marginTop="@dimen/spacing_small" + app:active="@{submissionCountrySelectViewModel.noInfoActive}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/submission_country_selection_selector" /> + + <TextView + android:id="@+id/submission_country_selection_data_faq" + style="@style/body1" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/submission_country_selection_data_faq_body" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_country_selection_no_selection" /> + + <Button + android:id="@+id/submission_country_selection_button" + style="@style/buttonPrimary" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginVertical="@dimen/spacing_normal" + android:enabled="@{submissionCountrySelectViewModel.nextActive}" + android:text="@string/submission_country_selection_button" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_country_selection_data_faq" /> + + <include layout="@layout/merge_guidelines_side" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + </ScrollView> + +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_dispatcher.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_dispatcher.xml index 64b3019ba1241bbdbd11f0735451a01f2d5c16d3..bd6ecad1b415a80f45ccf644a904b8037f539bde 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_dispatcher.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_dispatcher.xml @@ -9,7 +9,7 @@ android:layout_height="match_parent" android:contentDescription="@string/submission_dispatcher_accessibility_title" android:fillViewport="true" - tools:context=".ui.submission.SubmissionDispatcherFragment"> + tools:context=".ui.submission.fragment.SubmissionDispatcherFragment"> <include android:id="@+id/submission_dispatcher_header" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_done.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_done.xml index 92e8e11e3971b85aa8221a46be91b9ae2b68dc3d..06a69236b36b6b09bf881402fbb6f8726d5e2365 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_done.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_done.xml @@ -9,7 +9,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" - tools:context=".ui.submission.SubmissionDoneFragment"> + tools:context=".ui.submission.fragment.SubmissionDoneFragment"> <include android:id="@+id/submission_done_header" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_intro.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_intro.xml index cf44b0a02802ae9206f0ded2eb34f726173278e8..dec923dd8f0af95a4934f334b230bbc14a1b6aac 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_intro.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_intro.xml @@ -10,7 +10,7 @@ android:contentDescription="@string/submission_intro_accessibility_title" android:fillViewport="true" android:focusable="true" - tools:context=".ui.submission.SubmissionIntroFragment"> + tools:context=".ui.submission.fragment.SubmissionIntroFragment"> <include android:id="@+id/submission_intro_header" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_positive_other_warning.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_positive_other_warning.xml index 92dd63fe970143b79ed2d6532880d1dece9b2fa8..555709a0ab052805a88e12fc87c3421347548227 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_positive_other_warning.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_positive_other_warning.xml @@ -20,7 +20,7 @@ android:layout_height="match_parent" android:contentDescription="@string/submission_positive_other_warning_title" android:fillViewport="true" - tools:context=".ui.submission.SubmissionResultPositiveOtherWarningFragment"> + tools:context=".ui.submission.fragment.SubmissionResultPositiveOtherWarningFragment"> <include android:id="@+id/submission_positive_other_warning_header" @@ -37,6 +37,7 @@ layout="@layout/include_submission_positive_other_warning" android:layout_width="@dimen/match_constraint" android:layout_height="@dimen/match_constraint" + app:countryData="@{submissionViewModel.countryList}" app:layout_constraintBottom_toTopOf="@+id/guideline_action" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml new file mode 100644 index 0000000000000000000000000000000000000000..eb19ee84f777439eb95616fd29cd758dfc369bc5 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_calendar.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> + + <import type="de.rki.coronawarnapp.submission.Symptoms.StartOf" /> + + <variable + name="submissionViewModel" + type="de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel" /> + + </data> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fillViewport="true" + android:focusable="true" + tools:context=".ui.submission.fragment.SubmissionSymptomCalendarFragment"> + + <include + android:id="@+id/submission_symptom_calendar_header" + layout="@layout/include_header" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + app:icon="@{@drawable/ic_back}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:title="@{@string/submission_symptom_calendar_title}" /> + + <TextView + android:id="@+id/submission_symptom_calendar_headline" + style="@style/headline5" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/submission_symptom_calendar_headline" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_header" /> + + <TextView + android:id="@+id/submission_symptom_calendar_body" + style="@style/body1" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/submission_symptom_calendar_body" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_headline" /> + + <de.rki.coronawarnapp.ui.calendar.CalendarView + android:id="@+id/symptom_calendar_container" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_symptom_calendar_body"/> + + <include + android:id="@+id/symptom_calendar_choice_selection" + layout="@layout/include_submission_symptom_length_selection" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:focusable="true" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/symptom_calendar_container" /> + + <Button + android:id="@+id/symptom_button_next" + style="@style/buttonPrimary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_small" + android:layout_marginTop="@dimen/spacing_small" + android:text="@string/submission_symptom_further_button" + app:layout_constraintBottom_toTopOf="@id/guideline_bottom" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/symptom_calendar_choice_selection"/> + + <include layout="@layout/merge_guidelines_side" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_top" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_begin="@dimen/guideline_top" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_end="@dimen/spacing_small" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + </ScrollView> + +</layout> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml new file mode 100644 index 0000000000000000000000000000000000000000..0fb5a5e024a58ccb1cb3699b28add5c405dee041 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_symptom_intro.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> + + <variable + name="submissionViewModel" + type="de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel" /> + + </data> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/submission_symptom_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fillViewport="true" + android:focusable="true" + tools:context=".ui.submission.fragment.SubmissionIntroFragment"> + + <include + android:id="@+id/submission_symptom_header" + layout="@layout/include_header" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + app:icon="@{@drawable/ic_back}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:title="@{@string/submission_symptom_title}" /> + + <TextView + android:id="@+id/submission_symptom_initial_headline" + style="@style/headline5" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/submission_symptom_initial_headline" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_symptom_header" /> + + <de.rki.coronawarnapp.ui.view.BulletPointList + android:id="@+id/further_info_text" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:focusable="true" + android:layout_marginTop="@dimen/spacing_normal" + app:entries="@array/submission_symptom_symptom_bullets" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_symptom_initial_headline" /> + + <TextView + android:id="@+id/submission_symptom_intro_explanation" + style="@style/subtitleMedium" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@string/submission_symptom_initial_explanation" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/further_info_text" /> + + <include + android:id="@+id/symptom_choice_selection" + layout="@layout/include_submission_target_selection" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_symptom_intro_explanation" /> + + <Button + android:id="@+id/symptom_button_next" + style="@style/buttonPrimary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_small" + android:layout_marginTop="@dimen/spacing_small" + android:text="@string/submission_symptom_further_button" + app:layout_constraintBottom_toTopOf="@id/guideline_bottom" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/symptom_choice_selection"/> + + <include layout="@layout/merge_guidelines_side" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_top" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_begin="@dimen/guideline_top" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_end="@dimen/spacing_small" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + </ScrollView> + +</layout> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_tan.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_tan.xml index 0806273fc493d4ada0889377129427bf640400e5..3ef4b9f79ef0c89881003cd9e7f1ec963a4416c4 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_tan.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_tan.xml @@ -7,7 +7,7 @@ <variable name="viewmodel" - type="de.rki.coronawarnapp.ui.submission.SubmissionTanViewModel" /> + type="de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionTanViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout @@ -16,7 +16,7 @@ android:layout_height="match_parent" android:contentDescription="@string/submission_tan_accessibility_title" android:fillViewport="true" - tools:context=".ui.submission.SubmissionTanFragment"> + tools:context=".ui.submission.fragment.SubmissionTanFragment"> <include android:id="@+id/submission_tan_header" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result.xml index d7bcd4594ed7ba7ca5321331ad721d152b3e6035..a1b0cf12e9148e470da888cf38253f6500edf8ee 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result.xml @@ -105,12 +105,24 @@ style="@style/buttonPrimary" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" - android:text="@string/submission_test_result_positive_continue_button" + android:text="@string/submission_test_result_positive_continue_button_with_symptoms" + android:visibility="@{FormatterSubmissionHelper.formatTestResultPositiveStepsVisible(submissionViewModel.deviceUiState)}" + app:layout_constraintBottom_toTopOf="@+id/submission_test_result_button_positive_continue_without_symptoms" + app:layout_constraintEnd_toStartOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/guideline_action_large" /> + + <Button + android:id="@+id/submission_test_result_button_positive_continue_without_symptoms" + style="@style/buttonPrimary" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:text="@string/submission_test_result_positive_continue_button_wo_symptoms" android:visibility="@{FormatterSubmissionHelper.formatTestResultPositiveStepsVisible(submissionViewModel.deviceUiState)}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" - app:layout_constraintTop_toTopOf="@id/guideline_action" /> + app:layout_constraintTop_toBottomOf="@+id/submission_test_result_button_positive_continue" /> <Button android:id="@+id/submission_test_result_button_negative_remove_test" diff --git a/Corona-Warn-App/src/main/res/layout/include_16_years.xml b/Corona-Warn-App/src/main/res/layout/include_16_years.xml new file mode 100644 index 0000000000000000000000000000000000000000..2d6fbcdb4fe40deffad6cabf3142e14ff70066ff --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_16_years.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <variable + name="headline" + type="String" /> + + <variable + name="body" + type="String" /> + + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/sixteen_years" + style="@style/SixteenInclude" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:focusable="true"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/sixteen_years_header" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <TextView + android:id="@+id/sixteen_years_headline" + style="@style/headline6Sixteen" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/spacing_small" + android:accessibilityHeading="true" + android:contentDescription="@{headline}" + android:text="@{headline}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + </androidx.constraintlayout.widget.ConstraintLayout> + + <TextView + android:id="@+id/sixteen_years_body" + style="@style/subtitleSixteen" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{body}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/sixteen_years_header" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_contact_form.xml b/Corona-Warn-App/src/main/res/layout/include_contact_form.xml index 3369e7d09b226bca0af4011564fac16a261fdb63..0af8211cc6d358a0b26c03d88cbfbc6cf44749e9 100644 --- a/Corona-Warn-App/src/main/res/layout/include_contact_form.xml +++ b/Corona-Warn-App/src/main/res/layout/include_contact_form.xml @@ -26,9 +26,9 @@ android:clickable="true" android:focusable="true" android:linksClickable="true" - android:text="@string/information_legal_subtitle_contact_form" + android:text="@string/information_legal_subtitle_contact_label" android:textColorLink="@color/colorTextTint" - android:visibility="@{FormatterInformationLegalHelper.formatContactForm(true)}" + android:visibility="@{FormatterInformationLegalHelper.formatVisibilityLanguageBased(true)}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -42,7 +42,7 @@ android:linksClickable="true" android:text="@string/information_legal_subtitle_contact_form_non_en_de" android:textColorLink="@color/colorTextTint" - android:visibility="@{FormatterInformationLegalHelper.formatContactForm(false)}" + android:visibility="@{FormatterInformationLegalHelper.formatVisibilityLanguageBased(false)}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/information_legal_contact_form" /> diff --git a/Corona-Warn-App/src/main/res/layout/include_interop_list_participating_countries_overview.xml b/Corona-Warn-App/src/main/res/layout/include_interop_list_participating_countries_overview.xml new file mode 100644 index 0000000000000000000000000000000000000000..f6142d91d2b25a4ddeb6c664fbf4d346b6f046dc --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_interop_list_participating_countries_overview.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterHelper" /> + + <variable + name="countryData" + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> + + <variable + name="countryListTitle" + type="String" /> + + <variable + name="countryListHint" + type="String" /> + + </data> + + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/country_header_description" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@{countryListTitle}" + android:visibility="@{FormatterHelper.formatVisibilityText(countryListTitle)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <de.rki.coronawarnapp.ui.view.CountryList + android:id="@+id/countryList" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/country_header_description" + app:list="@{countryData}" /> + + <TextView + android:id="@+id/label_country_selection_info" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@{countryListHint}" + android:visibility="@{FormatterHelper.formatVisibilityText(countryListHint)}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@+id/countryList" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_interop_no_countries_infoview.xml b/Corona-Warn-App/src/main/res/layout/include_interop_no_countries_infoview.xml new file mode 100644 index 0000000000000000000000000000000000000000..d8f80cef7922d576428caf22a75656d0b46a74e7 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_interop_no_countries_infoview.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterHelper" /> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterRiskHelper" /> + + </data> + + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/participating_countries_notfetch_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:focusable="true"> + + <TextView + android:id="@+id/participating_countries_headline" + style="@style/headline5" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:focusable="false" + android:text="@string/interoperability_onboarding_list_title_failrequest" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + <TextView + android:id="@+id/participating_countries_body" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" + android:text="@string/interoperability_onboarding_list_subtitle_failrequest" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/participating_countries_headline" /> + </androidx.constraintlayout.widget.ConstraintLayout> + +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_interop_riskdetails_no_countries_infoview.xml b/Corona-Warn-App/src/main/res/layout/include_interop_riskdetails_no_countries_infoview.xml new file mode 100644 index 0000000000000000000000000000000000000000..c344112e0c13a141bb04cedba1b653b41bd30d84 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_interop_riskdetails_no_countries_infoview.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterHelper" /> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterRiskHelper" /> + + </data> + + + <androidx.constraintlayout.widget.ConstraintLayout + style="@style/cardTracing" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:padding="@dimen/card_padding" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/country_barrier"> + + <ImageView + android:id="@+id/no_network_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:importantForAccessibility="no" + android:src="@drawable/ic_interop_no_network" + android:visibility="visible" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/no_network_title" + style="@style/headline6" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/interoperability_onboarding_list_title_riskdetection_no_network" + app:layout_constraintEnd_toStartOf="@+id/no_network_icon" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/no_network_description" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@string/interoperability_onboarding_list_subtitle_failrequest_no_network" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/no_network_title" /> + + <Button + android:id="@+id/risk_details_open_settings_button" + style="@style/buttonPrimary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@string/interoperability_onboarding_list_button_title_no_network" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/no_network_description" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_interoperability.xml b/Corona-Warn-App/src/main/res/layout/include_interoperability.xml new file mode 100644 index 0000000000000000000000000000000000000000..afd91f1ecea348d005c50995bb0b649c47d6973b --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_interoperability.xml @@ -0,0 +1,307 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterHelper" /> + + <import type="android.view.View" /> + + <variable + name="countryData" + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> + + <variable + name="title" + type="String" /> + + <variable + name="firstSection" + type="String" /> + + <variable + name="secondSection" + type="String" /> + + <variable + name="thirdSection" + type="String" /> + + <variable + name="fourthSection" + type="String" /> + + <variable + name="footerTitle" + type="String" /> + + <variable + name="footerDescription" + type="String" /> + + <variable + name="countryListTitle" + type="String" /> + + <variable + name="countryListHint" + type="String" /> + + <variable + name="isOnboarding" + type="Boolean" /> + + <variable + name="isRiskdetection" + type="Boolean" /> + + <variable + name="showFooter" + type="Boolean" /> + </data> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@{title}"> + + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/interoperability_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/spacing_small" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <ImageView + android:id="@+id/interoperability_illustration" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:contentDescription="@{@string/interoperability_eu_illustration_description}" + android:src="@drawable/ic_illustration_interoperability" + android:visibility="@{FormatterHelper.formatVisibility(!isOnboarding)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/interoperability_title_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + app:layout_constraintTop_toBottomOf="@id/interoperability_illustration"> + + <TextView + style="@style/headline4" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:accessibilityHeading="true" + android:text="@{title}" + android:visibility="@{FormatterHelper.formatVisibility(!isOnboarding)}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:accessibilityHeading="true" + android:text="@{title}" + android:visibility="@{FormatterHelper.formatVisibility(isOnboarding)}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <TextView + android:id="@+id/label_interoperability_subtitle" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{firstSection}" + android:visibility="@{FormatterHelper.formatVisibilityText(firstSection)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/interoperability_title_container" /> + + <TextView + android:id="@+id/label_interoperability_subtitle2" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@{secondSection}" + android:visibility="@{FormatterHelper.formatVisibilityText(secondSection)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/label_interoperability_subtitle" /> + + <TextView + android:id="@+id/label_interoperability_subtitle3" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@{thirdSection}" + android:visibility="@{FormatterHelper.formatVisibilityText(thirdSection)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/label_interoperability_subtitle2" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <include + android:id="@+id/no_countries_default_infoview" + layout="@layout/include_interop_no_countries_infoview" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:visibility="@{FormatterHelper.formatVisibility(countryData.empty)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interoperability_header" /> + + <include + android:id="@+id/no_countries_riskdetails_infoview" + layout="@layout/include_interop_riskdetails_no_countries_infoview" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:visibility="@{FormatterHelper.formatVisibility(countryData.empty && isRiskdetection)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interoperability_header" /> + + <include + android:id="@+id/country_list_overview" + layout="@layout/include_interop_list_participating_countries_overview" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="@{FormatterHelper.formatVisibilityInverted(countryData.empty)}" + app:countryData="@{countryData}" + app:countryListHint="@{countryListHint}" + app:countryListTitle="@{countryListTitle}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interoperability_header" /> + + <androidx.constraintlayout.widget.Barrier + android:id="@+id/country_list_barrier" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:barrierAllowsGoneWidgets="false" + app:barrierDirection="bottom" + app:constraint_referenced_ids="country_list_overview, no_countries_default_infoview, no_countries_riskdetails_infoview" + tools:layout_editor_absoluteY="411dp" /> + + <TextView + android:id="@+id/label_interoperability_subtitle4" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@{fourthSection}" + android:visibility="@{FormatterHelper.formatVisibilityText(fourthSection)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/country_list_barrier" /> + + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/interoperability_footer" + style="@style/cardTracing" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:padding="@dimen/card_padding" + android:visibility="@{FormatterHelper.formatVisibility(showFooter)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/label_interoperability_subtitle4"> + + <TextView + android:id="@+id/interoperability_footer_title" + style="@style/headline6" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/spacing_normal" + android:accessibilityHeading="true" + android:text="@{footerTitle}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/interoperability_footer_description" + style="@style/body1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@{footerDescription}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interoperability_footer_title" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/expanded_terms_footer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:visibility="@{FormatterHelper.formatVisibility(showFooter)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/interoperability_footer"> + + <TextView + android:id="@+id/onboarding_delta_expanded_terms_text_part_1" + style="@style/subtitle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:paddingVertical="@dimen/button_icon_margin" + android:text="@string/interoperability_onboarding_delta_expanded_terms_text_part_1" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/onboarding_delta_expanded_terms_text_link" + style="@style/subtitle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:clickable="true" + android:linksClickable="true" + android:paddingVertical="@dimen/button_icon_margin" + android:text="@string/interoperability_onboarding_delta_terms_link" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/onboarding_delta_expanded_terms_text_part_1" /> + + <TextView + android:id="@+id/onboarding_delta_expanded_terms_text_part_2" + style="@style/subtitle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:paddingVertical="@dimen/button_icon_margin" + android:text="@string/interoperability_onboarding_delta_expanded_terms_text_part_2" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/onboarding_delta_expanded_terms_text_link" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + </androidx.constraintlayout.widget.ConstraintLayout> + </ScrollView> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_onboarding.xml b/Corona-Warn-App/src/main/res/layout/include_onboarding.xml index 2998539b56c537297ca6177c1514f32c5ec81d71..148009f3a9db6bd82531d73a62124e6d8be92524 100644 --- a/Corona-Warn-App/src/main/res/layout/include_onboarding.xml +++ b/Corona-Warn-App/src/main/res/layout/include_onboarding.xml @@ -57,6 +57,14 @@ name="easyLanguageText" type="String" /> + <variable + name="include" + type="android.view.View" /> + + <variable + name="countryData" + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> + </data> <ScrollView @@ -72,8 +80,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:contentDescription="@{FormatterAccessibilityHelper.formatImage(illustrationDescription)}" - android:src="@{illustration}" android:focusable="true" + android:src="@{illustration}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -82,12 +90,12 @@ <TextView android:id="@+id/onboarding_headline" style="@style/headline4" - android:accessibilityHeading="true" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" - android:text="@{headline}" + android:accessibilityHeading="true" android:focusable="true" + android:text="@{headline}" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" app:layout_constraintTop_toBottomOf="@+id/onboarding_illustration" @@ -99,9 +107,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" android:text="@{subtitle}" android:visibility="@{FormatterHelper.formatVisibilityText(subtitle)}" - android:focusable="true" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" app:layout_constraintTop_toBottomOf="@+id/onboarding_headline" @@ -113,8 +121,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" - android:text="@{body}" android:focusable="true" + android:text="@{body}" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" app:layout_constraintTop_toBottomOf="@+id/onboarding_subtitle" @@ -126,9 +134,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" android:text="@{bodyEmphasized}" android:visibility="@{FormatterHelper.formatVisibilityText(bodyEmphasized)}" - android:focusable="true" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" app:layout_constraintTop_toBottomOf="@id/onboarding_body" @@ -143,14 +151,35 @@ android:clickable="true" android:focusable="true" android:linksClickable="true" - android:textColorLink="@color/colorTextTint" android:text="@string/onboarding_tracing_easy_language_explanation" + android:textColorLink="@color/colorTextTint" android:visibility="@{FormatterHelper.formatVisibilityText(easyLanguageText)}" app:layout_constraintEnd_toEndOf="@id/guideline_end" app:layout_constraintStart_toStartOf="@id/guideline_start" app:layout_constraintTop_toBottomOf="@id/onboarding_body_emphasized" tools:text="@string/onboarding_tracing_easy_language_explanation" /> + <include + android:id="@+id/onboarding_interoperability" + layout="@layout/include_interoperability" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginBottom="@dimen/spacing_normal" + android:visibility="@{FormatterHelper.formatVisibility(countryData != null)}" + app:countryData="@{countryData}" + app:countryListTitle="@{@string/interoperability_onboarding_list_title}" + app:firstSection="@{@string/interoperability_onboarding_first_section}" + app:isOnboarding="@{true}" + app:isRiskdetection="@{false}" + app:layout_constraintBottom_toTopOf="@+id/onboarding_location_card" + app:layout_constraintEnd_toStartOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/onboarding_easy_language" + app:secondSection="@{@string/interoperability_onboarding_second_section}" + app:thirdSection="@{@string/interoperability_onboarding_randomid_download_free}" + app:title="@{@string/interoperability_onboarding_title}" /> + <include android:id="@+id/onboarding_location_card" layout="@layout/include_tracing_status_card" @@ -164,7 +193,21 @@ app:icon="@{locationIconCard}" app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/onboarding_easy_language" /> + app:layout_constraintTop_toBottomOf="@+id/onboarding_interoperability" /> + + <include + android:id="@+id/onboarding_location_card_16_years" + layout="@layout/include_16_years" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_medium" + android:focusable="true" + android:visibility="@{FormatterHelper.formatVisibilityText(locationHeadlineCard)}" + app:body="@{@string/sixteen_description_text}" + app:headline="@{@string/sixteen_title_text}" + app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" + app:layout_constraintStart_toStartOf="@+id/guideline_card_start" + app:layout_constraintTop_toBottomOf="@+id/onboarding_location_card" /> <include android:id="@+id/onboarding_card" @@ -172,13 +215,14 @@ android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_medium" + android:focusable="true" android:visibility="@{FormatterHelper.formatVisibilityText(headlineCard)}" app:body="@{bodyCard}" app:headline="@{headlineCard}" - android:focusable="true" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/onboarding_location_card" /> + app:layout_constraintTop_toBottomOf="@+id/onboarding_location_card_16_years" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_start" diff --git a/Corona-Warn-App/src/main/res/layout/include_risk_card.xml b/Corona-Warn-App/src/main/res/layout/include_risk_card.xml index 48b1e91d6db96e6eca06ea1431e5e71c6af70792..9c50cbc7028d3ad1b509b4c0f603f4fdc9864e5f 100644 --- a/Corona-Warn-App/src/main/res/layout/include_risk_card.xml +++ b/Corona-Warn-App/src/main/res/layout/include_risk_card.xml @@ -227,7 +227,6 @@ android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_small" - android:contentDescription="@{FormatterRiskHelper.formatNextUpdateContentDescription(tracingViewModel.riskLevel, settingsViewModel.isBackgroundJobEnabled())}" android:text="@{FormatterRiskHelper.formatNextUpdate(tracingViewModel.riskLevel, settingsViewModel.isBackgroundJobEnabled())}" android:textColor="@{FormatterRiskHelper.formatStableTextColor(tracingViewModel.riskLevel)}" app:layout_constraintEnd_toEndOf="parent" diff --git a/Corona-Warn-App/src/main/res/layout/include_settings_plain_row.xml b/Corona-Warn-App/src/main/res/layout/include_settings_plain_row.xml new file mode 100644 index 0000000000000000000000000000000000000000..357564afcea7fa7708003c2d3454b4dc0be47eb3 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_settings_plain_row.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterHelper" /> + + <import type="android.view.View" /> + + <variable + name="subtitle" + type="String" /> + + <variable + name="statusText" + type="String" /> + + <variable + name="showDivider" + type="Boolean" /> + + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/settings_plain_row" + style="@style/row" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:focusable="true" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <TextView + android:id="@+id/settings_plain_row_header_subtitle" + style="@style/subtitle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:text="@{subtitle}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/settings_plain_row_header_body" + style="@style/body2Medium" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_mega_tiny" + android:text="@{statusText}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/settings_plain_row_header_subtitle" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <include + android:id="@+id/divider" + layout="@layout/include_divider" + android:layout_width="0dp" + android:layout_height="@dimen/card_divider" + android:visibility="@{FormatterHelper.formatVisibility(showDivider)}" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/settings_plain_row" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_start" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_begin="@dimen/guideline_start" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_end" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_end="@dimen/guideline_end" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_settings_switch_row.xml b/Corona-Warn-App/src/main/res/layout/include_settings_switch_row.xml index d6340047e87241a588f8ce761c84775671833386..b818955eb8b7ada58d13356d64f759d8a50fbb73 100644 --- a/Corona-Warn-App/src/main/res/layout/include_settings_switch_row.xml +++ b/Corona-Warn-App/src/main/res/layout/include_settings_switch_row.xml @@ -86,6 +86,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" app:checked="@{status}" + android:importantForAccessibility="no" android:enabled="@{enabled}" android:contentDescription="@{FormatterSettingsHelper.formatSwitchContentDescription(subtitle, statusText)}" android:theme="@style/switchBase" diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_contact.xml b/Corona-Warn-App/src/main/res/layout/include_submission_contact.xml index 86fa23f9c3917f8209161d944b8332ddb9b8d259..bed4b0c4f55a3477adc248116a20cb6cda77a362 100644 --- a/Corona-Warn-App/src/main/res/layout/include_submission_contact.xml +++ b/Corona-Warn-App/src/main/res/layout/include_submission_contact.xml @@ -89,6 +89,7 @@ android:layout_marginTop="@dimen/spacing_small" android:text="@string/submission_contact_number_display" android:textColor="@color/colorTextTint" + android:clickable="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/submission_contact_step_1_body" /> diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_country_item.xml b/Corona-Warn-App/src/main/res/layout/include_submission_country_item.xml new file mode 100644 index 0000000000000000000000000000000000000000..c630f0f7d21e6b252d0b4598e27c6bc522567bad --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_submission_country_item.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> + + <variable + name="submissionCountry" + type="de.rki.coronawarnapp.ui.submission.SubmissionCountry" /> + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/submission_country_selector_country_body" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:focusable="true"> + + <ImageView + android:id="@+id/submission_country_selector_country_icon" + android:layout_width="@dimen/submission_country_selection_country_icon_size" + android:layout_height="@dimen/submission_country_selection_country_icon_size" + android:layout_marginVertical="@dimen/spacing_tiny" + android:layout_marginStart="@dimen/spacing_small" + android:importantForAccessibility="no" + android:scaleType="centerInside" + android:src="@{FormatterSubmissionHelper.formatCountryIsoTagToFlagDrawable(submissionCountry.countryCode), default=@drawable/ic_submission_country_flag_ireland}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/submission_country_selector_country_name" + style="@style/body1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_small" + android:focusable="true" + android:text="@{FormatterSubmissionHelper.formatCountryIsoTagToLocalizedName(submissionCountry.countryCode), default=Ireland}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@+id/submission_country_selector_country_icon" + app:layout_constraintTop_toTopOf="parent" /> + + <CheckBox + android:id="@+id/submission_country_selector_country_radiobutton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/spacing_small" + android:checked="@{submissionCountry.selected}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_country_no_selection.xml b/Corona-Warn-App/src/main/res/layout/include_submission_country_no_selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..239b2ef6f95f59219a6062bcb20f1cb679e58a6a --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_submission_country_no_selection.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> + + <variable + name="active" + type="Boolean" /> + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/submission_country_no_selection_container" + style="@style/cardGrey" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:backgroundTint="@{FormatterSubmissionHelper.formatCountrySelectCardColor(active)}" + android:focusable="true"> + + <TextView + android:id="@+id/submission_country_no_selection_header" + style="@style/headline5" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginVertical="@dimen/spacing_normal" + android:focusable="true" + android:text="@string/submission_country_no_selection_headline" + android:textColor="@{FormatterSubmissionHelper.formatCountrySelectCardTextColor(active)}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toTopOf="parent" /> + + <include layout="@layout/merge_guidelines_side" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_country_selector.xml b/Corona-Warn-App/src/main/res/layout/include_submission_country_selector.xml new file mode 100644 index 0000000000000000000000000000000000000000..78c77635574e9cd51fa806f587adc47a4f65cbae --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_submission_country_selector.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + <import type="java.util.List" /> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> + + <import type="de.rki.coronawarnapp.ui.submission.SubmissionCountry" /> + + <variable + name="active" + type="Boolean" /> + + <variable + name="countries" + type="List<SubmissionCountry>" /> + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + style="@style/cardGrey" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:backgroundTint="@{FormatterSubmissionHelper.formatCountrySelectCardColor(active)}" + android:focusable="true"> + + <TextView + android:id="@+id/submission_country_selector_header" + style="@style/headline5" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:focusable="true" + android:text="@string/submission_country_selector_headline" + android:textColor="@{FormatterSubmissionHelper.formatCountrySelectCardTextColor(active)}" + app:layout_constraintEnd_toStartOf="@+id/guideline_end" + app:layout_constraintStart_toStartOf="@+id/guideline_start" + app:layout_constraintTop_toTopOf="parent" /> + + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/submission_country_selector_recyclerview" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_mega_tiny" + android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginBottom="@dimen/spacing_mega_tiny" + android:background="@color/colorSurface1" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/submission_country_selector_header" + tools:listitem="@layout/include_submission_country_item" /> + + <include layout="@layout/merge_guidelines_side" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_done_content.xml b/Corona-Warn-App/src/main/res/layout/include_submission_done_content.xml index a988e9685244c9409f8c640b6449bef429b1ebcc..b66da1ae5a9c4565de443fa549fbb913fe04c672 100644 --- a/Corona-Warn-App/src/main/res/layout/include_submission_done_content.xml +++ b/Corona-Warn-App/src/main/res/layout/include_submission_done_content.xml @@ -47,7 +47,7 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" app:body="@{@string/submission_done_contagious}" - app:icon="@{@drawable/ic_risk_card_contact}" + app:icon="@{@drawable/ic_risk_details_contact}" app:layout_constraintEnd_toEndOf="@+id/guideline_end" app:layout_constraintStart_toStartOf="@+id/guideline_start" app:layout_constraintTop_toBottomOf="@+id/submission_done_subtitle" diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning.xml b/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning.xml index 9e33eb17669cbca920db59c406c4c430e0ac6105..2786f6c2d7e67e6e611ae7e83c2d56e92d71edd7 100644 --- a/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning.xml +++ b/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning.xml @@ -6,6 +6,10 @@ <import type="de.rki.coronawarnapp.util.formatter.FormatterAccessibilityHelper" /> + <variable + name="countryData" + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> + </data> <ScrollView @@ -51,6 +55,40 @@ app:layout_constraintStart_toStartOf="@id/guideline_start" app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_headline" /> + <TextView + android:id="@+id/submission_country_header_description" + style="@style/headline6" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@{@string/submission_interoperability_list_title}" + app:layout_constraintEnd_toEndOf="@id/guideline_end" + app:layout_constraintStart_toStartOf="@id/guideline_start" + app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_text" /> + + <de.rki.coronawarnapp.ui.view.CountryList + android:id="@+id/countryList" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + app:layout_constraintEnd_toEndOf="@+id/submission_country_header_description" + app:layout_constraintStart_toStartOf="@+id/submission_country_header_description" + app:layout_constraintTop_toBottomOf="@+id/submission_country_header_description" + app:list="@{countryData}" /> + + <include + android:id="@+id/submission_positive_location_card_16_years" + layout="@layout/include_16_years" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_large" + android:focusable="true" + app:body="@{@string/sixteen_description_text}" + app:headline="@{@string/sixteen_title_text}" + app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" + app:layout_constraintStart_toStartOf="@+id/guideline_card_start" + app:layout_constraintTop_toBottomOf="@+id/countryList" /> + <include android:id="@+id/submission_positive_other_privacy" layout="@layout/include_privacy_card" @@ -59,7 +97,7 @@ android:layout_marginTop="@dimen/spacing_large" app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/submission_positive_other_warning_text" /> + app:layout_constraintTop_toBottomOf="@+id/submission_positive_location_card_16_years" /> <include layout="@layout/merge_guidelines_side" /> diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml b/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..d95f4ed9f6f4201980e57caa01ec1e06c2d1ff6e --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_submission_symptom_length_selection.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" /> + + <import type="de.rki.coronawarnapp.submission.Symptoms.StartOf" /> + + <variable + name="submissionViewModel" + type="de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel" /> + + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/target_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:focusable="true"> + + <Button + android:id="@+id/calendar_button_seven_days" + style="@style/selectionButton" + android:enabled="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{@string/submission_symptom_less_seven}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + /> + + <Button + android:id="@+id/calendar_button_one_two_weeks" + style="@style/selectionButton" + android:enabled="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{@string/submission_symptom_one_two_weeks}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/calendar_button_seven_days" /> + + <Button + android:id="@+id/calendar_button_more_than_two_weeks" + style="@style/selectionButton" + android:enabled="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{@string/submission_symptom_more_two_weeks}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/calendar_button_one_two_weeks" /> + + <Button + android:id="@+id/target_button_verify" + style="@style/selectionButton" + android:enabled="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{@string/submission_symptom_verify}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/calendar_button_more_than_two_weeks" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_tan.xml b/Corona-Warn-App/src/main/res/layout/include_submission_tan.xml index c4d3a8243d0c1005b0c8069bfaeb76f382473c91..795e2414432a623b48ec39c9887c2a07db4e690d 100644 --- a/Corona-Warn-App/src/main/res/layout/include_submission_tan.xml +++ b/Corona-Warn-App/src/main/res/layout/include_submission_tan.xml @@ -11,7 +11,7 @@ <variable name="viewmodel" - type="de.rki.coronawarnapp.ui.submission.SubmissionTanViewModel" /> + type="de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionTanViewModel" /> </data> <ScrollView @@ -46,13 +46,13 @@ app:layout_constraintTop_toBottomOf="@+id/submission_tan_body" /> <TextView - android:id="@+id/submission_tan_character_error" + android:id="@+id/submission_tan_error" style="@style/subtitle" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_small" android:accessibilityLiveRegion="assertive" - android:text="@string/submission_tan_character_error" + android:text="@string/submission_tan_error" android:textColor="@color/colorTextSemanticRed" android:visibility="gone" app:layout_constraintEnd_toStartOf="@+id/guideline_end" @@ -61,18 +61,18 @@ tools:visibility="visible" /> <TextView - android:id="@+id/submission_tan_error" + android:id="@+id/submission_tan_character_error" style="@style/subtitle" android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_small" android:accessibilityLiveRegion="assertive" - android:text="@string/submission_tan_error" + android:text="@string/submission_tan_character_error" android:textColor="@color/colorTextSemanticRed" android:visibility="gone" app:layout_constraintEnd_toStartOf="@+id/guideline_end" app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@id/submission_tan_character_error" + app:layout_constraintTop_toBottomOf="@id/submission_tan_error" tools:visibility="visible" /> <include layout="@layout/merge_guidelines_side" /> diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml b/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..885289e1986f84037042802f1800f3aa632997b4 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_submission_target_selection.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/target_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:focusable="true"> + + <Button + android:id="@+id/target_button_apply" + style="@style/selectionButton" + android:enabled="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{@string/submission_symptom_positive_button}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <Button + android:id="@+id/target_button_reject" + style="@style/selectionButton" + android:enabled="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{@string/submission_symptom_negative_button}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/target_button_apply" /> + + <Button + android:id="@+id/target_button_verify" + style="@style/selectionButton" + android:enabled="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="@{@string/submission_symptom_no_information_button}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/target_button_reject" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/include_test_result_positive_steps.xml b/Corona-Warn-App/src/main/res/layout/include_test_result_positive_steps.xml index 93b8127a414aabbdc59c436c870062c3d38fadfb..0fbdd7e6c7182ef5252b72ef0214f8c27aacaf2f 100644 --- a/Corona-Warn-App/src/main/res/layout/include_test_result_positive_steps.xml +++ b/Corona-Warn-App/src/main/res/layout/include_test_result_positive_steps.xml @@ -22,25 +22,13 @@ app:step_entry_final="false" app:step_entry_icon="@drawable/ic_test_result_step_done" /> - <de.rki.coronawarnapp.ui.view.SimpleStepEntry - android:id="@+id/test_result_positive_steps_positive_result" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/test_result_positive_steps_added" - app:simple_step_entry_text="@string/submission_test_result_positive_steps_positive_body" - app:simple_step_entry_title="@string/submission_test_result_positive_steps_positive_heading" - app:step_entry_final="false" - app:step_entry_icon="@drawable/ic_test_result_step_done" /> - <de.rki.coronawarnapp.ui.view.SimpleStepEntry android:id="@+id/test_result_positive_steps_warning_others" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/test_result_positive_steps_positive_result" + app:layout_constraintTop_toBottomOf="@+id/test_result_positive_steps_added" app:simple_step_entry_text="@string/submission_test_result_positive_steps_warning_others_body" app:simple_step_entry_title="@string/submission_test_result_positive_steps_warning_others_heading" app:step_entry_final="true" diff --git a/Corona-Warn-App/src/main/res/layout/include_tracing_status_card_location.xml b/Corona-Warn-App/src/main/res/layout/include_tracing_status_card_location.xml new file mode 100644 index 0000000000000000000000000000000000000000..e7a794e026aeaed7ea17e28fdf869cfa47aa181f --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/include_tracing_status_card_location.xml @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <data> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterHelper" /> + + <import type="de.rki.coronawarnapp.util.formatter.FormatterAccessibilityHelper" /> + + <import type="android.view.View" /> + + <variable + name="tracingViewModel" + type="de.rki.coronawarnapp.ui.viewmodel.TracingViewModel" /> + + <variable + name="icon" + type="android.graphics.drawable.Drawable" /> + + <variable + name="headline" + type="String" /> + + <variable + name="buttonText" + type="String" /> + + + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/tracing_status_card" + style="@style/cardTracing" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:focusable="true"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/tracing_status_card_header" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <TextView + android:id="@+id/tracing_status_card_header_headline" + style="@style/headline6" + android:accessibilityHeading="true" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/spacing_small" + android:text="@{headline}" + android:contentDescription="@{headline}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@+id/tracing_status_card_header_icon" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <ImageView + android:id="@+id/tracing_status_card_header_icon" + android:layout_width="@dimen/icon_size_main_card_end" + android:layout_height="@dimen/icon_size_main_card_end" + android:importantForAccessibility="no" + android:focusable="false" + android:src="@{icon}" + android:visibility="@{FormatterHelper.formatVisibilityIcon(icon)}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/tracing_status_card_header_headline" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <de.rki.coronawarnapp.ui.view.LocationTracingStatusCardBodyTextView + android:id="@+id/tracing_status_card_body" + style="@style/subtitle" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tracing_status_card_header" /> + + <Button + android:id="@+id/tracing_status_card_button" + style="@style/buttonPrimary" + android:layout_width="@dimen/match_constraint" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_normal" + android:text="@{buttonText}" + android:visibility="@{FormatterHelper.formatVisibilityText(buttonText)}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tracing_status_card_body" /> + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/view_country_list_entry.xml b/Corona-Warn-App/src/main/res/layout/view_country_list_entry.xml new file mode 100644 index 0000000000000000000000000000000000000000..06461bae2bc856a22b3b68904ba25e699b4e6dcf --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/view_country_list_entry.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_tiny" + android:layout_marginBottom="@dimen/spacing_tiny"> + + <ImageView + android:id="@+id/country_list_entry_image" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_country_eu" /> + + <TextView + android:id="@+id/country_list_entry_label" + style="@style/subtitle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="48dp" + android:text="TextView" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <include + android:id="@+id/divider" + layout="@layout/include_divider" + android:layout_width="0dp" + android:layout_height="@dimen/card_divider" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintBottom_toBottomOf="parent" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/menu/menu_main.xml b/Corona-Warn-App/src/main/res/menu/menu_main.xml index 73c8756d988fe004d10977a42833f5c804d99f0b..811d32f472235221f4f0022d1c690fe4883b126b 100644 --- a/Corona-Warn-App/src/main/res/menu/menu_main.xml +++ b/Corona-Warn-App/src/main/res/menu/menu_main.xml @@ -1,4 +1,5 @@ -<menu xmlns:android="http://schemas.android.com/apk/res/android"> +<menu xmlns:tools="http://schemas.android.com/tools" + xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_help" android:title="@string/menu_help" /> @@ -8,4 +9,9 @@ <item android:id="@+id/menu_settings" android:title="@string/menu_settings" /> + <item + android:id="@+id/menu_test" + android:visible="false" + android:title="Test Menu" + tools:ignore="HardcodedText" /> </menu> diff --git a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml index 21404c33b88041912034f789c0e4b554728dfb3b..b8cdefde72a5d9ce7d1b36242cd442db8920d25a 100644 --- a/Corona-Warn-App/src/main/res/navigation/nav_graph.xml +++ b/Corona-Warn-App/src/main/res/navigation/nav_graph.xml @@ -5,6 +5,8 @@ android:id="@+id/nav_graph" app:startDestination="@id/mainFragment"> + <include app:graph="@navigation/test_nav_graph" /> + <!-- Main --> <fragment android:id="@+id/mainFragment" @@ -26,9 +28,6 @@ <action android:id="@+id/action_mainFragment_to_mainSharingFragment" app:destination="@id/mainSharingFragment" /> - <action - android:id="@+id/action_mainFragment_to_submissionIntroFragment" - app:destination="@id/submissionIntroFragment" /> <action android:id="@+id/action_mainFragment_to_submissionResultFragment" app:destination="@id/submissionResultFragment" /> @@ -39,8 +38,14 @@ android:id="@+id/action_mainFragment_to_mainOverviewFragment" app:destination="@id/mainOverviewFragment" /> <action - android:id="@+id/action_mainFragment_to_testRiskLevelCalculation" - app:destination="@id/testRiskLevelCalculation" /> + android:id="@+id/action_mainFragment_to_submissionIntroFragment" + app:destination="@id/submissionIntroFragment" /> + <action + android:id="@+id/action_mainFragment_to_onboardingDeltaInteroperabilityFragment" + app:destination="@id/onboardingDeltaInteroperabilityFragment" /> + <action + android:id="@+id/action_mainFragment_to_test_nav_graph" + app:destination="@id/test_nav_graph" /> </fragment> <fragment @@ -82,7 +87,31 @@ android:id="@+id/settingsTracingFragment" android:name="de.rki.coronawarnapp.ui.settings.SettingsTracingFragment" android:label="@layout/fragment_settings_tracing" - tools:layout="@layout/fragment_settings_tracing" /> + tools:layout="@layout/fragment_settings_tracing"> + <action + android:id="@+id/action_settingsTracingFragment_to_interopCountryConfigurationFragment" + app:destination="@id/interopCountryConfigurationFragment" /> + </fragment> + + <fragment + android:id="@+id/onboardingDeltaInteroperabilityFragment" + android:name="de.rki.coronawarnapp.ui.onboarding.OnboardingDeltaInteroperabilityFragment" + android:label="OnboardingDeltaInteroperabilityFragment" > + <action + android:id="@+id/action_onboardingDeltaInteroperabilityFragment_to_informationTermsFragment" + app:destination="@id/informationTermsFragment" /> + </fragment> + + <fragment + android:id="@+id/interopCountryConfigurationFragment" + android:name="de.rki.coronawarnapp.ui.interoperability.InteroperabilityConfigurationFragment" + android:label="InteropCountryConfigurationFragment" + tools:layout="@layout/fragment_interoperability_configuration"> + <action + android:id="@+id/action_interopCountryConfigurationFragment_to_settingTracingFragment" + app:destination="@id/settingsTracingFragment" /> + </fragment> + <fragment android:id="@+id/settingsNotificationFragment" @@ -168,7 +197,6 @@ android:label="InformationTechnicalFragment" tools:layout="@layout/fragment_information_technical" /> - <!-- Submission --> <fragment android:id="@+id/riskDetailsFragment" android:name="de.rki.coronawarnapp.ui.riskdetails.RiskDetailsFragment" @@ -178,10 +206,10 @@ android:id="@+id/action_riskDetailsFragment_to_settingsTracingFragment" app:destination="@id/settingsTracingFragment" /> </fragment> - + <!-- Submission --> <fragment android:id="@+id/submissionDispatcherFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionDispatcherFragment" + android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionDispatcherFragment" android:label="fragment_submission_dispatcher" tools:layout="@layout/fragment_submission_dispatcher"> <action @@ -196,7 +224,7 @@ </fragment> <fragment android:id="@+id/submissionResultPositiveOtherWarningFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionResultPositiveOtherWarningFragment" + android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionResultPositiveOtherWarningFragment" android:label="fragment_submission_result_positive_other_warning" tools:layout="@layout/fragment_submission_positive_other_warning"> <action @@ -209,17 +237,30 @@ app:destination="@id/submissionDoneFragment" app:popUpTo="@id/submissionDoneFragment" app:popUpToInclusive="true" /> + <action + android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionSymptomCalendarFragment" + app:destination="@id/submissionSymptomCalendarFragment" /> + <action + android:id="@+id/action_submissionResultPositiveOtherWarningFragment_to_submissionSymptomIntroductionFragment" + app:destination="@id/submissionSymptomIntroductionFragment" /> </fragment> <fragment android:id="@+id/submissionResultFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionTestResultFragment" + android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionTestResultFragment" android:label="fragment_submission_result" tools:layout="@layout/fragment_submission_test_result"> + <argument + android:name="skipInitialTestResultRefresh" + android:defaultValue="false" + app:argType="boolean" /> <action android:id="@+id/action_submissionResultFragment_to_mainFragment" app:destination="@id/mainFragment" app:popUpTo="@id/mainFragment" app:popUpToInclusive="true" /> + <action + android:id="@+id/action_submissionResultFragment_to_submissionSymptomIntroductionFragment" + app:destination="@id/submissionSymptomIntroductionFragment" /> <action android:id="@+id/action_submissionResultFragment_to_submissionResultPositiveOtherWarningFragment" app:destination="@id/submissionResultPositiveOtherWarningFragment" /> @@ -227,7 +268,7 @@ <fragment android:id="@+id/submissionTanFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionTanFragment" + android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionTanFragment" android:label="fragment_submission_tan" tools:layout="@layout/fragment_submission_tan"> <action @@ -239,12 +280,17 @@ android:id="@+id/action_submissionTanFragment_to_submissionResultFragment" app:destination="@id/submissionResultFragment" app:popUpTo="@id/submissionResultFragment" - app:popUpToInclusive="true" /> + app:popUpToInclusive="true"> + <argument + android:name="skipInitialTestResultRefresh" + android:defaultValue="true" + app:argType="boolean" /> + </action> </fragment> <fragment android:id="@+id/submissionIntroFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionIntroFragment" + android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionIntroFragment" android:label="SubmissionIntroFragment"> <action android:id="@+id/action_submissionIntroFragment_to_mainFragment" @@ -265,7 +311,7 @@ </activity> <fragment android:id="@+id/submissionQRCodeScanFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionQRCodeScanFragment" + android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionQRCodeScanFragment" android:label="SubmissionQRCodeScanFragment"> <action android:id="@+id/action_submissionQRCodeScanFragment_to_submissionDispatcherFragment" @@ -275,11 +321,16 @@ <action android:id="@+id/action_submissionQRCodeScanFragment_to_submissionResultFragment" app:destination="@id/submissionResultFragment" - app:popUpTo="@id/submissionResultFragment" /> + app:popUpTo="@id/submissionResultFragment"> + <argument + android:name="skipInitialTestResultRefresh" + android:defaultValue="true" + app:argType="boolean" /> + </action> </fragment> <fragment android:id="@+id/submissionDoneFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionDoneFragment" + android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionDoneFragment" android:label="SubmissionDoneFragment"> <action android:id="@+id/action_submissionDoneFragment_to_mainFragment" @@ -289,15 +340,36 @@ </fragment> <fragment android:id="@+id/submissionContactFragment" - android:name="de.rki.coronawarnapp.ui.submission.SubmissionContactFragment" + android:name="de.rki.coronawarnapp.ui.submission.fragment.SubmissionContactFragment" android:label="SubmissionContactFragment"> <action android:id="@+id/action_submissionContactFragment_to_submissionTanFragment" app:destination="@id/submissionTanFragment" /> </fragment> <fragment - android:id="@+id/testRiskLevelCalculation" - android:name="de.rki.coronawarnapp.TestRiskLevelCalculation" - android:label="fragment_test_risk_level_calculation" - tools:layout="@layout/fragment_test_risk_level_calculation" /> + android:id="@+id/submissionSymptomIntroductionFragment" + android:name="de.rki.coronawarnapp.ui.submission.SubmissionSymptomIntroductionFragment" + android:label="SubmissionSymptomIntroductionFragment" > + <action + android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionSymptomCalendarFragment" + app:destination="@id/submissionSymptomCalendarFragment" /> + <action + android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionResultFragment" + app:destination="@id/submissionResultFragment" /> + <action + android:id="@+id/action_submissionSymptomIntroductionFragment_to_submissionResultPositiveOtherWarningFragment" + app:destination="@id/submissionResultPositiveOtherWarningFragment" /> + </fragment> + <fragment + android:id="@+id/submissionSymptomCalendarFragment" + android:name="de.rki.coronawarnapp.ui.submission.SubmissionSymptomCalendarFragment" + android:label="SubmissionSymptomCalendarFragment" > + <action + android:id="@+id/action_submissionCalendarFragment_to_submissionSymptomIntroductionFragment" + app:destination="@id/submissionSymptomIntroductionFragment" /> + <action + android:id="@+id/action_submissionSymptomCalendarFragment_to_submissionResultPositiveOtherWarningFragment" + app:destination="@id/submissionResultPositiveOtherWarningFragment" /> + </fragment> + </navigation> diff --git a/Corona-Warn-App/src/main/res/values-bg/strings.xml b/Corona-Warn-App/src/main/res/values-bg/strings.xml index 45c9faa6befbd7ca8a1180c8d9208bd4aeca3a43..2e27091093c71586805a853e7afc9910410ad3f4 100644 --- a/Corona-Warn-App/src/main/res/values-bg/strings.xml +++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml @@ -212,7 +212,7 @@ <!-- XHED: main, FAQ --> <string name="main_about_headline">"ЧЗВ"</string> <!-- XTXT: main, explains faq on card --> - <string name="main_about_body">"Тук можете да намерите отговори на чеÑто задавани въпроÑи отноÑно приложението Corona-Warn-App. Ще Ви пренаÑочим към външен уебÑайт."</string> + <string name="main_about_body">"Тук можете да намерите отговори на чеÑто задавани въпроÑи отноÑно приложението Corona-Warn-App. Ще Ви пренаÑочим към външен уебÑайт на правителÑтвото на ГерманиÑ."</string> <!-- XTXT: FAQ link, should be translated --> <string name="main_about_link">"https://www.bundesregierung.de/corona-warn-app-faq-englisch"</string> <!-- XACT: Opens external webpage --> @@ -282,7 +282,7 @@ <!-- YTXT: App overview body for glossary notifications --> <string name="main_overview_body_glossary_notification">"Показват излаганиÑта на риÑк в приложението Corona-Warn-App."</string> <!-- XHED: App overview subtitle for glossary keys --> - <string name="main_overview_subtitle_glossary_keys">"Случайни идентификатори"</string> + <string name="main_overview_subtitle_glossary_keys">"Случаен идентификатор"</string> <!-- YTXT: App overview body for glossary keys --> <string name="main_overview_body_glossary_keys">"Случайните идентификатори Ñа произволно генерирани комбинации от цифри и букви, които уÑтройÑтвата Ñи разменÑÑ‚, когато Ñа в близоÑÑ‚ едно до друго. Идентифицирането на конкретни лица поÑредÑтвом проÑледÑването им е невъзможно. ОÑвен това те Ñе изтриват автоматично Ñлед 14 дни. Лицата, диагноÑтицирани Ñ COVID-19, могат да ÑподелÑÑ‚ Ñ Ð¾Ñтаналите потребители на приложението Ñвоите Ñлучайни идентификатори, генерирани през поÑледните 14 дни."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> @@ -345,7 +345,7 @@ <!-- YTXT: risk details - low risk explanation text --> <string name="risk_details_information_body_low_risk">"Вашето ниво на риÑк от заразÑване е ниÑко, защото нÑмате региÑтрирани контакти Ñ Ð»Ð¸Ñ†Ð°, които впоÑледÑтвие Ñа били диагноÑтицирани Ñ COVID-19, или ако Ñте имали такива, те Ñа били краткотрайни и от по-голÑмо разÑтоÑние."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"РиÑкът от заразÑване Ñе изчиÑлÑва локално на уÑтройÑтвото Ви въз оÑнова на региÑтрираните данни за излагане. ИзчиÑлението включва Ñъщо така разÑтоÑнието от и продължителноÑтта на вÑички контакти Ñ Ð»Ð¸Ñ†Ð°, диагноÑтицирани Ñ COVID-19., както и възможноÑтта им да заразÑÑ‚ околните. Ðикой оÑвен Ð’Ð°Ñ Ð½Ðµ може да види или да получи данни за Вашето ниво на риÑк."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"РиÑкът от заразÑване Ñе изчиÑлÑва локално на Ñмартфона Ви въз оÑнова на региÑтрираните данни за излагане. ИзчиÑлението включва Ñъщо така разÑтоÑнието от и продължителноÑтта на вÑички контакти Ñ Ð»Ð¸Ñ†Ð°, диагноÑтицирани Ñ COVID-19., както и възможноÑтта им да заразÑÑ‚ околните. Ðикой оÑвен Ð’Ð°Ñ Ð½Ðµ може да види или да получи данни за Вашето ниво на риÑк."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> <item quantity="one">"Изложени Ñте на повишен риÑк от заразÑване, защото преди %1$s дни Ñте имали продължителен и близък контакт Ñ Ð¿Ð¾Ð½Ðµ едно лице, диагноÑтицирано Ñ COVID-19."</item> @@ -372,6 +372,8 @@ <string name="risk_details_explanation_dialog_title">"Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ð½Ð¾Ñно функционалноÑтта за региÑтриране на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк"</string> <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information--> <string name="risk_details_explanation_dialog_faq_body">"За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ Ñтраницата „ЧЗВ“."</string> + <!-- XLNK: risk explanations and informations - pointing to the faq page for more information and contains hyperlink--> + <string name="risk_details_explanation_faq_body_with_link"><a href="https://www.coronawarn.app/en/faq/#encounter_but_green">"За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ Ñтраницата „ЧЗВ“."</a></string> <!-- #################################### Onboarding @@ -390,7 +392,7 @@ <!-- XTXT: onboarding - back description for screen reader --> <string name="onboarding_button_back_description">"Ðазад"</string> <!-- XACT: Onboarding (together) page title --> - <string name="onboarding_onboarding_accessibility_title">"Въведение - Ñтраница 1 от 5 Да Ñе преборим Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа заедно"</string> + <string name="onboarding_onboarding_accessibility_title">"Въведение - Ñтраница 1 от 6 Да Ñе преборим Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа заедно"</string> <!-- XHED: onboarding(together) - fight corona --> <string name="onboarding_headline">"Да Ñе преборим Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа заедно"</string> <!-- XHED: onboarding(together) - two/three line headline under an illustration --> @@ -402,28 +404,26 @@ <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Група лица използват Ñмартфоните Ñи, придвижвайки Ñе из града."</string> <!-- XACT: Onboarding (privacy) page title --> - <string name="onboarding_privacy_accessibility_title">"Въведение - Ñтраница 2 от 5 ÐеприкоÑновеноÑÑ‚ на личните данни. ТекÑÑ‚ÑŠÑ‚, който Ñледва, е дълъг. За да продължите да четете, използвайте бутона най-отдолу на екрана."</string> + <string name="onboarding_privacy_accessibility_title">"Въведение - Ñтраница 2 от 6 ÐеприкоÑновеноÑÑ‚ на личните данни. ТекÑÑ‚ÑŠÑ‚, който Ñледва, е дълъг. За да продължите да четете, използвайте бутона най-отдолу на екрана."</string> <!-- XHED: onboarding(privacy) - title --> <string name="onboarding_privacy_headline">"ПоверителноÑÑ‚"</string> <!-- XACT: onboarding(privacy) - illustraction description, header image --> <string name="onboarding_privacy_illustration_description">"Жена използва приложението Corona-Warn-App на Ñмартфона Ñи. Икона, изобразÑваща катинар на фона на щит Ñимволизира криптирането на данните."</string> <!-- XACT: Onboarding (tracing) page title --> - <string name="onboarding_tracing_accessibility_title">"Въведение - Ñтраница 3 от 5 Как да активирате региÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк"</string> + <string name="onboarding_tracing_accessibility_title">"Въведение - Ñтраница 3 от 6 Как да активирате региÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк"</string> <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"Как да активирате региÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> <string name="onboarding_tracing_subtitle">"За да уÑтановите дали за Ð’Ð°Ñ ÑъщеÑтвува риÑк от заразÑване, Ñ‚Ñ€Ñбва да активирате функциÑта за региÑтриране на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"РегиÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк Ñе извършва Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰Ñ‚Ð° на Bluetooth връзка, при коÑто Вашето уÑтройÑтво получава криптираните Ñлучайни ИД кодове на други потребители и изпраща до техните уÑтройÑтва Вашите Ñлучайни ИД кодове. ФункциÑта може да бъде дезактивирана по вÑÑко време."</string> + <string name="onboarding_tracing_body">"РегиÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк Ñе извършва Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰Ñ‚Ð° на Bluetooth връзка, при коÑто ВашиÑÑ‚ Ñмартфон получава криптираните Ñлучайни идентификационни кодове на други потребители и изпраща до техните уÑтройÑтва Вашите Ñлучайни ИД. ФункциÑта може да бъде дезактивирана по вÑÑко време."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body_emphasized">"Криптираните Ñлучайни ИД кодове предават Ñамо Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° дата, продължителноÑÑ‚ и близоÑÑ‚ на контакта Ñ Ð´Ñ€ÑƒÐ³Ð¸ лица (поÑредÑтвом Ñилата на Ñигнала). Лични данни от типа на име, Ð°Ð´Ñ€ÐµÑ Ð¸ меÑтоположение не Ñе запиÑват и идентифицирането на лицата е невъзможно."</string> + <string name="onboarding_tracing_body_emphasized">"Криптираните Ñлучайни идентификатори предават Ñамо Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° дата, продължителноÑÑ‚ и близоÑÑ‚ на контакта (изчиÑлена от Ñилата на Ñигнала). СамоличноÑтта Ви не може да бъде уÑтановена по Ñлучайните ИД."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> <string name="onboarding_tracing_easy_language_explanation"><a href="https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache">"Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° приложението на опроÑтен и жеÑтомимичен език."</a></string> - <!-- XHED: onboarding(tracing) - headline for consent information --> - <string name="onboarding_tracing_headline_consent">"ПоверителноÑÑ‚"</string> - <!-- YTXT: onboarding(tracing) - body for consent information --> - <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping on the “Enable†button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyses this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Informationâ€."</string> + <!-- NOTR: onboarding(tracing) - easy language explain tracing link URL--> + <string name="onboarding_tracing_easy_language_explanation_url">"https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache"</string> <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_button_next">"Ðктивиране на региÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк"</string> <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined --> @@ -465,7 +465,7 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Към наÑтройките за уÑтройÑтвото"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Въведение - Ñтраница 4 от 5: Ðко имате поÑтавена диагноза COVID-19..."</string> + <string name="onboarding_test_accessibility_title">"Въведение - Ñтраница 5 от 6: Ðко имате поÑтавена диагноза COVID-19..."</string> <!-- XHED: onboarding(test) - about positive tests --> <string name="onboarding_test_headline">"Ðко имате поÑтавена диагноза COVID-19,..."</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> @@ -475,7 +475,7 @@ <!-- XACT: onboarding(test) - illustraction description, header image --> <string name="onboarding_test_illustration_description">"КриптираниÑÑ‚ положителен резултат от теÑÑ‚ Ñе изпраща в ÑиÑтемата, за да бъдат предупредени оÑтаналите потребители."</string> <!-- XACT: Onboarding (datashare) page title --> - <string name="onboarding_notifications_accessibility_title">"Въведение - Ñтраница 5 от 5: Получаване на Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¸ идентифициране на риÑкове"</string> + <string name="onboarding_notifications_accessibility_title">"Въведение - Ñтраница 6 от 6: Получаване на Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¸ идентифициране на риÑкове"</string> <!-- XHED: onboarding(datashare) - about positive tests --> <string name="onboarding_notifications_headline">"ÐŸÑ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¸ риÑкове"</string> <!-- XHED: onboarding(datashare) - two/three line headline under an illustration --> @@ -485,6 +485,17 @@ <!-- XACT: onboarding(notifications) - illustraction description, header image --> <string name="onboarding_notifications_illustration_description">"Жена, коÑто получава извеÑтие от приложението Corona-Warn-App."</string> + <!-- #################################### + Onboarding sixteen include + ###################################### --> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_title_text">"Минимална възраÑÑ‚: 16 год."</string> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_description_text">"Употребата на това приложение е предназначено за лица, навършили 16 години, Ñ Ð¿Ð¾ÑтоÑнно пребиваване в ГерманиÑ."</string> + + <!-- #################################### Settings ###################################### --> @@ -498,7 +509,7 @@ <!-- XHED: settings(tracing) - page title --> <string name="settings_tracing_title">"РегиÑÑ‚ÑŠÑ€ на риÑковете"</string> <!-- XHED: settings(tracing) - headline bellow illustration --> - <string name="settings_tracing_headline">"Ето как работи региÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк"</string> + <string name="settings_tracing_headline">"Как работи региÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк"</string> <!-- XTXT: settings(tracing) - explain text in settings overview under headline --> <string name="settings_tracing_body_description">"Разрешаване на генерирането и ÑподелÑнето на Ñлучайни ИД кодове за COVID-19"</string> <!-- XTXT: settings(tracing) - shows status under header in home, active --> @@ -508,7 +519,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"УÑлугите за ÑподелÑне на меÑтоположението Ñа дезактивирани"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"РегиÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк Ñе извършва Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰Ñ‚Ð° на Bluetooth връзка, при коÑто Вашето уÑтройÑтво получава криптираните Ñлучайни идентификатори на други потребители и изпраща до техните уÑтройÑтва Вашите Ñлучайни идентификатори. ФункциÑта може да бъде дезактивирана по вÑÑко време."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Криптираните Ñлучайни ИД кодове предават Ñамо Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° дата, продължителноÑÑ‚ и близоÑÑ‚ на контакта Ñ Ð´Ñ€ÑƒÐ³Ð¸ лица (изчиÑлена чрез Ñилата на Ñигнала). Лични данни от типа на име, Ð°Ð´Ñ€ÐµÑ Ð¸ меÑтоположение не Ñе запиÑват и идентифицирането на лицата е невъзможно."</string> + <string name="settings_tracing_body_text">"За да може приложението да определи дали има вероÑтноÑÑ‚ да Ñте Ñе заразили в ÑледÑтвие на контакт ÑÑŠÑ Ð·Ð°Ñ€Ð°Ð·ÐµÐ½ потребител, Ñ‚Ñ€Ñбва да активирате функциÑта за региÑтриране на излаганиÑта на риÑк. Ð¢Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð¸ в различни държави, което означава, че Ñе вземат предвид и контактите Ви Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ð¸ на други официални Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа.\n\nФункциÑта за региÑтриране на излаганиÑта получава чрез Bluetooth и запиÑва на уÑтройÑтвото ви криптираните Ñлучайни идентификатори на оÑтаналите потребители в обхвата и изпраща към техните Ñмартфони Вашите Ñлучайни идентификатори Приложението вÑеки ден Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ ÑпиÑък ÑÑŠÑ Ñлучайните ИД и евентуални данни за развитието на Ñимптомите на вÑички потребители Ñ Ð¿Ð¾Ð»Ð¾Ð¶Ð¸Ñ‚ÐµÐ»ÐµÐ½ теÑÑ‚ за коронавируÑ, които доброволно Ñа Ñподелили тази Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· приложението Ñи. ПоÑле ÑпиÑъкът Ñе ÑравнÑва ÑÑŠÑ Ñлучайните ИД, запиÑани на Ð’Ð°ÑˆÐ¸Ñ Ñмартфон и така Ñе изчиÑлÑва вероÑтноÑтта да Ñте Ñе заразили и, ако е необходимо, получавате предупреждение. Можете да активирате и дезактивирате региÑтрирането на излаганиÑта по вÑÑко време.\n\nПриложението никога не Ñъбира лични данни от типа на име, Ð°Ð´Ñ€ÐµÑ Ð¸ меÑтоположение и не ÑÐ¿Ð¾Ð´ÐµÐ»Ñ Ð¿Ð¾Ð´Ð¾Ð±Ð½Ð° Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ Ð´Ñ€ÑƒÐ³Ð¸ потребители. СамоличноÑтта Ви не може да бъде определена по Вашите Ñлучайни ИД."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Ðктивно"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -528,7 +539,9 @@ <!--XHED : settings(tracing) - headline on card about the current status and what to do --> <string name="settings_tracing_status_location_headline">"Разрешаване на доÑтъп до данните за меÑтоположение"</string> <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled --> - <string name="settings_tracing_status_location_body">"Ðе може да бъде оÑъщеÑтвен доÑтъп до Вашето меÑтоположение. За да използвате Bluetooth, Google и/или Android изиÑкват от Ð’Ð°Ñ Ð´Ð° предоÑтавите доÑтъп до меÑтоположението на уÑтройÑтвото Ñи."</string> + <string name="settings_tracing_status_location_body">"Ðктивирайте уÑлугите за ÑподелÑне на меÑтоположение. Bluetooth Ñ Ð½Ð¸Ñък разход на ÐµÐ½ÐµÑ€Ð³Ð¸Ñ Ð¸Ð·Ð¸Ñква активирани уÑлуги за ÑподелÑне на меÑтоположението, за да може да изчиÑли физичеÑкото разÑтоÑние, но в момента нÑма доÑтъп до Вашето меÑтоположение. Повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð¶Ðµ да намерите на Ñтраницата “ЧеÑто задавани въпроÑиâ€."</string> + <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL --> + <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string> <!-- XBUT: settings(tracing) - go to operating system settings button on card - location --> <string name="settings_tracing_status_location_button">"Към наÑтройките за уÑтройÑтвото"</string> <!--XHED : settings(tracing) - headline on card about the current status and what to do --> @@ -614,9 +627,9 @@ <!-- XTXT: settings(background priority) - text in row on settings overview --> <string name="settings_background_priority_body_description">"Разрешаване на автоматични актуализации за ÑÑ‚Ð°Ñ‚ÑƒÑ Ð½Ð° риÑк"</string> <!-- XHED: settings(background priority) - multiline headline below illustration --> - <string name="settings_background_priority_headline">"Ðктивиране на фонов режим на работа на приложението Corona-Warn-App"</string> + <string name="settings_background_priority_headline">"Ðвтоматична Ð°ÐºÑ‚ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° ÑÑ‚Ð°Ñ‚ÑƒÑ Ð½Ð° риÑк"</string> <!-- YTXT: settings(background priority) - description text --> - <string name="settings_background_priority_body">"Ðко Ñте активирали приоритетната дейноÑÑ‚ във фонов режим, приложението Corona-Warn-App работи непрекъÑнато. Това дава възможноÑÑ‚ да Ñе определи ВашиÑÑ‚ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð½Ð° риÑк по вÑÑко време."</string> + <string name="settings_background_priority_body">"Ðко Ñте активирали приоритетната работа във фонов режим, приложението може да определи Ð’Ð°ÑˆÐ¸Ñ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð½Ð° риÑк по вÑÑко време. Това ще изключи оптимизациÑта на потребление на Ð±Ð°Ñ‚ÐµÑ€Ð¸Ñ Ñамо за приложението Corona-Warn-App."</string> <!-- XACT: settings(background priority) - illustraction description --> <string name="settings_background_priority_illustration_description"/> <!-- XTXT: settings(background priority) - explains user what to do on card if background priority is enabled --> @@ -641,7 +654,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"ИнÑтитутът „Роберт Кох“ (RKI) е федералната Ñлужба за общеÑтвено здравеопазване в ГерманиÑ. Той е издател на приложението Corona-Warn-App по поръчка на федералното правителÑтво. Приложението е предназначено да бъде дигитално допълнение на вече въведените мерки за опазване на общеÑтвеното здраве: Ñоциално диÑтанциране, поддържане на виÑока хигиена и ноÑене на маÑки."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Ð’Ñеки, който използва приложението, помага за проÑледÑване и прекъÑване на веригите на заразÑване. Приложението запазва във Вашето уÑтройÑтво данните за контактите Ви Ñ Ð´Ñ€ÑƒÐ³Ð¸ хора. Получавате извеÑтие, ако Ñте били в контакт Ñ Ð»Ð¸Ñ†Ð°, които впоÑледÑтвие Ñа били диагноÑтицирани Ñ COVID-19. Вашата ÑамоличноÑÑ‚ и неприкоÑновеноÑтта на данните Ви Ñа защитени по вÑÑко време."</string> + <string name="information_about_body">"Хората, които използват приложението, помагат за проÑледÑване и прекъÑване на веригите на заразÑване. Приложението запазва във Вашето уÑтройÑтво данните за контактите Ви Ñ Ð´Ñ€ÑƒÐ³Ð¸ хора. Получавате извеÑтие, ако Ñте били в контакт Ñ Ð»Ð¸Ñ†Ð°, които впоÑледÑтвие Ñа били диагноÑтицирани Ñ COVID-19. Вашата ÑамоличноÑÑ‚ и неприкоÑновеноÑтта на данните Ви Ñа защитени по вÑÑко време."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"Група лица използват Ñмартфоните Ñи, придвижвайки Ñе из града."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -663,7 +676,7 @@ <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_headline">"Как можем да Ви помогнем?"</string> <!-- YTXT: Body text for technical contact and hotline information page --> - <string name="information_contact_body">"МолÑ, използвайте нашата гореща Ð»Ð¸Ð½Ð¸Ñ Ð·Ð° техничеÑки въпроÑи отноÑно приложението Corona-Warn-App."</string> + <string name="information_contact_body">"За техничеÑки въпроÑи отноÑно Corona-Warn-App Ñе обадете на Ð³Ð¾Ñ€ÐµÑ‰Ð¸Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½.\n\nХората ÑÑŠÑ Ñлухови Ð·Ð°Ñ‚Ñ€ÑƒÐ´Ð½ÐµÐ½Ð¸Ñ Ð¸Ð¼Ð°Ñ‚ възможноÑтта да използват горещата телефонна Ð»Ð¸Ð½Ð¸Ñ Ñ‡Ñ€ÐµÐ· уÑлугата Tess Relay (за превод от пиÑмен немÑки на немÑÐºÐ¸Ñ ÐµÐ·Ð¸Ðº на знаците). Можете да Ñвалите Ð½ÐµÐ¾Ð±Ñ…Ð¾Ð´Ð¸Ð¼Ð¸Ñ Ñофтуер от App Store/Google Play."</string> <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_subtitle_phone">"Гореща Ð»Ð¸Ð½Ð¸Ñ Ð·Ð° техничеÑки въпроÑи:"</string> <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page --> @@ -700,17 +713,24 @@ <string name="information_legal_headline_contact">"Контакт"</string> <!-- YTXT: subtitle for legal information page, contact section --> <string name="information_legal_subtitle_contact">"Имейл: CoronaWarnApp@rki.de"</string> - <!-- YTXT: subtitle for legal information page, open contact form --> - <string name="information_legal_subtitle_contact_form"><a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"ФормулÑÑ€ за контакт"</a></string> + <!-- YTXT: subtitle for legal information page, open contact form : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_label">"ФормулÑÑ€ за контакт"</string> + <!-- YTXT: subtitle for legal information page url : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_url">"https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html"</string> <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German --> <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string> <!-- XHED: Headline for legal information page, tax section --> - <string name="information_legal_headline_taxid">"Идентификационен номер за ДДС"</string> + <string name="information_legal_headline_taxid">"Ðомер по ДДС"</string> <!-- YTXT: subtitle for legal information page, tax section --> <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string> <!-- XACT: describes illustration --> <string name="information_legal_illustration_description">"Ръка държи Ñмартфон, на чийто екран Ñе вижда голÑмо количеÑтво текÑÑ‚, а до Ð½ÐµÑ Ð¸Ð¼Ð° изображение на везна, коÑто Ñимволизира правната информациÑ."</string> + <!-- #################################### + Interoperability + ###################################### --> + <!-- XHED: headline for consent information --> + <string name="interop_consent_headline">"СъглаÑие"</string> <!-- #################################### Submission @@ -725,10 +745,14 @@ <!-- XBUT: Positive button for generic web request error --> <string name="submission_error_dialog_web_generic_error_button_positive">"Ðазад"</string> - <!-- XHED: Dialog title for already paired test error --> - <string name="submission_error_dialog_web_test_paired_title">"Грешка"</string> - <!-- XMSG: Dialog body for already paired test error --> - <string name="submission_error_dialog_web_test_paired_body">"QR/ТÐРкодът е невалиден или вече е използван. МолÑ, опитайте отново или Ñе обадете на горещата Ð»Ð¸Ð½Ð¸Ñ Ð·Ð° техничеÑки въпроÑи, коÑто може да намерите в раздел â€žÐ˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° приложението“."</string> + <!-- XHED: Dialog title for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_title">"Ðевалиден QR код"</string> + <!-- XMSG: Dialog body for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_body">"QR кодът е невалиден или вече е региÑтриран на друг Ñмартфон. Ще получите резултата Ñи от център за теÑтване или лабораториÑ, незавиÑимо от валидноÑтта на QR кода. Ðко Ви бъде поÑтавена диагноза COVID-19, Ñлужбата за общеÑтвено оÑигурÑване ще Ви уведоми за това."</string> + <!-- XHED: Dialog title for already paired test error: tan --> + <string name="submission_error_dialog_web_test_paired_title_tan">"ТÐРкодът е невалиден"</string> + <!-- XMSG: Dialog body for already paired test via tan - error: tan --> + <string name="submission_error_dialog_web_test_paired_body_tan">"ТÐРкодът е невалиден или вече е използван. За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñе обадете на номера, поÑочен под “ЗаÑвÑване на ТÐРкодâ€."</string> <!-- XBUT: Positive button for already paired test error --> <string name="submission_error_dialog_web_test_paired_button_positive">"Ðазад"</string> @@ -753,6 +777,15 @@ <!-- XBUT: Positive button for submission tan redeemed --> <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> + <!-- XHED: Dialog title for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_title">"Желаете ли отмÑна?"</string> + <!-- XMSG: Dialog body for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_body">"Въведените от Ð’Ð°Ñ Ð´Ð°Ð½Ð½Ð¸ нÑма да бъдат запазени."</string> + <!-- XBUT: Positive button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_positive">"Да"</string> + <!-- XBUT: Negative button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_negative">"Ðе"</string> + <!-- Permission Rationale Dialog --> <!-- XHED: Dialog headline QR Scan permission rationale --> <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"ИзиÑква Ñе разрешение за използване на камерата"</string> @@ -816,9 +849,13 @@ <!-- XHED: Page headline for other warnings screen --> <string name="submission_test_result_positive_steps_warning_others_heading">"Предупредете другите"</string> <!-- YTXT: Body text for for other warnings screen--> - <string name="submission_test_result_positive_steps_warning_others_body">"Споделете Ñвоите Ñлучайни ИД кодове от поÑледните 14 дни, за да помогнете за защитата на други хора и прекъÑването на веригата на заразÑване."</string> + <string name="submission_test_result_positive_steps_warning_others_body">"Споделете Ñвоите Ñлучайни идентификатори и предупредете околните.\nПомогнете ни да определÑме риÑка от заразÑване за Ñ‚ÑÑ… по-точно, като Ñподелите и кога за пръв път Ñте забелÑзали Ñимптомите на коронавируÑната инфекциÑ."</string> <!-- XBUT: positive test result : continue button --> <string name="submission_test_result_positive_continue_button">"Ðапред"</string> + <!-- XBUT: positive test result : continue button with symptoms--> + <string name="submission_test_result_positive_continue_button_with_symptoms">"Въведете Ñимптоми"</string> + <!-- XBUT: positive test result : continue button without symptoms --> + <string name="submission_test_result_positive_continue_button_wo_symptoms">"Ðе въвеждайте Ñимптоми"</string> <!-- XHED: Page headline for invalid test result screen --> <string name="submission_test_result_invalid_steps_invalid_heading">"Резултатът от Ð’Ð°ÑˆÐ¸Ñ Ñ‚ÐµÑÑ‚"</string> <!-- YTXT: Body text for next steps section of invalid test result--> @@ -854,9 +891,9 @@ <!-- XACT: Submission Tan page title --> <string name="submission_tan_accessibility_title">"Въвеждане на ТÐРкод"</string> <!-- YTXT: Error text for the tan submission page --> - <string name="submission_tan_error">"Ðевалиден ТÐРкод. Проверете въведените данни."</string> + <string name="submission_tan_error">"Ðевалиден ТÐРкод. МолÑ, проверете въведените данни!"</string> <!-- YTXT: Error text for the tan submission page (wrong characters) --> - <string name="submission_tan_character_error">"Въведете данни Ñа невалидни. МолÑ, проверете."</string> + <string name="submission_tan_character_error">"Въвели Ñте невалидни Ñимволи. МолÑ, проверете данните!"</string> <!-- Submission Intro --> <!-- XHED: Page title for menu at the start of the submission process --> @@ -912,16 +949,27 @@ <!-- XHED: Page headline for the positive result additional warning page--> <string name="submission_positive_other_warning_headline">"МолÑ, помогнете на вÑички наÑ!"</string> <!-- YTXT: Body text for the positive result additional warning page--> - <string name="submission_positive_other_warning_body">"Като Ñледваща Ñтъпка може да позволите на Corona-Warn-App да Ñподели Вашите Ñлучайни ИД кодове за поÑледните 14 дни Ñ Ð¾Ñтаналите потребители. По този начин може да предупредите други хора и да помогнете за прекъÑване на веригата на заразÑване.\n\nТъй като Ñе разменÑÑ‚ Ñамо Ñлучайни идентификатори, неÑъдържащи лични данни, анонимноÑтта Ви е гарантирана."</string> - <!-- XHED: Title for the privacy card--> - <string name="submission_positive_other_warning_privacy_title">"ПоверителноÑÑ‚"</string> - <!-- YTXT: Body text for the privacy card--> - <string name="submission_positive_other_warning_privacy_body">"By tapping on “Acceptâ€, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Informationâ€."</string> + <string name="submission_positive_other_warning_body">"Сега можете да Ñе уверите, че и околните ще бъдат предупредени за възможно заразÑване.\n\nЗа целта Ñ‚Ñ€Ñбва да Ñподелите на ÑъвмеÑÑ‚Ð½Ð¸Ñ Ñървър за обмен на данни, поддържан от учаÑтващите държави, Ñвоите Ñлучайни идентификатори от поÑледните 14 дни и, по желание, кога за пръв път Ñте забелÑзали Ñимптомите на коронавируÑната инфекциÑ. От там вашите уникални ИД и вÑÑка допълнителна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñе разпращат до потребителите на официални Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа. По този начин и вÑички потребители, Ñ ÐºÐ¾Ð¸Ñ‚Ð¾ Ñте били в контакт, ще бъдат предупредени за възможно заразÑване.\n\nСподелÑÑ‚ Ñе единÑтвено Вашите Ñлучайни идентификатори и информациÑта за развитието на Ñимптомите, коÑто доброволно Ñте Ñподелили. Ðе Ñе разкриват лични данни като име, Ð°Ð´Ñ€ÐµÑ Ð¸Ð»Ð¸ меÑтоположение."</string> <!-- XBUT: other warning continue button --> - <string name="submission_positive_other_warning_button">"Ðапред"</string> + <string name="submission_positive_other_warning_button">"Приемам"</string> <!-- XACT: other warning - illustration description, explanation image --> <string name="submission_positive_other_illustration_description">"УÑтройÑтво предава на ÑиÑтемата Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° положителен резултат от теÑÑ‚."</string> + <!-- XHED: Title for the interop country list--> + <string name="submission_interoperability_list_title">"Ð’ момента в международното региÑтриране на излаганиÑта учаÑтват Ñледните държави:"</string> + <!-- Submission Country Selector --> + <!-- XHED: Page title for the submission country selection page --> + <string name="submission_positive_country_selection_title">"ÐŸÑ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð·Ð° цÑла Европа"</string> + <!-- XHED: Page headline for the submission country selection page --> + <string name="submission_positive_country_selection_headline">"Кои държави Ñте поÑетили през поÑледните 14 дни?"</string> + <!-- XHED: Country selector headline for the submission country selection page --> + <string name="submission_country_selector_headline">"ПоÑетих Ñледните държави"</string> + <!-- XHED: Country no selection headline for the submission country selection page --> + <string name="submission_country_no_selection_headline">"Без отговор"</string> + <!-- YTXT: Data FAQ for the submission country selection page --> + <string name="submission_country_selection_data_faq_body">"Въведените от Ð’Ð°Ñ Ð´Ð°Ð½Ð½Ð¸ ще Ñе използват единÑтвено за оптимизиране на маÑива от данни.\n\nСпиÑъкът Ñъдържа вÑички учаÑтващи в момента държави и Ñе актуализира поÑтоÑнно."</string> + <!-- XBUT: submission country selection continue button --> + <string name="submission_country_selection_button">"Ðапред"</string> <!-- Submission Done --> <!-- XHED: Page title for completed submission page --> @@ -931,7 +979,7 @@ <!-- XHED: Page subtitle for completed submission page --> <string name="submission_done_subtitle">"МолÑ, не забравÑйте:"</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"Вие Ñте ноÑител на заразата."</string> + <string name="submission_done_contagious">"От Ñлужбата за общеÑтвено здравеопазване (Gesundheitsamt) ще Ñе Ñвържат Ñ Ð’Ð°Ñ Ð² Ñледващите нÑколко дни."</string> <!-- YTXT: text after submission: isolate --> <string name="submission_done_isolate">"Ðеобходимо е да Ñе Ñамоизолирате."</string> <!-- XHED: Title for further info --> @@ -946,7 +994,35 @@ <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Готово"</string> <!-- XACT: submission finished - illustration description, explanation image --> - <string name="submission_done_illustration_description">"Ð’Ñички в групата аплодират, защото нÑкой е Ñподелил резултата от ÑÐ²Ð¾Ñ Ñ‚ÐµÑÑ‚."</string> + <string name="submission_done_illustration_description">"Имали ли Ñте един или повече от Ñледните Ñимптоми през поÑледните нÑколко дни?"</string> + + <!-- Submission Symptoms --> + <!-- XHED: Page title for symptom screens --> + <string name="submission_symptom_title">"Симптоми"</string> + <!-- XTXT: headline text for initial symptom screen --> + <string name="submission_symptom_initial_headline">"Имали ли Ñте един или повече от Ñледните Ñимптоми?"</string> + <!-- YTXT: explanation text for initial symptom screen --> + <string name="submission_symptom_initial_explanation">"Можете да поÑочвате дали и кога Ñте проÑвили Ñимпотми на COVID-19, за да позволите на приложението да оцени по-точно риÑка от заразÑване за оÑтаналите потребители. Ðко не желаете да предоÑтавите такава информациÑ, проÑто изберете \"Без отговор\"."</string> + <!-- YTXT: Bullet points for symptoms --> + <string-array name="submission_symptom_symptom_bullets"> + <item>"Повишена температура или треÑка"</item> + <item>"Затруднено дишане"</item> + <item>"Загуба на обонÑние/вкуÑ"</item> + <item>"Кашлица"</item> + <item>"Хрема"</item> + <item>"Болки в гърлото"</item> + <item>"Главоболие и болки в крайниците"</item> + <item>"Обща ÑлабоÑÑ‚ и умора"</item> + </string-array> + <!-- XBUT: symptom initial screen yes button --> + <string name="submission_symptom_positive_button">"Да"</string> + <!-- XBUT: symptom initial screen no button --> + <string name="submission_symptom_negative_button">"Ðе"</string> + <!-- XBUT: symptom initial screen no information button --> + <string name="submission_symptom_no_information_button">"Без отговор"</string> + <!-- XBUT: symptom initial screen continue button --> + <string name="submission_symptom_further_button">"Ðапред"</string> + <!-- Submission Contact --> <!-- XHED: Page title for contact page in submission flow --> @@ -977,6 +1053,22 @@ <!-- XACT: Content Description for submission contact step 2 --> <string name="submission_contact_step_2_content">"Във втората Ñтъпка региÑтрирате теÑта Ñи, като въвеждате ТÐРкода в приложението."</string> + <!-- Submission Symptom Calendar --> + <!-- XHED: Page title for calendar page in submission symptom flow --> + <string name="submission_symptom_calendar_title">"Ðачало на Ñимптомите"</string> + <!-- XHED: Page headline for calendar page in symptom submission flow --> + <string name="submission_symptom_calendar_headline">"Кога Ñе поÑвиха за първи път тези Ñимптоми? "</string> + <!-- YTXT: Body text for calendar page in symptom submission flow--> + <string name="submission_symptom_calendar_body">"Изберете точната дата от календара или, ако не можете да Ñи Ñ Ñпомните, нÑÐºÐ¾Ñ Ð¾Ñ‚ другите опции."</string> + <!-- XBUT: symptom calendar screen less than 7 days button --> + <string name="submission_symptom_less_seven">"През поÑледните 7 дни"</string> + <!-- XBUT: symptom calendar screen 1-2 weeks button --> + <string name="submission_symptom_one_two_weeks">"Преди 1-2 Ñедмици"</string> + <!-- XBUT: symptom calendar screen more than 2 weeks button --> + <string name="submission_symptom_more_two_weeks">"Преди повече от 2 Ñедмици"</string> + <!-- XBUT: symptom calendar screen verify button --> + <string name="submission_symptom_verify">"Без отговор"</string> + <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> <string name="submission_status_card_title_fetching">"Извършва Ñе извличане на данни"</string> @@ -1013,7 +1105,7 @@ <!-- YTXT: text for contagious card --> <string name="submission_status_card_positive_result_contagious">"Вие Ñте ноÑител на заразата. Ðеобходимо е да Ñе Ñамоизолирате."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"От Ñлужбата за общеÑтвено здравеопазване (Gesundheitsamt) ще Ñе Ñвържат Ñ Ð’Ð°Ñ Ð² Ñледващите нÑколко дни по телефон или Ñ Ð¿Ð¸Ñмо."</string> + <string name="submission_status_card_positive_result_contact">"От Ñлужбата за общеÑтвено здравеопазване (Gesundheitsamt) ще Ñе Ñвържат Ñ Ð’Ð°Ñ Ð² Ñледващите нÑколко дни."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"Споделете Ñвоите Ñлучайни ИД кодове, за да предупредите оÑтаналите потребители."</string> @@ -1040,6 +1132,9 @@ <item>"Ðе ходете на работа, ако не Ñе чувÑтвате добре, за да не излагате други хора на риÑк. Ðко Ñимптомите Ви Ñе влошат, може да Ñе наложи да направите нов теÑÑ‚ за SARS-CoV-2."</item> </string-array> + <!-- XBUT Symptoms exact date button --> + <string name="symptoms_calendar_exact_date_button">"Точна дата"</string> + <!-- #################################### Button Tooltips for Accessibility ###################################### --> @@ -1068,7 +1163,7 @@ <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action --> <string name="errors_external_action">"Ðа може да извършите това дейÑтвие. МолÑ, обадете Ñе на горещата линиÑ."</string> <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update --> - <string name="errors_google_update_needed">"Вашето Corona-Warn-App приложение е инÑталирано правилно, но уÑлугата “извеÑÑ‚Ð¸Ñ Ð·Ð° Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк от заразÑване Ñ COVID-19†не Ñе предлага за операционната ÑиÑтема на Ð’Ð°ÑˆÐ¸Ñ Ñмартфон. Това означава, че не можете да използвате приложението Corona-Warn-App. Повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð¶Ðµ да намерите в Ñтраницата „ЧЗВ“ на адреÑ: https://www.coronawarn.app/en/faq/"</string> + <string name="errors_google_update_needed">"Вашето приложение Corona-Warn-App е инÑталирано правилно, но „СиÑтемата за извеÑÑ‚Ñване при Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк от заразÑване Ñ COVID-19†не Ñе предлага за операционната ÑиÑтема на Ð’Ð°ÑˆÐ¸Ñ Ñмартфон. Това означава, че не можете да използвате приложението Corona-Warn-App. Повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð¶Ðµ да намерите в Ñтраницата „ЧЗВ“ на адреÑ: https://www.coronawarn.app/en/faq/"</string> <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day --> <string name="errors_google_api_error">"Приложението Corona-Warn-App работи правилно, но не можем да актуализираме Ð’Ð°ÑˆÐ¸Ñ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð½Ð° риÑк. РегиÑтрирането на Ð¸Ð·Ð»Ð°Ð³Ð°Ð½Ð¸Ñ Ð½Ð° риÑк вÑе още е активно и функционира правилно. За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ñетете Ñтраницата „ЧЗВ“ на адреÑ: https://www.coronawarn.app/en/faq/"</string> @@ -1085,6 +1180,10 @@ <string name="errors_generic_button_negative">"Подробна информациÑ"</string> <!-- XTXT: error dialog - text when no error description is available --> <string name="errors_generic_text_unknown_error_cause">"Възникна неочаквана грешка."</string> + <!-- XTXT: error dialog - text when a catastrophic error occured from which the app recovered automatically via data reset --> + <string name="errors_generic_text_catastrophic_error_recovery_via_reset">"Приложението беше върнато към изходно ÑÑŠÑтоÑние поради техничеÑки проблем. Това нÑма да Ñе отрази на работата му. Ще продължите да получавате извеÑÑ‚Ð¸Ñ Ð·Ð° излаганиÑта и ще можете да предупредите околните в Ñлучай на положителен теÑÑ‚ за COVID-19."</string> + <!-- XTXT: error dialog - link for the details button in the catastrophic error recovery dialog --> + <string name="errors_generic_text_catastrophic_error_encryption_failure">"https://www.coronawarn.app/en/faq/#cause9002_recovery"</string> <!-- #################################### Just for Development @@ -1092,10 +1191,6 @@ <!-- NOTR --> <string name="lorem_ipsum">"Lorem Ipsum"</string> <!-- NOTR --> - <string name="menu_test_api">"Test API"</string> - <!-- NOTR --> - <string name="menu_test_risk_level">"Test Risk Level"</string> - <!-- NOTR --> <string name="menu_test_notification">"Test Notification"</string> <!-- NOTR --> <string name="test_api_button_api_launch">"Android API Test(Manual Test)"</string> @@ -1136,4 +1231,121 @@ <!-- NOTR --> <string name="test_api_calculate_risk_level">"Calculate Risk Level"</string> + <!-- XHED: Country Entry for Austria --> + <string name="country_name_at">"ÐвÑтриÑ"</string> + <!-- XHED: Country Entry for Belgium --> + <string name="country_name_be">"БелгиÑ"</string> + <!-- XHED: Country Entry for Bulgaria --> + <string name="country_name_bg">"БългариÑ"</string> + <!-- XHED: Country Entry for Switzerland --> + <string name="country_name_ch">"ШвейцариÑ"</string> + <!-- XHED: Country Entry for Cyprus --> + <string name="country_name_cy">"Кипър"</string> + <!-- XHED: Country Entry for Czech Republic --> + <string name="country_name_cz">"Чешка република"</string> + <!-- XHED: Country Entry for Germany --> + <string name="country_name_de">"ГерманиÑ"</string> + <!-- XHED: Country Entry for Denmark --> + <string name="country_name_dk">"ДаниÑ"</string> + <!-- XHED: Country Entry for Estonia --> + <string name="country_name_ee">"ЕÑтониÑ"</string> + <!-- XHED: Country Entry for Spain --> + <string name="country_name_es">"ИÑпаниÑ"</string> + <!-- XHED: Country Entry for Finland --> + <string name="country_name_fi">"ФинландиÑ"</string> + <!-- XHED: Country Entry for France --> + <string name="country_name_fr">"ФранциÑ"</string> + <!-- XHED: Country Entry for Great Britain --> + <string name="country_name_uk">"Обединено кралÑтво Ð’ÐµÐ»Ð¸ÐºÐ¾Ð±Ñ€Ð¸Ñ‚Ð°Ð½Ð¸Ñ Ð¸ Северна ИрландиÑ"</string> + <!-- XHED: Country Entry for Greece --> + <string name="country_name_gr">"ГърциÑ"</string> + <!-- XHED: Country Entry for Croatia --> + <string name="country_name_hr">"ХърватиÑ"</string> + <!-- XHED: Country Entry for Hungary --> + <string name="country_name_hu">"УнгариÑ"</string> + <!-- XHED: Country Entry for Ireland --> + <string name="country_name_ie">"ИрландиÑ"</string> + <!-- XHED: Country Entry for Iceland --> + <string name="country_name_is">"ИÑландиÑ"</string> + <!-- XHED: Country Entry for Italy --> + <string name="country_name_it">"ИталиÑ"</string> + <!-- XHED: Country Entry for Liechtenstein --> + <string name="country_name_li">"Лихтенщайн"</string> + <!-- XHED: Country Entry for Lithuania --> + <string name="country_name_lt">"Литва"</string> + <!-- XHED: Country Entry for Luxemburg --> + <string name="country_name_lu">"ЛюкÑембург"</string> + <!-- XHED: Country Entry for Latvia --> + <string name="country_name_lv">"ЛатвиÑ"</string> + <!-- XHED: Country Entry for Malta --> + <string name="country_name_mt">"Малта"</string> + <!-- XHED: Country Entry for Netherlands --> + <string name="country_name_nl">"ÐидерландиÑ"</string> + <!-- XHED: Country Entry for Norway --> + <string name="country_name_no">"ÐорвегиÑ"</string> + <!-- XHED: Country Entry for Poland --> + <string name="country_name_pl">"Полша"</string> + <!-- XHED: Country Entry for Portugal --> + <string name="country_name_pt">"ПортугалиÑ"</string> + <!-- XHED: Country Entry for Rumania --> + <string name="country_name_ro">"РумъниÑ"</string> + <!-- XHED: Country Entry for Sweden --> + <string name="country_name_se">"ШвециÑ"</string> + <!-- XHED: Country Entry for Slovenia --> + <string name="country_name_si">"СловениÑ"</string> + <!-- XHED: Country Entry for Slovakia --> + <string name="country_name_sk">"СловакиÑ"</string> + + <!-- XHED: Title of the interoperbaility information view. --> + <string name="interoperability_title">"Международно\nрегиÑтриране на излаганиÑта"</string> + + <!-- XHED: Setting title of interoperability in the tracing settings view --> + <string name="settings_interoperability_title">"Международно региÑтриране на излаганиÑта"</string> + <!-- XTXT: Settings description of the interoperability in the tracing settings view --> + <string name="settings_interoperability_subtitle">"УчаÑтващи държави"</string> + + <!-- XHED: Header of interoperability information/configuration view --> + <string name="interoperability_configuration_title">"Международно региÑтриране на излаганиÑта"</string> + <!-- XTXT: First section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_first_section">"ÐÑколко държави обединиха уÑилиÑ, за да можете да получавате международни Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ñ‡Ñ€ÐµÐ· ÑъвмеÑтен Ñървър за обмен на данни. Така при определÑнето на риÑка от заразÑване Ñе вземат предвид и контактите Ви Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ð¸ на официалните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа и в други държави."</string> + <!-- XTXT: Second section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_second_section">"За целта приложението Ð¸Ð·Ñ‚ÐµÐ³Ð»Ñ Ð¸ вÑеки ден актуализира ÑпиÑъка ÑÑŠÑ Ñлучайните идентификатори на потребителите, които Ñа избрали да ги ÑподелÑÑ‚ чрез ÑобÑтвените Ñи приложениÑ. ПоÑле този ÑпиÑък Ñе ÑравнÑва ÑÑŠÑ Ñлучайните ИД, запиÑани от вашето уÑтройÑтво. Ежедневната Ð°ÐºÑ‚ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° ÑпиÑъка обикновено е безплатна за Ð’Ð°Ñ â€“ използваните от приложението данни не Ñе такÑуват и за Ñ‚ÑÑ… не Ñе начиÑлÑват такÑи за роуминг в други държави от ЕС."</string> + <!-- XHED: Header right above the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_list_title">"Ð’ момента в международното региÑтриране на излаганиÑта на риÑк от заразÑване учаÑтват Ñледните държави:"</string> + <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_information">"ДекларациÑта за поверителноÑÑ‚ на приложението (коÑто включва Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° обработката на данни от функциÑта за международно региÑтриране на излаганиÑта) ще откриете в менюто в раздел “За приложението†> “ПоверителноÑÑ‚â€."</string> + + <!-- XHED: Sub header introducing interoperability in the tracing step of onboarding --> + <string name="interoperability_onboarding_title">"Международно\nрегиÑтриране на излаганиÑта"</string> + <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> + <string name="interoperability_onboarding_first_section">"ÐÑколко държави обединиха уÑилиÑ, за да направÑÑ‚ възможни международните предупреждениÑ. С други думи, вече могат да Ñе вземат под внимание потенциалните ви контакти Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð¸Ñ‚ÐµÐ»Ð¸ на официалните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° проÑледÑване на разпроÑтранението на коронавируÑа във вÑички учаÑтващи държави."</string> + <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> + <string name="interoperability_onboarding_second_section">"Когато потребителÑÑ‚ изпрати Ñвоите Ñлучайни ИД към Ñървъра за обмен на данни, ÑъвмеÑтно поддържан от учаÑтващите държави, потребителите на официалните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° борба Ñ ÐºÐ¾Ñ€Ð¾Ð½Ð°Ð²Ð¸Ñ€ÑƒÑа във вÑÑка една от Ñ‚ÑÑ… получават необходимите предупреждениÑ."</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_randomid_download_free">"Ежедневното изтеглÑне на ÑпиÑъка ÑÑŠÑ Ñлучайни идентификатори обикновено е безплатно за ВаÑ. Това означава, че мобилните оператори не такÑуват използваните от приложението данни и не начиÑлÑват за Ñ‚ÑÑ… такÑи за роуминг в други държави от ЕС. За повече подробноÑти Ñе обърнете към ÑÐ²Ð¾Ñ Ð¼Ð¾Ð±Ð¸Ð»ÐµÐ½ оператор."</string> + <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> + <string name="interoperability_onboarding_list_title">"Ð’ момента в обмена учаÑтват Ñредните държави:"</string> + + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 1 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_1">"УÑловиÑта за ползване Ñъщо бÑха актуализирани, за да отразÑÑ‚ разширената функционалноÑÑ‚ на приложението."</string> + <!-- XLNK: Terms of use link inside delta interoperability screen--> + <string name="interoperability_onboarding_delta_terms_link">"Покажи уÑловиÑта за ползване"</string> + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 2 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_2">"УÑловиÑта за ползване и декларациÑта за поверителноÑÑ‚ могат да бъдат прегледани от опциÑта \"За приложението\" в менюто и от опиÑанието в онлайн магазина. Промените нÑма да Ñе отразÑÑ‚ на работата на приложението. Ðко продължите да го ползвате или го отворите повторно, ще приемем, че Ñте Ñе ÑъглаÑили Ñ Ð¾Ð±Ð½Ð¾Ð²ÐµÐ½Ð¸Ñ‚Ðµ уÑÐ»Ð¾Ð²Ð¸Ñ Ð·Ð° ползване."</string> + + <!-- XACT: interoperability (eu) - illustraction description, explanation image --> + <string name="interoperability_eu_illustration_description">"Ръка държи Ñмартфон на фона на Европа и знамето на ЕС."</string> + + <!-- XTXT: Title for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_title_failrequest">"УчаÑтващи държави"</string> + <!-- XTXT: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest">"СпиÑък на учаÑтващите държави можете да видите в подробните данни за региÑтриране на излаганиÑта."</string> + + <!-- YDES: Title for the interoperability onboarding if country download fails for Risk Details --> + <string name="interoperability_onboarding_list_title_riskdetection_no_network">"Държавите не могат да бъдат показани в момента."</string> + <!-- YMSW: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest_no_network">"Възможно е да нÑмате доÑтъп до интернет. МолÑ, проверете дали имате връзка."</string> + <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> + <string name="interoperability_onboarding_list_button_title_no_network">"Към наÑтройките на уÑтройÑтвото"</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-de/legal_strings.xml b/Corona-Warn-App/src/main/res/values-de/legal_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..fc5f2be72a26eae03131d78f3e89bd5d52476eab --- /dev/null +++ b/Corona-Warn-App/src/main/res/values-de/legal_strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- XHED: Header of private data in the delta onboarding interoperability view --> + <string name="interoperability_onboarding_delta_footerTitle">Hinweis zur Datenverarbeitung</string> + <!-- XTXT: Description of private data in the delta onboarding interoperability view. Below interoperability_onboarding_delta_footerTitle --> + <string name="interoperability_onboarding_delta_footerDescription">Um zu erfahren, ob Sie Risiko-Begegnungen mit App-Nutzern der teilnehmenden Länder hatten und deshalb ein Infektionsrisiko besteht, müssen Sie nichts ändern. Es muss nur weiterhin die Risiko-Ermittlung aktiviert sein. Die Risiko-Ermittlung warnt Sie automatisch bei allen Risiko-Begegnungen, die Sie mit einem Nutzer der Corona-Warn-App oder einer anderen offiziellen Corona-App hatten.\n\nBei aktiviertem COVID-19-Benachrichtigungssystem erzeugt Ihr Android-Smartphone kontinuierlich Zufalls-IDs und versendet diese per Bluetooth, damit sie von Smartphones in Ihrer Umgebung empfangen werden können. Umgekehrt empfängt Ihr Android-Smartphone die Zufalls-IDs von anderen Smartphones. Die eigenen und die von anderen Smartphones empfangenen Zufalls-IDs werden von Ihrem Android-Smartphone aufgezeichnet und dort für 14 Tage gespeichert.\n\nFür die Risiko-Ermittlung lädt die App täglich eine aktuelle Liste mit den Zufalls-IDs aller Nutzer herunter, die diese über ihre offizielle Corona-App geteilt haben. Diese Liste wird dann mit den von Ihrem Smartphone aufgezeichneten Zufalls-IDs anderer Nutzer verglichen.\n\nWenn dabei eine Risiko-Begegnung festgestellt wird, werden Sie von der App informiert. In diesem Fall erhält die App Zugriff auf die von Ihrem Smartphone zu der Risiko-Begegnung aufgezeichneten Daten (Datum, Dauer und Bluetooth-Signalstärke des Kontakts). Aus der Bluetooth-Signalstärke wird der räumliche Abstand zu dem anderen Nutzer abgeleitet (je stärker das Signal, desto geringer der Abstand). Diese Angaben werden von der App ausgewertet, um Ihr Infektionsrisiko zu berechnen und Ihnen Verhaltensempfehlungen zu geben. Diese Auswertung wird ausschließlich lokal auf Ihrem Smartphone durchgeführt.\n\nAußer Ihnen erfährt niemand (auch nicht das RKI oder die Gesundheitsbehörden teilnehmender Länder), ob Sie eine Risiko-Begegnung hatten und welches Infektionsrisiko für Sie ermittelt wird.\n\nDie Datenschutzerklärung der App (einschließlich Informationen zur Datenverarbeitung für die länderübergreifende Risiko-Ermittlung) finden Sie unter dem Menüpunkt „App-Informationen“ > „Datenschutz“.</string> + <!-- XHED: Header of the delta onboarding screen for interoperability. If the user opens the app for the first time after the interoperability update --> + <string name="interoperability_onboarding_delta_title">Länderübergreifende\nRisiko-Ermittlung</string> + <!-- XTXT: Description of the interoperability extension of the app. Below interoperability_onboarding_delta_title --> + <string name="interoperability_onboarding_delta_subtitle">Die Funktion der Corona-Warn-App wurde erweitert. Es arbeiten nun mehrere Länder in der EU zusammen, um über das gemeinsam betriebene Serversystem länderübergreifende Warnungen zu ermöglichen. So können bei der Risiko-Ermittlung jetzt auch die Kontakte mit Nutzern der offiziellen Corona-Apps anderer teilnehmender Länder berücksichtigt werden.</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_delta_randomid">Hierfür lädt die App täglich eine aktuelle Liste mit den Zufalls-IDs aller Nutzer herunter, die diese über ihre App geteilt haben. Diese Liste wird dann mit den von Ihrem Smartphone aufgezeichneten Zufalls-IDs verglichen.</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_delta_free_download">Der tägliche Download der Liste mit den Zufalls-IDs ist für Sie in der Regel kostenlos. Das heißt: Das von der App verursachte Datenvolumen wird von den Mobilfunk-Betreibern nicht angerechnet und im EU-Ausland werden Ihnen keine Roaming-Gebühren berechnet. Näheres erfahren Sie von Ihrem Mobilfunk-Betreiber.</string> + <!-- XHED: Title for the privacy card--> + <string name="submission_positive_other_warning_privacy_title">"Einwilligungserklärung"</string> + <!-- YTXT: Body text for the privacy card--> + <string name="submission_positive_other_warning_privacy_body">"<b>Indem Sie „Einverstanden“ antippen, willigen Sie ein, dass Ihre Zufalls-IDs der letzten 14 Tage und eventuelle Angaben zum Symptombeginn an das Serversystem der App übermittelt werden.</b> Diese Informationen werden verwendet, um das Infektionsrisiko für Nutzer der App, mit denen Sie Kontakt hatten, zu bewerten und diese im Falle eines bestehenden Infektionsrisikos zu warnen. Damit auch die Nutzer von offiziellen Corona-Apps der anderen teilnehmenden Länder gewarnt werden können, werden diese Informationen vom Serversystem der App auch dem von den teilnehmenden Ländern gemeinsam betriebenen Austausch-Server bereitgestellt. Weder andere Nutzer noch das RKI oder die Gesundheitsbehörden teilnehmender Länder können anhand der übermittelten Daten auf Ihre Identität, Ihren Namen oder andere persönliche Angaben schließen.\n\nWeder andere Nutzer noch das RKI oder die Gesundheitsbehörden teilnehmender Länder können anhand der übermittelten Daten auf Ihre Identität, Ihren Namen oder andere persönliche Angaben schließen.\n\nDie Ãœbermittlung der Zufalls-IDs und der eventuellen Angaben zum Symptombeginn zur länderübergreifenden Warnung ist freiwillig. Wenn Sie die Daten nicht übermitteln, entstehen Ihnen keine Nachteile. Da weder nachvollzogen noch kontrolliert werden kann, ob und wie Sie die App verwenden, erfährt außer Ihnen auch niemand, ob Sie Ihre Zufalls-IDs zur Verfügung stellen.\n\nSie können Ihre Einwilligung jederzeit widerrufen, indem Sie die App löschen. Durch den Widerruf der Einwilligung wird die Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten Verarbeitung nicht berührt.\n\nWeitere Informationen – auch zu den teilnehmenden Ländern und datenschutzrechtlich verantwortlichen Gesundheitsbehörden – finden Sie unter dem Menüpunkt „App-Informationen“ > „Datenschutz“."</string> + <!-- XHED: onboarding(tracing) - headline for consent information --> + <string name="onboarding_tracing_headline_consent">"Einwilligungserklärung"</string> + <!-- YTXT: onboarding(tracing) - body for consent information --> + <string name="onboarding_tracing_body_consent">"Um zu erfahren, ob Sie Risiko-Begegnungen mit App-Nutzern der teilnehmenden Länder hatten und für Sie ein Infektionsrisiko besteht, müssen Sie die Risiko-Ermittlung aktivieren. Der Aktivierung der Risiko-Ermittlung und der damit im Zusammenhang stehenden Datenverarbeitung durch die App stimmen Sie mit Antippen des Buttons „Risiko-Ermittlung aktivieren“ zu.\n\nUm die Risiko-Ermittlung nutzen zu können müssen Sie zudem auf Ihrem Android-Smartphone die von Google bereitgestellte Funktion „COVID-19-Benachrichtigungen“ aktivieren und für die Corona-Warn-App freigeben.\n\nBei aktiviertem COVID-19-Benachrichtigungssystem erzeugt Ihr Android-Smartphone kontinuierlich Zufalls-IDs und versendet diese per Bluetooth, damit diese von Smartphones in Ihrer Umgebung empfangen werden können. Umgekehrt empfängt Ihr Android-Smartphone die Zufalls-IDs von anderen Smartphones. Die eigenen und die von anderen Smartphones empfangenen Zufalls-IDs werden von Ihrem Android-Smartphone aufgezeichnet und dort für 14 Tage gespeichert.\n\nFür die Risiko-Ermittlung lädt die App täglich eine aktuelle Liste mit den Zufalls-IDs aller Nutzer herunter, die diese über ihre offizielle Corona-App geteilt haben. Diese Liste wird dann mit den von Ihrem Smartphone aufgezeichneten Zufalls-IDs anderer Nutzer verglichen.\n\nWenn dabei eine Risiko-Begegnung festgestellt wird, werden Sie von der App informiert. In diesem Fall erhält die App Zugriff auf die von Ihrem Smartphone zu der Risiko-Begegnung aufgezeichneten Daten (Datum, Dauer und Bluetooth-Signalstärke des Kontakts). Aus der Bluetooth-Signalstärke wird der räumliche Abstand zu dem anderen Nutzer abgeleitet (je stärker das Signal, desto geringer der Abstand). Diese Angaben werden von der App ausgewertet, um Ihr Infektionsrisiko zu berechnen und Ihnen Verhaltensempfehlungen zu geben. Diese Auswertung wird ausschließlich lokal auf Ihrem Smartphone durchgeführt.\n\nAußer Ihnen erfährt niemand (auch nicht das RKI oder die Gesundheitsbehörden teilnehmender Länder), ob Sie eine Risiko-Begegnung hatten und welches Infektionsrisiko für Sie ermittelt wird.\n\nZum Widerruf Ihrer Einwilligung in die Risiko-Ermittlung können Sie die Funktion über den Schieberegler innerhalb der App deaktivieren oder die App löschen. Wenn Sie die Risiko-Ermittlung wieder nutzen möchten, können Sie den Schieberegler erneut aktivieren oder die App erneut installieren. Wenn Sie die Risiko-Ermittlung deaktivieren, prüft die App nicht mehr, ob Sie Risiko-Begegnungen hatten. Um auch das Aussenden und den Empfang der Zufalls-IDs anzuhalten, müssen Sie das COVID-19-Benachrichtigungssystem in den Einstellungen Ihres Android-Smartphones deaktivieren. Bitte beachten Sie, dass die vom COVID-19-Benachrichtigungssystem Ihres Android-Smartphones aufgezeichneten fremden und eigenen Zufalls-IDs nicht von der App gelöscht werden. Diese können Sie nur in den Einstellungen Ihres Android-Smartphones dauerhaft löschen.\n\nDie Datenschutzerklärung der App (einschließlich Informationen zur Datenverarbeitung für die länderübergreifende Risiko-Ermittlung) finden Sie unter dem Menüpunkt „App-Informationen“ > „Datenschutz“."</string> +</resources> diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml index 0c8e4fc5a355906bd1a178594213728b5311dac8..b717635bf7006c1aec608c7bd81033fbcd56c8fb 100644 --- a/Corona-Warn-App/src/main/res/values-de/strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/strings.xml @@ -1,4 +1,5 @@ -<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation"> +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation"> <!-- #################################### Preference Keys @@ -212,7 +213,7 @@ <!-- XHED: main, FAQ --> <string name="main_about_headline">"Häufige Fragen"</string> <!-- XTXT: main, explains faq on card --> - <string name="main_about_body">"Hier finden Sie Antworten auf häufig gestellte Fragen rund um die Corona-Warn-App. Sie werden auf eine externe Website weitergeleitet."</string> + <string name="main_about_body">"Hier finden Sie Antworten auf häufig gestellte Fragen rund um die Corona-Warn-App. Sie werden auf eine externe Website der Bundesregierung weitergeleitet."</string> <!-- XTXT: FAQ link, should be translated --> <string name="main_about_link">"https://www.bundesregierung.de/corona-warn-app-faq"</string> <!-- XACT: Opens external webpage --> @@ -268,7 +269,7 @@ <!-- XHED: App overview subtitle for glossary key storage --> <string name="main_overview_subtitle_glossary_tracing">"Begegnungs-Aufzeichnung"</string> <!-- YTXT: App overview body for glossary key storage --> - <string name="main_overview_body_glossary_tracing">"Liste der empfangenen und vorübergehend im Betriebssystemspeicher abgelegten kurzlebigen Zufallscodes. Diese Liste wird bei der Risiko-Ãœberprüfung gelesen. Alle Zufallscodes werden nach 14 Tagen automatisch gelöscht."</string> + <string name="main_overview_body_glossary_tracing">"Liste der empfangenen und vorübergehend im Betriebssystemspeicher abgelegten kurzlebigen Zufalls-IDs. Diese Liste wird bei der Risiko-Ãœberprüfung gelesen. Alle Zufalls-IDs werden nach 14 Tagen automatisch gelöscht."</string> <!-- XHED: App overview subtitle for glossary risk calculation --> <string name="main_overview_subtitle_glossary_calculation">"Risiko-Ãœberprüfung"</string> <!-- YTXT: App overview body for glossary risk calculation --> @@ -282,9 +283,9 @@ <!-- YTXT: App overview body for glossary notifications --> <string name="main_overview_body_glossary_notification">"Die Anzeige von Risiko-Begegnungen in der Corona-Warn-App."</string> <!-- XHED: App overview subtitle for glossary keys --> - <string name="main_overview_subtitle_glossary_keys">"Zufallscode"</string> + <string name="main_overview_subtitle_glossary_keys">"Zufalls-ID"</string> <!-- YTXT: App overview body for glossary keys --> - <string name="main_overview_body_glossary_keys">"Die Zufallscodes sind zufällig erzeugte Zahlen- und Buchstabenkombinationen. Sie werden zwischen benachbarten Smartphones ausgetauscht. Zufallscodes lassen sich nicht einer bestimmten Person zuordnen und werden nach 14 Tagen automatisch gelöscht. Eine Corona-positiv getestete Person kann ihre Zufallscodes der letzten bis zu 14 Tage freiwillig mit anderen App-Nutzern teilen."</string> + <string name="main_overview_body_glossary_keys">"Die Zufalls-IDs sind zufällig erzeugte Zahlen- und Buchstabenkombinationen. Sie werden zwischen benachbarten Smartphones ausgetauscht. Zufalls-IDs lassen sich nicht einer bestimmten Person zuordnen und werden nach 14 Tagen automatisch gelöscht. Eine Corona-positiv getestete Person kann ihre Zufalls-IDs der letzten bis zu 14 Tage freiwillig mit anderen App-Nutzern teilen."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> <string name="main_overview_illustration_description">"Ein Smartphone zeigt unterschiedliche Inhalte, die von eins bis drei nummeriert sind."</string> <!-- XACT: App main page title --> @@ -345,7 +346,7 @@ <!-- YTXT: risk details - low risk explanation text --> <string name="risk_details_information_body_low_risk">"Sie haben ein niedriges Infektionsrisiko, da keine Begegnung mit nachweislich Corona-positiv getesteten Personen aufgezeichnet wurde oder sich Ihre Begegnung auf kurze Zeit und einen größeren Abstand beschränkt hat."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"Das Infektionsrisiko wird anhand der Daten der Risiko-Ermittlung unter Berücksichtigung des Abstands und der Dauer von Begegnungen mit nachweislich Corona-positiv getesteten Personen sowie deren vermutlicher Infektiosität lokal auf Ihrem Endgerät berechnet. Ihr Infektionsrisiko ist für niemanden einsehbar und wird nicht weitergegeben."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"Das Infektionsrisiko wird anhand der Daten der Risiko-Ermittlung unter Berücksichtigung des Abstands und der Dauer von Begegnungen mit nachweislich Corona-positiv getesteten Personen sowie deren vermutlicher Infektiosität lokal auf Ihrem Smartphone berechnet. Ihr Infektionsrisiko ist für niemanden einsehbar und wird nicht weitergegeben."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> <item quantity="one">"Sie haben ein erhöhtes Infektionsrisiko, da Sie zuletzt vor %1$s Tag mindestens einer nachweislich Corona-positiv getesteten Person über einen längeren Zeitraum und mit einem geringen Abstand begegnet sind."</item> @@ -372,6 +373,8 @@ <string name="risk_details_explanation_dialog_title">"Information zur Funktionsweise der Risiko-Ermittlung"</string> <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information--> <string name="risk_details_explanation_dialog_faq_body">"Weitere Informationen finden Sie in den FAQ."</string> + <!-- XLNK: risk explanations and informations - pointing to the faq page for more information and contains hyperlink--> + <string name="risk_details_explanation_faq_body_with_link"><a href="https://www.coronawarn.app/de/faq/#encounter_but_green">Weitere Informationen finden Sie in den FAQ.</a></string> <!-- #################################### Onboarding @@ -390,7 +393,7 @@ <!-- XTXT: onboarding - back description for screen reader --> <string name="onboarding_button_back_description">"Zurück"</string> <!-- XACT: Onboarding (together) page title --> - <string name="onboarding_onboarding_accessibility_title">"Einführung Seite 1 von 5: Gemeinsam Corona bekämpfen"</string> + <string name="onboarding_onboarding_accessibility_title">"Einführung Seite 1 von 6: Gemeinsam Corona bekämpfen"</string> <!-- XHED: onboarding(together) - fight corona --> <string name="onboarding_headline">"Gemeinsam Corona bekämpfen"</string> <!-- XHED: onboarding(together) - two/three line headline under an illustration --> @@ -398,32 +401,30 @@ <!-- YTXT: onboarding(together) - inform about the app --> <string name="onboarding_body">"Machen Sie Ihr Smartphone zum Corona-Warn-System. Überblicken Sie Ihren Risikostatus und erfahren Sie, ob in den letzten 14 Tagen Corona-positiv getestete Personen in ihrer Nähe waren."</string> <!-- YTXT: onboarding(together) - explain application --> - <string name="onboarding_body_emphasized">"Die App merkt sich Begegnungen zwischen Menschen, indem ihre Smartphones verschlüsselte Zufallscodes austauschen. Und zwar ohne dabei auf persönliche Daten zuzugreifen."</string> + <string name="onboarding_body_emphasized">"Die App merkt sich Begegnungen zwischen Menschen, indem ihre Smartphones verschlüsselte Zufalls-IDs austauschen. Und zwar ohne dabei auf persönliche Daten zuzugreifen."</string> <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Eine vielfältige Gruppe in einer Stadt benutzt Smartphones."</string> <!-- XACT: Onboarding (privacy) page title --> - <string name="onboarding_privacy_accessibility_title">"Einführung Seite 2 von 5. Datenschutz. Es folgt ein Langtext. Eine statische Weitertaste steht am unteren Rand des Bildschirms zur Verfügung."</string> + <string name="onboarding_privacy_accessibility_title">"Einführung Seite 2 von 6. Datenschutz. Es folgt ein Langtext. Eine statische Weitertaste steht am unteren Rand des Bildschirms zur Verfügung."</string> <!-- XHED: onboarding(privacy) - title --> <string name="onboarding_privacy_headline">"Datenschutz"</string> <!-- XACT: onboarding(privacy) - illustraction description, header image --> - <string name="onboarding_privacy_illustration_description">"Eine Frau mit einem Handy benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."</string> + <string name="onboarding_privacy_illustration_description">"Eine Frau mit einem Smartphone benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."</string> <!-- XACT: Onboarding (tracing) page title --> - <string name="onboarding_tracing_accessibility_title">"Einführung Seite 3 von 5: Wie Sie die Risiko Ermittlung ermöglichen"</string> + <string name="onboarding_tracing_accessibility_title">"Einführung Seite 3 von 6: Wie Sie die Risiko Ermittlung ermöglichen"</string> <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"Wie Sie die Risiko-Ermittlung ermöglichen"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> <string name="onboarding_tracing_subtitle">"Um zu erkennen, ob für Sie ein Infektionsrisiko vorliegt, müssen Sie die Risiko-Ermittlung aktivieren."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"Die Risiko-Ermittlung funktioniert, indem Ihr Handy per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren."</string> + <string name="onboarding_tracing_body">"Die Risiko-Ermittlung funktioniert, indem Ihr Smartphone per Bluetooth verschlüsselte Zufalls-IDs anderer Nutzer empfängt und Ihre eigenen Zufalls-IDs an deren Smartphones weitergibt. Die Risiko-Ermittlung lässt sich jederzeit deaktivieren. "</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body_emphasized">"Die verschlüsselten Zufallscodes geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Persönliche Daten wie Name, Adresse oder Aufenthaltsort werden zu keiner Zeit erfasst. Konkrete Rückschlüsse auf Personen sind nicht möglich."</string> + <string name="onboarding_tracing_body_emphasized">"Die verschlüsselten Zufalls-IDs geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Rückschlüsse auf einzelne Personen sind anhand der Zufalls-IDs nicht möglich."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> <string name="onboarding_tracing_easy_language_explanation"><a href="https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache">Informationen zur App in leichter Sprache und Gebärdensprache</a></string> - <!-- XHED: onboarding(tracing) - headline for consent information --> - <string name="onboarding_tracing_headline_consent">"Einwilligungserklärung"</string> - <!-- YTXT: onboarding(tracing) - body for consent information --> - <string name="onboarding_tracing_body_consent">"Um zu erfahren, ob Sie Kontakt mit einer infizierten Person hatten und für Sie ein Infektionsrisiko besteht, müssen Sie die Funktion Risiko-Ermittlung in der App aktivieren. Der Aktivierung der Risiko-Ermittlung und der damit im Zusammenhang stehenden Datenverarbeitung stimmen Sie mit Antippen des Buttons: Risiko-Ermittlung aktivieren zu."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Um die Risiko-Ermittlung nutzen zu können müssen Sie zudem auf Ihrem Smartphone die von Google bereitgestellte Kontaktaufzeichnungs-Funktion „Benachrichtigungen zu möglicher Begegnung mit COVID-19-Infizierten“ aktivieren und für die Corona-Warn-App freigeben."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Ihr Smartphone erzeugt und versendet bei aktivierter Kontaktaufzeichnung kontinuierlich Zufalls-IDs per Bluetooth, die von anderen Apple- und Android-Smartphones mit ebenfalls aktivierter Kontaktaufzeichnung in Ihrer Umgebung empfangen werden können. Umgekehrt empfängt Ihr Smartphone die Zufalls-IDs der anderen Smartphones. Die eigenen und die von anderen Smartphones empfangenen Zufalls-IDs werden im Kontaktprotokoll der Kontaktaufzeichnungs-Funktion aufgezeichnet und dort für 14 Tage gespeichert."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Zur Ermittlung Ihres Infektionsrisikos lädt die App mehrmals täglich oder auf Abfrage eine Liste mit den Zufalls-IDs aller Nutzer, die Ihre Infektion mit dem Corona-Virus in der App geteilt haben. Diese Liste wird dann mit den im Kontaktprotokoll der Kontaktaufzeichnungs-Funktion gespeicherten Zufalls-IDs verglichen. Wenn die App dabei feststellt, dass Sie möglicherweise Kontakt zu einem infizierten Nutzer gehabt haben, werden Sie von der App informiert, dass Sie mit einer infizierten Person in Kontakt waren und insoweit ein Infektionsrisiko besteht. In diesem Fall erhält die App außerdem Zugriff auf weitere im Kontaktprotokoll der Kontaktaufzeichnungs-Funktion Ihres Smartphones gespeicherte Daten (Datum und Dauer sowie Bluetooth-Signalstärke des Kontakts)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Aus der Bluetooth-Signalstärke wird der räumliche Abstand abgeleitet (je stärker das Signal, desto geringer der Abstand). Diese Angaben werden von der App ausgewertet, um Ihr Gesundheitsrisiko durch eine Infektion mit dem Corona-Virus abzuschätzen und Ihnen Empfehlungen für die nächsten Schritte zu geben. Diese Auswertung wird ausschließlich lokal auf Ihrem Smartphone durchgeführt. Außer Ihnen erfährt niemand (auch nicht das RKI), ob Sie mit einer infizierten Person Kontakt hatten und welches Risiko für Sie ermittelt wird."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Zum Widerruf Ihrer Einwilligung in die Risiko-Ermittlung können Sie die Funktion über den Schieberegler innerhalb der App deaktivieren oder die App löschen. Wenn Sie die Risiko-Ermittlung wieder nutzen möchten, können Sie den Schieberegler erneut aktivieren oder die App erneut installieren. Wenn Sie die Risiko-Ermittlung deaktivieren, prüft die App nicht mehr, ob Sie Kontakt zu einem infizierten Nutzer gehabt haben. Um auch die Aussendung und den Empfang der Zufalls-IDs anzuhalten, müssen Sie das Kontaktprotokoll der Kontaktaufzeichnungs-Funktion in den Einstellungen Ihres Smartphones deaktivieren. Bitte beachten Sie, dass die im Kontaktprotokoll aufgezeichneten fremden und eigenen Zufalls-Kennungen nicht in der App gelöscht werden. Die im Kontaktprotokoll gespeicherten Daten können Sie nur in den Einstellungen Ihres Smartphones dauerhaft löschen."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Die Datenschutzhinweise der App (einschließlich Informationen zur Datenver1arbeitung für die Risiko-Ermittlung) finden Sie unter dem Menüpunkt „Datenschutzinformation“."</string> + <!-- NOTR: onboarding(tracing) - easy language explain tracing link URL--> + <string name="onboarding_tracing_easy_language_explanation_url">"https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache"</string> <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_button_next">"Risiko-Ermittlung aktivieren"</string> <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined --> @@ -465,17 +466,17 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Geräte-Einstellungen öffnen"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Einführung Seite 4 von 5: Falls Sie positiv getestet wurden"</string> + <string name="onboarding_test_accessibility_title">"Einführung Seite 5 von 6: Falls Sie positiv getestet wurden"</string> <!-- XHED: onboarding(test) - about positive tests --> <string name="onboarding_test_headline">"Falls Sie Corona-positiv getestet werden …"</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> <string name="onboarding_test_subtitle">"… teilen Sie es bitte über die Corona-Warn-App mit. Freiwillig und sicher. Für die Gesundheit aller."</string> <!-- YTXT: onboarding(test) - explain test --> - <string name="onboarding_test_body">"Ihre Mitteilung wird zuverlässig verschlüsselt über einen sicheren Server weiterverarbeitet. Die Personen, deren verschlüsselte Zufallscodes Sie gesammelt haben, erhalten nun eine Warnung und Informationen darüber, wie sie weiter vorgehen sollen."</string> + <string name="onboarding_test_body">"Ihre Mitteilung wird zuverlässig verschlüsselt über einen sicheren Server weiterverarbeitet. Die Personen, deren verschlüsselte Zufalls-IDs Sie gesammelt haben, erhalten nun eine Warnung und Informationen darüber, wie sie weiter vorgehen sollen."</string> <!-- XACT: onboarding(test) - illustraction description, header image --> <string name="onboarding_test_illustration_description">"Ein positiver Testbefund wird verschlüsselt ins System übermittelt, das nun andere Nutzerinnen und Nutzer warnt."</string> <!-- XACT: Onboarding (datashare) page title --> - <string name="onboarding_notifications_accessibility_title">"Einführung Seite 5 von 5: Warnungen erhalten und Risiken erkennen"</string> + <string name="onboarding_notifications_accessibility_title">"Einführung Seite 6 von 6: Warnungen erhalten und Risiken erkennen"</string> <!-- XHED: onboarding(datashare) - about positive tests --> <string name="onboarding_notifications_headline">"Warnungen erhalten, Risiken kennen"</string> <!-- XHED: onboarding(datashare) - two/three line headline under an illustration --> @@ -485,6 +486,17 @@ <!-- XACT: onboarding(notifications) - illustraction description, header image --> <string name="onboarding_notifications_illustration_description">"Eine Frau erhält eine Mitteilung von ihrer Corona-Warn-App."</string> + <!-- #################################### + Onboarding sixteen include + ###################################### --> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_title_text">"App-Nutzung ab 16 Jahren"</string> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_description_text">"Die App-Nutzung ist ab 16 Jahren gestattet und richtet sich an Personen, die sich in Deutschland aufhalten."</string> + + <!-- #################################### Settings ###################################### --> @@ -498,9 +510,9 @@ <!-- XHED: settings(tracing) - page title --> <string name="settings_tracing_title">"Risiko-Ermittlung"</string> <!-- XHED: settings(tracing) - headline bellow illustration --> - <string name="settings_tracing_headline">"So funktioniert die Begegnungs-Aufzeichnung"</string> + <string name="settings_tracing_headline">"So funktioniert die Risiko-Ermittlung"</string> <!-- XTXT: settings(tracing) - explain text in settings overview under headline --> - <string name="settings_tracing_body_description">"Erlauben Sie Erfassung und Weitergabe von COVID-19-Zufallscodes."</string> + <string name="settings_tracing_body_description">"Erlauben Sie Erfassung und Weitergabe von COVID-19-Zufalls-IDs."</string> <!-- XTXT: settings(tracing) - shows status under header in home, active --> <string name="settings_tracing_body_active">"Risiko-Ermittlung aktiv"</string> <!-- XTXT: settings(tracing) - shows status under header in home, inactive --> @@ -508,7 +520,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"Standortdienste deaktiviert"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"Um zu erkennen, ob für Sie ein Infektionsrisiko vorliegt, müssen Sie die Risiko-Ermittlung aktivieren. Die Risiko-Ermittlung funktioniert, indem Ihr Handy per Bluetooth verschlüsselte Zufallscodes anderer Nutzerinnen und Nutzer empfängt und Ihren eigenen Zufallscode an deren Smartphones weitergibt. Die Funktion lässt sich jederzeit wieder deaktivieren."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Die verschlüsselten Zufallscodes geben nur Auskunft über das Datum, die Dauer und die anhand der Signalstärke berechnete Entfernung zu Ihren Mitmenschen. Persönliche Daten wie Name, Adresse oder Aufenthaltsort werden zu keiner Zeit erfasst. Konkrete Rückschlüsse auf Personen sind nicht möglich."</string> + <string name="settings_tracing_body_text">"Um zu erkennen, ob für Sie ein Infektionsrisiko vorliegt, müssen Sie die Risiko-Ermittlung aktivieren. Die Risiko-Ermittlung funktioniert länderübergreifend, so dass auch RisikoBegegnungen mit Nutzern von anderen offiziellen Corona-Apps erkannt werden.\n\nDie Risiko-Ermittlung funktioniert, indem Ihr Smartphone per Bluetooth verschlüsselte Zufalls-IDs anderer Nutzer empfängt und Ihre eigenen Zufalls-IDs an deren Smartphone weitergibt. Die App lädt täglich eine Liste mit den Zufalls-IDs und eventuellen Angaben zum Symptombeginn aller Corona-positiv getesteten Nutzer herunter, die diese freiwillig über ihre App geteilt haben. Diese Liste wird dann mit den von Ihrem Smartphone aufgezeichneten Zufalls-IDs anderer Nutzer verglichen, um Ihr Infektionsrisiko zu berechnen und Sie zu warnen. Die Risiko-Ermittlung lässt sich jederzeit über den Schieberegler deaktivieren.\n\nPersönliche Daten wie Ihr Name, Ihre Adresse oder Ihr Aufenthaltsort werden über die App zu keiner Zeit erfasst oder an andere Nutzer übermittelt. Rückschlüsse auf Ihre Identität, Ihren Namen oder andere persönliche Angaben sind anhand der Zufalls-IDs nicht möglich."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Aktiv"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -528,7 +540,9 @@ <!--XHED : settings(tracing) - headline on card about the current status and what to do --> <string name="settings_tracing_status_location_headline">"Standort-Verwendung erlauben"</string> <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled --> - <string name="settings_tracing_status_location_body">"Auf Ihren Standort wird nicht zugegriffen. Die Standort-Erlaubnis wird benötigt, da Google bzw. Android diese für die Verwendung von Bluetooth voraussetzt."</string> + <string name="settings_tracing_status_location_body">"Aktivieren Sie die Standort-Dienste. Für die Abstandsberechnung benötigt Bluetooth Low Energy aktivierte Standort-Dienste, greift dabei aber nicht auf Ihren Standort zu. Weitere Informationen finden Sie in der FAQ."</string> + <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL --> + <string name="settings_tracing_status_location_body_url">https://www.coronawarn.app/de/faq/#android_location</string> <!-- XBUT: settings(tracing) - go to operating system settings button on card - location --> <string name="settings_tracing_status_location_button">"Geräte-Einstellungen öffnen"</string> <!--XHED : settings(tracing) - headline on card about the current status and what to do --> @@ -553,7 +567,7 @@ <!-- XACT: settings(tracing) - describes illustration --> <string name="settings_tracing_bluetooth_illustration_description_inactive">"Eine Person hat Bluetooth auf ihrem Smartphone ausgeschaltet, eine Begegnung mit zwei weiteren Personen wird daher nicht aufgezeichnet."</string> <!-- XACT: settings(tracing) - describes illustration --> - <string name="settings_tracing_location_illustration_description_inactive"/> + <string name="settings_tracing_location_illustration_description_inactive" /> <!-- XACT: settings(tracing) - describes illustration --> <string name="settings_tracing_connection_illustration_description_inactive">"Eine Person hat die Internetverbindung auf ihrem Smartphone ausgeschaltet, eine Begegnung mit zwei weiteren Personen wird daher nicht aufgezeichnet."</string> @@ -614,11 +628,11 @@ <!-- XTXT: settings(background priority) - text in row on settings overview --> <string name="settings_background_priority_body_description">"Erlauben Sie die automatische Aktualisierung Ihres Risikostatus."</string> <!-- XHED: settings(background priority) - multiline headline below illustration --> - <string name="settings_background_priority_headline">"Corona-Warn-App im Hintergrund ausführen"</string> + <string name="settings_background_priority_headline">"Risikostatus immer automatisch aktualisieren"</string> <!-- YTXT: settings(background priority) - description text --> - <string name="settings_background_priority_body">"Wenn Sie die priorisierte Hintergrundaktivität anschalten, wird die Corona-Warn-App dauerhaft im Hintergrund ausgeführt. So kann die App jederzeit Ihren Risikostatus ermitteln."</string> + <string name="settings_background_priority_body">"Wenn Sie die Priorisierte Hintergrundaktivität einschalten, kann die App Ihren Risikostatus immer automatisch prüfen. Damit wird die Optimierung des Akku-Verbrauchs ausschließlich für die Corona-Warn-App deaktiviert."</string> <!-- XACT: settings(background priority) - illustraction description --> - <string name="settings_background_priority_illustration_description"/> + <string name="settings_background_priority_illustration_description" /> <!-- XTXT: settings(background priority) - explains user what to do on card if background priority is enabled --> <string name="settings_background_priority_card_body">"Um die priorisierte Hintergrundaktivität auszuschalten, deaktivieren Sie sie bitte in den Geräte-Einstellungen."</string> <!-- XBUT: settings(background priority) - go to operating system settings button on card --> @@ -647,7 +661,7 @@ <!-- XHED: Page title for privacy information page, also menu item / button text --> <string name="information_privacy_title">"Datenschutz"</string> <!-- XACT: describes illustration --> - <string name="information_privacy_illustration_description">"Eine Frau mit einem Handy benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."</string> + <string name="information_privacy_illustration_description">"Eine Frau mit einem Smartphone benutzt die Corona-Warn-App, ein Vorhängeschloss auf einem Schild steht als Symbol für verschlüsselte Daten."</string> <!-- XTXT: Path to the full blown privacy html, to translate it exchange "_de" to "_en" and provide the corresponding html file --> <string name="information_privacy_html_path">"privacy_de.html"</string> <!-- XHED: Page title for terms of use information page, also menu item / button text --> @@ -663,7 +677,7 @@ <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_headline">"Wie können wir Ihnen helfen?"</string> <!-- YTXT: Body text for technical contact and hotline information page --> - <string name="information_contact_body">"Für technische Fragen rund um die Corona-Warn-App können Sie sich direkt an unsere technische Hotline wenden."</string> + <string name="information_contact_body">"Für technische Fragen rund um die Corona-Warn-App können Sie sich direkt an unsere technische Hotline wenden.\n\nGehörlose, schwerhörige und spätertaubte Menschen können zur telefonischen Kontaktaufnahme die Tess-Relay-Dienste (Dolmetschen in Gebärdensprache und deutscher Schriftsprache) nutzen. Die Software können Sie in Ihrem App Store / Play Store herunterladen."</string> <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_subtitle_phone">"Technische Hotline:"</string> <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page --> @@ -700,17 +714,24 @@ <string name="information_legal_headline_contact">"Kontakt"</string> <!-- YTXT: subtitle for legal information page, contact section --> <string name="information_legal_subtitle_contact">"E-Mail: CoronaWarnApp@rki.de"</string> - <!-- YTXT: subtitle for legal information page, open contact form --> - <string name="information_legal_subtitle_contact_form"><a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">Kontaktformular</a></string> + <!-- YTXT: subtitle for legal information page, open contact form : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_label">"Kontaktformular"</string> + <!-- YTXT: subtitle for legal information page url : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_url">"https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html"</string> <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German --> <string name="information_legal_subtitle_contact_form_non_en_de">Contact Form in <a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">English</a> or <a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">German</a></string> <!-- XHED: Headline for legal information page, tax section --> - <string name="information_legal_headline_taxid">"Umsatzsteueridentifikationsnummer"</string> + <string name="information_legal_headline_taxid">"Umsatzsteuer-\nIdentifikationsnummer"</string> <!-- YTXT: subtitle for legal information page, tax section --> <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string> <!-- XACT: describes illustration --> <string name="information_legal_illustration_description">"Eine Hand hält ein Smartphone mit viel Text, daneben ist ein Paragraphenzeichen als Symbol für das Impressum."</string> + <!-- #################################### + Interoperability + ###################################### --> + <!-- XHED: headline for consent information --> + <string name="interop_consent_headline">"Einwilligungserklärung"</string> <!-- #################################### Submission @@ -725,10 +746,14 @@ <!-- XBUT: Positive button for generic web request error --> <string name="submission_error_dialog_web_generic_error_button_positive">"Zurück"</string> - <!-- XHED: Dialog title for already paired test error --> - <string name="submission_error_dialog_web_test_paired_title">"Fehler"</string> - <!-- XMSG: Dialog body for already paired test error --> - <string name="submission_error_dialog_web_test_paired_body">"Der QR-Code / Die TAN ist ungültig oder wurde schon verwendet. Bitte versuchen Sie es erneut oder kontaktieren Sie die technische Hotline über App-Informationen → Technische Hotline."</string> + <!-- XHED: Dialog title for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_title">"QR-Code ist ungültig"</string> + <!-- XMSG: Dialog body for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_body">"Der QR-Code ist ungültig oder wurde bereits auf einem Smartphone registriert. Ihr Testergebnis bekommen Sie vom Testcenter oder Labor, unabhängig von der Gültigkeit des QR-Codes. Wenn Ihr Test positiv ausfällt, bekommen Sie vom Gesundheitsamt eine Mitteilung."</string> + <!-- XHED: Dialog title for already paired test error: tan --> + <string name="submission_error_dialog_web_test_paired_title_tan">"TAN ist ungültig"</string> + <!-- XMSG: Dialog body for already paired test via tan - error: tan --> + <string name="submission_error_dialog_web_test_paired_body_tan">"Die TAN ist ungültig oder wurde bereits verwendet. Bitte rufen Sie die unter „TAN anfragen“ angegebene Nummer an, um weitere Informationen zu erhalten."</string> <!-- XBUT: Positive button for already paired test error --> <string name="submission_error_dialog_web_test_paired_button_positive">"Zurück"</string> @@ -753,6 +778,15 @@ <!-- XBUT: Positive button for submission tan redeemed --> <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> + <!-- XHED: Dialog title for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_title">"Wollen Sie wirklich abbrechen?"</string> + <!-- XMSG: Dialog body for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_body">"Ihre bisherigen Angaben werden nicht gespeichert."</string> + <!-- XBUT: Positive button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_positive">"Ja"</string> + <!-- XBUT: Negative button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_negative">"Nein"</string> + <!-- Permission Rationale Dialog --> <!-- XHED: Dialog headline QR Scan permission rationale --> <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Kamera-Zugriff benötigt"</string> @@ -809,16 +843,16 @@ <string name="submission_test_result_negative_steps_negative_body">"Der Labortest hat keinen Nachweis für das Coronavirus SARS-CoV-2 bei Ihnen ergeben. \n\nBitte entfernen Sie den Test wieder aus der Corona-Warn-App, damit Sie bei Bedarf einen neuen Test hinterlegen können."</string> <!-- XBUT: negative test result : remove the test button --> <string name="submission_test_result_negative_remove_test_button">"Test entfernen"</string> - <!-- XHED: Page headline for positive test result screen --> - <string name="submission_test_result_positive_steps_positive_heading">"Ihr Testergebnis"</string> - <!-- YTXT: Body text for next steps section of test positive result--> - <string name="submission_test_result_positive_steps_positive_body">"Ihr Testergebnis wurde als positiv verifiziert."</string> <!-- XHED: Page headline for other warnings screen --> <string name="submission_test_result_positive_steps_warning_others_heading">"Andere warnen"</string> <!-- YTXT: Body text for for other warnings screen--> - <string name="submission_test_result_positive_steps_warning_others_body">"Ihre Zufallscodes der letzten 14 Tage teilen, um andere zu schützen und die Infektionskette zu unterbrechen."</string> + <string name="submission_test_result_positive_steps_warning_others_body">"Teilen Sie Ihre Zufalls-IDs und warnen Sie andere.\nHelfen Sie, das Infektionsrisiko für andere genauer zu bestimmen, indem Sie auch angeben, wann eventuelle Corona-Symptome zum ersten Mal aufgetreten sind."</string> <!-- XBUT: positive test result : continue button --> <string name="submission_test_result_positive_continue_button">"Weiter"</string> + <!-- XBUT: positive test result : continue button with symptoms--> + <string name="submission_test_result_positive_continue_button_with_symptoms">"Weiter mit Symptom-Erfassung"</string> + <!-- XBUT: positive test result : continue button without symptoms --> + <string name="submission_test_result_positive_continue_button_wo_symptoms">"Weiter ohne Symptom-Erfassung"</string> <!-- XHED: Page headline for invalid test result screen --> <string name="submission_test_result_invalid_steps_invalid_heading">"Ihr Testergebnis"</string> <!-- YTXT: Body text for next steps section of invalid test result--> @@ -854,9 +888,9 @@ <!-- XACT: Submission Tan page title --> <string name="submission_tan_accessibility_title">"TAN-Eingabe"</string> <!-- YTXT: Error text for the tan submission page --> - <string name="submission_tan_error">"Ungültige TAN, bitte überprüfen Sie Ihre Eingabe."</string> + <string name="submission_tan_error">"Ungültige TAN. Bitte überprüfen Sie Ihre Eingabe."</string> <!-- YTXT: Error text for the tan submission page (wrong characters) --> - <string name="submission_tan_character_error">"Ungültige Eingabe, bitte überprüfen Sie das Zeichen."</string> + <string name="submission_tan_character_error">"Ihre Eingabe enthält ein ungültiges Zeichen. Bitte überprüfen Sie Ihre Eingabe."</string> <!-- Submission Intro --> <!-- XHED: Page title for menu at the start of the submission process --> @@ -864,7 +898,7 @@ <!-- XHED: Page headline for menu the at start of the submission process --> <string name="submission_intro_headline">"So funktioniert das Corona-Warn-System"</string> <!-- YTXT: submission introduction text --> - <string name="submission_intro_text">"Damit die Corona-Warn-App funktioniert, sind wir auf die Mithilfe von Corona-positiv getesteten Personen angewiesen.\n\nDa nur verschlüsselte Zufallscodes ausgetauscht werden, bleiben Sie unerkannt. Sie können jetzt wie folgt vorgehen:"</string> + <string name="submission_intro_text">"Damit die Corona-Warn-App funktioniert, sind wir auf die Mithilfe von Corona-positiv getesteten Personen angewiesen.\n\nDa nur verschlüsselte Zufalls-IDs ausgetauscht werden, bleiben Sie unerkannt. Sie können jetzt wie folgt vorgehen:"</string> <!-- XBUT: Submission introduction next button--> <string name="submission_intro_button_next">"Weiter"</string> <!-- XACT: Submission intro - illustration description, explanation image --> @@ -912,16 +946,27 @@ <!-- XHED: Page headline for the positive result additional warning page--> <string name="submission_positive_other_warning_headline">"Helfen Sie mit!"</string> <!-- YTXT: Body text for the positive result additional warning page--> - <string name="submission_positive_other_warning_body">"Als Nächstes können Sie dafür sorgen, dass das Corona-Warn-System Ihre lokal gespeicherten Zufallscodes der letzten 14 Tage an andere verteilt. So können Sie Ihre Mitmenschen warnen und helfen, die Infektionskette zu unterbrechen.\n\nDa nur unpersönliche Zufallscodes übertragen werden, bleibt Ihre Identität unbekannt."</string> - <!-- XHED: Title for the privacy card--> - <string name="submission_positive_other_warning_privacy_title">"Datenschutz"</string> - <!-- YTXT: Body text for the privacy card--> - <string name="submission_positive_other_warning_privacy_body">"Durch Antippen von „Weiter“ willigen Sie ein, dass die App Ihr positives Testergebnis zusammen mit Ihren Zufalls-IDs der letzten 14 Tage an das Serversystem der App übermittelt, damit andere App-Nutzer mit aktivierter Risiko-Ermittlung automatisch informiert werden können, dass sie möglicherweise einem Infektionsrisiko ausgesetzt waren. Die übermittelten Zufalls-IDs enthalten keine Angaben, die Rückschlüsse auf Ihre Identität oder Ihre Person zulassen.\n\nDie Ãœbermittlung Ihres Testergebnisses per App ist freiwillig. Wenn Sie Ihr Testergebnis nicht übermitteln, entstehen Ihnen keine Nachteile. Da weder nachvollzogen noch kontrolliert werden kann, ob und wie Sie die App verwenden, erfährt außer Ihnen niemand, ob Sie eine Infektion übermittelt haben.\n\nSie können Ihre Einwilligung jederzeit widerrufen, indem Sie die App löschen. Durch den Widerruf der Einwilligung wird die Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten Verarbeitung nicht berührt. Weitere Informationen finden Sie unter dem Menüpunkt „Datenschutzinformation“."</string> + <string name="submission_positive_other_warning_body">"Als Nächstes können Sie dafür sorgen, dass Ihre Mitmenschen vor einer möglichen Infektion gewarnt werden.\n\nHierfür können Sie Ihre eigenen Zufalls-IDs der letzten 14 Tage und optional auch Angaben zum ersten Auftreten von eventuellen Corona-Symptomen an den von den teilnehmenden Ländern gemeinsam betriebenen Austausch-Server übertragen. Von dort werden Ihre Zufalls-IDs und eventuelle weitere Angaben an die Nutzer der jeweiligen offiziellen Corona-Apps verteilt. So können die anderen Nutzer, mit denen Sie Kontakt hatten, vor einer eventuellen Ansteckung gewarnt werden.\n\nEs werden nur Zufalls-IDs und eventuelle Angaben zum Symptombeginn übertragen. Es werden keine persönlichen Daten wie Ihr Name, Ihre Adresse oder Ihr Aufenthaltsort mitgeteilt."</string> <!-- XBUT: other warning continue button --> - <string name="submission_positive_other_warning_button">"Weiter"</string> + <string name="submission_positive_other_warning_button">"Einverstanden"</string> <!-- XACT: other warning - illustration description, explanation image --> <string name="submission_positive_other_illustration_description">"Ein Smartphone übermittelt einen positiven Testbefund verschlüsselt ins System."</string> + <!-- XHED: Title for the interop country list--> + <string name="submission_interoperability_list_title">"Folgende Länder nehmen derzeit an der länderübergreifenden Risiko-Ermittlung teil:"</string> + <!-- Submission Country Selector --> + <!-- XHED: Page title for the submission country selection page --> + <string name="submission_positive_country_selection_title">"Europaweit warnen"</string> + <!-- XHED: Page headline for the submission country selection page --> + <string name="submission_positive_country_selection_headline">"In welchen Ländern haben Sie sich in den letzten 14 Tagen aufgehalten?"</string> + <!-- XHED: Country selector headline for the submission country selection page --> + <string name="submission_country_selector_headline">"Ich war in den folgenden Ländern"</string> + <!-- XHED: Country no selection headline for the submission country selection page --> + <string name="submission_country_no_selection_headline">"Keine Angabe"</string> + <!-- YTXT: Data FAQ for the submission country selection page --> + <string name="submission_country_selection_data_faq_body">"Ihre Angabe dient lediglich der Optimierung des Datenvolumens.\n\nDie Auflistung enthält alle aktuell teilnehmenden Länder und wird stetig erweitert."</string> + <!-- XBUT: submission country selection continue button --> + <string name="submission_country_selection_button">"Weiter"</string> <!-- Submission Done --> <!-- XHED: Page title for completed submission page --> @@ -931,7 +976,7 @@ <!-- XHED: Page subtitle for completed submission page --> <string name="submission_done_subtitle">"Bitte beachten Sie:"</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"Sie sind ansteckend."</string> + <string name="submission_done_contagious">"Das Gesundheitsamt wird sich in den nächsten Tagen bei Ihnen melden."</string> <!-- YTXT: text after submission: isolate --> <string name="submission_done_isolate">"Bitte isolieren Sie sich von anderen Personen."</string> <!-- XHED: Title for further info --> @@ -946,7 +991,35 @@ <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Fertig"</string> <!-- XACT: submission finished - illustration description, explanation image --> - <string name="submission_done_illustration_description">"Eine vielfältige Gruppe begrüßt durch Jubel, dass jemand sein Testergebnis mit anderen geteilt hat."</string> + <string name="submission_done_illustration_description">"Sind eines oder mehrere der folgenden Symptome in den letzten Tagen bei Ihnen neu aufgetreten?"</string> + + <!-- Submission Symptoms --> + <!-- XHED: Page title for symptom screens --> + <string name="submission_symptom_title">"Symptome"</string> + <!-- XTXT: headline text for initial symptom screen --> + <string name="submission_symptom_initial_headline">"Sind bei Ihnen in den letzten Tagen folgende Symptome aufgetreten?"</string> + <!-- YTXT: explanation text for initial symptom screen --> + <string name="submission_symptom_initial_explanation">"Wenn Sie angeben, ob und wann eventuelle Corona-Symptome bei Ihnen aufgetreten sind, kann das Infektionsrisiko von anderen App-Nutzern genauer berechnet werden. Sie müssen keine Angabe machen, wählen Sie dazu „Keine Angabe“."</string> + <!-- YTXT: Bullet points for symptoms --> + <string-array name="submission_symptom_symptom_bullets"> + <item>"Erhöhte Temperatur oder Fieber"</item> + <item>"Kurzatmigkeit"</item> + <item>"Verlust des Geruchs-/Geschmackssinns"</item> + <item>"Husten"</item> + <item>"Schnupfen"</item> + <item>"Halsschmerzen"</item> + <item>"Kopf- und Gliederschmerzen"</item> + <item>"Allgemeine Schwäche und Abgeschlagenheit"</item> + </string-array> + <!-- XBUT: symptom initial screen yes button --> + <string name="submission_symptom_positive_button">"Ja"</string> + <!-- XBUT: symptom initial screen no button --> + <string name="submission_symptom_negative_button">"Nein"</string> + <!-- XBUT: symptom initial screen no information button --> + <string name="submission_symptom_no_information_button">"Keine Angabe"</string> + <!-- XBUT: symptom initial screen continue button --> + <string name="submission_symptom_further_button">"Weiter"</string> + <!-- Submission Contact --> <!-- XHED: Page title for contact page in submission flow --> @@ -977,6 +1050,22 @@ <!-- XACT: Content Description for submission contact step 2 --> <string name="submission_contact_step_2_content">"Im zweiten Schritt registrieren Sie den Test per TAN-Eingabe in der App."</string> + <!-- Submission Symptom Calendar --> + <!-- XHED: Page title for calendar page in submission symptom flow --> + <string name="submission_symptom_calendar_title">"Symptom-Beginn"</string> + <!-- XHED: Page headline for calendar page in symptom submission flow --> + <string name="submission_symptom_calendar_headline">"Wann sind die Symptome bei Ihnen aufgetreten? "</string> + <!-- YTXT: Body text for calendar page in symptom submission flow--> + <string name="submission_symptom_calendar_body">"Selektieren Sie entweder das genaue Datum in dem Kalender oder wenn Sie sich nicht genau erinnern, eine der anderen Optionen."</string> + <!-- XBUT: symptom calendar screen less than 7 days button --> + <string name="submission_symptom_less_seven">"In den letzten 7 Tagen"</string> + <!-- XBUT: symptom calendar screen 1-2 weeks button --> + <string name="submission_symptom_one_two_weeks">"Vor 1-2 Wochen"</string> + <!-- XBUT: symptom calendar screen more than 2 weeks button --> + <string name="submission_symptom_more_two_weeks">"Vor mehr als 2 Wochen"</string> + <!-- XBUT: symptom calendar screen verify button --> + <string name="submission_symptom_verify">"Keine Angabe"</string> + <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> <string name="submission_status_card_title_fetching">"Datenabruf…"</string> @@ -995,7 +1084,7 @@ <!-- YTXT: Body text for submission status: fetching --> <string name="submission_status_card_body_fetching">"Das Ergebnis wird aktualisiert"</string> <!-- YTXT: Body text for submission status: unregistered --> - <string name="submission_status_card_body_unregistered">"Helfen Sie mit, die Infektionskette zu durchbrechen und informieren Sie andere."</string> + <string name="submission_status_card_body_unregistered">"Helfen Sie mit, die Infektionskette zu durchbrechen, und informieren Sie andere."</string> <!-- YTXT: Body text for submission status: pending --> <string name="submission_status_card_body_pending">"Die Auswertung Ihres Tests ist noch nicht abgeschlossen."</string> <!-- YTXT: Body text for submission status: invalid --> @@ -1013,9 +1102,9 @@ <!-- YTXT: text for contagious card --> <string name="submission_status_card_positive_result_contagious">"Sie sind ansteckend. Isolieren Sie sich von anderen Personen."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"Das Gesundheitsamt wird sich in den nächsten Tagen telefonisch oder schriftlich bei Ihnen melden."</string> + <string name="submission_status_card_positive_result_contact">"Das Gesundheitsamt wird sich in den nächsten Tagen bei Ihnen melden."</string> <!-- YTXT: text for share result card--> - <string name="submission_status_card_positive_result_share">"Teilen Sie Ihre Zufallscodes, damit andere gewarnt werden können."</string> + <string name="submission_status_card_positive_result_share">"Teilen Sie Ihre Zufalls-IDs, damit andere gewarnt werden können."</string> <!-- Test Result Card --> <string name="test_result_card_headline">"Ihr Befund:"</string> @@ -1040,6 +1129,9 @@ <item>"Gehen Sie nicht krank zur Arbeit, um andere Personen nicht zu gefährden. Falls sich Ihre Symptome verschlechtern, kann die Notwendigkeit eines weiteren SARS-CoV-2-Tests bestehen."</item> </string-array> + <!-- XBUT Symptoms exact date button --> + <string name="symptoms_calendar_exact_date_button">"Genaues Datum"</string> + <!-- #################################### Button Tooltips for Accessibility ###################################### --> @@ -1068,7 +1160,7 @@ <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action --> <string name="errors_external_action">"Diese Aktion ist aktuell leider nicht verfügbar. Bitte kontaktieren Sie die Hotline."</string> <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update --> - <string name="errors_google_update_needed">"Ihre Corona-Warn-App ist korrekt installiert. Leider fehlt dem Betriebssystem Ihres Smartphones der Dienst „Benachrichtigungen zu möglicher Begegnung mit COVID-19-Infizierten“ und Sie können die Corona-Warn-App nicht nutzen. Weitere Informationen finden Sie in unseren FAQ: https://www.coronawarn.app/de/faq/"</string> + <string name="errors_google_update_needed">"Ihre Corona-Warn-App ist korrekt installiert. Leider fehlt dem Betriebssystem Ihres Smartphones der Dienst „COVID-19-Benachrichtigungen“ und Sie können die Corona-Warn-App nicht nutzen. Weitere Informationen finden Sie in unseren FAQ: https://www.coronawarn.app/de/faq/"</string> <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day --> <string name="errors_google_api_error">"Ihre Corona-Warn-App läuft fehlerfrei. Leider können Sie Ihren Risikostatus im Moment nicht aktualisieren. Ihre Risiko-Ermittlung ist weiterhin aktiv und funktioniert. Weitere Informationen finden Sie in unseren FAQ: https://www.coronawarn.app/de/faq/"</string> @@ -1085,6 +1177,10 @@ <string name="errors_generic_button_negative">"Details"</string> <!-- XTXT: error dialog - text when no error description is available --> <string name="errors_generic_text_unknown_error_cause">"Ein unbekannter Fehler ist aufgetreten."</string> + <!-- XTXT: error dialog - text when a catastrophic error occured from which the app recovered automatically via data reset --> + <string name="errors_generic_text_catastrophic_error_recovery_via_reset">"Aufgrund eines technischen Problems wurde Ihre App zurückgesetzt. Dies hat keine Auswirkung auf die Risiko-Ermittlung und damit auf Ihren Risikostatus. Sie werden weiterhin über Risiko-Begegnungen benachrichtigt und können andere warnen, falls Sie positiv auf COVID-19 getestet wurden. Durch das Zurücksetzen der App gehen aber zuvor eingelesene QR-Codes für die elektronische Benachrichtigung über Ihre Testergebnisse verloren. Bitte wenden Sie sich an Ihren Hausarzt oder Labor, um Ihr Testergebnis zu erfahren."</string> + <!-- XTXT: error dialog - link for the details button in the catastrophic error recovery dialog --> + <string name="errors_generic_text_catastrophic_error_encryption_failure">"https://www.coronawarn.app/de/faq/#cause9002_recovery"</string> <!-- #################################### Just for Development @@ -1092,10 +1188,6 @@ <!-- NOTR --> <string name="lorem_ipsum">"Lorem Ipsum"</string> <!-- NOTR --> - <string name="menu_test_api">"Test API"</string> - <!-- NOTR --> - <string name="menu_test_risk_level">"Test Risk Level"</string> - <!-- NOTR --> <string name="menu_test_notification">"Test Notification"</string> <!-- NOTR --> <string name="test_api_button_api_launch">"Android API Test(Manual Test)"</string> @@ -1136,4 +1228,121 @@ <!-- NOTR --> <string name="test_api_calculate_risk_level">"Calculate Risk Level"</string> + <!-- XHED: Country Entry for Austria --> + <string name="country_name_at">Österreich</string> + <!-- XHED: Country Entry for Belgium --> + <string name="country_name_be">Belgien</string> + <!-- XHED: Country Entry for Bulgaria --> + <string name="country_name_bg">Bulgarien</string> + <!-- XHED: Country Entry for Switzerland --> + <string name="country_name_ch">Schweiz</string> + <!-- XHED: Country Entry for Cyprus --> + <string name="country_name_cy">Zypern</string> + <!-- XHED: Country Entry for Czech Republic --> + <string name="country_name_cz">Tschechien</string> + <!-- XHED: Country Entry for Germany --> + <string name="country_name_de">Deutschland</string> + <!-- XHED: Country Entry for Denmark --> + <string name="country_name_dk">Dänemark</string> + <!-- XHED: Country Entry for Estonia --> + <string name="country_name_ee">Estland</string> + <!-- XHED: Country Entry for Spain --> + <string name="country_name_es">Spanien</string> + <!-- XHED: Country Entry for Finland --> + <string name="country_name_fi">Finland</string> + <!-- XHED: Country Entry for France --> + <string name="country_name_fr">Frankreich</string> + <!-- XHED: Country Entry for Great Britain --> + <string name="country_name_uk">Großbritannien</string> + <!-- XHED: Country Entry for Greece --> + <string name="country_name_gr">Griechenland</string> + <!-- XHED: Country Entry for Croatia --> + <string name="country_name_hr">Kroatien</string> + <!-- XHED: Country Entry for Hungary --> + <string name="country_name_hu">Ungarn</string> + <!-- XHED: Country Entry for Ireland --> + <string name="country_name_ie">Irland</string> + <!-- XHED: Country Entry for Iceland --> + <string name="country_name_is">Island</string> + <!-- XHED: Country Entry for Italy --> + <string name="country_name_it">Italien</string> + <!-- XHED: Country Entry for Liechtenstein --> + <string name="country_name_li">Liechtenstein</string> + <!-- XHED: Country Entry for Lithuania --> + <string name="country_name_lt">Litauen</string> + <!-- XHED: Country Entry for Luxemburg --> + <string name="country_name_lu">Luxemburg</string> + <!-- XHED: Country Entry for Latvia --> + <string name="country_name_lv">Lettland</string> + <!-- XHED: Country Entry for Malta --> + <string name="country_name_mt">Malta</string> + <!-- XHED: Country Entry for Netherlands --> + <string name="country_name_nl">Niederlande</string> + <!-- XHED: Country Entry for Norway --> + <string name="country_name_no">Norwegen</string> + <!-- XHED: Country Entry for Poland --> + <string name="country_name_pl">Polen</string> + <!-- XHED: Country Entry for Portugal --> + <string name="country_name_pt">Portugal</string> + <!-- XHED: Country Entry for Rumania --> + <string name="country_name_ro">Rumänien</string> + <!-- XHED: Country Entry for Sweden --> + <string name="country_name_se">Schweden</string> + <!-- XHED: Country Entry for Slovenia --> + <string name="country_name_si">Slowenien</string> + <!-- XHED: Country Entry for Slovakia --> + <string name="country_name_sk">Slowakei</string> + + <!-- XHED: Title of the interoperbaility information view. --> + <string name="interoperability_title">Länderübergreifende\nRisiko-Ermittlung</string> + + <!-- XHED: Setting title of interoperability in the tracing settings view --> + <string name="settings_interoperability_title">Länderübergreifende Risiko-Ermittlung</string> + <!-- XTXT: Settings description of the interoperability in the tracing settings view --> + <string name="settings_interoperability_subtitle">Teilnehmende Länder</string> + + <!-- XHED: Header of interoperability information/configuration view --> + <string name="interoperability_configuration_title">Länderübergreifende Risiko-Ermittlung</string> + <!-- XTXT: First section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_first_section">Mehrere Länder arbeiten zusammen, um über den gemeinsam betriebenen Austausch- Server länderübergreifende Warnungen zu ermöglichen. So können bei der Risiko-Ermittlung auch die Kontakte mit Nutzern einer offiziellen Corona-App anderer teilnehmender Länder berücksichtigt werden.</string> + <!-- XTXT: Second section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_second_section">Hierfür lädt die App täglich eine aktuelle Liste mit den Zufalls-IDs aller Nutzer herunter, die diese über ihre App geteilt haben. Diese Liste wird dann mit den von Ihrem Smartphone aufgezeichneten Zufalls-IDs verglichen. Der tägliche Download der Liste mit den Zufalls-IDs ist für Sie kostenlos – Ihr Datenvolumen wird nicht belastet und es fallen im europäischen Ausland keine Roaming-Gebühren an.</string> + <!-- XHED: Header right above the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_list_title">Derzeit nehmen die folgenden Länder an der länderübergreifenden Risiko-Ermittlung teil:</string> + <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_information">Die Datenschutzerklärung der App (einschließlich Informationen zur Datenverarbeitung für die länderübergreifende Risiko-Ermittlung) finden Sie unter dem Menüpunkt „App-Informationen“ > „Datenschutz“.</string> + + <!-- XHED: Sub header introducing interoperability in the tracing step of onboarding --> + <string name="interoperability_onboarding_title">Länderübergreifende\nRisiko-Ermittlung</string> + <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> + <string name="interoperability_onboarding_first_section">Mehrere Länder arbeiten zusammen, um länderübergreifende Warnungen zu ermöglichen. Das heißt es können die Kontakte mit Nutzern der offiziellen Corona-Apps aller teilnehmenden Länder berücksichtigt werden.</string> + <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> + <string name="interoperability_onboarding_second_section">Hat ein Nutzer seine Zufalls-IDs über den von den teilnehmenden Ländern gemeinsam betriebenen Austausch-Server zur Verfügung gestellt, können Nutzer der offiziellen Corona-Apps der teilnehmenden Länder gewarnt werden.</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_randomid_download_free">Der tägliche Download der Liste mit den Zufalls-IDs ist für Sie in der Regel kostenlos. Das heißt: Das von der App verursachte Datenvolumen wird von den Mobilfunk-Betreibern nicht angerechnet und im EU-Ausland werden Ihnen keine Roaming-Gebühren berechnet. Näheres erfahren Sie von Ihrem Mobilfunk-Betreiber.</string> + <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> + <string name="interoperability_onboarding_list_title">Derzeit nehmen die folgenden Länder teil:</string> + + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 1 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_1">Im Zuge der Erweiterung der Funktion der App wurden auch die Nutzungsbedingungen aktualisiert:</string> + <!-- XLNK: Terms of use link inside delta interoperability screen--> + <string name="interoperability_onboarding_delta_terms_link">Nutzungsbedingungen anzeigen</string> + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 2 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_2">Die Nutzungsbedingungen und die Datenschutzerklärung finden Sie auch unter dem Menüpunkt „App-Informationen“ sowie in der App-Beschreibung Ihres App Stores. Die Änderungen haben keine Auswirkungen auf Ihre Nutzung der App. Wenn Sie die App weiter nutzen oder erneut öffnen, gehen wir davon aus, dass Sie mit den aktualisierten Nutzungsbedingungen einverstanden sind.</string> + + <!-- XACT: interoperability (eu) - illustraction description, explanation image --> + <string name="interoperability_eu_illustration_description">Eine Hand hält ein Smartphone. Im Hintergrund ist Europa und die europäische Flagge illustriert</string> + + <!-- XTXT: Title for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_title_failrequest">Teilnehmende Länder</string> + <!-- XTXT: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest">Die teilnehmenden Länder können Sie jederzeit in den Details zur Risiko-Ermittlung einsehen.</string> + + <!-- YDES: Title for the interoperability onboarding if country download fails for Risk Details --> + <string name="interoperability_onboarding_list_title_riskdetection_no_network">Länder können im Moment nicht angezeigt werden.</string> + <!-- YMSW: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest_no_network">Möglicherweise wurde Ihre Internet-Verbindung unterbrochen. Bitte stellen Sie sicher, dass Sie mit dem Internet verbunden sind.</string> + <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> + <string name="interoperability_onboarding_list_button_title_no_network">Geräte-Einstellungen öffnen</string> + </resources> diff --git a/Corona-Warn-App/src/main/res/values-en/strings.xml b/Corona-Warn-App/src/main/res/values-en/strings.xml index 005b2a931e49760300082dc2fa747fd82b0c60d3..ce51ec09301929da72342485c42c919b973a0e63 100644 --- a/Corona-Warn-App/src/main/res/values-en/strings.xml +++ b/Corona-Warn-App/src/main/res/values-en/strings.xml @@ -212,7 +212,7 @@ <!-- XHED: main, FAQ --> <string name="main_about_headline">"FAQ"</string> <!-- XTXT: main, explains faq on card --> - <string name="main_about_body">"Here you can find answers to frequently asked questions about the Corona-Warn-App. You will be forwarded to an external website."</string> + <string name="main_about_body">"Here you can find answers to frequently asked questions about the Corona-Warn-App. You will be forwarded to an external German government website."</string> <!-- XTXT: FAQ link, should be translated --> <string name="main_about_link">"https://www.bundesregierung.de/corona-warn-app-faq-englisch"</string> <!-- XACT: Opens external webpage --> @@ -282,7 +282,7 @@ <!-- YTXT: App overview body for glossary notifications --> <string name="main_overview_body_glossary_notification">"The display of exposures in the Corona-Warn-App."</string> <!-- XHED: App overview subtitle for glossary keys --> - <string name="main_overview_subtitle_glossary_keys">"Random IDs"</string> + <string name="main_overview_subtitle_glossary_keys">"Random ID"</string> <!-- YTXT: App overview body for glossary keys --> <string name="main_overview_body_glossary_keys">"Random IDs are combinations of digits and letters generated randomly. They are exchanged between devices in close proximity. Random IDs cannot be traced to a specific person and are automatically deleted after 14 days. Persons diagnosed with COVID-19 can opt to share their random IDs of up to the last 14 days with other app users."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> @@ -345,7 +345,7 @@ <!-- YTXT: risk details - low risk explanation text --> <string name="risk_details_information_body_low_risk">"You have a low risk of infection because no exposure to people later diagnosed with COVID-19 was logged, or because your encounters were only for a short time and at a greater distance."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"The risk of infection is calculated locally on your device, using exposure logging data. The calculation also takes into account distance and duration of any exposure to persons diagnosed with COVID-19, as well as their potential infectiousness. Your risk of infection cannot be seen by or passed on to anyone else."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"The risk of infection is calculated locally on your smartphone, using exposure logging data. The calculation also takes into account distance and duration of any exposure to persons diagnosed with COVID-19, as well as their potential infectiousness. Your risk of infection cannot be seen by or passed on to anyone else."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> <item quantity="one">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</item> @@ -372,6 +372,8 @@ <string name="risk_details_explanation_dialog_title">"Information about exposure logging functionality"</string> <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information--> <string name="risk_details_explanation_dialog_faq_body">"For further information, please see our FAQ page."</string> + <!-- XLNK: risk explanations and informations - pointing to the faq page for more information and contains hyperlink--> + <string name="risk_details_explanation_faq_body_with_link"><a href="https://www.coronawarn.app/en/faq/#encounter_but_green">"For further information, please see our FAQ page."</a></string> <!-- #################################### Onboarding @@ -390,7 +392,7 @@ <!-- XTXT: onboarding - back description for screen reader --> <string name="onboarding_button_back_description">"Back"</string> <!-- XACT: Onboarding (together) page title --> - <string name="onboarding_onboarding_accessibility_title">"Onboarding page 1 of 5: Fighting coronavirus together"</string> + <string name="onboarding_onboarding_accessibility_title">"Onboarding page 1 of 6: Fighting coronavirus together"</string> <!-- XHED: onboarding(together) - fight corona --> <string name="onboarding_headline">"Let\'s fight coronavirus together"</string> <!-- XHED: onboarding(together) - two/three line headline under an illustration --> @@ -402,28 +404,26 @@ <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"A group of persons use their smartphones around town."</string> <!-- XACT: Onboarding (privacy) page title --> - <string name="onboarding_privacy_accessibility_title">"Onboarding page 2 of 5: Data Privacy. A long text follows. To proceed at any time, use the button at the bottom of the screen."</string> + <string name="onboarding_privacy_accessibility_title">"Onboarding page 2 of 6: Data Privacy. A long text follows. To proceed at any time, use the button at the bottom of the screen."</string> <!-- XHED: onboarding(privacy) - title --> <string name="onboarding_privacy_headline">"Data Privacy"</string> <!-- XACT: onboarding(privacy) - illustraction description, header image --> <string name="onboarding_privacy_illustration_description">"A woman uses the Corona-Warn-App on her smartphone. An icon showing a padlock on the background of a shield symbolizes encrypted data."</string> <!-- XACT: Onboarding (tracing) page title --> - <string name="onboarding_tracing_accessibility_title">"Onboarding page 3 of 5: How to Enable Exposure Logging"</string> + <string name="onboarding_tracing_accessibility_title">"Onboarding page 3 of 6: How to Enable Exposure Logging"</string> <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"How to Enable Exposure Logging"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> <string name="onboarding_tracing_subtitle">"To identify whether you are at risk of infection, you must activate the exposure logging feature."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"Exposure logging works by your device receiving, via Bluetooth, encrypted random IDs of other users and passing your own random ID to their devices. This feature can be deactivated at any time."</string> + <string name="onboarding_tracing_body">"Exposure logging works by your smartphone receiving, via Bluetooth, encrypted random IDs of other users and passing your own random IDs to their smartphones. Exposure logging can be deactivated at any time."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body_emphasized">"The encrypted random IDs only pass information about date, duration and proximity (using signal strength) to other people. Personal data such as name, address, location is never recorded. Individuals cannot be identified."</string> + <string name="onboarding_tracing_body_emphasized">"The encrypted random IDs only pass information about date, duration, and proximity (calculated from signal strength) to other people. Individuals cannot be identified based on the random IDs."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> <string name="onboarding_tracing_easy_language_explanation"><a href="https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache">"App Information in Simplified Language and Sign Language"</a></string> - <!-- XHED: onboarding(tracing) - headline for consent information --> - <string name="onboarding_tracing_headline_consent">"Declaration of Consent"</string> - <!-- YTXT: onboarding(tracing) - body for consent information --> - <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping on the “Enable†button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyses this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Informationâ€."</string> + <!-- NOTR: onboarding(tracing) - easy language explain tracing link URL--> + <string name="onboarding_tracing_easy_language_explanation_url">"https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache"</string> <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_button_next">"Activate Exposure Logging"</string> <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined --> @@ -465,7 +465,7 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Open Device Settings"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Onboarding page 4 of 5: If you are diagnosed with COVID-19..."</string> + <string name="onboarding_test_accessibility_title">"Onboarding page 5 of 6: If you are diagnosed with COVID-19..."</string> <!-- XHED: onboarding(test) - about positive tests --> <string name="onboarding_test_headline">"If you are diagnosed with COVID-19…"</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> @@ -475,7 +475,7 @@ <!-- XACT: onboarding(test) - illustraction description, header image --> <string name="onboarding_test_illustration_description">"An encrypted positive test diagnosis is transmitted to the system, which will now warn other users."</string> <!-- XACT: Onboarding (datashare) page title --> - <string name="onboarding_notifications_accessibility_title">"Onboarding page 5 of 5: Receive warnings and identify risks"</string> + <string name="onboarding_notifications_accessibility_title">"Onboarding page 6 of 6: Receive warnings and identify risks"</string> <!-- XHED: onboarding(datashare) - about positive tests --> <string name="onboarding_notifications_headline">"Receive warnings and identify risks"</string> <!-- XHED: onboarding(datashare) - two/three line headline under an illustration --> @@ -485,6 +485,17 @@ <!-- XACT: onboarding(notifications) - illustraction description, header image --> <string name="onboarding_notifications_illustration_description">"A woman receives a notification from her Corona-Warn-App."</string> + <!-- #################################### + Onboarding sixteen include + ###################################### --> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_title_text">"Age Limit: 16 and Up"</string> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_description_text">"The use of this app is intended for persons who are at least 16 years of age and who reside in Germany."</string> + + <!-- #################################### Settings ###################################### --> @@ -498,9 +509,9 @@ <!-- XHED: settings(tracing) - page title --> <string name="settings_tracing_title">"Exposure Logging"</string> <!-- XHED: settings(tracing) - headline bellow illustration --> - <string name="settings_tracing_headline">"This is how exposure logging works"</string> + <string name="settings_tracing_headline">"How exposure logging works"</string> <!-- XTXT: settings(tracing) - explain text in settings overview under headline --> - <string name="settings_tracing_body_description">"Allow COVID-19 random IDs to be generated and shared."</string> + <string name="settings_tracing_body_description">"Allow creation and sharing of COVID-19 random IDs."</string> <!-- XTXT: settings(tracing) - shows status under header in home, active --> <string name="settings_tracing_body_active">"Exposure Logging Active"</string> <!-- XTXT: settings(tracing) - shows status under header in home, inactive --> @@ -508,7 +519,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"Location services deactivated"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"You have to activate the exposure logging feature to identify whether you are at risk of infection. Risk identification works by your device receiving, via Bluetooth, encrypted random IDs of other users and passing your random ID to their devices. You can disable this feature any time."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Encrypted random IDs only pass information about date, duration, and proximity to other persons (calculated by signal strength). Personal data such as name, address, and location is never recorded. Individuals cannot be identified."</string> + <string name="settings_tracing_body_text">"You need to enable the exposure logging feature so that the app can determine whether you are at risk after encountering an infected app user. The exposure logging feature works transnationally, meaning any possible exposure involving users is also detected by other official coronavirus apps.\n\nThe exposure logging feature works by your smartphone receiving encrypted random IDs from other users via Bluetooth and passing your own random IDs to their smartphones. Every day, the app downloads a list containing the random IDs – along with any voluntary information about the onset of symptoms – of all users who have tested positive for the virus and voluntarily shared this information via their app. This list is then compared with the random IDs of other users that have been recorded by your smartphone, in order to calculate the likelihood that you have also been infected and to warn you if necessary. You can use the toggle switch to disable exposure logging at any time.\n\nThe app never collects personal data such as your name, address or location, nor is this information passed on to other users. It is not possible to use random IDs to draw conclusions about individual persons."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Active"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -528,7 +539,9 @@ <!--XHED : settings(tracing) - headline on card about the current status and what to do --> <string name="settings_tracing_status_location_headline">"Allow location access"</string> <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled --> - <string name="settings_tracing_status_location_body">"Your location cannot be accessed. Google and/or Android requires access to your device\'s location to use Bluetooth."</string> + <string name="settings_tracing_status_location_body">"Activate your location services. Bluetooth Low Energy requires activated location services to calculate physical distances, but does not access your location. For further information, please see our FAQ page."</string> + <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL --> + <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string> <!-- XBUT: settings(tracing) - go to operating system settings button on card - location --> <string name="settings_tracing_status_location_button">"Open Device Settings"</string> <!--XHED : settings(tracing) - headline on card about the current status and what to do --> @@ -614,9 +627,9 @@ <!-- XTXT: settings(background priority) - text in row on settings overview --> <string name="settings_background_priority_body_description">"Allow automatic risk status updates"</string> <!-- XHED: settings(background priority) - multiline headline below illustration --> - <string name="settings_background_priority_headline">"Run Corona-Warn-App in Background"</string> + <string name="settings_background_priority_headline">"Update Risk Status Automatically"</string> <!-- YTXT: settings(background priority) - description text --> - <string name="settings_background_priority_body">"Corona-Warn-App runs in the background permanently if you activate prioritized background activity. This enables the app to determine your risk status any time."</string> + <string name="settings_background_priority_body">"If you activate prioritized background activity, the App can determine your risk status at any time. This disables battery life optimization for the Corona-Warn-App only."</string> <!-- XACT: settings(background priority) - illustraction description --> <string name="settings_background_priority_illustration_description"/> <!-- XTXT: settings(background priority) - explains user what to do on card if background priority is enabled --> @@ -641,7 +654,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"Robert Koch Institute (RKI) is Germany’s federal public health body. The RKI publishes the Corona-Warn-App on behalf of the Federal Government. The app is intended as a digital complement to public health measures already introduced: social distancing, hygiene, and face masks."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Whoever uses the app helps to trace and break chains of infection. The app saves encounters with other people locally on your device. You are notified if you have encountered people who were later diagnosed with COVID-19. Your identity and privacy are always protected."</string> + <string name="information_about_body">"People who use the app help to trace and break chains of infection. The app saves encounters with other people locally on your device. You are notified if you have encountered people who were later diagnosed with COVID-19. Your identity and privacy are always protected."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"A group of persons use their smartphones around town."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -663,7 +676,7 @@ <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_headline">"How can we help you?"</string> <!-- YTXT: Body text for technical contact and hotline information page --> - <string name="information_contact_body">"For technical questions about the Corona-Warn-App, please contact our hotline."</string> + <string name="information_contact_body">"For technical questions about the Corona-Warn-App, please contact our hotline.\n\nPersons with hearing impairments can use Tess Relay services (interpreting between German written language and sign language) to contact the phone hotline. You can download the software from the App Store/Google Play."</string> <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_subtitle_phone">"Technical hotline:"</string> <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page --> @@ -700,17 +713,24 @@ <string name="information_legal_headline_contact">"Contact"</string> <!-- YTXT: subtitle for legal information page, contact section --> <string name="information_legal_subtitle_contact">"E-mail: CoronaWarnApp@rki.de"</string> - <!-- YTXT: subtitle for legal information page, open contact form --> - <string name="information_legal_subtitle_contact_form"><a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"Contact Form"</a></string> + <!-- YTXT: subtitle for legal information page, open contact form : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_label">"Contact Form"</string> + <!-- YTXT: subtitle for legal information page url : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_url">"https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html"</string> <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German --> <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string> <!-- XHED: Headline for legal information page, tax section --> - <string name="information_legal_headline_taxid">"VAT identification number"</string> + <string name="information_legal_headline_taxid">"VAT identification\nnumber"</string> <!-- YTXT: subtitle for legal information page, tax section --> <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string> <!-- XACT: describes illustration --> <string name="information_legal_illustration_description">"A hand holds a smartphone displaying a large body of text on the screen. Next to the text is a section symbol representing the imprint."</string> + <!-- #################################### + Interoperability + ###################################### --> + <!-- XHED: headline for consent information --> + <string name="interop_consent_headline">"Consent"</string> <!-- #################################### Submission @@ -725,10 +745,14 @@ <!-- XBUT: Positive button for generic web request error --> <string name="submission_error_dialog_web_generic_error_button_positive">"Back"</string> - <!-- XHED: Dialog title for already paired test error --> - <string name="submission_error_dialog_web_test_paired_title">"Error"</string> - <!-- XMSG: Dialog body for already paired test error --> - <string name="submission_error_dialog_web_test_paired_body">"The QR code/TAN is invalid or has been used already. Please try again or contact the technical hotline via App Information -> Technical Hotline."</string> + <!-- XHED: Dialog title for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_title">"QR code is invalid"</string> + <!-- XMSG: Dialog body for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_body">"The QR code is invalid or has been registered on another smartphone already. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with COVID-19, you will be notified by the public health authority."</string> + <!-- XHED: Dialog title for already paired test error: tan --> + <string name="submission_error_dialog_web_test_paired_title_tan">"TAN is invalid"</string> + <!-- XMSG: Dialog body for already paired test via tan - error: tan --> + <string name="submission_error_dialog_web_test_paired_body_tan">"The TAN is invalid or has already been used. For further information, call the number listed under \"Request TAN\"."</string> <!-- XBUT: Positive button for already paired test error --> <string name="submission_error_dialog_web_test_paired_button_positive">"Back"</string> @@ -753,6 +777,15 @@ <!-- XBUT: Positive button for submission tan redeemed --> <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> + <!-- XHED: Dialog title for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_title">"Do you want to cancel?"</string> + <!-- XMSG: Dialog body for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_body">"Your entries will not be saved."</string> + <!-- XBUT: Positive button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_positive">"Yes"</string> + <!-- XBUT: Negative button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_negative">"No"</string> + <!-- Permission Rationale Dialog --> <!-- XHED: Dialog headline QR Scan permission rationale --> <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Camera authorization required"</string> @@ -816,9 +849,13 @@ <!-- XHED: Page headline for other warnings screen --> <string name="submission_test_result_positive_steps_warning_others_heading">"Warning Others"</string> <!-- YTXT: Body text for for other warnings screen--> - <string name="submission_test_result_positive_steps_warning_others_body">"Share your random IDs of the last 14 days in order to protect others and break the chain of infection."</string> + <string name="submission_test_result_positive_steps_warning_others_body">"Share your random IDs and warn others.\nHelp determine the risk of infection for others more accurately by also indicating when you first noticed any coronavirus symptoms."</string> <!-- XBUT: positive test result : continue button --> <string name="submission_test_result_positive_continue_button">"Next"</string> + <!-- XBUT: positive test result : continue button with symptoms--> + <string name="submission_test_result_positive_continue_button_with_symptoms">"Enter Symptoms"</string> + <!-- XBUT: positive test result : continue button without symptoms --> + <string name="submission_test_result_positive_continue_button_wo_symptoms">"Don’t Enter Symptoms"</string> <!-- XHED: Page headline for invalid test result screen --> <string name="submission_test_result_invalid_steps_invalid_heading">"Your Test Result"</string> <!-- YTXT: Body text for next steps section of invalid test result--> @@ -854,9 +891,9 @@ <!-- XACT: Submission Tan page title --> <string name="submission_tan_accessibility_title">"TAN entry"</string> <!-- YTXT: Error text for the tan submission page --> - <string name="submission_tan_error">"Invalid TAN, please check your entry."</string> + <string name="submission_tan_error">"Invalid TAN. Please check your entry."</string> <!-- YTXT: Error text for the tan submission page (wrong characters) --> - <string name="submission_tan_character_error">"Invalid entry. Please check your entry."</string> + <string name="submission_tan_character_error">"Your entry contains invalid characters. Please check your entry."</string> <!-- Submission Intro --> <!-- XHED: Page title for menu at the start of the submission process --> @@ -912,16 +949,27 @@ <!-- XHED: Page headline for the positive result additional warning page--> <string name="submission_positive_other_warning_headline">"Please help all of us!"</string> <!-- YTXT: Body text for the positive result additional warning page--> - <string name="submission_positive_other_warning_body">"Next, you can make sure that the Corona-Warn-App shares your random IDs of the last 14 days with others. By doing this, you can warn other people and help to break the infection chain.\n\nSince only impersonal random IDs are transmitted, your identity will remain anonymous."</string> - <!-- XHED: Title for the privacy card--> - <string name="submission_positive_other_warning_privacy_title">"Data Privacy"</string> - <!-- YTXT: Body text for the privacy card--> - <string name="submission_positive_other_warning_privacy_body">"By tapping on “Acceptâ€, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Informationâ€."</string> + <string name="submission_positive_other_warning_body">"Next, you can make sure that others are notified of their potential exposure.\n\nTo do so, you can send your own random IDs from the last 14 days and, optionally, information about when you first noticed potential corona symptoms, to the exchange server operated jointly by all participating countries. From there, your random IDs and any other information you choose to provide will be distributed to the users of their official corona apps. This makes it possible to warn the other users of their potential exposure to you.\n\nOnly the random IDs are transmitted, along with any information you provide about when you noticed potential symptoms. No personal data, such as your name, address, or location, will be shared.."</string> <!-- XBUT: other warning continue button --> - <string name="submission_positive_other_warning_button">"Next"</string> + <string name="submission_positive_other_warning_button">"Accept"</string> <!-- XACT: other warning - illustration description, explanation image --> <string name="submission_positive_other_illustration_description">"A device transmits an encrypted positive test diagnosis to the system."</string> + <!-- XHED: Title for the interop country list--> + <string name="submission_interoperability_list_title">"The following countries currently participate in transnational exposure logging:"</string> + <!-- Submission Country Selector --> + <!-- XHED: Page title for the submission country selection page --> + <string name="submission_positive_country_selection_title">"Europe-wide warnings"</string> + <!-- XHED: Page headline for the submission country selection page --> + <string name="submission_positive_country_selection_headline">"Which countries have you visited in the last 14 days?"</string> + <!-- XHED: Country selector headline for the submission country selection page --> + <string name="submission_country_selector_headline">"I have visited the following countries"</string> + <!-- XHED: Country no selection headline for the submission country selection page --> + <string name="submission_country_no_selection_headline">"No statement"</string> + <!-- YTXT: Data FAQ for the submission country selection page --> + <string name="submission_country_selection_data_faq_body">"Your entry is used solely for optimizing the data volume.\n\nThe list contains all currently participating countries and is continuously updated."</string> + <!-- XBUT: submission country selection continue button --> + <string name="submission_country_selection_button">"Next"</string> <!-- Submission Done --> <!-- XHED: Page title for completed submission page --> @@ -931,7 +979,7 @@ <!-- XHED: Page subtitle for completed submission page --> <string name="submission_done_subtitle">"Please note:"</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"You are infectious."</string> + <string name="submission_done_contagious">"The public health authority will contact you within the next few days."</string> <!-- YTXT: text after submission: isolate --> <string name="submission_done_isolate">"Please isolate yourself from other people."</string> <!-- XHED: Title for further info --> @@ -946,7 +994,35 @@ <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Done"</string> <!-- XACT: submission finished - illustration description, explanation image --> - <string name="submission_done_illustration_description">"Everyone in the group is cheering because someone has shared the test result."</string> + <string name="submission_done_illustration_description">"Have you experienced one or more of the following symptoms in the past few days?"</string> + + <!-- Submission Symptoms --> + <!-- XHED: Page title for symptom screens --> + <string name="submission_symptom_title">"Symptoms"</string> + <!-- XTXT: headline text for initial symptom screen --> + <string name="submission_symptom_initial_headline">"Have you experienced one or more of the following symptoms?"</string> + <!-- YTXT: explanation text for initial symptom screen --> + <string name="submission_symptom_initial_explanation">"You can indicate whether and when you noticed any corona symptoms, to allow the App to calculate more accurately the risk of infection to other app users. If you do not want to provide that information, just select \"no answer\"."</string> + <!-- YTXT: Bullet points for symptoms --> + <string-array name="submission_symptom_symptom_bullets"> + <item>"Increased temperature or fever"</item> + <item>"Shortness of breath"</item> + <item>"Loss of sense of smell/taste"</item> + <item>"Cough"</item> + <item>"Runny nose"</item> + <item>"Sore throat"</item> + <item>"Headache and aching limbs"</item> + <item>"General weakness and exhaustion"</item> + </string-array> + <!-- XBUT: symptom initial screen yes button --> + <string name="submission_symptom_positive_button">"Yes"</string> + <!-- XBUT: symptom initial screen no button --> + <string name="submission_symptom_negative_button">"No"</string> + <!-- XBUT: symptom initial screen no information button --> + <string name="submission_symptom_no_information_button">"No statement"</string> + <!-- XBUT: symptom initial screen continue button --> + <string name="submission_symptom_further_button">"Next"</string> + <!-- Submission Contact --> <!-- XHED: Page title for contact page in submission flow --> @@ -977,6 +1053,22 @@ <!-- XACT: Content Description for submission contact step 2 --> <string name="submission_contact_step_2_content">"In the second step, you register your test with your TAN in the app."</string> + <!-- Submission Symptom Calendar --> + <!-- XHED: Page title for calendar page in submission symptom flow --> + <string name="submission_symptom_calendar_title">"Start of Symptoms"</string> + <!-- XHED: Page headline for calendar page in symptom submission flow --> + <string name="submission_symptom_calendar_headline">"When did you first start to experience these symptoms? "</string> + <!-- YTXT: Body text for calendar page in symptom submission flow--> + <string name="submission_symptom_calendar_body">"Select the exact date in the calendar or, if you cannot remember the exact date, choose one of the other options."</string> + <!-- XBUT: symptom calendar screen less than 7 days button --> + <string name="submission_symptom_less_seven">"In the last 7 days"</string> + <!-- XBUT: symptom calendar screen 1-2 weeks button --> + <string name="submission_symptom_one_two_weeks">"1-2 weeks ago"</string> + <!-- XBUT: symptom calendar screen more than 2 weeks button --> + <string name="submission_symptom_more_two_weeks">"More than 2 weeks ago"</string> + <!-- XBUT: symptom calendar screen verify button --> + <string name="submission_symptom_verify">"No statement"</string> + <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> <string name="submission_status_card_title_fetching">"Data being retrieved...."</string> @@ -1013,7 +1105,7 @@ <!-- YTXT: text for contagious card --> <string name="submission_status_card_positive_result_contagious">"You are infectious. Isolate yourself from other people."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"The public health authority will contact you within the next few days by telephone or by letter."</string> + <string name="submission_status_card_positive_result_contact">"The public health authority will contact you within the next few days."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"Share your random IDs so that others can be warned."</string> @@ -1040,6 +1132,9 @@ <item>"Do not go to work if you feel unwell to ensure you do not put other people at risk. If your symptoms worsen, you might need a further SARS-CoV-2 test."</item> </string-array> + <!-- XBUT Symptoms exact date button --> + <string name="symptoms_calendar_exact_date_button">"Exact date"</string> + <!-- #################################### Button Tooltips for Accessibility ###################################### --> @@ -1068,7 +1163,7 @@ <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action --> <string name="errors_external_action">"You cannot perform this action. Please contact the hotline."</string> <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update --> - <string name="errors_google_update_needed">"Your Corona-Warn-App is correctly installed, but the \"COVID-19 exposure notifications\" service is not available on your smartphone\'s operating system. This means that you cannot use the Corona-Warn-App. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string> + <string name="errors_google_update_needed">"Your Corona-Warn-App is correctly installed, but the \"COVID-19 Exposure Notifications System\" is not available on your smartphone\'s operating system. This means that you cannot use the Corona-Warn-App. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string> <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day --> <string name="errors_google_api_error">"The Corona-Warn-App is running correctly, but we cannot update your current risk status. Exposure logging remains active and is working correctly. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string> @@ -1085,6 +1180,10 @@ <string name="errors_generic_button_negative">"Details"</string> <!-- XTXT: error dialog - text when no error description is available --> <string name="errors_generic_text_unknown_error_cause">"An unknown error occurred."</string> + <!-- XTXT: error dialog - text when a catastrophic error occured from which the app recovered automatically via data reset --> + <string name="errors_generic_text_catastrophic_error_recovery_via_reset">"Your app was reset due to a technical problem. This has no effect on the app\'s functionality. You will continue to be notified about exposures and still be able to warn others, should you be tested positive for COVID-19."</string> + <!-- XTXT: error dialog - link for the details button in the catastrophic error recovery dialog --> + <string name="errors_generic_text_catastrophic_error_encryption_failure">"https://www.coronawarn.app/en/faq/#cause9002_recovery"</string> <!-- #################################### Just for Development @@ -1092,10 +1191,6 @@ <!-- NOTR --> <string name="lorem_ipsum">"Lorem Ipsum"</string> <!-- NOTR --> - <string name="menu_test_api">"Test API"</string> - <!-- NOTR --> - <string name="menu_test_risk_level">"Test Risk Level"</string> - <!-- NOTR --> <string name="menu_test_notification">"Test Notification"</string> <!-- NOTR --> <string name="test_api_button_api_launch">"Android API Test(Manual Test)"</string> @@ -1136,4 +1231,121 @@ <!-- NOTR --> <string name="test_api_calculate_risk_level">"Calculate Risk Level"</string> + <!-- XHED: Country Entry for Austria --> + <string name="country_name_at">"Austria"</string> + <!-- XHED: Country Entry for Belgium --> + <string name="country_name_be">"Belgium"</string> + <!-- XHED: Country Entry for Bulgaria --> + <string name="country_name_bg">"Bulgaria"</string> + <!-- XHED: Country Entry for Switzerland --> + <string name="country_name_ch">"Switzerland"</string> + <!-- XHED: Country Entry for Cyprus --> + <string name="country_name_cy">"Cyprus"</string> + <!-- XHED: Country Entry for Czech Republic --> + <string name="country_name_cz">"Czech Republic"</string> + <!-- XHED: Country Entry for Germany --> + <string name="country_name_de">"Germany"</string> + <!-- XHED: Country Entry for Denmark --> + <string name="country_name_dk">"Denmark"</string> + <!-- XHED: Country Entry for Estonia --> + <string name="country_name_ee">"Estonia"</string> + <!-- XHED: Country Entry for Spain --> + <string name="country_name_es">"Spain"</string> + <!-- XHED: Country Entry for Finland --> + <string name="country_name_fi">"Finnland"</string> + <!-- XHED: Country Entry for France --> + <string name="country_name_fr">"France"</string> + <!-- XHED: Country Entry for Great Britain --> + <string name="country_name_uk">"United Kingdom"</string> + <!-- XHED: Country Entry for Greece --> + <string name="country_name_gr">"Greece"</string> + <!-- XHED: Country Entry for Croatia --> + <string name="country_name_hr">"Croatia"</string> + <!-- XHED: Country Entry for Hungary --> + <string name="country_name_hu">"Hungary"</string> + <!-- XHED: Country Entry for Ireland --> + <string name="country_name_ie">"Ireland"</string> + <!-- XHED: Country Entry for Iceland --> + <string name="country_name_is">"Iceland"</string> + <!-- XHED: Country Entry for Italy --> + <string name="country_name_it">"Italy"</string> + <!-- XHED: Country Entry for Liechtenstein --> + <string name="country_name_li">"Liechtenstein"</string> + <!-- XHED: Country Entry for Lithuania --> + <string name="country_name_lt">"Lithuania"</string> + <!-- XHED: Country Entry for Luxemburg --> + <string name="country_name_lu">"Luxembourg"</string> + <!-- XHED: Country Entry for Latvia --> + <string name="country_name_lv">"Latvia"</string> + <!-- XHED: Country Entry for Malta --> + <string name="country_name_mt">"Malta"</string> + <!-- XHED: Country Entry for Netherlands --> + <string name="country_name_nl">"Netherlands"</string> + <!-- XHED: Country Entry for Norway --> + <string name="country_name_no">"Norway"</string> + <!-- XHED: Country Entry for Poland --> + <string name="country_name_pl">"Poland"</string> + <!-- XHED: Country Entry for Portugal --> + <string name="country_name_pt">"Portugal"</string> + <!-- XHED: Country Entry for Rumania --> + <string name="country_name_ro">"Romania"</string> + <!-- XHED: Country Entry for Sweden --> + <string name="country_name_se">"Sweden"</string> + <!-- XHED: Country Entry for Slovenia --> + <string name="country_name_si">"Slovenia"</string> + <!-- XHED: Country Entry for Slovakia --> + <string name="country_name_sk">"Slovakia"</string> + + <!-- XHED: Title of the interoperbaility information view. --> + <string name="interoperability_title">"Transnational\nExposure Logging"</string> + + <!-- XHED: Setting title of interoperability in the tracing settings view --> + <string name="settings_interoperability_title">"Transnational Exposure Logging"</string> + <!-- XTXT: Settings description of the interoperability in the tracing settings view --> + <string name="settings_interoperability_subtitle">"Participating Countries"</string> + + <!-- XHED: Header of interoperability information/configuration view --> + <string name="interoperability_configuration_title">"Transnational Exposure Logging"</string> + <!-- XTXT: First section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_first_section">"Several countries are working together to enable transnational alerts via a joint exchange server. For example, contacts with users of an official coronavirus app from other participating countries can also be taken into account for exposure logging."</string> + <!-- XTXT: Second section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_second_section">"To do this, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their random IDs via their own app. This list is then compared with the random IDs recorded by your smartphone. The daily download of the list with the random IDs is usually free of charge for you – you will not be charged for the data used by the app in this context, will roaming charges apply for this in other EU countries."</string> + <!-- XHED: Header right above the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_list_title">"The following countries currently participate in transnational exposure logging:"</string> + <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_information">"The app’s privacy notice (including information about the data processing carried out for the transnational exposure logging feature) can be found in the menu under “App Information†> “Data Privacyâ€."</string> + + <!-- XHED: Sub header introducing interoperability in the tracing step of onboarding --> + <string name="interoperability_onboarding_title">"Transnational\nExposure Logging"</string> + <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> + <string name="interoperability_onboarding_first_section">"Several countries have teamed up to enable transnational warnings. In other words, your potential exposure to users of the official corona apps in all participating countries can now be taken into account."</string> + <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> + <string name="interoperability_onboarding_second_section">"When a user submits their random IDs to the exchange server jointly operated by the participating countries, users of the official corona apps in all these countries can be warned of potential exposure."</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_randomid_download_free">"The daily download of the list with the random IDs is usually free of charge for you. Specifically, this means that mobile network operators do not charge you for the data used by the app in this context, and nor do they apply roaming charges for this in other EU countries. Please contact your mobile network operator for more information."</string> + <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> + <string name="interoperability_onboarding_list_title">"The following countries currently participate:"</string> + + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 1 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_1">"The terms of use have also been updated, to reflect the functional enhancements in the app."</string> + <!-- XLNK: Terms of use link inside delta interoperability screen--> + <string name="interoperability_onboarding_delta_terms_link">"Display terms of use"</string> + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 2 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_2">"The Terms of Use and privacy notice can also be found in the menu under “App Information†and in the app description in your app store. The changes will not affect how you use the app. If you continue to use the app or reopen it, we will assume that you agree to the updated Terms of Use."</string> + + <!-- XACT: interoperability (eu) - illustraction description, explanation image --> + <string name="interoperability_eu_illustration_description">"A hand holds a smartphone. Europe and the European flag are illustrated in the background."</string> + + <!-- XTXT: Title for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_title_failrequest">"Participating Countries"</string> + <!-- XTXT: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest">"You can view the participating countries in the exposure logging details."</string> + + <!-- YDES: Title for the interoperability onboarding if country download fails for Risk Details --> + <string name="interoperability_onboarding_list_title_riskdetection_no_network">"Countries cannot be displayed now."</string> + <!-- YMSW: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest_no_network">"Your Internet connection may have been lost. Please ensure that you are connected to the Internet."</string> + <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> + <string name="interoperability_onboarding_list_button_title_no_network">"Open Device Settings"</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-night/colors.xml b/Corona-Warn-App/src/main/res/values-night/colors.xml index 2c817a97a12ff797869888da9e575d85f767dd63..0481128c930d6fa77df913daa7402f94e00b4a51 100644 --- a/Corona-Warn-App/src/main/res/values-night/colors.xml +++ b/Corona-Warn-App/src/main/res/values-night/colors.xml @@ -19,6 +19,7 @@ <color name="colorTextPrimary2">#99FFFFFF</color> <color name="colorTextPrimary3">#4DFFFFFF</color> <color name="colorTextEmphasizedButton">#FFFFFF</color> + <color name="colorTextSixteenWhite">#FFFFFF</color> <color name="colorTextSemanticRed">#FF919A</color> <color name="colorTextSemanticGreen">#6ACC8B</color> <color name="colorTextSemanticNeutral">#B8C8D9</color> @@ -52,4 +53,6 @@ <color name="colorStableHairlineLight">#33FFFFFF</color> <color name="colorStableHairlineDark">#3317191A</color> + <!-- Calendar --> + <color name="colorCalendarMonthText">#DEFFFFFF</color> </resources> diff --git a/Corona-Warn-App/src/main/res/values-pl/strings.xml b/Corona-Warn-App/src/main/res/values-pl/strings.xml index fdf867dd9191d34ec6f1c2d62e674cb2ba33a8a3..4756022517b417eaf20ee0c0ae5fb7c39f033185 100644 --- a/Corona-Warn-App/src/main/res/values-pl/strings.xml +++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml @@ -212,7 +212,7 @@ <!-- XHED: main, FAQ --> <string name="main_about_headline">"CzÄ™sto zadawane pytania"</string> <!-- XTXT: main, explains faq on card --> - <string name="main_about_body">"Tutaj możesz znaleźć odpowiedzi na czÄ™sto zadawane pytania dotyczÄ…ce Corona-Warn-App. Zostaniesz przekierowany(-a) na zewnÄ™trznÄ… stronÄ™ internetowÄ…."</string> + <string name="main_about_body">"Tutaj możesz znaleźć odpowiedzi na czÄ™sto zadawane pytania dotyczÄ…ce Corona-Warn-App. Zostaniesz przekierowany(-a) na zewnÄ™trznÄ… stronÄ™ internetowÄ… administracji Niemiec."</string> <!-- XTXT: FAQ link, should be translated --> <string name="main_about_link">"https://www.bundesregierung.de/corona-warn-app-faq-englisch"</string> <!-- XACT: Opens external webpage --> @@ -282,7 +282,7 @@ <!-- YTXT: App overview body for glossary notifications --> <string name="main_overview_body_glossary_notification">"WyÅ›wietlanie narażeÅ„ w Corona-Warn-App."</string> <!-- XHED: App overview subtitle for glossary keys --> - <string name="main_overview_subtitle_glossary_keys">"Losowe identyfikatory"</string> + <string name="main_overview_subtitle_glossary_keys">"Identyfikator losowy"</string> <!-- YTXT: App overview body for glossary keys --> <string name="main_overview_body_glossary_keys">"Identyfikatory losowe sÄ… kombinacjÄ… cyfr i liter generowanych losowo. SÄ… one wymieniane pomiÄ™dzy urzÄ…dzeniami znajdujÄ…cymi siÄ™ w bliskiej odlegÅ‚oÅ›ci od siebie. Identyfikatorów losowych nie można przypisać do konkretnej osoby. SÄ… one automatycznie usuwane po 14 dniach. Osoby, u których zdiagnozowano COVID-19, mogÄ… zdecydować siÄ™ na udostÄ™pnienie swoich losowych identyfikatorów z ostatnich 14 dni innym użytkownikom aplikacji."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> @@ -345,7 +345,7 @@ <!-- YTXT: risk details - low risk explanation text --> <string name="risk_details_information_body_low_risk">"Masz niskie ryzyko zakażenia, ponieważ nie zarejestrowano narażenia na kontakt z osobami, u których później zdiagnozowano COVID-19, lub ponieważ Twoje kontakty trwaÅ‚y krótko przy zachowaniu odpowiednio dużej odlegÅ‚oÅ›ci."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"Ryzyko zakażenia jest obliczane lokalnie na Twoim urzÄ…dzeniu na podstawie danych rejestrowania narażenia. Ta kalkulacja uwzglÄ™dnia również dystans i czas trwania narażenia na kontakt z osobami, u których zdiagnozowano COVID-19, a także potencjalnÄ… podatność na zarażenie. Twoje ryzyko zakażenia nie jest widoczne dla nikogo ani nikomu przekazywane."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"Ryzyko zakażenia jest obliczane lokalnie na Twoim smartfonie na podstawie danych rejestrowania narażenia. Ta kalkulacja uwzglÄ™dnia również dystans i czas trwania narażenia na kontakt z osobami, u których zdiagnozowano COVID-19, a także potencjalnÄ… podatność na zakażenie. Twoje ryzyko zakażenia nie jest widoczne dla nikogo ani nikomu przekazywane."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> <item quantity="one">"Masz podwyższone ryzyko zakażenia, ponieważ %1$s dni temu byÅ‚eÅ›(-aÅ›) narażony(-a) na dÅ‚uższy, bliski kontakt z co najmniej jednÄ… osobÄ…, u której zdiagnozowano COVID-19."</item> @@ -372,6 +372,8 @@ <string name="risk_details_explanation_dialog_title">"Informacje o funkcjonalnoÅ›ci rejestrowania narażenia"</string> <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information--> <string name="risk_details_explanation_dialog_faq_body">"WiÄ™cej informacji znajduje siÄ™ na naszej stronie CzÄ™sto zadawane pytania."</string> + <!-- XLNK: risk explanations and informations - pointing to the faq page for more information and contains hyperlink--> + <string name="risk_details_explanation_faq_body_with_link"><a href="https://www.coronawarn.app/en/faq/#encounter_but_green">"WiÄ™cej informacji znajduje siÄ™ na naszej stronie „CzÄ™sto zadawane pytaniaâ€."</a></string> <!-- #################################### Onboarding @@ -390,7 +392,7 @@ <!-- XTXT: onboarding - back description for screen reader --> <string name="onboarding_button_back_description">"Wstecz"</string> <!-- XACT: Onboarding (together) page title --> - <string name="onboarding_onboarding_accessibility_title">"Strona wprowadzenia 1 z 5: Wspólna walka z koronawirusem"</string> + <string name="onboarding_onboarding_accessibility_title">"Strona wprowadzenia 1 z 6: Wspólna walka z koronawirusem"</string> <!-- XHED: onboarding(together) - fight corona --> <string name="onboarding_headline">"Razem pokonajmy koronawirusa"</string> <!-- XHED: onboarding(together) - two/three line headline under an illustration --> @@ -402,28 +404,26 @@ <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Grupa osób korzysta ze smartfonów na mieÅ›cie."</string> <!-- XACT: Onboarding (privacy) page title --> - <string name="onboarding_privacy_accessibility_title">"Strona wprowadzenia 2 z 5: Prywatność danych. W dalszej części znajduje siÄ™ opis. Aby kontynuować w dowolnym momencie, użyj przycisku w dolnej części ekranu."</string> + <string name="onboarding_privacy_accessibility_title">"Strona wprowadzenia 2 z 6: Prywatność danych. W dalszej części znajduje siÄ™ opis. Aby kontynuować w dowolnym momencie, użyj przycisku w dolnej części ekranu."</string> <!-- XHED: onboarding(privacy) - title --> <string name="onboarding_privacy_headline">"Prywatność danych"</string> <!-- XACT: onboarding(privacy) - illustraction description, header image --> <string name="onboarding_privacy_illustration_description">"Kobieta używa Corona-Warn-App na swoim smartfonie. Ikona przedstawiajÄ…ca kłódkÄ™ na tle tarczy symbolizuje zaszyfrowane dane."</string> <!-- XACT: Onboarding (tracing) page title --> - <string name="onboarding_tracing_accessibility_title">"Strona wprowadzenia 3 z 5: Jak wÅ‚Ä…czyć rejestrowanie narażenia"</string> + <string name="onboarding_tracing_accessibility_title">"Strona wprowadzenia 3 z 6: Jak wÅ‚Ä…czyć rejestrowanie narażenia"</string> <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"Jak wÅ‚Ä…czyć rejestrowanie narażenia"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> <string name="onboarding_tracing_subtitle">"Aby ustalić wystÄ™powanie ryzyka zakażenia, musisz aktywować funkcjÄ™ rejestrowania narażenia."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"DziaÅ‚anie funkcji rejestrowania narażenia polega na odbieraniu przez Twoje urzÄ…dzenie za pomocÄ… Bluetooth zaszyfrowanych, losowych identyfikatorów innych użytkowników i przekazywaniu Twoich wÅ‚asnych, losowych identyfikatorów do ich urzÄ…dzeÅ„. FunkcjÄ™ tÄ™ można wyÅ‚Ä…czyć w dowolnym momencie."</string> + <string name="onboarding_tracing_body">"DziaÅ‚anie funkcji rejestrowania narażenia polega na odbieraniu przez Twój smartfon za pomocÄ… Bluetooth zaszyfrowanych, losowych identyfikatorów innych użytkowników i przekazywaniu Twoich wÅ‚asnych, losowych identyfikatorów do ich smartfonów. Rejestrowanie narażenia można wyÅ‚Ä…czyć w dowolnym momencie."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body_emphasized">"Zaszyfrowane losowe identyfikatory przekazujÄ… innym osobom jedynie informacje o dacie, czasie trwania i bliskoÅ›ci (przy wykorzystaniu mocy sygnaÅ‚u). Dane osobowe, takie jak nazwisko, adres, lokalizacja, nie sÄ… nigdy rejestrowane. Ustalenie tożsamoÅ›ci osób nie jest możliwe."</string> + <string name="onboarding_tracing_body_emphasized">"Zaszyfrowane losowe identyfikatory przekazujÄ… innym osobom jedynie informacje o dacie kontaktu, czasie trwania i odlegÅ‚oÅ›ci (obliczonej na podstawie mocy sygnaÅ‚u) od innych użytkowników aplikacji. Ustalenie tożsamoÅ›ci osób na podstawie losowych identyfikatorów nie jest możliwe."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> <string name="onboarding_tracing_easy_language_explanation"><a href="https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache">"Informacja o aplikacji w jÄ™zyku uproszczonym i jÄ™zyku migowym"</a></string> - <!-- XHED: onboarding(tracing) - headline for consent information --> - <string name="onboarding_tracing_headline_consent">"OÅ›wiadczenia o wyrażeniu zgody"</string> - <!-- YTXT: onboarding(tracing) - body for consent information --> - <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping on the “Enable†button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyses this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Informationâ€."</string> + <!-- NOTR: onboarding(tracing) - easy language explain tracing link URL--> + <string name="onboarding_tracing_easy_language_explanation_url">"https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache"</string> <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_button_next">"Aktywuj rejestrowanie narażenia"</string> <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined --> @@ -465,7 +465,7 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Otwórz ustawienia urzÄ…dzenia"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Strona wprowadzenia 4 z 5: JeÅ›li zdiagnozowano u Ciebie COVID-19..."</string> + <string name="onboarding_test_accessibility_title">"Strona wprowadzenia 5 z 6: JeÅ›li zdiagnozowano u Ciebie COVID-19..."</string> <!-- XHED: onboarding(test) - about positive tests --> <string name="onboarding_test_headline">"JeÅ›li zdiagnozowano u Ciebie COVID-19..."</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> @@ -475,7 +475,7 @@ <!-- XACT: onboarding(test) - illustraction description, header image --> <string name="onboarding_test_illustration_description">"Zaszyfrowana diagnoza zakażenia jest przesyÅ‚ana do systemu, który bÄ™dzie teraz ostrzegaÅ‚ innych użytkowników."</string> <!-- XACT: Onboarding (datashare) page title --> - <string name="onboarding_notifications_accessibility_title">"Strona wprowadzenia 5 z 5: Otrzymuj ostrzeżenia i ustal ryzyko"</string> + <string name="onboarding_notifications_accessibility_title">"Strona wprowadzenia 6 z 6: Otrzymuj ostrzeżenia i ustal ryzyko"</string> <!-- XHED: onboarding(datashare) - about positive tests --> <string name="onboarding_notifications_headline">"Otrzymuj ostrzeżenia i ustal ryzyko"</string> <!-- XHED: onboarding(datashare) - two/three line headline under an illustration --> @@ -485,6 +485,17 @@ <!-- XACT: onboarding(notifications) - illustraction description, header image --> <string name="onboarding_notifications_illustration_description">"Kobieta otrzymuje powiadomienie od swojej aplikacji Corona-Warn-App."</string> + <!-- #################################### + Onboarding sixteen include + ###################################### --> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_title_text">"Limit wieku: 16 i wiÄ™cej"</string> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_description_text">"Ta aplikacja jest przeznaczona dla osób, które ukoÅ„czyÅ‚y 16 lat i mieszkajÄ… w Niemczech."</string> + + <!-- #################################### Settings ###################################### --> @@ -498,9 +509,9 @@ <!-- XHED: settings(tracing) - page title --> <string name="settings_tracing_title">"Rejestrowanie narażenia"</string> <!-- XHED: settings(tracing) - headline bellow illustration --> - <string name="settings_tracing_headline">"Sposób dziaÅ‚ania funkcji rejestrowania narażenia"</string> + <string name="settings_tracing_headline">"Jak dziaÅ‚a funkcja rejestrowania narażenia"</string> <!-- XTXT: settings(tracing) - explain text in settings overview under headline --> - <string name="settings_tracing_body_description">"Zezwól na generowanie i udostÄ™pnianie losowych identyfikatorów COVID-19."</string> + <string name="settings_tracing_body_description">"Zezwól na tworzenie i udostÄ™pnianie losowych identyfikatorów COVID-19."</string> <!-- XTXT: settings(tracing) - shows status under header in home, active --> <string name="settings_tracing_body_active">"Rejestrowanie narażenia aktywne"</string> <!-- XTXT: settings(tracing) - shows status under header in home, inactive --> @@ -508,7 +519,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"UsÅ‚ugi lokalizacji dezaktywowane"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"DziaÅ‚anie funkcji rejestrowania narażenia polega na odbieraniu przez Twoje urzÄ…dzenie za pomocÄ… Bluetooth zaszyfrowanych, losowych identyfikatorów innych użytkowników i przekazywaniu Twoich losowych identyfikatorów do ich urzÄ…dzeÅ„. FunkcjÄ™ tÄ™ można wyÅ‚Ä…czyć w dowolnym momencie. "<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Identyfikatory przekazujÄ… w sposób zaszyfrowany wyÅ‚Ä…cznie informacje o dacie, czasie trwania i odlegÅ‚oÅ›ci (przy wykorzystaniu mocy sygnaÅ‚u) od innych użytkowników aplikacji. Dane osobowe, takie jak nazwisko, adres, lokalizacja, nie sÄ… nigdy rejestrowane. Ustalenie tożsamoÅ›ci osób nie jest możliwe."</string> + <string name="settings_tracing_body_text">"Musisz wÅ‚Ä…czyć funkcjÄ™ rejestrowania narażenia, aby aplikacja mogÅ‚a ustalić, czy dotyczy CiÄ™ ryzyko zakażenia po kontakcie z zainfekowanym użytkownikiem aplikacji. Funkcja rejestrowania narażenia dziaÅ‚a we wszystkich uczestniczÄ…cych krajach, co oznacza, że potencjalne narażenie użytkowników jest wykrywane również przez inne oficjalne aplikacje koronawirusowe.\n\nDziaÅ‚anie funkcji rejestrowania narażenia polega na odbieraniu przez Twój smartfon za pomocÄ… Bluetooth zaszyfrowanych, losowych identyfikatorów innych użytkowników i przekazywaniu Twoich wÅ‚asnych, losowych identyfikatorów do ich urzÄ…dzeÅ„. Codziennie aplikacja pobiera listÄ™ losowych identyfikatorów – wraz z wszelkimi opcjonalnie podawanymi informacjami o wystÄ…pieniu symptomów – wszystkich użytkowników, którzy mieli pozytywny wynik testu na wirusa i dobrowolnie udostÄ™pnili tÄ™ informacjÄ™ poprzez aplikacjÄ™. Lista jest nastÄ™pnie porównywana z losowymi identyfikatorami innych użytkowników, które zarejestrowaÅ‚ Twój smartfon, w celu obliczenia prawdopodobieÅ„stwa Twojego zakażenia i ostrzeżenia CiÄ™ w razie potrzeby. FunkcjÄ™ tÄ™ można wyÅ‚Ä…czyć w dowolnym momencie..\n\nAplikacja nigdy nie gromadzi danych osobowych takich jak imiÄ™ i nazwisko, adres czy lokalizacja. Takie informacje nie sÄ… też przekazywane innym użytkownikom. Nie jest możliwe wykorzystanie losowych identyfikatorów w celu ustalenia tożsamoÅ›ci poszczególnych osób."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Aktywne"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -528,7 +539,9 @@ <!--XHED : settings(tracing) - headline on card about the current status and what to do --> <string name="settings_tracing_status_location_headline">"Zezwól na dostÄ™p do lokalizacji"</string> <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled --> - <string name="settings_tracing_status_location_body">"Nie można uzyskać dostÄ™pu do Twojej lokalizacji. Google i/lub Android wymaga dostÄ™pu do lokalizacji Twojego urzÄ…dzenia w celu użycia Bluetooth."</string> + <string name="settings_tracing_status_location_body">"Aktywuj swoje usÅ‚ugi lokalizacji. Bluetooth Low Energy wymaga aktywowanych usÅ‚ug lokalizacji do obliczenia fizycznego dystansu, ale nie uzyskuje dostÄ™pu do Twojej lokalizacji. WiÄ™cej informacji znajduje siÄ™ na stronie CzÄ™sto zadawane pytania."</string> + <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL --> + <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string> <!-- XBUT: settings(tracing) - go to operating system settings button on card - location --> <string name="settings_tracing_status_location_button">"Otwórz ustawienia urzÄ…dzenia"</string> <!--XHED : settings(tracing) - headline on card about the current status and what to do --> @@ -614,9 +627,9 @@ <!-- XTXT: settings(background priority) - text in row on settings overview --> <string name="settings_background_priority_body_description">"Zezwól na automatyczne aktualizacje statusu ryzyka"</string> <!-- XHED: settings(background priority) - multiline headline below illustration --> - <string name="settings_background_priority_headline">"Uruchom Corona-Warn-App w tle"</string> + <string name="settings_background_priority_headline">"Zaktualizuj automatycznie status ryzyka"</string> <!-- YTXT: settings(background priority) - description text --> - <string name="settings_background_priority_body">"Aplikacja Corona-Warn-App bÄ™dzie dziaÅ‚ać stale w tle, jeÅ›li aktywujesz priorytetowe dziaÅ‚anie w tle. DziÄ™ki temu aplikacja bÄ™dzie mogÅ‚a w dowolnym momencie ustalić Twój status ryzyka."</string> + <string name="settings_background_priority_body">"JeÅ›li aktywujesz priorytetowe dziaÅ‚anie w tle, aplikacja bÄ™dzie mogÅ‚a ustalić Twój status ryzyka w dowolnym momencie. Powoduje to wyÅ‚Ä…czenie optymalizacji żywotnoÅ›ci baterii tylko dla aplikacji Corona-Warn-App."</string> <!-- XACT: settings(background priority) - illustraction description --> <string name="settings_background_priority_illustration_description"/> <!-- XTXT: settings(background priority) - explains user what to do on card if background priority is enabled --> @@ -641,7 +654,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"Instytut Roberta Kocha (RKI) to niemiecka federalna instytucja zdrowia publicznego. RKI publikuje aplikacjÄ™ Corona-Warn-App w imieniu rzÄ…du federalnego. Aplikacja ta sÅ‚uży jako cyfrowe uzupeÅ‚nienie już wprowadzonych Å›rodków ochrony zdrowia publicznego, takich jak zachowanie dystansu spoÅ‚ecznego, dbanie o higienÄ™ oraz noszenie maseczek."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Wszystkie osoby korzystajÄ…ce z aplikacji pomagajÄ… w Å›ledzeniu i przerwaniu Å‚aÅ„cuchów zakażeÅ„. Aplikacja zapisuje kontakty z innymi osobami lokalnie na Twoim urzÄ…dzeniu. Otrzymasz powiadomienie, jeÅ›li okaże siÄ™, że u osób, z którymi miaÅ‚eÅ›(-aÅ›) kontakt, zdiagnozowano później COVID-19. Twoja tożsamość i prywatność sÄ… zawsze chronione."</string> + <string name="information_about_body">"Osoby korzystajÄ…ce z aplikacji pomagajÄ… w Å›ledzeniu i przerwaniu Å‚aÅ„cuchów zakażeÅ„. Aplikacja zapisuje kontakty z innymi osobami lokalnie na Twoim urzÄ…dzeniu. Otrzymasz powiadomienie, jeÅ›li okaże siÄ™, że u osób, z którymi miaÅ‚eÅ›(-aÅ›) kontakt, zdiagnozowano później COVID-19. Twoja tożsamość i prywatność sÄ… zawsze chronione."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"Grupa osób korzysta ze smartfonów na mieÅ›cie."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -663,7 +676,7 @@ <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_headline">"Jak możemy Ci pomóc?"</string> <!-- YTXT: Body text for technical contact and hotline information page --> - <string name="information_contact_body">"W przypadku pytaÅ„ technicznych dotyczÄ…cych Corona-Warn-App prosimy o kontakt z naszÄ… infoliniÄ…."</string> + <string name="information_contact_body">"W przypadku pytaÅ„ technicznych dotyczÄ…cych aplikacji Corona-Warn-App proszÄ™ siÄ™ skontaktować z naszÄ… infoliniÄ….\n\nOsoby niedosÅ‚yszÄ…ce mogÄ… skorzystać z usÅ‚ug Tess Relay (tÅ‚umaczenie z pisanego jÄ™zyka niemieckiego na jÄ™zyk migowy i odwrotnie) w celu skontaktowania siÄ™ z infoliniÄ…. To oprogramowanie można pobrać z App Store/Google Play."</string> <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_subtitle_phone">"Infolinia techniczna:"</string> <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page --> @@ -700,8 +713,10 @@ <string name="information_legal_headline_contact">"Kontakt"</string> <!-- YTXT: subtitle for legal information page, contact section --> <string name="information_legal_subtitle_contact">"E-mail: CoronaWarnApp@rki.de"</string> - <!-- YTXT: subtitle for legal information page, open contact form --> - <string name="information_legal_subtitle_contact_form"><a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"Formularz kontaktowy"</a></string> + <!-- YTXT: subtitle for legal information page, open contact form : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_label">"Formularz kontaktowy"</string> + <!-- YTXT: subtitle for legal information page url : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_url">"https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html"</string> <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German --> <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string> <!-- XHED: Headline for legal information page, tax section --> @@ -711,6 +726,11 @@ <!-- XACT: describes illustration --> <string name="information_legal_illustration_description">"W rÄ™ce trzymany jest smartfon z dużą iloÅ›ciÄ… tekstu na ekranie. Obok tekstu znajduje siÄ™ symbol paragrafu reprezentujÄ…cy impressum."</string> + <!-- #################################### + Interoperability + ###################################### --> + <!-- XHED: headline for consent information --> + <string name="interop_consent_headline">"Zgoda"</string> <!-- #################################### Submission @@ -725,10 +745,14 @@ <!-- XBUT: Positive button for generic web request error --> <string name="submission_error_dialog_web_generic_error_button_positive">"Wstecz"</string> - <!-- XHED: Dialog title for already paired test error --> - <string name="submission_error_dialog_web_test_paired_title">"BÅ‚Ä…d"</string> - <!-- XMSG: Dialog body for already paired test error --> - <string name="submission_error_dialog_web_test_paired_body">"Kod QR/TAN jest nieprawidÅ‚owy lub byÅ‚ już używany. Spróbuj ponownie lub skontaktuj siÄ™ z technicznÄ… infoliniÄ…, wybierajÄ…c opcje: Informacje o aplikacji -> Infolinia techniczna."</string> + <!-- XHED: Dialog title for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_title">"Niepoprawny kod QR"</string> + <!-- XMSG: Dialog body for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_body">"Kod QR jest niepoprawny lub zostaÅ‚ już zarejestrowany na innym smartfonie. Otrzymasz swój wynik testu z oÅ›rodka wykonujÄ…cego testy lub laboratorium niezależnie od ważnoÅ›ci kodu QR. W przypadku zdiagnozowania u Ciebie COVID-19 otrzymasz powiadomienie z organu ds. zdrowia publicznego."</string> + <!-- XHED: Dialog title for already paired test error: tan --> + <string name="submission_error_dialog_web_test_paired_title_tan">"TAN jest nieprawidÅ‚owy."</string> + <!-- XMSG: Dialog body for already paired test via tan - error: tan --> + <string name="submission_error_dialog_web_test_paired_body_tan">"TAN jest nieprawidÅ‚owy lub zostaÅ‚ już użyty. WiÄ™cej informacji można uzyskać dzwoniÄ…c na numer wymieniony w sekcji „PoproÅ› o TANâ€."</string> <!-- XBUT: Positive button for already paired test error --> <string name="submission_error_dialog_web_test_paired_button_positive">"Wstecz"</string> @@ -753,6 +777,15 @@ <!-- XBUT: Positive button for submission tan redeemed --> <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> + <!-- XHED: Dialog title for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_title">"Czy chcesz anulować?"</string> + <!-- XMSG: Dialog body for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_body">"Twoje wpisy nie zostanÄ… zapisane."</string> + <!-- XBUT: Positive button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_positive">"Tak"</string> + <!-- XBUT: Negative button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_negative">"Nie"</string> + <!-- Permission Rationale Dialog --> <!-- XHED: Dialog headline QR Scan permission rationale --> <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Wymagana autoryzacja aparatu"</string> @@ -816,9 +849,13 @@ <!-- XHED: Page headline for other warnings screen --> <string name="submission_test_result_positive_steps_warning_others_heading">"Ostrzeganie innych"</string> <!-- YTXT: Body text for for other warnings screen--> - <string name="submission_test_result_positive_steps_warning_others_body">"UdostÄ™pnij swoje losowe identyfikatory z ostatnich 14 dni w celu ochrony innych osób i przerwania Å‚aÅ„cucha zakażeÅ„."</string> + <string name="submission_test_result_positive_steps_warning_others_body">"UdostÄ™pnij swoje losowe identyfikatory, aby ostrzegać innych.\nPomóż innym dokÅ‚adniej ocenić ryzyko zakażenia, wysyÅ‚ajÄ…c informacjÄ™, gdy dostrzeżesz u siebie symptomy koronawirusa."</string> <!-- XBUT: positive test result : continue button --> <string name="submission_test_result_positive_continue_button">"Dalej"</string> + <!-- XBUT: positive test result : continue button with symptoms--> + <string name="submission_test_result_positive_continue_button_with_symptoms">"Wprowadź symptomy"</string> + <!-- XBUT: positive test result : continue button without symptoms --> + <string name="submission_test_result_positive_continue_button_wo_symptoms">"Nie wprowadzaj symptomów"</string> <!-- XHED: Page headline for invalid test result screen --> <string name="submission_test_result_invalid_steps_invalid_heading">"Twój wynik testu"</string> <!-- YTXT: Body text for next steps section of invalid test result--> @@ -856,7 +893,7 @@ <!-- YTXT: Error text for the tan submission page --> <string name="submission_tan_error">"NieprawidÅ‚owy TAN, sprawdź swój wpis."</string> <!-- YTXT: Error text for the tan submission page (wrong characters) --> - <string name="submission_tan_character_error">"NieprawidÅ‚owy wpis, sprawdź go."</string> + <string name="submission_tan_character_error">"Twój wpis zawiera nieprawidÅ‚owe znaki, Sprawdź swój wpis."</string> <!-- Submission Intro --> <!-- XHED: Page title for menu at the start of the submission process --> @@ -912,16 +949,27 @@ <!-- XHED: Page headline for the positive result additional warning page--> <string name="submission_positive_other_warning_headline">"Pomóż nam wszystkim!"</string> <!-- YTXT: Body text for the positive result additional warning page--> - <string name="submission_positive_other_warning_body">"Teraz możesz aktywować udostÄ™pnianie Twoich losowych identyfikatorów z ostatnich 14 dni. W ten sposób ostrzeżesz inne osoby i pomożesz w przerwaniu Å‚aÅ„cucha zakażeÅ„.\n\nZachowasz anonimowość, ponieważ przekazywane sÄ… tylko bezosobowe, losowe identyfikatory."</string> - <!-- XHED: Title for the privacy card--> - <string name="submission_positive_other_warning_privacy_title">"Prywatność danych"</string> - <!-- YTXT: Body text for the privacy card--> - <string name="submission_positive_other_warning_privacy_body">"By tapping on “Acceptâ€, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Informationâ€."</string> + <string name="submission_positive_other_warning_body">"Możesz siÄ™ teraz upewnić, czy inni zostali powiadomieni o potencjalnym narażeniu.\n\nW tym celu możesz wysyÅ‚ać swoje wÅ‚asne losowe identyfikatory z ostatnich 14 dni, a opcjonalnie również informacje o dostrzeżeniu symptomów koronawirusa u siebie, na wspólny serwer wymiany danych obsÅ‚ugiwany przez wszystkie uczestniczÄ…ce kraje. Z tego serwera Twoje losowe identyfikatory i wszelkie dodatkowe informacje bÄ™dÄ… przesyÅ‚ane do użytkowników oficjalnych aplikacji. Umożliwia to ostrzeżenie innych użytkowników o potencjalnym narażeniu na kontakt z TobÄ….\n\nUdostÄ™pniane sÄ… tylko losowe identyfikatory i podane przez Ciebie informacje o wystÄ…pieniu potencjalnych symptomów. Dane osobowe, takie jak imiÄ™ i nazwisko, adres czy lokalizacja, nie sÄ… udostÄ™pniane."</string> <!-- XBUT: other warning continue button --> - <string name="submission_positive_other_warning_button">"Dalej"</string> + <string name="submission_positive_other_warning_button">"Akceptuj"</string> <!-- XACT: other warning - illustration description, explanation image --> <string name="submission_positive_other_illustration_description">"Zaszyfrowana diagnoza zakażenia jest przesyÅ‚ana do systemu."</string> + <!-- XHED: Title for the interop country list--> + <string name="submission_interoperability_list_title">"NastÄ™pujÄ…ce kraje uczestniczÄ… obecnie w miÄ™dzynarodowym rejestrowaniu narażenia:"</string> + <!-- Submission Country Selector --> + <!-- XHED: Page title for the submission country selection page --> + <string name="submission_positive_country_selection_title">"Ostrzeżenia obejmujÄ…ce caÅ‚Ä… EuropÄ™"</string> + <!-- XHED: Page headline for the submission country selection page --> + <string name="submission_positive_country_selection_headline">"W jakich krajach byÅ‚eÅ›(-Å‚aÅ›) w ciÄ…gu ostatnich 14 dni?"</string> + <!-- XHED: Country selector headline for the submission country selection page --> + <string name="submission_country_selector_headline">"ByÅ‚em(-Å‚am) w nastÄ™pujÄ…cych krajach"</string> + <!-- XHED: Country no selection headline for the submission country selection page --> + <string name="submission_country_no_selection_headline">"Bez komentarza"</string> + <!-- YTXT: Data FAQ for the submission country selection page --> + <string name="submission_country_selection_data_faq_body">"Twój wpis posÅ‚uży wyÅ‚Ä…cznie w celu optymalizacji wolumenu danych.\n\nNa liÅ›cie znajdujÄ… siÄ™ wszystkie kraje obecnie uczestniczÄ…ce w projekcie i jest ona stale aktualizowana."</string> + <!-- XBUT: submission country selection continue button --> + <string name="submission_country_selection_button">"Dalej"</string> <!-- Submission Done --> <!-- XHED: Page title for completed submission page --> @@ -931,7 +979,7 @@ <!-- XHED: Page subtitle for completed submission page --> <string name="submission_done_subtitle">"Uwaga:"</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"Możesz zarażać."</string> + <string name="submission_done_contagious">"Organ ds. zdrowia publicznego skontaktuje siÄ™ z TobÄ… w ciÄ…gu kilku najbliższych dni."</string> <!-- YTXT: text after submission: isolate --> <string name="submission_done_isolate">"Izoluj siÄ™ od innych osób."</string> <!-- XHED: Title for further info --> @@ -946,7 +994,35 @@ <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Gotowe"</string> <!-- XACT: submission finished - illustration description, explanation image --> - <string name="submission_done_illustration_description">"Wszyscy w grupie siÄ™ cieszÄ…, ponieważ ktoÅ› podzieliÅ‚ siÄ™ wynikiem testu."</string> + <string name="submission_done_illustration_description">"Czy w ciÄ…gu ostatnich kilku dni wystÄ…piÅ‚ u Ciebie jeden lub kilka z wymienionych poniżej symptomów?"</string> + + <!-- Submission Symptoms --> + <!-- XHED: Page title for symptom screens --> + <string name="submission_symptom_title">"Symptomy"</string> + <!-- XTXT: headline text for initial symptom screen --> + <string name="submission_symptom_initial_headline">"Czy wystÄ…piÅ‚ u Ciebie jeden lub kilka z wymienionych poniżej symptomów?"</string> + <!-- YTXT: explanation text for initial symptom screen --> + <string name="submission_symptom_initial_explanation">"Możesz podać, czy i kiedy zauważyÅ‚eÅ›(-Å‚aÅ›) symptomy koronawirusa, aby umożliwić aplikacji dokÅ‚adniejsze obliczenie ryzyka zakażenia innych użytkowników aplikacji. JeÅ›li nie chcesz podawać tych informacji, wybierz „brak odpowiedziâ€."</string> + <!-- YTXT: Bullet points for symptoms --> + <string-array name="submission_symptom_symptom_bullets"> + <item>"Podwyższona temperatura lub gorÄ…czka"</item> + <item>"DusznoÅ›ci"</item> + <item>"Utrata wÄ™chu/smaku"</item> + <item>"Kaszel"</item> + <item>"Katar"</item> + <item>"Ból gardÅ‚a"</item> + <item>"Ból gÅ‚owy i koÅ„czyn"</item> + <item>"Ogólne osÅ‚abienie i wyczerpanie"</item> + </string-array> + <!-- XBUT: symptom initial screen yes button --> + <string name="submission_symptom_positive_button">"Tak"</string> + <!-- XBUT: symptom initial screen no button --> + <string name="submission_symptom_negative_button">"Nie"</string> + <!-- XBUT: symptom initial screen no information button --> + <string name="submission_symptom_no_information_button">"Bez komentarza"</string> + <!-- XBUT: symptom initial screen continue button --> + <string name="submission_symptom_further_button">"Dalej"</string> + <!-- Submission Contact --> <!-- XHED: Page title for contact page in submission flow --> @@ -977,6 +1053,22 @@ <!-- XACT: Content Description for submission contact step 2 --> <string name="submission_contact_step_2_content">"NastÄ™pnie zarejestruj test przy użyciu numeru TAN w aplikacji."</string> + <!-- Submission Symptom Calendar --> + <!-- XHED: Page title for calendar page in submission symptom flow --> + <string name="submission_symptom_calendar_title">"PoczÄ…tek wystÄ…pienia symptomów"</string> + <!-- XHED: Page headline for calendar page in symptom submission flow --> + <string name="submission_symptom_calendar_headline">"Kiedy zaczÄ…Å‚eÅ›(-Å‚aÅ›) odczutwać te symptomy? "</string> + <!-- YTXT: Body text for calendar page in symptom submission flow--> + <string name="submission_symptom_calendar_body">"Wybierz dokÅ‚adnÄ… datÄ™ w kalendarzu lub, jeÅ›li nie pamiÄ™tasz dokÅ‚adnej daty, wybierz jednÄ… z innych opcji."</string> + <!-- XBUT: symptom calendar screen less than 7 days button --> + <string name="submission_symptom_less_seven">"W ciÄ…gu ostatnich 7 dni"</string> + <!-- XBUT: symptom calendar screen 1-2 weeks button --> + <string name="submission_symptom_one_two_weeks">"1-2 tygodnie temu"</string> + <!-- XBUT: symptom calendar screen more than 2 weeks button --> + <string name="submission_symptom_more_two_weeks">"Ponad 2 tygodnie temu"</string> + <!-- XBUT: symptom calendar screen verify button --> + <string name="submission_symptom_verify">"Bez komentarza"</string> + <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> <string name="submission_status_card_title_fetching">"Pobieranie danych..."</string> @@ -1013,7 +1105,7 @@ <!-- YTXT: text for contagious card --> <string name="submission_status_card_positive_result_contagious">"Możesz zarażać. Izoluj siÄ™ od innych osób."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"Organ ds. zdrowia publicznego skontaktuje siÄ™ z TobÄ… w ciÄ…gu kilku najbliższych dni telefonicznie lub listownie."</string> + <string name="submission_status_card_positive_result_contact">"Organ ds. zdrowia publicznego skontaktuje siÄ™ z TobÄ… w ciÄ…gu kilku najbliższych dni."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"UdostÄ™pnij swoje losowe identyfikatory, aby umożliwić ostrzeganie innych osób."</string> @@ -1040,6 +1132,9 @@ <item>"Nie idź do pracy, jeÅ›li nie czujesz siÄ™ dobrze, aby nie stwarzać zagrożenia dla innych osób. JeÅ›li objawy nasilÄ… siÄ™, może być konieczne wykonanie kolejnego testu SARS-CoV-2."</item> </string-array> + <!-- XBUT Symptoms exact date button --> + <string name="symptoms_calendar_exact_date_button">"DokÅ‚adna data"</string> + <!-- #################################### Button Tooltips for Accessibility ###################################### --> @@ -1068,7 +1163,7 @@ <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action --> <string name="errors_external_action">"Nie możesz wykonać tej czynnoÅ›ci. Skontaktuj siÄ™ z infoliniÄ…."</string> <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update --> - <string name="errors_google_update_needed">"Twoja aplikacja Corona-Warn-App jest poprawnie zainstalowana, ale usÅ‚uga „Powiadomienia o narażeniu na COVID-19†nie jest dostÄ™pna w systemie operacyjnym Twojego smartfona. Oznacza to, że nie możesz korzystać z aplikacji Corona-Warn-App. WiÄ™cej informacji znajduje siÄ™ na naszej stronie CzÄ™sto zadawane pytania: https://www.coronawarn.app/en/faq/."</string> + <string name="errors_google_update_needed">"Twoja aplikacja Corona-Warn-App jest poprawnie zainstalowana, ale system „Powiadomienia o narażeniu na COVID-19†nie jest dostÄ™pny w systemie operacyjnym Twojego smartfona. Oznacza to, że nie możesz korzystać z aplikacji Corona-Warn-App. WiÄ™cej informacji znajduje siÄ™ na naszej stronie „CzÄ™sto zadawane pytaniaâ€: https://www.coronawarn.app/en/faq/."</string> <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day --> <string name="errors_google_api_error">"Aplikacja Corona-Warn-App dziaÅ‚a prawidÅ‚owo, ale nie możemy zaaktualizować Twojego aktualnego statusu ryzyka. Rejestrowanie narażenia pozostaje aktywne i dziaÅ‚a prawidÅ‚owo. WiÄ™cej informacji można znaleźć na naszej stronie CzÄ™sto zadawane pytania: https://www.coronawarn.app/en/faq/"</string> @@ -1085,6 +1180,10 @@ <string name="errors_generic_button_negative">"Szczegóły"</string> <!-- XTXT: error dialog - text when no error description is available --> <string name="errors_generic_text_unknown_error_cause">"WystÄ…piÅ‚ nieznany bÅ‚Ä…d."</string> + <!-- XTXT: error dialog - text when a catastrophic error occured from which the app recovered automatically via data reset --> + <string name="errors_generic_text_catastrophic_error_recovery_via_reset">"Twoja aplikacja zostaÅ‚a zresetowana z powodu problemu technicznego. Nie bÄ™dzie to miaÅ‚o wpÅ‚ywu na funkcjonalność aplikacji. Nadal bÄ™dziesz otrzymywać powiadomienia o narażeniach i bÄ™dziesz w stanie ostrzegać innych w razie pozytywnego wyniku testu na COVID-19."</string> + <!-- XTXT: error dialog - link for the details button in the catastrophic error recovery dialog --> + <string name="errors_generic_text_catastrophic_error_encryption_failure">"https://www.coronawarn.app/en/faq/#cause9002_recovery"</string> <!-- #################################### Just for Development @@ -1092,10 +1191,6 @@ <!-- NOTR --> <string name="lorem_ipsum">"Lorem Ipsum"</string> <!-- NOTR --> - <string name="menu_test_api">"Test API"</string> - <!-- NOTR --> - <string name="menu_test_risk_level">"Test Risk Level"</string> - <!-- NOTR --> <string name="menu_test_notification">"Test Notification"</string> <!-- NOTR --> <string name="test_api_button_api_launch">"Android API Test(Manual Test)"</string> @@ -1136,4 +1231,121 @@ <!-- NOTR --> <string name="test_api_calculate_risk_level">"Calculate Risk Level"</string> + <!-- XHED: Country Entry for Austria --> + <string name="country_name_at">"Austria"</string> + <!-- XHED: Country Entry for Belgium --> + <string name="country_name_be">"Belgia"</string> + <!-- XHED: Country Entry for Bulgaria --> + <string name="country_name_bg">"BuÅ‚garia"</string> + <!-- XHED: Country Entry for Switzerland --> + <string name="country_name_ch">"Szwajcaria"</string> + <!-- XHED: Country Entry for Cyprus --> + <string name="country_name_cy">"Cypr"</string> + <!-- XHED: Country Entry for Czech Republic --> + <string name="country_name_cz">"Republika Czeska"</string> + <!-- XHED: Country Entry for Germany --> + <string name="country_name_de">"Niemcy"</string> + <!-- XHED: Country Entry for Denmark --> + <string name="country_name_dk">"Dania"</string> + <!-- XHED: Country Entry for Estonia --> + <string name="country_name_ee">"Estonia"</string> + <!-- XHED: Country Entry for Spain --> + <string name="country_name_es">"Hiszpania"</string> + <!-- XHED: Country Entry for Finland --> + <string name="country_name_fi">"Finlandia"</string> + <!-- XHED: Country Entry for France --> + <string name="country_name_fr">"Francja"</string> + <!-- XHED: Country Entry for Great Britain --> + <string name="country_name_uk">"Wielka Brytania"</string> + <!-- XHED: Country Entry for Greece --> + <string name="country_name_gr">"Grecja"</string> + <!-- XHED: Country Entry for Croatia --> + <string name="country_name_hr">"Chorwacja"</string> + <!-- XHED: Country Entry for Hungary --> + <string name="country_name_hu">"WÄ™gry"</string> + <!-- XHED: Country Entry for Ireland --> + <string name="country_name_ie">"Irlandia"</string> + <!-- XHED: Country Entry for Iceland --> + <string name="country_name_is">"Islandia"</string> + <!-- XHED: Country Entry for Italy --> + <string name="country_name_it">"WÅ‚ochy"</string> + <!-- XHED: Country Entry for Liechtenstein --> + <string name="country_name_li">"Liechtenstein"</string> + <!-- XHED: Country Entry for Lithuania --> + <string name="country_name_lt">"Litwa"</string> + <!-- XHED: Country Entry for Luxemburg --> + <string name="country_name_lu">"Luksemburg"</string> + <!-- XHED: Country Entry for Latvia --> + <string name="country_name_lv">"Åotwa"</string> + <!-- XHED: Country Entry for Malta --> + <string name="country_name_mt">"Malta"</string> + <!-- XHED: Country Entry for Netherlands --> + <string name="country_name_nl">"Holandia"</string> + <!-- XHED: Country Entry for Norway --> + <string name="country_name_no">"Norwegia"</string> + <!-- XHED: Country Entry for Poland --> + <string name="country_name_pl">"Polska"</string> + <!-- XHED: Country Entry for Portugal --> + <string name="country_name_pt">"Portugalia"</string> + <!-- XHED: Country Entry for Rumania --> + <string name="country_name_ro">"Rumunia"</string> + <!-- XHED: Country Entry for Sweden --> + <string name="country_name_se">"Szwecja"</string> + <!-- XHED: Country Entry for Slovenia --> + <string name="country_name_si">"SÅ‚owenia"</string> + <!-- XHED: Country Entry for Slovakia --> + <string name="country_name_sk">"SÅ‚owacja"</string> + + <!-- XHED: Title of the interoperbaility information view. --> + <string name="interoperability_title">"Rejestrowanie narażenia\nw różnych krajach"</string> + + <!-- XHED: Setting title of interoperability in the tracing settings view --> + <string name="settings_interoperability_title">"Rejestrowanie narażenia\nw różnych krajach"</string> + <!-- XTXT: Settings description of the interoperability in the tracing settings view --> + <string name="settings_interoperability_subtitle">"Kraje uczestniczÄ…ce"</string> + + <!-- XHED: Header of interoperability information/configuration view --> + <string name="interoperability_configuration_title">"Rejestrowanie narażenia\nw różnych krajach"</string> + <!-- XTXT: First section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_first_section">"Wiele krajów współpracuje ze sobÄ… w celu aktywacji transgranicznych alertów wysyÅ‚anych poprzez wspólny serwer wymiany danych. Na przykÅ‚ad przy rejestrowaniu narażenia można wziąć pod uwagÄ™ również kontakty z użytkownikami oficjalnych aplikacji koronawirusowyych z innych uczestniczÄ…cych krajów."</string> + <!-- XTXT: Second section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_second_section">"W tym celu aplikacja pobiera listÄ™, która jest aktualizowana codziennie, z losowymi identyfikatorami wszystkich użytkowników, którzy udostÄ™pnili swoje losowe identyfikatory poprzez wÅ‚asnÄ… aplikacjÄ™. Lista jest nastÄ™pnie porównywana z losowymi identyfikatorami zarejestrowanymi przez Twój smartfon. Codzienne pobieranie listy z losowymi identyfikatorami jest z reguÅ‚y bezpÅ‚atne – za dane używane przez aplikacjÄ™ w tym kontekÅ›cie nie bÄ™dÄ… pobierane opÅ‚aty roamingowe w innych krajach UE."</string> + <!-- XHED: Header right above the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_list_title">"NastÄ™pujÄ…ce kraje uczestniczÄ… obecnie w miÄ™dzynarodowym rejestrowaniu narażenia:"</string> + <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_information">"Informacje aplikacji o prywatnoÅ›ci danych (Å‚Ä…cznie z wyjaÅ›nieniem dotyczÄ…cym przetwarzania danych wykonywanego dla funkcji rejestrowania narażenia) można znaleźć w menu w sekcji „Informacje aplikacji†> „Informacje o ochronie danychâ€."</string> + + <!-- XHED: Sub header introducing interoperability in the tracing step of onboarding --> + <string name="interoperability_onboarding_title">"Rejestrowanie narażenia\nw różnych krajach"</string> + <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> + <string name="interoperability_onboarding_first_section">"Wiele krajów współpracuje w zakresie aktywowania miÄ™dzynarodowych ostrzeżeÅ„. Innymi sÅ‚owy, można teraz okreÅ›lić Twoje potencjalne narażenie wobec użytkowników oficjalnych aplikacji koronawirusowych we wszystkich uczestniczÄ…cych krajach."</string> + <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> + <string name="interoperability_onboarding_second_section">"Gdy użytkownik przesyÅ‚a swój losowy identyfikator do serwera wymiany danych obsÅ‚ugiwanego wspólnie przez kraje uczestniczÄ…ce, użytkownicy oficjalnych aplikacji koronawirusowych we wszystkich tych krajach mogÄ… zostać ostrzeżeni o potencjalnym narażeniu."</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_randomid_download_free">"Codzienne pobieranie listy z losowymi identyfikatorami jest z reguÅ‚y bezpÅ‚atne. Oznacza to, że operatorzy sieci mobilnych nie bÄ™dÄ… pobierać opÅ‚at za transmisjÄ™ danych używanych przez aplikacjÄ™ w tym kontekÅ›cie ani też nie bÄ™dÄ… naliczane opÅ‚aty roamingowe w innych krajach UE. Aby uzyskać wiÄ™cej informacji, skontaktuj siÄ™ ze swoim operatorem sieci mobilnej."</string> + <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> + <string name="interoperability_onboarding_list_title">"Obecnie uczestniczÄ… nastÄ™pujÄ…ce kraje:"</string> + + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 1 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_1">"Warunki korzystania zostaÅ‚y również zaktualizowane w celu uwzglÄ™dnienia rozszerzeÅ„ funkcji w aplikacji,"</string> + <!-- XLNK: Terms of use link inside delta interoperability screen--> + <string name="interoperability_onboarding_delta_terms_link">"WyÅ›wietl warunki korzystania"</string> + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 2 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_2">"Warunki korzystania i informacje o prywatnoÅ›ci danych można znaleźć w menu w sekcji „Informacje aplikacji†oraz w opisie aplikacji w Twoim App Store. Zmiany nie bÄ™dÄ… miaÅ‚y wpÅ‚ywu na korzystanie przez Ciebie z aplikacji. W przypadku dalszego korzystania z aplikacji lub jej ponownego otwarcia, zakÅ‚adamy, że użytkownik zgadza siÄ™ na zaktualizowane warunki korzystania."</string> + + <!-- XACT: interoperability (eu) - illustraction description, explanation image --> + <string name="interoperability_eu_illustration_description">"RÄ™ka trzyma smartfon. Europa i flaga europejska sÄ… przedstawione w tle."</string> + + <!-- XTXT: Title for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_title_failrequest">"Kraje uczestniczÄ…ce"</string> + <!-- XTXT: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest">"Możesz wyÅ›wietlić kraje uczestniczÄ…ce w danych rejestrowania narażenia."</string> + + <!-- YDES: Title for the interoperability onboarding if country download fails for Risk Details --> + <string name="interoperability_onboarding_list_title_riskdetection_no_network">"Nie można teraz wyÅ›wietlić krajów"</string> + <!-- YMSW: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest_no_network">"Twoje poÅ‚Ä…czenie z Internetem mogÅ‚o zostać utracone. Upewnij siÄ™, że masz poÅ‚Ä…czenie z Internetem."</string> + <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> + <string name="interoperability_onboarding_list_button_title_no_network">"Otwórz ustawienia urzÄ…dzenia"</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-ro/strings.xml b/Corona-Warn-App/src/main/res/values-ro/strings.xml index 62cf4a4e029ee56234c811f2f59c18233b03cf80..efafe39a5005b2eed437b74fbb084367be06cd50 100644 --- a/Corona-Warn-App/src/main/res/values-ro/strings.xml +++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml @@ -212,7 +212,7 @@ <!-- XHED: main, FAQ --> <string name="main_about_headline">"ÃŽntrebări frecvente"</string> <!-- XTXT: main, explains faq on card --> - <string name="main_about_body">"Aici puteÈ›i găsi răspunsuri la întrebările frecvente legate de aplicaÈ›ia Corona-Warn. VeÈ›i fi redirecÈ›ionat către un site web extern."</string> + <string name="main_about_body">"Aici puteÈ›i găsi răspunsuri la întrebările frecvente legate de aplicaÈ›ia Corona-Warn. VeÈ›i fi redirecÈ›ionat către un site web extern al guvernului german."</string> <!-- XTXT: FAQ link, should be translated --> <string name="main_about_link">"https://www.bundesregierung.de/corona-warn-app-faq-englisch"</string> <!-- XACT: Opens external webpage --> @@ -282,7 +282,7 @@ <!-- YTXT: App overview body for glossary notifications --> <string name="main_overview_body_glossary_notification">"AfiÈ™area expunerilor în Corona-Warn-App."</string> <!-- XHED: App overview subtitle for glossary keys --> - <string name="main_overview_subtitle_glossary_keys">"ID-uri aleatorii"</string> + <string name="main_overview_subtitle_glossary_keys">"ID aleatoriu"</string> <!-- YTXT: App overview body for glossary keys --> <string name="main_overview_body_glossary_keys">"ID-urile aleatorii sunt combinaÈ›ii de cifre È™i litere generate aleatoriu. Acestea sunt schimbate între dispozitivele aflate în proximitate strânsă. ID-urile aleatorii nu pot fi asociate cu o persoană anume È™i sunt È™terse automat după 14 zile. Persoanele diagnosticate cu COVID-19 pot opta să trimită ID-urile aleatorii din ultimele 14 zile È™i altor utilizatori ai aplicaÈ›iei."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> @@ -345,7 +345,7 @@ <!-- YTXT: risk details - low risk explanation text --> <string name="risk_details_information_body_low_risk">"AveÈ›i un risc redus de infectare deoarece nu a fost înregistrată nicio expunere la persoane diagnosticate ulterior cu COVID-19 sau întâlnirile au fost limitate la o perioadă scurtă È™i la o distanță mai mare."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"Riscul de infectare este calculat local pe dispozitivul dvs., utilizând datele de înregistrare în jurnal a expunerilor. Calculul poate È›ine cont È™i de distanÈ›a È™i durata expunerii la persoane diagnosticate cu COVID-19, precum È™i de potenÈ›iala contagiozitate a acestora. Riscul dvs. de infectare nu poate fi observat sau transmis mai departe niciunei alte persoane."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"Riscul de infectare este calculat local pe smartphone-ul dvs., utilizând datele de înregistrare în jurnal a expunerilor. Calculul poate È›ine cont È™i de distanÈ›a È™i durata expunerii la persoane diagnosticate cu COVID-19, precum È™i de potenÈ›iala contagiozitate a acestora. Riscul dvs. de infectare nu poate fi observat sau transmis mai departe niciunei alte persoane."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> <item quantity="one">"AveÈ›i un risc crescut de infectare deoarece aÈ›i fost expus ultima dată acum %1$s zi pe o perioadă mai lungă de timp È™i în strânsă proximitate cu cel puÈ›in o persoană diagnosticată cu COVID-19."</item> @@ -372,6 +372,8 @@ <string name="risk_details_explanation_dialog_title">"InformaÈ›ii despre funcÈ›ionalitatea de înregistrare în jurnal a expunerilor"</string> <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information--> <string name="risk_details_explanation_dialog_faq_body">"Pentru mai multe informaÈ›ii, consultaÈ›i pagina noastră de întrebări frecvente."</string> + <!-- XLNK: risk explanations and informations - pointing to the faq page for more information and contains hyperlink--> + <string name="risk_details_explanation_faq_body_with_link"><a href="https://www.coronawarn.app/en/faq/#encounter_but_green">"Pentru mai multe informaÈ›ii, consultaÈ›i pagina noastră de întrebări frecvente."</a></string> <!-- #################################### Onboarding @@ -390,7 +392,7 @@ <!-- XTXT: onboarding - back description for screen reader --> <string name="onboarding_button_back_description">"ÃŽnapoi"</string> <!-- XACT: Onboarding (together) page title --> - <string name="onboarding_onboarding_accessibility_title">"Pagina de înregistrare 1 din 5: Să combatem împreună COVID-19"</string> + <string name="onboarding_onboarding_accessibility_title">"Pagina de înregistrare 1 din 6: Să combatem împreună COVID-19"</string> <!-- XHED: onboarding(together) - fight corona --> <string name="onboarding_headline">"Să combatem împreună COVID-19"</string> <!-- XHED: onboarding(together) - two/three line headline under an illustration --> @@ -402,28 +404,26 @@ <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Un grup de persoane își utilizează smartphone-urile prin oraÈ™."</string> <!-- XACT: Onboarding (privacy) page title --> - <string name="onboarding_privacy_accessibility_title">"Pagina de înregistrare 2 din 5: ConfidenÈ›ialitatea datelor. Urmează un text lung. Pentru a continua în orice moment, utilizaÈ›i butonul din partea de jos a ecranului."</string> + <string name="onboarding_privacy_accessibility_title">"Pagina de înregistrare 2 din 6: ConfidenÈ›ialitatea datelor. Urmează un text lung. Pentru a continua în orice moment, utilizaÈ›i butonul din partea de jos a ecranului."</string> <!-- XHED: onboarding(privacy) - title --> <string name="onboarding_privacy_headline">"ConfidenÈ›ialitatea datelor"</string> <!-- XACT: onboarding(privacy) - illustraction description, header image --> <string name="onboarding_privacy_illustration_description">"O femeie utilizează Corona-Warn-App pe smartphone. O pictogramă care arată un lacăt pe un fundal în formă de scut simbolizează datele criptate."</string> <!-- XACT: Onboarding (tracing) page title --> - <string name="onboarding_tracing_accessibility_title">"Pagina de înregistrare 3 din 5: Cum se activează înregistrarea în jurnal a expunerilor"</string> + <string name="onboarding_tracing_accessibility_title">"Pagina de înregistrare 3 din 6: Cum se activează înregistrarea în jurnal a expunerilor"</string> <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"Cum se activează înregistrarea în jurnal a expunerilor"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> <string name="onboarding_tracing_subtitle">"Pentru a identifica dacă sunteÈ›i supus riscului de infectare, trebuie să activaÈ›i caracteristica de înregistrare în jurnal a expunerilor."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"ÃŽnregistrarea în jurnal a expunerilor funcÈ›ionează astfel: dispozitivul dvs. primeÈ™te prin Bluetooth ID-uri aleatorii criptate ale altor utilizatori È™i transmite propriul dvs. ID aleatoriu către dispozitivele acestora. Această caracteristică poate fi oricând dezactivată."</string> + <string name="onboarding_tracing_body">"ÃŽnregistrarea în jurnal a expunerilor funcÈ›ionează astfel: smartphone-ul dvs. primeÈ™te prin Bluetooth ID-uri aleatorii criptate ale altor utilizatori È™i transmite propriile dvs. ID-uri aleatorii către smartphone-urile acestora. ÃŽnregistrarea în jurnal a expunerilor poate fi oricând dezactivată."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body_emphasized">"ID-urile aleatorii criptate transmit informaÈ›ii doar despre dată, durată È™i proximitatea față de alte persoane (utilizând intensitatea semnalului). Datele personale, precum numele, adresa, locaÈ›ia nu sunt înregistrate niciodată. Nu se pot identifica persoanele individuale."</string> + <string name="onboarding_tracing_body_emphasized">"ID-urile aleatorii criptate transmit informaÈ›ii doar despre dată, durată È™i proximitatea față de alte persoane (calculată prin intensitatea semnalului). Nu se pot identifica persoane individuale pe baza ID-urilor aleatorii."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> <string name="onboarding_tracing_easy_language_explanation"><a href="https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache">"InformaÈ›ii despre aplicaÈ›ie în limbaj simplificat È™i în limbajul semnelor"</a></string> - <!-- XHED: onboarding(tracing) - headline for consent information --> - <string name="onboarding_tracing_headline_consent">"DeclaraÈ›ie de consimțământ"</string> - <!-- YTXT: onboarding(tracing) - body for consent information --> - <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping on the “Enable†button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyses this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Informationâ€."</string> + <!-- NOTR: onboarding(tracing) - easy language explain tracing link URL--> + <string name="onboarding_tracing_easy_language_explanation_url">"https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache"</string> <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_button_next">"ActivaÈ›i înregistrarea în jurnal a expunerilor"</string> <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined --> @@ -465,7 +465,7 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"DeschideÈ›i Setările dispozitivului"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Pagina de înregistrare 4 din 5: Dacă sunteÈ›i diagnosticat cu COVID-19…"</string> + <string name="onboarding_test_accessibility_title">"Pagina de înregistrare 5 din 6: Dacă sunteÈ›i diagnosticat cu COVID-19…"</string> <!-- XHED: onboarding(test) - about positive tests --> <string name="onboarding_test_headline">"Dacă sunteÈ›i diagnosticat cu COVID-19…"</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> @@ -475,7 +475,7 @@ <!-- XACT: onboarding(test) - illustraction description, header image --> <string name="onboarding_test_illustration_description">"Un diagnostic de test pozitiv criptat este transmis la sistem, iar acesta va avertiza apoi ceilalÈ›i utilizatori."</string> <!-- XACT: Onboarding (datashare) page title --> - <string name="onboarding_notifications_accessibility_title">"Pagina de înregistrare 5 din 5: PrimiÈ›i avertizări È™i identificaÈ›i riscurile"</string> + <string name="onboarding_notifications_accessibility_title">"Pagina de înregistrare 6 din 6: PrimiÈ›i avertizări È™i identificaÈ›i riscurile"</string> <!-- XHED: onboarding(datashare) - about positive tests --> <string name="onboarding_notifications_headline">"PrimiÈ›i avertizări È™i identificaÈ›i riscurile"</string> <!-- XHED: onboarding(datashare) - two/three line headline under an illustration --> @@ -485,6 +485,17 @@ <!-- XACT: onboarding(notifications) - illustraction description, header image --> <string name="onboarding_notifications_illustration_description">"O femeie primeÈ™te o notificare de la Corona-Warn-App."</string> + <!-- #################################### + Onboarding sixteen include + ###################################### --> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_title_text">"Limita de vârstă: începând cu 16 ani"</string> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_description_text">"Utilizarea acestei aplicaÈ›ii este destinată persoanelor care au vârsta de cel puÈ›in 16 ani È™i care locuiesc în Germania."</string> + + <!-- #################################### Settings ###################################### --> @@ -500,7 +511,7 @@ <!-- XHED: settings(tracing) - headline bellow illustration --> <string name="settings_tracing_headline">"Modul în care funcÈ›ionează înregistrarea în jurnal a expunerilor"</string> <!-- XTXT: settings(tracing) - explain text in settings overview under headline --> - <string name="settings_tracing_body_description">"PermiteÈ›i generarea È™i trimiterea de ID-uri aleatorii de COVID-19."</string> + <string name="settings_tracing_body_description">"PermiteÈ›i crearea È™i partajarea de ID-uri aleatorii asociate COVID-19."</string> <!-- XTXT: settings(tracing) - shows status under header in home, active --> <string name="settings_tracing_body_active">"ÃŽnregistrarea în jurnal a expunerilor este activă"</string> <!-- XTXT: settings(tracing) - shows status under header in home, inactive --> @@ -508,7 +519,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"Serviciile de localizare au fost dezactivate"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"Trebuie să activaÈ›i caracteristica de înregistrare în jurnal a expunerilor, pentru a identifica dacă sunteÈ›i supus riscului de infectare. Identificarea riscului funcÈ›ionează astfel: dispozitivul dvs. primeÈ™te prin Bluetooth ID-uri aleatorii criptate ale altor utilizatori È™i transmite propriul dvs. ID aleatoriu către dispozitivele acestora. PuteÈ›i dezactiva oricând această caracteristică."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"ID-urile aleatorii criptate transmit informaÈ›ii doar despre dată, durată È™i proximitatea față de alte persoane (calculate utilizând intensitatea semnalului). Datele personale, precum numele, adresa È™i locaÈ›ia nu sunt înregistrate niciodată. Nu se pot identifica persoanele individuale."</string> + <string name="settings_tracing_body_text">"Trebuie să activaÈ›i caracteristica de înregistrare în jurnal a expunerilor, pentru ca aplicaÈ›ia să poată determina dacă aveÈ›i risc de infectare după ce aÈ›i întâlnit un utilizator al aplicaÈ›iei care este infectat. Caracteristica de înregistrare în jurnal a expunerilor funcÈ›ionează la nivel transnaÈ›ional, ceea ce înseamnă că orice expunere posibilă care îi implică pe utilizatori este detectată È™i de alte aplicaÈ›ii oficiale împotriva coronavirusului.\n\nCaracteristica de înregistrare în jurnal a expunerilor funcÈ›ionează astfel: smartphone-ul dvs. primeÈ™te prin Bluetooth ID-uri aleatorii criptate ale altor utilizatori È™i transmite propriul dvs. ID aleatoriu către smartphone-urile acestora. ÃŽn fiecare zi, aplicaÈ›ia descarcă o listă ce conÈ›ine ID-uri aleatorii – împreună cu orice alte informaÈ›ii voluntare despre debutul simptomelor – ale tuturor utilizatorilor testaÈ›i pozitiv la virus È™i care au împărtășit voluntar aceste informaÈ›ii prin aplicaÈ›ia lor. Apoi, lista este comparată cu ID-urile aleatorii ale altor utilizatori care au fost înregistrate de smartphone-ul dvs., pentru a calcula probabilitatea ca È™i dvs. să fi fost infectat È™i să vă avertizeze dacă este necesar. PuteÈ›i utiliza comutatorul pentru a dezactiva în orice moment înregistrarea în jurnal a expunerilor.\n\nAplicaÈ›ia nu colectează niciodată date personale, precum numele, adresa sau locaÈ›ia dvs., iar aceste informaÈ›ii nu sunt transmise niciodată altor utilizatori. Nu se pot utiliza ID-urile aleatorii pentru a trage concluzii despre persoane individuale."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Activă"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -528,7 +539,9 @@ <!--XHED : settings(tracing) - headline on card about the current status and what to do --> <string name="settings_tracing_status_location_headline">"PermiteÈ›i accesul la locaÈ›ie"</string> <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled --> - <string name="settings_tracing_status_location_body">"LocaÈ›ia dvs. nu poate fi accesată. Google È™i/sau Android necesită acces la locaÈ›ia dispozitivului dvs. pentru a utiliza Bluetooth-ul."</string> + <string name="settings_tracing_status_location_body">"ActivaÈ›i serviciile de localizare. Bluetooth Low Energy necesită ca serviciile de localizare să fie activate pentru a calcula distanÈ›ele fizice, dar nu vă accesează locaÈ›ia. Pentru informaÈ›ii suplimentare, consultaÈ›i pagina noastră de întrebări frecvente."</string> + <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL --> + <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string> <!-- XBUT: settings(tracing) - go to operating system settings button on card - location --> <string name="settings_tracing_status_location_button">"DeschideÈ›i Setările dispozitivului"</string> <!--XHED : settings(tracing) - headline on card about the current status and what to do --> @@ -614,9 +627,9 @@ <!-- XTXT: settings(background priority) - text in row on settings overview --> <string name="settings_background_priority_body_description">"PermiteÈ›i actualizări automate privind starea riscului"</string> <!-- XHED: settings(background priority) - multiline headline below illustration --> - <string name="settings_background_priority_headline">"RulaÈ›i aplicaÈ›ia Corona-Warn în fundal"</string> + <string name="settings_background_priority_headline">"Actualizare automată a stării de risc"</string> <!-- YTXT: settings(background priority) - description text --> - <string name="settings_background_priority_body">"AplicaÈ›ia Corona-Warn rulează permanent în fundal dacă activaÈ›i Activitate în fundal cu prioritate. Aceasta permite aplicaÈ›iei să determine starea riscului dvs. în orice moment."</string> + <string name="settings_background_priority_body">"Dacă activaÈ›i activitatea în fundal cu prioritate, aplicaÈ›ia poate determina în orice moment starea riscului dvs. Această opÈ›iune dezactivează optimizarea vieÈ›ii bateriei doar pentru aplicaÈ›ia Corona-Warn."</string> <!-- XACT: settings(background priority) - illustraction description --> <string name="settings_background_priority_illustration_description"/> <!-- XTXT: settings(background priority) - explains user what to do on card if background priority is enabled --> @@ -663,7 +676,7 @@ <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_headline">"Cum vă putem ajuta?"</string> <!-- YTXT: Body text for technical contact and hotline information page --> - <string name="information_contact_body">"Pentru întrebări tehnice despre aplicaÈ›ia Corona-Warn, contactaÈ›i hotline-ul."</string> + <string name="information_contact_body">"Pentru întrebări tehnice despre aplicaÈ›ia Corona-Warn, contactaÈ›i hotline-ul.\n\nPersoanele cu deficienÈ›e de auz pot utiliza serviciile Tess Relay (interpretare între limba germană scrisă È™i limbajul semnelor) pentru a contacta hotline-ul telefonic. PuteÈ›i descărca software-ul din App Store/Google Play."</string> <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_subtitle_phone">"Hotline tehnic:"</string> <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page --> @@ -700,17 +713,24 @@ <string name="information_legal_headline_contact">"Contact"</string> <!-- YTXT: subtitle for legal information page, contact section --> <string name="information_legal_subtitle_contact">"E-mail: CoronaWarnApp@rki.de"</string> - <!-- YTXT: subtitle for legal information page, open contact form --> - <string name="information_legal_subtitle_contact_form"><a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"Formular de contact"</a></string> + <!-- YTXT: subtitle for legal information page, open contact form : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_label">"Formular de contact"</string> + <!-- YTXT: subtitle for legal information page url : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_url">"https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html"</string> <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German --> <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string> <!-- XHED: Headline for legal information page, tax section --> - <string name="information_legal_headline_taxid">"Număr de înregistrare în scop de TVA"</string> + <string name="information_legal_headline_taxid">"Număr de înregistrare\nîn scop de TVA"</string> <!-- YTXT: subtitle for legal information page, tax section --> <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string> <!-- XACT: describes illustration --> <string name="information_legal_illustration_description">"O mână È›ine un smartphone pe al cărui ecran este afiÈ™at un corp mare de text. Lângă text există un simbol de secÈ›iune, reprezentând informaÈ›iile de contact."</string> + <!-- #################################### + Interoperability + ###################################### --> + <!-- XHED: headline for consent information --> + <string name="interop_consent_headline">"Consimțământ"</string> <!-- #################################### Submission @@ -725,10 +745,14 @@ <!-- XBUT: Positive button for generic web request error --> <string name="submission_error_dialog_web_generic_error_button_positive">"ÃŽnapoi"</string> - <!-- XHED: Dialog title for already paired test error --> - <string name="submission_error_dialog_web_test_paired_title">"Eroare"</string> - <!-- XMSG: Dialog body for already paired test error --> - <string name="submission_error_dialog_web_test_paired_body">"Codul QR/TAN este nevalabil sau a fost deja utilizat. ReîncercaÈ›i sau contactaÈ›i hotline-ul tehnic accesând InformaÈ›ii aplicaÈ›ie -> Hotline tehnic."</string> + <!-- XHED: Dialog title for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_title">"Codul QR este nevalabil"</string> + <!-- XMSG: Dialog body for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_body">"Codul QR este nevalabil sau a fost deja înregistrat pe un alt smartphone. VeÈ›i primi rezultatul testului dvs. de la centrul sau laboratorul de testare, indiferent de valabilitatea codului QR. Dacă sunteÈ›i diagnosticat cu COVID-19, veÈ›i fi notificat de autoritatea de sănătate publică."</string> + <!-- XHED: Dialog title for already paired test error: tan --> + <string name="submission_error_dialog_web_test_paired_title_tan">"TAN-ul este nevalabil"</string> + <!-- XMSG: Dialog body for already paired test via tan - error: tan --> + <string name="submission_error_dialog_web_test_paired_body_tan">"TAN-ul este nevalabil sau a fost deja utilizat. Pentru informaÈ›ii suplimentare, apelaÈ›i numărul afiÈ™at la „Solicitare TANâ€."</string> <!-- XBUT: Positive button for already paired test error --> <string name="submission_error_dialog_web_test_paired_button_positive">"ÃŽnapoi"</string> @@ -753,6 +777,15 @@ <!-- XBUT: Positive button for submission tan redeemed --> <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> + <!-- XHED: Dialog title for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_title">"DoriÈ›i să anulaÈ›i?"</string> + <!-- XMSG: Dialog body for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_body">"Intrările dvs. nu vor fi salvate."</string> + <!-- XBUT: Positive button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_positive">"Da"</string> + <!-- XBUT: Negative button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_negative">"Nu"</string> + <!-- Permission Rationale Dialog --> <!-- XHED: Dialog headline QR Scan permission rationale --> <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Este necesară autorizaÈ›ia pentru camera foto"</string> @@ -816,9 +849,13 @@ <!-- XHED: Page headline for other warnings screen --> <string name="submission_test_result_positive_steps_warning_others_heading">"Avertizarea altora"</string> <!-- YTXT: Body text for for other warnings screen--> - <string name="submission_test_result_positive_steps_warning_others_body">"TrimiteÈ›i ID-urile dvs. aleatorii din ultimele 14 zile pentru a proteja alte persoane È™i pentru a întrerupe lanÈ›ul de infectare."</string> + <string name="submission_test_result_positive_steps_warning_others_body">"PartajaÈ›i ID-urile dvs. aleatorii È™i avertizaÈ›i-i pe ceilalÈ›i.\nAjutaÈ›i la stabilirea riscului de infectare pentru ceilalÈ›i cu mai multă acurateÈ›e, indicând momentul în care aÈ›i observat prima dată simptomele de coronavirus."</string> <!-- XBUT: positive test result : continue button --> <string name="submission_test_result_positive_continue_button">"ÃŽnainte"</string> + <!-- XBUT: positive test result : continue button with symptoms--> + <string name="submission_test_result_positive_continue_button_with_symptoms">"Introducere simptome"</string> + <!-- XBUT: positive test result : continue button without symptoms --> + <string name="submission_test_result_positive_continue_button_wo_symptoms">"Nu se introduc simptome"</string> <!-- XHED: Page headline for invalid test result screen --> <string name="submission_test_result_invalid_steps_invalid_heading">"Rezultatul testului dvs."</string> <!-- YTXT: Body text for next steps section of invalid test result--> @@ -854,9 +891,9 @@ <!-- XACT: Submission Tan page title --> <string name="submission_tan_accessibility_title">"Intrare TAN"</string> <!-- YTXT: Error text for the tan submission page --> - <string name="submission_tan_error">"TAN nevalabil. VerificaÈ›i intrarea."</string> + <string name="submission_tan_error">"TAN nevalabil. VerificaÈ›i intrarea dvs."</string> <!-- YTXT: Error text for the tan submission page (wrong characters) --> - <string name="submission_tan_character_error">"Intrare nevalabilă. VerificaÈ›i intrarea."</string> + <string name="submission_tan_character_error">"Intrarea dvs. conÈ›ine caractere nevalabile. Vă rugăm să o verificaÈ›i."</string> <!-- Submission Intro --> <!-- XHED: Page title for menu at the start of the submission process --> @@ -912,16 +949,27 @@ <!-- XHED: Page headline for the positive result additional warning page--> <string name="submission_positive_other_warning_headline">"Să ne ajutăm împreună!"</string> <!-- YTXT: Body text for the positive result additional warning page--> - <string name="submission_positive_other_warning_body">"Apoi, puteÈ›i să vă asiguraÈ›i că aplicaÈ›ia Corona-Warn trimite altor persoane ID-urile aleatorii din ultimele 14 zile. Prin aceasta, puteÈ›i avertiza È™i alte persoane È™i puteÈ›i contribui la întreruperea lanÈ›ului de infectare\n\nPentru că sunt transmise doar ID-uri aleatorii impersonale, identitatea dvs. va rămâne anonimă."</string> - <!-- XHED: Title for the privacy card--> - <string name="submission_positive_other_warning_privacy_title">"ConfidenÈ›ialitatea datelor"</string> - <!-- YTXT: Body text for the privacy card--> - <string name="submission_positive_other_warning_privacy_body">"By tapping on “Acceptâ€, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Informationâ€."</string> + <string name="submission_positive_other_warning_body">"Apoi, puteÈ›i să vă asiguraÈ›i că alte persoane sunt înÈ™tiinÈ›ate de posibila expunere.\n\nPentru aceasta, puteÈ›i transmite ID-urile dvs. aleatorii din ultimele 14 zile È™i, opÈ›ional, informaÈ›ii despre momentul în care aÈ›i observat prima dată simptomele de coronavirus, către serverul de schimb operat în comun de toate țările participante. De aici, ID-urile aleatorii È™i orice informaÈ›ii alegeÈ›i să furnizaÈ›i vor fi distribuite către utilizatorii aplicaÈ›iilor oficiale împotriva coronavirusului. ÃŽn acest mod, este posibilă avertizarea altor utilizatori de posibila lor expunere la dvs.\n\nSunt transmise doar ID-urile aleatorii, împreună cu orice alte informaÈ›ii pe care le furnizaÈ›i despre momentul în care aÈ›i observat primele simptome. Nu vor fi partajate date personale, precum numele, adresa sau locaÈ›ia dvs."</string> <!-- XBUT: other warning continue button --> - <string name="submission_positive_other_warning_button">"ÃŽnainte"</string> + <string name="submission_positive_other_warning_button">"Accept"</string> <!-- XACT: other warning - illustration description, explanation image --> <string name="submission_positive_other_illustration_description">"Un dispozitiv transmite un diagnostic de test pozitiv criptat către sistem."</string> + <!-- XHED: Title for the interop country list--> + <string name="submission_interoperability_list_title">"Următoarele țări participă în prezent la înregistrarea în jurnal a expunerilor la nivel transnaÈ›ional:"</string> + <!-- Submission Country Selector --> + <!-- XHED: Page title for the submission country selection page --> + <string name="submission_positive_country_selection_title">"Avertizări la nivel european"</string> + <!-- XHED: Page headline for the submission country selection page --> + <string name="submission_positive_country_selection_headline">"Ce țări aÈ›i vizitat în ultimele 14 zile?"</string> + <!-- XHED: Country selector headline for the submission country selection page --> + <string name="submission_country_selector_headline">"Am vizitat următoarele țări"</string> + <!-- XHED: Country no selection headline for the submission country selection page --> + <string name="submission_country_no_selection_headline">"Nu comentez"</string> + <!-- YTXT: Data FAQ for the submission country selection page --> + <string name="submission_country_selection_data_faq_body">"Intrarea dvs. este utilizată exclusiv pentru optimizarea volumului de date.\n\nLista conÈ›ine toate țările participante în prezent È™i este actualizată permanent."</string> + <!-- XBUT: submission country selection continue button --> + <string name="submission_country_selection_button">"ÃŽnainte"</string> <!-- Submission Done --> <!-- XHED: Page title for completed submission page --> @@ -931,7 +979,7 @@ <!-- XHED: Page subtitle for completed submission page --> <string name="submission_done_subtitle">"ReÈ›ineÈ›i:"</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"SunteÈ›i infectat."</string> + <string name="submission_done_contagious">"Autoritatea de sănătate publică vă va contacta în următoarele zile."</string> <!-- YTXT: text after submission: isolate --> <string name="submission_done_isolate">"IzolaÈ›i-vă de alte persoane."</string> <!-- XHED: Title for further info --> @@ -946,7 +994,35 @@ <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Gata"</string> <!-- XACT: submission finished - illustration description, explanation image --> - <string name="submission_done_illustration_description">"Toată lumea din grup aclamă deoarece o persoană È™i-a împărtășit rezultatul testului."</string> + <string name="submission_done_illustration_description">"AÈ›i resimÈ›it unul sau mai multe dintre următoarele simptome în ultimele zile?"</string> + + <!-- Submission Symptoms --> + <!-- XHED: Page title for symptom screens --> + <string name="submission_symptom_title">"Simptome"</string> + <!-- XTXT: headline text for initial symptom screen --> + <string name="submission_symptom_initial_headline">"AÈ›i resimÈ›it unul sau mai multe dintre următoarele simptome?"</string> + <!-- YTXT: explanation text for initial symptom screen --> + <string name="submission_symptom_initial_explanation">"PuteÈ›i indica momentul când È™i dacă aÈ›i observat simptomele specifice coronavirusului pentru a-i permite aplicaÈ›iei să calculeze mai exact riscul de infectare al altor utilizatori ai aplicaÈ›iei. Dacă nu doriÈ›i să furnizaÈ›i aceste informaÈ›ii, selectaÈ›i „Nu răspundâ€."</string> + <!-- YTXT: Bullet points for symptoms --> + <string-array name="submission_symptom_symptom_bullets"> + <item>"Temperatură crescută sau febră"</item> + <item>"Scurtarea respiraÈ›iei"</item> + <item>"Pierderea mirosului/gustului"</item> + <item>"Tuse"</item> + <item>"Curgerea nasului"</item> + <item>"Durere în gât"</item> + <item>"Durere de cap È™i dureri de membre"</item> + <item>"Slăbiciune generală È™i epuizare"</item> + </string-array> + <!-- XBUT: symptom initial screen yes button --> + <string name="submission_symptom_positive_button">"Da"</string> + <!-- XBUT: symptom initial screen no button --> + <string name="submission_symptom_negative_button">"Nu"</string> + <!-- XBUT: symptom initial screen no information button --> + <string name="submission_symptom_no_information_button">"Nu comentez"</string> + <!-- XBUT: symptom initial screen continue button --> + <string name="submission_symptom_further_button">"ÃŽnainte"</string> + <!-- Submission Contact --> <!-- XHED: Page title for contact page in submission flow --> @@ -977,6 +1053,22 @@ <!-- XACT: Content Description for submission contact step 2 --> <string name="submission_contact_step_2_content">"Al doilea pas: înregistraÈ›i-vă testul cu codul dvs. TAN în aplicaÈ›ie."</string> + <!-- Submission Symptom Calendar --> + <!-- XHED: Page title for calendar page in submission symptom flow --> + <string name="submission_symptom_calendar_title">"ÃŽnceputul simptomelor"</string> + <!-- XHED: Page headline for calendar page in symptom submission flow --> + <string name="submission_symptom_calendar_headline">"Când aÈ›i început să resimÈ›iÈ›i aceste simptome? "</string> + <!-- YTXT: Body text for calendar page in symptom submission flow--> + <string name="submission_symptom_calendar_body">"SelectaÈ›i data exactă din calendar sau, în cazul în care nu È›ineÈ›i minte data exactă, alegeÈ›i una dintre celelalte opÈ›iuni:"</string> + <!-- XBUT: symptom calendar screen less than 7 days button --> + <string name="submission_symptom_less_seven">"ÃŽn ultimele 7 zile"</string> + <!-- XBUT: symptom calendar screen 1-2 weeks button --> + <string name="submission_symptom_one_two_weeks">"Acum 1-2 săptămâni"</string> + <!-- XBUT: symptom calendar screen more than 2 weeks button --> + <string name="submission_symptom_more_two_weeks">"Cu peste 2 săptămâni în urmă"</string> + <!-- XBUT: symptom calendar screen verify button --> + <string name="submission_symptom_verify">"Nu comentez"</string> + <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> <string name="submission_status_card_title_fetching">"Datele sunt citite...."</string> @@ -1013,7 +1105,7 @@ <!-- YTXT: text for contagious card --> <string name="submission_status_card_positive_result_contagious">"SunteÈ›i infectat. IzolaÈ›i-vă de alte persoane."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"Autoritatea de sănătate publică vă va contacta în următoarele zile telefonic sau în scris."</string> + <string name="submission_status_card_positive_result_contact">"Autoritatea de sănătate publică vă va contacta în următoarele zile."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"TrimiteÈ›i ID-ul dvs. aleatoriu pentru a-i avertiza È™i pe alÈ›ii."</string> @@ -1040,6 +1132,9 @@ <item>"Nu mergeÈ›i la serviciu dacă nu vă simÈ›iÈ›i bine pentru a nu expune la risc alte persoane. Dacă simptomele dvs. se agravează, se poate să aveÈ›i nevoie de un test SARS-CoV-2 suplimentar."</item> </string-array> + <!-- XBUT Symptoms exact date button --> + <string name="symptoms_calendar_exact_date_button">"Data exactă"</string> + <!-- #################################### Button Tooltips for Accessibility ###################################### --> @@ -1085,6 +1180,10 @@ <string name="errors_generic_button_negative">"Detalii"</string> <!-- XTXT: error dialog - text when no error description is available --> <string name="errors_generic_text_unknown_error_cause">"A apărut o eroare necunoscută."</string> + <!-- XTXT: error dialog - text when a catastrophic error occured from which the app recovered automatically via data reset --> + <string name="errors_generic_text_catastrophic_error_recovery_via_reset">"AplicaÈ›ia dvs. a fost resetată din cauza unei probleme tehnice. Acest lucru nu are efect asupra funcÈ›ionalității aplicaÈ›iei. VeÈ›i continua să primiÈ›i notificări despre expuneri È™i îi veÈ›i putea avertiza pe ceilalÈ›i în continuare, în cazul în care sunteÈ›i testat pozitiv la COVID-19."</string> + <!-- XTXT: error dialog - link for the details button in the catastrophic error recovery dialog --> + <string name="errors_generic_text_catastrophic_error_encryption_failure">"https://www.coronawarn.app/en/faq/#cause9002_recovery"</string> <!-- #################################### Just for Development @@ -1092,10 +1191,6 @@ <!-- NOTR --> <string name="lorem_ipsum">"Lorem Ipsum"</string> <!-- NOTR --> - <string name="menu_test_api">"Test API"</string> - <!-- NOTR --> - <string name="menu_test_risk_level">"Test Risk Level"</string> - <!-- NOTR --> <string name="menu_test_notification">"Test Notification"</string> <!-- NOTR --> <string name="test_api_button_api_launch">"Android API Test(Manual Test)"</string> @@ -1136,4 +1231,121 @@ <!-- NOTR --> <string name="test_api_calculate_risk_level">"Calculate Risk Level"</string> + <!-- XHED: Country Entry for Austria --> + <string name="country_name_at">"Austria"</string> + <!-- XHED: Country Entry for Belgium --> + <string name="country_name_be">"Belgia"</string> + <!-- XHED: Country Entry for Bulgaria --> + <string name="country_name_bg">"Bulgaria"</string> + <!-- XHED: Country Entry for Switzerland --> + <string name="country_name_ch">"ElveÈ›ia"</string> + <!-- XHED: Country Entry for Cyprus --> + <string name="country_name_cy">"Cipru"</string> + <!-- XHED: Country Entry for Czech Republic --> + <string name="country_name_cz">"Republica Cehă"</string> + <!-- XHED: Country Entry for Germany --> + <string name="country_name_de">"Germania"</string> + <!-- XHED: Country Entry for Denmark --> + <string name="country_name_dk">"Danemarca"</string> + <!-- XHED: Country Entry for Estonia --> + <string name="country_name_ee">"Estonia"</string> + <!-- XHED: Country Entry for Spain --> + <string name="country_name_es">"Spania"</string> + <!-- XHED: Country Entry for Finland --> + <string name="country_name_fi">"Finlanda"</string> + <!-- XHED: Country Entry for France --> + <string name="country_name_fr">"FranÈ›a"</string> + <!-- XHED: Country Entry for Great Britain --> + <string name="country_name_uk">"Regatul Unit"</string> + <!-- XHED: Country Entry for Greece --> + <string name="country_name_gr">"Grecia"</string> + <!-- XHED: Country Entry for Croatia --> + <string name="country_name_hr">"CroaÈ›ia"</string> + <!-- XHED: Country Entry for Hungary --> + <string name="country_name_hu">"Ungaria"</string> + <!-- XHED: Country Entry for Ireland --> + <string name="country_name_ie">"Irlanda"</string> + <!-- XHED: Country Entry for Iceland --> + <string name="country_name_is">"Islanda"</string> + <!-- XHED: Country Entry for Italy --> + <string name="country_name_it">"Italia"</string> + <!-- XHED: Country Entry for Liechtenstein --> + <string name="country_name_li">"Liechtenstein"</string> + <!-- XHED: Country Entry for Lithuania --> + <string name="country_name_lt">"Lituania"</string> + <!-- XHED: Country Entry for Luxemburg --> + <string name="country_name_lu">"Luxemburg"</string> + <!-- XHED: Country Entry for Latvia --> + <string name="country_name_lv">"Letonia"</string> + <!-- XHED: Country Entry for Malta --> + <string name="country_name_mt">"Malta"</string> + <!-- XHED: Country Entry for Netherlands --> + <string name="country_name_nl">"Țările de Jos"</string> + <!-- XHED: Country Entry for Norway --> + <string name="country_name_no">"Norvegia"</string> + <!-- XHED: Country Entry for Poland --> + <string name="country_name_pl">"Polonia"</string> + <!-- XHED: Country Entry for Portugal --> + <string name="country_name_pt">"Portugalia"</string> + <!-- XHED: Country Entry for Rumania --> + <string name="country_name_ro">"România"</string> + <!-- XHED: Country Entry for Sweden --> + <string name="country_name_se">"Suedia"</string> + <!-- XHED: Country Entry for Slovenia --> + <string name="country_name_si">"Slovenia"</string> + <!-- XHED: Country Entry for Slovakia --> + <string name="country_name_sk">"Slovacia"</string> + + <!-- XHED: Title of the interoperbaility information view. --> + <string name="interoperability_title">"ÃŽnregistrare transnaÈ›ională\na expunerilor în jurnal"</string> + + <!-- XHED: Setting title of interoperability in the tracing settings view --> + <string name="settings_interoperability_title">"ÃŽnregistrare transnaÈ›ională a expunerilor în jurnal"</string> + <!-- XTXT: Settings description of the interoperability in the tracing settings view --> + <string name="settings_interoperability_subtitle">"Țări participante"</string> + + <!-- XHED: Header of interoperability information/configuration view --> + <string name="interoperability_configuration_title">"ÃŽnregistrare transnaÈ›ională a expunerilor în jurnal"</string> + <!-- XTXT: First section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_first_section">"Mai multe țări colaborează pentru a susÈ›ine alarmele transnaÈ›ionale printr-un server de schimb comun. De exemplu, contactele cu utilizatorii unei aplicaÈ›ii oficiale anticoronavirus din alte țări participante pot fi, de asemenea, luate în considerare pentru înregistrarea în jurnal a expunerilor."</string> + <!-- XTXT: Second section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_second_section">"Pentru aceasta, aplicaÈ›ia descarcă o listă care este actualizată zilnic de ID-uri aleatorii ale tuturor utilizatorilor care È™i-au partajat ID-urile aleatorii prin propria aplicaÈ›ie. Această listă este apoi comparată cu ID-urile aleatorii înregistrate de smartphone-ul dvs. Descărcarea zilnică a listei de ID-uri aleatorii este, de obicei, gratuită pentru dvs. – nu veÈ›i suporta costuri pentru datele utilizate de aplicaÈ›ie în acest context È™i nu vor fi aplicate costuri de roaming pentru această opÈ›iune în alte țări UE."</string> + <!-- XHED: Header right above the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_list_title">"Următoarele țări participă în prezent la înregistrarea în jurnal a expunerilor la nivel transnaÈ›ional:"</string> + <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_information">"ÃŽnÈ™tiinÈ›area de confidenÈ›ialitate a aplicaÈ›iei (inclusiv informaÈ›iile despre prelucrarea datelor efectuată pentru caracteristica de înregistrare în jurnal a expunerilor la nivel transnaÈ›ional) poate fi găsită în meniu la „InformaÈ›ii aplicaÈ›ie†> „ConfidenÈ›ialitate dateâ€."</string> + + <!-- XHED: Sub header introducing interoperability in the tracing step of onboarding --> + <string name="interoperability_onboarding_title">"ÃŽnregistrare transnaÈ›ională\na expunerilor în jurnal"</string> + <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> + <string name="interoperability_onboarding_first_section">"Mai multe țări s-au asociat pentru a susÈ›ine avertizarea la nivel transnaÈ›ional. Cu alte cuvinte, acum poate fi luată în considerare posibila dvs. expunere la utilizatori ai aplicaÈ›iilor oficiale anticoronavirus din toate țările participante."</string> + <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> + <string name="interoperability_onboarding_second_section">"Când un utilizator transmite ID-urile sale aleatorii la serverul de schimb operat în comun de țările participante, utilizatorii aplicaÈ›iilor oficiale anticoronavirus din toate aceste țări pot fi avertizaÈ›i de posibila expunere."</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_randomid_download_free">"Descărcarea zilnică a listei cu ID-urilor aleatorii este, de obicei, gratuită pentru dvs. ÃŽn mod specific, aceasta înseamnă că operatorii de reÈ›ele mobile nu percep costuri pentru datele utilizate de aplicaÈ›ie în acest context È™i nu aplică niciun fel de costuri de roaming pentru această opÈ›iune în alte țări UE. ContactaÈ›i operatorul reÈ›elei mobile pentru mai multe informaÈ›ii."</string> + <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> + <string name="interoperability_onboarding_list_title">"ÃŽn prezent participă următoare țări:"</string> + + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 1 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_1">"CondiÈ›iile de utilizare au fost, de asemenea, actualizate, pentru a reflecta îmbunătățirile funcÈ›ionale ale aplicaÈ›iei."</string> + <!-- XLNK: Terms of use link inside delta interoperability screen--> + <string name="interoperability_onboarding_delta_terms_link">"AfiÈ™are condiÈ›ii de utilizare"</string> + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 2 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_2">"CondiÈ›iile de utilizare È™i înÈ™tiinÈ›area privind confidenÈ›ialitatea pot fi găsite, de asemenea, în meniu la „InformaÈ›ii aplicaÈ›ieâ€, dar È™i în descrierea aplicaÈ›iei din App Store. Modificările nu vor afecta modul în care utilizaÈ›i aplicaÈ›ia. Dacă veÈ›i continua să utilizaÈ›i aplicaÈ›ia sau dacă o redeschideÈ›i, vom presupune că sunteÈ›i de acord cu CondiÈ›iile de utilizare actualizate."</string> + + <!-- XACT: interoperability (eu) - illustraction description, explanation image --> + <string name="interoperability_eu_illustration_description">"O mână È›ine un smartphone. ÃŽn fundal sunt ilustrate Europa È™i steagul european."</string> + + <!-- XTXT: Title for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_title_failrequest">"Țări participante"</string> + <!-- XTXT: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest">"PuteÈ›i vedea țările participante în detaliile înregistrării în jurnal a expunerilor."</string> + + <!-- YDES: Title for the interoperability onboarding if country download fails for Risk Details --> + <string name="interoperability_onboarding_list_title_riskdetection_no_network">"ÃŽn prezent, nu pot fi afiÈ™ate țările."</string> + <!-- YMSW: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest_no_network">"Se poate să fi pierdut conexiunea la internet. AsiguraÈ›i-vă că sunteÈ›i conectat la internet."</string> + <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> + <string name="interoperability_onboarding_list_button_title_no_network">"DeschideÈ›i setările dispozitivului"</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml b/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..abc2d1e3df2d7172f8a1ad997ada03b7625580a8 --- /dev/null +++ b/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- XHED: Header of private data in the delta onboarding interoperability view --> + <string name="interoperability_onboarding_delta_footerTitle">"Veri iÅŸlemeye iliÅŸkin notlar"</string> + <!-- XTXT: Description of private data in the delta onboarding interoperability view. Below interoperability_onboarding_delta_footerTitle --> + <string name="interoperability_onboarding_delta_footerDescription">"Uygulamanın katılımcı ülkelerdeki kullanıcılarıyla bir riskli temasa maruz kalıp kalmadığınızı ve bu nedenle sizin için bir enfeksiyon riski olup olmadığını öğrenmek için hiçbir ÅŸeyi deÄŸiÅŸtirmenize gerek yoktur. Sadece maruz kalma günlüğünü etkinleÅŸtirmeniz yeterlidir. Maruz kalma günlüğü, bir Corona-Warn-App kullanıcısı veya diÄŸer bir resmi Korona uygulaması kullanıcısı ile yaÅŸadığınız tüm riske maruz kalmalarda sizi otomatik olarak uyarır.\n\nCOVID-19 bildirim sistemi etkinleÅŸtirildiÄŸinde, Android akıllı telefonunuz sürekli olarak rastgele kimlik no’ları oluÅŸturur ve bunları Bluetooth aracılığıyla göndererek çevrenizdeki akıllı telefonlar tarafından alınabilmelerini saÄŸlar. Öte yandan, kendi Android akıllı telefonunuz da diÄŸer akıllı telefonlardan rastgele kimlik no’ları alır. Kendi rastgele kimlik no’larınız ve diÄŸer akıllı telefonlardan alınan kimlik no’ları, Android akıllı telefonunuz tarafından kaydedilir ve orada 14 gün boyunca saklanır.\n\nMaruz kalma günlüğü için uygulama, böyle bir teması bu uygulama üzerinden paylaÅŸan tüm kullanıcıların rastgele kimlik no'larını içeren ve günlük olarak güncellenen bir liste indirir. Daha sonra bu liste, akıllı telefonunuz tarafından kaydedilen rastgele kimlik no’ları ile karşılaÅŸtırılır.\n\nBir riske maruz kalma tespit edilirse, Korona uygulaması sizi bu konuda bilgilendirir. Böyle bir durumda uygulama, akıllı telefonunuz tarafından kaydedilen maruz kalma verilerine (temasın tarihi, süresi ve Bluetooth sinyal gücü) eriÅŸir. DiÄŸer kullanıcıya olan mekânsal mesafe, Bluetooth sinyal gücü üzerinden elde edilir (sinyal ne kadar güçlüyse, mesafe o kadar kısadır). Bu veriler, enfeksiyon riskinizi hesaplamak ve nasıl davranmanız gerektiÄŸi konusunda size önerilerde bulunmak üzere uygulama tarafından deÄŸerlendirilir. Bu deÄŸerlendirme iÅŸlemi, sadece kendi akıllı telefonunuzda gerçekleÅŸtirilir.\n\nSizden baÅŸka hiç kimse (RKI (Robert Koch Enstitüsü) veya katılımcı ülkelerin saÄŸlık kurumu yetkilileri bile), enfeksiyon riskine maruz kalıp kalmadığınızı ve sizin için nasıl bir enfeksiyon riskinin saptandığını öğrenemez.\n\nUygulamanın veri gizliliÄŸi beyanını (sınır ötesi maruz kalma günlüğü için veri iÅŸlemeye iliÅŸkin bilgiler de dahil) „Uygulama bilgileri“ > „Veri gizliliÄŸi“ menü öğeleri altında bulabilirsiniz."</string> + <!-- XHED: Header of the delta onboarding screen for interoperability. If the user opens the app for the first time after the interoperability update --> + <string name="interoperability_onboarding_delta_title">Sınır ötesi maruz kalma günlüğü</string> + <!-- XTXT: Description of the interoperability extension of the app. Below interoperability_onboarding_delta_title --> + <string name="interoperability_onboarding_delta_subtitle">Corona-Warn-App’ın iÅŸlevi geniÅŸletildi. Sınır ötesi uyarıları mümkün kılmak adına, artık birçok ülke ortaklaÅŸa iÅŸletilen bir veri deÄŸiÅŸim sunucusu üzerinden birlikte çalışmaktadır. Artık diÄŸer katılımcı ülkelerdeki resmi Korona uygulamalarının kullanıcılarıyla oluÅŸan temaslar da enfeksiyon riskine maruz kalma günlüğünde dikkate alınabilmektedir.</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_delta_randomid">Bu amaç doÄŸrultusunda Korona uygulaması, kendi uygulaması üzerinden paylaşımda bulunan tüm kullanıcıların rastgele kimlik no’larını içeren ve günlük olarak güncellenen bir liste indirir. Daha sonra bu liste, akıllı telefonunuz tarafından kaydedilen rastgele kimlik no’ları ile karşılaÅŸtırılır.</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_delta_free_download">Rastgele kimlik no’ları içeren bu listenin günlük olarak indirilmesi genellikle sizin için ücretsiz gerçekleÅŸir. Bu demektir ki: Uygulamanın neden olduÄŸu veri hacmi, mobil aÄŸ operatörleri tarafından hesaba geçirilmez ve diÄŸer AB ülkelerinde herhangi bir uluslararası dolaşım (roaming) ücreti alınmaz. Mobil aÄŸ operatörünüzden bu konuda ayrıntılı bilgi edinebilirsiniz.</string> + <!-- XHED: Title for the privacy card--> + <string name="submission_positive_other_warning_privacy_title">"Onay beyanı"</string> + <!-- YTXT: Body text for the privacy card--> + <string name="submission_positive_other_warning_privacy_body">"<b>“Kabul etâ€e tıkladığınızda, son 14 gün içinde oluÅŸan rastgele kimlik no’larınız ve olası semptomların baÅŸlangıcı ile ilgili tüm verilerin uygulamanın sunucu sistemine iletilmesine izin vermiÅŸ olursunuz.</b> Bu veriler, temas halinde olduÄŸunuz uygulama kullanıcıları için enfeksiyon riskini deÄŸerlendirmek ve olası bir enfeksiyon riski durumunda onları uyarmak için kullanılır. DiÄŸer katılımcı ülkelerdeki resmi Korona uygulamalarının kullanıcılarının da uyarılması adına, bu veriler aynı zamanda uygulamanın sunucu sistemi tarafından katılımcı ülkelerin ortaklaÅŸa iÅŸletilen veri deÄŸiÅŸim sunucusuna da gönderilmektedir.\n\nNe diÄŸer kullanıcılar, ne de RKI (Robert Koch Enstitüsü) veya katılımcı ülkelerin saÄŸlık kurumu yetkilileri, aktarılan bu veriler üzerinden sizin kimliÄŸinizi, adınızı veya diÄŸer kiÅŸisel bilgilerinizi öğrenebilir.\n\nSınır ötesi uyarılar için rastgele kimlik no’larının ve olası semptomların baÅŸlangıcı ile ilgili verilerin aktarılması isteÄŸe baÄŸlı gerçekleÅŸir. Bu verileri aktarmak istemezseniz, bu durum sizin için herhangi bir sakınca doÄŸurmaz. Bu uygulamayı kullanıp kullanmadığınız ve nasıl kullandığınız, takip ve kontrol edilemediÄŸinden, rastgele kimlik no’larınızı kullanıma açıp açmadığınızı sizden baÅŸka hiç kimse bilemez.\n\nVermiÅŸ olduÄŸunuz onayı, istediÄŸiniz an bu uygulamayı silmek suretiyle iptal edebilirsiniz. VerilmiÅŸ olan onayın iptali, iptal iÅŸlemi geçerli oluncaya kadar bu onay temelinde yürütülmüş olan iÅŸlemlerin yasalara uygunluÄŸunu etkilemez.\n\nKatılımcı ülkeler ve veri korumasından sorumlu saÄŸlık kurumu hakkında daha fazla bilgiyi „Uygulama bilgileri“ > „Veri gizliliÄŸi“ menü öğeleri altında bulabilirsiniz."</string> + <!-- XHED: onboarding(tracing) - headline for consent information --> + <string name="onboarding_tracing_headline_consent">"Onay beyanı"</string> + <!-- YTXT: onboarding(tracing) - body for consent information --> + <string name="onboarding_tracing_body_consent">"DiÄŸer katılımcı ülkelerdeki uygulama kullanıcılarıyla bir riskli temasa maruz kalıp kalmadığınızı ve bu nedenle bir enfeksiyon riski olup olmadığını öğrenmek için, maruz kalma günlüğünü etkinleÅŸtirmeniz gerekmektedir. “Maruz kalma günlüğünü etkinleÅŸtir†tuÅŸuna tıkladığınızda, uygulamanızdaki maruz kalma günlüğünü ve ilgili veri iÅŸlemenin etkinleÅŸtirilmesini kabul etmiÅŸ olursunuz.\n\n Maruz kalma günlüğünü kullanabilmek için, ayrıca Android akıllı telefonunuzdaki Google tarafından saÄŸlanan “COVID-19 bildirimleri†iÅŸlevini de etkinleÅŸtirmeniz ve Corona-Warn-App’ı kullanıma açmanız gerekir.\n\n COVID-19 bildirim sistemi etkinleÅŸtirildiÄŸinde, Android akıllı telefonunuz sürekli olarak rastgele kimlik no’ları oluÅŸturur ve bunları Bluetooth aracılığıyla göndererek çevrenizdeki akıllı telefonlar tarafından alınabilmelerini saÄŸlar. Öte yandan, kendi Android akıllı telefonunuz da diÄŸer akıllı telefonlardan rastgele kimlik no’ları alır. Kendi rastgele kimlik no’larınız ve diÄŸer akıllı telefonlardan alınan kimlik no’ları, Android akıllı telefonunuz tarafından kaydedilir ve orada 14 gün boyunca saklanır.\n\nMaruz kalma günlüğü için uygulama, böyle bir teması bu uygulama üzerinden paylaÅŸan tüm kullanıcıların rastgele kimlik no'larını içeren ve günlük olarak güncellenen bir liste indirir. Daha sonra bu liste, akıllı telefonunuz tarafından kaydedilen rastgele kimlik no’ları ile karşılaÅŸtırılır.\n\nBir riske maruz kalma tespit edilirse, Korona uygulaması sizi bu konuda bilgilendirir. Böyle bir durumda uygulama, akıllı telefonunuz tarafından kaydedilen maruz kalma verilerine (temasın tarihi, süresi ve Bluetooth sinyal gücü) eriÅŸir. DiÄŸer kullanıcıya olan mekânsal mesafe, Bluetooth sinyal gücü üzerinden elde edilir (sinyal ne kadar güçlüyse, mesafe o kadar kısadır). Bu veriler, enfeksiyon riskinizi hesaplamak ve nasıl davranmanız gerektiÄŸi konusunda size önerilerde bulunmak üzere uygulama tarafından deÄŸerlendirilir. Bu deÄŸerlendirme iÅŸlemi, sadece kendi akıllı telefonunuzda gerçekleÅŸtirilir.\n\nSizden baÅŸka hiç kimse (RKI (Robert Koch Enstitüsü) veya katılımcı ülkelerin saÄŸlık kurumu yetkilileri bile), enfeksiyon riskine maruz kalıp kalmadığınızı ve sizin için nasıl bir enfeksiyon riskinin saptandığını öğrenemez.\n\nMaruz kalma günlüğüne vermiÅŸ olduÄŸunuz onayı iptal etmek için, uygulamadaki kaydırıcıyı kullanarak, iÅŸlevi devre dışı bırakabilir veya uygulamayı silebilirsiniz. Maruz kalma günlüğünü tekrar kullanmak isterseniz, kaydırıcıyı yeniden etkinleÅŸtirebilir veya uygulamayı yeniden yükleyebilirsiniz. Maruz kalma günlüğünü devre dışı bırakırsanız, uygulama, artık riskle karşılaşıp karşılaÅŸmadığınızı denetleyemez. Rastgele kimlik no’larının gönderilmesini ve tarafınızdan alınmasını durdurmak için, Android akıllı telefonunuzdaki COVID-19 bildirim sistemini devre dışı bırakmanız gerekir. Android akıllı telefonunuzun COVID-19 bildirim sistemi tarafından kaydedilen kendinize ait ve dışarıdan gelen rastgele kimlik no’larının uygulama tarafından silinmediÄŸini unutmayın. Bunları, sadece Android akıllı telefonunuzun ayarlarından kalıcı olarak silebilirsiniz.\n\nUygulamanın veri gizliliÄŸi beyanını (sınır ötesi maruz kalma günlüğü için veri iÅŸlemeye iliÅŸkin bilgiler de dahil) „Uygulama bilgileri“ > „Veri gizliliÄŸi“ menü öğeleri altında bulabilirsiniz."</string> +</resources> diff --git a/Corona-Warn-App/src/main/res/values-tr/strings.xml b/Corona-Warn-App/src/main/res/values-tr/strings.xml index 98808553c5f60bc14d6661af6004bbf825d4eb7f..62d35a5b58357a2a9a91cb004a4128657180069b 100644 --- a/Corona-Warn-App/src/main/res/values-tr/strings.xml +++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml @@ -212,9 +212,9 @@ <!-- XHED: main, FAQ --> <string name="main_about_headline">"SSS"</string> <!-- XTXT: main, explains faq on card --> - <string name="main_about_body">"Bu bölümde, Corona-Warn-App hakkında sık sorulan soruların yanıtlarını bulabilirsiniz. Harici bir web sitesine yönlendirileceksiniz."</string> + <string name="main_about_body">"Bu bölümde, Corona-Warn-App hakkında sık sorulan soruların yanıtlarını bulabilirsiniz. Alman hükûmetinin harici bir web sitesine yönlendirileceksiniz."</string> <!-- XTXT: FAQ link, should be translated --> - <string name="main_about_link">"https://www.bundesregierung.de/corona-warn-app-faq-englisch"</string> + <string name="main_about_link">"https://www.bundesregierung.de/corona-warn-app-faq-tuerkisch"</string> <!-- XACT: Opens external webpage --> <string name="hint_external_webpage">"Bu bölümde, Corona-Warn-App hakkında sık sorulan soruların yanıtlarını bulabilirsiniz. Harici bir web sitesine yönlendirileceksiniz."</string> @@ -282,7 +282,7 @@ <!-- YTXT: App overview body for glossary notifications --> <string name="main_overview_body_glossary_notification">"Corona-Warn-App\'te maruz kalmalara iliÅŸkin görüntü."</string> <!-- XHED: App overview subtitle for glossary keys --> - <string name="main_overview_subtitle_glossary_keys">"Rastgele Kimlikler"</string> + <string name="main_overview_subtitle_glossary_keys">"Rastgele Kimlik"</string> <!-- YTXT: App overview body for glossary keys --> <string name="main_overview_body_glossary_keys">"Rastgele Kimlikler, rastgele oluÅŸturulan rakam ve harf kombinasyonlarıdır. Yakın mesafedeki cihazlar arasında deÄŸiÅŸtirilir. Rastgele Kimlikler belirli bir kiÅŸiyi izlemek üzere kullanılamaz ve 14 günün sonunda otomatik olarak silinir. COVID-19 tanısı konan kiÅŸiler son 14 güne kadar rastgele kimliklerinin uygulamanın diÄŸer kullanıcıları ile paylaşılmasını seçebilir."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> @@ -345,7 +345,7 @@ <!-- YTXT: risk details - low risk explanation text --> <string name="risk_details_information_body_low_risk">"Daha sonra COVID-19 tanısı konan kiÅŸilere maruz kaldığınıza dair bir günlük kaydı oluÅŸturulmadığı veya bu kiÅŸilerle yalnızca kısa süreyle ve uzak mesafeden karşılaÅŸtığınız için enfeksiyon riskiniz düşüktür."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"Enfeksiyon riskiniz, maruz kalma günlüğünün verileri kullanılarak yerel olarak cihazınızda hesaplanır. Hesaplamada COVID-19 tanısı konan kiÅŸilere maruz kalma mesafesi ve süresinin yanında potansiyel enfeksiyon bulaÅŸtırma durumu da göz önünde bulundurulur. Enfeksiyon riskiniz bir baÅŸkası tarafından görüntülenemez ya da bir baÅŸkasına aktarılamaz."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"Enfeksiyon riskiniz, maruz kalma günlüğünün verileri kullanılarak yerel olarak akıllı telefonunuzda hesaplanır. Hesaplamada COVID-19 tanısı konan kiÅŸilere maruz kalma mesafesi ve süresinin yanında potansiyel enfeksiyon bulaÅŸtırma durumu da göz önünde bulundurulur. Enfeksiyon riskiniz bir baÅŸkası tarafından görüntülenemez ya da bir baÅŸkasına aktarılamaz."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> <item quantity="one">"En son %1$s gün önce, COVID-19 tanısı konan en az bir kiÅŸiyle daha uzun süreyle ve yakın mesafeden maruz kalma yaÅŸadığınız için enfeksiyon riskiniz daha yüksektir."</item> @@ -372,6 +372,8 @@ <string name="risk_details_explanation_dialog_title">"Maruz kalma günlüğü iÅŸlevi hakkında bilgi"</string> <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information--> <string name="risk_details_explanation_dialog_faq_body">"Daha fazla bilgi için lütfen SSS sayfamıza bakın."</string> + <!-- XLNK: risk explanations and informations - pointing to the faq page for more information and contains hyperlink--> + <string name="risk_details_explanation_faq_body_with_link"><a href="https://www.coronawarn.app/en/faq/#encounter_but_green">"Daha fazla bilgi için lütfen SSS sayfamıza bakın."</a></string> <!-- #################################### Onboarding @@ -390,7 +392,7 @@ <!-- XTXT: onboarding - back description for screen reader --> <string name="onboarding_button_back_description">"Geri"</string> <!-- XACT: Onboarding (together) page title --> - <string name="onboarding_onboarding_accessibility_title">"EtkinleÅŸtirme sayfası 1/5: Koronavirüs ile birlikte mücadele edelim"</string> + <string name="onboarding_onboarding_accessibility_title">"EtkinleÅŸtirme sayfası 1/6: Koronavirüs ile birlikte mücadele edelim"</string> <!-- XHED: onboarding(together) - fight corona --> <string name="onboarding_headline">"Koronavirüs ile birlikte mücadele edelim"</string> <!-- XHED: onboarding(together) - two/three line headline under an illustration --> @@ -402,28 +404,26 @@ <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"Bölgedeki bir grup insan akıllı telefonlarını kullanıyor."</string> <!-- XACT: Onboarding (privacy) page title --> - <string name="onboarding_privacy_accessibility_title">"EtkinleÅŸtirme sayfası 2/5: Veri GizliliÄŸi. Uzun bir metin yerleÅŸtirilecektir. DilediÄŸiniz zaman devam etmek için ekranın alt kısmındaki düğmeyi kullanın."</string> + <string name="onboarding_privacy_accessibility_title">"EtkinleÅŸtirme sayfası 2/6: Veri GizliliÄŸi. Uzun bir metin yerleÅŸtirilecektir. DilediÄŸiniz zaman devam etmek için ekranın alt kısmındaki düğmeyi kullanın."</string> <!-- XHED: onboarding(privacy) - title --> <string name="onboarding_privacy_headline">"Veri GizliliÄŸi"</string> <!-- XACT: onboarding(privacy) - illustraction description, header image --> <string name="onboarding_privacy_illustration_description">"Bir kadın akıllı telefonunda Corona-Warn-App\'i kullanıyor. Kılıfın arka planındaki kilit, ÅŸifrelenmiÅŸ verilerin simgesidir."</string> <!-- XACT: Onboarding (tracing) page title --> - <string name="onboarding_tracing_accessibility_title">"EtkinleÅŸtirme sayfası 3/5: Maruz Kalma Günlüğünü EtkinleÅŸtirme"</string> + <string name="onboarding_tracing_accessibility_title">"EtkinleÅŸtirme sayfası 3/6: Maruz Kalma Günlüğünü EtkinleÅŸtirme"</string> <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"Maruz Kalma Günlüğünü EtkinleÅŸtirme"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> <string name="onboarding_tracing_subtitle">"Enfeksiyon riski taşıyıp taşımadığınızı belirlemek için maruz kalma günlüğü özelliÄŸini etkinleÅŸtirmeniz gerekir."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"Maruz kalma günlüğü, cihazınızın Bluetooth üzerinden diÄŸer kullanıcıların ÅŸifrelenmiÅŸ rastgele kimliklerini alması ve size ait rastgele kimliÄŸi diÄŸer kullanıcıların cihazlarına aktarmasıyla çalışır. Bu özellik dilediÄŸiniz zaman devre dışı bırakılabilir."</string> + <string name="onboarding_tracing_body">"Maruz kalma günlüğü, akıllı telefonunuzun Bluetooth üzerinden diÄŸer kullanıcıların ÅŸifrelenmiÅŸ rastgele kimliklerini alması ve size ait rastgele kimlikleri diÄŸer kullanıcıların akıllı telefonlarına aktarmasıyla çalışır. Maruz kalma günlüğü, dilediÄŸiniz zaman devre dışı bırakılabilir."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body_emphasized">"ÅžifrelenmiÅŸ rastgele kimlikler yalnızca tarih, süre ve yakınlık (sinyal gücünü kullanarak) hakkındaki bilgileri aktarır. Ad, adres, konum gibi kiÅŸisel veriler asla kaydedilmez. KiÅŸilerin kimliÄŸi belirlenemez."</string> + <string name="onboarding_tracing_body_emphasized">"ÅžifrelenmiÅŸ rastgele kimlikler diÄŸer kullanıcılara yalnızca tarih, süre ve yakınlık (sinyal gücü ile hesaplanır) hakkındaki bilgileri aktarır. KiÅŸilerin kimlikleri rastgele kimliklere göre belirlenemez."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> <string name="onboarding_tracing_easy_language_explanation"><a href="https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache">"BasitleÅŸtirilmiÅŸ Dilde ve Ä°ÅŸaret Dilinde Uygulama Bilgileri"</a></string> - <!-- XHED: onboarding(tracing) - headline for consent information --> - <string name="onboarding_tracing_headline_consent">"Kabul Beyanı"</string> - <!-- YTXT: onboarding(tracing) - body for consent information --> - <string name="onboarding_tracing_body_consent">"Enfekte olan biriyle temas halinde olup olmadığınızı ve sizin de enfeksiyon riski altında olup olmadığınızı öğrenmek için Uygulamanın maruz kalma günlüğü özelliÄŸini etkinleÅŸtirmeniz gerekir. \"EtkinleÅŸtir\" düğmesine dokunarak Uygulamanın maruz kalma günlüğü özelliÄŸini etkinleÅŸtirmeyi ve iliÅŸkili verilerin iÅŸlenmesini kabul edersiniz."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulamanın maruz kalma günlüğü özelliÄŸini kullanmak için akıllı telefonunuzda Google tarafından sunulan COVID-19\'a Maruz Kalma Günlüğü iÅŸlevini etkinleÅŸtirmeniz ve Corona-Warn-App\'e bu iÅŸlevi kullanma izni vermeniz gerekecektir."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Maruz kalma günlüğü etkinleÅŸtirildiÄŸinde akıllı telefonunuz sürekli olarak rastgele kimlikler oluÅŸturur ve bu rastgele kimlikleri maruz kalma günlüğü etkinleÅŸtirilmiÅŸ olan yakınınızdaki diÄŸer Android veya Apple akıllı telefonlara Bluetooth üzerinden aktarır. Bunun karşılığında akıllı telefonunuz diÄŸer akıllı telefonların rastgele kimliklerini alır. Size ait olan ve diÄŸer akıllı telefonlardan alınan rastgele kimlikler, maruz kalma günlüğüne kaydedilir ve 14 gün süreyle burada saklanır."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulama, enfeksiyon riskinizi belirlemek için koronavirüs enfeksiyonu olduÄŸunu Uygulamada belirten tüm kullanıcıların rastgele kimliklerinin listesini (günde birkaç kez veya talep üzerine) yükler. Ardından bu liste maruz kalma günlüğünde tutulan rastgele kimliklerle karşılaÅŸtırılır. Uygulama enfekte olan bir kullanıcı ile temas halinde olabileceÄŸinizi saptadığında bu konuda bilgilendirilirsiniz ve sizin de enfeksiyon riski taşıdığınız belirtilir. Bu durumda Uygulama akıllı telefonunuzun maruz kalma günlüğünde tutulan diÄŸer verilere (tarih, süre ve temas sırasındaki Bluetooth sinyalinin gücü) eriÅŸir."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Bluetooth sinyal gücü, fiziksel mesafenin belirlenmesi için kullanılır (sinyal ne kadar güçlü olursa mesafe o kadar kısa olur). Ardından Uygulama, koronavirüs enfeksiyonu olasılığınızı deÄŸerlendirmek ve sonraki adımlara yönelik öneriler sunmak üzere bu bilgileri analiz eder. Bu analiz akıllı telefonunuzda yalnızca yerel olarak gerçekleÅŸtirilir. Sizin dışınızda hiç kimse (RKI bile) enfekte olan biriyle temas ettiÄŸinizi ve sizin için belirlenen riski bilmez."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Maruz kalma günlüğüne verdiÄŸiniz onayı geri çekmek için Uygulamadaki düğmeyi kullanarak veya Uygulamayı silerek özelliÄŸi devre dışı bırakabilirsiniz. Maruz kalma günlüğü özelliÄŸini yeniden kullanmaya karar verirseniz özelliÄŸi geri açabilir veya Uygulamayı yeniden yükleyebilirsiniz. Maruz kalma günlüğü özelliÄŸini devre dışı bırakırsanız Uygulama artık enfekte olan bir kullanıcı ile temas halinde olup olmadığınızı kontrol etmez. Cihazınızın rastgele kimlik göndermesini ve almasını durdurmak isterseniz de akıllı telefonunuzun ayarlarında COVID-19\'a Maruz Kalma Günlüğü özelliÄŸini devre dışı bırakmanız gerekir. Size ait olan ve diÄŸer akıllı telefonlardan alınan maruz kalma günlüğündeki rastgele kimliklerin Uygulamada silinmeyeceÄŸini unutmayın. Akıllı telefonunuzun ayarlarında yalnızca maruz kalma günlüğünde tutulan verileri kalıcı olarak silebilirsiniz."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Uygulamanın gizlilik bildirimini (maruz kalma günlüğü özelliÄŸi için gerçekleÅŸtirilen veri iÅŸlemeye iliÅŸkin açıklama dahil) menüde \"Veri GizliliÄŸi Bilgileri\" baÅŸlığında bulabilirsiniz."</string> + <!-- NOTR: onboarding(tracing) - easy language explain tracing link URL--> + <string name="onboarding_tracing_easy_language_explanation_url">"https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache"</string> <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_button_next">"Maruz Kalma Günlüğünü EtkinleÅŸtir"</string> <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined --> @@ -465,7 +465,7 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Cihaz Ayarlarını Aç"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"EtkinleÅŸtirme sayfası 4/5: Size COVID-19 tanısı konduysa..."</string> + <string name="onboarding_test_accessibility_title">"EtkinleÅŸtirme sayfası 5/6: Size COVID-19 tanısı konduysa..."</string> <!-- XHED: onboarding(test) - about positive tests --> <string name="onboarding_test_headline">"COVID-19 tanısı aldıysanız..."</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> @@ -475,7 +475,7 @@ <!-- XACT: onboarding(test) - illustraction description, header image --> <string name="onboarding_test_illustration_description">"ÅžifrelenmiÅŸ bir pozitif test tanısı sisteme aktarılır ve diÄŸer kullanıcılar uyarılır."</string> <!-- XACT: Onboarding (datashare) page title --> - <string name="onboarding_notifications_accessibility_title">"EtkinleÅŸtirme sayfası 5/5: Uyarıları alma ve riskleri belirleme"</string> + <string name="onboarding_notifications_accessibility_title">"EtkinleÅŸtirme sayfası 6/6: Uyarıları alma ve riskleri belirleme"</string> <!-- XHED: onboarding(datashare) - about positive tests --> <string name="onboarding_notifications_headline">"Uyarıları alma ve riskleri belirleme"</string> <!-- XHED: onboarding(datashare) - two/three line headline under an illustration --> @@ -485,6 +485,17 @@ <!-- XACT: onboarding(notifications) - illustraction description, header image --> <string name="onboarding_notifications_illustration_description">"Bir kadın Corona-Warn-App uygulamasından bildirim alıyor."</string> + <!-- #################################### + Onboarding sixteen include + ###################################### --> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_title_text">"YaÅŸ Sınırı: 16 ve Ãœzeri"</string> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_description_text">"Bu uygulama, 16 yaÅŸ ve üzerinde olan ve Almanya\'da yaÅŸayan kiÅŸilerin kullanması için hazırlanmıştır."</string> + + <!-- #################################### Settings ###################################### --> @@ -498,7 +509,7 @@ <!-- XHED: settings(tracing) - page title --> <string name="settings_tracing_title">"Maruz Kalma Günlüğü"</string> <!-- XHED: settings(tracing) - headline bellow illustration --> - <string name="settings_tracing_headline">"Maruz kalma günlüğü bu ÅŸekilde çalışır"</string> + <string name="settings_tracing_headline">"Maruz kalma günlüğü nasıl çalışır?"</string> <!-- XTXT: settings(tracing) - explain text in settings overview under headline --> <string name="settings_tracing_body_description">"COVID-19 rastgele kimliklerinin oluÅŸturulmasına ve paylaşılmasına izin verin."</string> <!-- XTXT: settings(tracing) - shows status under header in home, active --> @@ -508,7 +519,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"Konum hizmetleri devre dışı bırakıldı"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"Enfeksiyon riski taşıyıp taşımadığınızı belirlemek için maruz kalma günlüğü özelliÄŸini etkinleÅŸtirmeniz gerekir. Risk belirleme, cihazınızın Bluetooth üzerinden diÄŸer kullanıcıların rastgele kimliklerini alması ve size ait rastgele kimlikleri diÄŸer kullanıcıların cihazlarına göndermesi ile çalışır. Bu özelliÄŸi dilediÄŸiniz zaman devre dışı bırakabilirsiniz."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"ÅžifrelenmiÅŸ rastgele kimliklerde diÄŸer kiÅŸilere yalnızca tarih, süre ve yakınlık bilgileri (sinyal gücüne göre hesaplanır) gönderilir. Ad, adres ve konum gibi kiÅŸisel veriler hiçbir durumda kaydedilmez. KiÅŸilerin kimlikleri belirlenemez."</string> + <string name="settings_tracing_body_text">"Uygulamanın, enfekte olan bir kullanıcı ile karşılaÅŸmanızın ardından risk altında olup olmadığınızı belirleyebilmesi için maruz kalma günlüğü özelliÄŸini etkinleÅŸtirmeniz gerekir. Maruz kalma günlüğü özelliÄŸi uluslararası olarak çalışır; yani, kullanıcılara iliÅŸkin tüm olası maruz kalmalar da diÄŸer resmi koronavirüs uygulamalarıyla tespit edilir.\n\nMaruz kalma günlüğü özelliÄŸi, akıllı telefonunuzun Bluetooth üzerinden diÄŸer kullanıcıların ÅŸifrelenmiÅŸ rastgele kimliklerini alması ve size ait rastgele kimlikleri diÄŸer kullanıcıların akıllı telefonlarına aktarmasıyla çalışır. Uygulama her gün, virüs testi pozitif olan ve uygulamaları aracılığıyla bu bilgileri gönüllü olarak paylaÅŸan tüm kullanıcıların rastgele kimliklerini içeren bir liste ile birlikte bu kullanıcıların semptomlarının baÅŸlangıcına iliÅŸkin gönüllü olarak verilen tüm bilgileri indirir. Ardından bu liste, sizin de enfekte olma olasılığınızı hesaplamak ve gereken durumlarda sizi uyarmak için akıllı telefonunuzun kaydetttiÄŸi diÄŸer kullanıcıların rastgele kimliklerle karşılaÅŸtırılır. Düğmeyi kullanarak dilediÄŸiniz zaman maruz kalma günlüğünü devre dışı bırakabilirsiniz.\n\nUygulama hiçbir durumda adınız, adresiniz veya konumunuz gibi kiÅŸisel verileri toplamaz ve bu bilgileri diÄŸer kullanıcılara aktarmaz. Rastgele kimlikleri kullanarak kiÅŸilerin kimlikleri hakkında sonuçlar çıkarılamaz."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Etkin"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -528,7 +539,9 @@ <!--XHED : settings(tracing) - headline on card about the current status and what to do --> <string name="settings_tracing_status_location_headline">"Konum eriÅŸimine izin ver"</string> <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled --> - <string name="settings_tracing_status_location_body">"Konumunuza eriÅŸilemiyor. Bluetooth\'u kullanmak için Google ve/veya Android\'in cihazınızın konumuna eriÅŸmesi gerekiyor."</string> + <string name="settings_tracing_status_location_body">"Konum hizmetlerinizi etkinleÅŸtirin. Bluetooth Düşük Enerji iÅŸlevi ile fiziksel mesafeleri hesaplamak için konum hizmetlerinin etkinleÅŸtirilmesi gerekir ancak konumunuza eriÅŸmez. Daha fazla bilgi için lütfen SSS sayfamıza bakın."</string> + <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL --> + <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string> <!-- XBUT: settings(tracing) - go to operating system settings button on card - location --> <string name="settings_tracing_status_location_button">"Cihaz Ayarlarını Aç"</string> <!--XHED : settings(tracing) - headline on card about the current status and what to do --> @@ -614,9 +627,9 @@ <!-- XTXT: settings(background priority) - text in row on settings overview --> <string name="settings_background_priority_body_description">"Otomatik risk durumu güncellemelerinen izin ver"</string> <!-- XHED: settings(background priority) - multiline headline below illustration --> - <string name="settings_background_priority_headline">"Corona-Warn-App\'i Arka Planda Çalıştır"</string> + <string name="settings_background_priority_headline">"Risk Durumunu Otomatik Olarak Güncelle"</string> <!-- YTXT: settings(background priority) - description text --> - <string name="settings_background_priority_body">"ÖnceliklendirilmiÅŸ arka plan aktivitesini etkinleÅŸtirirseniz Corona-Warn-App sürekli olarak arka planda çalışır. Bu, uygulamanın her an risk durumunuzu belirlemesini saÄŸlar."</string> + <string name="settings_background_priority_body">"ÖnceliklendirilmiÅŸ arka plan aktivitesini etkinleÅŸtirirseniz Uygulama risk durumunuzu sürekli olarak belirleyebilir. Bu iÅŸlem, yalnızca Corona-Warn-App için pil ömrü optimizasyonunu devre dışı bırakır."</string> <!-- XACT: settings(background priority) - illustraction description --> <string name="settings_background_priority_illustration_description"/> <!-- XTXT: settings(background priority) - explains user what to do on card if background priority is enabled --> @@ -641,7 +654,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"Robert Koch Institute (RKI), Almanya\'nın federal kamu saÄŸlığı kurumudur. RKI, Federal Hükûmet adına Corona-Warn-App uygulamasını yayınlamaktadır. Uygulama, daha önce açıklanan kamu saÄŸlığı önlemlerine iliÅŸkin dijital bir tamamlayıcı niteliÄŸindedir: sosyal mesafe, hijyen uygulamaları ve yüz maskeleri."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Uygulamayı kullanan herkes, enfeksiyon zincirlerinin takip edilmesine ve kırılmasına yardımcı olur. Uygulama, diÄŸer kiÅŸilerle karşılaÅŸmaları cihazınızda yerel olarak kaydeder. Daha sonra COVID-19 tanısı konan kiÅŸilerle karşılaÅŸmışsanız size bildirim gönderilir. KimliÄŸiniz ve gizliliÄŸiniz daima koruma altındadır."</string> + <string name="information_about_body">"Uygulamayı kullanan kiÅŸiler, enfeksiyon zincirlerinin takip edilmesine ve kırılmasına yardımcı olur. Uygulama, diÄŸer kiÅŸilerle karşılaÅŸmaları cihazınızda yerel olarak kaydeder. Daha sonra COVID-19 tanısı konan kiÅŸilerle karşılaÅŸmışsanız size bildirim gönderilir. KimliÄŸiniz ve gizliliÄŸiniz daima koruma altındadır."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"Bölgedeki bir grup insan akıllı telefonlarını kullanıyor."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -663,7 +676,7 @@ <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_headline">"Size nasıl yardımcı olabiliriz?"</string> <!-- YTXT: Body text for technical contact and hotline information page --> - <string name="information_contact_body">"Corona-Warn-App hakkında teknik sorularınız için lütfen yardım hattımızla iletiÅŸime geçin."</string> + <string name="information_contact_body">"Corona-Warn-App hakkında teknik sorularınız için lütfen yardım hattımızla iletiÅŸime geçin.\n\nÄ°ÅŸitme engeli bulunan kiÅŸiler yardım hattı ile iletiÅŸime geçmek için Tess Relay hizmetlerini (Almanca yazı dili ile iÅŸaret dili arasında tercüme) kullanabilir. Yazılımı App Store/Google Play\'den indirebilirsiniz."</string> <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_subtitle_phone">"Teknik yardım hattı:"</string> <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page --> @@ -700,8 +713,10 @@ <string name="information_legal_headline_contact">"Ä°letiÅŸim"</string> <!-- YTXT: subtitle for legal information page, contact section --> <string name="information_legal_subtitle_contact">"E-posta: CoronaWarnApp@rki.de"</string> - <!-- YTXT: subtitle for legal information page, open contact form --> - <string name="information_legal_subtitle_contact_form"><a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"Ä°letiÅŸim Formu"</a></string> + <!-- YTXT: subtitle for legal information page, open contact form : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_label">"Ä°letiÅŸim Formu"</string> + <!-- YTXT: subtitle for legal information page url : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_url">"https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html"</string> <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German --> <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string> <!-- XHED: Headline for legal information page, tax section --> @@ -711,6 +726,11 @@ <!-- XACT: describes illustration --> <string name="information_legal_illustration_description">"Bir kiÅŸi ekranında uzun bir metin olan bir akıllı telefon tutuyor. Metnin yanında baskıyı temsil eden bir bölüm bulunuyor."</string> + <!-- #################################### + Interoperability + ###################################### --> + <!-- XHED: headline for consent information --> + <string name="interop_consent_headline">"Onay"</string> <!-- #################################### Submission @@ -725,10 +745,14 @@ <!-- XBUT: Positive button for generic web request error --> <string name="submission_error_dialog_web_generic_error_button_positive">"Geri"</string> - <!-- XHED: Dialog title for already paired test error --> - <string name="submission_error_dialog_web_test_paired_title">"Hata"</string> - <!-- XMSG: Dialog body for already paired test error --> - <string name="submission_error_dialog_web_test_paired_body">"QR kod/TAN geçersiz veya zaten kullanılmış. Lütfen tekrar deneyin veya Uygulama Bilgileri -> Teknik Yardım Hattı üzerinden teknik yardım hattı ile iletiÅŸime geçin."</string> + <!-- XHED: Dialog title for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_title">"QR kod geçersiz"</string> + <!-- XMSG: Dialog body for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_body">"QR kod geçersiz veya baÅŸka bir akıllı telefona zaten kaydedilmiÅŸ. QR kod geçerli olsun veya olmasın test sonucunuzu test merkezinden veya laboratuvardan alacaksınız. COVID-19 tanısı alırsanız kamu saÄŸlığı yetkilisi tarafından bilgilendirileceksiniz."</string> + <!-- XHED: Dialog title for already paired test error: tan --> + <string name="submission_error_dialog_web_test_paired_title_tan">"TAN geçersiz"</string> + <!-- XMSG: Dialog body for already paired test via tan - error: tan --> + <string name="submission_error_dialog_web_test_paired_body_tan">"TAN geçersiz veya zaten kullanılmış. Daha fazla bilgi için \"TAN Talebi\" bölümünün altında listelenen numarayı arayın."</string> <!-- XBUT: Positive button for already paired test error --> <string name="submission_error_dialog_web_test_paired_button_positive">"Geri"</string> @@ -753,6 +777,15 @@ <!-- XBUT: Positive button for submission tan redeemed --> <string name="submission_error_dialog_web_tan_redeemed_button_positive">"Tamam"</string> + <!-- XHED: Dialog title for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_title">"Ä°ptal etmek istiyor musunuz?"</string> + <!-- XMSG: Dialog body for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_body">"GiriÅŸleriniz kaydedilmeyecektir."</string> + <!-- XBUT: Positive button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_positive">"Evet"</string> + <!-- XBUT: Negative button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_negative">"Hayır"</string> + <!-- Permission Rationale Dialog --> <!-- XHED: Dialog headline QR Scan permission rationale --> <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Kamera yetkisi gereklidir"</string> @@ -816,9 +849,13 @@ <!-- XHED: Page headline for other warnings screen --> <string name="submission_test_result_positive_steps_warning_others_heading">"DiÄŸer Kullanıcıları Uyarma"</string> <!-- YTXT: Body text for for other warnings screen--> - <string name="submission_test_result_positive_steps_warning_others_body">"DiÄŸer insanları korumak ve enfeksiyon zincirini kırmak için son 14 güne ait rastgele kimliklerinizi paylaşın."</string> + <string name="submission_test_result_positive_steps_warning_others_body">"Rastgele kimliklerinizi paylaşın ve diÄŸer kullanıcıları uyarın.\nHerhangi bir koronavirüs semptomunu ne zaman ilk kez fark ettiÄŸinizi de belirterek diÄŸer kullanıcıların enfeksiyon riskini daha doÄŸru ÅŸekilde belirlemeye yardımcı olun."</string> <!-- XBUT: positive test result : continue button --> <string name="submission_test_result_positive_continue_button">"Sonraki"</string> + <!-- XBUT: positive test result : continue button with symptoms--> + <string name="submission_test_result_positive_continue_button_with_symptoms">"Semptomları Gir"</string> + <!-- XBUT: positive test result : continue button without symptoms --> + <string name="submission_test_result_positive_continue_button_wo_symptoms">"Semptomları Girme"</string> <!-- XHED: Page headline for invalid test result screen --> <string name="submission_test_result_invalid_steps_invalid_heading">"Test Sonucunuz"</string> <!-- YTXT: Body text for next steps section of invalid test result--> @@ -854,9 +891,9 @@ <!-- XACT: Submission Tan page title --> <string name="submission_tan_accessibility_title">"TAN giriÅŸi"</string> <!-- YTXT: Error text for the tan submission page --> - <string name="submission_tan_error">"TAN geçersiz, lütfen giriÅŸinizi kontrol edin."</string> + <string name="submission_tan_error">"TAN geçersiz. Lütfen giriÅŸinizi kontrol edin."</string> <!-- YTXT: Error text for the tan submission page (wrong characters) --> - <string name="submission_tan_character_error">"GiriÅŸ geçersiz. Lütfen giriÅŸinizi kontrol edin."</string> + <string name="submission_tan_character_error">"GiriÅŸiniz geçersiz karakterler içeriyor. Lütfen giriÅŸinizi kontrol edin."</string> <!-- Submission Intro --> <!-- XHED: Page title for menu at the start of the submission process --> @@ -912,16 +949,27 @@ <!-- XHED: Page headline for the positive result additional warning page--> <string name="submission_positive_other_warning_headline">"Lütfen hepimize yardımcı olun!"</string> <!-- YTXT: Body text for the positive result additional warning page--> - <string name="submission_positive_other_warning_body">"Corona-Warn-App\'in son 14 güne ait rastgele kimliklerinizi diÄŸer kullanıcılarla paylaÅŸmasını saÄŸlayabilirsiniz. Bu sayede diÄŸer kullanıcıları uyarabilir ve enfeksiyon zincirini kırabilirsiniz.\n\nYalnızca kiÅŸisel olmayan rastgele kimlikler aktarıldığından kimliÄŸiniz gizli kalacaktır."</string> - <!-- XHED: Title for the privacy card--> - <string name="submission_positive_other_warning_privacy_title">"Veri GizliliÄŸi"</string> - <!-- YTXT: Body text for the privacy card--> - <string name="submission_positive_other_warning_privacy_body">"\"Kabul et\" seçeneÄŸine dokunduÄŸunuzda, Uygulamanın pozitif test sonucunuzu son 14 güne ait rastgele kimliklerinizle birlikte uygulamanın sunucu sistemine göndermesine izin vermiÅŸ olursunuz, bu sayede maruz kalma günlüğünü etkinleÅŸtirmiÅŸ olan diÄŸer Uygulama kullanıcıları otomatik ÅŸekilde bilgilendirilebilir. Ä°letilen rastgele kimlikler, kimliÄŸiniz ya da kiÅŸiliÄŸinize iliÅŸkin sonuç çıkartacak hiçbir bilgi içermez. \n\nTest sonucunuzun Uygulama aracılığıyla iletilmesi, isteÄŸe baÄŸlıdır. Test sonucunuzu iletmezseniz size hiçbir dezavantajı olmaz. Uygulamayı kullanıp kullanmadığınızı ve nasıl kullandığınızı anlayamadığımız ve kontrol edemediÄŸimiz için enfeksiyonu bulaÅŸtırıp bulaÅŸtırmadığınızı sizden baÅŸka kimse öğrenemez.\n\nUygulamayı silerek, onayınızı dilediÄŸinizde geri alabilirsiniz. Onayın geri alınmasıyla, geri almaya kadar yapılmış veri iÅŸlemelerin hukuka uygunlukları bu durumdan etkilenmez. \"Veri GizliliÄŸi Bilgileri\" menüsünden diÄŸer bilgilere ulaÅŸabilirsiniz."</string> + <string name="submission_positive_other_warning_body">"Ardından diÄŸer kullanıcıların maruz kalma olasılıkları konusunda bilgilendirilmesini saÄŸlayabilirsiniz.\n\nBunun için son 14 güne ait rastgele kimliklerinizi ve isteÄŸe baÄŸlı olarak olası koronavirüs semptomlarını ne zaman ilk kez fark ettiÄŸinizi katılımcı ülkeler tarafından iÅŸletilen ortak exchange sunucusuna gönderebilirsiniz. Rastgele kimlikleriniz ve tüm ek bilgiler, bu sunucudan resmi koronavirüs uygulamalarının kullanıcılarına dağıtılacaktır. Bu sayede, diÄŸer kullanıcılar olası size maruz kalmış olabilecekleri konusunda uyarılabilir.\n\nYalnızca rastfele kimlikler ve olası semptomları fark ettiÄŸinizde saÄŸladığınız bilgiler aktarılır. Adınız, adresiniz veya konumunuz gibi hiçbir kiÅŸisel veri paylaşılmaz."</string> <!-- XBUT: other warning continue button --> - <string name="submission_positive_other_warning_button">"Sonraki"</string> + <string name="submission_positive_other_warning_button">"Kabul Et"</string> <!-- XACT: other warning - illustration description, explanation image --> <string name="submission_positive_other_illustration_description">"Bir cihaz ÅŸifrelenmiÅŸ pozitif test tanısını sisteme aktarır."</string> + <!-- XHED: Title for the interop country list--> + <string name="submission_interoperability_list_title">"AÅŸağıdaki ülkeler, ülkeler arası maruz kalma günlüğüne katılmaktadır:"</string> + <!-- Submission Country Selector --> + <!-- XHED: Page title for the submission country selection page --> + <string name="submission_positive_country_selection_title">"Avrupa geneli uyarılar"</string> + <!-- XHED: Page headline for the submission country selection page --> + <string name="submission_positive_country_selection_headline">"Son 14 günde hangi ülkelere gittiniz?"</string> + <!-- XHED: Country selector headline for the submission country selection page --> + <string name="submission_country_selector_headline">"Åžu ülkelere gittim:"</string> + <!-- XHED: Country no selection headline for the submission country selection page --> + <string name="submission_country_no_selection_headline">"Beyan yok"</string> + <!-- YTXT: Data FAQ for the submission country selection page --> + <string name="submission_country_selection_data_faq_body">"GiriÅŸiniz yalnızca veri hacmini optimize etmek için kullanılır.\n\nListe tüm güncel katılımcı ülkeleri içerir ve sürekli olarak güncellenir."</string> + <!-- XBUT: submission country selection continue button --> + <string name="submission_country_selection_button">"Sonraki"</string> <!-- Submission Done --> <!-- XHED: Page title for completed submission page --> @@ -931,7 +979,7 @@ <!-- XHED: Page subtitle for completed submission page --> <string name="submission_done_subtitle">"Lütfen unutmayın:"</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"Bulaşıcı bir hastalık taşıyorsunuz."</string> + <string name="submission_done_contagious">"Kamu saÄŸlığı yetkiliniz önümüzdeki birkaç gün içinde size ulaÅŸacaktır."</string> <!-- YTXT: text after submission: isolate --> <string name="submission_done_isolate">"Lütfen kendinizi diÄŸer insanlardan izole edin."</string> <!-- XHED: Title for further info --> @@ -946,7 +994,35 @@ <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Tamamlandı"</string> <!-- XACT: submission finished - illustration description, explanation image --> - <string name="submission_done_illustration_description">"Bir kiÅŸi test sonucunu paylaÅŸtığı için gruptaki herkes gülüyor."</string> + <string name="submission_done_illustration_description">"Son birkaç günde aÅŸağıdaki belirtilerden birini veya daha fazlasını yaÅŸadınız mı?"</string> + + <!-- Submission Symptoms --> + <!-- XHED: Page title for symptom screens --> + <string name="submission_symptom_title">"Belirtiler"</string> + <!-- XTXT: headline text for initial symptom screen --> + <string name="submission_symptom_initial_headline">"AÅŸağıdaki belirtilerden birini veya daha fazlasını yaÅŸadınız mı?"</string> + <!-- YTXT: explanation text for initial symptom screen --> + <string name="submission_symptom_initial_explanation">"Uygulamanın, diÄŸer kullanıcılar açısından enfeksiyon riskini daha doÄŸru bir biçimde hesaplayabilmesi için herhangi bir korona belirtisi fark edip etmediÄŸinizi ve ne zaman fark ettiÄŸinizi belirtebilirsiniz. Bu bilgileri saÄŸlamak istemiyorsanız \"bilgi yok\" seçeneÄŸini belirlemeniz yeterlidir."</string> + <!-- YTXT: Bullet points for symptoms --> + <string-array name="submission_symptom_symptom_bullets"> + <item>"Artan vücut sıcaklığı veya ateÅŸ"</item> + <item>"Nefes darlığı"</item> + <item>"Koku/tat kaybı"</item> + <item>"Öksürük"</item> + <item>"Burun akıntısı"</item> + <item>"BoÄŸaz aÄŸrısı"</item> + <item>"BaÅŸ aÄŸrısı ve kol/bacak aÄŸrısı"</item> + <item>"Genel zayıflık ve bitkinlik"</item> + </string-array> + <!-- XBUT: symptom initial screen yes button --> + <string name="submission_symptom_positive_button">"Evet"</string> + <!-- XBUT: symptom initial screen no button --> + <string name="submission_symptom_negative_button">"Hayır"</string> + <!-- XBUT: symptom initial screen no information button --> + <string name="submission_symptom_no_information_button">"Beyan yok"</string> + <!-- XBUT: symptom initial screen continue button --> + <string name="submission_symptom_further_button">"Sonraki"</string> + <!-- Submission Contact --> <!-- XHED: Page title for contact page in submission flow --> @@ -977,6 +1053,22 @@ <!-- XACT: Content Description for submission contact step 2 --> <string name="submission_contact_step_2_content">"Ä°kinci adımda, TAN\'nizi kullanarak testinizi uygulamaya kaydedersiniz."</string> + <!-- Submission Symptom Calendar --> + <!-- XHED: Page title for calendar page in submission symptom flow --> + <string name="submission_symptom_calendar_title">"Belirtilerin baÅŸlangıcı"</string> + <!-- XHED: Page headline for calendar page in symptom submission flow --> + <string name="submission_symptom_calendar_headline">"Bu belirtileri ilk kez ne zaman yaÅŸamaya baÅŸladınız? "</string> + <!-- YTXT: Body text for calendar page in symptom submission flow--> + <string name="submission_symptom_calendar_body">"Takvimde tam tarihi seçin veya tam tarihi hatırlayamıyorsanız diÄŸer seçeneklerden birini seçin."</string> + <!-- XBUT: symptom calendar screen less than 7 days button --> + <string name="submission_symptom_less_seven">"Son 7 gün içinde"</string> + <!-- XBUT: symptom calendar screen 1-2 weeks button --> + <string name="submission_symptom_one_two_weeks">"1-2 hafta önce"</string> + <!-- XBUT: symptom calendar screen more than 2 weeks button --> + <string name="submission_symptom_more_two_weeks">"2 haftadan uzun süre önce"</string> + <!-- XBUT: symptom calendar screen verify button --> + <string name="submission_symptom_verify">"Beyan yok"</string> + <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> <string name="submission_status_card_title_fetching">"Veriler alınıyor...."</string> @@ -1013,7 +1105,7 @@ <!-- YTXT: text for contagious card --> <string name="submission_status_card_positive_result_contagious">"Bulaşıcı bir hastalık taşıyorsunuz. Kendinizi diÄŸer insanlardan izole edin."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"Kamu saÄŸlığı yetkiliniz önümüzdeki birkaç gün içinde telefonla veya mektupla size ulaÅŸacaktır."</string> + <string name="submission_status_card_positive_result_contact">"Kamu saÄŸlığı yetkiliniz önümüzdeki birkaç gün içinde size ulaÅŸacaktır."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"DiÄŸer kullanıcıların uyarılabilmesi için rastgele kimliklerinizi paylaşın."</string> @@ -1040,6 +1132,9 @@ <item>"Kendinizi iyi hissetmiyorsanız diÄŸer insanları riske atmamak için iÅŸe gitmeyin. Belirtileriniz kötüleÅŸirse ilave SARS-CoV-2 testi yapılması gerekebilir."</item> </string-array> + <!-- XBUT Symptoms exact date button --> + <string name="symptoms_calendar_exact_date_button">"Tam tarih"</string> + <!-- #################################### Button Tooltips for Accessibility ###################################### --> @@ -1068,7 +1163,7 @@ <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action --> <string name="errors_external_action">"Bu iÅŸlemi gerçekleÅŸtiremezsiniz. Lütfen yardım hattı ile iletiÅŸime geçin."</string> <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update --> - <string name="errors_google_update_needed">"Corona-Warn-App uygulamanız doÄŸru ÅŸekilde yüklendi ancak akıllı telefonunuzun iÅŸletim sisteminde \"COVID-19 maruz kalma bildirimleri\" hizmeti yok. Bu, Corona-Warn-App\'i kullanamayacağınız anlamına geliyor. Daha fazla bilgi için lütfen SSS sayfamıza bakın: https://www.coronawarn.app/en/faq/"</string> + <string name="errors_google_update_needed">"Corona-Warn-App uygulamanız doÄŸru ÅŸekilde yüklendi ancak akıllı telefonunuzun iÅŸletim sisteminde \"COVID-19 Maruz Kalma Bildirimleri Sistemi\" yok. Bu, Corona-Warn-App\'i kullanamayacağınız anlamına geliyor. Daha fazla bilgi için lütfen SSS sayfamıza bakın: https://www.coronawarn.app/en/faq/"</string> <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day --> <string name="errors_google_api_error">"Corona-Warn-App doÄŸru ÅŸekilde çalışıyor ancak mevcut risk durumunuzu güncelleyemiyoruz. Maruz kalma günlüğü aktif ve doÄŸru ÅŸekilde çalışıyor. Daha fazla bilgi için lütfen SSS sayfamıza bakın: https://www.coronawarn.app/en/faq/"</string> @@ -1085,6 +1180,10 @@ <string name="errors_generic_button_negative">"Ayrıntılar"</string> <!-- XTXT: error dialog - text when no error description is available --> <string name="errors_generic_text_unknown_error_cause">"Bilinmeyen bir hata oluÅŸtu."</string> + <!-- XTXT: error dialog - text when a catastrophic error occured from which the app recovered automatically via data reset --> + <string name="errors_generic_text_catastrophic_error_recovery_via_reset">"Uygulamanız teknik bir problem nedeniyle sıfırlandı. Bunun, uygulamanın iÅŸlevi üzerinde hiçbir etkisi yoktur. Maruz kalmalar hakkında bildirim almaya ve COVID-19 testiniz pozitif çıkarsa diÄŸer kullanıcıları uyarmaya devam edebileceksiniz."</string> + <!-- XTXT: error dialog - link for the details button in the catastrophic error recovery dialog --> + <string name="errors_generic_text_catastrophic_error_encryption_failure">"https://www.coronawarn.app/en/faq/#cause9002_recovery"</string> <!-- #################################### Just for Development @@ -1092,10 +1191,6 @@ <!-- NOTR --> <string name="lorem_ipsum">"Lorem Ipsum"</string> <!-- NOTR --> - <string name="menu_test_api">"Test API"</string> - <!-- NOTR --> - <string name="menu_test_risk_level">"Test Risk Level"</string> - <!-- NOTR --> <string name="menu_test_notification">"Test Notification"</string> <!-- NOTR --> <string name="test_api_button_api_launch">"Android API Test(Manual Test)"</string> @@ -1136,4 +1231,121 @@ <!-- NOTR --> <string name="test_api_calculate_risk_level">"Calculate Risk Level"</string> + <!-- XHED: Country Entry for Austria --> + <string name="country_name_at">"Avusturya"</string> + <!-- XHED: Country Entry for Belgium --> + <string name="country_name_be">"Belçika"</string> + <!-- XHED: Country Entry for Bulgaria --> + <string name="country_name_bg">"Bulgaristan"</string> + <!-- XHED: Country Entry for Switzerland --> + <string name="country_name_ch">"Ä°sviçre"</string> + <!-- XHED: Country Entry for Cyprus --> + <string name="country_name_cy">"Kıbrıs"</string> + <!-- XHED: Country Entry for Czech Republic --> + <string name="country_name_cz">"Çek Cumhuriyeti"</string> + <!-- XHED: Country Entry for Germany --> + <string name="country_name_de">"Almanya"</string> + <!-- XHED: Country Entry for Denmark --> + <string name="country_name_dk">"Danimarka"</string> + <!-- XHED: Country Entry for Estonia --> + <string name="country_name_ee">"Estonya"</string> + <!-- XHED: Country Entry for Spain --> + <string name="country_name_es">"Ä°spanya"</string> + <!-- XHED: Country Entry for Finland --> + <string name="country_name_fi">"Finlandiya"</string> + <!-- XHED: Country Entry for France --> + <string name="country_name_fr">"Fransa"</string> + <!-- XHED: Country Entry for Great Britain --> + <string name="country_name_uk">"BirleÅŸik Krallık"</string> + <!-- XHED: Country Entry for Greece --> + <string name="country_name_gr">"Yunanistan"</string> + <!-- XHED: Country Entry for Croatia --> + <string name="country_name_hr">"Hırvatistan"</string> + <!-- XHED: Country Entry for Hungary --> + <string name="country_name_hu">"Macaristan"</string> + <!-- XHED: Country Entry for Ireland --> + <string name="country_name_ie">"Ä°rlanda"</string> + <!-- XHED: Country Entry for Iceland --> + <string name="country_name_is">"Ä°zlanda"</string> + <!-- XHED: Country Entry for Italy --> + <string name="country_name_it">"Ä°talya"</string> + <!-- XHED: Country Entry for Liechtenstein --> + <string name="country_name_li">"Liechtenstein"</string> + <!-- XHED: Country Entry for Lithuania --> + <string name="country_name_lt">"Litvanya"</string> + <!-- XHED: Country Entry for Luxemburg --> + <string name="country_name_lu">"Lüksemburg"</string> + <!-- XHED: Country Entry for Latvia --> + <string name="country_name_lv">"Letonya"</string> + <!-- XHED: Country Entry for Malta --> + <string name="country_name_mt">"Malta"</string> + <!-- XHED: Country Entry for Netherlands --> + <string name="country_name_nl">"Hollanda"</string> + <!-- XHED: Country Entry for Norway --> + <string name="country_name_no">"Norveç"</string> + <!-- XHED: Country Entry for Poland --> + <string name="country_name_pl">"Polonya"</string> + <!-- XHED: Country Entry for Portugal --> + <string name="country_name_pt">"Portekiz"</string> + <!-- XHED: Country Entry for Rumania --> + <string name="country_name_ro">"Romanya"</string> + <!-- XHED: Country Entry for Sweden --> + <string name="country_name_se">"Ä°sveç"</string> + <!-- XHED: Country Entry for Slovenia --> + <string name="country_name_si">"Slovenya"</string> + <!-- XHED: Country Entry for Slovakia --> + <string name="country_name_sk">"Slovakya"</string> + + <!-- XHED: Title of the interoperbaility information view. --> + <string name="interoperability_title">"Ãœlkeler Arası\nMaruz Kalma Günlüğü"</string> + + <!-- XHED: Setting title of interoperability in the tracing settings view --> + <string name="settings_interoperability_title">"Ãœlkeler Arası Maruz Kalma Günlüğü"</string> + <!-- XTXT: Settings description of the interoperability in the tracing settings view --> + <string name="settings_interoperability_subtitle">"Katılımcı Ãœlkeler"</string> + + <!-- XHED: Header of interoperability information/configuration view --> + <string name="interoperability_configuration_title">"Ãœlkeler Arası Maruz Kalma Günlüğü"</string> + <!-- XTXT: First section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_first_section">"Bazı ülkeler, ortak bir exchange sunucusu üzerinden uluslararası uyarıları etkinleÅŸtirmek üzere birlikte çalışma yürütmektedir. ÖrneÄŸin, diÄŸer katılımcı ülkelerin resmi koronavirüs uygulamasının kullanıcıları ile temaslar da maruz kalma günlüğünde hesaba katılabilir."</string> + <!-- XTXT: Second section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_second_section">"Bunun için uygulama, uygulamaları aracılığıyla kendi rastgele kimliklerini paylaÅŸan tüm kullanıcıların rastgele kimliklerinin bir listesini (günlük olarak güncellenir) indirir. Ardından bu liste, akıllı telefonunuzun kaydettiÄŸi rastgele kimliklerle karşılaÅŸtırılır. Normal koÅŸullarda, rastgele kimlikleri içeren listenin günlük olarak indirilmesi için ücret alınmaz, bu baÄŸlamda uygulamanın kullandığı veriler için de ücret alınmaz ve diÄŸer AB ülkelerinde bunun için dolaşım ücretleri de alınmaz."</string> + <!-- XHED: Header right above the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_list_title">"AÅŸağıdaki ülkeler, uluslararası maruz kalma günlüğüne katılmaktadır:"</string> + <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_information">"Uygulamanın gizlilik bildirimine (uluslararası maruz kalma günlüğü özelliÄŸi için gerçekleÅŸtirilen veri iÅŸleme hakkında bilgileri) menüde “Uygulama Bilgileri†> “Veri GizliliÄŸi†bölümünde bulabilirsiniz."</string> + + <!-- XHED: Sub header introducing interoperability in the tracing step of onboarding --> + <string name="interoperability_onboarding_title">"Ãœlkeler Arası\nMaruz Kalma Günlüğü"</string> + <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> + <string name="interoperability_onboarding_first_section">"Bazı ülkeler uluslararası uyarıları etkinleÅŸtirmek üzere iÅŸ birliÄŸi yapmaktadır. DiÄŸer bir ifadeyle, tüm katılımcı ülkelerdeki resmi korona uygulamalarının kullanıcılarına maruz kalma olasılığınız da artık hesaba katılabilir."</string> + <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> + <string name="interoperability_onboarding_second_section">"Bir kullanıcı, katılımcı ülkeler tarafından ortak olarak iÅŸletilen exchange sunucusuna rastgele kimliklerini gönderdiÄŸinde tüm bu ülkelerdeki resmi korona uygulamalarının kullanıcıları maruz kalma olasılığı konusunda uyarılabilir."</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_randomid_download_free">"Rastgele kimlikleri içeren bu listenin günlük olarak indirilmesi için ücret alınmaz. Buna göre, mobil aÄŸ operatörleri uygulamanın bu baÄŸlamda kullandığı veriler için ücret almaz ve bu doÄŸrultuda, diÄŸer AB ülkelerindeki kullanımlar için dolaşım ücreti almaz. Daha fazla bilgi için lütfen mobil aÄŸ operatörünüzle iletiÅŸime geçin."</string> + <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> + <string name="interoperability_onboarding_list_title">"Åžu anda aÅŸağıdaki ülkeler katılmaktadır:"</string> + + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 1 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_1">"Uygulamadaki iÅŸlev geliÅŸtirmelerini yansıtmak üzere kullanım koÅŸulları da güncellenmiÅŸtir."</string> + <!-- XLNK: Terms of use link inside delta interoperability screen--> + <string name="interoperability_onboarding_delta_terms_link">"Kullanım koÅŸullarını görüntüle"</string> + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 2 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_2">"Kullanım KoÅŸulları ve gizlilik bildirimi \"Uygulama Bilgileri\" baÅŸlığındaki menüde ve uygulama maÄŸazanızdaki uygulama açıklamasında yer almaktadır. DeÄŸiÅŸiklikler, uygulamayı nasıl kullandığınızı etkilemeyecektir. Uygulamayı kullanmaya devam eder veya uygulamayı yeniden açarsanız güncellenen Kullanım KoÅŸullarını kabul ettiÄŸinizi varsayacağız."</string> + + <!-- XACT: interoperability (eu) - illustraction description, explanation image --> + <string name="interoperability_eu_illustration_description">"Birinin elinde akıllı telefon tutuluyor. Arka planda Avrupa ve Avrupa bayrağı gösterilmektedir."</string> + + <!-- XTXT: Title for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_title_failrequest">"Katılımcı Ãœlkeler"</string> + <!-- XTXT: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest">"Katılımcı ülkeleri, maruz kalma günlüğü ayrıntılarında görüntüleyebilirsiniz."</string> + + <!-- YDES: Title for the interoperability onboarding if country download fails for Risk Details --> + <string name="interoperability_onboarding_list_title_riskdetection_no_network">"Åžu anda ülkeler görüntülenemiyor."</string> + <!-- YMSW: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest_no_network">"Ä°nternet baÄŸlantınız kesilmiÅŸ olabilir. Lütfen internet baÄŸlantınızın olduÄŸundan emin olun."</string> + <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> + <string name="interoperability_onboarding_list_button_title_no_network">"Cihaz Ayarlarını Aç"</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values/colors.xml b/Corona-Warn-App/src/main/res/values/colors.xml index d7364070c058a4664fe3e663e9c31171cafe8381..b0246b90d5372420f43b7d242d32815a7ef2cc14 100644 --- a/Corona-Warn-App/src/main/res/values/colors.xml +++ b/Corona-Warn-App/src/main/res/values/colors.xml @@ -19,6 +19,7 @@ <color name="colorTextPrimary2">#9917191A</color> <color name="colorTextPrimary3">#4D17191A</color> <color name="colorTextEmphasizedButton">#FFFFFF</color> + <color name="colorTextSixteenWhite">#FFFFFF</color> <color name="colorTextSemanticRed">#C00F2D</color> <color name="colorTextSemanticGreen">#2E854B</color> <color name="colorTextSemanticNeutral">#5D6E80</color> @@ -52,4 +53,11 @@ <color name="colorStableHairlineLight">#33FFFFFF</color> <color name="colorStableHairlineDark">#3317191A</color> + <!-- Calendar --> + <color name="colorCalendarSelectedDayBackground">#5D6F80</color> + <color name="colorCalendarTodayBorder">#007FAD</color> + <color name="colorCalendarTodayText">#007FAD</color> + <color name="colorCalendarMonthText">#DE000000</color> + <color name="colorCalendarLayoutFocusOn">#FF5D6F80</color> + <color name="colorCalendarLayoutFocusOff">#F5F5F5</color> </resources> diff --git a/Corona-Warn-App/src/main/res/values/dimens.xml b/Corona-Warn-App/src/main/res/values/dimens.xml index 148cc90bfe4039d4bb5340e43b778f6ed1aad71d..a411731f9aa6b3d473a92cb90143b7858f813c4e 100644 --- a/Corona-Warn-App/src/main/res/values/dimens.xml +++ b/Corona-Warn-App/src/main/res/values/dimens.xml @@ -111,6 +111,9 @@ <dimen name="submission_scan_qr_code_viewfinder_size">240dp</dimen> <dimen name="submission_scan_qr_code_viewfinder_center_offset">120dp</dimen> + <!-- Submission Country Select --> + <dimen name="submission_country_selection_country_icon_size">40dp</dimen> + <!-- Bullet Points --> <dimen name="bullet_point_size">4dp</dimen> <dimen name="bullet_point_baseline_offset">8sp</dimen> @@ -120,4 +123,13 @@ <dimen name="match_constraint">0dp</dimen> <dimen name="no_padding">0dp</dimen> + + <!-- Calendar --> + <dimen name="calendar_header_height">72dp</dimen> + <dimen name="calendar_header_initial_radius">1dp</dimen> + <dimen name="calendar_header_top_radius">4dp</dimen> + <dimen name="calendar_header_bottom_radius">4dp</dimen> + <dimen name="calendar_layout_stroke">2dp</dimen> + <dimen name="calendar_day_size">40dp</dimen> + <dimen name="calendar_day_spacing">4dp</dimen> </resources> diff --git a/Corona-Warn-App/src/main/res/values/legal_strings.xml b/Corona-Warn-App/src/main/res/values/legal_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..117e87dbb30cbfee51b4f5a8ff37b5a951799b2b --- /dev/null +++ b/Corona-Warn-App/src/main/res/values/legal_strings.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="interop_consent_body" translatable="false" /> + <!-- XHED: Header of private data in the delta onboarding interoperability view --> + <string name="interoperability_onboarding_delta_footerTitle" translatable="false">"Information on data processing"</string> + <!-- XTXT: Description of private data in the delta onboarding interoperability view. Below interoperability_onboarding_delta_footerTitle --> + <string name="interoperability_onboarding_delta_footerDescription" translatable="false">"You do not need to change anything to find out whether you have had possible exposures involving app users in the participating countries and are therefore at risk of infection yourself. You just need to make sure that the exposure logging feature is still enabled. Exposure logging will automatically warn you about any possible exposure you had with a user of the Corona-Warn-App or any other official coronavirus app.\n\nWhen COVID-19 Exposure Notifications are enabled, your Android smartphone continuously generates random IDs and sends them via Bluetooth so that they can be received by other smartphones near you. Your Android smartphone, in turn, receives the random IDs of other smartphones. Your own random IDs and those received from other smartphones are recorded by your Android smartphone and stored there for 14 days.\n\nFor exposure logging, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their random IDs via their official coronavirus app. This list is then compared with the random IDs of other users which have been recorded by your smartphone.\n\nThe app will inform you if it detects a possible exposure. In this case, the app gains access to the data recorded by your smartphone about the possible exposure (date, duration and Bluetooth signal strength of the contact). The Bluetooth signal strength is used to derive the physical distance to the other user (the stronger the signal, the smaller the distance). The app analyses this information in order to calculate your risk of infection and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone.\n\nApart from you, nobody (not even the RKI or the health authorities of participating countries) will know whether a possible exposure has been detected and what risk of infection has been identified for you.\n\nThe app’s privacy notice (including information about the data processing carried out for the transnational exposure logging feature) can be found in the menu under „App Information“ > „Data Privacy“."</string> + <!-- XHED: Header of the delta onboarding screen for interoperability. If the user opens the app for the first time after the interoperability update --> + <string name="interoperability_onboarding_delta_title" translatable="false">Transnational exposure logging</string> + <!-- XTXT: Description of the interoperability extension of the app. Below interoperability_onboarding_delta_title --> + <string name="interoperability_onboarding_delta_subtitle" translatable="false">The functionality of the Corona-Warn-App has been extended. Several countries are now working together to enable transnational alerts via a joint exchange server. For example, contacts with users of an official coronavirus app from other participating countries can now also be taken into account during exposure logging.</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_delta_randomid" translatable="false">To do this, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their random IDs via their own app. This list is then compared with the random IDs recorded by your smartphone.</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_delta_free_download" translatable="false">The daily download of the list with the random IDs is usually free of charge for you. Specifically, this means that mobile network operators do not charge you for the data used by the app in this context, and nor do they apply roaming charges for this in other EU countries. Please contact your mobile network operator for more information.</string> + <!-- XHED: Title for the privacy card--> + <string name="submission_positive_other_warning_privacy_title" translatable="false">"Declaration of consent"</string> + <!-- YTXT: Body text for the privacy card--> + <string name="submission_positive_other_warning_privacy_body" translatable="false">"<b>By tapping on „Accept“, you consent to your random IDs from the last 14 days, along with any optional information you provide about the onset of your symptoms, being transmitted to the app’s server system.</b> This information will be used to assess the risk of infection for app users with whom you have come into contact, and to warn them if there is a risk that they are infected. In order to be able to warn the users of official coronavirus apps in other participating countries, the app’s server system will also make this information available to the joint exchange server operated by the participating countries.\n\nNeither other users nor the RKI or the health authorities of participating countries can infer your identity, name or other personal information from the data transmitted.\n\nTransmitting your random IDs and any information about the onset of your symptoms for transnational alerts is voluntary. You will not be penalised if you do not share this information. Since it is not possible to trace or check whether and how you use the app, nobody but you will know whether you provide your random IDs.\n\nYou can withdraw your consent at any time by deleting the app. This withdrawal of your consent will not affect the lawfulness of the processing carried out on the basis of the consent prior to the withdrawal.\n\nFurther information – including about the participating countries and their health authorities responsible for data protection matters – can be found in the menu under „App Information“ > „Data Privacy“."</string> + <!-- XHED: onboarding(tracing) - headline for consent information --> + <string name="onboarding_tracing_headline_consent" translatable="false">"Declaration of consent"</string> + <!-- YTXT: onboarding(tracing) - body for consent information --> + <string name="onboarding_tracing_body_consent" translatable="false">"You need to enable exposure logging to find out whether you have had possible exposures involving app users in the participating countries and are therefore at risk of infection yourself. By tapping on the “Activate exposure logging†button, you agree to enabling the exposure logging feature and to the associated data processing by the app.\n\nIn order to use the exposure logging feature, you will also have to enable the “COVID-19 Exposure Notifications†functionality provided by Google on your Android smartphone and grant the Corona-Warn-App permission to use this.\n\nWhen COVID-19 Exposure Notifications are enabled, your Android smartphone continuously generates random IDs and sends them via Bluetooth so that they can be received by other smartphones near you. Your Android smartphone, in turn, receives the random IDs of other smartphones. Your own random IDs and those received from other smartphones are recorded by your Android smartphone and stored there for 14 days.\n\nFor exposure logging, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their random IDs via their official coronavirus app. This list is then compared with the random IDs of other users which have been recorded by your smartphone.\n\nThe app will inform you if it detects a possible exposure. In this case, the app gains access to the data recorded by your smartphone about the possible exposure (date, duration and Bluetooth signal strength of the contact). The Bluetooth signal strength is used to derive the physical distance to the other user (the stronger the signal, the smaller the distance). The app analyses this information in order to calculate your risk of infection and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone.\n\nApart from you, nobody (not even the RKI or the health authorities of participating countries) will know whether a possible exposure has been detected and what risk of infection has been identified for you.\n\nTo withdraw your consent to the exposure logging feature, you can disable the feature by using the toggle switch in the app or delete the app. If you would like to use the exosure logging feature again, you can toggle the feature back on or reinstall the app. If you disable the exposure logging feature, the app will no longer check for possible exposures. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Notifications in your Android smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored by your Android smartphone’s COVID-19 Exposure Notification functionality will not be deleted by the app. You can only permanently delete these in your Android smartphone settings.\n\nThe app’s privacy notice (including information about the data processing carried out for the transnational exposure logging feature) can be found in the menu under „App Information“ > „Data Privacy“."</string> +</resources> diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml index 135dfaf5e3fd34c013236ad308e03362463086a1..d23fdb5567037970e29509b9f13fec0cb89b3067 100644 --- a/Corona-Warn-App/src/main/res/values/strings.xml +++ b/Corona-Warn-App/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ -<?xml version="1.0" encoding="UTF-8"?><resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation"> +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" tools:ignore="MissingTranslation"> <!-- #################################### Preference Keys @@ -75,6 +76,10 @@ <string name="preference_risk_days_explanation_shown"><xliff:g id="preference">"preference_risk_days_explanation_shown"</xliff:g></string> <!-- NOTR --> <string name="preference_background_notification"><xliff:g id="preference">"preference_background_notification"</xliff:g></string> + <!-- NOTR --> + <string name="preference_interoperability_selected_country_codes"><xliff:g id="preference">"preference_interoperability_selected_country_codes"</xliff:g></string> + <!-- NOTR --> + <string name="preference_interoperability_all_countries_selected">preference_interoperability_all_countries_selected</string> <!-- #################################### Generics @@ -214,7 +219,7 @@ <!-- XHED: main, FAQ --> <string name="main_about_headline">"FAQ"</string> <!-- XTXT: main, explains faq on card --> - <string name="main_about_body">"Here you can find answers to frequently asked questions about the Corona-Warn-App. You will be forwarded to an external website."</string> + <string name="main_about_body">"Here you can find answers to frequently asked questions about the Corona-Warn-App. You will be forwarded to an external German government website."</string> <!-- XTXT: FAQ link, should be translated --> <string name="main_about_link">"https://www.bundesregierung.de/corona-warn-app-faq-englisch"</string> <!-- XACT: Opens external webpage --> @@ -278,13 +283,13 @@ <!-- XHED: App overview subtitle for glossary contact --> <string name="main_overview_subtitle_glossary_contact">"Exposures"</string> <!-- YTXT: App overview body for glossary contact --> - <string name="main_overview_body_glossary_contact">"Encounters over a longer duration and close proximity to people diagnosed with COVID-19."</string> + <string name="main_overview_body_glossary_contact">"Encounters over an extended period and in close proximity to a person diagnosed with COVID-19."</string> <!-- XHED: App overview subtitle for glossary notifications --> <string name="main_overview_subtitle_glossary_notification">"Exposure Notification"</string> <!-- YTXT: App overview body for glossary notifications --> <string name="main_overview_body_glossary_notification">"The display of exposures in the Corona-Warn-App."</string> <!-- XHED: App overview subtitle for glossary keys --> - <string name="main_overview_subtitle_glossary_keys">"Random IDs"</string> + <string name="main_overview_subtitle_glossary_keys">"Random ID"</string> <!-- YTXT: App overview body for glossary keys --> <string name="main_overview_body_glossary_keys">"Random IDs are combinations of digits and letters generated randomly. They are exchanged between devices in close proximity. Random IDs cannot be traced to a specific person and are automatically deleted after 14 days. Persons diagnosed with COVID-19 can opt to share their random IDs of up to the last 14 days with other app users."</string> <!-- XACT: main (overview) - illustraction description, explanation image --> @@ -347,7 +352,7 @@ <!-- YTXT: risk details - low risk explanation text --> <string name="risk_details_information_body_low_risk">"You have a low risk of infection because no exposure to people later diagnosed with COVID-19 was logged, or because your encounters were only for a short time and at a greater distance."</string> <!-- YTXT: risk details - low risk explanation text with encounter with low risk --> - <string name="risk_details_information_body_low_risk_with_encounter">"The risk of infection is calculated locally on your device, using exposure logging data. The calculation also takes into account distance and duration of any exposure to persons diagnosed with COVID-19, as well as their potential infectiousness. Your risk of infection cannot be seen by or passed on to anyone else."</string> + <string name="risk_details_information_body_low_risk_with_encounter">"The risk of infection is calculated locally on your smartphone, using exposure logging data. The calculation also takes into account distance and duration of any exposure to persons diagnosed with COVID-19, as well as their potential infectiousness. Your risk of infection cannot be seen by or passed on to anyone else."</string> <!-- YTXT: risk details - increased risk explanation text with variable for day(s) since last contact --> <plurals name="risk_details_information_body_increased_risk"> <item quantity="one">"You have an increased risk of infection because you were last exposed %1$s days ago over a longer period of time and at close proximity to at least one person diagnosed with COVID-19."</item> @@ -374,6 +379,8 @@ <string name="risk_details_explanation_dialog_title">"Information about exposure logging functionality"</string> <!-- YTXT: one time risk explanation dialog - pointing to the faq page for more information--> <string name="risk_details_explanation_dialog_faq_body">"For further information, please see our FAQ page."</string> + <!-- XLNK: risk explanations and informations - pointing to the faq page for more information and contains hyperlink--> + <string name="risk_details_explanation_faq_body_with_link"><a href="https://www.coronawarn.app/en/faq/#encounter_but_green">"For further information, please see our FAQ page."</a></string> <!-- #################################### Onboarding @@ -392,7 +399,7 @@ <!-- XTXT: onboarding - back description for screen reader --> <string name="onboarding_button_back_description">"Back"</string> <!-- XACT: Onboarding (together) page title --> - <string name="onboarding_onboarding_accessibility_title">"Onboarding page 1 of 5: Fighting coronavirus together"</string> + <string name="onboarding_onboarding_accessibility_title">"Onboarding page 1 of 6: Fighting coronavirus together"</string> <!-- XHED: onboarding(together) - fight corona --> <string name="onboarding_headline">"Let\'s fight coronavirus together"</string> <!-- XHED: onboarding(together) - two/three line headline under an illustration --> @@ -404,28 +411,26 @@ <!-- XACT: onboarding(together) - illustraction description, header image --> <string name="onboarding_illustration_description">"A group of persons use their smartphones around town."</string> <!-- XACT: Onboarding (privacy) page title --> - <string name="onboarding_privacy_accessibility_title">"Onboarding page 2 of 5: Data Privacy. A long text follows. To proceed at any time, use the button at the bottom of the screen."</string> + <string name="onboarding_privacy_accessibility_title">"Onboarding page 2 of 6: Data Privacy. A long text follows. To proceed at any time, use the button at the bottom of the screen."</string> <!-- XHED: onboarding(privacy) - title --> <string name="onboarding_privacy_headline">"Data Privacy"</string> <!-- XACT: onboarding(privacy) - illustraction description, header image --> <string name="onboarding_privacy_illustration_description">"A woman uses the Corona-Warn-App on her smartphone. An icon showing a padlock on the background of a shield symbolizes encrypted data."</string> <!-- XACT: Onboarding (tracing) page title --> - <string name="onboarding_tracing_accessibility_title">"Onboarding page 3 of 5: How to Enable Exposure Logging"</string> + <string name="onboarding_tracing_accessibility_title">"Onboarding page 3 of 6: How to Enable Exposure Logging"</string> <!-- XHED: onboarding(tracing) - how to enable tracing --> <string name="onboarding_tracing_headline">"How to Enable Exposure Logging"</string> <!-- XHED: onboarding(tracing) - two/three line headline under an illustration --> <string name="onboarding_tracing_subtitle">"To identify whether you are at risk of infection, you must activate the exposure logging feature."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body">"Exposure logging works by your device receiving, via Bluetooth, encrypted random IDs of other users and passing your own random ID to their devices. This feature can be deactivated at any time."</string> + <string name="onboarding_tracing_body">"Exposure logging works by your smartphone receiving, via Bluetooth, encrypted random IDs of other users and passing your own random IDs to their smartphones. Exposure logging can be deactivated at any time."</string> <!-- YTXT: onboarding(tracing) - explain tracing --> - <string name="onboarding_tracing_body_emphasized">"The encrypted random IDs only pass information about date, duration and proximity (using signal strength) to other people. Personal data such as name, address, location is never recorded. Individuals cannot be identified."</string> + <string name="onboarding_tracing_body_emphasized">"The encrypted random IDs only pass information about date, duration, and proximity (calculated from signal strength) to other people. Individuals cannot be identified based on the random IDs."</string> <!-- YTXT: onboarding(tracing) - easy language explain tracing link--> <string name="onboarding_tracing_easy_language_explanation"><a href="https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache">"App Information in Simplified Language and Sign Language"</a></string> - <!-- XHED: onboarding(tracing) - headline for consent information --> - <string name="onboarding_tracing_headline_consent">"Declaration of Consent"</string> - <!-- YTXT: onboarding(tracing) - body for consent information --> - <string name="onboarding_tracing_body_consent">"To find out whether you have been in contact with an infected person and whether there is a risk that you yourself have been infected, you need to enable the App’s exposure logging feature. By tapping on the “Enable†button, you agree to the enabling of the App’s exposure logging feature and the associated data processing."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"In order to use the App’s exposure logging feature, you will have to enable the COVID-19 Exposure Logging functionality provided by Google on your smartphone and grant the Corona-Warn-App permission to use this."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"When exposure logging is enabled, your smartphone continuously generates and transmits random IDs via Bluetooth, which other Android or Apple smartphones in your vicinity can receive if exposure logging is also enabled on them. Your smartphone, in turn, receives the random IDs of the other smartphones. Your own random IDs and those received from other smartphones are recorded in the exposure log and stored there for 14 days."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To identify your risk of infection, the App loads a list – several times a day or on request – of the random IDs of all users who have told the App that they have been infected with the coronavirus. This list is then compared with the random IDs stored in the exposure log. If the App detects that you may have been in contact with an infected user, it will inform you of this and tell you that there is a risk that you are also infected. In this case, the App is also given access to other data stored in your smartphone’s exposure log (date, duration and Bluetooth signal strength of the contact)."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The Bluetooth signal strength is used to derive the physical distance (the stronger the signal, the smaller the distance). The App then analyses this information in order to assess your likelihood of having been infected with the coronavirus and to give you recommendations for what to do next. This analysis is only performed locally on your smartphone. Apart from you, nobody (not even the RKI) will know whether you have been in contact with an infected person and what risk has been identified for you."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"To withdraw your consent to the exposure logging feature, you can disable the feature using the toggle switch in the App or delete the App. If you decide to use the exposure logging feature again, you can toggle the feature back on or reinstall the App. If you disable the exposure logging feature, the App will no longer check whether you have been in contact with an infected user. If you also wish to stop your device sending and receiving random IDs, you will need to disable COVID-19 Exposure Logging in your smartphone settings. Please note that your own random IDs and those received from other smartphones which are stored in the exposure log will not be deleted in the App. You can only permanently delete the data stored in the exposure log in your smartphone settings."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"The App’s privacy notice (including an explanation of the data processing carried out for the exposure logging feature) can be found in the menu under “Data Privacy Informationâ€."</string> + <!-- NOTR: onboarding(tracing) - easy language explain tracing link URL--> + <string name="onboarding_tracing_easy_language_explanation_url">"https://www.bundesregierung.de/breg-de/themen/corona-warn-app/corona-warn-app-leichte-sprache-gebaerdensprache"</string> <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_button_next">"Activate Exposure Logging"</string> <!-- XTXT: onboarding(tracing) - dialog about tracing permission declined --> @@ -467,7 +472,7 @@ <!-- XBUT: onboarding(tracing) - button enable tracing --> <string name="onboarding_tracing_location_button">"Open Device Settings"</string> <!-- XACT: Onboarding (test) page title --> - <string name="onboarding_test_accessibility_title">"Onboarding page 4 of 5: If you are diagnosed with COVID-19..."</string> + <string name="onboarding_test_accessibility_title">"Onboarding page 5 of 6: If you are diagnosed with COVID-19..."</string> <!-- XHED: onboarding(test) - about positive tests --> <string name="onboarding_test_headline">"If you are diagnosed with COVID-19…"</string> <!-- XHED: onboarding(test) - two/three line headline under an illustration --> @@ -477,7 +482,7 @@ <!-- XACT: onboarding(test) - illustraction description, header image --> <string name="onboarding_test_illustration_description">"An encrypted positive test diagnosis is transmitted to the system, which will now warn other users."</string> <!-- XACT: Onboarding (datashare) page title --> - <string name="onboarding_notifications_accessibility_title">"Onboarding page 5 of 5: Receive warnings and identify risks"</string> + <string name="onboarding_notifications_accessibility_title">"Onboarding page 6 of 6: Receive warnings and identify risks"</string> <!-- XHED: onboarding(datashare) - about positive tests --> <string name="onboarding_notifications_headline">"Receive warnings and identify risks"</string> <!-- XHED: onboarding(datashare) - two/three line headline under an illustration --> @@ -487,6 +492,17 @@ <!-- XACT: onboarding(notifications) - illustraction description, header image --> <string name="onboarding_notifications_illustration_description">"A woman receives a notification from her Corona-Warn-App."</string> + <!-- #################################### + Onboarding sixteen include + ###################################### --> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_title_text">"Age Limit: 16 and Up"</string> + + <!-- XACT: onboarding(sixteen) title --> + <string name="sixteen_description_text">"The use of this app is intended for persons who are at least 16 years of age and who reside in Germany."</string> + + <!-- #################################### Settings ###################################### --> @@ -500,9 +516,9 @@ <!-- XHED: settings(tracing) - page title --> <string name="settings_tracing_title">"Exposure Logging"</string> <!-- XHED: settings(tracing) - headline bellow illustration --> - <string name="settings_tracing_headline">"This is how exposure logging works"</string> + <string name="settings_tracing_headline">"How exposure logging works"</string> <!-- XTXT: settings(tracing) - explain text in settings overview under headline --> - <string name="settings_tracing_body_description">"Allow COVID-19 random IDs to be generated and shared."</string> + <string name="settings_tracing_body_description">"Allow creation and sharing of COVID-19 random IDs."</string> <!-- XTXT: settings(tracing) - shows status under header in home, active --> <string name="settings_tracing_body_active">"Exposure Logging Active"</string> <!-- XTXT: settings(tracing) - shows status under header in home, inactive --> @@ -510,7 +526,7 @@ <!-- XTXT: settings(tracing) - shows status under header in home, inactive location --> <string name="settings_tracing_body_inactive_location">"Location services deactivated"</string> <!-- YTXT: settings(tracing) - explains tracings --> - <string name="settings_tracing_body_text">"You have to activate the exposure logging feature to identify whether you are at risk of infection. Risk identification works by your device receiving, via Bluetooth, encrypted random IDs of other users and passing your random ID to their devices. You can disable this feature any time."<xliff:g id="line_break">"\n"</xliff:g><xliff:g id="line_break">"\n"</xliff:g>"Encrypted random IDs only pass information about date, duration, and proximity to other persons (calculated by signal strength). Personal data such as name, address, and location is never recorded. Individuals cannot be identified."</string> + <string name="settings_tracing_body_text">"You need to enable the exposure logging feature so that the app can determine whether you are at risk after encountering an infected app user. The exposure logging feature works transnationally, meaning any possible exposure involving users is also detected by other official coronavirus apps.\n\nThe exposure logging feature works by your smartphone receiving encrypted random IDs from other users via Bluetooth and passing your own random IDs to their smartphones. Every day, the app downloads a list containing the random IDs – along with any voluntary information about the onset of symptoms – of all users who have tested positive for the virus and voluntarily shared this information via their app. This list is then compared with the random IDs of other users that have been recorded by your smartphone, in order to calculate the likelihood that you have also been infected and to warn you if necessary. You can use the toggle switch to disable exposure logging at any time.\n\nThe app never collects personal data such as your name, address or location, nor is this information passed on to other users. It is not possible to use random IDs to draw conclusions about individual persons."</string> <!-- XTXT: settings(tracing) - status next to switch under title --> <string name="settings_tracing_status_active">"Active"</string> <!-- XTXT: settings(tracing) - status next to switch under title --> @@ -530,7 +546,9 @@ <!--XHED : settings(tracing) - headline on card about the current status and what to do --> <string name="settings_tracing_status_location_headline">"Allow location access"</string> <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled --> - <string name="settings_tracing_status_location_body">"Your location cannot be accessed. Google and/or Android requires access to your device\'s location to use Bluetooth."</string> + <string name="settings_tracing_status_location_body">"Activate your location services. Bluetooth Low Energy requires activated location services to calculate physical distances, but does not access your location. For further information, please see our FAQ page."</string> + <!-- XTXT: settings(tracing) - explains user what to do on card if location is disabled: URL --> + <string name="settings_tracing_status_location_body_url">"https://www.coronawarn.app/en/faq/#android_location"</string> <!-- XBUT: settings(tracing) - go to operating system settings button on card - location --> <string name="settings_tracing_status_location_button">"Open Device Settings"</string> <!--XHED : settings(tracing) - headline on card about the current status and what to do --> @@ -616,9 +634,9 @@ <!-- XTXT: settings(background priority) - text in row on settings overview --> <string name="settings_background_priority_body_description">"Allow automatic risk status updates"</string> <!-- XHED: settings(background priority) - multiline headline below illustration --> - <string name="settings_background_priority_headline">"Run Corona-Warn-App in Background"</string> + <string name="settings_background_priority_headline">"Update Risk Status Automatically"</string> <!-- YTXT: settings(background priority) - description text --> - <string name="settings_background_priority_body">"Corona-Warn-App runs in the background permanently if you activate prioritized background activity. This enables the app to determine your risk status any time."</string> + <string name="settings_background_priority_body">"If you activate prioritized background activity, the App can determine your risk status at any time. This disables battery life optimization for the Corona-Warn-App only."</string> <!-- XACT: settings(background priority) - illustraction description --> <string name="settings_background_priority_illustration_description" /> <!-- XTXT: settings(background priority) - explains user what to do on card if background priority is enabled --> @@ -643,7 +661,7 @@ <!-- YTXT: Body text for about information page --> <string name="information_about_body_emphasized">"Robert Koch Institute (RKI) is Germany’s federal public health body. The RKI publishes the Corona-Warn-App on behalf of the Federal Government. The app is intended as a digital complement to public health measures already introduced: social distancing, hygiene, and face masks."</string> <!-- YTXT: Body text for about information page --> - <string name="information_about_body">"Whoever uses the app helps to trace and break chains of infection. The app saves encounters with other people locally on your device. You are notified if you have encountered people who were later diagnosed with COVID-19. Your identity and privacy are always protected."</string> + <string name="information_about_body">"People who use the app help to trace and break chains of infection. The app saves encounters with other people locally on your device. You are notified if you have encountered people who were later diagnosed with COVID-19. Your identity and privacy are always protected."</string> <!-- XACT: describes illustration --> <string name="information_about_illustration_description">"A group of persons use their smartphones around town."</string> <!-- XHED: Page title for privacy information page, also menu item / button text --> @@ -665,7 +683,7 @@ <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_headline">"How can we help you?"</string> <!-- YTXT: Body text for technical contact and hotline information page --> - <string name="information_contact_body">"For technical questions about the Corona-Warn-App, please contact our hotline."</string> + <string name="information_contact_body">"For technical questions about the Corona-Warn-App, please contact our hotline.\n\nPersons with hearing impairments can use Tess Relay services (interpreting between German written language and sign language) to contact the phone hotline. You can download the software from the App Store/Google Play."</string> <!-- XHED: Subtitle for technical contact and hotline information page --> <string name="information_contact_subtitle_phone">"Technical hotline:"</string> <!-- XLNK: Button / hyperlink to phone call for technical contact and hotline information page --> @@ -702,17 +720,24 @@ <string name="information_legal_headline_contact">"Contact"</string> <!-- YTXT: subtitle for legal information page, contact section --> <string name="information_legal_subtitle_contact">"E-mail: CoronaWarnApp@rki.de"</string> - <!-- YTXT: subtitle for legal information page, open contact form --> - <string name="information_legal_subtitle_contact_form"><a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"Contact Form"</a></string> + <!-- YTXT: subtitle for legal information page, open contact form : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_label">"Contact Form"</string> + <!-- YTXT: subtitle for legal information page url : Only has to be translated in URL for English FOrm--> + <string name="information_legal_subtitle_contact_url">"https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html"</string> <!-- NOTR: subtitle for legal information page, open contact form for languages other than English and German --> <string name="information_legal_subtitle_contact_form_non_en_de">"Contact Form in "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/en/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"English"</a>" or "<a href="https://www.rki.de/SharedDocs/Kontaktformulare/weitere/Corona-Warn-App/Corona-Warn-App_Integrator.html">"German"</a></string> <!-- XHED: Headline for legal information page, tax section --> - <string name="information_legal_headline_taxid">"VAT identification number"</string> + <string name="information_legal_headline_taxid">"VAT identification\nnumber"</string> <!-- YTXT: subtitle for legal information page, tax section --> <string name="information_legal_subtitle_taxid">"DE 165 893 430"</string> <!-- XACT: describes illustration --> <string name="information_legal_illustration_description">"A hand holds a smartphone displaying a large body of text on the screen. Next to the text is a section symbol representing the imprint."</string> + <!-- #################################### + Interoperability + ###################################### --> + <!-- XHED: headline for consent information --> + <string name="interop_consent_headline">"Consent"</string> <!-- #################################### Submission @@ -727,10 +752,14 @@ <!-- XBUT: Positive button for generic web request error --> <string name="submission_error_dialog_web_generic_error_button_positive">"Back"</string> - <!-- XHED: Dialog title for already paired test error --> - <string name="submission_error_dialog_web_test_paired_title">"Error"</string> - <!-- XMSG: Dialog body for already paired test error --> - <string name="submission_error_dialog_web_test_paired_body">"The QR code/TAN is invalid or has been used already. Please try again or contact the technical hotline via App Information -> Technical Hotline."</string> + <!-- XHED: Dialog title for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_title">"QR code is invalid"</string> + <!-- XMSG: Dialog body for already paired test error: qr --> + <string name="submission_error_dialog_web_test_paired_body">"The QR code is invalid or has been registered on another smartphone already. You will receive your test result from the test center or laboratory regardless of the validity of the QR code. If you are diagnosed with COVID-19, you will be notified by the public health authority."</string> + <!-- XHED: Dialog title for already paired test error: tan --> + <string name="submission_error_dialog_web_test_paired_title_tan">"TAN is invalid"</string> + <!-- XMSG: Dialog body for already paired test via tan - error: tan --> + <string name="submission_error_dialog_web_test_paired_body_tan">"The TAN is invalid or has already been used. For further information, call the number listed under \"Request TAN\"."</string> <!-- XBUT: Positive button for already paired test error --> <string name="submission_error_dialog_web_test_paired_button_positive">"Back"</string> @@ -755,6 +784,15 @@ <!-- XBUT: Positive button for submission tan redeemed --> <string name="submission_error_dialog_web_tan_redeemed_button_positive">"OK"</string> + <!-- XHED: Dialog title for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_title">"Do you want to cancel?"</string> + <!-- XMSG: Dialog body for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_body">"Your entries will not be saved."</string> + <!-- XBUT: Positive button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_positive">"Yes"</string> + <!-- XBUT: Negative button for keys submission process cancellation --> + <string name="submission_error_dialog_confirm_cancellation_button_negative">"No"</string> + <!-- Permission Rationale Dialog --> <!-- XHED: Dialog headline QR Scan permission rationale --> <string name="submission_qr_code_scan_permission_rationale_dialog_headline">"Camera authorization required"</string> @@ -805,22 +843,26 @@ <string name="submission_test_result_pending_refresh_button">"Update"</string> <!-- XBUT: test result pending : remove the test button --> <string name="submission_test_result_pending_remove_test_button">"Delete Test"</string> + <!-- XHED: Page headline for positive test result screen --> + <string name="submission_test_result_positive_steps_positive_heading">"Your Test Result"</string> + <!-- YTXT: Body text for next steps section of test positive result--> + <string name="submission_test_result_positive_steps_positive_body">"Your test result was verified as positive."</string> <!-- XHED: Page headline for negative test result next steps --> <string name="submission_test_result_negative_steps_negative_heading">"Your Test Result"</string> <!-- YTXT: Body text for next steps section of test negative result --> <string name="submission_test_result_negative_steps_negative_body">"The laboratory result indicates no verification that you have coronavirus SARS-CoV-2.\n\nPlease delete the test from the Corona-Warn-App, so that you can save a new test code here if necessary."</string> <!-- XBUT: negative test result : remove the test button --> <string name="submission_test_result_negative_remove_test_button">"Delete Test"</string> - <!-- XHED: Page headline for positive test result screen --> - <string name="submission_test_result_positive_steps_positive_heading">"Your Test Result"</string> - <!-- YTXT: Body text for next steps section of test positive result--> - <string name="submission_test_result_positive_steps_positive_body">"Your test result was verified as positive."</string> <!-- XHED: Page headline for other warnings screen --> <string name="submission_test_result_positive_steps_warning_others_heading">"Warning Others"</string> <!-- YTXT: Body text for for other warnings screen--> - <string name="submission_test_result_positive_steps_warning_others_body">"Share your random IDs of the last 14 days in order to protect others and break the chain of infection."</string> + <string name="submission_test_result_positive_steps_warning_others_body">"Share your random IDs and warn others.\nHelp determine the risk of infection for others more accurately by also indicating when you first noticed any coronavirus symptoms."</string> <!-- XBUT: positive test result : continue button --> <string name="submission_test_result_positive_continue_button">"Next"</string> + <!-- XBUT: positive test result : continue button with symptoms--> + <string name="submission_test_result_positive_continue_button_with_symptoms">"Enter Symptoms"</string> + <!-- XBUT: positive test result : continue button without symptoms --> + <string name="submission_test_result_positive_continue_button_wo_symptoms">"Don’t Enter Symptoms"</string> <!-- XHED: Page headline for invalid test result screen --> <string name="submission_test_result_invalid_steps_invalid_heading">"Your Test Result"</string> <!-- YTXT: Body text for next steps section of invalid test result--> @@ -856,9 +898,9 @@ <!-- XACT: Submission Tan page title --> <string name="submission_tan_accessibility_title">"TAN entry"</string> <!-- YTXT: Error text for the tan submission page --> - <string name="submission_tan_error">"Invalid TAN, please check your entry."</string> + <string name="submission_tan_error">"Invalid TAN. Please check your entry."</string> <!-- YTXT: Error text for the tan submission page (wrong characters) --> - <string name="submission_tan_character_error">"Invalid entry. Please check your entry."</string> + <string name="submission_tan_character_error">"Your entry contains invalid characters. Please check your entry."</string> <!-- Submission Intro --> <!-- XHED: Page title for menu at the start of the submission process --> @@ -914,16 +956,27 @@ <!-- XHED: Page headline for the positive result additional warning page--> <string name="submission_positive_other_warning_headline">"Please help all of us!"</string> <!-- YTXT: Body text for the positive result additional warning page--> - <string name="submission_positive_other_warning_body">"Next, you can make sure that the Corona-Warn-App shares your random IDs of the last 14 days with others. By doing this, you can warn other people and help to break the infection chain.\n\nSince only impersonal random IDs are transmitted, your identity will remain anonymous."</string> - <!-- XHED: Title for the privacy card--> - <string name="submission_positive_other_warning_privacy_title">"Data Privacy"</string> - <!-- YTXT: Body text for the privacy card--> - <string name="submission_positive_other_warning_privacy_body">"By tapping on “Acceptâ€, you consent to the App sending your positive test result to the App’s server system along with your random IDs from the last 14 days, so that other App users who have enabled the exposure logging feature can be automatically notified that they may have been exposed to a risk of infection. The random IDs transmitted for this purpose do not contain any information that would allow conclusions to be drawn about your identity or your person. \n\nTransmitting your test result via the App is voluntary. You will not be penalized if you do not transmit your test result. Since it is not possible to trace or check whether and how you use the App, nobody but you will know whether you have transmitted the information that you are infected.\n\nYou can withdraw your consent at any time by deleting the App. This withdrawal of your consent will not affect the lawfulness of the processing carried out based on the consent prior to the withdrawal. Further information can be found in the menu under “Data Privacy Informationâ€."</string> + <string name="submission_positive_other_warning_body">"Next, you can make sure that others are notified of their potential exposure.\n\nTo do so, you can send your own random IDs from the last 14 days and, optionally, information about when you first noticed potential corona symptoms, to the exchange server operated jointly by all participating countries. From there, your random IDs and any other information you choose to provide will be distributed to the users of their official corona apps. This makes it possible to warn the other users of their potential exposure to you.\n\nOnly the random IDs are transmitted, along with any information you provide about when you noticed potential symptoms. No personal data, such as your name, address, or location, will be shared.."</string> <!-- XBUT: other warning continue button --> - <string name="submission_positive_other_warning_button">"Next"</string> + <string name="submission_positive_other_warning_button">"Accept"</string> <!-- XACT: other warning - illustration description, explanation image --> <string name="submission_positive_other_illustration_description">"A device transmits an encrypted positive test diagnosis to the system."</string> + <!-- XHED: Title for the interop country list--> + <string name="submission_interoperability_list_title">"The following countries currently participate in transnational exposure logging:"</string> + <!-- Submission Country Selector --> + <!-- XHED: Page title for the submission country selection page --> + <string name="submission_positive_country_selection_title"></string> + <!-- XHED: Page headline for the submission country selection page --> + <string name="submission_positive_country_selection_headline"></string> + <!-- XHED: Country selector headline for the submission country selection page --> + <string name="submission_country_selector_headline"></string> + <!-- XHED: Country no selection headline for the submission country selection page --> + <string name="submission_country_no_selection_headline"></string> + <!-- YTXT: Data FAQ for the submission country selection page --> + <string name="submission_country_selection_data_faq_body"></string> + <!-- XBUT: submission country selection continue button --> + <string name="submission_country_selection_button"></string> <!-- Submission Done --> <!-- XHED: Page title for completed submission page --> @@ -933,7 +986,7 @@ <!-- XHED: Page subtitle for completed submission page --> <string name="submission_done_subtitle">"Please note:"</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"You are infectious."</string> + <string name="submission_done_contagious">"The public health authority will contact you within the next few days."</string> <!-- YTXT: text after submission: isolate --> <string name="submission_done_isolate">"Please isolate yourself from other people."</string> <!-- XHED: Title for further info --> @@ -948,7 +1001,35 @@ <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Done"</string> <!-- XACT: submission finished - illustration description, explanation image --> - <string name="submission_done_illustration_description">"Everyone in the group is cheering because someone has shared the test result."</string> + <string name="submission_done_illustration_description">"Have you experienced one or more of the following symptoms in the past few days?"</string> + + <!-- Submission Symptoms --> + <!-- XHED: Page title for symptom screens --> + <string name="submission_symptom_title">"Symptoms"</string> + <!-- YTXT: headline text for initial symptom screen --> + <string name="submission_symptom_initial_headline">"Have you experienced one or more of the following symptoms?"</string> + <!-- YTXT: explanation text for initial symptom screen --> + <string name="submission_symptom_initial_explanation">"You can indicate whether and when you noticed any corona symptoms, to allow the App to calculate more accurately the risk of infection to other app users. If you do not want to provide that information, just select \"no answer\"."</string> + <!-- YTXT: Bullet points for symptoms --> + <string-array name="submission_symptom_symptom_bullets"> + <item>"Increased temperature or fever"</item> + <item>"Shortness of breath"</item> + <item>"Loss of sense of smell/taste"</item> + <item>"Cough"</item> + <item>"Runny nose"</item> + <item>"Sore throat"</item> + <item>"Headache and aching limbs"</item> + <item>"General weakness and exhaustion"</item> + </string-array> + <!-- XBUT: symptom initial screen yes button --> + <string name="submission_symptom_positive_button">"Yes"</string> + <!-- XBUT: symptom initial screen no button --> + <string name="submission_symptom_negative_button">"No"</string> + <!-- XBUT: symptom initial screen no information button --> + <string name="submission_symptom_no_information_button">"No statement"</string> + <!-- XBUT: symptom initial screen continue button --> + <string name="submission_symptom_further_button">"Next"</string> + <!-- Submission Contact --> <!-- XHED: Page title for contact page in submission flow --> @@ -979,6 +1060,22 @@ <!-- XACT: Content Description for submission contact step 2 --> <string name="submission_contact_step_2_content">"In the second step, you register your test with your TAN in the app."</string> + <!-- Submission Symptom Calendar --> + <!-- XHED: Page title for calendar page in submission symptom flow --> + <string name="submission_symptom_calendar_title">"Start of Symptoms"</string> + <!-- XHED: Page headline for calendar page in symptom submission flow --> + <string name="submission_symptom_calendar_headline">"When did you first start to experience these symptoms? "</string> + <!-- YTXT: Body text for calendar page in symptom submission flow--> + <string name="submission_symptom_calendar_body">"Select the exact date in the calendar or, if you cannot remember the exact date, choose one of the other options."</string> + <!-- XBUT: symptom calendar screen less than 7 days button --> + <string name="submission_symptom_less_seven">"In the last 7 days"</string> + <!-- XBUT: symptom calendar screen 1-2 weeks button --> + <string name="submission_symptom_one_two_weeks">"1-2 weeks ago"</string> + <!-- XBUT: symptom calendar screen more than 2 weeks button --> + <string name="submission_symptom_more_two_weeks">"More than 2 weeks ago"</string> + <!-- XBUT: symptom calendar screen verify button --> + <string name="submission_symptom_verify">"No statement"</string> + <!-- Submission Status Card --> <!-- XHED: Page title for the various submission status: fetching --> <string name="submission_status_card_title_fetching">"Data being retrieved...."</string> @@ -1015,7 +1112,7 @@ <!-- YTXT: text for contagious card --> <string name="submission_status_card_positive_result_contagious">"You are infectious. Isolate yourself from other people."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"The public health authority will contact you within the next few days by telephone or by letter."</string> + <string name="submission_status_card_positive_result_contact">"The public health authority will contact you within the next few days."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"Share your random IDs so that others can be warned."</string> @@ -1042,6 +1139,9 @@ <item>"Do not go to work if you feel unwell to ensure you do not put other people at risk. If your symptoms worsen, you might need a further SARS-CoV-2 test."</item> </string-array> + <!-- XBUT Symptoms exact date button --> + <string name="symptoms_calendar_exact_date_button">"Exact date"</string> + <!-- #################################### Button Tooltips for Accessibility ###################################### --> @@ -1070,7 +1170,7 @@ <!-- XTXT: error dialog - detailed text if there is an error during external navigation / external action --> <string name="errors_external_action">"You cannot perform this action. Please contact the hotline."</string> <!-- XTXT: error dialog - phone still needs Google Play Services or Google Mobile Services update --> - <string name="errors_google_update_needed">"Your Corona-Warn-App is correctly installed, but the \"COVID-19 exposure notifications\" service is not available on your smartphone\'s operating system. This means that you cannot use the Corona-Warn-App. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string> + <string name="errors_google_update_needed">"Your Corona-Warn-App is correctly installed, but the \"COVID-19 Exposure Notifications System\" is not available on your smartphone\'s operating system. This means that you cannot use the Corona-Warn-App. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string> <!-- XTXT: error dialog - either Google API Error (10) or reached request limit per day --> <string name="errors_google_api_error">"The Corona-Warn-App is running correctly, but we cannot update your current risk status. Exposure logging remains active and is working correctly. For further information, please see our FAQ page: https://www.coronawarn.app/en/faq/"</string> @@ -1087,6 +1187,10 @@ <string name="errors_generic_button_negative">"Details"</string> <!-- XTXT: error dialog - text when no error description is available --> <string name="errors_generic_text_unknown_error_cause">"An unknown error occurred."</string> + <!-- XTXT: error dialog - text when a catastrophic error occured from which the app recovered automatically via data reset --> + <string name="errors_generic_text_catastrophic_error_recovery_via_reset">"Your app was reset due to a technical problem. This has no effect on the app\'s functionality. You will continue to be notified about exposures and still be able to warn others, should you be tested positive for COVID-19."</string> + <!-- XTXT: error dialog - link for the details button in the catastrophic error recovery dialog --> + <string name="errors_generic_text_catastrophic_error_encryption_failure">"https://www.coronawarn.app/en/faq/#cause9002_recovery"</string> <!-- #################################### Just for Development @@ -1094,10 +1198,6 @@ <!-- NOTR --> <string name="lorem_ipsum">"Lorem Ipsum"</string> <!-- NOTR --> - <string name="menu_test_api">"Test API"</string> - <!-- NOTR --> - <string name="menu_test_risk_level">"Test Risk Level"</string> - <!-- NOTR --> <string name="menu_test_notification">"Test Notification"</string> <!-- NOTR --> <string name="test_api_button_api_launch">"Android API Test(Manual Test)"</string> @@ -1140,4 +1240,119 @@ <!-- NOTR --> <string name="test_api_switch_background_notifications">"Background Notifications"</string> + <!-- XHED: Country Entry for Austria --> + <string name="country_name_at">"Austria"</string> + <!-- XHED: Country Entry for Belgium --> + <string name="country_name_be">"Belgium"</string> + <!-- XHED: Country Entry for Bulgaria --> + <string name="country_name_bg">"Bulgaria"</string> + <!-- XHED: Country Entry for Switzerland --> + <string name="country_name_ch">"Switzerland"</string> + <!-- XHED: Country Entry for Cyprus --> + <string name="country_name_cy">"Cyprus"</string> + <!-- XHED: Country Entry for Czech Republic --> + <string name="country_name_cz">"Czech Republic"</string> + <!-- XHED: Country Entry for Germany --> + <string name="country_name_de">"Germany"</string> + <!-- XHED: Country Entry for Denmark --> + <string name="country_name_dk">"Denmark"</string> + <!-- XHED: Country Entry for Estonia --> + <string name="country_name_ee">"Estonia"</string> + <!-- XHED: Country Entry for Spain --> + <string name="country_name_es">"Spain"</string> + <!-- XHED: Country Entry for Finland --> + <string name="country_name_fi">"Finnland"</string> + <!-- XHED: Country Entry for France --> + <string name="country_name_fr">"France"</string> + <!-- XHED: Country Entry for Great Britain --> + <string name="country_name_uk">"United Kingdom"</string> + <!-- XHED: Country Entry for Greece --> + <string name="country_name_gr">"Greece"</string> + <!-- XHED: Country Entry for Croatia --> + <string name="country_name_hr">"Croatia"</string> + <!-- XHED: Country Entry for Hungary --> + <string name="country_name_hu">"Hungary"</string> + <!-- XHED: Country Entry for Ireland --> + <string name="country_name_ie">"Ireland"</string> + <!-- XHED: Country Entry for Iceland --> + <string name="country_name_is">"Iceland"</string> + <!-- XHED: Country Entry for Italy --> + <string name="country_name_it">"Italy"</string> + <!-- XHED: Country Entry for Liechtenstein --> + <string name="country_name_li">"Liechtenstein"</string> + <!-- XHED: Country Entry for Lithuania --> + <string name="country_name_lt">"Lithuania"</string> + <!-- XHED: Country Entry for Luxemburg --> + <string name="country_name_lu">"Luxembourg"</string> + <!-- XHED: Country Entry for Latvia --> + <string name="country_name_lv">"Latvia"</string> + <!-- XHED: Country Entry for Malta --> + <string name="country_name_mt">"Malta"</string> + <!-- XHED: Country Entry for Netherlands --> + <string name="country_name_nl">"Netherlands"</string> + <!-- XHED: Country Entry for Norway --> + <string name="country_name_no">"Norway"</string> + <!-- XHED: Country Entry for Poland --> + <string name="country_name_pl">"Poland"</string> + <!-- XHED: Country Entry for Portugal --> + <string name="country_name_pt">"Portugal"</string> + <!-- XHED: Country Entry for Rumania --> + <string name="country_name_ro">"Romania"</string> + <!-- XHED: Country Entry for Sweden --> + <string name="country_name_se">"Sweden"</string> + <!-- XHED: Country Entry for Slovenia --> + <string name="country_name_si">"Slovenia"</string> + <!-- XHED: Country Entry for Slovakia --> + <string name="country_name_sk">"Slovakia"</string> + + <!-- XHED: Title of the interoperbaility information view. --> + <string name="interoperability_title">"Transnational\nExposure Logging"</string> + + <!-- XHED: Setting title of interoperability in the tracing settings view --> + <string name="settings_interoperability_title">"Transnational Exposure Logging"</string> + <!-- XTXT: Settings description of the interoperability in the tracing settings view --> + <string name="settings_interoperability_subtitle">"Participating Countries"</string> + + <!-- XHED: Header of interoperability information/configuration view --> + <string name="interoperability_configuration_title">"Transnational Exposure Logging"</string> + <!-- XTXT: First section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_first_section">"Several countries are working together to enable transnational alerts via a joint exchange server. For example, contacts with users of an official coronavirus app from other participating countries can also be taken into account for exposure logging."</string> + <!-- XTXT: Second section after the header of the interoperability information/configuration view --> + <string name="interoperability_configuration_second_section">"To do this, the app downloads a list, which is updated daily, of the random IDs of all users who have shared their random IDs via their own app. This list is then compared with the random IDs recorded by your smartphone. The daily download of the list with the random IDs is usually free of charge for you – you will not be charged for the data used by the app in this context, will roaming charges apply for this in other EU countries."</string> + <!-- XHED: Header right above the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_list_title">"The following countries currently participate in transnational exposure logging:"</string> + <!-- XTXT: Text right under the country list in the interoperability information/configuration view --> + <string name="interoperability_configuration_information">"The app’s privacy notice (including information about the data processing carried out for the transnational exposure logging feature) can be found in the menu under “App Information†> “Data Privacyâ€."</string> + + <!-- XHED: Sub header introducing interoperability in the tracing step of onboarding --> + <string name="interoperability_onboarding_title">"Transnational\nExposure Logging"</string> + <!-- YMSG: Onboarding tracing step first section in interoperability after the title --> + <string name="interoperability_onboarding_first_section">"Several countries have teamed up to enable transnational warnings. In other words, your potential exposure to users of the official corona apps in all participating countries can now be taken into account."</string> + <!-- YMSG: Onboarding tracing step second section in interoperability after the title --> + <string name="interoperability_onboarding_second_section">"When a user submits their random IDs to the exchange server jointly operated by the participating countries, users of the official corona apps in all these countries can be warned of potential exposure."</string> + <!-- YMSG: Onboarding tracing step third section in interoperability after the title. --> + <string name="interoperability_onboarding_randomid_download_free">"The daily download of the list with the random IDs is usually free of charge for you. Specifically, this means that mobile network operators do not charge you for the data used by the app in this context, and nor do they apply roaming charges for this in other EU countries. Please contact your mobile network operator for more information."</string> + <!-- XTXT: Small header above the country list in the onboarding screen for interoperability. --> + <string name="interoperability_onboarding_list_title">"The following countries currently participate:"</string> + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 1 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_1">"The terms of use have also been updated, to reflect the functional enhancements in the app."</string> + <!-- XLNK: Terms of use link inside delta interoperability screen--> + <string name="interoperability_onboarding_delta_terms_link">"Display terms of use"</string> + <!-- XTXT: Description of the expanded terms in delta interopoerability screen part 2 --> + <string name="interoperability_onboarding_delta_expanded_terms_text_part_2">"The Terms of Use and privacy notice can also be found in the menu under “App Information†and in the app description in your app store. The changes will not affect how you use the app. If you continue to use the app or reopen it, we will assume that you agree to the updated Terms of Use."</string> + + <!-- XACT: interoperability (eu) - illustraction description, explanation image --> + <string name="interoperability_eu_illustration_description">"A hand holds a smartphone. Europe and the European flag are illustrated in the background."</string> + + <!-- XTXT: Title for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_title_failrequest">"Participating Countries"</string> + <!-- XTXT: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest">"You can view the participating countries in the exposure logging details."</string> + + <!-- YDES: Title for the interoperability onboarding if country download fails for Risk Details --> + <string name="interoperability_onboarding_list_title_riskdetection_no_network">"Countries cannot be displayed now."</string> + <!-- YMSW: Subtitle for the interoperability onboarding if country download fails --> + <string name="interoperability_onboarding_list_subtitle_failrequest_no_network">"Your Internet connection may have been lost. Please ensure that you are connected to the Internet."</string> + <!-- XBUT: Title for the interoperability onboarding Settings-Button if no network is available --> + <string name="interoperability_onboarding_list_button_title_no_network">"Open Device Settings"</string> </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml index c479ad198c7a8c138f7673166268a3c89b4eb1e9..51dd9c9e93f2e565424502e1e487754f4d5dd475 100644 --- a/Corona-Warn-App/src/main/res/values/styles.xml +++ b/Corona-Warn-App/src/main/res/values/styles.xml @@ -133,11 +133,34 @@ <item name="android:backgroundTint">@color/colorSurface2</item> </style> + <style name="SixteenInclude"> + <item name="android:padding">@dimen/card_padding</item> + <item name="android:background">@drawable/card</item> + <item name="android:backgroundTint">@color/colorSemanticNeutralRisk</item> + <item name="android:textColor">@color/colorStableLight</item> + </style> + + <style name="selectionButton" parent="@style/Widget.AppCompat.Button.Borderless"> + <item name="android:padding">@dimen/card_padding</item> + <item name="android:gravity">left</item> + <item name="android:background">@drawable/card</item> + <item name="fontFamily">sans-serif-medium</item> + <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:textStyle">normal</item> + <item name="android:textAllCaps">false</item> + <item name="android:textSize">20sp</item> + <item name="android:letterSpacing">0.0125</item> + </style> + + <style name="targetLayout"> + <item name="android:padding">@dimen/card_padding</item> + <item name="android:background">@drawable/card</item> + </style> + <style name="cardGrey"> <item name="android:background">@drawable/card_dark</item> </style> - <!-- #################################### Grey Body Background ###################################### --> @@ -198,6 +221,14 @@ <item name="android:textColor">@color/colorTextPrimary1</item> </style> + <style name="headline6Sixteen" parent="@style/TextAppearance.MaterialComponents.Headline6"> + <item name="android:textColor">@color/colorTextSixteenWhite</item> + </style> + + <style name="subtitleSixteen" parent="@style/TextAppearance.MaterialComponents.Subtitle1"> + <item name="android:textColor">@color/colorTextSixteenWhite</item> + </style> + <!-- #################################### Icons ###################################### --> @@ -270,4 +301,28 @@ <item name="android:textColor">@color/colorStableLight</item> <item name="android:textSize">14sp</item> </style> + + <!-- #################################### + Calendar + ###################################### --> + <style name="calendarMonthText"> + <item name="android:textColor">@color/colorCalendarMonthText</item> + <item name="android:textSize">@dimen/font_normal</item> + <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:letterSpacing">0.1</item> + </style> + + <style name="calendarWeekDayNormal"> + <item name="android:textColor">@color/colorTextPrimary2</item> + <item name="android:textSize">@dimen/font_small</item> + <item name="android:fontFamily">sans-serif</item> + <item name="android:letterSpacing">0.4</item> + </style> + + <style name="calendarWeekDaySelected"> + <item name="android:textColor">@color/colorCalendarTodayText</item> + <item name="android:textSize">@dimen/font_small</item> + <item name="android:fontFamily">sans-serif-black</item> + <item name="android:letterSpacing">2</item> + </style> </resources> diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigApiTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigApiTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..24c628143e943212db418d207f749ea758e383d5 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigApiTest.kt @@ -0,0 +1,157 @@ +package de.rki.coronawarnapp.appconfig + +import android.content.Context +import de.rki.coronawarnapp.environment.download.DownloadCDNModule +import de.rki.coronawarnapp.http.HttpModule +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.runBlocking +import okhttp3.ConnectionSpec +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import okhttp3.mockwebserver.SocketPolicy +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File +import java.util.concurrent.TimeUnit + +class AppConfigApiTest : BaseIOTest() { + + @MockK private lateinit var context: Context + + private lateinit var webServer: MockWebServer + private lateinit var serverAddress: String + + private val testDir = File(IO_TEST_BASEDIR, this::class.java.simpleName) + private val cacheFiles = File(testDir, "cache") + private val cacheDir = File(cacheFiles, "http_app-config") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { context.cacheDir } returns cacheFiles + + webServer = MockWebServer() + webServer.start() + serverAddress = "http://${webServer.hostName}:${webServer.port}" + } + + @AfterEach + fun teardown() { + clearAllMocks() + webServer.shutdown() + testDir.deleteRecursively() + } + + private fun createAPI(): AppConfigApiV1 { + val httpModule = HttpModule() + val defaultHttpClient = httpModule.defaultHttpClient() + val gsonConverterFactory = httpModule.provideGSONConverter() + + val cdnHttpClient = DownloadCDNModule() + .cdnHttpClient(defaultHttpClient) + .newBuilder() + .connectionSpecs(listOf(ConnectionSpec.CLEARTEXT, ConnectionSpec.MODERN_TLS)) + .build() + + return AppConfigModule().provideAppConfigApi( + context = context, + client = cdnHttpClient, + url = serverAddress, + gsonConverterFactory = gsonConverterFactory + ) + } + + @Test + fun `application config download`() { + val api = createAPI() + + webServer.enqueue(MockResponse().setBody("~appconfig")) + + runBlocking { + api.getApplicationConfiguration("DE").string() shouldBe "~appconfig" + } + + val request = webServer.takeRequest(5, TimeUnit.SECONDS)!! + request.method shouldBe "GET" + request.path shouldBe "/version/v1/configuration/country/DE/app_config" + } + + @Test + fun `application config download uses cache`() { + cacheDir.exists() shouldBe false + + val api = createAPI() + + val configResponse = + MockResponse().setBody("~appconfig").addHeader("Cache-Control: max-age=2") + + webServer.enqueue(configResponse) + runBlocking { + api.getApplicationConfiguration("DE").string() shouldBe "~appconfig" + } + cacheDir.exists() shouldBe true + cacheDir.listFiles()!!.size shouldBe 3 + + webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply { + method shouldBe "GET" + path shouldBe "/version/v1/configuration/country/DE/app_config" + } + + webServer.enqueue(configResponse) + runBlocking { + api.getApplicationConfiguration("DE").string() shouldBe "~appconfig" + } + cacheDir.exists() shouldBe true + cacheDir.listFiles()!!.size shouldBe 3 + + webServer.takeRequest(2, TimeUnit.SECONDS) shouldBe null + + Thread.sleep(4000) // Let the cache expire + + webServer.enqueue(configResponse) + runBlocking { + api.getApplicationConfiguration("DE").string() shouldBe "~appconfig" + } + cacheDir.exists() shouldBe true + cacheDir.listFiles()!!.size shouldBe 3 + + webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply { + method shouldBe "GET" + path shouldBe "/version/v1/configuration/country/DE/app_config" + } + } + + @Test + fun `cache is used when connection is flaky`() { + cacheDir.exists() shouldBe false + + val api = createAPI() + + val configResponse = + MockResponse().setBody("~appconfig").addHeader("Cache-Control: max-age=300") + + webServer.enqueue(configResponse) + runBlocking { + api.getApplicationConfiguration("DE").string() shouldBe "~appconfig" + } + cacheDir.exists() shouldBe true + cacheDir.listFiles()!!.size shouldBe 3 + + webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply { + method shouldBe "GET" + path shouldBe "/version/v1/configuration/country/DE/app_config" + } + + webServer.enqueue(MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_DURING_REQUEST_BODY)) + + runBlocking { + api.getApplicationConfiguration("DE").string() shouldBe "~appconfig" + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigModuleTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigModuleTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..fdae6dd05d6b673b95c5b49a3a5edf39d76c9124 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigModuleTest.kt @@ -0,0 +1,47 @@ +package de.rki.coronawarnapp.appconfig + +import android.content.Context +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File + +class AppConfigModuleTest : BaseIOTest() { + @MockK + private lateinit var context: Context + + private val testDir = File(IO_TEST_BASEDIR, this::class.java.simpleName) + private val cacheFiles = File(testDir, "cache") + private val httpCacheDir = File(cacheFiles, "http_app-config") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { context.cacheDir } returns cacheFiles + + testDir.mkdirs() + testDir.exists() shouldBe true + } + + @AfterEach + fun teardown() { + clearAllMocks() + testDir.deleteRecursively() + } + + private fun createModule() = AppConfigModule() + + @Test + fun `sideeffect free instantiation`() { + shouldNotThrowAny { + createModule() + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigProviderTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..e744b2fc360cc3214b41a46243014e1b33ef77b6 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigProviderTest.kt @@ -0,0 +1,224 @@ +package de.rki.coronawarnapp.appconfig + +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.util.security.VerificationKeys +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import kotlinx.coroutines.runBlocking +import okhttp3.ResponseBody.Companion.toResponseBody +import okio.ByteString.Companion.decodeHex +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File +import java.io.IOException + +class AppConfigProviderTest : BaseIOTest() { + + @MockK lateinit var api: AppConfigApiV1 + @MockK lateinit var verificationKeys: VerificationKeys + @MockK lateinit var appConfigStorage: AppConfigStorage + + private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) + + private val defaultHomeCountry = LocationCode("DE") + + private var mockConfigStorage: ByteArray? = null + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + testDir.mkdirs() + testDir.exists() shouldBe true + + every { appConfigStorage.isAppConfigAvailable } answers { mockConfigStorage != null } + every { appConfigStorage.appConfigRaw } answers { mockConfigStorage } + every { appConfigStorage.appConfigRaw = any() } answers { mockConfigStorage = arg(0) } + } + + @AfterEach + fun teardown() { + clearAllMocks() + testDir.deleteRecursively() + } + + private fun createDownloadServer( + homeCountry: LocationCode = defaultHomeCountry + ) = AppConfigProvider( + appConfigAPI = { api }, + verificationKeys = verificationKeys, + homeCountry = homeCountry, + configStorage = appConfigStorage + ) + + @Test + fun `application config download`() { + coEvery { api.getApplicationConfiguration("DE") } returns APPCONFIG_BUNDLE.toResponseBody() + + every { verificationKeys.hasInvalidSignature(any(), any()) } returns false + + val downloadServer = createDownloadServer() + + runBlocking { + val rawConfig = downloadServer.downloadAppConfig() + rawConfig shouldBe APPCONFIG_RAW.toByteArray() + } + + verify(exactly = 1) { verificationKeys.hasInvalidSignature(any(), any()) } + } + + @Test + fun `application config data is faulty`() { + coEvery { api.getApplicationConfiguration("DE") } returns "123ABC".decodeHex() + .toResponseBody() + + every { verificationKeys.hasInvalidSignature(any(), any()) } returns false + + val downloadServer = createDownloadServer() + + runBlocking { + shouldThrow<ApplicationConfigurationInvalidException> { + downloadServer.downloadAppConfig() + } + } + } + + @Test + fun `application config verification fails`() { + coEvery { api.getApplicationConfiguration("DE") } returns APPCONFIG_BUNDLE + .toResponseBody() + + every { verificationKeys.hasInvalidSignature(any(), any()) } returns true + + val downloadServer = createDownloadServer() + + runBlocking { + shouldThrow<ApplicationConfigurationCorruptException> { + downloadServer.downloadAppConfig() + } + } + } + + @Test + fun `successful download stores new config`() { + coEvery { api.getApplicationConfiguration("DE") } returns APPCONFIG_BUNDLE + .toResponseBody() + + every { verificationKeys.hasInvalidSignature(any(), any()) } returns false + + val downloadServer = createDownloadServer() + + runBlocking { + downloadServer.getAppConfig() + + mockConfigStorage shouldBe APPCONFIG_RAW.toByteArray() + verify { appConfigStorage.appConfigRaw = APPCONFIG_RAW.toByteArray() } + } + } + + @Test + fun `failed download doesn't overwrite valid config`() { + mockConfigStorage = APPCONFIG_RAW.toByteArray() + coEvery { api.getApplicationConfiguration("DE") } throws IOException() + + every { verificationKeys.hasInvalidSignature(any(), any()) } returns false + + runBlocking { + createDownloadServer().getAppConfig() + } + + verify(exactly = 0) { appConfigStorage.appConfigRaw = any() } + mockConfigStorage shouldBe APPCONFIG_RAW.toByteArray() + } + + @Test + fun `failed verification doesn't overwrite valid config`() { + mockConfigStorage = APPCONFIG_RAW.toByteArray() + coEvery { api.getApplicationConfiguration("DE") } returns APPCONFIG_BUNDLE + .toResponseBody() + + every { verificationKeys.hasInvalidSignature(any(), any()) } returns true + + runBlocking { + createDownloadServer().getAppConfig() + } + + verify(exactly = 0) { appConfigStorage.appConfigRaw = any() } + mockConfigStorage shouldBe APPCONFIG_RAW.toByteArray() + } + + @Test + fun `fallback to last config if verification fails`() { + mockConfigStorage = APPCONFIG_RAW.toByteArray() + + coEvery { api.getApplicationConfiguration("DE") } returns "123ABC".decodeHex() + .toResponseBody() + + every { verificationKeys.hasInvalidSignature(any(), any()) } throws Exception() + runBlocking { + createDownloadServer().getAppConfig().minRiskScore shouldBe 11 + } + + every { verificationKeys.hasInvalidSignature(any(), any()) } returns true + runBlocking { + createDownloadServer().getAppConfig().minRiskScore shouldBe 11 + } + } + + @Test + fun `fallback to last config if download fails`() { + mockConfigStorage = APPCONFIG_RAW.toByteArray() + + coEvery { api.getApplicationConfiguration("DE") } throws Exception() + + every { verificationKeys.hasInvalidSignature(any(), any()) } returns false + + runBlocking { + createDownloadServer().getAppConfig().minRiskScore shouldBe 11 + } + } + + // Because the UI requires this to detect when to show alternative UI elements + @Test + fun `if supportedCountryList is empty, we do not insert DE as fallback`() { + coEvery { api.getApplicationConfiguration("DE") } returns APPCONFIG_BUNDLE.toResponseBody() + every { verificationKeys.hasInvalidSignature(any(), any()) } returns false + + runBlocking { + createDownloadServer().getAppConfig().supportedCountriesList shouldBe emptyList() + } + } + + companion object { + private val APPCONFIG_BUNDLE = + ("504b0304140008080800856b22510000000000000000000000000a0000006578706f72742e62696ee3e016" + + "f2e552e662f6f10f97e05792ca28292928b6d2d72f2f2fd74bce2fcacf4b2c4f2ccad34b2c28e0" + + "52e362f1f074f710e097f0c0a74e2a854b80835180498259814583d580cd82dd814390010c3c1d" + + "a4b8141835180d182d181d181561825a021cac02ac12ac0aac40f5ac16ac0eac86102913072b3e" + + "01460946841e47981e25192e160e73017b21214e88d0077ba8250fec1524b5a4b8b8b858043824" + + "98849804588578806a19255884c02400504b0708df2c788daf000000f1000000504b0304140008" + + "080800856b22510000000000000000000000000a0000006578706f72742e736967018a0075ff0a" + + "87010a380a1864652e726b692e636f726f6e617761726e6170702d6465761a0276312203323632" + + "2a13312e322e3834302e31303034352e342e332e321001180122473045022100cf32ff24ea18a1" + + "ffcc7ff4c9fe8d1808cecbc5a37e3e1d4c9ce682120450958c022064bf124b6973a9b510a43d47" + + "9ff93e0ef97a5b893c7af4abc4a8d399969cd8a0504b070813c517c68f0000008a000000504b01" + + "021400140008080800856b2251df2c788daf000000f10000000a00000000000000000000000000" + + "000000006578706f72742e62696e504b01021400140008080800856b225113c517c68f0000008a" + + "0000000a00000000000000000000000000e70000006578706f72742e736967504b050600000000" + + "0200020070000000ae0100000000").decodeHex() + private val APPCONFIG_RAW = + ("080b124d0a230a034c4f57180f221a68747470733a2f2f777777" + + "2e636f726f6e617761726e2e6170700a260a0448494748100f1848221a68747470733a2f2f7777772e636f7" + + "26f6e617761726e2e6170701a640a10080110021803200428053006380740081100000000000049401a0a20" + + "0128013001380140012100000000000049402a1008051005180520052805300538054005310000000000003" + + "4403a0e1001180120012801300138014001410000000000004940221c0a040837103f121209000000000000" + + "f03f11000000000000e03f20192a1a0a0a0a041008180212021005120c0a0408011804120408011804").decodeHex() + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigStorageTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..dd637fbb7269ad1f404b5c58282f9a6f405c1a8b --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/AppConfigStorageTest.kt @@ -0,0 +1,87 @@ +package de.rki.coronawarnapp.appconfig + +import android.content.Context +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File + +class AppConfigStorageTest : BaseIOTest() { + + @MockK private lateinit var context: Context + + private val testDir = File(IO_TEST_BASEDIR, this::class.java.simpleName) + private val privateFiles = File(testDir, "files") + private val storageDir = File(privateFiles, "appconfig_storage") + private val configPath = File(storageDir, "appconfig") + private val testByteArray = "The Cake Is A Lie".toByteArray() + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { context.filesDir } returns privateFiles + } + + @AfterEach + fun teardown() { + clearAllMocks() + testDir.deleteRecursively() + } + + private fun createStorage() = AppConfigStorage(context) + + @Test + fun `config availability is determined by file existence and min size`() { + storageDir.mkdirs() + val storage = createStorage() + storage.isAppConfigAvailable shouldBe false + configPath.createNewFile() + storage.isAppConfigAvailable shouldBe false + + configPath.writeBytes(ByteArray(128) { 1 }) + storage.isAppConfigAvailable shouldBe false + + configPath.writeBytes(ByteArray(129) { 1 }) + storage.isAppConfigAvailable shouldBe true + } + + @Test + fun `simple read and write config`() { + configPath.exists() shouldBe false + val storage = createStorage() + configPath.exists() shouldBe false + + storage.appConfigRaw = testByteArray + + configPath.exists() shouldBe true + configPath.readBytes() shouldBe testByteArray + + storage.appConfigRaw shouldBe testByteArray + } + + @Test + fun `nulling and overwriting`() { + val storage = createStorage() + configPath.exists() shouldBe false + + storage.appConfigRaw shouldBe null + storage.appConfigRaw = null + configPath.exists() shouldBe false + + storage.appConfigRaw shouldBe null + storage.appConfigRaw = testByteArray + storage.appConfigRaw shouldBe testByteArray + configPath.exists() shouldBe true + configPath.readBytes() shouldBe testByteArray + + storage.appConfigRaw = null + storage.appConfigRaw shouldBe null + configPath.exists() shouldBe false + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationExtensionsTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..2b0301482234f80c7bf19fca063a893adfeb194e --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/ApplicationConfigurationExtensionsTest.kt @@ -0,0 +1,22 @@ +package de.rki.coronawarnapp.appconfig + +import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class ApplicationConfigurationExtensionsTest : BaseTest() { + + @Test + fun `to new Config`() { + val orig = ApplicationConfiguration.newBuilder().addSupportedCountries("NL").build() + orig.supportedCountriesList shouldBe listOf("NL") + + orig.toNewConfig { + clearSupportedCountries() + addSupportedCountries("DE") + }.supportedCountriesList shouldBe listOf("DE") + + orig.supportedCountriesList shouldBe listOf("NL") + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/DiagnosisKeysModuleTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/DiagnosisKeysModuleTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..6c8049eba3c415145afa96a3fda15ff0ae8262b7 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/DiagnosisKeysModuleTest.kt @@ -0,0 +1,17 @@ +package de.rki.coronawarnapp.diagnosiskeys + +import io.kotest.assertions.throwables.shouldNotThrowAny +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class DiagnosisKeysModuleTest : BaseTest() { + + private fun createModule() = DiagnosisKeysModule() + + @Test + fun `sideeffect free instantiation`() { + shouldNotThrowAny { + createModule() + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/CountryDataTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/CountryDataTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..52f54f51b584993994e1ec40df2d8aca36cfd147 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/CountryDataTest.kt @@ -0,0 +1,272 @@ +package de.rki.coronawarnapp.diagnosiskeys.download + +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class CountryDataTest : BaseTest() { + private val locationCode = LocationCode("DE") + + private fun createCachedKey(dayString: String, hourString: String? = null): CachedKeyInfo { + return mockk<CachedKeyInfo>().apply { + every { location } returns locationCode + every { day } returns LocalDate.parse(dayString) + every { hour } returns hourString?.let { LocalTime.parse(it) } + } + } + + @Test + fun `missing days default`() { + val availableDates = listOf( + "2222-12-30", "2222-12-31" + ).map { LocalDate.parse(it) } + val cd = CountryDays(locationCode, availableDates) + + cd.dayData shouldBe availableDates + + val cachedDays = listOf( + createCachedKey("2222-12-30") + ) + + cd.getMissingDays(cachedDays) shouldBe listOf(availableDates[1]) + cd.toMissingDays(cachedDays) shouldBe cd.copy( + dayData = listOf(availableDates[1]) + ) + } + + @Test + fun `missing days empty day data`() { + val availableDates = emptyList<LocalDate>() + val cd = CountryDays(locationCode, availableDates) + + cd.dayData shouldBe availableDates + + val cachedDays = listOf( + createCachedKey("2222-12-30"), + createCachedKey("2222-12-31") + ) + + cd.getMissingDays(cachedDays) shouldBe emptyList() + cd.toMissingDays(cachedDays) shouldBe null + } + + @Test + fun `missing days empty cache`() { + val availableDates = listOf( + "2222-11-28", "2222-11-29" + ).map { LocalDate.parse(it) } + val cd = CountryDays(locationCode, availableDates) + + cd.dayData shouldBe availableDates + + val cachedDays = emptyList<CachedKeyInfo>() + + cd.getMissingDays(cachedDays) shouldBe availableDates + cd.toMissingDays(cachedDays) shouldBe cd + } + + @Test + fun `missing days disjunct`() { + val availableDates = listOf( + "2222-11-28", "2222-11-29" + ).map { LocalDate.parse(it) } + val cd = CountryDays(locationCode, availableDates) + + cd.dayData shouldBe availableDates + + val cachedDays = listOf( + createCachedKey("2222-12-28"), + createCachedKey("2222-12-29") + ) + + cd.getMissingDays(cachedDays) shouldBe availableDates + cd.toMissingDays(cachedDays) shouldBe cd + } + + @Test + fun `missing days none missing`() { + val availableDates = listOf( + "2222-12-30", "2222-12-31" + ).map { LocalDate.parse(it) } + val cd = CountryDays(locationCode, availableDates) + + cd.dayData shouldBe availableDates + + val cachedDays = listOf( + createCachedKey("2222-12-30"), + createCachedKey("2222-12-31") + ) + + cd.getMissingDays(cachedDays) shouldBe emptyList() + cd.toMissingDays(cachedDays) shouldBe null + } + + @Test + fun `missing hours default`() { + val availableHours = mapOf( + LocalDate.parse("2222-12-30") to listOf( + LocalTime.parse("19:00"), LocalTime.parse("20:00") + ), + LocalDate.parse("2222-12-31") to listOf( + LocalTime.parse("22:00"), LocalTime.parse("23:00") + ) + ) + val cd = CountryHours(locationCode, availableHours) + + cd.hourData shouldBe availableHours + + val cachedHours = listOf( + createCachedKey("2222-12-30", "19:00"), + createCachedKey("2222-12-31", "23:00") + ) + + val missingHours = mapOf( + LocalDate.parse("2222-12-30") to listOf(LocalTime.parse("20:00")), + LocalDate.parse("2222-12-31") to listOf(LocalTime.parse("22:00")) + ) + + cd.getMissingHours(cachedHours) shouldBe missingHours + cd.toMissingHours(cachedHours) shouldBe cd.copy(hourData = missingHours) + } + + @Test + fun `missing hours empty available hour data`() { + val availableHours: Map<LocalDate, List<LocalTime>> = emptyMap() + val cd = CountryHours(locationCode, availableHours) + + cd.hourData shouldBe availableHours + + val cachedHours = listOf( + createCachedKey("2222-12-30", "19:00"), + createCachedKey("2222-12-31", "23:00") + ) + + cd.getMissingHours(cachedHours) shouldBe emptyMap() + cd.toMissingHours(cachedHours) shouldBe null + } + + @Test + fun `missing hours faulty hour map`() { + val availableHours = mapOf( + LocalDate.parse("2222-12-30") to emptyList<LocalTime>() + ) + val cd = CountryHours(locationCode, availableHours) + + cd.hourData shouldBe availableHours + + val cachedHours = listOf( + createCachedKey("2222-12-30", "19:00"), + createCachedKey("2222-12-31", "23:00") + ) + + cd.getMissingHours(cachedHours) shouldBe emptyMap() + cd.toMissingHours(cachedHours) shouldBe null + } + + @Test + fun `missing hours empty cache`() { + val availableHours = mapOf( + LocalDate.parse("2222-12-30") to listOf( + LocalTime.parse("19:00"), LocalTime.parse("20:00") + ), + LocalDate.parse("2222-12-31") to listOf( + LocalTime.parse("22:00"), LocalTime.parse("23:00") + ) + ) + val cd = CountryHours(locationCode, availableHours) + + cd.hourData shouldBe availableHours + + val cachedHours = emptyList<CachedKeyInfo>() + + cd.getMissingHours(cachedHours) shouldBe availableHours + cd.toMissingHours(cachedHours) shouldBe cd.copy(hourData = availableHours) + } + + @Test + fun `missing hours disjunct`() { + val availableHours = mapOf( + LocalDate.parse("2222-12-30") to listOf( + LocalTime.parse("19:00"), LocalTime.parse("20:00") + ), + LocalDate.parse("2222-12-31") to listOf( + LocalTime.parse("22:00"), LocalTime.parse("23:00") + ) + ) + val cd = CountryHours(locationCode, availableHours) + + cd.hourData shouldBe availableHours + + val cachedHours = listOf( + createCachedKey("2022-12-30", "19:00"), + createCachedKey("2022-12-31", "23:00") + ) + + cd.getMissingHours(cachedHours) shouldBe availableHours + cd.toMissingHours(cachedHours) shouldBe cd.copy(hourData = availableHours) + } + + @Test + fun `missing hours none missing`() { + val availableHours = mapOf( + LocalDate.parse("2222-12-30") to listOf( + LocalTime.parse("19:00"), LocalTime.parse("20:00") + ), + LocalDate.parse("2222-12-31") to listOf( + LocalTime.parse("22:00"), LocalTime.parse("23:00") + ) + ) + val cd = CountryHours(locationCode, availableHours) + + cd.hourData shouldBe availableHours + + val cachedHours = listOf( + createCachedKey("2222-12-30", "19:00"), + createCachedKey("2222-12-30", "20:00"), + createCachedKey("2222-12-31", "22:00"), + createCachedKey("2222-12-31", "23:00") + ) + + cd.getMissingHours(cachedHours) shouldBe emptyMap() + cd.toMissingHours(cachedHours) shouldBe null + } + + @Test + fun `calculate approximate required space for day data`() { + CountryDays(LocationCode("DE"), emptyList()).approximateSizeInBytes shouldBe 0 + CountryDays( + LocationCode("DE"), + listOf(LocalDate.parse("2222-12-30")) + ).approximateSizeInBytes shouldBe 512 * 1024L + CountryDays( + LocationCode("DE"), + listOf(LocalDate.parse("2222-12-30"), LocalDate.parse("2222-12-31")) + ).approximateSizeInBytes shouldBe 2 * 512 * 1024L + } + + @Test + fun `calculate approximate required space for day hour`() { + CountryHours(LocationCode("DE"), emptyMap()).approximateSizeInBytes shouldBe 0 + CountryHours( + LocationCode("DE"), + mapOf(LocalDate.parse("2222-12-30") to listOf(LocalTime.parse("23:00"))) + ).approximateSizeInBytes shouldBe 22 * 1024L + CountryHours( + LocationCode("DE"), + mapOf( + LocalDate.parse("2222-12-30") to listOf(LocalTime.parse("23:00")), + LocalDate.parse("2222-12-31") to listOf( + LocalTime.parse("22:00"), + LocalTime.parse("23:00") + ) + + ) + ).approximateSizeInBytes shouldBe 3 * 22 * 1024L + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloaderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloaderTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..22f91097f670188188e9f450f9372b903d71b1be --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/download/KeyFileDownloaderTest.kt @@ -0,0 +1,767 @@ +package de.rki.coronawarnapp.diagnosiskeys.download + +import android.database.SQLException +import de.rki.coronawarnapp.diagnosiskeys.server.DiagnosisKeyServer +import de.rki.coronawarnapp.diagnosiskeys.server.DownloadInfo +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo +import de.rki.coronawarnapp.diagnosiskeys.storage.CachedKeyInfo.Type +import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.diagnosiskeys.storage.legacy.LegacyKeyCacheMigration +import de.rki.coronawarnapp.storage.AppSettings +import de.rki.coronawarnapp.storage.DeviceStorage +import de.rki.coronawarnapp.storage.InsufficientStorageException +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.runBlocking +import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import testhelpers.BaseIOTest +import testhelpers.extensions.CoroutinesTestExtension +import testhelpers.extensions.InstantExecutorExtension +import testhelpers.flakyTest +import timber.log.Timber +import java.io.File +import java.io.IOException +import kotlin.time.ExperimentalTime + +/** + * CachedKeyFileHolder test. + */ +@ExperimentalTime +@ExperimentalCoroutinesApi +@ExtendWith(InstantExecutorExtension::class, CoroutinesTestExtension::class) +class KeyFileDownloaderTest : BaseIOTest() { + + @MockK + private lateinit var keyCache: KeyCacheRepository + + @MockK + private lateinit var legacyMigration: LegacyKeyCacheMigration + + @MockK + private lateinit var server: DiagnosisKeyServer + + @MockK + private lateinit var deviceStorage: DeviceStorage + + @MockK + private lateinit var settings: AppSettings + + private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) + private val keyRepoData = mutableMapOf<String, CachedKeyInfo>() + + private val String.loc get() = LocationCode(this) + private val String.day get() = LocalDate.parse(this) + private val String.hour get() = LocalTime.parse(this) + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + testDir.mkdirs() + testDir.exists() shouldBe true + + every { settings.isLast3HourModeEnabled } returns false + + coEvery { server.getCountryIndex() } returns listOf("DE".loc, "NL".loc) + coEvery { deviceStorage.requireSpacePrivateStorage(any()) } returns mockk<DeviceStorage.CheckResult>().apply { + every { isSpaceAvailable } returns true + } + + coEvery { server.getDayIndex("DE".loc) } returns listOf( + "2020-09-01".day, "2020-09-02".day + ) + coEvery { + server.getHourIndex("DE".loc, "2020-09-01".day) + } returns (0..23).map { "$it".hour } + coEvery { + server.getHourIndex("DE".loc, "2020-09-02".day) + } returns (0..23).map { "$it".hour } + coEvery { + server.getHourIndex("DE".loc, "2020-09-03".day) + } returns (0..12).map { "$it".hour } + + coEvery { server.getDayIndex("NL".loc) } returns listOf( + "2020-09-01".day, "2020-09-02".day + ) + coEvery { + server.getHourIndex("NL".loc, "2020-09-01".day) + } returns (0..23).map { "$it".hour } + coEvery { + server.getHourIndex("NL".loc, "2020-09-02".day) + } returns (0..23).map { "$it".hour } + coEvery { + server.getHourIndex("NL".loc, "2020-09-03".day) + } returns (0..12).map { "$it".hour } + + coEvery { server.downloadKeyFile(any(), any(), any(), any(), any()) } answers { + mockDownloadServerDownload( + locationCode = arg(0), + day = arg(1), + hour = arg(2), + saveTo = arg(3), + precondition = arg(4) + ) + } + + coEvery { keyCache.createCacheEntry(any(), any(), any(), any()) } answers { + mockKeyCacheCreateEntry(arg(0), arg(1), arg(2), arg(3)) + } + coEvery { keyCache.markKeyComplete(any(), any()) } answers { + mockKeyCacheUpdateComplete(arg(0), arg(1)) + } + coEvery { keyCache.getEntriesForType(any()) } answers { + val type = arg<Type>(0) + keyRepoData.values.filter { it.type == type }.map { it to File(testDir, it.id) } + } + coEvery { keyCache.getAllCachedKeys() } answers { + keyRepoData.values.map { + it to File(testDir, it.id) + } + } + coEvery { keyCache.delete(any()) } answers { + val keyInfos = arg<List<CachedKeyInfo>>(0) + keyInfos.forEach { + keyRepoData.remove(it.id) + } + } + } + + @AfterEach + fun teardown() { + clearAllMocks() + keyRepoData.clear() + testDir.deleteRecursively() + } + + private fun mockKeyCacheCreateEntry( + type: Type, + location: LocationCode, + dayIdentifier: LocalDate, + hourIdentifier: LocalTime? + ): Pair<CachedKeyInfo, File> { + val keyInfo = CachedKeyInfo( + type = type, + location = location, + day = dayIdentifier, + hour = hourIdentifier, + createdAt = Instant.now() + ) + Timber.i("mockKeyCacheCreateEntry(...): %s", keyInfo) + val file = File(testDir, keyInfo.id) + keyRepoData[keyInfo.id] = keyInfo + return keyInfo to file + } + + private fun mockKeyCacheUpdateComplete( + keyInfo: CachedKeyInfo, + checksum: String + ) { + keyRepoData[keyInfo.id] = keyInfo.copy( + isDownloadComplete = true, + checksumMD5 = checksum + ) + } + + private fun mockDownloadServerDownload( + locationCode: LocationCode, + day: LocalDate, + hour: LocalTime? = null, + saveTo: File, + precondition: suspend (DownloadInfo) -> Boolean = { true }, + checksumServerMD5: String? = "serverMD5", + checksumLocalMD5: String? = "localMD5" + ): DownloadInfo { + saveTo.writeText("$locationCode.$day.$hour") + return mockk<DownloadInfo>().apply { + every { serverMD5 } returns checksumServerMD5 + every { localMD5 } returns checksumLocalMD5 + } + } + + private fun mockAddData( + type: Type, + location: LocationCode, + day: LocalDate, + hour: LocalTime?, + isCompleted: Boolean + ): Pair<CachedKeyInfo, File> { + val (keyInfo, file) = mockKeyCacheCreateEntry(type, location, day, hour) + if (isCompleted) { + mockDownloadServerDownload( + locationCode = location, + day = day, + hour = hour, + saveTo = file + ) + mockKeyCacheUpdateComplete(keyInfo, "serverMD5") + } + return keyRepoData[keyInfo.id]!! to file + } + + private fun createDownloader(): KeyFileDownloader { + val downloader = KeyFileDownloader( + deviceStorage = deviceStorage, + keyServer = server, + keyCache = keyCache, + legacyKeyCache = legacyMigration, + settings = settings + ) + Timber.i("createDownloader(): %s", downloader) + return downloader + } + + @Test + fun `wanted country list is empty, day mode`() = flakyTest { + val downloader = createDownloader() + runBlocking { + downloader.asyncFetchKeyFiles(emptyList()) shouldBe emptyList() + } + } + + @Test + fun `wanted country list is empty, hour mode`() = flakyTest { + every { settings.isLast3HourModeEnabled } returns true + + val downloader = createDownloader() + runBlocking { + downloader.asyncFetchKeyFiles(emptyList()) shouldBe emptyList() + } + } + + @Test + fun `fetching is aborted in day if not enough free storage`() = flakyTest { + coEvery { deviceStorage.requireSpacePrivateStorage(1048576L) } throws InsufficientStorageException( + mockk(relaxed = true) + ) + + val downloader = createDownloader() + + runBlocking { + shouldThrow<InsufficientStorageException> { + downloader.asyncFetchKeyFiles(listOf("DE".loc)) + } + } + } + + @Test + fun `fetching is aborted in hour if not enough free storage`() = flakyTest { + every { settings.isLast3HourModeEnabled } returns true + + coEvery { deviceStorage.requireSpacePrivateStorage(67584L) } throws InsufficientStorageException( + mockk(relaxed = true) + ) + + val downloader = createDownloader() + + runBlocking { + shouldThrow<InsufficientStorageException> { + downloader.asyncFetchKeyFiles(listOf("DE".loc)) + } + } + } + + @Test + fun `error during country index fetch`() = flakyTest { + coEvery { server.getCountryIndex() } throws IOException() + + val downloader = createDownloader() + + runBlocking { + shouldThrow<IOException> { + downloader.asyncFetchKeyFiles(listOf("DE".loc)) + } + } + } + + @Test + fun `day fetch without prior data`() = flakyTest { + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 4 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "DE".loc, + dayIdentifier = "2020-09-01".day, + hourIdentifier = null + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "DE".loc, + dayIdentifier = "2020-09-02".day, + hourIdentifier = null + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "NL".loc, + dayIdentifier = "2020-09-01".day, + hourIdentifier = null + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "NL".loc, + dayIdentifier = "2020-09-02".day, + hourIdentifier = null + ) + } + keyRepoData.size shouldBe 4 + keyRepoData.values.forEach { it.isDownloadComplete shouldBe true } + coVerify { deviceStorage.requireSpacePrivateStorage(2097152L) } + } + + @Test + fun `day fetch with existing data`() = flakyTest { + mockAddData( + type = Type.COUNTRY_DAY, + location = "DE".loc, + day = "2020-09-01".day, + hour = null, + isCompleted = true + ) + mockAddData( + type = Type.COUNTRY_DAY, + location = "NL".loc, + day = "2020-09-02".day, + hour = null, + isCompleted = true + ) + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 4 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "DE".loc, + dayIdentifier = "2020-09-02".day, + hourIdentifier = null + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "NL".loc, + dayIdentifier = "2020-09-01".day, + hourIdentifier = null + ) + } + + coVerify(exactly = 2) { keyCache.createCacheEntry(any(), any(), any(), any()) } + coVerify(exactly = 2) { keyCache.markKeyComplete(any(), any()) } + + coVerify { deviceStorage.requireSpacePrivateStorage(1048576L) } + } + + @Test + fun `day fetch deletes stale data`() = flakyTest { + coEvery { server.getDayIndex("DE".loc) } returns listOf("2020-09-02".day) + val (staleKeyInfo, _) = mockAddData( + type = Type.COUNTRY_DAY, + location = "DE".loc, + day = "2020-09-01".day, + hour = null, + isCompleted = true + ) + + mockAddData( + type = Type.COUNTRY_DAY, + location = "NL".loc, + day = "2020-09-02".day, + hour = null, + isCompleted = true + ) + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 3 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "DE".loc, + dayIdentifier = "2020-09-02".day, + hourIdentifier = null + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "NL".loc, + dayIdentifier = "2020-09-01".day, + hourIdentifier = null + ) + } + coVerify(exactly = 1) { keyCache.delete(listOf(staleKeyInfo)) } + coVerify(exactly = 2) { keyCache.createCacheEntry(any(), any(), any(), any()) } + coVerify(exactly = 2) { keyCache.markKeyComplete(any(), any()) } + } + + @Test + fun `day fetch skips single download failures`() = flakyTest { + var dlCounter = 0 + coEvery { server.downloadKeyFile(any(), any(), any(), any(), any()) } answers { + dlCounter++ + if (dlCounter == 2) throw IOException("Timeout") + mockDownloadServerDownload( + locationCode = arg(0), + day = arg(1), + hour = arg(2), + saveTo = arg(3), + precondition = arg(4) + ) + } + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 3 + } + + // We delete the entry for the failed download + coVerify(exactly = 1) { keyCache.delete(any()) } + } + + @Test + fun `last3Hours fetch without prior data`() = flakyTest { + every { settings.isLast3HourModeEnabled } returns true + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 6 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "12".hour + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "11".hour + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "10".hour + ) + + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "12".hour + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "11".hour + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "10".hour + ) + } + coVerify(exactly = 6) { keyCache.markKeyComplete(any(), any()) } + + keyRepoData.size shouldBe 6 + keyRepoData.values.forEach { it.isDownloadComplete shouldBe true } + + coVerify { deviceStorage.requireSpacePrivateStorage(135168L) } + } + + @Test + fun `last3Hours fetch with prior data`() = flakyTest { + every { settings.isLast3HourModeEnabled } returns true + + mockAddData( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + day = "2020-09-03".day, + hour = "11".hour, + isCompleted = true + ) + mockAddData( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + day = "2020-09-03".day, + hour = "11".hour, + isCompleted = true + ) + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles( + listOf("DE".loc, "NL".loc) + ).size shouldBe 6 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "12".hour + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "10".hour + ) + + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "12".hour + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "10".hour + ) + } + coVerify(exactly = 4) { + server.downloadKeyFile(any(), any(), any(), any(), any()) + } + coVerify { deviceStorage.requireSpacePrivateStorage(90112L) } + } + + @Test + fun `last3Hours fetch deletes stale data`() = flakyTest { + every { settings.isLast3HourModeEnabled } returns true + + val (staleKey1, _) = mockAddData( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + day = "2020-09-02".day, + hour = "01".hour, // Stale hour + isCompleted = true + ) + + val (staleKey2, _) = mockAddData( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + day = "2020-09-02".day, // Stale day + hour = "01".hour, + isCompleted = true + ) + + mockAddData( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + day = "2020-09-03".day, + hour = "10".hour, + isCompleted = true + ) + mockAddData( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + day = "2020-09-03".day, + hour = "10".hour, + isCompleted = true + ) + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 6 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "12".hour + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "DE".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "11".hour + ) + + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "12".hour + ) + keyCache.createCacheEntry( + type = Type.COUNTRY_HOUR, + location = "NL".loc, + dayIdentifier = "2020-09-03".day, + hourIdentifier = "11".hour + ) + } + coVerify(exactly = 4) { + server.downloadKeyFile(any(), any(), any(), any(), any()) + } + coVerify(exactly = 1) { keyCache.delete(listOf(staleKey1, staleKey2)) } + } + + @Test + fun `last3Hours fetch skips single download failures`() = flakyTest { + every { settings.isLast3HourModeEnabled } returns true + + var dlCounter = 0 + coEvery { server.downloadKeyFile(any(), any(), any(), any(), any()) } answers { + dlCounter++ + if (dlCounter == 2) throw IOException("Timeout") + mockDownloadServerDownload( + locationCode = arg(0), + day = arg(1), + hour = arg(2), + saveTo = arg(3), + precondition = arg(4) + ) + } + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 5 + } + + // We delete the entry for the failed download + coVerify(exactly = 1) { keyCache.delete(any()) } + } + + @Test + fun `not completed cache entries are overwritten`() = flakyTest { + mockAddData( + type = Type.COUNTRY_DAY, + location = "DE".loc, + day = "2020-09-01".day, + hour = null, + isCompleted = false + ) + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 4 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "DE".loc, + dayIdentifier = "2020-09-01".day, + hourIdentifier = null + ) + } + } + + @Test + fun `database errors do not abort the whole process`() = flakyTest { + var completionCounter = 0 + coEvery { keyCache.markKeyComplete(any(), any()) } answers { + completionCounter++ + if (completionCounter == 2) throw SQLException(":)") + mockKeyCacheUpdateComplete(arg(0), arg(1)) + } + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc, "NL".loc)).size shouldBe 3 + } + + coVerify(exactly = 4) { + server.downloadKeyFile(any(), any(), any(), any(), any()) + } + } + + @Test + fun `store server md5`() = flakyTest { + coEvery { server.getCountryIndex() } returns listOf("DE".loc) + coEvery { server.getDayIndex("DE".loc) } returns listOf("2020-09-01".day) + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc)).size shouldBe 1 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "DE".loc, + dayIdentifier = "2020-09-01".day, + hourIdentifier = null + ) + } + keyRepoData.size shouldBe 1 + keyRepoData.values.forEach { + it.isDownloadComplete shouldBe true + it.checksumMD5 shouldBe "serverMD5" + } + } + + @Test + fun `use local MD5 as fallback if there is none available from the server`() = flakyTest { + coEvery { server.getCountryIndex() } returns listOf("DE".loc) + coEvery { server.getDayIndex("DE".loc) } returns listOf("2020-09-01".day) + coEvery { server.downloadKeyFile(any(), any(), any(), any(), any()) } answers { + mockDownloadServerDownload( + locationCode = arg(0), + day = arg(1), + hour = arg(2), + saveTo = arg(3), + precondition = arg(4), + checksumServerMD5 = null + ) + } + + val downloader = createDownloader() + + runBlocking { + downloader.asyncFetchKeyFiles(listOf("DE".loc)).size shouldBe 1 + } + + coVerify { + keyCache.createCacheEntry( + type = Type.COUNTRY_DAY, + location = "DE".loc, + dayIdentifier = "2020-09-01".day, + hourIdentifier = null + ) + } + keyRepoData.size shouldBe 1 + keyRepoData.values.forEach { + it.isDownloadComplete shouldBe true + it.checksumMD5 shouldBe "localMD5" + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyApiTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyApiTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..a8ed796f69eb60e567d503d66f02018d6e43a7d2 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyApiTest.kt @@ -0,0 +1,127 @@ +package de.rki.coronawarnapp.diagnosiskeys.server + +import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule +import de.rki.coronawarnapp.environment.download.DownloadCDNModule +import de.rki.coronawarnapp.http.HttpModule +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.runBlocking +import okhttp3.ConnectionSpec +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.util.concurrent.TimeUnit + +class DiagnosisKeyApiTest : BaseIOTest() { + + lateinit var webServer: MockWebServer + lateinit var serverAddress: String + + @BeforeEach + fun setup() { + webServer = MockWebServer() + webServer.start() + serverAddress = "http://${webServer.hostName}:${webServer.port}" + } + + @AfterEach + fun teardown() { + webServer.shutdown() + } + + private fun createAPI(): DiagnosisKeyApiV1 { + val httpModule = HttpModule() + val defaultHttpClient = httpModule.defaultHttpClient() + val gsonConverterFactory = httpModule.provideGSONConverter() + + val cdnHttpClient = DownloadCDNModule() + .cdnHttpClient(defaultHttpClient) + .newBuilder() + .connectionSpecs(listOf(ConnectionSpec.CLEARTEXT, ConnectionSpec.MODERN_TLS)) + .build() + + return DiagnosisKeysModule().provideDiagnosisKeyApi( + client = cdnHttpClient, + url = serverAddress, + gsonConverterFactory = gsonConverterFactory + ) + } + + @Test + fun `download country index`() { + val api = createAPI() + + webServer.enqueue(MockResponse().setBody("[\"DE\",\"NL\"]")) + + runBlocking { + api.getCountryIndex() shouldBe listOf("DE", "NL") + } + + val request = webServer.takeRequest(5, TimeUnit.SECONDS)!! + request.method shouldBe "GET" + request.path shouldBe "/version/v1/diagnosis-keys/country" + } + + @Test + fun `download day index for country`() { + val api = createAPI() + + webServer.enqueue(MockResponse().setBody("[\"2020-08-19\",\"2020-08-20\"]")) + + runBlocking { + api.getDayIndex("DE") shouldBe listOf("2020-08-19", "2020-08-20") + } + + val request = webServer.takeRequest(5, TimeUnit.SECONDS)!! + request.method shouldBe "GET" + request.path shouldBe "/version/v1/diagnosis-keys/country/DE/date" + } + + @Test + fun `download hour index for country and day`() { + val api = createAPI() + + webServer.enqueue(MockResponse().setBody("[22,23]")) + + runBlocking { + api.getHourIndex("DE", "2020-08-19") shouldBe listOf("22", "23") + } + + val request = webServer.takeRequest(5, TimeUnit.SECONDS)!! + request.method shouldBe "GET" + request.path shouldBe "/version/v1/diagnosis-keys/country/DE/date/2020-08-19/hour" + } + + @Test + fun `download key files for day`() { + val api = createAPI() + + webServer.enqueue(MockResponse().setBody("~daykeyfile")) + + runBlocking { + api.downloadKeyFileForDay("DE", "2020-09-09").body()!!.string() shouldBe "~daykeyfile" + } + + val request = webServer.takeRequest(5, TimeUnit.SECONDS)!! + request.method shouldBe "GET" + request.path shouldBe "/version/v1/diagnosis-keys/country/DE/date/2020-09-09" + } + + @Test + fun `download key files for hour`() { + val api = createAPI() + + webServer.enqueue(MockResponse().setBody("~hourkeyfile")) + + runBlocking { + api.downloadKeyFileForHour("DE", "2020-09-09", "23").body()!! + .string() shouldBe "~hourkeyfile" + } + + val request = webServer.takeRequest(5, TimeUnit.SECONDS)!! + request.method shouldBe "GET" + request.path shouldBe "/version/v1/diagnosis-keys/country/DE/date/2020-09-09/hour/23" + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..08aed5e5ad0fcfd395d52169b7c3b3d760e9b049 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DiagnosisKeyServerTest.kt @@ -0,0 +1,172 @@ +package de.rki.coronawarnapp.diagnosiskeys.server + +import dagger.Lazy +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.runBlocking +import okhttp3.ResponseBody.Companion.toResponseBody +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import retrofit2.Response +import testhelpers.BaseIOTest +import java.io.File + +class DiagnosisKeyServerTest : BaseIOTest() { + + @MockK + lateinit var api: DiagnosisKeyApiV1 + + private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) + + private val defaultHomeCountry = LocationCode("DE") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + testDir.mkdirs() + testDir.exists() shouldBe true + } + + @AfterEach + fun teardown() { + clearAllMocks() + testDir.deleteRecursively() + } + + private fun createDownloadServer( + homeCountry: LocationCode = defaultHomeCountry + ) = DiagnosisKeyServer( + diagnosisKeyAPI = Lazy { api }, + homeCountry = homeCountry + ) + + @Test + fun `download country index`() { + val downloadServer = createDownloadServer() + coEvery { api.getCountryIndex() } returns listOf("DE", "NL") + + runBlocking { + downloadServer.getCountryIndex() shouldBe listOf( + LocationCode("DE"), LocationCode("NL") + ) + } + + coVerify { api.getCountryIndex() } + } + + @Test + fun `download day index for country`() { + val downloadServer = createDownloadServer() + coEvery { api.getDayIndex("DE") } returns listOf( + "2000-01-01", "2000-01-02" + ) + + runBlocking { + downloadServer.getDayIndex(LocationCode("DE")) shouldBe listOf( + "2000-01-01", "2000-01-02" + ).map { LocalDate.parse(it) } + } + + coVerify { api.getDayIndex("DE") } + } + + @Test + fun `download hour index for country and day`() { + val downloadServer = createDownloadServer() + coEvery { api.getHourIndex("DE", "2000-01-01") } returns listOf( + "1", "2", "20", "21" + ) + + runBlocking { + downloadServer.getHourIndex( + LocationCode("DE"), + LocalDate.parse("2000-01-01") + ) shouldBe listOf( + "01:00", "02:00", "20:00", "21:00" + ).map { LocalTime.parse(it) } + } + + coVerify { api.getHourIndex("DE", "2000-01-01") } + } + + @Test + fun `download key files for day`() { + val downloadServer = createDownloadServer() + coEvery { + api.downloadKeyFileForDay( + "DE", + "2000-01-01" + ) + } returns Response.success("testdata-day".toResponseBody()) + + val targetFile = File(testDir, "day-keys") + + runBlocking { + downloadServer.downloadKeyFile( + locationCode = LocationCode("DE"), + day = LocalDate.parse("2000-01-01"), + hour = null, + saveTo = targetFile + ) + } + + targetFile.exists() shouldBe true + targetFile.readText() shouldBe "testdata-day" + } + + @Test + fun `download key files for hour and check hour format`() { + val downloadServer = createDownloadServer() + + runBlocking { + coEvery { + api.downloadKeyFileForHour( + "DE", + "2000-01-01", + "1" // no leading ZEROS! + ) + } returns Response.success("testdata-hour".toResponseBody()) + + val targetFile = File(testDir, "hour-keys") + + downloadServer.downloadKeyFile( + locationCode = LocationCode("DE"), + day = LocalDate.parse("2000-01-01"), + hour = LocalTime.parse("01:00"), + saveTo = targetFile + ) + + targetFile.exists() shouldBe true + targetFile.readText() shouldBe "testdata-hour" + } + + runBlocking { + coEvery { + api.downloadKeyFileForHour( + "DE", + "2000-01-01", + "13" + ) + } returns Response.success("testdata-hour".toResponseBody()) + + val targetFile = File(testDir, "hour-keys") + + downloadServer.downloadKeyFile( + locationCode = LocationCode("DE"), + day = LocalDate.parse("2000-01-01"), + hour = LocalTime.parse("13:00"), + saveTo = targetFile + ) + + targetFile.exists() shouldBe true + targetFile.readText() shouldBe "testdata-hour" + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DownloadInfoTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DownloadInfoTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..cceb7f2d5481cccdb7f1e6c3edd1afbaf38bf0e4 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/server/DownloadInfoTest.kt @@ -0,0 +1,19 @@ +package de.rki.coronawarnapp.diagnosiskeys.server + +import io.kotest.matchers.shouldBe +import okhttp3.Headers +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class DownloadInfoTest : BaseTest() { + + @Test + fun `extract server MD5`() { + val info = DownloadInfo( + headers = Headers.headersOf("ETAG", "serverMD5"), + localMD5 = "localMD5" + ) + info.serverMD5 shouldBe "serverMD5" + info.localMD5 shouldBe "localMD5" + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyFileTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyFileTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..cf1d1ebe08debced8dc4ccda7b90eed1e5d0da18 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/CachedKeyFileTest.kt @@ -0,0 +1,62 @@ +package de.rki.coronawarnapp.diagnosiskeys.storage + +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import io.kotest.matchers.shouldBe +import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class CachedKeyFileTest : BaseTest() { + private val type = CachedKeyInfo.Type.COUNTRY_DAY + private val location = LocationCode("DE") + private val day = LocalDate.parse("2222-12-31") + private val hour = LocalTime.parse("23:59") + private val now = Instant.EPOCH + + @Test + fun `secondary constructor`() { + val key = CachedKeyInfo(type, location, day, hour, now) + + key.id shouldBe CachedKeyInfo.calcluateId(location, day, hour, type) + key.checksumMD5 shouldBe null + key.isDownloadComplete shouldBe false + } + + @Test + fun `keyfile id calculation`() { + val calculatedId1 = CachedKeyInfo.calcluateId(location, day, hour, type) + val calculatedId2 = CachedKeyInfo.calcluateId(location, day, hour, type) + calculatedId1 shouldBe calculatedId2 + + calculatedId1 shouldBe "550b64773e052b9ddf232998a92846833ed3f907" + } + + @Test + fun `to completion`() { + val key = CachedKeyInfo(type, location, day, hour, now) + val testChecksum = "testchecksum" + val downloadCompleteUpdate = key.toDownloadUpdate(testChecksum) + + downloadCompleteUpdate shouldBe CachedKeyInfo.DownloadUpdate( + id = downloadCompleteUpdate.id, + isDownloadComplete = true, + checksumMD5 = testChecksum + ) + + val resetDownloadUpdate = key.toDownloadUpdate(null) + + resetDownloadUpdate shouldBe CachedKeyInfo.DownloadUpdate( + id = downloadCompleteUpdate.id, + isDownloadComplete = false, + checksumMD5 = null + ) + } + + @Test + fun `trip changed typing`() { + CachedKeyInfo.Type.COUNTRY_DAY.typeValue shouldBe "country_day" + CachedKeyInfo.Type.COUNTRY_HOUR.typeValue shouldBe "country_hour" + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheRepositoryTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..95fe5150464b5906f94d5555fd0ec10785712d56 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/KeyCacheRepositoryTest.kt @@ -0,0 +1,206 @@ +package de.rki.coronawarnapp.diagnosiskeys.storage + +import android.content.Context +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.util.TimeStamper +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.runBlocking +import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File + +class KeyCacheRepositoryTest : BaseIOTest() { + @MockK + lateinit var context: Context + + @MockK + lateinit var timeStamper: TimeStamper + + @MockK + lateinit var databaseFactory: KeyCacheDatabase.Factory + + @MockK + lateinit var database: KeyCacheDatabase + + @MockK + lateinit var keyfileDAO: KeyCacheDatabase.CachedKeyFileDao + + private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + testDir.mkdirs() + testDir.exists() shouldBe true + + every { timeStamper.nowUTC } returns Instant.EPOCH + every { context.cacheDir } returns File(testDir, "cache") + + every { databaseFactory.create() } returns database + every { database.cachedKeyFiles() } returns keyfileDAO + + coEvery { keyfileDAO.getAllEntries() } returns emptyList() + } + + @AfterEach + fun teardown() { + clearAllMocks() + testDir.deleteRecursively() + } + + private fun createRepo(): KeyCacheRepository = KeyCacheRepository( + context = context, + databaseFactory = databaseFactory, + timeStamper = timeStamper + ) + + @Test + fun `housekeeping runs before data access`() { + val lostKey = CachedKeyInfo( + location = LocationCode("DE"), + day = LocalDate.now(), + hour = LocalTime.now(), + type = CachedKeyInfo.Type.COUNTRY_HOUR, + createdAt = Instant.now() + ).copy( + isDownloadComplete = true, + checksumMD5 = "checksum" + ) + + val existingKey = CachedKeyInfo( + location = LocationCode("NL"), + day = LocalDate.now(), + hour = LocalTime.now(), + type = CachedKeyInfo.Type.COUNTRY_HOUR, + createdAt = Instant.now() + ) + + File(testDir, "diagnosis_keys/${existingKey.id}.zip").apply { + parentFile!!.mkdirs() + createNewFile() + } + + coEvery { keyfileDAO.getAllEntries() } returns listOf(lostKey, existingKey) + coEvery { keyfileDAO.updateDownloadState(any()) } returns Unit + coEvery { keyfileDAO.deleteEntry(lostKey) } returns Unit + + val repo = createRepo() + + coVerify(exactly = 0) { keyfileDAO.updateDownloadState(any()) } + + runBlocking { + repo.getAllCachedKeys() + coVerify(exactly = 2) { keyfileDAO.getAllEntries() } + coVerify { keyfileDAO.deleteEntry(lostKey) } + } + } + + @Test + fun `insert and retrieve`() { + val repo = createRepo() + + coEvery { keyfileDAO.insertEntry(any()) } returns Unit + + runBlocking { + val (keyFile, path) = repo.createCacheEntry( + location = LocationCode("NL"), + dayIdentifier = LocalDate.parse("2020-09-09"), + hourIdentifier = LocalTime.parse("23:00"), + type = CachedKeyInfo.Type.COUNTRY_HOUR + ) + + path shouldBe File(context.cacheDir, "diagnosis_keys/${keyFile.id}.zip") + + coVerify { keyfileDAO.insertEntry(keyFile) } + } + } + + @Test + fun `update download state`() { + val repo = createRepo() + + coEvery { keyfileDAO.insertEntry(any()) } returns Unit + coEvery { keyfileDAO.updateDownloadState(any()) } returns Unit + + runBlocking { + val (keyFile, _) = repo.createCacheEntry( + location = LocationCode("NL"), + dayIdentifier = LocalDate.parse("2020-09-09"), + hourIdentifier = LocalTime.parse("23:00"), + type = CachedKeyInfo.Type.COUNTRY_HOUR + ) + + repo.markKeyComplete(keyFile, "checksum") + + coVerify { + keyfileDAO.insertEntry(keyFile) + keyfileDAO.updateDownloadState(keyFile.toDownloadUpdate("checksum")) + } + } + } + + @Test + fun `delete only selected entries`() { + val repo = createRepo() + + coEvery { keyfileDAO.insertEntry(any()) } returns Unit + coEvery { keyfileDAO.deleteEntry(any()) } returns Unit + + runBlocking { + val (keyFile, path) = repo.createCacheEntry( + location = LocationCode("NL"), + dayIdentifier = LocalDate.parse("2020-09-09"), + hourIdentifier = LocalTime.parse("23:00"), + type = CachedKeyInfo.Type.COUNTRY_HOUR + ) + + path.createNewFile() shouldBe true + path.exists() shouldBe true + + repo.delete(listOf(keyFile)) + + coVerify { keyfileDAO.deleteEntry(keyFile) } + + path.exists() shouldBe false + } + } + + @Test + fun `clear all files`() { + val repo = createRepo() + + val keyFileToClear = CachedKeyInfo( + location = LocationCode("DE"), + day = LocalDate.now(), + hour = LocalTime.now(), + type = CachedKeyInfo.Type.COUNTRY_HOUR, + createdAt = Instant.now() + ) + + coEvery { keyfileDAO.getAllEntries() } returns listOf(keyFileToClear) + coEvery { keyfileDAO.deleteEntry(any()) } returns Unit + + val keyFilePath = repo.getPathForKey(keyFileToClear) + keyFilePath.createNewFile() shouldBe true + keyFilePath.exists() shouldBe true + + runBlocking { + repo.clear() + + coVerify { keyfileDAO.deleteEntry(keyFileToClear) } + + keyFilePath.exists() shouldBe false + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheEntityTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheEntityTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..311923c1019b7cc973c7a381eae25ad750ac3905 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/KeyCacheEntityTest.kt @@ -0,0 +1,5 @@ +package de.rki.coronawarnapp.diagnosiskeys.storage.legacy + +import testhelpers.BaseTest + +class KeyCacheEntityTest : BaseTest() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/LegacyKeyCacheMigrationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/LegacyKeyCacheMigrationTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..e1a33d271802f2e3c2ea47f4999ddb71666a6271 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/diagnosiskeys/storage/legacy/LegacyKeyCacheMigrationTest.kt @@ -0,0 +1,215 @@ +package de.rki.coronawarnapp.diagnosiskeys.storage.legacy + +import android.content.Context +import android.database.SQLException +import dagger.Lazy +import de.rki.coronawarnapp.util.HashExtensions.hashToMD5 +import de.rki.coronawarnapp.util.TimeStamper +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import kotlinx.coroutines.runBlocking +import org.joda.time.Duration +import org.joda.time.Instant +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File +import java.io.IOException + +class LegacyKeyCacheMigrationTest : BaseIOTest() { + + @MockK + lateinit var context: Context + + @MockK + lateinit var timeStamper: TimeStamper + + @MockK + lateinit var legacyDao: KeyCacheLegacyDao + + private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) + private val legacyDir = File(testDir, "key-export") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + testDir.mkdirs() + testDir.exists() shouldBe true + + every { context.cacheDir } returns testDir + every { timeStamper.nowUTC } returns Instant.EPOCH + + coEvery { legacyDao.clear() } returns Unit + } + + @AfterEach + fun teardown() { + clearAllMocks() + testDir.deleteRecursively() + } + + private fun createTool() = LegacyKeyCacheMigration( + context = context, + legacyDao = Lazy { legacyDao }, + timeStamper = timeStamper + ) + + @Test + fun `nothing happens on null checksum`() { + val tool = createTool() + runBlocking { + tool.tryMigration(null, File(testDir, "something")) + } + + coVerify(exactly = 0) { legacyDao.clear() } + } + + @Test + fun `migrate a file successfully`() { + val legacyFile1 = File(legacyDir, "1234.zip") + legacyFile1.parentFile!!.mkdirs() + legacyFile1.writeText("testdata") + legacyFile1.exists() shouldBe true + + val legacyFile1MD5 = legacyFile1.hashToMD5() + legacyFile1MD5.isNotEmpty() shouldBe true + + val migrationTarget = File(testDir, "migratedkey.zip") + + val tool = createTool() + runBlocking { + tool.tryMigration(legacyFile1MD5, migrationTarget) + } + + legacyFile1.exists() shouldBe false + migrationTarget.exists() shouldBe true + migrationTarget.hashToMD5() shouldBe legacyFile1MD5 + + coVerify(exactly = 1) { legacyDao.clear() } + } + + @Test + fun `migrating a single file fails gracefully`() { + val legacyFile1 = File(legacyDir, "1234.zip") + legacyFile1.parentFile!!.mkdirs() + legacyFile1.writeText("testdata") + legacyFile1.exists() shouldBe true + + val legacyFile1MD5 = legacyFile1.hashToMD5() + legacyFile1MD5.isNotEmpty() shouldBe true + + val migrationTarget = mockk<File>() + every { migrationTarget.path } throws IOException() + + val tool = createTool() + runBlocking { + tool.tryMigration(legacyFile1MD5, migrationTarget) + } + + legacyFile1.exists() shouldBe false + + coVerify(exactly = 1) { legacyDao.clear() } + } + + @Test + fun `legacy app database can crash, we don't care`() { + val legacyFile1 = File(legacyDir, "1234.zip") + legacyFile1.parentFile!!.mkdirs() + legacyFile1.writeText("testdata") + legacyFile1.exists() shouldBe true + + val legacyFile1MD5 = legacyFile1.hashToMD5() + legacyFile1MD5.isNotEmpty() shouldBe true + + val migrationTarget = File(testDir, "migratedkey.zip") + + coEvery { legacyDao.clear() } throws SQLException() + + val tool = createTool() + runBlocking { + tool.tryMigration(legacyFile1MD5, migrationTarget) + } + + legacyFile1.exists() shouldBe false + migrationTarget.exists() shouldBe true + migrationTarget.hashToMD5() shouldBe legacyFile1MD5 + + coVerify(exactly = 1) { legacyDao.clear() } + } + + @Test + fun `init failure causes legacy cache to be cleared`() { + val legacyFile1 = File(legacyDir, "1234.zip") + legacyFile1.parentFile!!.mkdirs() + legacyFile1.writeText("testdata") + + val legacyFile1MD5 = legacyFile1.hashToMD5() + legacyFile1MD5.isNotEmpty() shouldBe true + + legacyFile1.setReadable(false) + + val migrationTarget = File(testDir, "migratedkey.zip") + + val tool = createTool() + runBlocking { + tool.tryMigration(legacyFile1MD5, migrationTarget) + } + + legacyFile1.exists() shouldBe false + migrationTarget.exists() shouldBe false + } + + @Test + fun `stale legacy files (older than 15 days) are cleaned up on init`() { + val legacyFile1 = File(legacyDir, "1234.zip") + legacyFile1.parentFile!!.mkdirs() + legacyFile1.writeText("testdata") + + val legacyFile1MD5 = legacyFile1.hashToMD5() + legacyFile1MD5.isNotEmpty() shouldBe true + + every { timeStamper.nowUTC } returns Instant.ofEpochMilli(legacyFile1.lastModified()) + .plus(Duration.standardDays(16)) + + val migrationTarget = File(testDir, "migratedkey.zip") + + coEvery { legacyDao.clear() } throws SQLException() + + val tool = createTool() + runBlocking { + tool.tryMigration(legacyFile1MD5, migrationTarget) + } + + legacyFile1.exists() shouldBe false + migrationTarget.exists() shouldBe false + } + + @Test + fun `init deletes empty cache dir`() { + legacyDir.mkdirs() + legacyDir.exists() shouldBe true + + runBlocking { + val tool = createTool() + tool.tryMigration("doesntmatter", File(testDir, "1")) + } + legacyDir.exists() shouldBe false + legacyDir.parentFile!!.exists() shouldBe true + + runBlocking { + val tool = createTool() + tool.tryMigration("doesntmatter", File(testDir, "1")) + } + legacyDir.exists() shouldBe false + legacyDir.parentFile!!.exists() shouldBe true + + coVerify(exactly = 1) { legacyDao.clear() } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/BuildConfigWrapTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/BuildConfigWrapTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..cded06c92cf5f0f3783bcc1bb2c3f4684d72e03e --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/BuildConfigWrapTest.kt @@ -0,0 +1,13 @@ +package de.rki.coronawarnapp.environment + +import io.kotest.matchers.collections.shouldBeIn +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class BuildConfigWrapTest : BaseTest() { + + @Test + fun `default environment type should be DEV`() { + BuildConfigWrap.ENVIRONMENT_TYPE_DEFAULT shouldBeIn listOf("DEV", "INT", "WRU-XD", "PROD") + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentModuleTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentModuleTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..f1f62538e2164cae883b4e9853cf6f655b190f9c --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentModuleTest.kt @@ -0,0 +1,17 @@ +package de.rki.coronawarnapp.environment + +import io.kotest.assertions.throwables.shouldNotThrowAny +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class EnvironmentModuleTest : BaseTest() { + + private fun createModule() = EnvironmentModule() + + @Test + fun `side effect free instantiation`() { + shouldNotThrowAny { + createModule() + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..0bedabb73cecff5ed4b75c253d8c8c4abd579962 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt @@ -0,0 +1,188 @@ +package de.rki.coronawarnapp.environment + +import android.content.Context +import de.rki.coronawarnapp.environment.EnvironmentSetup.Type.Companion.toEnvironmentType +import de.rki.coronawarnapp.util.CWADebug +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockkObject +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import testhelpers.preferences.MockSharedPreferences + +class EnvironmentSetupTest : BaseTest() { + @MockK lateinit var context: Context + private lateinit var mockPreferences: MockSharedPreferences + private fun createEnvSetup() = EnvironmentSetup(context) + + @BeforeEach + fun setUp() { + MockKAnnotations.init(this) + mockkObject(BuildConfigWrap) + mockkObject(CWADebug) + + every { BuildConfigWrap.ENVIRONMENT_JSONDATA } returns GOOD_JSON + + mockPreferences = MockSharedPreferences() + every { + context.getSharedPreferences( + "environment_setup", + Context.MODE_PRIVATE + ) + } returns mockPreferences + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + @Test + fun `parsing bad json throws an exception in debug builds`() { + every { BuildConfigWrap.ENVIRONMENT_JSONDATA } returns BAD_JSON + shouldThrow<IllegalStateException> { + createEnvSetup().downloadCdnUrl + } + } + + @Test + fun `mapping between function and JSON variable names is correct`() { + every { CWADebug.buildFlavor } returns CWADebug.BuildFlavor.DEVICE_FOR_TESTERS + val envSetup = createEnvSetup() + + EnvironmentSetup.Type.values().forEach { env -> + envSetup.apply { + currentEnvironment = env + currentEnvironment shouldBe env + + useEuropeKeyPackageFiles shouldBe ENVS_WITH_EUR_PKGS.contains(env) + downloadCdnUrl shouldBe "https://download-${env.rawKey}" + submissionCdnUrl shouldBe "https://submission-${env.rawKey}" + verificationCdnUrl shouldBe "https://verification-${env.rawKey}" + appConfigVerificationKey shouldBe "12345678-${env.rawKey}" + } + } + } + + @Test + fun `default environment type is set correctly`() { + createEnvSetup().defaultEnvironment shouldBe BuildConfigWrap.ENVIRONMENT_TYPE_DEFAULT.toEnvironmentType() + } + + @Test + fun `switching the default type is persisted in storage (preferences)`() { + every { BuildConfigWrap.ENVIRONMENT_TYPE_DEFAULT } returns EnvironmentSetup.Type.DEV.rawKey + if (CWADebug.buildFlavor == CWADebug.BuildFlavor.DEVICE_FOR_TESTERS) { + createEnvSetup().apply { + defaultEnvironment shouldBe EnvironmentSetup.Type.DEV + currentEnvironment shouldBe defaultEnvironment + currentEnvironment = EnvironmentSetup.Type.WRU + currentEnvironment shouldBe EnvironmentSetup.Type.WRU + } + mockPreferences.dataMapPeek.values.single() shouldBe EnvironmentSetup.Type.WRU.rawKey + createEnvSetup().apply { + defaultEnvironment shouldBe EnvironmentSetup.Type.DEV + currentEnvironment shouldBe EnvironmentSetup.Type.WRU + } + } else { + createEnvSetup().apply { + defaultEnvironment shouldBe EnvironmentSetup.Type.DEV + currentEnvironment shouldBe defaultEnvironment + currentEnvironment = EnvironmentSetup.Type.WRU + currentEnvironment shouldBe defaultEnvironment + } + mockPreferences.dataMapPeek.values shouldBe emptyList() + createEnvSetup().apply { + currentEnvironment shouldBe defaultEnvironment + } + } + } + + @Test + fun `test enum mapping values`() { + EnvironmentSetup.Type.PRODUCTION.rawKey shouldBe "PROD" + EnvironmentSetup.Type.DEV.rawKey shouldBe "DEV" + EnvironmentSetup.Type.INT.rawKey shouldBe "INT" + EnvironmentSetup.Type.INT_FED.rawKey shouldBe "INT-FED" + EnvironmentSetup.Type.WRU.rawKey shouldBe "WRU" + EnvironmentSetup.Type.WRU_XA.rawKey shouldBe "WRU-XA" + EnvironmentSetup.Type.WRU_XD.rawKey shouldBe "WRU-XD" + EnvironmentSetup.Type.values().size shouldBe 7 + + EnvironmentSetup.EnvKey.USE_EUR_KEY_PKGS.rawKey shouldBe "USE_EUR_KEY_PKGS" + EnvironmentSetup.EnvKey.SUBMISSION.rawKey shouldBe "SUBMISSION_CDN_URL" + EnvironmentSetup.EnvKey.VERIFICATION.rawKey shouldBe "VERIFICATION_CDN_URL" + EnvironmentSetup.EnvKey.DOWNLOAD.rawKey shouldBe "DOWNLOAD_CDN_URL" + EnvironmentSetup.EnvKey.VERIFICATION_KEYS.rawKey shouldBe "PUB_KEYS_SIGNATURE_VERIFICATION" + EnvironmentSetup.EnvKey.values().size shouldBe 5 + } + + companion object { + private const val BAD_JSON = "{ environmentType: {\n \"SUBMISSION_CDN_U" + private val ENVS_WITH_EUR_PKGS = listOf( + EnvironmentSetup.Type.PRODUCTION, + EnvironmentSetup.Type.INT_FED, + EnvironmentSetup.Type.WRU_XD, + EnvironmentSetup.Type.WRU_XA + ) + private const val GOOD_JSON = """ + { + "PROD": { + "USE_EUR_KEY_PKGS" : true, + "SUBMISSION_CDN_URL": "https://submission-PROD", + "DOWNLOAD_CDN_URL": "https://download-PROD", + "VERIFICATION_CDN_URL": "https://verification-PROD", + "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-PROD" + }, + "DEV": { + "USE_EUR_KEY_PKGS" : false, + "SUBMISSION_CDN_URL": "https://submission-DEV", + "DOWNLOAD_CDN_URL": "https://download-DEV", + "VERIFICATION_CDN_URL": "https://verification-DEV", + "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-DEV" + }, + "INT": { + "USE_EUR_KEY_PKGS" : false, + "SUBMISSION_CDN_URL": "https://submission-INT", + "DOWNLOAD_CDN_URL": "https://download-INT", + "VERIFICATION_CDN_URL": "https://verification-INT", + "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-INT" + }, + "INT-FED": { + "USE_EUR_KEY_PKGS" : true, + "SUBMISSION_CDN_URL": "https://submission-INT-FED", + "DOWNLOAD_CDN_URL": "https://download-INT-FED", + "VERIFICATION_CDN_URL": "https://verification-INT-FED", + "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-INT-FED" + }, + "WRU": { + "USE_EUR_KEY_PKGS" : false, + "SUBMISSION_CDN_URL": "https://submission-WRU", + "DOWNLOAD_CDN_URL": "https://download-WRU", + "VERIFICATION_CDN_URL": "https://verification-WRU", + "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU" + }, + "WRU-XD": { + "USE_EUR_KEY_PKGS" : true, + "SUBMISSION_CDN_URL": "https://submission-WRU-XD", + "DOWNLOAD_CDN_URL": "https://download-WRU-XD", + "VERIFICATION_CDN_URL": "https://verification-WRU-XD", + "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XD" + }, + "WRU-XA": { + "USE_EUR_KEY_PKGS" : true, + "SUBMISSION_CDN_URL": "https://submission-WRU-XA", + "DOWNLOAD_CDN_URL": "https://download-WRU-XA", + "VERIFICATION_CDN_URL": "https://verification-WRU-XA", + "PUB_KEYS_SIGNATURE_VERIFICATION": "12345678-WRU-XA" + } + } + """ + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/download/DownloadCDNModuleTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/download/DownloadCDNModuleTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..05d67c24d46c6e3f0fc5e8adfddd575f90a81cb2 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/download/DownloadCDNModuleTest.kt @@ -0,0 +1,58 @@ +package de.rki.coronawarnapp.environment.download + +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import de.rki.coronawarnapp.environment.EnvironmentSetup +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.assertions.throwables.shouldThrowAny +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest + +class DownloadCDNModuleTest : BaseIOTest() { + + private val validUrl = "https://coronawarn-test.com/Download" + private val inValidUrl = "Biryani" + + @MockK + private lateinit var environmentSetup: EnvironmentSetup + + @BeforeEach + fun setUp() { + MockKAnnotations.init(this) + every { environmentSetup.downloadCdnUrl } returns validUrl + } + + private fun createModule() = DownloadCDNModule() + + @Test + fun `sideeffect free instantiation`() { + shouldNotThrowAny { + createModule() + } + } + + @Test + fun `home country should be DE`() { + val module = createModule() + module.provideDiagnosisHomeCountry() shouldBe LocationCode("DE") + } + + @Test + fun `valid downloaded URL comes from environment`() { + val module = createModule() + module.provideDownloadServerUrl(environmentSetup) shouldBe validUrl + } + + @Test + fun `invalid downloaded URL comes from environment`() { + every { environmentSetup.downloadCdnUrl } returns inValidUrl + val module = createModule() + shouldThrowAny { + module.provideDownloadServerUrl(environmentSetup) shouldBe validUrl + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNModuleTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNModuleTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..c316aeb2c0e08b5855832c8e89ad5cff75d809c8 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/submission/SubmissionCDNModuleTest.kt @@ -0,0 +1,51 @@ +package de.rki.coronawarnapp.environment.submission + +import de.rki.coronawarnapp.environment.EnvironmentSetup +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.assertions.throwables.shouldThrowAny +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest + +class SubmissionCDNModuleTest : BaseIOTest() { + + private val validUrl = "https://coronawarn-test.com/Submission" + private val inValidUrl = "Tiramisu" + + @MockK + private lateinit var environmentSetup: EnvironmentSetup + + @BeforeEach + fun setUp() { + MockKAnnotations.init(this) + every { environmentSetup.submissionCdnUrl } returns validUrl + } + + private fun createModule() = SubmissionCDNModule() + + @Test + fun `sideeffect free instantiation`() { + shouldNotThrowAny { + createModule() + } + } + + @Test + fun `valid downloaded URL comes from environment`() { + val module = createModule() + module.provideSubmissionUrl(environmentSetup) shouldBe validUrl + } + + @Test + fun `invalid downloaded URL comes from environment`() { + every { environmentSetup.submissionCdnUrl } returns inValidUrl + val module = createModule() + shouldThrowAny { + module.provideSubmissionUrl(environmentSetup) + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/verification/VerificationCDNModuleTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/verification/VerificationCDNModuleTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..83b3f1d922ce2b825c363c8028e16f87547f60bf --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/verification/VerificationCDNModuleTest.kt @@ -0,0 +1,49 @@ +package de.rki.coronawarnapp.environment.verification + +import de.rki.coronawarnapp.environment.EnvironmentSetup +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.assertions.throwables.shouldThrowAny +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest + +class VerificationCDNModuleTest : BaseIOTest() { + private val validUrl = "https://coronawarn-test.com/Verification" + private val inValidUrl = "Chicken Wings" + + @MockK lateinit var environmentSetup: EnvironmentSetup + + @BeforeEach + fun setUp() { + MockKAnnotations.init(this) + } + + private fun createModule() = VerificationCDNModule() + + @Test + fun `sideeffect free instantiation`() { + shouldNotThrowAny { + createModule() + } + } + + @Test + fun `valid downloaded URL comes from environment`() { + every { environmentSetup.verificationCdnUrl } returns validUrl + val module = VerificationCDNModule() + module.provideVerificationUrl(environmentSetup) shouldBe validUrl + } + + @Test + fun `invalid downloaded URL comes from environment`() { + every { environmentSetup.verificationCdnUrl } returns inValidUrl + shouldThrowAny { + val module = VerificationCDNModule() + module.provideVerificationUrl(environmentSetup) + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/WebRequestBuilderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/WebRequestBuilderTest.kt deleted file mode 100644 index 1b931b2dac8eea912dc31f56db3992e0c8f609ae..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/WebRequestBuilderTest.kt +++ /dev/null @@ -1,82 +0,0 @@ -package de.rki.coronawarnapp.http - -import de.rki.coronawarnapp.http.service.DistributionService -import de.rki.coronawarnapp.http.service.SubmissionService -import de.rki.coronawarnapp.http.service.VerificationService -import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants -import de.rki.coronawarnapp.util.TimeAndDateExtensions.toServerFormat -import de.rki.coronawarnapp.util.security.VerificationKeys -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.impl.annotations.MockK -import io.mockk.unmockkAll -import kotlinx.coroutines.runBlocking -import org.junit.After -import org.junit.Assert -import org.junit.Before -import org.junit.Test -import java.util.Date - -class WebRequestBuilderTest { - @MockK - private lateinit var verificationService: VerificationService - - @MockK - private lateinit var distributionService: DistributionService - - @MockK - private lateinit var submissionService: SubmissionService - - @MockK - private lateinit var verificationKeys: VerificationKeys - - private lateinit var webRequestBuilder: WebRequestBuilder - - @Before - fun setUp() = run { - MockKAnnotations.init(this) - webRequestBuilder = WebRequestBuilder( - distributionService, - verificationService, - submissionService, - verificationKeys - ) - } - - @After - fun tearDown() = unmockkAll() - - @Test - fun retrievingDateIndexIsSuccessful() { - val urlString = DiagnosisKeyConstants.AVAILABLE_DATES_URL - coEvery { distributionService.getDateIndex(urlString) } - .returns(listOf("1900-01-01", "2000-01-01")) - - runBlocking { - val expectedResult = listOf("1900-01-01", "2000-01-01") - Assert.assertEquals(webRequestBuilder.asyncGetDateIndex(), expectedResult) - coVerify { - distributionService.getDateIndex(urlString) - } - } - } - - @Test - fun asyncGetHourIndex() { - val day = Date() - val urlString = DiagnosisKeyConstants.AVAILABLE_DATES_URL + - "/${day.toServerFormat()}/${DiagnosisKeyConstants.HOUR}" - - coEvery { distributionService.getHourIndex(urlString) } - .returns(listOf("1", "2")) - - runBlocking { - val expectedResult = listOf("1", "2") - Assert.assertEquals(webRequestBuilder.asyncGetHourIndex(day), expectedResult) - coVerify { - distributionService.getHourIndex(urlString) - } - } - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/config/HTTPVariablesTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/config/HTTPVariablesTest.kt index f0f051a514c7734bf4ee3d63f037a399a961ad3e..c3ce75478f90366a98587ac61a2e25caf3fc5b0d 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/config/HTTPVariablesTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/config/HTTPVariablesTest.kt @@ -7,16 +7,16 @@ class HTTPVariablesTest { @Test fun getHTTPConnectionTimeout() { - Assert.assertEquals(HTTPVariables.getHTTPConnectionTimeout(), 10000L) + Assert.assertEquals(HTTPVariables.getHTTPConnectionTimeout(), 20000L) } @Test fun getHTTPReadTimeout() { - Assert.assertEquals(HTTPVariables.getHTTPReadTimeout(), 10000L) + Assert.assertEquals(HTTPVariables.getHTTPReadTimeout(), 20000L) } @Test fun getHTTPWriteTimeout() { - Assert.assertEquals(HTTPVariables.getHTTPWriteTimeout(), 10000L) + Assert.assertEquals(HTTPVariables.getHTTPWriteTimeout(), 20000L) } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/DefaultPlaybookTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/DefaultPlaybookTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..0b12d642f1af921448573e95ea908ac221fbb8e1 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/DefaultPlaybookTest.kt @@ -0,0 +1,240 @@ +package de.rki.coronawarnapp.http.playbook + +import de.rki.coronawarnapp.playbook.DefaultPlaybook +import de.rki.coronawarnapp.playbook.Playbook +import de.rki.coronawarnapp.submission.server.SubmissionServer +import de.rki.coronawarnapp.util.formatter.TestResult +import de.rki.coronawarnapp.verification.server.VerificationKeyType +import de.rki.coronawarnapp.verification.server.VerificationServer +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerifySequence +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import testhelpers.exceptions.TestException + +class DefaultPlaybookTest : BaseTest() { + + @MockK lateinit var submissionServer: SubmissionServer + @MockK lateinit var verificationServer: VerificationServer + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + coEvery { verificationServer.retrieveRegistrationToken(any(), any()) } returns "token" + coEvery { verificationServer.retrieveTestResults(any()) } returns 0 + coEvery { verificationServer.retrieveTanFake() } returns mockk() + coEvery { verificationServer.retrieveTan(any()) } returns "tan" + + coEvery { submissionServer.submitKeysToServer(any()) } returns mockk() + coEvery { submissionServer.submitKeysToServerFake() } returns mockk() + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + private fun createPlaybook() = DefaultPlaybook( + verificationServer = verificationServer, + submissionServer = submissionServer + ) + + @Test + fun `initial registration pattern matches`(): Unit = runBlocking { + coEvery { verificationServer.retrieveRegistrationToken(any(), any()) } returns "response" + + createPlaybook().initialRegistration("9A3B578UMG", VerificationKeyType.TELETAN) + + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveRegistrationToken(any(), any()) + verificationServer.retrieveTestResults(any()) + submissionServer.submitKeysToServerFake() + } + } + + @Test + fun ` registration pattern matches despite token failure`(): Unit = runBlocking { + coEvery { + verificationServer.retrieveRegistrationToken(any(), any()) + } throws TestException() + + shouldThrow<TestException> { + createPlaybook().initialRegistration("9A3B578UMG", VerificationKeyType.TELETAN) + } + + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveRegistrationToken(any(), any()) + verificationServer.retrieveTanFake() + submissionServer.submitKeysToServerFake() + } + } + + @Test + fun `submission matches request pattern`(): Unit = runBlocking { + coEvery { verificationServer.retrieveTan(any()) } returns "tan" + + createPlaybook().submission( + Playbook.SubmissionData( + registrationToken = "token", + temporaryExposureKeys = listOf(), + consentToFederation = true, + visistedCountries = listOf("DE") + ) + ) + + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveTan(any()) + verificationServer.retrieveTanFake() + submissionServer.submitKeysToServer(any()) + } + } + + @Test + fun `submission matches request pattern despite missing authcode`(): Unit = runBlocking { + coEvery { verificationServer.retrieveTan(any()) } throws TestException() + + shouldThrow<TestException> { + createPlaybook().submission( + Playbook.SubmissionData( + registrationToken = "token", + temporaryExposureKeys = listOf(), + consentToFederation = true, + visistedCountries = listOf("DE") + ) + ) + } + + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveTan(any()) + verificationServer.retrieveTanFake() + // Only called when null TAN is returned? But when does that happen? + submissionServer.submitKeysToServerFake() + } + } + + @Test + fun `test result retrieval matches pattern`(): Unit = runBlocking { + coEvery { verificationServer.retrieveTestResults(any()) } returns 0 + + createPlaybook().testResult("token") + + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveTestResults(any()) + verificationServer.retrieveTanFake() + submissionServer.submitKeysToServerFake() + } + } + + @Test + fun `dummy request pattern matches`(): Unit = runBlocking { + createPlaybook().dummy() + + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveTanFake() + verificationServer.retrieveTanFake() + submissionServer.submitKeysToServerFake() + } + } + + @Test + fun `failures during dummy requests should be ignored`(): Unit = runBlocking { + val expectedToken = "token" + coEvery { verificationServer.retrieveRegistrationToken(any(), any()) } returns expectedToken + val expectedResult = TestResult.PENDING + coEvery { verificationServer.retrieveTestResults(expectedToken) } returns expectedResult.value + coEvery { submissionServer.submitKeysToServerFake() } throws TestException() + + val (registrationToken, testResult) = createPlaybook() + .initialRegistration("key", VerificationKeyType.GUID) + + registrationToken shouldBe expectedToken + testResult shouldBe expectedResult + } + + @Test + fun `registration pattern matches despire token failure`(): Unit = runBlocking { + coEvery { + verificationServer.retrieveRegistrationToken(any(), any()) + } throws TestException() + + shouldThrow<TestException> { + createPlaybook().initialRegistration("9A3B578UMG", VerificationKeyType.TELETAN) + } + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveRegistrationToken(any(), any()) + verificationServer.retrieveTanFake() + submissionServer.submitKeysToServerFake() + } + } + + @Test + fun `registration pattern matches despite test result failure`(): Unit = runBlocking { + coEvery { verificationServer.retrieveTestResults(any()) } throws TestException() + + shouldThrow<TestException> { + createPlaybook().initialRegistration("9A3B578UMG", VerificationKeyType.TELETAN) + } + + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveRegistrationToken(any(), any()) + verificationServer.retrieveTestResults(any()) + submissionServer.submitKeysToServerFake() + } + } + + @Test + fun `test result pattern matches despite failure`(): Unit = runBlocking { + coEvery { verificationServer.retrieveTestResults(any()) } throws TestException() + + shouldThrow<TestException> { + createPlaybook().testResult("token") + } + + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveTestResults(any()) + verificationServer.retrieveTanFake() + submissionServer.submitKeysToServerFake() + } + } + + @Test + fun `submission pattern matches despite tan failure`(): Unit = runBlocking { + coEvery { verificationServer.retrieveTan(any()) } throws TestException() + + shouldThrow<TestException> { + createPlaybook().submission( + Playbook.SubmissionData( + registrationToken = "token", + temporaryExposureKeys = listOf(), + consentToFederation = true, + visistedCountries = listOf("DE") + ) + ) + } + coVerifySequence { + // ensure request order is 2x verification and 1x submission + verificationServer.retrieveTan(any()) + verificationServer.retrieveTanFake() + submissionServer.submitKeysToServerFake() + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/PlaybookImplTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/PlaybookImplTest.kt deleted file mode 100644 index 60cf0a738269c3df3724c686ea7aba3c42f3c918..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/PlaybookImplTest.kt +++ /dev/null @@ -1,164 +0,0 @@ -package de.rki.coronawarnapp.http.playbook - -import de.rki.coronawarnapp.exception.http.InternalServerErrorException -import de.rki.coronawarnapp.service.submission.KeyType -import de.rki.coronawarnapp.util.newWebRequestBuilder -import kotlinx.coroutines.runBlocking -import okhttp3.mockwebserver.MockResponse -import okhttp3.mockwebserver.MockWebServer -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers -import org.hamcrest.Matchers.equalTo -import org.junit.Assert.fail -import org.junit.Test - -class PlaybookImplTest { - - @Test - fun hasRequestPattern_initialRegistration(): Unit = runBlocking { - val server = MockWebServer() - server.start() - - server.enqueue(MockResponse().setBody("""{"registrationToken":"response"}""")) - server.enqueue(MockResponse().setBody("{}")) - server.enqueue(MockResponse().setBody("{}")) - - PlaybookImpl(server.newWebRequestBuilder()) - .initialRegistration("9A3B578UMG", KeyType.TELETAN) - - // ensure request order is 2x verification and 1x submission - assertRequestPattern(server) - } - - @Test - fun hasRequestPattern_submission(): Unit = runBlocking { - val server = MockWebServer() - server.start() - - server.enqueue(MockResponse().setBody("""{"tan":"response"}""")) - server.enqueue(MockResponse().setBody("{}")) - server.enqueue(MockResponse().setBody("{}")) - - PlaybookImpl(server.newWebRequestBuilder()) - .submission("token", listOf()) - - // ensure request order is 2x verification and 1x submission - assertRequestPattern(server) - } - - @Test - fun hasRequestPattern_testResult(): Unit = runBlocking { - val server = MockWebServer() - server.start() - - server.enqueue(MockResponse().setBody("""{"testResult":0}""")) - server.enqueue(MockResponse().setBody("{}")) - server.enqueue(MockResponse().setBody("{}")) - - PlaybookImpl(server.newWebRequestBuilder()) - .testResult("token") - - // ensure request order is 2x verification and 1x submission - assertRequestPattern(server) - } - - @Test - fun hasRequestPattern_dummy(): Unit = runBlocking { - val server = MockWebServer() - server.start() - - server.enqueue(MockResponse().setBody("{}")) - server.enqueue(MockResponse().setBody("{}")) - server.enqueue(MockResponse().setBody("{}")) - - PlaybookImpl(server.newWebRequestBuilder()) - .dummy() - - // ensure request order is 2x verification and 1x submission - assertRequestPattern(server) - } - - @Test - fun shouldIgnoreFailuresForDummyRequests(): Unit = runBlocking { - val server = MockWebServer() - server.start() - - val expectedRegistrationToken = "token" - server.enqueue(MockResponse().setBody("""{"registrationToken":"$expectedRegistrationToken"}""")) - server.enqueue(MockResponse().setResponseCode(500)) - server.enqueue(MockResponse().setResponseCode(500)) - - val registrationToken = PlaybookImpl(server.newWebRequestBuilder()) - .initialRegistration("key", KeyType.GUID) - - assertThat(registrationToken, equalTo(expectedRegistrationToken)) - } - - @Test - fun hasRequestPatternWhenRealRequestFails_initialRegistration(): Unit = runBlocking { - val server = MockWebServer() - server.start() - - server.enqueue(MockResponse().setResponseCode(500)) - server.enqueue(MockResponse().setBody("{}")) - server.enqueue(MockResponse().setBody("{}")) - - try { - - PlaybookImpl(server.newWebRequestBuilder()) - .initialRegistration("9A3B578UMG", KeyType.TELETAN) - fail("exception propagation expected") - } catch (e: InternalServerErrorException) { - } - - // ensure request order is 2x verification and 1x submission - assertRequestPattern(server) - } - - @Test - fun hasRequestPatternWhenRealRequestFails_testResult(): Unit = runBlocking { - val server = MockWebServer() - server.start() - - server.enqueue(MockResponse().setResponseCode(500)) - server.enqueue(MockResponse().setBody("{}")) - server.enqueue(MockResponse().setBody("{}")) - - try { - - PlaybookImpl(server.newWebRequestBuilder()) - .testResult("token") - fail("exception propagation expected") - } catch (e: InternalServerErrorException) { - } - - // ensure request order is 2x verification and 1x submission - assertRequestPattern(server) - } - - @Test - fun hasRequestPatternWhenRealRequestFails_submission(): Unit = runBlocking { - val server = MockWebServer() - server.start() - - server.enqueue(MockResponse().setResponseCode(500)) - server.enqueue(MockResponse().setBody("{}")) - server.enqueue(MockResponse().setBody("{}")) - - try { - PlaybookImpl(server.newWebRequestBuilder()) - .submission("token", listOf()) - fail("exception propagation expected") - } catch (e: InternalServerErrorException) { - } - - // ensure request order is 2x verification and 1x submission - assertRequestPattern(server) - } - - private fun assertRequestPattern(server: MockWebServer) { - assertThat(server.takeRequest().path, Matchers.startsWith("/verification/")) - assertThat(server.takeRequest().path, Matchers.startsWith("/verification/")) - assertThat(server.takeRequest().path, Matchers.startsWith("/submission/")) - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/service/SubmissionServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/service/SubmissionServiceTest.kt deleted file mode 100644 index d8eae0c49d434fdee968072fa9afb1302672df73..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/service/SubmissionServiceTest.kt +++ /dev/null @@ -1,43 +0,0 @@ -package de.rki.coronawarnapp.http.service - -import de.rki.coronawarnapp.util.headerSizeIgnoringContentLength -import de.rki.coronawarnapp.util.newWebRequestBuilder -import kotlinx.coroutines.runBlocking -import okhttp3.mockwebserver.MockResponse -import okhttp3.mockwebserver.MockWebServer -import org.junit.Assert -import org.junit.Test - -class SubmissionServiceTest { - - @Test - fun allRequestHaveSameFootprintForPlausibleDeniability(): Unit = runBlocking { - - val server = MockWebServer() - server.start() - - val webRequestBuilder = server.newWebRequestBuilder() - - val authCodeExample = "39ec4930-7a1f-4d5d-921f-bfad3b6f1269" - - server.enqueue(MockResponse().setBody("{}")) - webRequestBuilder.asyncSubmitKeysToServer(authCodeExample, listOf()) - - server.enqueue(MockResponse().setBody("{}")) - webRequestBuilder.asyncFakeSubmission() - - val requests = listOf( - server.takeRequest(), - server.takeRequest() - ) - - // ensure all request have same size (header & body) - requests.zipWithNext().forEach { (a, b) -> - Assert.assertEquals( - "Header size mismatch: ", - a.headerSizeIgnoringContentLength(), - b.headerSizeIgnoringContentLength() - ) - } - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/service/VerificationServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/service/VerificationServiceTest.kt deleted file mode 100644 index 3dde34e4171d63c625a2d6db9a50acb6f19d2ee2..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/service/VerificationServiceTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -package de.rki.coronawarnapp.http.service - -import de.rki.coronawarnapp.service.submission.KeyType -import de.rki.coronawarnapp.util.headerSizeIgnoringContentLength -import de.rki.coronawarnapp.util.newWebRequestBuilder -import kotlinx.coroutines.runBlocking -import okhttp3.mockwebserver.MockResponse -import okhttp3.mockwebserver.MockWebServer -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test - -class VerificationServiceTest { - - @Test - fun allRequestHaveSameFootprintForPlausibleDeniability(): Unit = runBlocking { - - val server = MockWebServer() - server.start() - - val webRequestBuilder = server.newWebRequestBuilder() - - val guidExample = "3BF1D4-1C6003DD-733D-41F1-9F30-F85FA7406BF7" - val teletanExample = "9A3B578UMG" - val registrationTokenExample = "63b4d3ff-e0de-4bd4-90c1-17c2bb683a2f" - - server.enqueue(MockResponse().setBody("{}")) - webRequestBuilder.asyncGetRegistrationToken(guidExample, KeyType.GUID) - - server.enqueue(MockResponse().setBody("{}")) - webRequestBuilder.asyncGetRegistrationToken(teletanExample, KeyType.TELETAN) - - server.enqueue(MockResponse().setBody("{}")) - webRequestBuilder.asyncGetTestResult(registrationTokenExample) - - server.enqueue(MockResponse().setBody("{}")) - webRequestBuilder.asyncGetTan(registrationTokenExample) - - server.enqueue(MockResponse().setBody("{}")) - webRequestBuilder.asyncFakeVerification() - - val requests = listOf( - server.takeRequest(), - server.takeRequest(), - server.takeRequest(), - server.takeRequest(), - server.takeRequest() - ) - - // ensure all request have same size (header & body) - requests.forEach { assertThat(it.bodySize, equalTo(250L)) } - - requests.zipWithNext().forEach { (a, b) -> - assertThat( - a.headerSizeIgnoringContentLength(), - equalTo(b.headerSizeIgnoringContentLength()) - ) - } - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..5a91e9b4eed50fdb33c859eef3bebe22b406e2dc --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/ENFClientTest.kt @@ -0,0 +1,76 @@ +package de.rki.coronawarnapp.nearby + +import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import java.io.File + +@Suppress("DEPRECATION") +class ENFClientTest : BaseTest() { + + @MockK + lateinit var googleENFClient: ExposureNotificationClient + + @MockK + lateinit var diagnosisKeyProvider: DiagnosisKeyProvider + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any(), any()) } returns true + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + private fun createClient() = ENFClient( + googleENFClient = googleENFClient, + diagnosisKeyProvider = diagnosisKeyProvider + ) + + @Test + fun `internal enf client is available as workaround`() { + val client = createClient() + client.internalClient shouldBe googleENFClient + } + + @Test + fun `provide diagnosis key call is forwarded to the right module`() { + val client = createClient() + val keyFiles = listOf(File("test")) + val configuration = mockk<ExposureConfiguration>() + val token = "123" + + coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any(), any()) } returns true + runBlocking { + client.provideDiagnosisKeys(keyFiles, configuration, token) shouldBe true + } + + coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any(), any()) } returns false + runBlocking { + client.provideDiagnosisKeys(keyFiles, configuration, token) shouldBe false + } + + coVerify(exactly = 2) { + diagnosisKeyProvider.provideDiagnosisKeys( + keyFiles, + configuration, + token + ) + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..2141680366571b7216d7d003b3874eb570a60160 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt @@ -0,0 +1,200 @@ +@file:Suppress("DEPRECATION") + +package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider + +import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import com.google.android.gms.tasks.OnSuccessListener +import com.google.android.gms.tasks.Task +import de.rki.coronawarnapp.util.GoogleAPIVersion +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import java.io.File + +class DefaultDiagnosisKeyProviderTest : BaseTest() { + @MockK + lateinit var googleENFClient: ExposureNotificationClient + + @MockK + lateinit var googleAPIVersion: GoogleAPIVersion + + @MockK + lateinit var submissionQuota: SubmissionQuota + + @MockK + lateinit var exampleConfiguration: ExposureConfiguration + private val exampleKeyFiles = listOf(File("file1"), File("file2")) + private val exampleToken = "123e4567-e89b-12d3-a456-426655440000" + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + coEvery { submissionQuota.consumeQuota(any()) } returns true + + val taskResult = mockk<Task<Void>>() + every { taskResult.addOnSuccessListener(any()) } answers { + val listener = arg<OnSuccessListener<Nothing>>(0) + listener.onSuccess(null) + taskResult + } + every { taskResult.addOnFailureListener(any()) } returns taskResult + coEvery { googleENFClient.provideDiagnosisKeys(any(), any(), any()) } returns taskResult + + coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns true + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + private fun createProvider() = DefaultDiagnosisKeyProvider( + googleAPIVersion = googleAPIVersion, + submissionQuota = submissionQuota, + enfClient = googleENFClient + ) + + @Test + fun `legacy key provision is used on older ENF versions`() { + coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns false + + val provider = createProvider() + + runBlocking { + provider.provideDiagnosisKeys(exampleKeyFiles, exampleConfiguration, exampleToken) + } + + coVerify(exactly = 0) { + googleENFClient.provideDiagnosisKeys( + exampleKeyFiles, exampleConfiguration, exampleToken + ) + } + + coVerify(exactly = 1) { + googleENFClient.provideDiagnosisKeys( + listOf(exampleKeyFiles[0]), exampleConfiguration, exampleToken + ) + googleENFClient.provideDiagnosisKeys( + listOf(exampleKeyFiles[1]), exampleConfiguration, exampleToken + ) + submissionQuota.consumeQuota(2) + } + } + + @Test + fun `normal key provision is used on newer ENF versions`() { + coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns true + + val provider = createProvider() + + runBlocking { + provider.provideDiagnosisKeys(exampleKeyFiles, exampleConfiguration, exampleToken) + } + + coVerify(exactly = 1) { + googleENFClient.provideDiagnosisKeys(any(), any(), any()) + googleENFClient.provideDiagnosisKeys( + exampleKeyFiles, exampleConfiguration, exampleToken + ) + submissionQuota.consumeQuota(1) + } + } + + @Test + fun `passing an a null configuration leads to constructing a fallback from defaults`() { + coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns true + + val provider = createProvider() + val fallback = ExposureConfiguration.ExposureConfigurationBuilder().build() + + runBlocking { + provider.provideDiagnosisKeys(exampleKeyFiles, null, exampleToken) + } + + coVerify(exactly = 1) { + googleENFClient.provideDiagnosisKeys(any(), any(), any()) + googleENFClient.provideDiagnosisKeys(exampleKeyFiles, fallback, exampleToken) + } + } + + @Test + fun `passing an a null configuration leads to constructing a fallback from defaults, legacy`() { + coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns false + + val provider = createProvider() + val fallback = ExposureConfiguration.ExposureConfigurationBuilder().build() + + runBlocking { + provider.provideDiagnosisKeys(exampleKeyFiles, null, exampleToken) + } + + coVerify(exactly = 1) { + googleENFClient.provideDiagnosisKeys( + listOf(exampleKeyFiles[0]), fallback, exampleToken + ) + googleENFClient.provideDiagnosisKeys( + listOf(exampleKeyFiles[1]), fallback, exampleToken + ) + submissionQuota.consumeQuota(2) + } + } + + @Test + fun `quota is consumed silenently`() { + coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns true + coEvery { submissionQuota.consumeQuota(any()) } returns false + + val provider = createProvider() + + runBlocking { + provider.provideDiagnosisKeys(exampleKeyFiles, exampleConfiguration, exampleToken) + } + + coVerify(exactly = 1) { + googleENFClient.provideDiagnosisKeys(any(), any(), any()) + googleENFClient.provideDiagnosisKeys( + exampleKeyFiles, exampleConfiguration, exampleToken + ) + submissionQuota.consumeQuota(1) + } + } + + @Test + fun `quota is consumed silently, legacy`() { + coEvery { googleAPIVersion.isAtLeast(GoogleAPIVersion.V16) } returns false + coEvery { submissionQuota.consumeQuota(any()) } returns false + + val provider = createProvider() + + runBlocking { + provider.provideDiagnosisKeys(exampleKeyFiles, exampleConfiguration, exampleToken) + } + + coVerify(exactly = 0) { + googleENFClient.provideDiagnosisKeys( + exampleKeyFiles, exampleConfiguration, exampleToken + ) + } + + coVerify(exactly = 1) { + googleENFClient.provideDiagnosisKeys( + listOf(exampleKeyFiles[0]), exampleConfiguration, exampleToken + ) + googleENFClient.provideDiagnosisKeys( + listOf(exampleKeyFiles[1]), exampleConfiguration, exampleToken + ) + submissionQuota.consumeQuota(2) + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuotaTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuotaTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..c5d7238a84bd7dea1318173e73841f09ee74bbdc --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/SubmissionQuotaTest.kt @@ -0,0 +1,228 @@ +package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider + +import de.rki.coronawarnapp.nearby.ENFClientLocalData +import de.rki.coronawarnapp.util.TimeStamper +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import kotlinx.coroutines.runBlocking +import org.joda.time.Duration +import org.joda.time.Instant +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class SubmissionQuotaTest : BaseTest() { + @MockK + lateinit var enfData: ENFClientLocalData + + @MockK + lateinit var timeStamper: TimeStamper + + private var testStorageCurrentQuota = SubmissionQuota.DEFAULT_QUOTA + private var testStorageLastQuotaReset = Instant.parse("2020-08-01T01:00:00.000Z") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + every { enfData.currentQuota = any() } answers { + testStorageCurrentQuota = arg(0) + Unit + } + every { enfData.currentQuota } answers { + testStorageCurrentQuota + } + every { enfData.lastQuotaResetAt } answers { + testStorageLastQuotaReset + } + every { enfData.lastQuotaResetAt = any() } answers { + testStorageLastQuotaReset = arg(0) + Unit + } + every { timeStamper.nowUTC } returns Instant.parse("2020-08-01T23:00:00.000Z") + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + private fun createQuota() = SubmissionQuota( + enfData = enfData, + timeStamper = timeStamper + ) + + @Test + fun `first init sets a sane default quota`() { + // The default lastQuotaReset is at 0L EPOCH Millis + testStorageLastQuotaReset = Instant.EPOCH + + val quota = createQuota() + + runBlocking { + quota.consumeQuota(5) shouldBe true + } + + coVerify { enfData.currentQuota = 20 } + + // Reset to 20, then consumed 5 + testStorageCurrentQuota shouldBe 15 + } + + @Test + fun `quota consumption return true if quota was available`() { + testStorageCurrentQuota shouldBe 20 + + val quota = createQuota() + + runBlocking { + quota.consumeQuota(10) shouldBe true + quota.consumeQuota(10) shouldBe true + quota.consumeQuota(10) shouldBe false + quota.consumeQuota(1) shouldBe false + } + + verify(exactly = 4) { timeStamper.nowUTC } + } + + @Test + fun `consumption of 0 quota is handled`() { + val quota = createQuota() + + runBlocking { + quota.consumeQuota(0) shouldBe true + quota.consumeQuota(20) shouldBe true + quota.consumeQuota(0) shouldBe true + quota.consumeQuota(1) shouldBe false + } + } + + @Test + fun `partial consumption is not possible`() { + testStorageCurrentQuota shouldBe 20 + + val quota = createQuota() + + runBlocking { + quota.consumeQuota(18) shouldBe true + quota.consumeQuota(1) shouldBe true + quota.consumeQuota(2) shouldBe false + } + } + + @Test + fun `quota consumption automatically fills up quota if possible`() { + val quota = createQuota() + + // Reset is at 00:00:00UTC, we trigger at 1 milisecond after midnight + val timeTravelTarget = Instant.parse("2020-12-24T00:00:00.001Z") + + runBlocking { + quota.consumeQuota(20) shouldBe true + quota.consumeQuota(20) shouldBe false + + every { timeStamper.nowUTC } returns timeTravelTarget + + quota.consumeQuota(20) shouldBe true + quota.consumeQuota(1) shouldBe false + } + + coVerify(exactly = 1) { enfData.currentQuota = 20 } + verify(exactly = 4) { timeStamper.nowUTC } + verify(exactly = 1) { enfData.lastQuotaResetAt = timeTravelTarget } + } + + @Test + fun `quota fill up is at midnight`() { + testStorageCurrentQuota = 20 + testStorageLastQuotaReset = Instant.parse("2020-12-24T23:00:00.000Z") + val startTime = Instant.parse("2020-12-24T23:59:59.998Z") + every { timeStamper.nowUTC } returns startTime + + val quota = createQuota() + + runBlocking { + quota.consumeQuota(20) shouldBe true + quota.consumeQuota(1) shouldBe false + + every { timeStamper.nowUTC } returns startTime.plus(1) + quota.consumeQuota(1) shouldBe false + + every { timeStamper.nowUTC } returns startTime.plus(2) + quota.consumeQuota(1) shouldBe false + + every { timeStamper.nowUTC } returns startTime.plus(3) + quota.consumeQuota(1) shouldBe true + + every { timeStamper.nowUTC } returns startTime.plus(4) + quota.consumeQuota(20) shouldBe false + + every { timeStamper.nowUTC } returns startTime.plus(3).plus(Duration.standardDays(1)) + quota.consumeQuota(20) shouldBe true + } + } + + @Test + fun `large time gaps are no issue`() { + val startTime = Instant.parse("2020-12-24T20:00:00.000Z") + + runBlocking { + every { timeStamper.nowUTC } returns startTime + val quota = createQuota() + quota.consumeQuota(17) shouldBe true + } + + runBlocking { + every { timeStamper.nowUTC } returns startTime.plus(Duration.standardDays(365)) + val quota = createQuota() + quota.consumeQuota(20) shouldBe true + quota.consumeQuota(1) shouldBe false + } + + runBlocking { + every { timeStamper.nowUTC } returns startTime.plus(Duration.standardDays(365 * 2)) + val quota = createQuota() + quota.consumeQuota(17) shouldBe true + } + runBlocking { + every { timeStamper.nowUTC } returns startTime.plus(Duration.standardDays(365 * 3)) + val quota = createQuota() + quota.consumeQuota(3) shouldBe true + quota.consumeQuota(17) shouldBe true + quota.consumeQuota(1) shouldBe false + } + } + + @Test + fun `reverse timetravel is handled `() { + testStorageLastQuotaReset = Instant.parse("2020-12-24T23:00:00.000Z") + val startTime = Instant.parse("2020-12-24T23:59:59.999Z") + every { timeStamper.nowUTC } returns startTime + + val quota = createQuota() + + runBlocking { + quota.consumeQuota(20) shouldBe true + quota.consumeQuota(1) shouldBe false + + // Go forward and get a reset + every { timeStamper.nowUTC } returns startTime.plus(Duration.standardHours(1)) + quota.consumeQuota(20) shouldBe true + quota.consumeQuota(1) shouldBe false + + // Go backwards and don't gain a reset + every { timeStamper.nowUTC } returns startTime.minus(Duration.standardHours(1)) + quota.consumeQuota(1) shouldBe false + + // Go forward again, but no new reset happens + every { timeStamper.nowUTC } returns startTime.plus(Duration.standardHours(1)) + quota.consumeQuota(1) shouldBe false + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/DefaultRiskScoreAnalysisTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/DefaultRiskScoreAnalysisTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..dd2cac3e9e09e3585da83bddcf86fe3e63d1ae62 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/DefaultRiskScoreAnalysisTest.kt @@ -0,0 +1,22 @@ +package de.rki.coronawarnapp.risk + +import org.junit.Assert +import org.junit.Test + +class DefaultRiskScoreAnalysisTest { + + @Test + fun test_withinDefinedLevelThreshold() { + val instance = DefaultRiskScoreAnalysis() + + // positive + Assert.assertTrue(instance.withinDefinedLevelThreshold(2.0, 1, 3)) + + // negative + Assert.assertFalse(instance.withinDefinedLevelThreshold(4.0, 1, 3)) + + // edge cases + Assert.assertTrue(instance.withinDefinedLevelThreshold(1.0, 1, 3)) + Assert.assertTrue(instance.withinDefinedLevelThreshold(3.0, 1, 3)) + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelCalculationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelCalculationTest.kt index 237f7274f6686ff9285542944a48851f6eb35cb0..b14848e383596cb5214d17c62acd00db6954f725 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelCalculationTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelCalculationTest.kt @@ -10,7 +10,7 @@ class RiskLevelCalculationTest { @Test fun calculateRiskScoreZero() { val riskScore = - RiskLevelCalculation.calculateRiskScore( + DefaultRiskLevelCalculation().calculateRiskScore( buildAttenuationDuration(0.5, 0.5, 1.0), buildSummary(0, 0, 0, 0) ) @@ -21,7 +21,7 @@ class RiskLevelCalculationTest { @Test fun calculateRiskScoreLow() { val riskScore = - RiskLevelCalculation.calculateRiskScore( + DefaultRiskLevelCalculation().calculateRiskScore( buildAttenuationDuration(0.5, 0.5, 1.0), buildSummary(156, 10, 10, 10) ) @@ -32,7 +32,7 @@ class RiskLevelCalculationTest { @Test fun calculateRiskScoreMid() { val riskScore = - RiskLevelCalculation.calculateRiskScore( + DefaultRiskLevelCalculation().calculateRiskScore( buildAttenuationDuration(0.5, 0.5, 1.0), buildSummary(256, 15, 15, 15) ) @@ -43,7 +43,7 @@ class RiskLevelCalculationTest { @Test fun calculateRiskScoreHigh() { val riskScore = - RiskLevelCalculation.calculateRiskScore( + DefaultRiskLevelCalculation().calculateRiskScore( buildAttenuationDuration(0.5, 0.5, 1.0), buildSummary(512, 30, 30, 30) ) @@ -54,7 +54,7 @@ class RiskLevelCalculationTest { @Test fun calculateRiskScoreMax() { val riskScore = - RiskLevelCalculation.calculateRiskScore( + DefaultRiskLevelCalculation().calculateRiskScore( buildAttenuationDuration(0.5, 0.5, 1.0), buildSummary(4096, 30, 30, 30) ) @@ -65,7 +65,7 @@ class RiskLevelCalculationTest { @Test fun calculateRiskScoreCapped() { val riskScore = - RiskLevelCalculation.calculateRiskScore( + DefaultRiskLevelCalculation().calculateRiskScore( buildAttenuationDuration(0.5, 0.5, 1.0), buildSummary(4096, 45, 45, 45) ) diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/TimeVariablesTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/TimeVariablesTest.kt index 0f769204da01f76de88fa25affca553ee5221a6c..4055ddf1fb9875c2d340e257cfb13c91c5843a4b 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/TimeVariablesTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/TimeVariablesTest.kt @@ -1,7 +1,9 @@ package de.rki.coronawarnapp.risk -import de.rki.coronawarnapp.BuildConfig +import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.TimeAndDateExtensions.daysToMilliseconds +import io.mockk.every +import io.mockk.mockkObject import org.junit.Assert import org.junit.Test @@ -14,7 +16,7 @@ class TimeVariablesTest { @Test fun getTransactionTimeout() { - Assert.assertEquals(TimeVariables.getTransactionTimeout(), 60000L) + Assert.assertEquals(TimeVariables.getTransactionTimeout(), 180000L) } @Test @@ -39,11 +41,12 @@ class TimeVariablesTest { @Test fun getManualKeyRetrievalDelay() { - if (BuildConfig.FLAVOR == "deviceForTesters") { - Assert.assertEquals(TimeVariables.getManualKeyRetrievalDelay(), 1000 * 60) - } else { - Assert.assertEquals(TimeVariables.getManualKeyRetrievalDelay(), 1000 * 60 * 60 * 24) - } + mockkObject(CWADebug) + every { CWADebug.buildFlavor } returns CWADebug.BuildFlavor.DEVICE_FOR_TESTERS + Assert.assertEquals(TimeVariables.getManualKeyRetrievalDelay(), 1000 * 60) + + every { CWADebug.buildFlavor } returns CWADebug.BuildFlavor.DEVICE + Assert.assertEquals(TimeVariables.getManualKeyRetrievalDelay(), 1000 * 60 * 60 * 24) } @Test diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyConstantsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyConstantsTest.kt deleted file mode 100644 index a7a85c268817a012eb0d012de8aea2703a1935a5..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/diagnosiskey/DiagnosisKeyConstantsTest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package de.rki.coronawarnapp.service.diagnosiskey - -import org.junit.Assert -import org.junit.Test - -class DiagnosisKeyConstantsTest { - - @Test - fun allDiagnosisKeyConstants() { - Assert.assertEquals(DiagnosisKeyConstants.HOUR, "hour") - Assert.assertEquals(DiagnosisKeyConstants.SERVER_ERROR_CODE_403, 403) - Assert.assertEquals(DiagnosisKeyConstants.INDEX_DOWNLOAD_URL, "version/v1/index.txt") - Assert.assertEquals(DiagnosisKeyConstants.DIAGNOSIS_KEYS_DOWNLOAD_URL, "version/v1/diagnosis-keys") - Assert.assertEquals(DiagnosisKeyConstants.DIAGNOSIS_KEYS_SUBMISSION_URL, "version/v1/diagnosis-keys") - Assert.assertEquals(DiagnosisKeyConstants.PARAMETERS_COUNTRY_DOWNLOAD_URL, "version/v1/parameters/country") - Assert.assertEquals(DiagnosisKeyConstants.APPCONFIG_COUNTRY_DOWNLOAD_URL, "version/v1/configuration/country") - Assert.assertEquals( - DiagnosisKeyConstants.COUNTRY_APPCONFIG_DOWNLOAD_URL, - "version/v1/configuration/country/DE/app_config" - ) - Assert.assertEquals(DiagnosisKeyConstants.AVAILABLE_DATES_URL, "version/v1/diagnosis-keys/country/DE/date") - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..ee4cd09b339d00404b05056550bb3403939be060 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt @@ -0,0 +1,53 @@ +package de.rki.coronawarnapp.service.submission + +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockkObject +import org.junit.Before +import org.junit.Test + +class ScanResultTest { + private val guid = "123456-12345678-1234-4DA7-B166-B86D85475064" + + @MockK + private lateinit var scanResult: QRScanResult + + @Before + fun setUp() { + MockKAnnotations.init(this) + mockkObject(scanResult) + every { scanResult.isValid } returns false + } + + @Test + fun containsValidGUID() { + // valid test + scanResult = QRScanResult("https://localhost/?$guid") + scanResult.isValid shouldBe true + + // more invalid tests checks + scanResult = QRScanResult("http://localhost/?$guid") + scanResult.isValid shouldBe false + scanResult = QRScanResult("https://localhost/?") + scanResult.isValid shouldBe false + scanResult = QRScanResult("htps://wrongformat.com") + scanResult.isValid shouldBe false + scanResult = + QRScanResult("https://localhost/%20?3D6D08-3567F3F2-4DCF-43A3-8737-4CD1F87D6FDA") + scanResult.isValid shouldBe false + scanResult = + QRScanResult("https://some-host.com/?3D6D08-3567F3F2-4DCF-43A3-8737-4CD1F87D6FDA") + scanResult.isValid shouldBe false + scanResult = QRScanResult("https://localhost/?3567F3F2-4DCF-43A3-8737-4CD1F87D6FDA") + scanResult.isValid shouldBe false + scanResult = QRScanResult("https://localhost/?4CD1F87D6FDA") + scanResult.isValid shouldBe false + } + + @Test + fun extractGUID() { + QRScanResult("https://localhost/?$guid").guid shouldBe guid + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionConstantsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionConstantsTest.kt index 98efa5fec86386ae2035ec6699f6a62b743e42b0..5b070bfb4607c79ee19e4c294493c9043ac02fd3 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionConstantsTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionConstantsTest.kt @@ -7,24 +7,8 @@ class SubmissionConstantsTest { @Test fun allSubmissionConstants() { - // TODO: Should we really keep these now? - Assert.assertEquals(KeyType.GUID.name, "GUID") - Assert.assertEquals(KeyType.TELETAN.name, "TELETAN") - - Assert.assertEquals(SubmissionConstants.REGISTRATION_TOKEN_URL, "version/v1/registrationToken") - Assert.assertEquals(SubmissionConstants.TEST_RESULT_URL, "version/v1/testresult") - Assert.assertEquals(SubmissionConstants.TAN_REQUEST_URL, "version/v1/tan") - - Assert.assertEquals(SubmissionConstants.MAX_QR_CODE_LENGTH, 150) - Assert.assertEquals(SubmissionConstants.MAX_GUID_LENGTH, 80) - Assert.assertEquals(SubmissionConstants.GUID_SEPARATOR, '?') - - Assert.assertEquals(SubmissionConstants.SERVER_ERROR_CODE_400, 400) - - // dummy token passes server verification - Assert.assertTrue( - Regex("^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}\$") - .matches(SubmissionConstants.DUMMY_REGISTRATION_TOKEN) - ) + Assert.assertEquals(QRScanResult.MAX_QR_CODE_LENGTH, 150) + Assert.assertEquals(QRScanResult.MAX_GUID_LENGTH, 80) + Assert.assertEquals(QRScanResult.GUID_SEPARATOR, '?') } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt index 9d1f958c6895c1dcac2e4984294c9e00e769e83a..f5084219d09a5c1c661af6962dce58a69e44ea8a 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt @@ -2,13 +2,21 @@ package de.rki.coronawarnapp.service.submission import de.rki.coronawarnapp.exception.NoGUIDOrTANSetException import de.rki.coronawarnapp.exception.NoRegistrationTokenSetException -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.http.playbook.BackgroundNoise +import de.rki.coronawarnapp.playbook.BackgroundNoise +import de.rki.coronawarnapp.playbook.Playbook import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.submission.Symptoms import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction +import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.di.ApplicationComponent import de.rki.coronawarnapp.util.formatter.TestResult +import de.rki.coronawarnapp.verification.server.VerificationKeyType +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.Runs +import io.mockk.clearAllMocks import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK @@ -16,26 +24,30 @@ import io.mockk.just import io.mockk.mockkObject import io.mockk.verify import kotlinx.coroutines.runBlocking -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Before -import org.junit.Test +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test class SubmissionServiceTest { + private val guid = "123456-12345678-1234-4DA7-B166-B86D85475064" private val registrationToken = "asdjnskjfdniuewbheboqudnsojdff" + private val testResult = TestResult.PENDING - @MockK - private lateinit var webRequestBuilder: WebRequestBuilder + @MockK lateinit var backgroundNoise: BackgroundNoise + @MockK lateinit var mockPlaybook: Playbook + @MockK lateinit var appComponent: ApplicationComponent - @MockK - private lateinit var backgroundNoise: BackgroundNoise + private val symptoms = Symptoms(Symptoms.StartOf.OneToTwoWeeksAgo, Symptoms.Indication.POSITIVE) - @Before + @BeforeEach fun setUp() { MockKAnnotations.init(this) - mockkObject(WebRequestBuilder.Companion) - every { WebRequestBuilder.getInstance() } returns webRequestBuilder + + mockkObject(AppInjector) + every { AppInjector.component } returns appComponent + + every { appComponent.playbook } returns mockPlaybook mockkObject(BackgroundNoise.Companion) every { BackgroundNoise.getInstance() } returns backgroundNoise @@ -43,14 +55,22 @@ class SubmissionServiceTest { mockkObject(SubmitDiagnosisKeysTransaction) mockkObject(LocalData) + mockkObject(SubmissionRepository) + every { SubmissionRepository.updateTestResult(any()) } just Runs + every { LocalData.teletan() } returns null every { LocalData.testGUID() } returns null every { LocalData.registrationToken() } returns null } - @Test(expected = NoGUIDOrTANSetException::class) - fun registerDeviceWithoutTANOrGUIDFails() { - runBlocking { + @AfterEach + fun cleanUp() { + clearAllMocks() + } + + @Test + fun registerDeviceWithoutTANOrGUIDFails(): Unit = runBlocking { + shouldThrow<NoGUIDOrTANSetException> { SubmissionService.asyncRegisterDevice() } } @@ -64,8 +84,10 @@ class SubmissionServiceTest { every { LocalData.devicePairingSuccessfulTimestamp(any()) } just Runs coEvery { - webRequestBuilder.asyncGetRegistrationToken(any(), KeyType.GUID) - } returns registrationToken + mockPlaybook.initialRegistration(any(), VerificationKeyType.GUID) + } returns (registrationToken to TestResult.PENDING) + coEvery { mockPlaybook.testResult(registrationToken) } returns testResult + every { backgroundNoise.scheduleDummyPattern() } just Runs runBlocking { @@ -77,6 +99,7 @@ class SubmissionServiceTest { LocalData.devicePairingSuccessfulTimestamp(any()) LocalData.testGUID(null) backgroundNoise.scheduleDummyPattern() + SubmissionRepository.updateTestResult(testResult) } } @@ -89,8 +112,10 @@ class SubmissionServiceTest { every { LocalData.devicePairingSuccessfulTimestamp(any()) } just Runs coEvery { - webRequestBuilder.asyncGetRegistrationToken(any(), KeyType.TELETAN) - } returns registrationToken + mockPlaybook.initialRegistration(any(), VerificationKeyType.TELETAN) + } returns (registrationToken to TestResult.PENDING) + coEvery { mockPlaybook.testResult(registrationToken) } returns testResult + every { backgroundNoise.scheduleDummyPattern() } just Runs runBlocking { @@ -102,12 +127,13 @@ class SubmissionServiceTest { LocalData.devicePairingSuccessfulTimestamp(any()) LocalData.teletan(null) backgroundNoise.scheduleDummyPattern() + SubmissionRepository.updateTestResult(testResult) } } - @Test(expected = NoRegistrationTokenSetException::class) - fun requestTestResultWithoutRegistrationTokenFails() { - runBlocking { + @Test + fun requestTestResultWithoutRegistrationTokenFails(): Unit = runBlocking { + shouldThrow<NoRegistrationTokenSetException> { SubmissionService.asyncRequestTestResult() } } @@ -115,27 +141,33 @@ class SubmissionServiceTest { @Test fun requestTestResultSucceeds() { every { LocalData.registrationToken() } returns registrationToken - coEvery { webRequestBuilder.asyncGetTestResult(registrationToken) } returns TestResult.NEGATIVE.value + coEvery { mockPlaybook.testResult(registrationToken) } returns TestResult.NEGATIVE runBlocking { - assertThat(SubmissionService.asyncRequestTestResult(), equalTo(TestResult.NEGATIVE)) + SubmissionService.asyncRequestTestResult() shouldBe TestResult.NEGATIVE } } - @Test(expected = NoRegistrationTokenSetException::class) - fun submitExposureKeysWithoutRegistrationTokenFails() { - runBlocking { - SubmissionService.asyncSubmitExposureKeys(listOf()) + @Test + fun submitExposureKeysWithoutRegistrationTokenFails(): Unit = runBlocking { + shouldThrow<NoRegistrationTokenSetException> { + SubmissionService.asyncSubmitExposureKeys(listOf(), symptoms) } } @Test fun submitExposureKeysSucceeds() { every { LocalData.registrationToken() } returns registrationToken - coEvery { SubmitDiagnosisKeysTransaction.start(registrationToken, any()) } just Runs + coEvery { + SubmitDiagnosisKeysTransaction.start( + registrationToken, + any(), + symptoms + ) + } just Runs runBlocking { - SubmissionService.asyncSubmitExposureKeys(listOf()) + SubmissionService.asyncSubmitExposureKeys(listOf(), symptoms) } } @@ -151,27 +183,4 @@ class SubmissionServiceTest { LocalData.devicePairingSuccessfulTimestamp(0L) } } - - @Test - fun containsValidGUID() { - // valid - assertThat( - SubmissionService.containsValidGUID("https://bs-sd.de/covid-19/?$guid"), - equalTo(true) - ) - - // invalid - assertThat( - SubmissionService.containsValidGUID("https://no-guid-here"), - equalTo(false) - ) - } - - @Test - fun extractGUID() { - assertThat( - SubmissionService.extractGUID("https://bs-sd.de/covid-19/?$guid"), - equalTo(guid) - ) - } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/DeviceStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/DeviceStorageTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..2b26304d3fe1abf473c6f11e84b4e591e70b55fe --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/DeviceStorageTest.kt @@ -0,0 +1,220 @@ +package de.rki.coronawarnapp.storage + +import android.app.usage.StorageStatsManager +import android.content.Context +import android.os.Build +import android.os.StatFs +import android.os.storage.StorageManager +import de.rki.coronawarnapp.util.ApiLevel +import de.rki.coronawarnapp.util.storage.StatsFsProvider +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File +import java.io.IOException +import java.util.UUID + +class DeviceStorageTest : BaseIOTest() { + + @MockK + lateinit var context: Context + + private val defaultApiLevel = ApiLevel(Build.VERSION_CODES.O) + private val legacyApiLevel = ApiLevel(Build.VERSION_CODES.M) + + @MockK + lateinit var storageManager: StorageManager + + @MockK + lateinit var storageStatsManager: StorageStatsManager + + @MockK + lateinit var statsFsProvider: StatsFsProvider + + private val privateDataDir = File(IO_TEST_BASEDIR, "privData") + private val privateDataDirUUID = UUID.randomUUID() + + private val defaultAllocatableBytes = 512L + private val defaultFreeSpace = 1000 * 1024L + private val defaultTotalSpace = Long.MAX_VALUE + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + every { context.filesDir } returns privateDataDir + every { context.getSystemService(Context.STORAGE_SERVICE) } returns storageManager + every { context.getSystemService(Context.STORAGE_STATS_SERVICE) } returns storageStatsManager + + every { storageManager.getUuidForPath(privateDataDir) } returns privateDataDirUUID + every { storageManager.getAllocatableBytes(privateDataDirUUID) } returns defaultAllocatableBytes + every { storageManager.allocateBytes(any<UUID>(), any()) } returns Unit + + every { storageStatsManager.getFreeBytes(any()) } returns defaultFreeSpace + every { storageStatsManager.getTotalBytes(any()) } returns defaultTotalSpace + + every { statsFsProvider.createStats(privateDataDir) } returns mockk<StatFs>().apply { + every { availableBytes } returns defaultFreeSpace + every { totalBytes } returns defaultTotalSpace + } + } + + @AfterEach + fun teardown() { + clearAllMocks() + + privateDataDir.deleteRecursively() + } + + private fun buildInstance(level: ApiLevel = defaultApiLevel): DeviceStorage = DeviceStorage( + context = context, + apiLevel = level, + statsFsProvider = statsFsProvider + ) + + @Test + fun `check private storage space`() { + val deviceStorage = buildInstance() + runBlocking { + deviceStorage.checkSpacePrivateStorage() shouldBe DeviceStorage.CheckResult( + path = privateDataDir, + isSpaceAvailable = true, + freeBytes = defaultFreeSpace, + totalBytes = defaultTotalSpace + ) + } + verify { storageManager.getUuidForPath(any()) } + verify(exactly = 0) { statsFsProvider.createStats(any()) } + + verify(exactly = 0) { storageManager.allocateBytes(any<UUID>(), any()) } + } + + @Test + fun `check private storage space, sub API26`() { + val deviceStorage = buildInstance(level = legacyApiLevel) + runBlocking { + deviceStorage.checkSpacePrivateStorage() shouldBe DeviceStorage.CheckResult( + path = privateDataDir, + isSpaceAvailable = true, + freeBytes = defaultFreeSpace, + totalBytes = defaultTotalSpace + ) + } + verify(exactly = 0) { storageManager.getUuidForPath(any()) } + verify { statsFsProvider.createStats(any()) } + } + + @Test + fun `request space from private storage successfully`() { + val deviceStorage = buildInstance() + runBlocking { + deviceStorage.checkSpacePrivateStorage(requiredBytes = defaultFreeSpace) shouldBe DeviceStorage.CheckResult( + path = privateDataDir, + isSpaceAvailable = true, + requiredBytes = defaultFreeSpace, + freeBytes = defaultFreeSpace, + totalBytes = defaultTotalSpace + ) + } + verify(exactly = 0) { storageManager.allocateBytes(any<UUID>(), any()) } + } + + @Test + fun `request space from private storage successfully, sub API26`() { + val deviceStorage = buildInstance(level = legacyApiLevel) + runBlocking { + deviceStorage.checkSpacePrivateStorage(requiredBytes = defaultFreeSpace) shouldBe DeviceStorage.CheckResult( + path = privateDataDir, + isSpaceAvailable = true, + requiredBytes = defaultFreeSpace, + freeBytes = defaultFreeSpace, + totalBytes = defaultTotalSpace + ) + } + } + + @Test + fun `request space from private storage wth allocation`() { + val deviceStorage = buildInstance() + runBlocking { + val targetBytes = defaultFreeSpace + defaultAllocatableBytes + deviceStorage.checkSpacePrivateStorage(requiredBytes = targetBytes) shouldBe DeviceStorage.CheckResult( + path = privateDataDir, + isSpaceAvailable = true, + requiredBytes = targetBytes, + freeBytes = targetBytes, + totalBytes = defaultTotalSpace + ) + } + + verify { storageManager.allocateBytes(privateDataDirUUID, defaultAllocatableBytes) } + } + + @Test + fun `request space from private storage unsuccessfully`() { + val deviceStorage = buildInstance() + runBlocking { + deviceStorage.checkSpacePrivateStorage(requiredBytes = Long.MAX_VALUE) shouldBe DeviceStorage.CheckResult( + path = privateDataDir, + isSpaceAvailable = false, + freeBytes = defaultFreeSpace, + requiredBytes = Long.MAX_VALUE, + totalBytes = defaultTotalSpace + ) + shouldThrow<InsufficientStorageException> { + deviceStorage.requireSpacePrivateStorage(Long.MAX_VALUE) + } + } + } + + @Test + fun `request space from private storage unsuccessfully, sub API26`() { + val deviceStorage = buildInstance(level = legacyApiLevel) + runBlocking { + deviceStorage.checkSpacePrivateStorage(requiredBytes = Long.MAX_VALUE) shouldBe DeviceStorage.CheckResult( + path = privateDataDir, + isSpaceAvailable = false, + requiredBytes = Long.MAX_VALUE, + freeBytes = defaultFreeSpace, + totalBytes = defaultTotalSpace + ) + } + } + + @Test + fun `check private storage space, fallback in error case`() { + every { storageManager.getUuidForPath(privateDataDir) } throws IOException("uh oh") + + val deviceStorage = buildInstance() + runBlocking { + deviceStorage.checkSpacePrivateStorage() shouldBe DeviceStorage.CheckResult( + path = privateDataDir, + isSpaceAvailable = true, + freeBytes = defaultFreeSpace, + totalBytes = defaultTotalSpace + ) + } + + verify { statsFsProvider.createStats(privateDataDir) } + } + + @Test + fun `check private storage space, sub API26, error case has no fallback`() { + every { statsFsProvider.createStats(privateDataDir) } throws IOException("uh oh") + + val deviceStorage = buildInstance(level = legacyApiLevel) + runBlocking { + shouldThrow<IOException> { deviceStorage.checkSpacePrivateStorage() } + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/FileStorageConstantsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/FileStorageConstantsTest.kt deleted file mode 100644 index a9d311996024332510d8f2d819c0957c82e66a7d..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/FileStorageConstantsTest.kt +++ /dev/null @@ -1,14 +0,0 @@ -package de.rki.coronawarnapp.storage - -import org.junit.Assert -import org.junit.Test - -class FileStorageConstantsTest { - - @Test - fun allFileStorageConstants() { - Assert.assertEquals(FileStorageConstants.DAYS_TO_KEEP, 14) - Assert.assertEquals(FileStorageConstants.FREE_SPACE_THRESHOLD, 15) - Assert.assertEquals(FileStorageConstants.KEY_EXPORT_DIRECTORY_NAME, "key-export") - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/keycache/KeyCacheRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/keycache/KeyCacheRepositoryTest.kt deleted file mode 100644 index ea58f3a5f155af7b85c67342e2298870fabae25f..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/keycache/KeyCacheRepositoryTest.kt +++ /dev/null @@ -1,88 +0,0 @@ -package de.rki.coronawarnapp.storage.keycache - -import io.mockk.MockKAnnotations -import io.mockk.Runs -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.coVerifyOrder -import io.mockk.impl.annotations.MockK -import io.mockk.just -import io.mockk.unmockkAll -import kotlinx.coroutines.runBlocking -import org.junit.After -import org.junit.Before -import org.junit.Test -import java.net.URI - -/** - * KeyCacheRepository test. - */ -class KeyCacheRepositoryTest { - - @MockK - private lateinit var keyCacheDao: KeyCacheDao - - private lateinit var keyCacheRepository: KeyCacheRepository - - @Before - fun setUp() { - MockKAnnotations.init(this) - keyCacheRepository = KeyCacheRepository(keyCacheDao) - - // DAO tests in another test - coEvery { keyCacheDao.getAllEntries() } returns listOf() - coEvery { keyCacheDao.getHours() } returns listOf() - coEvery { keyCacheDao.clear() } just Runs - coEvery { keyCacheDao.clearHours() } just Runs - coEvery { keyCacheDao.insertEntry(any()) } returns 0 - } - - /** - * Test clear order. - */ - @Test - fun testClear() { - runBlocking { - keyCacheRepository.clear() - - coVerifyOrder { - keyCacheDao.getAllEntries() - - keyCacheDao.clear() - } - } - - runBlocking { - keyCacheRepository.clearHours() - - coVerifyOrder { - keyCacheDao.getHours() - - keyCacheDao.clearHours() - } - } - } - - /** - * Test insert order. - */ - @Test - fun testInsert() { - runBlocking { - keyCacheRepository.createEntry( - key = "1", - type = KeyCacheRepository.DateEntryType.DAY, - uri = URI("1") - ) - - coVerify { - keyCacheDao.insertEntry(any()) - } - } - } - - @After - fun cleanUp() { - unmockkAll() - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVectorDeterminatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVectorDeterminatorTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..6b54adde308412e8353b44be328057cf2a27ca77 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/DaysSinceOnsetOfSymptomsVectorDeterminatorTest.kt @@ -0,0 +1,134 @@ +package de.rki.coronawarnapp.submission + +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDate +import de.rki.coronawarnapp.util.TimeStamper +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.joda.time.DateTime +import org.joda.time.DateTimeZone +import org.joda.time.Instant +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class DaysSinceOnsetOfSymptomsVectorDeterminatorTest { + + private lateinit var thisMorning: DateTime + + @MockK + private lateinit var timeStamper: TimeStamper + + @BeforeEach + fun setUp() { + MockKAnnotations.init(this) + thisMorning = DateTime(2012, 10, 15, 10, 0, DateTimeZone.UTC) + every { timeStamper.nowUTC } returns thisMorning.toInstant() + } + + @Test + fun `match a positive symptom indication to the exact date of yesterday`() { + val daysAgo = 1 + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + createDate(thisMorning.millis - 1000 * 3600 * (24 * daysAgo)), + Symptoms.Indication.POSITIVE + ) + ) shouldBe intArrayOf(1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13) + } + + @Test + fun `match a positive symptom indication to the exact date of today`() { + val daysAgo = 0 + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + createDate(thisMorning.millis - 1000 * 3600 * (24 * daysAgo)), + Symptoms.Indication.POSITIVE + ) + ) shouldBe intArrayOf(0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14) + } + + @Test + fun `match a positive symptom indication to the exact date 5 days ago`() { + val daysAgo = 5 + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + createDate(thisMorning.millis - 1000 * 3600 * (24 * daysAgo)), + Symptoms.Indication.POSITIVE + ) + ) shouldBe intArrayOf(5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9) + } + + @Test + fun `match a positive symptom indication to the exact date 21 days ago`() { + val daysAgo = 21 + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + createDate(thisMorning.millis - 1000 * 3600 * (24 * daysAgo)), + Symptoms.Indication.POSITIVE + ) + ) shouldBe intArrayOf(21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7) + } + + @Test + fun `match a positive symptom indication to a range within the last 7 days`() { + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + Symptoms.StartOf.LastSevenDays, + Symptoms.Indication.POSITIVE + ) + ) shouldBe intArrayOf(701, 700, 699, 698, 697, 696, 695, 694, 693, 692, 691, 690, 689, 688, 687) + } + + @Test + fun `match a positive symptom indication to a range within the last two weeks`() { + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + Symptoms.StartOf.OneToTwoWeeksAgo, + Symptoms.Indication.POSITIVE + ) + ) shouldBe intArrayOf(708, 707, 706, 705, 704, 703, 702, 701, 700, 699, 698, 697, 696, 695, 694) + } + + @Test + fun `match a positive symptom indication to a range more than two weeks ago`() { + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + Symptoms.StartOf.MoreThanTwoWeeks, + Symptoms.Indication.POSITIVE + ) + ) shouldBe intArrayOf(715, 714, 713, 712, 711, 710, 709, 708, 707, 706, 705, 704, 703, 702, 701) + } + + @Test + fun `match a positive symptom indication with other or no detailed information`() { + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + Symptoms.StartOf.NoInformation, + Symptoms.Indication.POSITIVE + ) + ) shouldBe intArrayOf(2000, 1999, 1998, 1997, 1996, 1995, 1994, 1993, 1992, 1991, 1990, 1989, 1988, 1987, 1986) + } + + @Test + fun `match no information about symptoms`() { + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + null, + Symptoms.Indication.NO_INFORMATION + ) + ) shouldBe intArrayOf(4000, 3999, 3998, 3997, 3996, 3995, 3994, 3993, 3992, 3991, 3990, 3989, 3988, 3987, 3986) + } + + @Test + fun `match no symptoms`() { + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper).determine( + Symptoms( + null, + Symptoms.Indication.NEGATIVE + ) + ) shouldBe intArrayOf(3000, 2999, 2998, 2997, 2996, 2995, 2994, 2993, 2992, 2991, 2990, 2989, 2988, 2987, 2986) + } + + private fun createDate(millis: Long) = Symptoms.StartOf.Date(Instant.ofEpochMilli(millis).toLocalDate()) +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculationsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculationsTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..e07d347de7c9e1d08d189aabebfddccdd2c8043d --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/ExposureKeyHistoryCalculationsTest.kt @@ -0,0 +1,193 @@ +package de.rki.coronawarnapp.submission + +import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey +import de.rki.coronawarnapp.server.protocols.KeyExportFormat +import de.rki.coronawarnapp.util.TimeStamper +import org.joda.time.DateTime +import org.joda.time.DateTimeZone +import org.junit.Assert +import org.junit.Before +import org.junit.Test + +class ExposureKeyHistoryCalculationsTest { + + private lateinit var instance: ExposureKeyHistoryCalculations + private lateinit var converter: KeyConverter + private lateinit var todayMidnight: DateTime + private lateinit var thisMorning: DateTime + private lateinit var thisEvening: DateTime + + private var timeStamper = TimeStamper() + + @Before + fun setUp() { + todayMidnight = DateTime(2012, 10, 15, 0, 0, DateTimeZone.UTC) + thisMorning = DateTime(2012, 10, 15, 10, 0, DateTimeZone.UTC) + thisEvening = DateTime(2012, 10, 15, 20, 0, DateTimeZone.UTC) + + converter = object : KeyConverter { + override fun toExternalFormat( + key: TemporaryExposureKey, + riskValue: Int, + daysSinceOnsetOfSymptoms: Int + ) = + KeyExportFormat.TemporaryExposureKey.newBuilder() + .setRollingStartIntervalNumber(key.rollingStartIntervalNumber) + .setTransmissionRiskLevel(riskValue) + .setDaysSinceOnsetOfSymptoms(daysSinceOnsetOfSymptoms) + .build() + } + + instance = ExposureKeyHistoryCalculations( + TransmissionRiskVectorDeterminator(timeStamper), + DaysSinceOnsetOfSymptomsVectorDeterminator(timeStamper), + converter, + timeStamper + ) + } + + @Test + fun test_limitKeyCount() { + val tek1 = createKey(thisMorning) + val tek2 = createKey(thisMorning.minusDays(14)) + val tek3 = createKey(thisMorning.minusDays(15)) + Assert.assertArrayEquals( + arrayOf(tek1.rollingStartIntervalNumber, tek2.rollingStartIntervalNumber), + instance.removeOldKeys( + listOf( + tek1, + tek2, + tek3 + ), + thisMorning.toLocalDate() + ).map { it.rollingStartIntervalNumber }.toTypedArray() + ) + } + + @Test + fun test_toSortedHistory() { + Assert.assertArrayEquals( + intArrayOf(8, 4, 3, 2, 1), instance.sortWithRecentKeyFirst( + listOf( + createKey(3), + createKey(8), + createKey(1), + createKey(2), + createKey(4) + ) + ).map { it.rollingStartIntervalNumber }.toTypedArray().toIntArray() + ) + } + + @Test + fun test_toExternalFormat() { + // regular case + var tek1 = createKey(thisMorning) + var tek2 = createKey(thisMorning.minusDays(1)) + var result = instance.toExternalFormat( + listOf(tek1, tek2), + TransmissionRiskVector(intArrayOf(0, 1, 2)), + intArrayOf(3998, 3999, 4000), + thisMorning.toLocalDate() + ) + f( + result, + intArrayOf(tek1.rollingStartIntervalNumber, tek2.rollingStartIntervalNumber), + intArrayOf(3998, 3999), + intArrayOf(0, 1) + ) + + // gap + tek1 = createKey(thisEvening) + tek2 = createKey(thisEvening.minusDays(7)) + result = instance.toExternalFormat( + listOf(tek1, tek2), + TransmissionRiskVector(intArrayOf(0, 1, 2, 3, 4, 5, 6, 7)), + intArrayOf(3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005), + thisMorning.toLocalDate() + ) + f( + result, + intArrayOf(tek1.rollingStartIntervalNumber, tek2.rollingStartIntervalNumber), + intArrayOf(3998, 4005), + intArrayOf(0, 7) + ) + + // several keys in one day + tek1 = createKey(todayMidnight) + tek2 = createKey(todayMidnight) + result = instance.toExternalFormat( + listOf(tek1, tek2), + TransmissionRiskVector(intArrayOf(0, 1, 2, 3, 4, 5, 6, 7)), + intArrayOf(3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005), + thisMorning.toLocalDate() + ) + f( + result, + intArrayOf(tek1.rollingStartIntervalNumber, tek1.rollingStartIntervalNumber), + intArrayOf(3998, 3998), + intArrayOf(0, 0) + ) + + // submitting later that day + tek1 = createKey(thisMorning) + tek2 = createKey(thisEvening.minusDays(1)) + result = instance.toExternalFormat( + listOf(tek1, tek2), + TransmissionRiskVector(intArrayOf(0, 1, 2)), + intArrayOf(3998, 3999, 4000), + thisEvening.toLocalDate() + ) + f( + result, + intArrayOf(tek1.rollingStartIntervalNumber, tek2.rollingStartIntervalNumber), + intArrayOf(3998, 3999), + intArrayOf(0, 1) + ) + + // several keys yesterday + tek1 = createKey(thisMorning.minusDays(1)) + tek2 = createKey(thisEvening.minusDays(1)) + val tek3 = createKey(thisMorning) + result = instance.toExternalFormat( + listOf(tek3, tek2, tek1), + TransmissionRiskVector(intArrayOf(0, 1, 2, 3, 4, 5, 6, 7)), + intArrayOf(3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005), + thisMorning.toLocalDate() + ) + f( + result, intArrayOf( + tek3.rollingStartIntervalNumber, + tek2.rollingStartIntervalNumber, + tek1.rollingStartIntervalNumber + ), intArrayOf(3998, 3999, 3999), intArrayOf(0, 1, 1) + ) + } + + private fun f( + result: List<KeyExportFormat.TemporaryExposureKey>, + intArrayOf: IntArray, + intArrayOf1: IntArray, + intArrayOf2: IntArray + ) { + Assert.assertArrayEquals( + intArrayOf, + result.map { it.rollingStartIntervalNumber }.toTypedArray().toIntArray() + ) + Assert.assertArrayEquals( + intArrayOf1, + result.map { it.daysSinceOnsetOfSymptoms }.toTypedArray().toIntArray() + ) + Assert.assertArrayEquals( + intArrayOf2, + result.map { it.transmissionRiskLevel }.toTypedArray().toIntArray() + ) + } + + private fun createKey(rollingStartIntervalNumber: Int) = + TemporaryExposureKey.TemporaryExposureKeyBuilder() + .setRollingStartIntervalNumber(rollingStartIntervalNumber).build() + + private fun createKey(dateTime: DateTime) = + createKey((dateTime.millis / ExposureKeyHistoryCalculations.TEN_MINUTES_IN_MILLIS).toInt()) +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionModuleTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionModuleTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..ba8b4b91b1e824534587068ed8408cca176f9a64 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/SubmissionModuleTest.kt @@ -0,0 +1,85 @@ +package de.rki.coronawarnapp.submission + +import android.content.Context +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import okhttp3.ConnectionSpec +import okhttp3.OkHttpClient +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.converter.protobuf.ProtoConverterFactory +import testhelpers.BaseIOTest +import java.io.File + +class SubmissionModuleTest : BaseIOTest() { + + @MockK lateinit var context: Context + + private val testDir = File(IO_TEST_BASEDIR, this::class.java.simpleName) + private val cacheFiles = File(testDir, "cache") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { context.cacheDir } returns cacheFiles + + testDir.mkdirs() + testDir.exists() shouldBe true + } + + @AfterEach + fun teardown() { + clearAllMocks() + testDir.deleteRecursively() + } + + private fun createModule() = SubmissionModule() + + @Test + fun `side effect free instantiation`() { + shouldNotThrowAny { + createModule() + } + } + + @Test + fun `client creation uses connection specs`() { + val module = createModule() + + val specs = listOf(ConnectionSpec.MODERN_TLS) + val client = OkHttpClient.Builder().build() + + val newClient = module.cdnHttpClient( + defaultHttpClient = client, + connectionSpecs = specs + ) + + newClient.apply { + connectionSpecs shouldBe specs + } + } + + @Test + fun `api uses a cache`() { + val module = createModule() + + val client = OkHttpClient.Builder().build() + + module.provideSubmissionApi( + context = context, + client = client, + url = "https://testurl", + gsonConverterFactory = GsonConverterFactory.create(), + protoConverterFactory = ProtoConverterFactory.create() + ) + + verify { context.cacheDir } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminatorTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..4bdb52acae9969644b3ab7704c2bd7d0ac3861d3 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/TransmissionRiskVectorDeterminatorTest.kt @@ -0,0 +1,113 @@ +package de.rki.coronawarnapp.submission + +import de.rki.coronawarnapp.util.TimeStamper +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.joda.time.DateTime +import org.joda.time.DateTimeZone +import org.joda.time.LocalDate +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class TransmissionRiskVectorDeterminatorTest { + + private lateinit var thisMorning: DateTime + + @MockK + private lateinit var timeStamper: TimeStamper + + @BeforeEach + fun setUp() { + MockKAnnotations.init(this) + thisMorning = DateTime(2012, 10, 15, 10, 0, DateTimeZone.UTC) + every { timeStamper.nowUTC } returns thisMorning.toInstant() + } + + @Test + fun test_determine() { + // positive - exact days + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + createSpecificStart(thisMorning.toLocalDate()), + Symptoms.Indication.POSITIVE + ), + thisMorning.toLocalDate() + ).raw shouldBe intArrayOf(8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1) + + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + createSpecificStart(thisMorning.minusDays(1).toLocalDate()), + Symptoms.Indication.POSITIVE + ), + thisMorning.toLocalDate() + ).raw shouldBe intArrayOf(8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1) + + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + createSpecificStart(thisMorning.minusDays(5).toLocalDate()), + Symptoms.Indication.POSITIVE + ), + thisMorning.toLocalDate() + ).raw shouldBe intArrayOf(2, 3, 5, 6, 8, 8, 8, 7, 6, 4, 2, 1, 1, 1, 1) + + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + createSpecificStart(thisMorning.minusDays(21).toLocalDate()), + Symptoms.Indication.POSITIVE + ), + thisMorning.toLocalDate() + ).raw shouldBe intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) + + // positive - LastSevenDays + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + Symptoms.StartOf.LastSevenDays, + Symptoms.Indication.POSITIVE + ) + ).raw shouldBe intArrayOf(4, 5, 6, 7, 7, 7, 6, 5, 4, 3, 2, 1, 1, 1, 1) + + // positive - OneToTwoWeeksAgo + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + Symptoms.StartOf.OneToTwoWeeksAgo, + Symptoms.Indication.POSITIVE + ) + ).raw shouldBe intArrayOf(1, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 6, 6, 4) + + // positive - MoreThanTwoWeeks + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + Symptoms.StartOf.MoreThanTwoWeeks, + Symptoms.Indication.POSITIVE + ) + ).raw shouldBe intArrayOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5) + + // positive - no info + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + Symptoms.StartOf.NoInformation, + Symptoms.Indication.POSITIVE + ) + ).raw shouldBe intArrayOf(5, 6, 8, 8, 8, 7, 5, 3, 2, 1, 1, 1, 1, 1, 1) + + // negative + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + null, + Symptoms.Indication.NEGATIVE + ) + ).raw shouldBe intArrayOf(4, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) + + // no info + TransmissionRiskVectorDeterminator(timeStamper).determine( + Symptoms( + null, Symptoms.Indication.NO_INFORMATION + ) + ).raw shouldBe intArrayOf(5, 6, 7, 7, 7, 6, 4, 3, 2, 1, 1, 1, 1, 1, 1) + } + + private fun createSpecificStart(localDate: LocalDate): Symptoms.StartOf.Date = + Symptoms.StartOf.Date(localDate) +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/server/SubmissionApiV1Test.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/server/SubmissionApiV1Test.kt new file mode 100644 index 0000000000000000000000000000000000000000..68ac0a71049438798b0f02de956605b2e72d2ac2 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/server/SubmissionApiV1Test.kt @@ -0,0 +1,103 @@ +package de.rki.coronawarnapp.submission.server + +import android.content.Context +import com.google.protobuf.ByteString +import de.rki.coronawarnapp.http.HttpModule +import de.rki.coronawarnapp.server.protocols.KeyExportFormat +import de.rki.coronawarnapp.submission.SubmissionModule +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.runBlocking +import okhttp3.ConnectionSpec +import okhttp3.mockwebserver.MockWebServer +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import testhelpers.BaseTest +import testhelpers.extensions.toJsonResponse +import java.io.File +import java.util.concurrent.TimeUnit + +class SubmissionApiV1Test : BaseTest() { + + @MockK + private lateinit var context: Context + + private lateinit var webServer: MockWebServer + private lateinit var serverAddress: String + + private val testDir = File(BaseIOTest.IO_TEST_BASEDIR, this::class.java.simpleName) + private val cacheDir = File(testDir, "cache") + private val httpCacheDir = File(cacheDir, "http_submission") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { context.cacheDir } returns cacheDir + + webServer = MockWebServer() + webServer.start() + serverAddress = "http://${webServer.hostName}:${webServer.port}" + } + + @AfterEach + fun teardown() { + clearAllMocks() + webServer.shutdown() + } + + private fun createAPI(): SubmissionApiV1 { + val httpModule = HttpModule() + val defaultHttpClient = httpModule.defaultHttpClient() + + return SubmissionModule().let { + val downloadHttpClient = it.cdnHttpClient( + defaultHttpClient, + listOf(ConnectionSpec.CLEARTEXT, ConnectionSpec.MODERN_TLS) + ) + it.provideSubmissionApi( + context = context, + client = downloadHttpClient, + url = serverAddress, + gsonConverterFactory = httpModule.provideGSONConverter(), + protoConverterFactory = httpModule.provideProtoConverter() + ) + } + } + + @Test + fun `test submitKeys`(): Unit = runBlocking { + val api = createAPI() + + """ + { + "tan": "testTan" + } + """.toJsonResponse().apply { webServer.enqueue(this) } + + val submissionPayload = KeyExportFormat.SubmissionPayload.newBuilder() + .setPadding(ByteString.copyFromUtf8("fakeKeyPadding")) + .build() + + api.submitKeys( + authCode = "testAuthCode", + fake = "0", + headerPadding = "testPadding", + requestBody = submissionPayload + ) + + webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply { + headers["cwa-authorization"] shouldBe "testAuthCode" + headers["cwa-fake"] shouldBe "0" + headers["cwa-header-padding"] shouldBe "testPadding" + path shouldBe "/version/v1/diagnosis-keys" + body.readUtf8() shouldBe """fakeKeyPadding""" + } + + httpCacheDir.exists() shouldBe true + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/server/SubmissionServerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/server/SubmissionServerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..68031d83b88d7f3ae4dc74c2a57c0358a3117968 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/submission/server/SubmissionServerTest.kt @@ -0,0 +1,166 @@ +package de.rki.coronawarnapp.submission.server + +import android.content.Context +import com.google.protobuf.ByteString +import de.rki.coronawarnapp.http.HttpModule +import de.rki.coronawarnapp.server.protocols.KeyExportFormat +import de.rki.coronawarnapp.submission.SubmissionModule +import de.rki.coronawarnapp.util.headerSizeIgnoringContentLength +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.runBlocking +import okhttp3.ConnectionSpec +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import testhelpers.BaseTest +import java.io.File + +class SubmissionServerTest : BaseTest() { + @MockK lateinit var submissionApi: SubmissionApiV1 + @MockK lateinit var context: Context + + private lateinit var webServer: MockWebServer + private lateinit var serverAddress: String + + private val testDir = File(BaseIOTest.IO_TEST_BASEDIR, this::class.java.simpleName) + private val cacheDir = File(testDir, "cache") + private val httpCacheDir = File(cacheDir, "http_submission") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + testDir.mkdirs() + testDir.exists() shouldBe true + every { context.cacheDir } returns cacheDir + + webServer = MockWebServer() + webServer.start() + serverAddress = "http://${webServer.hostName}:${webServer.port}" + } + + @AfterEach + fun teardown() { + clearAllMocks() + webServer.shutdown() + testDir.deleteRecursively() + } + + private fun createServer( + customApi: SubmissionApiV1 = submissionApi + ) = SubmissionServer(submissionApi = { customApi }) + + @Test + fun `normal submission`(): Unit = runBlocking { + val testKeyData = ByteString.copyFrom("TestKeyDataGoogle", Charsets.UTF_8) + + val server = createServer() + coEvery { submissionApi.submitKeys(any(), any(), any(), any()) } answers { + arg<String>(0) shouldBe "testAuthCode" + arg<String>(1) shouldBe "0" + arg<String>(2) shouldBe "" + arg<KeyExportFormat.SubmissionPayload>(3).apply { + keysList.single().keyData shouldBe testKeyData + padding.size() shouldBe 364 + hasConsentToFederation() shouldBe true + visitedCountriesList shouldBe listOf("DE") + } + Unit + } + + val googleKeyList = KeyExportFormat.TemporaryExposureKey + .newBuilder() + .setKeyData(testKeyData) + .build() + + val submissionData = SubmissionServer.SubmissionData( + authCode = "testAuthCode", + keyList = listOf(googleKeyList), + consentToFederation = true, + visistedCountries = listOf("DE") + ) + server.submitKeysToServer(submissionData) + + coVerify { submissionApi.submitKeys(any(), any(), any(), any()) } + } + + @Test + fun `fake submission`(): Unit = runBlocking { + val server = createServer() + coEvery { submissionApi.submitKeys(any(), any(), any(), any()) } answers { + arg<String>(0) shouldBe "" // cwa-authorization + arg<String>(1) shouldBe "1" // cwa-fake + arg<String>(2).length shouldBe 36 // cwa-header-padding + arg<KeyExportFormat.SubmissionPayload>(3).apply { + keysList.size shouldBe 0 + padding.size() shouldBe 392 + hasConsentToFederation() shouldBe false + visitedCountriesList shouldBe emptyList() + } + Unit + } + + server.submitKeysToServerFake() + + coVerify { submissionApi.submitKeys(any(), any(), any(), any()) } + } + + private fun createRealApi(): SubmissionApiV1 { + val httpModule = HttpModule() + val defaultHttpClient = httpModule.defaultHttpClient() + + return SubmissionModule().let { + val downloadHttpClient = it.cdnHttpClient( + defaultHttpClient, + listOf(ConnectionSpec.CLEARTEXT, ConnectionSpec.MODERN_TLS) + ) + it.provideSubmissionApi( + context = context, + client = downloadHttpClient, + url = serverAddress, + gsonConverterFactory = httpModule.provideGSONConverter(), + protoConverterFactory = httpModule.provideProtoConverter() + ) + } + } + + @Test + fun allRequestHaveSameFootprintForPlausibleDeniability(): Unit = runBlocking { + val server = createServer(createRealApi()) + + val testKeyData = ByteString.copyFrom("TestKeyDataGoogle", Charsets.UTF_8) + val googleKeyList = KeyExportFormat.TemporaryExposureKey + .newBuilder() + .setKeyData(testKeyData) + .build() + val submissionData = SubmissionServer.SubmissionData( + authCode = "39ec4930-7a1f-4d5d-921f-bfad3b6f1269", + keyList = listOf(googleKeyList), + consentToFederation = true, + visistedCountries = listOf("DE") + ) + webServer.enqueue(MockResponse().setBody("{}")) + server.submitKeysToServer(submissionData) + + webServer.enqueue(MockResponse().setBody("{}")) + server.submitKeysToServerFake() + + val requests = listOf( + webServer.takeRequest(), + webServer.takeRequest() + ) + + // ensure all request have same size (header & body) + requests.zipWithNext().forEach { (a, b) -> + a.headerSizeIgnoringContentLength() shouldBe b.headerSizeIgnoringContentLength() + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransactionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransactionTest.kt index e8c59395e8583acf1d6313379823f3b75d1edb94..81581412be578ed1f02be138075b250f0c7dcf01 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransactionTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RetrieveDiagnosisKeysTransactionTest.kt @@ -1,21 +1,30 @@ package de.rki.coronawarnapp.transaction -import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration +import de.rki.coronawarnapp.environment.EnvironmentSetup +import de.rki.coronawarnapp.nearby.ENFClient import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.util.GoogleAPIVersion +import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.di.ApplicationComponent +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations import io.mockk.Runs +import io.mockk.clearAllMocks import io.mockk.coEvery +import io.mockk.coVerify import io.mockk.coVerifyOrder import io.mockk.every +import io.mockk.impl.annotations.MockK import io.mockk.just import io.mockk.mockk import io.mockk.mockkObject -import io.mockk.unmockkAll import kotlinx.coroutines.runBlocking -import org.junit.After -import org.junit.Before -import org.junit.Test +import org.joda.time.LocalDate +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import java.io.File import java.nio.file.Paths import java.util.Date @@ -26,71 +35,128 @@ import java.util.UUID */ class RetrieveDiagnosisKeysTransactionTest { - @Before + @MockK lateinit var mockEnfClient: ENFClient + @MockK lateinit var environmentSetup: EnvironmentSetup + + @BeforeEach fun setUp() { + MockKAnnotations.init(this) + + mockkObject(AppInjector) + val appComponent = mockk<ApplicationComponent>().apply { + every { transRetrieveKeysInjection } returns RetrieveDiagnosisInjectionHelper( + TransactionCoroutineScope(), + GoogleAPIVersion(), + mockEnfClient, + environmentSetup + ) + } + every { AppInjector.component } returns appComponent + mockkObject(InternalExposureNotificationClient) mockkObject(ApplicationConfigurationService) mockkObject(RetrieveDiagnosisKeysTransaction) mockkObject(LocalData) coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns true - coEvery { - InternalExposureNotificationClient.asyncProvideDiagnosisKeys( - any(), - any(), - any() - ) - } returns mockk() + coEvery { ApplicationConfigurationService.asyncRetrieveExposureConfiguration() } returns mockk() every { LocalData.googleApiToken(any()) } just Runs every { LocalData.lastTimeDiagnosisKeysFromServerFetch() } returns Date() every { LocalData.lastTimeDiagnosisKeysFromServerFetch(any()) } just Runs every { LocalData.googleApiToken() } returns UUID.randomUUID().toString() + + every { environmentSetup.useEuropeKeyPackageFiles } returns false + } + + @AfterEach + fun cleanUp() { + clearAllMocks() + } + + @Test + fun `unsuccessful ENF submission`() { + coEvery { mockEnfClient.provideDiagnosisKeys(any(), any(), any()) } returns false + val requestedCountries = listOf("DE") + coEvery { + RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"]( + requestedCountries + ) + } returns listOf<File>() + + runBlocking { + RetrieveDiagnosisKeysTransaction.start(requestedCountries) + } + + coVerifyOrder { + RetrieveDiagnosisKeysTransaction["executeSetup"]() + RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]() + RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"]( + requestedCountries + ) + } + coVerify(exactly = 0) { + RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>()) + } } @Test - fun testTransactionNoFiles() { - coEvery { RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](any<Date>()) } returns listOf<File>() + fun `successful submission`() { + val file = Paths.get("src", "test", "resources", "keys.bin").toFile() + coEvery { mockEnfClient.provideDiagnosisKeys(listOf(file), any(), any()) } returns true + val requestedCountries = listOf("DE") + + coEvery { + RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"]( + requestedCountries + ) + } returns listOf(file) runBlocking { - RetrieveDiagnosisKeysTransaction.start() - - coVerifyOrder { - RetrieveDiagnosisKeysTransaction["executeSetup"]() - RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]() - RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](any<Date>()) - RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>()) - } + RetrieveDiagnosisKeysTransaction.start(requestedCountries) + } + + coVerifyOrder { + RetrieveDiagnosisKeysTransaction["executeSetup"]() + RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]() + RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"]( + requestedCountries + ) + mockEnfClient.provideDiagnosisKeys(listOf(file), any(), any()) + RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>()) } } @Test - fun testTransactionHasFiles() { + fun `successful submission with EUR`() { + every { environmentSetup.useEuropeKeyPackageFiles } returns true val file = Paths.get("src", "test", "resources", "keys.bin").toFile() + coEvery { mockEnfClient.provideDiagnosisKeys(listOf(file), any(), any()) } returns true + val requestedCountries = listOf("EUR") - coEvery { RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](any<Date>()) } returns listOf( - file - ) + coEvery { + RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"]( + requestedCountries + ) + } returns listOf(file) runBlocking { - RetrieveDiagnosisKeysTransaction.start() - - coVerifyOrder { - RetrieveDiagnosisKeysTransaction["executeSetup"]() - RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]() - RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"](any<Date>()) - RetrieveDiagnosisKeysTransaction["executeAPISubmission"]( - any<String>(), - listOf(file), - any<ExposureConfiguration>() - ) - RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>()) - } + RetrieveDiagnosisKeysTransaction.start(requestedCountries) + } + + coVerifyOrder { + RetrieveDiagnosisKeysTransaction["executeSetup"]() + RetrieveDiagnosisKeysTransaction["executeRetrieveRiskScoreParams"]() + RetrieveDiagnosisKeysTransaction["executeFetchKeyFilesFromServer"]( + requestedCountries + ) + mockEnfClient.provideDiagnosisKeys(listOf(file), any(), any()) + RetrieveDiagnosisKeysTransaction["executeFetchDateUpdate"](any<Date>()) } } - @After - fun cleanUp() { - unmockkAll() + @Test + fun `conversion from date to localdate`() { + LocalDate.fromDateFields(Date(0)) shouldBe LocalDate.parse("1970-01-01") } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RiskLevelTransactionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RiskLevelTransactionTest.kt index 3e30b2306e42f8d187ff9b35f8ba487b8d87c71d..3634926310b6126a27887872df35457d73eebb72 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RiskLevelTransactionTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/RiskLevelTransactionTest.kt @@ -12,6 +12,8 @@ import de.rki.coronawarnapp.risk.RiskLevel.UNDETERMINED import de.rki.coronawarnapp.risk.RiskLevel.UNKNOWN_RISK_INITIAL import de.rki.coronawarnapp.risk.RiskLevel.UNKNOWN_RISK_OUTDATED_RESULTS import de.rki.coronawarnapp.risk.RiskLevel.UNKNOWN_RISK_OUTDATED_RESULTS_MANUAL +import de.rki.coronawarnapp.risk.RiskLevelCalculation +import de.rki.coronawarnapp.risk.RiskScoreAnalysis import de.rki.coronawarnapp.risk.TimeVariables import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.RiskScoreClass @@ -21,6 +23,8 @@ import de.rki.coronawarnapp.storage.ExposureSummaryRepository import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.RiskLevelRepository import de.rki.coronawarnapp.util.ConnectivityHelper +import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.di.ApplicationComponent import io.mockk.MockKAnnotations import io.mockk.Runs import io.mockk.coEvery @@ -28,10 +32,12 @@ import io.mockk.coVerifyOrder import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.just +import io.mockk.mockk import io.mockk.mockkObject import io.mockk.unmockkAll import kotlinx.coroutines.runBlocking import org.junit.After +import org.junit.Assert import org.junit.Before import org.junit.Test import java.util.UUID @@ -49,6 +55,14 @@ class RiskLevelTransactionTest { fun setUp() { MockKAnnotations.init(this) + mockkObject(AppInjector) + val appComponent = mockk<ApplicationComponent>().apply { + every { transRiskLevelInjection } returns RiskLevelInjectionHelper( + TransactionCoroutineScope() + ) + } + every { AppInjector.component } returns appComponent + mockkObject(InternalExposureNotificationClient) mockkObject(ApplicationConfigurationService) mockkObject(LocalData) @@ -460,6 +474,35 @@ class RiskLevelTransactionTest { } } + @Test + fun test_getRiskLevel() { + + // if risk score is within defined level threshold + // expected: INCREASED_RISK + + val testAppConfig = buildTestAppConfig() + Assert.assertEquals( + RiskLevel.INCREASED_RISK, RiskLevelTransaction.getRiskLevel( + object : RiskLevelCalculation { + override fun calculateRiskScore( + attenuationParameters: ApplicationConfigurationOuterClass.AttenuationDuration, + exposureSummary: ExposureSummary + ) = 0.0 + }, + object : RiskScoreAnalysis { + override fun withinDefinedLevelThreshold( + riskScore: Double, + min: Int, + max: Int + ) = true + }, + testAppConfig.attenuationDuration, + buildSummary(1600, 0, 30, 15), + testAppConfig.riskScoreClasses + ) + ) + } + @After fun cleanUp() { unmockkAll() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransactionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransactionTest.kt index c43d6b9ebd0d1fc9e9c3ef6d4cb9925941e5317f..ad63224dc1f20f00af2faa84792586595b7d3a85 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransactionTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/SubmitDiagnosisKeysTransactionTest.kt @@ -1,105 +1,180 @@ package de.rki.coronawarnapp.transaction -import KeyExportFormat import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.http.playbook.BackgroundNoise -import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient +import com.google.protobuf.ByteString +import de.rki.coronawarnapp.appconfig.AppConfigProvider +import de.rki.coronawarnapp.playbook.BackgroundNoise +import de.rki.coronawarnapp.playbook.Playbook +import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration +import de.rki.coronawarnapp.server.protocols.KeyExportFormat import de.rki.coronawarnapp.service.submission.SubmissionService import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.submission.ExposureKeyHistoryCalculations +import de.rki.coronawarnapp.submission.Symptoms +import de.rki.coronawarnapp.util.di.AppInjector +import de.rki.coronawarnapp.util.di.ApplicationComponent import de.rki.coronawarnapp.worker.BackgroundWorkScheduler +import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.Runs +import io.mockk.clearAllMocks import io.mockk.coEvery -import io.mockk.coVerifyOrder +import io.mockk.coVerifySequence import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.just import io.mockk.mockkObject -import io.mockk.slot -import io.mockk.unmockkAll import kotlinx.coroutines.runBlocking -import org.hamcrest.CoreMatchers.`is` -import org.hamcrest.MatcherAssert.assertThat -import org.junit.After -import org.junit.Before -import org.junit.Test +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import java.time.Instant class SubmitDiagnosisKeysTransactionTest { - @MockK - private lateinit var webRequestBuilder: WebRequestBuilder + @MockK lateinit var backgroundNoise: BackgroundNoise + @MockK lateinit var mockPlaybook: Playbook + @MockK lateinit var appConfigProvider: AppConfigProvider + @MockK lateinit var appComponent: ApplicationComponent + @MockK lateinit var exposureKeyHistoryCalculations: ExposureKeyHistoryCalculations - @MockK - private lateinit var backgroundNoise: BackgroundNoise - - private val authString = "authString" private val registrationToken = "123" - @Before + private val symptoms = Symptoms(Symptoms.StartOf.OneToTwoWeeksAgo, Symptoms.Indication.POSITIVE) + private val defaultCountries = listOf("DE", "NL", "FR") + + @BeforeEach fun setUp() { MockKAnnotations.init(this) - mockkObject(WebRequestBuilder.Companion) - every { WebRequestBuilder.getInstance() } returns webRequestBuilder + val appConfig = ApplicationConfiguration.newBuilder() + .addAllSupportedCountries(defaultCountries) + .build() + coEvery { appConfigProvider.getAppConfig() } returns appConfig + + every { appComponent.transSubmitDiagnosisInjection } returns SubmitDiagnosisInjectionHelper( + TransactionCoroutineScope(), + mockPlaybook, + appConfigProvider, + exposureKeyHistoryCalculations + ) + mockkObject(AppInjector) + every { AppInjector.component } returns appComponent + + every { + exposureKeyHistoryCalculations.transformToKeyHistoryInExternalFormat( + any(), + any() + ) + } returns emptyList() mockkObject(BackgroundNoise.Companion) every { BackgroundNoise.getInstance() } returns backgroundNoise mockkObject(LocalData) mockkObject(SubmissionService) - mockkObject(InternalExposureNotificationClient) mockkObject(BackgroundWorkScheduler) every { BackgroundWorkScheduler.stopWorkScheduler() } just Runs every { LocalData.numberOfSuccessfulSubmissions(any()) } just Runs - coEvery { webRequestBuilder.asyncGetTan(registrationToken) } returns authString } - @Test - fun testTransactionNoKeys() { - coEvery { InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory() } returns listOf() - coEvery { webRequestBuilder.asyncSubmitKeysToServer(authString, listOf()) } just Runs - - runBlocking { - SubmitDiagnosisKeysTransaction.start(registrationToken, listOf()) + @AfterEach + fun cleanUp() { + clearAllMocks() + } - coVerifyOrder { - webRequestBuilder.asyncSubmitKeysToServer(authString, listOf()) - SubmissionService.submissionSuccessful() - } + @Test + fun `submission without keys`(): Unit = runBlocking { + coEvery { mockPlaybook.submission(any()) } returns Unit + + SubmitDiagnosisKeysTransaction.start(registrationToken, listOf(), symptoms) + + coVerifySequence { + appConfigProvider.getAppConfig() + mockPlaybook.submission( + Playbook.SubmissionData( + registrationToken = registrationToken, + temporaryExposureKeys = emptyList(), + consentToFederation = true, + visistedCountries = defaultCountries + ) + ) + SubmissionService.submissionSuccessful() } } @Test - fun testTransactionHasKeys() { - val key = TemporaryExposureKey.TemporaryExposureKeyBuilder() - .setKeyData(ByteArray(1)) - .setRollingPeriod(1) - .setRollingStartIntervalNumber(1) - .setTransmissionRiskLevel(1) - .build() - val testList = slot<List<KeyExportFormat.TemporaryExposureKey>>() - coEvery { InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory() } returns listOf( - key - ) - coEvery { - webRequestBuilder.asyncSubmitKeysToServer(authString, capture(testList)) - } just Runs + fun `submission without keys and fallback country`(): Unit = runBlocking { + val appConfig = ApplicationConfiguration.newBuilder().build() + coEvery { appConfigProvider.getAppConfig() } returns appConfig + coEvery { mockPlaybook.submission(any()) } returns Unit + + SubmitDiagnosisKeysTransaction.start(registrationToken, listOf(), symptoms) + + coVerifySequence { + appConfigProvider.getAppConfig() + mockPlaybook.submission( + Playbook.SubmissionData( + registrationToken = registrationToken, + temporaryExposureKeys = emptyList(), + consentToFederation = true, + visistedCountries = listOf("DE") + ) + ) + SubmissionService.submissionSuccessful() + } + } + @Test + fun `submission with keys`() { + val intervalNumber = (Instant.now().toEpochMilli() / (60 * 10 * 1000)).toInt() runBlocking { - SubmitDiagnosisKeysTransaction.start(registrationToken, listOf(key)) + val key = TemporaryExposureKey.TemporaryExposureKeyBuilder() + .setKeyData(ByteArray(1)) + .setRollingPeriod(144) + .setRollingStartIntervalNumber(intervalNumber) + .setTransmissionRiskLevel(1) + .setDaysSinceOnsetOfSymptoms(10) + .build() + + every { + exposureKeyHistoryCalculations.transformToKeyHistoryInExternalFormat( + any(), + any() + ) + } returns listOf( + KeyExportFormat.TemporaryExposureKey.newBuilder() + .setKeyData(ByteString.copyFrom(ByteArray(1))) + .setRollingPeriod(144) + .setRollingStartIntervalNumber(intervalNumber) + .setTransmissionRiskLevel(1) + .setDaysSinceOnsetOfSymptoms(10) + .build() + ) + + coEvery { mockPlaybook.submission(any()) } answers { + arg<Playbook.SubmissionData>(0).also { + it.registrationToken shouldBe registrationToken + it.temporaryExposureKeys.single().apply { + keyData.toByteArray() shouldBe ByteArray(1) + rollingPeriod shouldBe 144 + rollingStartIntervalNumber shouldBe intervalNumber + transmissionRiskLevel shouldBe 1 + daysSinceOnsetOfSymptoms shouldBe 10 + } + it.consentToFederation shouldBe true + it.visistedCountries shouldBe defaultCountries + } + Unit + } + + SubmitDiagnosisKeysTransaction.start(registrationToken, listOf(key), symptoms) - coVerifyOrder { - webRequestBuilder.asyncSubmitKeysToServer(authString, any()) + coVerifySequence { + appConfigProvider.getAppConfig() + mockPlaybook.submission(any()) SubmissionService.submissionSuccessful() } - assertThat(testList.isCaptured, `is`(true)) - assertThat(testList.captured.size, `is`(1)) } } - - @After - fun cleanUp() { - unmockkAll() - } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/TransactionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/TransactionTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..5ba62a995d754feedd5966522f036871c2f0da84 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/transaction/TransactionTest.kt @@ -0,0 +1,113 @@ +package de.rki.coronawarnapp.transaction + +import de.rki.coronawarnapp.exception.RollbackException +import de.rki.coronawarnapp.exception.TransactionException +import de.rki.coronawarnapp.risk.TimeVariables +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.should +import io.kotest.matchers.types.beInstanceOf +import io.mockk.clearAllMocks +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockkObject +import io.mockk.spyk +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.TestCoroutineScope +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import java.io.IOException + +@ExperimentalCoroutinesApi +class TransactionTest : BaseTest() { + + @BeforeEach + fun setup() { + mockkObject(TimeVariables) + } + + @AfterEach + fun tearDown() { + clearAllMocks() + } + + @Suppress("UNREACHABLE_CODE") + private class TestTransaction( + val errorOnRollBack: Exception? = null + ) : Transaction() { + override val TAG: String = "TestTag" + + public override suspend fun rollback() { + errorOnRollBack?.let { handleRollbackError(it) } + super.rollback() + } + + public override suspend fun handleTransactionError(error: Throwable): Nothing { + return super.handleTransactionError(error) + } + + public override fun handleRollbackError(error: Throwable?): Nothing { + return super.handleRollbackError(error) + } + } + + @Test + fun `transaction error handler is called`() { + val testScope = TestCoroutineScope() + val testTransaction = spyk(TestTransaction()) + shouldThrow<TransactionException> { + runBlocking { + testTransaction.lockAndExecute(scope = testScope) { + throw IOException() + } + } + } + + coVerify { testTransaction.handleTransactionError(any()) } + coVerify { testTransaction.rollback() } + } + + @Test + fun `rollback error handler is called`() { + val testScope = TestCoroutineScope() + val testTransaction = spyk( + TestTransaction( + errorOnRollBack = IllegalAccessException() + ) + ) + shouldThrow<RollbackException> { + runBlocking { + testTransaction.lockAndExecute(scope = testScope) { + throw IOException() + } + } + } + + coVerify { testTransaction.handleTransactionError(ofType<IOException>()) } + coVerify { testTransaction.rollback() } + coVerify { testTransaction.handleRollbackError(ofType<IllegalAccessException>()) } + } + + @Test + fun `transactions can timeout`() { + /** + * TODO use runBlockingTest & advanceTime, which currently does not work + * https://github.com/Kotlin/kotlinx.coroutines/issues/1204 + */ + every { TimeVariables.getTransactionTimeout() } returns 0L + + val testTransaction = TestTransaction() + val exception = shouldThrow<TransactionException> { + runBlocking { + testTransaction.lockAndExecute(scope = this) { + delay(TimeVariables.getTransactionTimeout()) + } + } + } + exception.cause should beInstanceOf<TimeoutCancellationException>() + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculationTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..ad8e47590f0c812119283aa3f66442855d432736 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/calendar/CalendarCalculationTest.kt @@ -0,0 +1,116 @@ +package de.rki.coronawarnapp.ui.calendar + +import io.kotest.matchers.shouldBe +import org.joda.time.DateTime +import org.joda.time.format.DateTimeFormat +import org.junit.Test + +class CalendarCalculationTest { + + private var pattern = "dd.MM.yyyy" + private val formatter = DateTimeFormat.forPattern(pattern) + + @Test + fun calculateSameYearSameMonth() { + var input = "27.08.2020" + val dateTime = + DateTime.parse(input, DateTimeFormat.forPattern(pattern)) + val dates = CalendarCalculation().getDates(dateTime) + + // First day - 3 of August + dates.first().date.dayOfMonth shouldBe 3 + dates.first().date.monthOfYear shouldBe 8 + + // Last day - 30 of August + dates.last().date.dayOfMonth shouldBe 30 + dates.last().date.monthOfYear shouldBe 8 + + CalendarCalculation().getMonthText( + dates.first().date, + dates.last().date + ) shouldBe "August 2020" + } + + @Test + fun calculateSameYearDifferentMonth() { + var input = "15.09.2020" + val dateTime = + DateTime.parse(input, DateTimeFormat.forPattern(pattern)) + val dates = CalendarCalculation().getDates(dateTime) + + // First day - 24 of August + dates.first().date.dayOfMonth shouldBe 24 + dates.first().date.monthOfYear shouldBe 8 + + // Last day - 20 of September + dates.last().date.dayOfMonth shouldBe 20 + dates.last().date.monthOfYear shouldBe 9 + + CalendarCalculation().getMonthText( + dates.first().date, + dates.last().date + ) shouldBe "August - September 2020" + } + + @Test + fun calculateDifferentYearDifferentMonth() { + var input = "12.01.2021" + val dateTime = + DateTime.parse(input, DateTimeFormat.forPattern(pattern)) + val dates = CalendarCalculation().getDates(dateTime) + + // First day - 21 of December 2020 + dates.first().date.dayOfMonth shouldBe 21 + dates.first().date.monthOfYear shouldBe 12 + dates.first().date.year shouldBe 2020 + + // Last day - 17 of January 2021 + dates.last().date.dayOfMonth shouldBe 17 + dates.last().date.monthOfYear shouldBe 1 + dates.last().date.year shouldBe 2021 + + CalendarCalculation().getMonthText( + dates.first().date, + dates.last().date + ) shouldBe "December 2020 - January 2021" + } + + @Test + fun calculateEdgeCases() { + // new year + CalendarCalculation().getDates(DateTime.parse("27.12.2021", formatter)).apply { + // First day - 6 of December 2021 + first().date.dayOfMonth shouldBe 6 + first().date.monthOfYear shouldBe 12 + first().date.year shouldBe 2021 + + // Last day - 2 of January 2022 + last().date.dayOfMonth shouldBe 2 + last().date.monthOfYear shouldBe 1 + last().date.year shouldBe 2022 + + CalendarCalculation().getMonthText( + first().date, + last().date + ) shouldBe "December 2021 - January 2022" + } + + // leap year + CalendarCalculation().getDates(DateTime.parse("29.02.2024", formatter)).apply { + // First day - 5 of February 2024 + first().date.dayOfMonth shouldBe 5 + first().date.monthOfYear shouldBe 2 + first().date.year shouldBe 2024 + + // Last day - 2 of March 2024 + last().date.dayOfMonth shouldBe 3 + last().date.monthOfYear shouldBe 3 + last().date.year shouldBe 2024 + + CalendarCalculation().getMonthText( + first().date, + last().date + ) shouldBe "February - March 2024" + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/information/InformationLegalPresentationTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/information/InformationLegalPresentationTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..6e3b4a6003cbaacff6b60217ed62ae7360b2bf18 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/information/InformationLegalPresentationTest.kt @@ -0,0 +1,36 @@ +package de.rki.coronawarnapp.ui.information + +import de.rki.coronawarnapp.util.device.SystemInfoProvider +import org.junit.Assert +import org.junit.Test +import java.util.Locale + +class InformationLegalPresentationTest { + + @Test + fun test_showBackupLinkToContactForm() { + // NO BACKUP NEEDED IN DE + Assert.assertFalse(InformationLegalPresentation(object : SystemInfoProvider { + override val locale: Locale + get() = Locale.GERMAN + }).showBackupLinkToContactForm) + + // NO BACKUP NEEDED IN EN + Assert.assertFalse(InformationLegalPresentation(object : SystemInfoProvider { + override val locale: Locale + get() = Locale.ENGLISH + }).showBackupLinkToContactForm) + + // BACKUP NEEDED IN FR + Assert.assertTrue(InformationLegalPresentation(object : SystemInfoProvider { + override val locale: Locale + get() = Locale.FRENCH + }).showBackupLinkToContactForm) + + // BACKUP NEEDED IN CN + Assert.assertTrue(InformationLegalPresentation(object : SystemInfoProvider { + override val locale: Locale + get() = Locale.CHINESE + }).showBackupLinkToContactForm) + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModelTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..d5e13842a13a8de0cdacbd91bffca9cae2b65fce --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModelTest.kt @@ -0,0 +1,59 @@ +package de.rki.coronawarnapp.ui.interoperability + +import androidx.lifecycle.MutableLiveData +import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository +import de.rki.coronawarnapp.ui.Country +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.Runs +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.verify +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import testhelpers.extensions.InstantExecutorExtension +import testhelpers.extensions.getOrAwaitValue + +@ExtendWith(InstantExecutorExtension::class) +class InteroperabilityConfigurationFragmentViewModelTest { + + @MockK lateinit var interoperabilityRepository: InteroperabilityRepository + + @BeforeEach + fun setupFreshViewModel() { + MockKAnnotations.init(this) + + every { interoperabilityRepository.countryList } returns MutableLiveData( + Country.values().toList() + ) + every { interoperabilityRepository.getAllCountries() } just Runs + } + + private fun createViewModel() = + InteroperabilityConfigurationFragmentViewModel(interoperabilityRepository) + + @Test + fun `viewmodel returns interop repo countryList`() { + val vm = createViewModel() + + vm.countryList.getOrAwaitValue() shouldBe Country.values().toList() + } + + @Test + fun testFetchCountryList() { + val vm = createViewModel() + verify(exactly = 0) { interoperabilityRepository.getAllCountries() } + vm.getAllCountries() + verify(exactly = 1) { interoperabilityRepository.getAllCountries() } + } + + @Test + fun testBackPressButton() { + val vm = createViewModel() + vm.onBackPressed() + + vm.navigateBack.getOrAwaitValue() shouldBe true + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModelTest.kt index 805e975068920ae3916e0fc6f42bfa0cdfb12eb8..8f49bcb3f001e37e3e3012895d795f3217c9485b 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/SubmissionTanViewModelTest.kt @@ -1,6 +1,7 @@ package de.rki.coronawarnapp.ui.submission import de.rki.coronawarnapp.storage.SubmissionRepository +import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionTanViewModel import io.mockk.Runs import io.mockk.every import io.mockk.just diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionCountrySelectViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionCountrySelectViewModelTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..6fc0545edb85f385a0cbafe1fad98b23b3d1ed41 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/submission/viewmodel/SubmissionCountrySelectViewModelTest.kt @@ -0,0 +1,59 @@ +package de.rki.coronawarnapp.ui.submission.viewmodel + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import de.rki.coronawarnapp.ui.submission.SubmissionCountry +import io.kotest.inspectors.forAll +import io.kotest.inspectors.forAtLeastOne +import io.kotest.inspectors.forAtMostOne +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.shouldBe +import org.junit.Rule +import org.junit.Test + +class SubmissionCountrySelectViewModelTest { + @get:Rule + val instantTaskExecRule = InstantTaskExecutorRule() + + @Test + fun testFetchCountries() { + val viewModel = SubmissionCountrySelectViewModel() + + viewModel.fetchCountries() + // TODO: implement proper test one backend is merged + viewModel.countries.value!!.shouldHaveSize(2) + } + + @Test + fun testUpdateCountryCheckedState() { + val viewModel = SubmissionCountrySelectViewModel() + + viewModel.fetchCountries() + + viewModel.updateCountryCheckedState(SubmissionCountry("IT", true)) + viewModel.countries.value!!.forAtMostOne { + it.countryCode shouldBe "IT" + it.selected shouldBe true + } + + viewModel.updateCountryCheckedState(SubmissionCountry("IT", false)) + viewModel.countries.value!!.forAtLeastOne { + it.countryCode shouldBe "IT" + it.selected shouldBe false + } + } + + @Test + fun testNoInfoClickRemovesSelections() { + val viewModel = SubmissionCountrySelectViewModel() + + viewModel.fetchCountries() + + viewModel.updateCountryCheckedState(SubmissionCountry("IT", true)) + viewModel.updateCountryCheckedState(SubmissionCountry("ES", true)) + viewModel.countries.value!!.forAll { it.selected shouldBe true } + + viewModel.noInfoClick() + + viewModel.countries.value!!.forAll { it.selected shouldBe false } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModelTest.kt index a7fa73cbf1963e41a9b698b328dd807e4bda4d97..cbc54ad5d3a78b2dddbe89f2a525c0576ca03672 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModelTest.kt @@ -1,10 +1,9 @@ package de.rki.coronawarnapp.ui.viewmodel -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.http.playbook.BackgroundNoise +import de.rki.coronawarnapp.playbook.BackgroundNoise import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.ui.submission.ScanStatus +import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.Runs import io.mockk.every @@ -12,46 +11,39 @@ import io.mockk.impl.annotations.MockK import io.mockk.just import io.mockk.mockkObject import org.junit.Assert -import org.junit.Before -import org.junit.Rule -import org.junit.Test +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import testhelpers.extensions.InstantExecutorExtension +@ExtendWith(InstantExecutorExtension::class) class SubmissionViewModelTest { - private var viewModel: SubmissionViewModel = SubmissionViewModel() - @JvmField - @Rule - var instantTaskExecutorRule: InstantTaskExecutorRule = InstantTaskExecutorRule() + @MockK lateinit var backgroundNoise: BackgroundNoise - @MockK - private lateinit var webRequestBuilder: WebRequestBuilder - - @MockK - private lateinit var backgroundNoise: BackgroundNoise - - @Before + @BeforeEach fun setUp() { MockKAnnotations.init(this) mockkObject(LocalData) every { LocalData.testGUID(any()) } just Runs - mockkObject(WebRequestBuilder.Companion) - every { WebRequestBuilder.getInstance() } returns webRequestBuilder - mockkObject(BackgroundNoise.Companion) every { BackgroundNoise.getInstance() } returns backgroundNoise } + private fun createViewModel() = SubmissionViewModel() + @Test fun scanStatusValid() { + val viewModel = createViewModel() // start - viewModel.scanStatus.value?.getContent().let { Assert.assertEquals(ScanStatus.STARTED, it) } + viewModel.scanStatus.value!!.getContent() shouldBe ScanStatus.STARTED // valid guid val guid = "123456-12345678-1234-4DA7-B166-B86D85475064" - viewModel.validateAndStoreTestGUID("https://bs-sd.de/covid-19/?$guid") + viewModel.validateAndStoreTestGUID("https://localhost/?$guid") viewModel.scanStatus.value?.getContent().let { Assert.assertEquals(ScanStatus.SUCCESS, it) } // invalid guid diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/CachedKeyFileHolderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/CachedKeyFileHolderTest.kt deleted file mode 100644 index b03e57dd79478303134648a0bd26d9d8638d2b04..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/CachedKeyFileHolderTest.kt +++ /dev/null @@ -1,75 +0,0 @@ -package de.rki.coronawarnapp.util - -import android.content.Context -import de.rki.coronawarnapp.CoronaWarnApplication -import de.rki.coronawarnapp.storage.keycache.KeyCacheRepository -import io.mockk.MockKAnnotations -import io.mockk.Runs -import io.mockk.coEvery -import io.mockk.coVerifyOrder -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.just -import io.mockk.mockkObject -import io.mockk.unmockkAll -import kotlinx.coroutines.runBlocking -import org.junit.After -import org.junit.Before -import org.junit.Test -import java.util.Date - -/** - * CachedKeyFileHolder test. - */ -class CachedKeyFileHolderTest { - - @MockK - private lateinit var keyCacheRepository: KeyCacheRepository - - @MockK - private lateinit var context: Context - - @Before - fun setUp() { - MockKAnnotations.init(this) - mockkObject(CoronaWarnApplication.Companion) - mockkObject(KeyCacheRepository.Companion) - every { CoronaWarnApplication.getAppContext() } returns context - every { KeyCacheRepository.getDateRepository(any()) } returns keyCacheRepository - mockkObject(CachedKeyFileHolder) - coEvery { keyCacheRepository.deleteOutdatedEntries(any()) } just Runs - } - - /** - * Test call order is correct. - */ - @Test - fun testAsyncFetchFiles() { - val date = Date() - - coEvery { keyCacheRepository.getDates() } returns listOf() - coEvery { keyCacheRepository.getFilesFromEntries() } returns listOf() - every { CachedKeyFileHolder["isLast3HourFetchEnabled"]() } returns false - every { CachedKeyFileHolder["checkForFreeSpace"]() } returns Unit - every { CachedKeyFileHolder["getDatesFromServer"]() } returns arrayListOf<String>() - - runBlocking { - - CachedKeyFileHolder.asyncFetchFiles(date) - - coVerifyOrder { - CachedKeyFileHolder.asyncFetchFiles(date) - CachedKeyFileHolder["getDatesFromServer"]() - keyCacheRepository.deleteOutdatedEntries(any()) - CachedKeyFileHolder["getMissingDaysFromDiff"](arrayListOf<String>()) - keyCacheRepository.getDates() - keyCacheRepository.getFilesFromEntries() - } - } - } - - @After - fun cleanUp() { - unmockkAll() - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ExternalActionHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ExternalActionHelperTest.kt index 2ed5436204ef831e009df21951b2f55ed0a1b42a..0ca6efe8ca0da64c57dfd852a2253cd8427774ee 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ExternalActionHelperTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ExternalActionHelperTest.kt @@ -79,21 +79,6 @@ class ExternalActionHelperTest { verify(exactly = 1) { fragment.startActivity(any()) } } - @Test - fun disableBatteryOptimizations() { - every { context.packageName } returns "package_name" - every { context.startActivity(any()) } just Runs - ExternalActionHelper.disableBatteryOptimizations(context) - verify(exactly = 1) { context.startActivity(any()) } - } - - @Test - fun toBatteryOptimizationSettings() { - every { context.startActivity(any()) } just Runs - ExternalActionHelper.toBatteryOptimizationSettings(context) - verify(exactly = 1) { context.startActivity(any()) } - } - @After fun cleanUp() { unmockkAll() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..110d8cbeed2aef3b469c0355c3a848025f1faadf --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/GoogleAPIVersionTest.kt @@ -0,0 +1,75 @@ +package de.rki.coronawarnapp.util + +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.CommonStatusCodes.API_NOT_CONNECTED +import com.google.android.gms.common.api.Status +import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient +import io.kotest.matchers.shouldBe +import io.mockk.Called +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockkObject +import io.mockk.unmockkObject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +@ExperimentalCoroutinesApi +internal class GoogleAPIVersionTest { + + private lateinit var classUnderTest: GoogleAPIVersion + + @BeforeEach + fun setUp() { + mockkObject(InternalExposureNotificationClient) + classUnderTest = GoogleAPIVersion() + } + + @AfterEach + fun tearDown() { + unmockkObject(InternalExposureNotificationClient) + } + + @Test + fun `isAbove API v16 is true for v17`() { + coEvery { InternalExposureNotificationClient.getVersion() } returns 17000000L + + runBlockingTest { + classUnderTest.isAtLeast(GoogleAPIVersion.V16) shouldBe true + } + } + + @Test + fun `isAbove API v16 is false for v15`() { + coEvery { InternalExposureNotificationClient.getVersion() } returns 15000000L + + runBlockingTest { + classUnderTest.isAtLeast(GoogleAPIVersion.V16) shouldBe false + } + } + + @Test + fun `isAbove API v16 throws IllegalArgument for invalid version`() { + assertThrows<IllegalArgumentException> { + runBlockingTest { + classUnderTest.isAtLeast(1L) + } + coVerify { + InternalExposureNotificationClient.getVersion() wasNot Called + } + } + } + + @Test + fun `isAbove API v16 false when APIException for too low version`() { + coEvery { InternalExposureNotificationClient.getVersion() } throws + ApiException(Status(API_NOT_CONNECTED)) + + runBlockingTest { + classUnderTest.isAtLeast(GoogleAPIVersion.V16) shouldBe false + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/HashExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/HashExtensionsTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..ad8d1c58d286307a36d310eff65450b97042a18e --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/HashExtensionsTest.kt @@ -0,0 +1,60 @@ +package de.rki.coronawarnapp.util + +import de.rki.coronawarnapp.util.HashExtensions.hashToMD5 +import de.rki.coronawarnapp.util.HashExtensions.toMD5 +import de.rki.coronawarnapp.util.HashExtensions.toSHA1 +import de.rki.coronawarnapp.util.HashExtensions.toSHA256 +import io.kotest.matchers.shouldBe +import io.mockk.clearAllMocks +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File + +class HashExtensionsTest : BaseIOTest() { + + private val testInput = "The Cake Is A Lie" + private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) + + @BeforeEach + fun setup() { + testDir.mkdirs() + } + + @AfterEach + fun teardown() { + clearAllMocks() + + testDir.deleteRecursively() + } + + @Test + fun `hash string to MD5`() { + testInput.toMD5() shouldBe "e42997e37d8d70d4927b0b396254c179" + } + + @Test + fun `hash string to SHA256`() { + testInput.toSHA256() shouldBe "3afc82e0c5df81d1733fe0c289538a1a1f7a5038d5c261860a5c83952f4bcb61" + } + + @Test + fun `hash string to SHA1`() { + testInput.toSHA1() shouldBe "4d57f806e5f714ebdb5a74a12fda9523fae21d76" + } + + @Test + fun `hash file to md5`() { + val fileName = "FileToMD5.txt" + val testFile = File(testDir, fileName) + try { + testFile.printWriter().use { out -> + out.print("This is a test") + } + testFile.hashToMD5() shouldBe "ce114e4501d2f4e2dcea3e17b546f339" + } finally { + testFile.delete() + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/MockWebServerUtil.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/MockWebServerUtil.kt index 5a908210db83ae12f96e4b825b10dba3a53667a1..6f31074edc2393b995c0f1e87b41356c74fa34c9 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/MockWebServerUtil.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/MockWebServerUtil.kt @@ -1,43 +1,7 @@ package de.rki.coronawarnapp.util -import de.rki.coronawarnapp.http.HttpErrorParser -import de.rki.coronawarnapp.http.WebRequestBuilder -import de.rki.coronawarnapp.http.interceptor.RetryInterceptor -import de.rki.coronawarnapp.http.service.DistributionService -import de.rki.coronawarnapp.http.service.SubmissionService -import de.rki.coronawarnapp.http.service.VerificationService -import de.rki.coronawarnapp.util.security.VerificationKeys -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.RecordedRequest import okio.utf8Size -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import retrofit2.converter.protobuf.ProtoConverterFactory - -fun MockWebServer.newWebRequestBuilder(): WebRequestBuilder { - val httpClient = OkHttpClient.Builder() - .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) - .addInterceptor(RetryInterceptor()) - .addInterceptor(HttpErrorParser()) - .build() - - val retrofit = Retrofit.Builder() - .client(httpClient) - .addConverterFactory(ProtoConverterFactory.create()) - .addConverterFactory(GsonConverterFactory.create()) - - return WebRequestBuilder( - retrofit.baseUrl(this.url("/distribution/")).build() - .create(DistributionService::class.java), - retrofit.baseUrl(this.url("/verification/")).build() - .create(VerificationService::class.java), - retrofit.baseUrl(this.url("/submission/")).build() - .create(SubmissionService::class.java), - VerificationKeys() - ) -} fun RecordedRequest.requestHeaderWithoutContentLength() = listOf(this.requestLine) diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/PaddingToolTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/PaddingToolTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..593f9f566c137b5146a66865185921aabe7ab049 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/PaddingToolTest.kt @@ -0,0 +1,25 @@ +package de.rki.coronawarnapp.util + +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import timber.log.Timber +import kotlin.math.abs +import kotlin.random.Random + +class PaddingToolTest : BaseTest() { + + private val validPattern = "^([A-Za-z0-9]+)$".toRegex() + + @Test + fun `verify padding patterns`() { + repeat(1000) { + val randomLength = abs(Random.nextInt(1, 1024)) + PaddingTool.requestPadding(randomLength).apply { + length shouldBe randomLength + Timber.v("RandomLength: %d, Padding: %s", randomLength, this) + validPattern.matches(this) shouldBe true + } + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensionsTest.kt deleted file mode 100644 index 9ffe27e56ca4d9ca4c6e2243be2751397d72cfa8..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/ProtoFormatConverterExtensionsTest.kt +++ /dev/null @@ -1,124 +0,0 @@ -package de.rki.coronawarnapp.util - -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey -import de.rki.coronawarnapp.util.ProtoFormatConverterExtensions.transformKeyHistoryToExternalFormat -import org.hamcrest.CoreMatchers -import org.hamcrest.MatcherAssert -import org.junit.Test - -private const val DEFAULT_TRANSMISSION_RISK_LEVEL = 1 -private const val TRANSMISSION_RISK_DAY_0 = 5 -private const val TRANSMISSION_RISK_DAY_1 = 6 -private const val TRANSMISSION_RISK_DAY_2 = 8 -private const val TRANSMISSION_RISK_DAY_3 = 8 -private const val TRANSMISSION_RISK_DAY_4 = 8 -private const val TRANSMISSION_RISK_DAY_5 = 5 -private const val TRANSMISSION_RISK_DAY_6 = 3 -private const val TRANSMISSION_RISK_DAY_7 = 1 - -class ProtoFormatConverterExtensionsTest { - - @Test - fun areTransmissionRiskLevelsCorrectlyAssigned() { - - val key1 = byteArrayOf( - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - ) - - val diagnosisKeyList = mutableListOf<TemporaryExposureKey>() - val numKeys = 13 - for (pos in 0 until numKeys) { - diagnosisKeyList.add( - TemporaryExposureKey.TemporaryExposureKeyBuilder() - .setKeyData(key1) - .setRollingStartIntervalNumber(pos * 144) - .setRollingPeriod(144) - .setTransmissionRiskLevel(0) - .build() - ) - } - - val transformedKeyList = diagnosisKeyList.transformKeyHistoryToExternalFormat() - .sortedWith(compareBy { it.rollingStartIntervalNumber }) - - MatcherAssert.assertThat( - transformedKeyList.size, - CoreMatchers.equalTo(numKeys) - ) - - val correctRiskLevels = arrayOf( - DEFAULT_TRANSMISSION_RISK_LEVEL, - DEFAULT_TRANSMISSION_RISK_LEVEL, - DEFAULT_TRANSMISSION_RISK_LEVEL, - DEFAULT_TRANSMISSION_RISK_LEVEL, - DEFAULT_TRANSMISSION_RISK_LEVEL, - DEFAULT_TRANSMISSION_RISK_LEVEL, - TRANSMISSION_RISK_DAY_7, - TRANSMISSION_RISK_DAY_6, - TRANSMISSION_RISK_DAY_5, - TRANSMISSION_RISK_DAY_4, - TRANSMISSION_RISK_DAY_3, - TRANSMISSION_RISK_DAY_2, - TRANSMISSION_RISK_DAY_1 - ) - - for (pos in 0 until numKeys) { - val key = transformedKeyList[pos] - MatcherAssert.assertThat( - key.transmissionRiskLevel, - CoreMatchers.equalTo(correctRiskLevels[pos]) - ) - MatcherAssert.assertThat( - key.rollingStartIntervalNumber, - CoreMatchers.equalTo(pos * 144) - ) - } - } - - @Test - fun areTransmissionRiskLevelsCorrectlyAssignedWithOnlyOneKey() { - - val key1 = byteArrayOf( - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - ) - - val diagnosisKeyList = mutableListOf<TemporaryExposureKey>() - val numKeys = 1 - for (pos in 0 until numKeys) { - diagnosisKeyList.add( - TemporaryExposureKey.TemporaryExposureKeyBuilder() - .setKeyData(key1) - .setRollingStartIntervalNumber(pos * 144) - .setRollingPeriod(144) - .setTransmissionRiskLevel(0) - .build() - ) - } - - val transformedKeyList = diagnosisKeyList.transformKeyHistoryToExternalFormat() - .sortedWith(compareBy { it.rollingStartIntervalNumber }) - - MatcherAssert.assertThat( - transformedKeyList.size, - CoreMatchers.equalTo(numKeys) - ) - - val correctRiskLevels = arrayOf( - TRANSMISSION_RISK_DAY_1 - ) - - for (pos in 0 until numKeys) { - val key = transformedKeyList[pos] - MatcherAssert.assertThat( - key.transmissionRiskLevel, - CoreMatchers.equalTo(correctRiskLevels[pos]) - ) - MatcherAssert.assertThat( - key.rollingStartIntervalNumber, - CoreMatchers.equalTo(pos * 144) - ) - } - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/RetryMechanismTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/RetryMechanismTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..c0697e18d92b3fc8b9ca33f0b5be90f73db5b857 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/RetryMechanismTest.kt @@ -0,0 +1,92 @@ +package de.rki.coronawarnapp.util + +import de.rki.coronawarnapp.util.RetryMechanism.createDelayCalculator +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.longs.beInRange +import io.kotest.matchers.should +import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe +import io.kotest.matchers.types.instanceOf +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import java.util.UUID + +class RetryMechanismTest : BaseTest() { + @MockK lateinit var mockFunction: () -> String + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { mockFunction.invoke() } answers { + throw RuntimeException(UUID.randomUUID().toString()) + } + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + @Test + fun `simple retry`() { + val attempts = mutableListOf<RetryMechanism.Attempt>() + shouldThrow<RuntimeException> { + RetryMechanism.retryWithBackOff( + delayCalculator = createDelayCalculator(), + delayOperation = { Thread.sleep(it) }, + retryCondition = { + attempts.add(it) + it.count < 3 + }, + action = mockFunction + ) + } + verify(exactly = 3) { mockFunction() } + + attempts[0].apply { + count shouldBe 1 + totalDelay shouldBe 0L + lastDelay shouldBe 0L + exception should instanceOf(RuntimeException::class) + } + attempts[1].apply { + count shouldBe 2 + totalDelay shouldBe lastDelay + lastDelay shouldBe totalDelay + exception should instanceOf(RuntimeException::class) + } + attempts[2].apply { + count shouldBe 3 + totalDelay shouldBe attempts[1].totalDelay + lastDelay + lastDelay shouldBe totalDelay - attempts[1].totalDelay + exception should instanceOf(RuntimeException::class) + } + attempts[0].exception shouldNotBe attempts[1].exception + attempts[1].exception shouldNotBe attempts[2].exception + } + + @Test + fun `test clamping`() { + val calculator = createDelayCalculator() + RetryMechanism.Attempt(count = -5, lastDelay = 20).let { + calculator(it) shouldBe 25 // -X .. 20 -> clamp to min (25) + } + RetryMechanism.Attempt(count = 100, lastDelay = 3 * 1000L).let { + calculator(it) shouldBe 3 * 1000L // lastDelay .. HugeNewDelay -> clamp to max (3k) + } + + RetryMechanism.Attempt(count = 10, lastDelay = 16 * 1000L).let { + calculator(it) shouldBe beInRange(1536L..3000L) + } + RetryMechanism.Attempt(count = 100, lastDelay = 1).let { + calculator(it) shouldBe 3 * 1000L + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/TimeAndDateExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/TimeAndDateExtensionsTest.kt index 6366bbeb12e9c6488bb42b47490d7ad18b57c1b3..a5ca1f82d2a3d9657fdeb7a82fcebddab07e29be 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/TimeAndDateExtensionsTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/TimeAndDateExtensionsTest.kt @@ -1,6 +1,7 @@ package de.rki.coronawarnapp.util import de.rki.coronawarnapp.CoronaWarnApplication +import de.rki.coronawarnapp.util.TimeAndDateExtensions.ageInDays import de.rki.coronawarnapp.util.TimeAndDateExtensions.calculateDays import de.rki.coronawarnapp.util.TimeAndDateExtensions.getCurrentHourUTC import io.mockk.MockKAnnotations @@ -11,7 +12,9 @@ import org.hamcrest.MatcherAssert import org.joda.time.DateTime import org.joda.time.DateTimeZone import org.joda.time.Instant +import org.joda.time.LocalDate import org.junit.After +import org.junit.Assert import org.junit.Before import org.junit.Test import java.util.concurrent.TimeUnit @@ -43,6 +46,28 @@ class TimeAndDateExtensionsTest { MatcherAssert.assertThat(result, CoreMatchers.`is`(TimeUnit.MILLISECONDS.toDays(lSecondDate - lFirstDate))) } + @Test + fun test_daysAgo() { + Assert.assertEquals( + 0, + LocalDate(2012, 3, 4).ageInDays( + LocalDate(2012, 3, 4) + ) + ) + Assert.assertEquals( + 2, + LocalDate(2013, 12, 31).ageInDays( + LocalDate(2014, 1, 2) + ) + ) + Assert.assertEquals( + 3, + LocalDate(2014, 5, 2).ageInDays( + LocalDate(2014, 5, 5) + ) + ) + } + @After fun cleanUp() { unmockkAll() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/database/CommonConvertersTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/database/CommonConvertersTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..16c04ae999000000e315538ba9cda4234f5b733d --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/database/CommonConvertersTest.kt @@ -0,0 +1,104 @@ +/****************************************************************************** + * Corona-Warn-App * + * * + * SAP SE and all other contributors / * + * copyright owners license this file to you under the Apache * + * License, Version 2.0 (the "License"); you may not use this * + * file except in compliance with the License. * + * You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ******************************************************************************/ + +package de.rki.coronawarnapp.util.database + +import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode +import io.kotest.matchers.shouldBe +import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import java.io.File +import java.util.UUID + +class CommonConvertersTest : BaseTest() { + private val converters = CommonConverters() + + @Test + fun `int list conversion`() { + converters.apply { + val orig = listOf(1, 2, 3) + val raw = "[1,2,3]" + fromIntList(orig) shouldBe raw + toIntList(raw) shouldBe orig + } + } + + @Test + fun `UUID conversion`() { + converters.apply { + val orig = UUID.fromString("123e4567-e89b-12d3-a456-426614174000") + val raw = "123e4567-e89b-12d3-a456-426614174000" + fromUUID(orig) shouldBe raw + toUUID(raw) shouldBe orig + } + } + + @Test + fun `path conversion`() { + converters.apply { + val orig = File("/row/row/row/your/boat") + val raw = "/row/row/row/your/boat" + fromPath(orig) shouldBe raw + toPath(raw) shouldBe orig + } + } + + @Test + fun `local date conversion`() { + converters.apply { + val orig = LocalDate.parse("2222-12-31") + val raw = "2222-12-31" + fromLocalDate(orig) shouldBe raw + toLocalDate(raw) shouldBe orig + } + } + + @Test + fun `local time conversion`() { + converters.apply { + val orig = LocalTime.parse("23:59") + val raw = "23:59:00.000" + fromLocalTime(orig) shouldBe raw + toLocalTime(raw) shouldBe orig + } + } + + @Test + fun `instant conversion`() { + converters.apply { + val orig = Instant.EPOCH + val raw = "1970-01-01T00:00:00.000Z" + fromInstant(orig) shouldBe raw + toInstant(raw) shouldBe orig + } + } + + @Test + fun `LocationCode conversion`() { + converters.apply { + val orig = LocationCode("DE") + val raw = "DE" + fromLocationCode(orig) shouldBe raw + toLocationCode(raw) shouldBe orig + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/errors/ExceptionExtensionsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/errors/ExceptionExtensionsTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..9af659ed6cfb1a590d248c5d58a30fb102db7946 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/errors/ExceptionExtensionsTest.kt @@ -0,0 +1,46 @@ +package de.rki.coronawarnapp.util.errors + +import io.kotest.matchers.shouldBe +import org.junit.Test +import testhelpers.BaseTest +import java.io.IOException + +class ExceptionExtensionsTest : BaseTest() { + + @Test + fun `exception without child cause`() { + val testException: Throwable = IndexOutOfBoundsException() + testException.causes().toList().size shouldBe 1 + testException.causes().toList() shouldBe listOf(IndexOutOfBoundsException()) + } + + @Test + fun `exception with multiple nested causes`() { + val inner: Throwable = + IllegalArgumentException(IOException(NullPointerException())) + val outer: Throwable = IllegalStateException(inner) + + outer.causes().toList().size shouldBe 4 + outer.causes().toList() shouldBe listOf( + IllegalStateException(IllegalArgumentException(IOException(NullPointerException()))), + IllegalArgumentException(IOException(NullPointerException())), + IOException(NullPointerException()), + NullPointerException() + ) + } + + @Test + fun `find specific exception in causes`() { + val inner: Throwable = + IllegalArgumentException(IOException(NullPointerException())) + val outer: Throwable = IllegalStateException(inner) + + outer.causes().toList().size shouldBe 4 + outer.causes().toList() shouldBe listOf( + IllegalStateException(IllegalArgumentException(IOException(NullPointerException()))), + IllegalArgumentException(IOException(NullPointerException())), + IOException(NullPointerException()), + NullPointerException() + ) + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelperTest.kt index 76cdd364785e7a32633eb744e3b58a0fb6f673c6..46786d0d90d29ee08a82c9e88dbeeb2a9663ecc3 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelperTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelperTest.kt @@ -171,24 +171,6 @@ class FormatterRiskHelperTest { ) } - private fun formatNextUpdateContentDescriptionBase( - iRiskLevelScore: Int?, - bIsBackgroundJobEnabled: Boolean?, - sValue: String - ) { - every { context.getString(R.string.risk_card_body_next_update) } returns R.string.risk_card_body_next_update.toString() - every { context.getString(R.string.accessibility_button) } returns R.string.accessibility_button.toString() - - val result = - formatNextUpdateContentDescription( - riskLevelScore = iRiskLevelScore, - isBackgroundJobEnabled = bIsBackgroundJobEnabled - ) - assertThat( - result, `is`(sValue) - ) - } - private fun formatRiskDetailsRiskLevelBodyBase( iRiskLevelScore: Int?, iDaysSinceLastExposure: Int?, @@ -978,79 +960,6 @@ class FormatterRiskHelperTest { ) } - @Test - fun formatNextUpdateContentDescription() { - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = null, - bIsBackgroundJobEnabled = null, - sValue = "" - ) - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.INCREASED_RISK, - bIsBackgroundJobEnabled = null, - sValue = "" - ) - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.UNKNOWN_RISK_OUTDATED_RESULTS, - bIsBackgroundJobEnabled = null, - sValue = "" - ) - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.NO_CALCULATION_POSSIBLE_TRACING_OFF, - bIsBackgroundJobEnabled = null, - sValue = "" - ) - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.LOW_LEVEL_RISK, - bIsBackgroundJobEnabled = null, - sValue = "" - ) - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.UNKNOWN_RISK_INITIAL, - bIsBackgroundJobEnabled = null, - sValue = "" - ) - - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = null, - bIsBackgroundJobEnabled = true, - sValue = "" - ) - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.INCREASED_RISK, - bIsBackgroundJobEnabled = true, - sValue = context.getString( - R.string.risk_card_body_next_update - ) + " " + context.getString( - R.string.accessibility_button - ) - ) - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.UNKNOWN_RISK_OUTDATED_RESULTS, - bIsBackgroundJobEnabled = true, - sValue = "" - ) - - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.LOW_LEVEL_RISK, - bIsBackgroundJobEnabled = true, - sValue = context.getString( - R.string.risk_card_body_next_update - ) + " " + context.getString( - R.string.accessibility_button - ) - ) - formatNextUpdateContentDescriptionBase( - iRiskLevelScore = RiskLevelConstants.UNKNOWN_RISK_INITIAL, - bIsBackgroundJobEnabled = true, - sValue = context.getString( - R.string.risk_card_body_next_update - ) + " " + context.getString( - R.string.accessibility_button - ) - ) - } - @Test fun formatRiskDetailsRiskLevelBody() { formatRiskDetailsRiskLevelBodyBase( diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelperTest.kt index 0d61cfb3769eea89f2ef343111a965660c8b25b1..61f8adb4086775c585955ee01f6dc7aacc9a0223 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelperTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelperTest.kt @@ -71,7 +71,6 @@ class FormatterSettingsHelperTest { private fun formatTracingStatusBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean, iValue: Int ) { @@ -82,7 +81,6 @@ class FormatterSettingsHelperTest { val result = formatTracingStatusText( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) assertThat(result, `is`((context.getString(iValue)))) @@ -91,12 +89,10 @@ class FormatterSettingsHelperTest { private fun formatTracingDescriptionBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean, iValue: Int ) { every { context.getString(R.string.settings_tracing_body_bluetooth_inactive) } returns R.string.settings_tracing_body_bluetooth_inactive.toString() - every { context.getString(R.string.settings_tracing_body_connection_inactive) } returns R.string.settings_tracing_body_connection_inactive.toString() every { context.getString(R.string.settings_tracing_body_active) } returns R.string.settings_tracing_body_active.toString() every { context.getString(R.string.settings_tracing_body_inactive) } returns R.string.settings_tracing_body_inactive.toString() every { context.getString(R.string.settings_tracing_body_inactive_location) } returns R.string.settings_tracing_body_inactive_location.toString() @@ -104,7 +100,6 @@ class FormatterSettingsHelperTest { val result = formatTracingDescription( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) @@ -114,12 +109,10 @@ class FormatterSettingsHelperTest { private fun formatTracingContentDescriptionBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean, sValue: String ) { every { context.getString(R.string.settings_tracing_body_bluetooth_inactive) } returns R.string.settings_tracing_body_bluetooth_inactive.toString() - every { context.getString(R.string.settings_tracing_body_connection_inactive) } returns R.string.settings_tracing_body_connection_inactive.toString() every { context.getString(R.string.settings_tracing_body_active) } returns R.string.settings_tracing_body_active.toString() every { context.getString(R.string.settings_tracing_body_inactive) } returns R.string.settings_tracing_body_inactive.toString() every { context.getString(R.string.settings_tracing_body_inactive_location) } returns R.string.settings_tracing_body_inactive_location.toString() @@ -128,7 +121,6 @@ class FormatterSettingsHelperTest { val result = formatTracingContentDescription( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) assertThat( @@ -174,14 +166,12 @@ class FormatterSettingsHelperTest { private fun formatTracingSwitchBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean, bValue: Boolean ) { val result = formatTracingSwitch( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) assertThat( @@ -192,14 +182,12 @@ class FormatterSettingsHelperTest { private fun formatTracingSwitchEnabledBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean, bValue: Boolean ) { val result = formatTracingSwitchEnabled( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) assertThat( @@ -210,16 +198,14 @@ class FormatterSettingsHelperTest { private fun formatTracingIconBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean ) { every { context.getDrawable(R.drawable.ic_settings_tracing_bluetooth_inactive) } returns drawable - every { context.getDrawable(R.drawable.ic_settings_tracing_connection_inactive) } returns drawable every { context.getDrawable(R.drawable.ic_settings_tracing_active) } returns drawable every { context.getDrawable(R.drawable.ic_settings_tracing_inactive) } returns drawable val result = - formatTracingIcon(tracing = bTracing, bluetooth = bBluetooth, connection = bConnection, location = bLocation) + formatTracingIcon(tracing = bTracing, bluetooth = bBluetooth, location = bLocation) assertThat( result, CoreMatchers.isA(Int::class.java) ) @@ -228,7 +214,6 @@ class FormatterSettingsHelperTest { private fun formatTracingIconColorBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean, iColor: Int ) { @@ -238,7 +223,6 @@ class FormatterSettingsHelperTest { val result = formatTracingIconColor( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) assertThat( @@ -249,18 +233,15 @@ class FormatterSettingsHelperTest { private fun formatTracingStatusImageBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean ) { every { context.getDrawable(R.drawable.ic_settings_illustration_bluetooth_off) } returns drawable - every { context.getDrawable(R.drawable.ic_settings_illustration_connection_off) } returns drawable every { context.getDrawable(R.drawable.ic_illustration_tracing_on) } returns drawable every { context.getDrawable(R.drawable.ic_settings_illustration_tracing_off) } returns drawable val result = formatTracingStatusImage( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) assertThat( @@ -268,32 +249,15 @@ class FormatterSettingsHelperTest { ) } - private fun formatTracingStatusConnectionBase( - bTracing: Boolean, - bBluetooth: Boolean, - bConnection: Boolean, - bLocation: Boolean - ) { - val result = formatTracingStatusConnection( - tracing = bTracing, - bluetooth = bBluetooth, - connection = bConnection, - location = bLocation - ) - assertThat(true, `is`(result > -1)) - } - private fun formatTracingStatusVisibilityTracingBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean ) { val result = formatTracingStatusVisibilityTracing( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) assertThat(true, `is`(result > -1)) @@ -302,14 +266,12 @@ class FormatterSettingsHelperTest { private fun formatTracingStatusVisibilityBluetoothBase( bTracing: Boolean, bBluetooth: Boolean, - bConnection: Boolean, bLocation: Boolean ) { val result = formatTracingStatusVisibilityBluetooth( tracing = bTracing, bluetooth = bBluetooth, - connection = bConnection, location = bLocation ) assertThat(true, `is`(result > -1)) @@ -406,74 +368,66 @@ class FormatterSettingsHelperTest { @Test fun formatTracingStatusText() { - // When tracing is true, bluetooth is true, connection is true, location is true + // When tracing is true, bluetooth is true, location is true formatTracingStatusBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = true, iValue = R.string.settings_tracing_status_active ) - // When tracing is false, bluetooth is false, connection is false, location is false + // When tracing is false, bluetooth is false, location is false formatTracingStatusBase( bTracing = false, bBluetooth = false, - bConnection = false, bLocation = false, iValue = R.string.settings_tracing_status_inactive ) - // When tracing is true, bluetooth is false, connection is false, location is true + // When tracing is true, bluetooth is false, location is true formatTracingStatusBase( bTracing = true, bBluetooth = false, - bConnection = false, bLocation = true, iValue = R.string.settings_tracing_status_restricted ) - // When tracing is true, bluetooth is true, connection is false, location is true + // When tracing is true, bluetooth is true, location is true formatTracingStatusBase( bTracing = true, bBluetooth = true, - bConnection = false, bLocation = true, - iValue = R.string.settings_tracing_status_restricted + iValue = R.string.settings_tracing_status_active ) - // When tracing is false, bluetooth is true, connection is false, location is false + // When tracing is false, bluetooth is true, location is false formatTracingStatusBase( bTracing = false, bBluetooth = true, - bConnection = false, bLocation = false, iValue = R.string.settings_tracing_status_inactive ) - // When tracing is false, bluetooth is true, connection is true, location is true + // When tracing is false, bluetooth is true, location is true formatTracingStatusBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = true, iValue = R.string.settings_tracing_status_inactive ) - // When tracing is true, bluetooth is false, connection is true, location is true + // When tracing is true, bluetooth is false, location is true formatTracingStatusBase( bTracing = true, bBluetooth = false, - bConnection = true, bLocation = true, iValue = R.string.settings_tracing_status_restricted ) - // When tracing is false, bluetooth is false, connection is true, location is true + // When tracing is false, bluetooth is false, location is true formatTracingStatusBase( bTracing = false, bBluetooth = false, - bConnection = true, bLocation = true, iValue = R.string.settings_tracing_status_inactive ) @@ -481,92 +435,74 @@ class FormatterSettingsHelperTest { @Test fun formatTracingDescription() { - // When tracing is true, bluetooth is true, connection is true, location is true + // When tracing is true, bluetooth is true, location is true formatTracingDescriptionBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = true, iValue = R.string.settings_tracing_body_active ) - // When tracing is false, bluetooth is false, connection is false, location is false + // When tracing is false, bluetooth is false, location is false formatTracingDescriptionBase( bTracing = false, bBluetooth = false, - bConnection = false, bLocation = false, iValue = R.string.settings_tracing_body_inactive ) - // When tracing is true, bluetooth is false, connection is false, location is true + // When tracing is true, bluetooth is false, location is true formatTracingDescriptionBase( bTracing = true, bBluetooth = false, - bConnection = false, bLocation = true, iValue = R.string.settings_tracing_body_bluetooth_inactive ) - // When tracing is true, bluetooth is true, connection is false, location is true - formatTracingDescriptionBase( - bTracing = true, - bBluetooth = true, - bConnection = false, - bLocation = true, - iValue = R.string.settings_tracing_body_connection_inactive - ) - - // When tracing is false, bluetooth is true, connection is false, location is true + // When tracing is false, bluetooth is true, location is true formatTracingDescriptionBase( bTracing = false, bBluetooth = true, - bConnection = false, bLocation = true, iValue = R.string.settings_tracing_body_inactive ) - // When tracing is false, bluetooth is true, connection is true, location is true + // When tracing is false, bluetooth is true, location is true formatTracingDescriptionBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = true, iValue = R.string.settings_tracing_body_inactive ) - // When tracing is true, bluetooth is false, connection is true, location is true + // When tracing is true, bluetooth is false, location is true formatTracingDescriptionBase( bTracing = true, bBluetooth = false, - bConnection = true, bLocation = true, iValue = R.string.settings_tracing_body_bluetooth_inactive ) - // When tracing is false, bluetooth is false, connection is true, location is true + // When tracing is false, bluetooth is false, location is true formatTracingDescriptionBase( bTracing = false, bBluetooth = false, - bConnection = true, bLocation = true, iValue = R.string.settings_tracing_body_inactive ) - // When tracing is true, bluetooth is true, connection is true, location is false + // When tracing is true, bluetooth is true, location is false formatTracingDescriptionBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = false, iValue = R.string.settings_tracing_body_inactive_location ) - // When tracing is false, bluetooth is true, connection is true, location is false + // When tracing is false, bluetooth is true, location is false formatTracingDescriptionBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = false, iValue = R.string.settings_tracing_body_inactive ) @@ -574,92 +510,74 @@ class FormatterSettingsHelperTest { @Test fun formatTracingContentDescription() { - // When tracing is true, bluetooth is true, connection is true, location is true + // When tracing is true, bluetooth is true, location is true formatTracingContentDescriptionBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = true, sValue = R.string.settings_tracing_body_active.toString() + " " + R.string.accessibility_button.toString() ) - // When tracing is false, bluetooth is false, connection is false, location is true + // When tracing is false, bluetooth is false, location is true formatTracingContentDescriptionBase( bTracing = false, bBluetooth = false, - bConnection = false, bLocation = true, sValue = R.string.settings_tracing_body_inactive.toString() + " " + R.string.accessibility_button.toString() ) - // When tracing is true, bluetooth is false, connection is false, location is true + // When tracing is true, bluetooth is false, location is true formatTracingContentDescriptionBase( bTracing = true, bBluetooth = false, - bConnection = false, bLocation = true, sValue = R.string.settings_tracing_body_bluetooth_inactive.toString() + " " + R.string.accessibility_button.toString() ) - // When tracing is true, bluetooth is true, connection is false, location is true - formatTracingContentDescriptionBase( - bTracing = true, - bBluetooth = true, - bConnection = false, - bLocation = true, - sValue = R.string.settings_tracing_body_connection_inactive.toString() + " " + R.string.accessibility_button.toString() - ) - - // When tracing is false, bluetooth is true, connection is false, location is true + // When tracing is false, bluetooth is true, location is true formatTracingContentDescriptionBase( bTracing = false, bBluetooth = true, - bConnection = false, bLocation = true, sValue = R.string.settings_tracing_body_inactive.toString() + " " + R.string.accessibility_button.toString() ) - // When tracing is false, bluetooth is true, connection is true, location is true + // When tracing is false, bluetooth is true, location is true formatTracingContentDescriptionBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = true, sValue = R.string.settings_tracing_body_inactive.toString() + " " + R.string.accessibility_button.toString() ) - // When tracing is true, bluetooth is false, connection is true, location is true + // When tracing is true, bluetooth is false, location is true formatTracingContentDescriptionBase( bTracing = true, bBluetooth = false, - bConnection = true, bLocation = true, sValue = R.string.settings_tracing_body_bluetooth_inactive.toString() + " " + R.string.accessibility_button.toString() ) - // When tracing is false, bluetooth is false, connection is true, location is true + // When tracing is false, bluetooth is false, location is true formatTracingContentDescriptionBase( bTracing = false, bBluetooth = false, - bConnection = true, bLocation = true, sValue = R.string.settings_tracing_body_inactive.toString() + " " + R.string.accessibility_button.toString() ) - // When tracing is false, bluetooth is true, connection is true, location is false + // When tracing is false, bluetooth is true, location is false formatTracingContentDescriptionBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = false, sValue = R.string.settings_tracing_body_inactive.toString() + " " + R.string.accessibility_button.toString() ) - // When tracing is true, bluetooth is true, connection is true, location is false + // When tracing is true, bluetooth is true, location is false formatTracingContentDescriptionBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = false, sValue = R.string.settings_tracing_body_inactive_location.toString() + " " + R.string.accessibility_button.toString() ) @@ -697,7 +615,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = true, bValue = true ) @@ -705,7 +622,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = false, bBluetooth = false, - bConnection = false, bLocation = true, bValue = false ) @@ -713,7 +629,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = false, bBluetooth = false, - bConnection = true, bLocation = true, bValue = false ) @@ -721,7 +636,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = false, bBluetooth = true, - bConnection = false, bLocation = true, bValue = false ) @@ -729,7 +643,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = true, bValue = false ) @@ -737,7 +650,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = true, bBluetooth = false, - bConnection = false, bLocation = true, bValue = false ) @@ -745,7 +657,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = true, bBluetooth = false, - bConnection = true, bLocation = true, bValue = false ) @@ -753,15 +664,13 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = true, bBluetooth = true, - bConnection = false, bLocation = true, - bValue = false + bValue = true ) formatTracingSwitchBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = false, bValue = false ) @@ -769,7 +678,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = false, bValue = false ) @@ -781,7 +689,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchEnabledBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = true, bValue = true ) @@ -789,7 +696,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchEnabledBase( bTracing = false, bBluetooth = false, - bConnection = false, bLocation = true, bValue = true ) @@ -797,7 +703,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchEnabledBase( bTracing = false, bBluetooth = false, - bConnection = true, bLocation = true, bValue = true ) @@ -805,7 +710,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchEnabledBase( bTracing = false, bBluetooth = true, - bConnection = false, bLocation = true, bValue = true ) @@ -813,7 +717,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchEnabledBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = true, bValue = true ) @@ -821,7 +724,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchEnabledBase( bTracing = true, bBluetooth = false, - bConnection = false, bLocation = true, bValue = false ) @@ -829,7 +731,6 @@ class FormatterSettingsHelperTest { formatTracingSwitchEnabledBase( bTracing = true, bBluetooth = false, - bConnection = true, bLocation = true, bValue = false ) @@ -837,31 +738,30 @@ class FormatterSettingsHelperTest { formatTracingSwitchEnabledBase( bTracing = true, bBluetooth = true, - bConnection = false, bLocation = true, - bValue = false + bValue = true ) } @Test fun formatTracingIcon() { - formatTracingIconBase(bTracing = true, bBluetooth = true, bConnection = true, bLocation = true) + formatTracingIconBase(bTracing = true, bBluetooth = true, bLocation = true) - formatTracingIconBase(bTracing = false, bBluetooth = false, bConnection = false, bLocation = true) + formatTracingIconBase(bTracing = false, bBluetooth = false, bLocation = true) - formatTracingIconBase(bTracing = false, bBluetooth = false, bConnection = true, bLocation = true) + formatTracingIconBase(bTracing = false, bBluetooth = false, bLocation = true) - formatTracingIconBase(bTracing = false, bBluetooth = true, bConnection = false, bLocation = true) + formatTracingIconBase(bTracing = false, bBluetooth = true, bLocation = true) - formatTracingIconBase(bTracing = false, bBluetooth = true, bConnection = true, bLocation = true) + formatTracingIconBase(bTracing = false, bBluetooth = true, bLocation = true) - formatTracingIconBase(bTracing = true, bBluetooth = false, bConnection = false, bLocation = true) + formatTracingIconBase(bTracing = true, bBluetooth = false, bLocation = true) - formatTracingIconBase(bTracing = true, bBluetooth = false, bConnection = true, bLocation = true) + formatTracingIconBase(bTracing = true, bBluetooth = false, bLocation = true) - formatTracingIconBase(bTracing = true, bBluetooth = true, bConnection = false, bLocation = true) + formatTracingIconBase(bTracing = true, bBluetooth = true, bLocation = true) - formatTracingIconBase(bTracing = true, bBluetooth = true, bConnection = true, bLocation = false) + formatTracingIconBase(bTracing = true, bBluetooth = true, bLocation = false) } @Test @@ -870,7 +770,6 @@ class FormatterSettingsHelperTest { formatTracingIconColorBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = true, iColor = R.color.colorAccentTintIcon ) @@ -878,7 +777,6 @@ class FormatterSettingsHelperTest { formatTracingIconColorBase( bTracing = false, bBluetooth = false, - bConnection = false, bLocation = true, iColor = R.color.colorTextSemanticRed ) @@ -886,7 +784,6 @@ class FormatterSettingsHelperTest { formatTracingIconColorBase( bTracing = false, bBluetooth = false, - bConnection = true, bLocation = true, iColor = R.color.colorTextSemanticRed ) @@ -894,7 +791,6 @@ class FormatterSettingsHelperTest { formatTracingIconColorBase( bTracing = false, bBluetooth = true, - bConnection = false, bLocation = true, iColor = R.color.colorTextSemanticRed ) @@ -902,7 +798,6 @@ class FormatterSettingsHelperTest { formatTracingIconColorBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = true, iColor = R.color.colorTextSemanticRed ) @@ -910,7 +805,6 @@ class FormatterSettingsHelperTest { formatTracingIconColorBase( bTracing = true, bBluetooth = false, - bConnection = false, bLocation = true, iColor = R.color.colorTextSemanticRed ) @@ -918,15 +812,6 @@ class FormatterSettingsHelperTest { formatTracingIconColorBase( bTracing = true, bBluetooth = false, - bConnection = true, - bLocation = true, - iColor = R.color.colorTextSemanticRed - ) - - formatTracingIconColorBase( - bTracing = true, - bBluetooth = true, - bConnection = false, bLocation = true, iColor = R.color.colorTextSemanticRed ) @@ -934,7 +819,6 @@ class FormatterSettingsHelperTest { formatTracingIconColorBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = false, iColor = R.color.colorTextSemanticRed ) @@ -942,40 +826,21 @@ class FormatterSettingsHelperTest { @Test fun formatTracingStatusImage() { - formatTracingStatusImageBase(bTracing = true, bBluetooth = true, bConnection = true, bLocation = true) + formatTracingStatusImageBase(bTracing = true, bBluetooth = true, bLocation = true) - formatTracingStatusImageBase(bTracing = false, bBluetooth = false, bConnection = false, bLocation = true) + formatTracingStatusImageBase(bTracing = false, bBluetooth = false, bLocation = true) - formatTracingStatusImageBase(bTracing = false, bBluetooth = false, bConnection = true, bLocation = true) + formatTracingStatusImageBase(bTracing = false, bBluetooth = false, bLocation = true) - formatTracingStatusImageBase(bTracing = false, bBluetooth = true, bConnection = false, bLocation = true) + formatTracingStatusImageBase(bTracing = false, bBluetooth = true, bLocation = true) - formatTracingStatusImageBase(bTracing = false, bBluetooth = true, bConnection = true, bLocation = true) + formatTracingStatusImageBase(bTracing = false, bBluetooth = true, bLocation = true) - formatTracingStatusImageBase(bTracing = true, bBluetooth = false, bConnection = false, bLocation = true) + formatTracingStatusImageBase(bTracing = true, bBluetooth = false, bLocation = true) - formatTracingStatusImageBase(bTracing = true, bBluetooth = false, bConnection = true, bLocation = true) + formatTracingStatusImageBase(bTracing = true, bBluetooth = false, bLocation = true) - formatTracingStatusImageBase(bTracing = true, bBluetooth = true, bConnection = false, bLocation = true) - } - - @Test - fun formatTracingStatusConnection() { - formatTracingStatusConnectionBase(bTracing = true, bBluetooth = true, bConnection = true, bLocation = true) - - formatTracingStatusConnectionBase(bTracing = false, bBluetooth = false, bConnection = false, bLocation = true) - - formatTracingStatusConnectionBase(bTracing = false, bBluetooth = false, bConnection = true, bLocation = true) - - formatTracingStatusConnectionBase(bTracing = false, bBluetooth = true, bConnection = false, bLocation = true) - - formatTracingStatusConnectionBase(bTracing = false, bBluetooth = true, bConnection = true, bLocation = true) - - formatTracingStatusConnectionBase(bTracing = true, bBluetooth = false, bConnection = false, bLocation = true) - - formatTracingStatusConnectionBase(bTracing = true, bBluetooth = false, bConnection = true, bLocation = true) - - formatTracingStatusConnectionBase(bTracing = true, bBluetooth = true, bConnection = false, bLocation = true) + formatTracingStatusImageBase(bTracing = true, bBluetooth = true, bLocation = true) } @Test @@ -983,48 +848,38 @@ class FormatterSettingsHelperTest { formatTracingStatusVisibilityBluetoothBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = true ) formatTracingStatusVisibilityBluetoothBase( bTracing = false, bBluetooth = false, - bConnection = false, bLocation = true ) formatTracingStatusVisibilityBluetoothBase( bTracing = false, bBluetooth = false, - bConnection = true, bLocation = true ) formatTracingStatusVisibilityBluetoothBase( bTracing = false, bBluetooth = true, - bConnection = false, bLocation = true ) formatTracingStatusVisibilityBluetoothBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = true ) formatTracingStatusVisibilityBluetoothBase( bTracing = true, bBluetooth = false, - bConnection = false, bLocation = true ) - - formatTracingStatusConnectionBase(bTracing = true, bBluetooth = false, bConnection = true, bLocation = true) - - formatTracingStatusConnectionBase(bTracing = true, bBluetooth = true, bConnection = false, bLocation = true) } @Test @@ -1032,56 +887,48 @@ class FormatterSettingsHelperTest { formatTracingStatusVisibilityTracingBase( bTracing = true, bBluetooth = true, - bConnection = true, bLocation = true ) formatTracingStatusVisibilityTracingBase( bTracing = false, bBluetooth = false, - bConnection = false, bLocation = true ) formatTracingStatusVisibilityTracingBase( bTracing = false, bBluetooth = false, - bConnection = true, bLocation = true ) formatTracingStatusVisibilityTracingBase( bTracing = false, bBluetooth = true, - bConnection = false, bLocation = true ) formatTracingStatusVisibilityTracingBase( bTracing = false, bBluetooth = true, - bConnection = true, bLocation = true ) formatTracingStatusVisibilityTracingBase( bTracing = true, bBluetooth = false, - bConnection = false, bLocation = true ) formatTracingStatusVisibilityTracingBase( bTracing = true, bBluetooth = false, - bConnection = true, bLocation = true ) formatTracingStatusVisibilityTracingBase( bTracing = true, bBluetooth = true, - bConnection = false, bLocation = true ) } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/TracingStatusHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/TracingStatusHelperTest.kt index 372fc4f94adc436de42a2ca0f92bbcfbdd88050d..ca7d152b56c5b5266f1d159b10b074e6708cafe0 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/TracingStatusHelperTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/TracingStatusHelperTest.kt @@ -8,55 +8,43 @@ class TracingStatusHelperTest { @Test fun testTracingActiveAllOn() { - val result = tracingStatusHelper(tracing = true, bluetooth = true, connection = true, location = true) + val result = tracingStatusHelper(tracing = true, bluetooth = true, location = true) assertThat(result, `is`((TracingStatusHelper.TRACING_ACTIVE))) } @Test fun testTracingInactiveWhenAllOff() { - val result = tracingStatusHelper(tracing = false, bluetooth = false, connection = false, location = true) + val result = tracingStatusHelper(tracing = false, bluetooth = false, location = true) assertThat(result, `is`((TracingStatusHelper.TRACING_INACTIVE))) } @Test - fun testTracingInactiveWhenTracingOffBluetoothOffConnectionOn() { - val result = tracingStatusHelper(tracing = false, bluetooth = false, connection = true, location = true) + fun testTracingInactiveWhenTracingOffBluetoothOff() { + val result = tracingStatusHelper(tracing = false, bluetooth = false, location = true) assertThat(result, `is`((TracingStatusHelper.TRACING_INACTIVE))) } @Test - fun testTracingInactiveWhenTracingOffBluetoothOnConnectionOff() { - val result = tracingStatusHelper(tracing = false, bluetooth = true, connection = false, location = true) + fun testTracingInactiveWhenTracingOffBluetoothOn() { + val result = tracingStatusHelper(tracing = false, bluetooth = true, location = true) assertThat(result, `is`((TracingStatusHelper.TRACING_INACTIVE))) } @Test - fun testTracingInactiveWhenTracingOffBluetoothOnConnectionOn() { - val result = tracingStatusHelper(tracing = false, bluetooth = true, connection = true, location = true) - assertThat(result, `is`((TracingStatusHelper.TRACING_INACTIVE))) - } - - @Test - fun testBluetoothInactiveWhenTracingOnBluetoothOffConnectionOn() { - val result = tracingStatusHelper(tracing = true, bluetooth = false, connection = true, location = true) + fun testBluetoothInactiveWhenTracingOnBluetoothOff() { + val result = tracingStatusHelper(tracing = true, bluetooth = false, location = true) assertThat(result, `is`((TracingStatusHelper.BLUETOOTH))) } @Test - fun testConnectionInactiveWhenTracingOnBluetoothOffConnectionOff() { - val result = tracingStatusHelper(tracing = true, bluetooth = true, connection = false, location = true) - assertThat(result, `is`((TracingStatusHelper.CONNECTION))) - } - - @Test - fun testConnectionInactiveWhenTracingOffBluetoothOnConnectionOnLocationOff() { - val result = tracingStatusHelper(tracing = false, bluetooth = true, connection = true, location = false) + fun testConnectionInactiveWhenTracingOffBluetoothOnLocationOff() { + val result = tracingStatusHelper(tracing = false, bluetooth = true, location = false) assertThat(result, `is`((TracingStatusHelper.TRACING_INACTIVE))) } @Test - fun testConnectionInactiveWhenTracingOnBluetoothOnConnectionOnLocationOff() { - val result = tracingStatusHelper(tracing = true, bluetooth = true, connection = true, location = false) + fun testConnectionInactiveWhenTracingOnBluetoothOnLocationOff() { + val result = tracingStatusHelper(tracing = true, bluetooth = true, location = false) assertThat(result, `is`((TracingStatusHelper.LOCATION))) } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactoryTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..a2c7fd375dada6f1af5880ae0b114d0373a4ea77 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptedPreferencesFactoryTest.kt @@ -0,0 +1,35 @@ +package de.rki.coronawarnapp.util.security + +import android.content.Context +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.mockk.Called +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class EncryptedPreferencesFactoryTest : BaseTest() { + @MockK lateinit var context: Context + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + @Test + fun `sideeffect free init`() { + shouldNotThrowAny { + EncryptedPreferencesFactory(context) + } + verify { context.getSharedPreferences(any(), any()) wasNot Called } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptionResetToolTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptionResetToolTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..7daab4ac94863c9880ca2387accf09aec4a4710b --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/EncryptionResetToolTest.kt @@ -0,0 +1,269 @@ +package de.rki.coronawarnapp.util.security + +import android.content.Context +import de.rki.coronawarnapp.exception.CwaSecurityException +import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import testhelpers.preferences.MockSharedPreferences +import java.io.File +import java.security.GeneralSecurityException +import java.security.KeyStoreException + +class EncryptionResetToolTest : BaseIOTest() { + + @MockK + lateinit var context: Context + private lateinit var mockPreferences: MockSharedPreferences + + private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) + private val privateFilesDir = File(testDir, "files") + private val encryptedPrefsFile = File(testDir, "shared_prefs/shared_preferences_cwa.xml") + private val encryptedDatabaseFile = File(testDir, "databases/coronawarnapp-db") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + every { context.filesDir } returns privateFilesDir + every { context.getDatabasePath("coronawarnapp-db") } returns encryptedDatabaseFile + + mockPreferences = MockSharedPreferences() + every { + context.getSharedPreferences( + "encryption_error_reset_tool", + Context.MODE_PRIVATE + ) + } returns mockPreferences + } + + @AfterEach + fun teardown() { + clearAllMocks() + + testDir.deleteRecursively() + } + + private fun createInstance() = EncryptionErrorResetTool( + context = context + ) + + private fun createMockFiles() { + encryptedPrefsFile.apply { + parentFile!!.mkdirs() + createNewFile() + exists() shouldBe true + } + encryptedDatabaseFile.apply { + parentFile!!.mkdirs() + createNewFile() + exists() shouldBe true + } + } + + @Test + fun `initialiation is sideeffect free`() { + createMockFiles() + + createInstance() + + encryptedPrefsFile.exists() shouldBe true + encryptedDatabaseFile.exists() shouldBe true + mockPreferences.dataMapPeek shouldBe emptyMap() + } + + @Test + fun `reset dialog show flag is writable and persisted`() { + val instance = createInstance() + mockPreferences.dataMapPeek["ea1851.reset.shownotice"] shouldBe null + instance.isResetNoticeToBeShown shouldBe false + + instance.isResetNoticeToBeShown = true + mockPreferences.dataMapPeek["ea1851.reset.shownotice"] shouldBe true + instance.isResetNoticeToBeShown shouldBe true + + createInstance().isResetNoticeToBeShown shouldBe true + + instance.isResetNoticeToBeShown = false + mockPreferences.dataMapPeek["ea1851.reset.shownotice"] shouldBe false + instance.isResetNoticeToBeShown shouldBe false + } + + @Test + fun `reset is not warranted by default`() { + createMockFiles() + + createInstance().tryResetIfNecessary(Exception()) + + encryptedPrefsFile.exists() shouldBe true + encryptedDatabaseFile.exists() shouldBe true + } + + /** + Based on https://github.com/corona-warn-app/cwa-app-android/issues/642#issuecomment-650199424 + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: java.lang.SecurityException: Could not decrypt value. decryption failed + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at androidx.security.crypto.EncryptedSharedPreferences.getDecryptedObject(EncryptedSharedPreferences.java:33) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at androidx.security.crypto.EncryptedSharedPreferences.getBoolean(EncryptedSharedPreferences.java:1) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at de.rki.coronawarnapp.update.UpdateChecker.checkForUpdate(UpdateChecker.kt:23) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at de.rki.coronawarnapp.update.UpdateChecker$checkForUpdate$1.invokeSuspend(Unknown Source:11) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:2) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:18) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:809) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at android.os.Looper.loop(Looper.java:166) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7377) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:963) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: Caused by: java.security.GeneralSecurityException: decryption failed + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at com.google.crypto.tink.aead.AeadWrapper$WrappedAead.decrypt(AeadWrapper.java:15) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: at androidx.security.crypto.EncryptedSharedPreferences.getDecryptedObject(EncryptedSharedPreferences.java:5) + 06-23 21:52:51.681 10311 17331 17331 E AndroidRuntime: ... 12 more + */ + @Test + fun `reset is warranted if the first exception after upgrade was a GeneralSecurityException`() { + // We only perform the reset for users who encounter it the first time after the upgrade + createMockFiles() + + createInstance().tryResetIfNecessary( + GeneralSecurityException("decryption failed") + ) shouldBe true + + createInstance().tryResetIfNecessary( + GeneralSecurityException("decryption failed") + ) shouldBe false + + encryptedPrefsFile.exists() shouldBe false + encryptedDatabaseFile.exists() shouldBe false + + mockPreferences.dataMapPeek.apply { + this["ea1851.reset.performedAt"] shouldNotBe null + this["ea1851.reset.windowconsumed"] shouldBe true + this["ea1851.reset.shownotice"] shouldBe true + } + } + + @Test + fun `reset is also warranted if the exception has our desired exception as cause`() { + // We only perform the reset for users who encounter it the first time after the upgrade + createMockFiles() + + createInstance().tryResetIfNecessary( + CwaSecurityException(RuntimeException(GeneralSecurityException("decryption failed"))) + ) shouldBe true + + encryptedPrefsFile.exists() shouldBe false + encryptedDatabaseFile.exists() shouldBe false + + mockPreferences.dataMapPeek.apply { + this["ea1851.reset.performedAt"] shouldNotBe null + this["ea1851.reset.windowconsumed"] shouldBe true + this["ea1851.reset.shownotice"] shouldBe true + } + } + + @Test + fun `we want only a specific type of GeneralSecurityException`() { + createMockFiles() + + createInstance().tryResetIfNecessary( + GeneralSecurityException("2020 failed") + ) shouldBe false + + encryptedPrefsFile.exists() shouldBe true + encryptedDatabaseFile.exists() shouldBe true + + mockPreferences.dataMapPeek.apply { + this["ea1851.reset.performedAt"] shouldBe null + this["ea1851.reset.windowconsumed"] shouldBe true + this["ea1851.reset.shownotice"] shouldBe null + } + } + + @Test + fun `reset is not warranted for GeneralSecurityException that happened later`() { + createMockFiles() + + createInstance().tryResetIfNecessary(KeyStoreException()) shouldBe false + + createInstance().tryResetIfNecessary( + GeneralSecurityException("decryption failed") + ) shouldBe false + + encryptedPrefsFile.exists() shouldBe true + encryptedDatabaseFile.exists() shouldBe true + + mockPreferences.dataMapPeek.apply { + this["ea1851.reset.performedAt"] shouldBe null + this["ea1851.reset.windowconsumed"] shouldBe true + this["ea1851.reset.shownotice"] shouldBe null + } + } + + @Test + fun `reset is not warranted if the error fits, but there is no existing preference file`() { + encryptedPrefsFile.exists() shouldBe false + + createInstance().tryResetIfNecessary( + GeneralSecurityException("decryption failed") + ) shouldBe false + + encryptedPrefsFile.exists() shouldBe false + encryptedDatabaseFile.exists() shouldBe false + + mockPreferences.dataMapPeek.apply { + this["ea1851.reset.performedAt"] shouldBe null + this["ea1851.reset.windowconsumed"] shouldBe true + this["ea1851.reset.shownotice"] shouldBe null + } + } + + @Test + fun `the reset is considered failed if the preferences can not be deleted`() { + createMockFiles() + encryptedPrefsFile.delete() + encryptedPrefsFile.mkdir() // Can't delete directories with children via `delete()` + File(encryptedPrefsFile, "prevent deletion").createNewFile() + + createInstance().tryResetIfNecessary( + GeneralSecurityException("decryption failed") + ) shouldBe false + + encryptedPrefsFile.exists() shouldBe true + encryptedDatabaseFile.exists() shouldBe true + + mockPreferences.dataMapPeek.apply { + this["ea1851.reset.performedAt"] shouldBe null + this["ea1851.reset.windowconsumed"] shouldBe true + this["ea1851.reset.shownotice"] shouldBe null + } + } + + @Test + fun `the reset is considered failed if the database exists and can not be deleted`() { + createMockFiles() + encryptedDatabaseFile.delete() + encryptedDatabaseFile.mkdir() // Can't delete directories with children via `delete()` + File(encryptedDatabaseFile, "prevent deletion").createNewFile() + + createInstance().tryResetIfNecessary( + GeneralSecurityException("decryption failed") + ) shouldBe false + + encryptedPrefsFile.exists() shouldBe false + encryptedDatabaseFile.exists() shouldBe true + + mockPreferences.dataMapPeek.apply { + this["ea1851.reset.performedAt"] shouldBe null + this["ea1851.reset.windowconsumed"] shouldBe true + this["ea1851.reset.shownotice"] shouldBe null + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/SecurityHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/SecurityHelperTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..8aefbcda323d2de64c1d8ec4456c7395371b8301 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/security/SecurityHelperTest.kt @@ -0,0 +1,97 @@ +package de.rki.coronawarnapp.util.security + +import android.content.SharedPreferences +import de.rki.coronawarnapp.util.di.ApplicationComponent +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.verify +import io.mockk.verifySequence +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class SecurityHelperTest : BaseTest() { + @MockK + lateinit var appComponent: ApplicationComponent + + @MockK + lateinit var errorResetTool: EncryptionErrorResetTool + + @MockK + lateinit var preferenceFactory: EncryptedPreferencesFactory + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + every { appComponent.errorResetTool } returns errorResetTool + every { appComponent.encryptedPreferencesFactory } returns preferenceFactory + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + @Test + fun `error free case is sideeffect free`() { + val sharedPreferences: SharedPreferences = mockk() + every { preferenceFactory.create("shared_preferences_cwa") } returns sharedPreferences + + SecurityHelper.encryptedPreferencesProvider(appComponent) shouldBe sharedPreferences + verify(exactly = 0) { errorResetTool.tryResetIfNecessary(any()) } + } + + @Test + fun `positive reset tool results cause a retry`() { + val ourPreferences: SharedPreferences = mockk() + var ourException: Exception? = null + every { preferenceFactory.create("shared_preferences_cwa") } answers { + if (ourException == null) { + ourException = Exception("99 bugs") + throw ourException!! + } else { + ourPreferences + } + } + every { errorResetTool.tryResetIfNecessary(any()) } returns true + + SecurityHelper.encryptedPreferencesProvider(appComponent) shouldBe ourPreferences + + verifySequence { + preferenceFactory.create(any()) + errorResetTool.tryResetIfNecessary(ourException!!) + preferenceFactory.create(any()) + } + } + + @Test + fun `negative reset tool results rethrow the exception`() { + val ourPreferences: SharedPreferences = mockk() + var ourException: Exception? = null + every { preferenceFactory.create("shared_preferences_cwa") } answers { + if (ourException == null) { + ourException = Exception("99 bugs") + throw ourException!! + } else { + ourPreferences + } + } + every { errorResetTool.tryResetIfNecessary(any()) } returns false + + shouldThrow<Exception> { + SecurityHelper.encryptedPreferencesProvider(appComponent) shouldBe ourPreferences + }.cause shouldBe ourException + + verifySequence { + preferenceFactory.create(any()) + errorResetTool.tryResetIfNecessary(ourException!!) + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/VerificationModuleTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/VerificationModuleTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..8ea767b587f35699e874af1e05f6b29094f5a493 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/VerificationModuleTest.kt @@ -0,0 +1,83 @@ +package de.rki.coronawarnapp.verification + +import android.content.Context +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import okhttp3.ConnectionSpec +import okhttp3.OkHttpClient +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import retrofit2.converter.gson.GsonConverterFactory +import testhelpers.BaseIOTest +import java.io.File + +class VerificationModuleTest : BaseIOTest() { + + @MockK lateinit var context: Context + + private val testDir = File(IO_TEST_BASEDIR, this::class.java.simpleName) + private val cacheFiles = File(testDir, "cache") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { context.cacheDir } returns cacheFiles + + testDir.mkdirs() + testDir.exists() shouldBe true + } + + @AfterEach + fun teardown() { + clearAllMocks() + testDir.deleteRecursively() + } + + private fun createModule() = VerificationModule() + + @Test + fun `side effect free instantiation`() { + shouldNotThrowAny { + createModule() + } + } + + @Test + fun `client creation uses connection specs`() { + val module = createModule() + + val specs = listOf(ConnectionSpec.MODERN_TLS) + val client = OkHttpClient.Builder().build() + + val newClient = module.cdnHttpClient( + defaultHttpClient = client, + connectionSpecs = specs + ) + + newClient.apply { + connectionSpecs shouldBe specs + } + } + + @Test + fun `api uses a cache`() { + val module = createModule() + + val client = OkHttpClient.Builder().build() + + module.provideVerificationApi( + context = context, + client = client, + url = "https://testurl", + gsonConverterFactory = GsonConverterFactory.create() + ) + + verify { context.cacheDir } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/server/VerificationApiV1Test.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/server/VerificationApiV1Test.kt new file mode 100644 index 0000000000000000000000000000000000000000..3fe5a0c47a1f30a09a681788c97646221d91821e --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/server/VerificationApiV1Test.kt @@ -0,0 +1,181 @@ +package de.rki.coronawarnapp.verification.server + +import android.content.Context +import de.rki.coronawarnapp.http.HttpModule +import de.rki.coronawarnapp.verification.VerificationModule +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.runBlocking +import okhttp3.ConnectionSpec +import okhttp3.mockwebserver.MockWebServer +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import testhelpers.extensions.toComparableJson +import testhelpers.extensions.toJsonResponse +import java.io.File +import java.util.concurrent.TimeUnit + +class VerificationApiV1Test : BaseIOTest() { + + @MockK private lateinit var context: Context + + private lateinit var webServer: MockWebServer + private lateinit var serverAddress: String + + private val testDir = File(IO_TEST_BASEDIR, this::class.java.simpleName) + private val cacheDir = File(testDir, "cache") + private val httpCacheDir = File(cacheDir, "http_verification") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { context.cacheDir } returns cacheDir + + webServer = MockWebServer() + webServer.start() + serverAddress = "http://${webServer.hostName}:${webServer.port}" + } + + @AfterEach + fun teardown() { + clearAllMocks() + webServer.shutdown() + testDir.deleteRecursively() + } + + private fun createAPI(): VerificationApiV1 { + val httpModule = HttpModule() + val defaultHttpClient = httpModule.defaultHttpClient() + val gsonConverterFactory = httpModule.provideGSONConverter() + + return VerificationModule().let { + val downloadHttpClient = it.cdnHttpClient( + defaultHttpClient, + listOf(ConnectionSpec.CLEARTEXT, ConnectionSpec.MODERN_TLS) + ) + it.provideVerificationApi( + context = context, + client = downloadHttpClient, + url = serverAddress, + gsonConverterFactory = gsonConverterFactory + ) + } + } + + @Test + fun `test getRegistrationToken`(): Unit = runBlocking { + val api = createAPI() + + """ + { + "registrationToken": "testRegistrationToken" + } + """.toJsonResponse().apply { webServer.enqueue(this) } + + val requestBody = VerificationApiV1.RegistrationTokenRequest( + keyType = "testKeyType", + key = "testKey", + requestPadding = "testRequestPadding" + ) + + api.getRegistrationToken( + fake = "0", + headerPadding = "testPadding", + requestBody + ) shouldBe VerificationApiV1.RegistrationTokenResponse( + registrationToken = "testRegistrationToken" + ) + + webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply { + headers["cwa-fake"] shouldBe "0" + headers["cwa-header-padding"] shouldBe "testPadding" + path shouldBe "/version/v1/registrationToken" + body.readUtf8() shouldBe """ + { + "keyType": "testKeyType", + "key": "testKey", + "requestPadding": "testRequestPadding" + } + """.toComparableJson() + } + + httpCacheDir.exists() shouldBe true + } + + @Test + fun `test getTestResult`(): Unit = runBlocking { + val api = createAPI() + + """ + { + "testResult": 1 + } + """.toJsonResponse().apply { webServer.enqueue(this) } + + val requestBody = VerificationApiV1.RegistrationRequest( + registrationToken = "testRegistrationToken", + requestPadding = "testRequestPadding" + ) + + api.getTestResult( + fake = "0", + headerPadding = "testPadding", + requestBody + ) shouldBe VerificationApiV1.TestResultResponse( + testResult = 1 + ) + + webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply { + headers["cwa-fake"] shouldBe "0" + headers["cwa-header-padding"] shouldBe "testPadding" + path shouldBe "/version/v1/testresult" + body.readUtf8() shouldBe """ + { + "registrationToken": "testRegistrationToken", + "requestPadding": "testRequestPadding" + } + """.toComparableJson() + } + } + + @Test + fun `test getTAN`(): Unit = runBlocking { + val api = createAPI() + + """ + { + "tan": "testTan" + } + """.toJsonResponse().apply { webServer.enqueue(this) } + + val requestBody = VerificationApiV1.TanRequestBody( + registrationToken = "testRegistrationToken", + requestPadding = "testRequestPadding" + ) + + api.getTAN( + fake = "0", + headerPadding = "testPadding", + requestBody + ) shouldBe VerificationApiV1.TanResponse( + tan = "testTan" + ) + + webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply { + headers["cwa-fake"] shouldBe "0" + headers["cwa-header-padding"] shouldBe "testPadding" + path shouldBe "/version/v1/tan" + body.readUtf8() shouldBe """ + { + "registrationToken": "testRegistrationToken", + "requestPadding": "testRequestPadding" + } + """.toComparableJson() + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/server/VerificationServerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/server/VerificationServerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..463cb73d8daf556e681efa5fa61c09f099995727 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/verification/server/VerificationServerTest.kt @@ -0,0 +1,215 @@ +package de.rki.coronawarnapp.verification.server + +import android.content.Context +import de.rki.coronawarnapp.http.HttpModule +import de.rki.coronawarnapp.util.headerSizeIgnoringContentLength +import de.rki.coronawarnapp.verification.VerificationModule +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.runBlocking +import okhttp3.ConnectionSpec +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseIOTest +import java.io.File + +class VerificationServerTest : BaseIOTest() { + + @MockK lateinit var verificationApi: VerificationApiV1 + @MockK private lateinit var context: Context + + private lateinit var webServer: MockWebServer + private lateinit var serverAddress: String + + private val testDir = File(IO_TEST_BASEDIR, this::class.java.simpleName) + private val cacheDir = File(testDir, "cache") + private val httpCacheDir = File(cacheDir, "http_verification") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + testDir.mkdirs() + testDir.exists() shouldBe true + every { context.cacheDir } returns cacheDir + + webServer = MockWebServer() + webServer.start() + serverAddress = "http://${webServer.hostName}:${webServer.port}" + } + + @AfterEach + fun teardown() { + clearAllMocks() + webServer.shutdown() + testDir.deleteRecursively() + } + + private fun createServer( + customApi: VerificationApiV1 = verificationApi + ) = VerificationServer(verificationAPI = { customApi }) + + @Test + fun `get registration token via GUID`(): Unit = runBlocking { + val server = createServer() + coEvery { verificationApi.getRegistrationToken(any(), any(), any()) } answers { + arg<String>(0) shouldBe "0" + arg<String>(1) shouldBe "" + arg<VerificationApiV1.RegistrationTokenRequest>(2).apply { + keyType shouldBe VerificationKeyType.GUID.name + key shouldBe "15291f67d99ea7bc578c3544dadfbb991e66fa69cb36ff70fe30e798e111ff5f" + requestPadding!!.length shouldBe 139 + } + VerificationApiV1.RegistrationTokenResponse( + registrationToken = "testRegistrationToken" + ) + } + + server.retrieveRegistrationToken( + "testKey", VerificationKeyType.GUID + ) shouldBe "testRegistrationToken" + + coVerify { verificationApi.getRegistrationToken(any(), any(), any()) } + } + + @Test + fun `get registration token via TELETAN`() = runBlocking { + val server = createServer() + coEvery { verificationApi.getRegistrationToken(any(), any(), any()) } answers { + arg<String>(0) shouldBe "0" + arg<String>(1) shouldBe "" + arg<VerificationApiV1.RegistrationTokenRequest>(2).apply { + keyType shouldBe VerificationKeyType.TELETAN.name + key shouldBe "testKey" + requestPadding!!.length shouldBe 190 + } + VerificationApiV1.RegistrationTokenResponse( + registrationToken = "testRegistrationToken" + ) + } + + server.retrieveRegistrationToken( + "testKey", VerificationKeyType.TELETAN + ) shouldBe "testRegistrationToken" + + coVerify { verificationApi.getRegistrationToken(any(), any(), any()) } + } + + @Test + fun `get test result`(): Unit = runBlocking { + val server = createServer() + coEvery { verificationApi.getTestResult(any(), any(), any()) } answers { + arg<String>(0) shouldBe "0" + arg<String>(1).length shouldBe 7 // Header-padding + arg<VerificationApiV1.RegistrationRequest>(2).apply { + registrationToken shouldBe "testRegistrationToken" + requestPadding!!.length shouldBe 170 + } + VerificationApiV1.TestResultResponse(testResult = 2) + } + + server.retrieveTestResults("testRegistrationToken") shouldBe 2 + + coVerify { verificationApi.getTestResult(any(), any(), any()) } + } + + @Test + fun `get TAN`(): Unit = runBlocking { + val server = createServer() + coEvery { verificationApi.getTAN(any(), any(), any()) } answers { + arg<String>(0) shouldBe "0" + arg<String>(1).length shouldBe 14 // Header-padding + arg<VerificationApiV1.TanRequestBody>(2).apply { + registrationToken shouldBe "testRegistrationToken" + requestPadding!!.length shouldBe 170 + } + VerificationApiV1.TanResponse(tan = "testTan") + } + + server.retrieveTan("testRegistrationToken") shouldBe "testTan" + + coVerify { verificationApi.getTAN(any(), any(), any()) } + } + + @Test + fun `get TAN with fake data`(): Unit = runBlocking { + val server = createServer() + coEvery { verificationApi.getTAN(any(), any(), any()) } answers { + arg<String>(0) shouldBe "1" + arg<String>(1).length shouldBe 14 // Header-padding + arg<VerificationApiV1.TanRequestBody>(2).apply { + registrationToken shouldBe "11111111-2222-4444-8888-161616161616" + requestPadding!!.length shouldBe 170 + } + VerificationApiV1.TanResponse(tan = "testTan") + } + + server.retrieveTanFake() shouldBe VerificationApiV1.TanResponse(tan = "testTan") + + coVerify { verificationApi.getTAN(any(), any(), any()) } + } + + private fun createRealApi(): VerificationApiV1 { + val httpModule = HttpModule() + val defaultHttpClient = httpModule.defaultHttpClient() + val gsonConverterFactory = httpModule.provideGSONConverter() + + return VerificationModule().let { + val downloadHttpClient = it.cdnHttpClient( + defaultHttpClient, + listOf(ConnectionSpec.CLEARTEXT, ConnectionSpec.MODERN_TLS) + ) + it.provideVerificationApi( + context = context, + client = downloadHttpClient, + url = serverAddress, + gsonConverterFactory = gsonConverterFactory + ) + } + } + + @Test + fun `all requests have the same footprint for pleasible deniability`(): Unit = runBlocking { + val guidExample = "3BF1D4-1C6003DD-733D-41F1-9F30-F85FA7406BF7" + val teletanExample = "9A3B578UMG" + val registrationTokenExample = "63b4d3ff-e0de-4bd4-90c1-17c2bb683a2f" + + val api = createServer(createRealApi()) + webServer.enqueue(MockResponse().setBody("{}")) + api.retrieveRegistrationToken(guidExample, VerificationKeyType.GUID) + + webServer.enqueue(MockResponse().setBody("{}")) + api.retrieveRegistrationToken(teletanExample, VerificationKeyType.TELETAN) + + webServer.enqueue(MockResponse().setBody("{}")) + api.retrieveTestResults(registrationTokenExample) + + webServer.enqueue(MockResponse().setBody("{}")) + api.retrieveTan(registrationTokenExample) + + webServer.enqueue(MockResponse().setBody("{}")) + api.retrieveTanFake() + + val requests = listOf( + webServer.takeRequest(), + webServer.takeRequest(), + webServer.takeRequest(), + webServer.takeRequest(), + webServer.takeRequest() + ) + + // ensure all request have same size (header & body) + requests.forEach { it.bodySize shouldBe 250L } + + requests.zipWithNext().forEach { (a, b) -> + a.headerSizeIgnoringContentLength() shouldBe b.headerSizeIgnoringContentLength() + } + } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/BaseIOTest.kt b/Corona-Warn-App/src/test/java/testhelpers/BaseIOTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..d2a94e95fde04dbbcbb3c5a6ed1d9058bef07558 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/BaseIOTest.kt @@ -0,0 +1,8 @@ +package testhelpers + +abstract class BaseIOTest : BaseTest() { + + companion object { + const val IO_TEST_BASEDIR = "build/tmp/unit_tests" + } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/BaseTest.kt b/Corona-Warn-App/src/test/java/testhelpers/BaseTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..8dbaf6bff0b72e636829165f2f7629b11a2aa331 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/BaseTest.kt @@ -0,0 +1,12 @@ +package testhelpers + +import testhelpers.logging.JUnitTree +import timber.log.Timber + +abstract class BaseTest { + + init { + Timber.uprootAll() + Timber.plant(JUnitTree()) + } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/KotestExtensions.kt b/Corona-Warn-App/src/test/java/testhelpers/KotestExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..4841a1926aff437c96ae59385930252709e2ff63 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/KotestExtensions.kt @@ -0,0 +1,27 @@ +package testhelpers + +import io.kotest.assertions.retry +import kotlinx.coroutines.runBlocking +import timber.log.Timber +import kotlin.time.ExperimentalTime +import kotlin.time.seconds + +/** + * TODO Remove flaky tests where possible + * A flaky test is a test that sometimes fails and sometimes doesn't + * Feel free to find usages of this method and to refactor them such that they are working reliably. + */ +@ExperimentalTime +fun <T> flakyTest(flakyAction: () -> T): Unit = runBlocking { + retry( + maxRetry = 10, + timeout = 60.seconds, + delay = 1.seconds, + multiplier = 1, + exceptionClass = Exception::class, + f = { + Timber.v("Flaky test try...") + flakyAction() + } + ) +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/exceptions/TestException.kt b/Corona-Warn-App/src/test/java/testhelpers/exceptions/TestException.kt new file mode 100644 index 0000000000000000000000000000000000000000..5b88672366ae8e2b0e4eba1e4e11eae654c52bbf --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/exceptions/TestException.kt @@ -0,0 +1,5 @@ +package testhelpers.exceptions + +import java.util.UUID + +class TestException(private val uuid: UUID = UUID.randomUUID()) : Exception() diff --git a/Corona-Warn-App/src/test/java/testhelpers/extensions/CoroutinesTestExtension.kt b/Corona-Warn-App/src/test/java/testhelpers/extensions/CoroutinesTestExtension.kt new file mode 100644 index 0000000000000000000000000000000000000000..b2180a1c80b9363e296fbaefb538d1aca762a008 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/extensions/CoroutinesTestExtension.kt @@ -0,0 +1,26 @@ +package testhelpers.extensions + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestCoroutineDispatcher +import kotlinx.coroutines.test.TestCoroutineScope +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.jupiter.api.extension.AfterEachCallback +import org.junit.jupiter.api.extension.BeforeEachCallback +import org.junit.jupiter.api.extension.ExtensionContext + +@ExperimentalCoroutinesApi +class CoroutinesTestExtension( + private val dispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher() +) : BeforeEachCallback, AfterEachCallback, TestCoroutineScope by TestCoroutineScope(dispatcher) { + + override fun beforeEach(context: ExtensionContext?) { + Dispatchers.setMain(dispatcher) + } + + override fun afterEach(context: ExtensionContext?) { + cleanupTestCoroutines() + Dispatchers.resetMain() + } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/extensions/InstantExecutorExtension.kt b/Corona-Warn-App/src/test/java/testhelpers/extensions/InstantExecutorExtension.kt new file mode 100644 index 0000000000000000000000000000000000000000..60264bc21bce2d77fb691d9096f781a14bc2bbc4 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/extensions/InstantExecutorExtension.kt @@ -0,0 +1,24 @@ +package testhelpers.extensions + +import androidx.arch.core.executor.ArchTaskExecutor +import androidx.arch.core.executor.TaskExecutor +import org.junit.jupiter.api.extension.AfterEachCallback +import org.junit.jupiter.api.extension.BeforeEachCallback +import org.junit.jupiter.api.extension.ExtensionContext + +class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback { + + override fun beforeEach(context: ExtensionContext?) { + ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() { + override fun executeOnDiskIO(runnable: Runnable) = runnable.run() + + override fun postToMainThread(runnable: Runnable) = runnable.run() + + override fun isMainThread(): Boolean = true + }) + } + + override fun afterEach(context: ExtensionContext?) { + ArchTaskExecutor.getInstance().setDelegate(null) + } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/extensions/JsonExtensions.kt b/Corona-Warn-App/src/test/java/testhelpers/extensions/JsonExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..bc1304959208fcebe18ef38a3c8fb7ebfaafd631 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/extensions/JsonExtensions.kt @@ -0,0 +1,13 @@ +package testhelpers.extensions + +import com.google.gson.Gson +import com.google.gson.JsonObject +import okhttp3.mockwebserver.MockResponse + +fun String.toComparableJson() = try { + Gson().fromJson(this, JsonObject::class.java).toString() +} catch (e: Exception) { + throw IllegalArgumentException("'$this' wasn't valid JSON") +} + +fun String.toJsonResponse(): MockResponse = MockResponse().setBody(this.toComparableJson()) diff --git a/Corona-Warn-App/src/test/java/testhelpers/extensions/LiveDataTestExtension.kt b/Corona-Warn-App/src/test/java/testhelpers/extensions/LiveDataTestExtension.kt new file mode 100644 index 0000000000000000000000000000000000000000..1041e72dd00afe48bdd692be583af5696925023d --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/extensions/LiveDataTestExtension.kt @@ -0,0 +1,58 @@ +package testhelpers.extensions + +/** + * Thanks to https://github.com/android/architecture-components-samples/blob/master/LiveDataSample/app/src/test/java/com/android/example/livedatabuilder/util/LiveDataTestUtil.kt + */ + +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException + +/** + * Gets the value of a [LiveData] or waits for it to have one, with a timeout. + * + * Use this extension from host-side (JVM) tests. It's recommended to use it alongside + * `InstantTaskExecutorRule` or a similar mechanism to execute tasks synchronously. + */ +fun <T> LiveData<T>.getOrAwaitValue( + time: Long = 2, + timeUnit: TimeUnit = TimeUnit.SECONDS, + afterObserve: () -> Unit = {} +): T { + var data: T? = null + val latch = CountDownLatch(1) + val observer = object : Observer<T> { + override fun onChanged(o: T?) { + data = o + latch.countDown() + this@getOrAwaitValue.removeObserver(this) + } + } + this.observeForever(observer) + + afterObserve.invoke() + + // Don't wait indefinitely if the LiveData is not set. + if (!latch.await(time, timeUnit)) { + this.removeObserver(observer) + throw TimeoutException("LiveData value was never set.") + } + + @Suppress("UNCHECKED_CAST") + return data as T +} + +/** + * Observes a [LiveData] until the `block` is done executing. + */ +fun <T> LiveData<T>.observeForTesting(block: () -> Unit) { + val observer = Observer<T> { } + try { + observeForever(observer) + block() + } finally { + removeObserver(observer) + } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/logging/JUnitTree.kt b/Corona-Warn-App/src/test/java/testhelpers/logging/JUnitTree.kt new file mode 100644 index 0000000000000000000000000000000000000000..f10732b30a7d7a996f0c85766e8fc335ef8785d2 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/logging/JUnitTree.kt @@ -0,0 +1,22 @@ +package testhelpers.logging + +import android.util.Log + +import timber.log.Timber + +class JUnitTree(private val minLogLevel: Int = Log.VERBOSE) : Timber.DebugTree() { + + private fun priorityToString(priority: Int): String = when (priority) { + Log.ERROR -> "E" + Log.WARN -> "W" + Log.INFO -> "I" + Log.DEBUG -> "D" + Log.VERBOSE -> "V" + else -> priority.toString() + } + + override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { + if (priority < minLogLevel) return + println("${System.currentTimeMillis()} ${priorityToString(priority)}/$tag: $message") + } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/preferences/MockSharedPreferences.kt b/Corona-Warn-App/src/test/java/testhelpers/preferences/MockSharedPreferences.kt new file mode 100644 index 0000000000000000000000000000000000000000..a6294b00f54bcdbc96ab6bd18195389fc1a79e51 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/preferences/MockSharedPreferences.kt @@ -0,0 +1,98 @@ +package testhelpers.preferences + +import android.content.SharedPreferences + +class MockSharedPreferences : SharedPreferences { + private val dataMap = mutableMapOf<String, Any>() + val dataMapPeek: Map<String, Any> + get() = dataMap.toMap() + + override fun getAll(): MutableMap<String, *> = dataMap + + override fun getString(key: String, defValue: String?): String? = + dataMap[key] as? String ?: defValue + + override fun getStringSet(key: String, defValues: MutableSet<String>?): MutableSet<String> { + throw NotImplementedError() + } + + override fun getInt(key: String, defValue: Int): Int = + dataMap[key] as? Int ?: defValue + + override fun getLong(key: String, defValue: Long): Long = + dataMap[key] as? Long ?: defValue + + override fun getFloat(key: String, defValue: Float): Float { + throw NotImplementedError() + } + + override fun getBoolean(key: String, defValue: Boolean): Boolean = + dataMap[key] as? Boolean ?: defValue + + override fun contains(key: String): Boolean = dataMap.contains(key) + + override fun edit(): SharedPreferences.Editor = createEditor(dataMap.toMap()) { newData -> + dataMap.clear() + dataMap.putAll(newData) + } + + override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) { + throw NotImplementedError() + } + + override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) { + throw NotImplementedError() + } + + private fun createEditor( + toEdit: Map<String, Any>, + onSave: (Map<String, Any>) -> Unit + ): SharedPreferences.Editor { + return object : SharedPreferences.Editor { + private val editorData = toEdit.toMutableMap() + override fun putString(key: String, value: String?): SharedPreferences.Editor = apply { + value?.let { editorData[key] = it } ?: editorData.remove(key) + } + + override fun putStringSet( + key: String?, + values: MutableSet<String>? + ): SharedPreferences.Editor { + throw NotImplementedError() + } + + override fun putInt(key: String, value: Int): SharedPreferences.Editor = apply { + editorData[key] = value + } + + override fun putLong(key: String, value: Long): SharedPreferences.Editor = apply { + editorData[key] = value + } + + override fun putFloat(key: String, value: Float): SharedPreferences.Editor = apply { + editorData[key] = value + } + + override fun putBoolean(key: String, value: Boolean): SharedPreferences.Editor = apply { + editorData[key] = value + } + + override fun remove(key: String): SharedPreferences.Editor = apply { + editorData.remove(key) + } + + override fun clear(): SharedPreferences.Editor = apply { + editorData.clear() + } + + override fun commit(): Boolean { + onSave(editorData) + return true + } + + override fun apply() { + onSave(editorData) + } + } + } +} diff --git a/Corona-Warn-App/src/test/java/testhelpers/preferences/MockSharedPreferencesTest.kt b/Corona-Warn-App/src/test/java/testhelpers/preferences/MockSharedPreferencesTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..d6909726ebf3b20978271c0c03762cce6d135ff7 --- /dev/null +++ b/Corona-Warn-App/src/test/java/testhelpers/preferences/MockSharedPreferencesTest.kt @@ -0,0 +1,21 @@ +package testhelpers.preferences + +import androidx.core.content.edit +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class MockSharedPreferencesTest : BaseTest() { + + private fun createInstance() = MockSharedPreferences() + + @Test + fun `test boolean insertion`() { + val prefs = createInstance() + prefs.dataMapPeek shouldBe emptyMap() + prefs.getBoolean("key", true) shouldBe true + prefs.edit { putBoolean("key", false) } + prefs.getBoolean("key", true) shouldBe false + prefs.dataMapPeek["key"] shouldBe false + } +} diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModelTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..9003b9ce6ddb1c575ae6258e00ce84eb221c4b4f --- /dev/null +++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/api/ui/TestForApiFragmentViewModelTest.kt @@ -0,0 +1,101 @@ +package de.rki.coronawarnapp.test.api.ui + +import android.content.Context +import androidx.lifecycle.Observer +import de.rki.coronawarnapp.environment.EnvironmentSetup +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.Runs +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import testhelpers.BaseTest +import testhelpers.extensions.CoroutinesTestExtension +import testhelpers.extensions.InstantExecutorExtension +import testhelpers.flakyTest +import kotlin.time.ExperimentalTime + +@ExperimentalTime +@ExperimentalCoroutinesApi +@ExtendWith(InstantExecutorExtension::class, CoroutinesTestExtension::class) +class TestForApiFragmentViewModelTest : BaseTest() { + + @MockK private lateinit var environmentSetup: EnvironmentSetup + @MockK private lateinit var context: Context + + private var currentEnvironment = EnvironmentSetup.Type.DEV + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + currentEnvironment = EnvironmentSetup.Type.DEV + + every { environmentSetup.defaultEnvironment } returns EnvironmentSetup.Type.DEV + every { environmentSetup.submissionCdnUrl } returns "submissionUrl" + every { environmentSetup.downloadCdnUrl } returns "downloadUrl" + every { environmentSetup.verificationCdnUrl } returns "verificationUrl" + + every { environmentSetup.currentEnvironment = any() } answers { + currentEnvironment = arg(0) + Unit + } + every { environmentSetup.currentEnvironment } answers { + currentEnvironment + } + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + private fun createViewModel(): TestForApiFragmentViewModel = TestForApiFragmentViewModel( + envSetup = environmentSetup, + context = context + ) + + @Test + fun `toggeling the env works`() = flakyTest { + currentEnvironment = EnvironmentSetup.Type.DEV + val vm = createViewModel() + + val states = mutableListOf<EnvironmentState>() + val observerState = mockk<Observer<EnvironmentState>>() + every { observerState.onChanged(capture(states)) } just Runs + vm.environmentState.observeForever(observerState) + + val events = mutableListOf<EnvironmentSetup.Type>() + val observerEvent = mockk<Observer<EnvironmentSetup.Type>>() + every { observerEvent.onChanged(capture(events)) } just Runs + vm.environmentChangeEvent.observeForever(observerEvent) + + vm.selectEnvironmentTytpe(EnvironmentSetup.Type.DEV.rawKey) + vm.selectEnvironmentTytpe(EnvironmentSetup.Type.WRU_XA.rawKey) + + verify(exactly = 3, timeout = 3000) { observerState.onChanged(any()) } + verify(exactly = 2, timeout = 3000) { observerEvent.onChanged(any()) } + + states[0].apply { + current shouldBe EnvironmentSetup.Type.DEV + } + + states[1].apply { + current shouldBe EnvironmentSetup.Type.DEV + } + events[0] shouldBe EnvironmentSetup.Type.DEV + + + states[2].apply { + current shouldBe EnvironmentSetup.Type.WRU_XA + } + events[1] shouldBe EnvironmentSetup.Type.WRU_XA + } +} diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModelTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..db3450dbfac08368b08b90ffd21c8c49387e5d26 --- /dev/null +++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragmentCWAViewModelTest.kt @@ -0,0 +1,106 @@ +package de.rki.coronawarnapp.test.risklevel.ui + +import android.content.Context +import androidx.lifecycle.SavedStateHandle +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient +import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository +import de.rki.coronawarnapp.nearby.ENFClient +import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction +import de.rki.coronawarnapp.transaction.RiskLevelTransaction +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.clearAllMocks +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.coVerifyOrder +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockkObject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import testhelpers.BaseTest +import testhelpers.extensions.CoroutinesTestExtension +import testhelpers.extensions.InstantExecutorExtension + +@ExperimentalCoroutinesApi +@ExtendWith(InstantExecutorExtension::class, CoroutinesTestExtension::class) +class TestRiskLevelCalculationFragmentCWAViewModelTest : BaseTest() { + + @MockK lateinit var context: Context + @MockK lateinit var savedStateHandle: SavedStateHandle + @MockK lateinit var enfClient: ENFClient + @MockK lateinit var exposureNotificationClient: ExposureNotificationClient + @MockK lateinit var keyCacheRepository: KeyCacheRepository + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + mockkObject(RetrieveDiagnosisKeysTransaction) + coEvery { RetrieveDiagnosisKeysTransaction.start() } returns Unit + mockkObject(RiskLevelTransaction) + coEvery { RiskLevelTransaction.start() } returns Unit + + coEvery { keyCacheRepository.clear() } returns Unit + every { enfClient.internalClient } returns exposureNotificationClient + } + + @AfterEach + fun teardown() { + clearAllMocks() + } + + private fun createViewModel(exampleArgs: String? = null): TestRiskLevelCalculationFragmentCWAViewModel = + TestRiskLevelCalculationFragmentCWAViewModel( + handle = savedStateHandle, + exampleArg = exampleArgs, + context = context, + enfClient = enfClient, + keyCacheRepository = keyCacheRepository + ) + + @Test + fun `action retrieveDiagnosisKeys, retieves diagnosis keys and calls risklevel calculation`() { + val vm = createViewModel() + + vm.retrieveDiagnosisKeys() + + coVerifyOrder { + RetrieveDiagnosisKeysTransaction.start() + RiskLevelTransaction.start() + } + } + + @Test + fun `action calculateRiskLevel, calls risklevel calculation`() { + val vm = createViewModel() + + vm.calculateRiskLevel() + + coVerify(exactly = 1) { RiskLevelTransaction.start() } + coVerify(exactly = 0) { RetrieveDiagnosisKeysTransaction.start() } + } + + @Test + fun `action clearDiagnosisKeys calls the keyCacheRepo`() { + val vm = createViewModel() + + vm.clearKeyCache() + + coVerify(exactly = 1) { keyCacheRepository.clear() } + } + + @Test + fun `action scanLocalQRCodeAndProvide, triggers event`() { + val vm = createViewModel() + + vm.startLocalQRCodeScanEvent.value shouldBe null + + vm.scanLocalQRCodeAndProvide() + + vm.startLocalQRCodeScanEvent.value shouldBe Unit + } +} diff --git a/NOTICE b/NOTICE index a7f75b970750bb29a028a4668acee3d7a03b658d..3bec41f9248f8e514dbdf106e8831e6c0bc3fda4 100644 --- a/NOTICE +++ b/NOTICE @@ -16,3 +16,9 @@ Thomas Klingbeil (tklingbeil), SAP SE Kolya Opahle (kolyaopahle), SAP SE Fabian Kajzar (Fabian-K), SAP SE Oliver Zimmerman (Oliver-Zimmerman), SAP SE +Rituraj Sambherao (ritsam), SAP SE +Alexander Popov (apopovsap), SAP SE +Bernd Mitter (BMItter), SAP SE (external) +Alexandru Paulenscu (SamuraiKek), SAP SE +Mert Safter (MertSafter), SAP SE +Matthias Urhahn (d4rken), SAP SE (external) diff --git a/README.md b/README.md index b2ebfeb975679e41214b4f8bbf45d2f75acafa93..1175fc7fe38548145564012c4545aadcf03fc325 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ </p> The goal of this project is to develop the official Corona-Warn-App for Germany based on the exposure notification API from [Apple](https://www.apple.com/covid19/contacttracing/) and [Google](https://www.google.com/covid19/exposurenotifications/). The apps (for both iOS and Android) use Bluetooth technology to exchange anonymous encrypted data with other mobile phones (on which the app is also installed) in the vicinity of an app user's phone. The data is stored locally on each user's device, preventing authorities or other parties from accessing or controlling the data. This repository contains the **native Android implementation** of the Corona-Warn-App. -**Visit our [FAQ page](https://www.coronawarn.app/en/faq) for more information and common issues** +**Visit our [FAQ page](https://www.coronawarn.app/en/faq/) for more information and common issues** ## Development diff --git a/Server-Protocol-Buffer/src/main/proto/applicationConfiguration.proto b/Server-Protocol-Buffer/src/main/proto/applicationConfiguration.proto index a840bcd6aa94bea18886a3eb6f19bb17538a6be0..19f1619471b41cd51bc32fc0dde6abfbcefbbb5b 100644 --- a/Server-Protocol-Buffer/src/main/proto/applicationConfiguration.proto +++ b/Server-Protocol-Buffer/src/main/proto/applicationConfiguration.proto @@ -12,6 +12,10 @@ message ApplicationConfiguration { AttenuationDuration attenuationDuration = 4; ApplicationVersionConfiguration appVersion = 5; + + AppFeatures appFeatures = 6; + + repeated string supportedCountries = 7; } message RiskScoreParameters { @@ -126,4 +130,13 @@ message SemanticVersion { uint32 major = 1; uint32 minor = 2; uint32 patch = 3; +} + +message AppFeatures { + repeated AppFeature app_features = 1; +} + +message AppFeature { + string label = 1; + int32 value = 2; } \ No newline at end of file diff --git a/Server-Protocol-Buffer/src/main/proto/keyExportFormat.proto b/Server-Protocol-Buffer/src/main/proto/keyExportFormat.proto index 3ef93b1da8622faedce917cb40d40e41b1f2d612..a40ece0dc89a36652e6951cd56f9e1349c651841 100644 --- a/Server-Protocol-Buffer/src/main/proto/keyExportFormat.proto +++ b/Server-Protocol-Buffer/src/main/proto/keyExportFormat.proto @@ -1,4 +1,6 @@ syntax = "proto2"; +package de.rki.coronawarnapp.server.protocols; + message TemporaryExposureKeyExport { // Time window of keys in this batch based on arrival to server, in UTC seconds optional fixed64 start_timestamp = 1; @@ -30,6 +32,9 @@ message SignatureInfo { message SubmissionPayload { repeated TemporaryExposureKey keys = 1; optional bytes padding = 2; + repeated string visitedCountries = 3; + optional string origin = 4; + optional bool consentToFederation = 5; } message TemporaryExposureKey { @@ -41,6 +46,21 @@ message TemporaryExposureKey { optional int32 rolling_start_interval_number = 3; // Increments of 10 minutes describing how long a key is valid optional int32 rolling_period = 4 [default = 144]; // defaults to 24 hours + // Type of diagnosis associated with a key. + optional ReportType report_type = 5 [default = CONFIRMED_CLINICAL_DIAGNOSIS]; + // Number of days elapsed between symptom onset and the TEK being used. + // E.g. 2 means TEK is 2 days after onset of symptoms. + optional sint32 days_since_onset_of_symptoms = 6; +} + +// Data type representing why this key was published. +enum ReportType { + UNKNOWN = 0; // Never returned by the client API. + CONFIRMED_TEST = 1; + CONFIRMED_CLINICAL_DIAGNOSIS = 2; + SELF_REPORT = 3; + RECURSIVE = 4; // Reserved for future use. + REVOKED = 5; // Used to revoke a key, never returned by client API. } message TEKSignatureList { diff --git a/build.gradle b/build.gradle index 785ef66089b8c02de580979c2246fb14e9e3e2d8..3758485c638c3420912fe1f8c8a0afefebdc3773 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.72' + ext.kotlin_version = '1.4.0' ext.protobufVersion = '0.8.12' ext.navVersion = "2.2.2" @@ -47,7 +47,7 @@ subprojects { } ktlint { - debug = true + debug = false ignoreFailures = false coloredOutput = false } diff --git a/prod_environments.json b/prod_environments.json new file mode 100644 index 0000000000000000000000000000000000000000..6303f5b395a5f5ae445ce13d303589d0871260fd --- /dev/null +++ b/prod_environments.json @@ -0,0 +1,9 @@ +{ + "PROD": { + "USE_EUR_KEY_PKGS": true, + "SUBMISSION_CDN_URL": "https://submission.coronawarn.app", + "DOWNLOAD_CDN_URL": "https://svc90.main.px.t-online.de", + "VERIFICATION_CDN_URL": "https://verification.coronawarn.app", + "PUB_KEYS_SIGNATURE_VERIFICATION": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==" + } +}