[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[Bug report] Title for the bug\"\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nExample Steps to reproduce the behavior in sample app:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\nIf applicable, please include `code snippet` and `sample input(image, video, text, etc)` \n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**SDK Info:**\n - SDK Name & Version [e.g. com.google.mlkit:face-detection:16.1.3]\n\n**Smartphone:**\n - Device/Simulator: [e.g. iPhone6, Pixel 5]\n - Device/Simulator OS: [e.g. iOS8.1, Android API 30]\n\n**Development Environment:**\n*(For Android issue feel free to skip this section)*\n- IDE Eversion: [e.g. Xcode 13.1, Android Studio 4.2]\n- Laptop/Desktop: [e.g. iMac Pro (2017), HP Z840 Workstation]\n- Laptop/Desktop OS/version: [e.g. macOS 12.0.1]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[Feature request] Title for the request\"\nlabels: ''\nassignees: ''\n\n---\n\n**What's your feature request? Please describe.**\nA clear and concise description of what the request is. Ex. I would like to have X language support in text recognition[...]\n\n**Mobile environment**\nAndroid, IOS or both\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".gitignore",
    "content": "*.DS_Store\n*.idea\n*.iml\n.gradle\nlocal.properties\n\n.project\n.settings\n.classpath\n\n**/Pods/\n**/*.xcuserstate\nios-snippets/Podfile.lock\nios-snippets/mlkit-snippets.xcworkspace/xcuserdata/dfurlong.xcuserdatad/UserInterfaceState.xcuserstate"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.md",
    "content": "# MLKit Samples\n\nA collection of quickstart samples demonstrating the [ML Kit](https://developers.google.com/ml-kit) APIs on Android and iOS.\n\nNote: due to how this repo works, we no longer accept pull requests directly. Instead, we'll patch them internally and then sync them out.\n"
  },
  {
    "path": "android/.gitignore",
    "content": ".gradle\nbuild/\n.DS_Store\n*.iml\n*.apk\n*.aar\n*.zip\ngoogle-services.json\n\n.project\n.settings\n.classpath\n\nlocal.properties\n\n.idea/*\n!idea/codeStyles\n\ncaptures\n.externalNativeBuild\n.cxx\n\n"
  },
  {
    "path": "android/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020 Google Inc\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "android/README.md",
    "content": "# MLKit Android Samples\n\nA collection of quickstart samples demonstrating the MLKit APIs on Android.\n\n[See a full list of Quickstart apps here.](https://developers.google.com/ml-kit/samples)\n\n## Introduction\n[Read more about ML Kit](https://developers.google.com/ml-kit)\n"
  },
  {
    "path": "android/android-snippets/README.md",
    "content": "# ML Kit Android Snippets\n\nThis is a collection of Android code snippets seen on https://developers.google.com/ml-kit. This project is not meant to be run as a standalone app to demo ML Kit APIs. \n\n## License\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/android-snippets/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 31\n\n    defaultConfig {\n        applicationId \"com.google.example.mlkit\"\n        minSdkVersion 19\n        targetSdkVersion 31\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n        multiDexEnabled true\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    packagingOptions {\n        exclude 'META-INF/androidx.exifinterface_exifinterface.version'\n        exclude 'META-INF/proguard/androidx-annotations.pro'\n    }\n}\n\ndependencies {\n    implementation 'androidx.legacy:legacy-support-v4:1.0.0'\n    implementation 'androidx.appcompat:appcompat:1.4.2'\n    implementation 'androidx.exifinterface:exifinterface:1.3.3'\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n\n    // Add this dependency and multiDexEnabled = true in your defaultConfig to solve the error:\n    // Cannot fit requested classes in a single dex file\n    implementation 'androidx.multidex:multidex:2.0.1'\n\n    // ML Kit related dependencies\n\n    // Barcode model\n    implementation 'com.google.mlkit:barcode-scanning:17.0.2'\n\n    // Object detection and tracking features\n    implementation 'com.google.mlkit:object-detection:17.0.0'\n    implementation 'com.google.mlkit:object-detection-custom:17.0.0'\n\n    // Face features\n    implementation 'com.google.android.gms:play-services-mlkit-face-detection:17.0.1'\n\n    // Text features\n    implementation 'com.google.android.gms:play-services-mlkit-text-recognition:18.0.0'\n\n    // Image labeling\n    implementation 'com.google.mlkit:image-labeling:17.0.7'\n\n    // Language Identification\n    implementation 'com.google.mlkit:language-id:17.0.3'\n\n    implementation 'androidx.appcompat:appcompat:1.4.2'\n    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'\n}\n"
  },
  {
    "path": "android/android-snippets/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/ianbarber/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.example.mlkit\">\n\n  <application\n      android:allowBackup=\"true\"\n      android:icon=\"@mipmap/ic_launcher\"\n      android:label=\"@string/app_name\"\n      android:supportsRtl=\"true\"\n      android:theme=\"@style/AppTheme\">\n    <activity\n        android:name=\".MainActivity\"\n        android:exported=\"true\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n    <activity android:name=\".kotlin.MainActivity\" />\n  </application>\n\n</manifest>"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/BarcodeScanningActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit;\n\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.barcode.common.Barcode;\nimport com.google.mlkit.vision.barcode.BarcodeScanner;\nimport com.google.mlkit.vision.barcode.BarcodeScannerOptions;\nimport com.google.mlkit.vision.barcode.BarcodeScanning;\nimport com.google.mlkit.vision.common.InputImage;\n\nimport java.util.List;\n\npublic class BarcodeScanningActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    private void scanBarcodes(InputImage image) {\n        // [START set_detector_options]\n        BarcodeScannerOptions options =\n                new BarcodeScannerOptions.Builder()\n                .setBarcodeFormats(\n                        Barcode.FORMAT_QR_CODE,\n                        Barcode.FORMAT_AZTEC)\n                .build();\n        // [END set_detector_options]\n\n        // [START get_detector]\n        BarcodeScanner scanner = BarcodeScanning.getClient();\n        // Or, to specify the formats to recognize:\n        // BarcodeScanner scanner = BarcodeScanning.getClient(options);\n        // [END get_detector]\n\n        // [START run_detector]\n        Task<List<Barcode>> result = scanner.process(image)\n                .addOnSuccessListener(new OnSuccessListener<List<Barcode>>() {\n                    @Override\n                    public void onSuccess(List<Barcode> barcodes) {\n                        // Task completed successfully\n                        // [START_EXCLUDE]\n                        // [START get_barcodes]\n                        for (Barcode barcode: barcodes) {\n                            Rect bounds = barcode.getBoundingBox();\n                            Point[] corners = barcode.getCornerPoints();\n\n                            String rawValue = barcode.getRawValue();\n\n                            int valueType = barcode.getValueType();\n                            // See API reference for complete list of supported types\n                            switch (valueType) {\n                                case Barcode.TYPE_WIFI:\n                                    String ssid = barcode.getWifi().getSsid();\n                                    String password = barcode.getWifi().getPassword();\n                                    int type = barcode.getWifi().getEncryptionType();\n                                    break;\n                                case Barcode.TYPE_URL:\n                                    String title = barcode.getUrl().getTitle();\n                                    String url = barcode.getUrl().getUrl();\n                                    break;\n                            }\n                        }\n                        // [END get_barcodes]\n                        // [END_EXCLUDE]\n                    }\n                })\n                .addOnFailureListener(new OnFailureListener() {\n                    @Override\n                    public void onFailure(@NonNull Exception e) {\n                        // Task failed with an exception\n                        // ...\n                    }\n                });\n        // [END run_detector]\n    }\n\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/FaceDetectionActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit;\n\nimport android.graphics.PointF;\nimport android.graphics.Rect;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.face.Face;\nimport com.google.mlkit.vision.face.FaceContour;\nimport com.google.mlkit.vision.face.FaceDetection;\nimport com.google.mlkit.vision.face.FaceDetector;\nimport com.google.mlkit.vision.face.FaceDetectorOptions;\nimport com.google.mlkit.vision.face.FaceLandmark;\n\nimport java.util.List;\n\npublic class FaceDetectionActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    private void detectFaces(InputImage image) {\n        // [START set_detector_options]\n        FaceDetectorOptions options =\n                new FaceDetectorOptions.Builder()\n                        .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)\n                        .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)\n                        .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)\n                        .setMinFaceSize(0.15f)\n                        .enableTracking()\n                        .build();\n        // [END set_detector_options]\n\n        // [START get_detector]\n        FaceDetector detector = FaceDetection.getClient(options);\n        // Or use the default options:\n        // FaceDetector detector = FaceDetection.getClient();\n        // [END get_detector]\n\n        // [START run_detector]\n        Task<List<Face>> result =\n                detector.process(image)\n                        .addOnSuccessListener(\n                                new OnSuccessListener<List<Face>>() {\n                                    @Override\n                                    public void onSuccess(List<Face> faces) {\n                                        // Task completed successfully\n                                        // [START_EXCLUDE]\n                                        // [START get_face_info]\n                                        for (Face face : faces) {\n                                            Rect bounds = face.getBoundingBox();\n                                            float rotY = face.getHeadEulerAngleY();  // Head is rotated to the right rotY degrees\n                                            float rotZ = face.getHeadEulerAngleZ();  // Head is tilted sideways rotZ degrees\n\n                                            // If landmark detection was enabled (mouth, ears, eyes, cheeks, and\n                                            // nose available):\n                                            FaceLandmark leftEar = face.getLandmark(FaceLandmark.LEFT_EAR);\n                                            if (leftEar != null) {\n                                                PointF leftEarPos = leftEar.getPosition();\n                                            }\n\n                                            // If classification was enabled:\n                                            if (face.getSmilingProbability() != null) {\n                                                float smileProb = face.getSmilingProbability();\n                                            }\n                                            if (face.getRightEyeOpenProbability() != null) {\n                                                float rightEyeOpenProb = face.getRightEyeOpenProbability();\n                                            }\n\n                                            // If face tracking was enabled:\n                                            if (face.getTrackingId() != null) {\n                                                int id = face.getTrackingId();\n                                            }\n                                        }\n                                        // [END get_face_info]\n                                        // [END_EXCLUDE]\n                                    }\n                                })\n                        .addOnFailureListener(\n                                new OnFailureListener() {\n                                    @Override\n                                    public void onFailure(@NonNull Exception e) {\n                                        // Task failed with an exception\n                                        // ...\n                                    }\n                                });\n        // [END run_detector]\n    }\n\n    private void faceOptionsExamples() {\n        // [START mlkit_face_options_examples]\n        // High-accuracy landmark detection and face classification\n        FaceDetectorOptions highAccuracyOpts =\n                new FaceDetectorOptions.Builder()\n                        .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)\n                        .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)\n                        .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)\n                        .build();\n\n        // Real-time contour detection\n        FaceDetectorOptions realTimeOpts =\n                new FaceDetectorOptions.Builder()\n                        .setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL)\n                        .build();\n        // [END mlkit_face_options_examples]\n    }\n\n    private void processFaceList(List<Face> faces) {\n        // [START mlkit_face_list]\n        for (Face face : faces) {\n            Rect bounds = face.getBoundingBox();\n            float rotY = face.getHeadEulerAngleY();  // Head is rotated to the right rotY degrees\n            float rotZ = face.getHeadEulerAngleZ();  // Head is tilted sideways rotZ degrees\n\n            // If landmark detection was enabled (mouth, ears, eyes, cheeks, and\n            // nose available):\n            FaceLandmark leftEar = face.getLandmark(FaceLandmark.LEFT_EAR);\n            if (leftEar != null) {\n                PointF leftEarPos = leftEar.getPosition();\n            }\n\n            // If contour detection was enabled:\n            List<PointF> leftEyeContour =\n                    face.getContour(FaceContour.LEFT_EYE).getPoints();\n            List<PointF> upperLipBottomContour =\n                    face.getContour(FaceContour.UPPER_LIP_BOTTOM).getPoints();\n\n            // If classification was enabled:\n            if (face.getSmilingProbability() != null) {\n                float smileProb = face.getSmilingProbability();\n            }\n            if (face.getRightEyeOpenProbability() != null) {\n                float rightEyeOpenProb = face.getRightEyeOpenProbability();\n            }\n\n            // If face tracking was enabled:\n            if (face.getTrackingId() != null) {\n                int id = face.getTrackingId();\n            }\n        }\n        // [END mlkit_face_list]\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/ImageLabelingActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.label.ImageLabel;\nimport com.google.mlkit.vision.label.ImageLabeler;\nimport com.google.mlkit.vision.label.ImageLabeling;\nimport com.google.mlkit.vision.label.defaults.ImageLabelerOptions;\n\nimport java.util.List;\n\npublic class ImageLabelingActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    private void labelImages(InputImage image) {\n        ImageLabelerOptions options =\n                new ImageLabelerOptions.Builder()\n                        .setConfidenceThreshold(0.8f)\n                        .build();\n\n        // [START get_detector_options]\n        ImageLabeler labeler = ImageLabeling.getClient(options);\n        // [END get_detector_options]\n\n        /*\n        // [START get_detector_default]\n        // Or use the default options:\n        ImageLabeler detector = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS);\n        // [END get_detector_default]\n        */\n\n        // [START run_detector]\n        Task<List<ImageLabel>> result =\n                labeler.process(image)\n                        .addOnSuccessListener(\n                                new OnSuccessListener<List<ImageLabel>>() {\n                                    @Override\n                                    public void onSuccess(List<ImageLabel> labels) {\n                                        // Task completed successfully\n                                        // [START_EXCLUDE]\n                                        // [START get_labels]\n                                        for (ImageLabel label : labels) {\n                                            String text = label.getText();\n                                            float confidence = label.getConfidence();\n                                        }\n                                        // [END get_labels]\n                                        // [END_EXCLUDE]\n                                    }\n                                })\n                        .addOnFailureListener(\n                                new OnFailureListener() {\n                                    @Override\n                                    public void onFailure(@NonNull Exception e) {\n                                        // Task failed with an exception\n                                        // ...\n                                    }\n                                });\n        // [END run_detector]\n    }\n\n    private void configureAndRunImageLabeler(InputImage image) {\n        // [START on_device_image_labeler]\n        // To use default options:\n        ImageLabeler labeler = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS);\n\n        // Or, to set the minimum confidence required:\n        // ImageLabelerOptions options =\n        //     new ImageLabelerOptions.Builder()\n        //         .setConfidenceThreshold(0.7f)\n        //         .build();\n        // ImageLabeler labeler = ImageLabeling.getClient(options);\n\n        // [END on_device_image_labeler]\n\n        // Process image with custom onSuccess() example\n        // [START process_image]\n        labeler.process(image)\n                .addOnSuccessListener(new OnSuccessListener<List<ImageLabel>>() {\n                    @Override\n                    public void onSuccess(List<ImageLabel> labels) {\n                        // Task completed successfully\n                        // ...\n                    }\n                })\n                .addOnFailureListener(new OnFailureListener() {\n                    @Override\n                    public void onFailure(@NonNull Exception e) {\n                        // Task failed with an exception\n                        // ...\n                    }\n                });\n        // [END process_image]\n\n        // Process image with example onSuccess()\n        labeler.process(image)\n                .addOnSuccessListener(new OnSuccessListener<List<ImageLabel>>() {\n                    @Override\n                    public void onSuccess(List<ImageLabel> labels) {\n                        // [START get_image_label_info]\n                        for (ImageLabel label : labels) {\n                            String text = label.getText();\n                            float confidence = label.getConfidence();\n                            int index = label.getIndex();\n                        }\n                        // [END get_image_label_info]\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/LanguageIdentificationActivity.java",
    "content": "package com.google.example.mlkit;\n\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.mlkit.nl.languageid.IdentifiedLanguage;\nimport com.google.mlkit.nl.languageid.LanguageIdentification;\nimport com.google.mlkit.nl.languageid.LanguageIdentificationOptions;\nimport com.google.mlkit.nl.languageid.LanguageIdentifier;\n\nimport java.util.List;\n\n\npublic class LanguageIdentificationActivity extends AppCompatActivity {\n\n    private static final String TAG = \"LangID\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    private void identifyLanguageWithStringInput(String text) {\n        // [START identify_languages]\n        LanguageIdentifier languageIdentifier =\n                LanguageIdentification.getClient();\n        languageIdentifier.identifyLanguage(text)\n                .addOnSuccessListener(\n                        new OnSuccessListener<String>() {\n                            @Override\n                            public void onSuccess(@Nullable String languageCode) {\n                                if (languageCode.equals(\"und\")) {\n                                    Log.i(TAG, \"Can't identify language.\");\n                                } else {\n                                    Log.i(TAG, \"Language: \" + languageCode);\n                                }\n                            }\n                        })\n                .addOnFailureListener(\n                        new OnFailureListener() {\n                            @Override\n                            public void onFailure(@NonNull Exception e) {\n                                // Model couldn’t be loaded or other internal error.\n                                // ...\n                            }\n                        });\n        // [END identify_languages]\n    }\n\n    private void setConfidence() {\n        // [START set_confidence]\n        LanguageIdentifier languageIdentifier = LanguageIdentification.getClient(\n                new LanguageIdentificationOptions.Builder()\n                        .setConfidenceThreshold(0.34f)\n                        .build());\n        // [END set_confidence]\n    }\n\n    private void getPossibleLanguuages(String text) {\n        // [START get_possible_languages]\n        LanguageIdentifier languageIdentifier =\n                LanguageIdentification.getClient();\n        languageIdentifier.identifyPossibleLanguages(text)\n                .addOnSuccessListener(new OnSuccessListener<List<IdentifiedLanguage>>() {\n                    @Override\n                    public void onSuccess(List<IdentifiedLanguage> identifiedLanguages) {\n                        for (IdentifiedLanguage identifiedLanguage : identifiedLanguages) {\n                            String language = identifiedLanguage.getLanguageTag();\n                            float confidence = identifiedLanguage.getConfidence();\n                            Log.i(TAG, language + \" (\" + confidence + \")\");\n                        }\n                    }\n                })\n                .addOnFailureListener(\n                        new OnFailureListener() {\n                            @Override\n                            public void onFailure(@NonNull Exception e) {\n                                // Model couldn’t be loaded or other internal error.\n                                // ...\n                            }\n                        });\n        // [END get_possible_languages]\n    }\n\n    private void setConfidenceThreshold() {\n        // [START set_confidence_threshold]\n        LanguageIdentificationOptions identifierOptions =\n                new LanguageIdentificationOptions.Builder()\n                        .setConfidenceThreshold(0.5f)\n                        .build();\n        LanguageIdentifier languageIdentifier = LanguageIdentification\n                .getClient(identifierOptions);\n        // [END set_confidence_threshold]\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/MLKitVisionImage.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.hardware.camera2.CameraAccessException;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.hardware.camera2.CameraManager;\nimport android.media.Image;\nimport android.net.Uri;\nimport android.os.Build;\n\nimport androidx.annotation.RequiresApi;\n\nimport android.util.SparseIntArray;\nimport android.view.Surface;\n\nimport com.google.mlkit.vision.common.InputImage;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\nimport static android.content.Context.CAMERA_SERVICE;\n\npublic class MLKitVisionImage {\n\n    private static final String TAG = \"MLKIT\";\n    private static final String MY_CAMERA_ID = \"my_camera_id\";\n\n    private void imageFromBitmap(Bitmap bitmap) {\n        int rotationDegree = 0;\n        // [START image_from_bitmap]\n        InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);\n        // [END image_from_bitmap]\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.KITKAT)\n    private void imageFromMediaImage(Image mediaImage, int rotation) {\n        // [START image_from_media_image]\n        InputImage image = InputImage.fromMediaImage(mediaImage, rotation);\n        // [END image_from_media_image]\n    }\n\n    private void imageFromBuffer(ByteBuffer byteBuffer, int rotationDegrees) {\n        // [START set_metadata]\n        // TODO How do we document the FrameMetadata developers need to implement?\n        // [END set_metadata]\n\n        // [START image_from_buffer]\n        InputImage image = InputImage.fromByteBuffer(byteBuffer,\n                /* image width */ 480,\n                /* image height */ 360,\n                rotationDegrees,\n                InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12\n        );\n        // [END image_from_buffer]\n    }\n\n    private void imageFromArray(byte[] byteArray, int rotation) {\n        // [START image_from_array]\n        InputImage image = InputImage.fromByteArray(\n                byteArray,\n                /* image width */480,\n                /* image height */360,\n                rotation,\n                InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12\n        );\n        // [END image_from_array]\n    }\n\n    private void imageFromPath(Context context, Uri uri) {\n        // [START image_from_path]\n        InputImage image;\n        try {\n            image = InputImage.fromFilePath(context, uri);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        // [END image_from_path]\n    }\n\n    // [START get_rotation]\n    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();\n    static {\n        ORIENTATIONS.append(Surface.ROTATION_0, 0);\n        ORIENTATIONS.append(Surface.ROTATION_90, 90);\n        ORIENTATIONS.append(Surface.ROTATION_180, 180);\n        ORIENTATIONS.append(Surface.ROTATION_270, 270);\n    }\n\n    /**\n     * Get the angle by which an image must be rotated given the device's current\n     * orientation.\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private int getRotationCompensation(String cameraId, Activity activity, boolean isFrontFacing)\n            throws CameraAccessException {\n        // Get the device's current rotation relative to its \"native\" orientation.\n        // Then, from the ORIENTATIONS table, look up the angle the image must be\n        // rotated to compensate for the device's rotation.\n        int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();\n        int rotationCompensation = ORIENTATIONS.get(deviceRotation);\n\n        // Get the device's sensor orientation.\n        CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE);\n        int sensorOrientation = cameraManager\n                .getCameraCharacteristics(cameraId)\n                .get(CameraCharacteristics.SENSOR_ORIENTATION);\n\n        if (isFrontFacing) {\n            rotationCompensation = (sensorOrientation + rotationCompensation) % 360;\n        } else { // back-facing\n            rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360;\n        }\n        return rotationCompensation;\n    }\n    // [END get_rotation]\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void getCompensation(Activity activity, boolean isFrontFacing) throws CameraAccessException {\n        // Get the ID of the camera using CameraManager. Then:\n        int rotation = getRotationCompensation(MY_CAMERA_ID, activity, isFrontFacing);\n    }\n\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/MainActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\npublic class MainActivity extends AppCompatActivity {\n\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/ObjectDetectionActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Rect;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.mlkit.common.model.LocalModel;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.objects.DetectedObject;\nimport com.google.mlkit.vision.objects.ObjectDetection;\nimport com.google.mlkit.vision.objects.ObjectDetector;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions;\nimport com.google.mlkit.vision.objects.defaults.PredefinedCategory;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ObjectDetectionActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    private void useDefaultObjectDetector() {\n        // [START create_default_options]\n        // Live detection and tracking\n        ObjectDetectorOptions options =\n                new ObjectDetectorOptions.Builder()\n                        .setDetectorMode(ObjectDetectorOptions.STREAM_MODE)\n                        .enableClassification()  // Optional\n                        .build();\n\n        // Multiple object detection in static images\n        options =\n                new ObjectDetectorOptions.Builder()\n                        .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE)\n                        .enableMultipleObjects()\n                        .enableClassification()  // Optional\n                        .build();\n        // [END create_default_options]\n\n        // [START create_detector]\n        ObjectDetector objectDetector = ObjectDetection.getClient(options);\n        // [END create_detector]\n\n        InputImage image =\n                InputImage.fromBitmap(\n                        Bitmap.createBitmap(new int[100 * 100], 100, 100, Bitmap.Config.ARGB_8888),\n                        0);\n\n        // [START process_image]\n        objectDetector.process(image)\n                .addOnSuccessListener(\n                        new OnSuccessListener<List<DetectedObject>>() {\n                            @Override\n                            public void onSuccess(List<DetectedObject> detectedObjects) {\n                                // Task completed successfully\n                                // ...\n                            }\n                        })\n                .addOnFailureListener(\n                        new OnFailureListener() {\n                            @Override\n                            public void onFailure(@NonNull Exception e) {\n                                // Task failed with an exception\n                                // ...\n                            }\n                        });\n        // [END process_image]\n\n        List<DetectedObject> results = new ArrayList<>();\n        // [START read_results_default]\n        // The list of detected objects contains one item if multiple\n        // object detection wasn't enabled.\n        for (DetectedObject detectedObject : results) {\n            Rect boundingBox = detectedObject.getBoundingBox();\n            Integer trackingId = detectedObject.getTrackingId();\n            for (DetectedObject.Label label : detectedObject.getLabels()) {\n                String text = label.getText();\n                if (PredefinedCategory.FOOD.equals(text)) {\n                  // ...\n                }\n                int index = label.getIndex();\n                if (PredefinedCategory.FOOD_INDEX == index) {\n                  // ...\n                }\n                float confidence = label.getConfidence();\n            }\n        }\n        // [END read_results_default]\n    }\n\n    private void useCustomObjectDetector() {\n        InputImage image =\n                InputImage.fromBitmap(\n                        Bitmap.createBitmap(new int[100 * 100], 100, 100, Bitmap.Config.ARGB_8888),\n                        0);\n\n        // [START create_local_model]\n        LocalModel localModel =\n                new LocalModel.Builder()\n                        .setAssetFilePath(\"asset_file_path_to_tflite_model\")\n                        // or .setAbsoluteFilePath(\"absolute_file_path_to_tflite_model\")\n                        .build();\n        // [END create_local_model]\n\n        // [START create_custom_options]\n        // Live detection and tracking\n        CustomObjectDetectorOptions options =\n                new CustomObjectDetectorOptions.Builder(localModel)\n                        .setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE)\n                        .enableClassification()\n                        .setClassificationConfidenceThreshold(0.5f)\n                        .setMaxPerObjectLabelCount(3)\n                        .build();\n\n        // Multiple object detection in static images\n        options =\n                new CustomObjectDetectorOptions.Builder(localModel)\n                        .setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE)\n                        .enableMultipleObjects()\n                        .enableClassification()\n                        .setClassificationConfidenceThreshold(0.5f)\n                        .setMaxPerObjectLabelCount(3)\n                        .build();\n        // [END create_custom_options]\n\n        List<DetectedObject> results = new ArrayList<>();\n        // [START read_results_custom]\n        // The list of detected objects contains one item if multiple\n        // object detection wasn't enabled.\n        for (DetectedObject detectedObject : results) {\n            Rect boundingBox = detectedObject.getBoundingBox();\n            Integer trackingId = detectedObject.getTrackingId();\n            for (DetectedObject.Label label : detectedObject.getLabels()) {\n                String text = label.getText();\n                int index = label.getIndex();\n                float confidence = label.getConfidence();\n            }\n        }\n        // [END read_results_custom]\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/TextRecognitionActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit;\n\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.text.Text;\nimport com.google.mlkit.vision.text.TextRecognition;\nimport com.google.mlkit.vision.text.TextRecognizer;\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions;\n\npublic class TextRecognitionActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    private void recognizeText(InputImage image) {\n\n        // [START get_detector_default]\n        TextRecognizer recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);\n        // [END get_detector_default]\n\n        // [START run_detector]\n        Task<Text> result =\n                recognizer.process(image)\n                        .addOnSuccessListener(new OnSuccessListener<Text>() {\n                            @Override\n                            public void onSuccess(Text visionText) {\n                                // Task completed successfully\n                                // [START_EXCLUDE]\n                                // [START get_text]\n                                for (Text.TextBlock block : visionText.getTextBlocks()) {\n                                    Rect boundingBox = block.getBoundingBox();\n                                    Point[] cornerPoints = block.getCornerPoints();\n                                    String text = block.getText();\n\n                                    for (Text.Line line: block.getLines()) {\n                                        // ...\n                                        for (Text.Element element: line.getElements()) {\n                                            // ...\n                                            for (Text.Symbol symbol: element.getSymbols()) {\n                                                // ...\n                                            }\n                                        }\n                                    }\n                                }\n                                // [END get_text]\n                                // [END_EXCLUDE]\n                            }\n                        })\n                        .addOnFailureListener(\n                                new OnFailureListener() {\n                                    @Override\n                                    public void onFailure(@NonNull Exception e) {\n                                        // Task failed with an exception\n                                        // ...\n                                    }\n                                });\n        // [END run_detector]\n    }\n\n    private void processTextBlock(Text result) {\n        // [START mlkit_process_text_block]\n        String resultText = result.getText();\n        for (Text.TextBlock block : result.getTextBlocks()) {\n            String blockText = block.getText();\n            Point[] blockCornerPoints = block.getCornerPoints();\n            Rect blockFrame = block.getBoundingBox();\n            for (Text.Line line : block.getLines()) {\n                String lineText = line.getText();\n                Point[] lineCornerPoints = line.getCornerPoints();\n                Rect lineFrame = line.getBoundingBox();\n                for (Text.Element element : line.getElements()) {\n                    String elementText = element.getText();\n                    Point[] elementCornerPoints = element.getCornerPoints();\n                    Rect elementFrame = element.getBoundingBox();\n                    for (Text.Symbol symbol : element.getSymbols()) {\n                        String symbolText = symbol.getText();\n                        Point[] symbolCornerPoints = symbol.getCornerPoints();\n                        Rect symbolFrame = symbol.getBoundingBox();\n                    }\n                }\n            }\n        }\n        // [END mlkit_process_text_block]\n    }\n\n    private TextRecognizer getTextRecognizer() {\n        // [START mlkit_local_doc_recognizer]\n        TextRecognizer detector = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);\n        // [END mlkit_local_doc_recognizer]\n\n        return detector;\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/kotlin/BarcodeScanningActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit.kotlin\n\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.vision.barcode.BarcodeScannerOptions\nimport com.google.mlkit.vision.barcode.BarcodeScanning\nimport com.google.mlkit.vision.barcode.common.Barcode\nimport com.google.mlkit.vision.common.InputImage\n\nclass BarcodeScanningActivity : AppCompatActivity() {\n\n    private fun scanBarcodes(image: InputImage) {\n        // [START set_detector_options]\n        val options = BarcodeScannerOptions.Builder()\n                .setBarcodeFormats(\n                        Barcode.FORMAT_QR_CODE,\n                        Barcode.FORMAT_AZTEC)\n                .build()\n        // [END set_detector_options]\n\n        // [START get_detector]\n        val scanner = BarcodeScanning.getClient()\n        // Or, to specify the formats to recognize:\n        // val scanner = BarcodeScanning.getClient(options)\n        // [END get_detector]\n\n        // [START run_detector]\n        val result = scanner.process(image)\n                .addOnSuccessListener { barcodes ->\n                    // Task completed successfully\n                    // [START_EXCLUDE]\n                    // [START get_barcodes]\n                    for (barcode in barcodes) {\n                        val bounds = barcode.boundingBox\n                        val corners = barcode.cornerPoints\n\n                        val rawValue = barcode.rawValue\n\n                        val valueType = barcode.valueType\n                        // See API reference for complete list of supported types\n                        when (valueType) {\n                            Barcode.TYPE_WIFI -> {\n                                val ssid = barcode.wifi!!.ssid\n                                val password = barcode.wifi!!.password\n                                val type = barcode.wifi!!.encryptionType\n                            }\n                            Barcode.TYPE_URL -> {\n                                val title = barcode.url!!.title\n                                val url = barcode.url!!.url\n                            }\n                        }\n                    }\n                    // [END get_barcodes]\n                    // [END_EXCLUDE]\n                }\n                .addOnFailureListener {\n                    // Task failed with an exception\n                    // ...\n                }\n        // [END run_detector]\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/kotlin/FaceDetectionActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit.kotlin\n\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.face.*\n\nclass FaceDetectionActivity : AppCompatActivity() {\n\n    private fun detectFaces(image: InputImage) {\n        // [START set_detector_options]\n        val options = FaceDetectorOptions.Builder()\n                .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)\n                .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)\n                .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)\n                .setMinFaceSize(0.15f)\n                .enableTracking()\n                .build()\n        // [END set_detector_options]\n\n        // [START get_detector]\n        val detector = FaceDetection.getClient(options)\n        // Or, to use the default option:\n        // val detector = FaceDetection.getClient();\n        // [END get_detector]\n\n        // [START run_detector]\n        val result = detector.process(image)\n                .addOnSuccessListener { faces ->\n                    // Task completed successfully\n                    // [START_EXCLUDE]\n                    // [START get_face_info]\n                    for (face in faces) {\n                        val bounds = face.boundingBox\n                        val rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees\n                        val rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees\n\n                        // If landmark detection was enabled (mouth, ears, eyes, cheeks, and\n                        // nose available):\n                        val leftEar = face.getLandmark(FaceLandmark.LEFT_EAR)\n                        leftEar?.let {\n                            val leftEarPos = leftEar.position\n                        }\n\n                        // If classification was enabled:\n                        if (face.smilingProbability != null) {\n                            val smileProb = face.smilingProbability\n                        }\n                        if (face.rightEyeOpenProbability != null) {\n                            val rightEyeOpenProb = face.rightEyeOpenProbability\n                        }\n\n                        // If face tracking was enabled:\n                        if (face.trackingId != null) {\n                            val id = face.trackingId\n                        }\n                    }\n                    // [END get_face_info]\n                    // [END_EXCLUDE]\n                }\n                .addOnFailureListener { e ->\n                    // Task failed with an exception\n                    // ...\n                }\n        // [END run_detector]\n    }\n\n    private fun faceOptionsExamples() {\n        // [START mlkit_face_options_examples]\n        // High-accuracy landmark detection and face classification\n        val highAccuracyOpts = FaceDetectorOptions.Builder()\n                .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)\n                .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)\n                .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)\n                .build()\n\n        // Real-time contour detection\n        val realTimeOpts = FaceDetectorOptions.Builder()\n                .setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL)\n                .build()\n        // [END mlkit_face_options_examples]\n    }\n\n    private fun processFaceList(faces: List<Face>) {\n        // [START mlkit_face_list]\n        for (face in faces) {\n            val bounds = face.boundingBox\n            val rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees\n            val rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees\n\n            // If landmark detection was enabled (mouth, ears, eyes, cheeks, and\n            // nose available):\n            val leftEar = face.getLandmark(FaceLandmark.LEFT_EAR)\n            leftEar?.let {\n                val leftEarPos = leftEar.position\n            }\n\n            // If contour detection was enabled:\n            val leftEyeContour = face.getContour(FaceContour.LEFT_EYE)?.points\n            val upperLipBottomContour = face.getContour(FaceContour.UPPER_LIP_BOTTOM)?.points\n\n            // If classification was enabled:\n            if (face.smilingProbability != null) {\n                val smileProb = face.smilingProbability\n            }\n            if (face.rightEyeOpenProbability != null) {\n                val rightEyeOpenProb = face.rightEyeOpenProbability\n            }\n\n            // If face tracking was enabled:\n            if (face.trackingId != null) {\n                val id = face.trackingId\n            }\n        }\n        // [END mlkit_face_list]\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/kotlin/ImageLabelingActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit.kotlin\n\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.label.ImageLabeler\nimport com.google.mlkit.vision.label.ImageLabeling\nimport com.google.mlkit.vision.label.defaults.ImageLabelerOptions\n\nclass ImageLabelingActivity : AppCompatActivity() {\n\n    private fun labelImages(image: InputImage) {\n        val options = ImageLabelerOptions.Builder()\n                .setConfidenceThreshold(0.8f)\n                .build()\n\n        val labeler = ImageLabeling.getClient(options)\n\n        // [START run_detector]\n        val result = labeler.process(image)\n                .addOnSuccessListener { labels ->\n                    // Task completed successfully\n                    // [START_EXCLUDE]\n                    // [START get_labels]\n                    for (label in labels) {\n                        val text = label.text\n                        val confidence = label.confidence\n                    }\n                    // [END get_labels]\n                    // [END_EXCLUDE]\n                }\n                .addOnFailureListener { e ->\n                    // Task failed with an exception\n                    // ...\n                }\n        // [END run_detector]\n    }\n\n    private fun configureAndRunImageLabeler(image: InputImage) {\n        // [START on_device_image_labeler]\n        // To use default options:\n        val labeler = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS)\n\n        // Or, to set the minimum confidence required:\n        // val options = ImageLabelerOptions.Builder()\n        //     .setConfidenceThreshold(0.7f)\n        //     .build()\n        // val labeler = ImageLabeling.getClient(options)\n\n        // [END on_device_image_labeler]\n\n        // Process image with custom onSuccess() example\n        // [START process_image]\n        labeler.process(image)\n                .addOnSuccessListener { labels ->\n                    // Task completed successfully\n                    // ...\n                }\n                .addOnFailureListener { e ->\n                    // Task failed with an exception\n                    // ...\n                }\n        // [END process_image]\n\n        // Process image with example onSuccess()\n        labeler.process(image)\n                .addOnSuccessListener { labels ->\n                    // [START get_image_label_info]\n                    for (label in labels) {\n                        val text = label.text\n                        val confidence = label.confidence\n                        val index = label.index\n                    }\n                    // [END get_image_label_info]\n                }\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/kotlin/LanguageIdentificationActivity.kt",
    "content": "package com.google.example.mlkit.kotlin\n\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.nl.languageid.LanguageIdentification\nimport com.google.mlkit.nl.languageid.LanguageIdentificationOptions\n\nprivate const val TAG = \"LangIDActivity\"\n\nclass LanguageIdentificationActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n    }\n\n    fun identifyLanguageWithStringInput(text: String) {\n        // [START identify_languages]\n        val languageIdentifier = LanguageIdentification.getClient()\n        languageIdentifier.identifyLanguage(text)\n                .addOnSuccessListener { languageCode ->\n                    if (languageCode == \"und\") {\n                        Log.i(TAG, \"Can't identify language.\")\n                    } else {\n                        Log.i(TAG, \"Language: $languageCode\")\n                    }\n                }\n                .addOnFailureListener {\n                    // Model couldn’t be loaded or other internal error.\n                    // ...\n                }\n        // [END identify_languages]\n    }\n\n    fun setConfidence() {\n        // [START set_confidence]\n        val languageIdentifier = LanguageIdentification\n                .getClient(LanguageIdentificationOptions.Builder()\n                        .setConfidenceThreshold(0.34f)\n                        .build())\n        // [END set_confidence]\n    }\n\n    fun getPossibleLanguuages(text: String) {\n        // [START get_possible_languages]\n        val languageIdentifier = LanguageIdentification.getClient()\n        languageIdentifier.identifyPossibleLanguages(text)\n                .addOnSuccessListener { identifiedLanguages ->\n                    for (identifiedLanguage in identifiedLanguages) {\n                        val language = identifiedLanguage.languageTag\n                        val confidence = identifiedLanguage.confidence\n                        Log.i(TAG, \"$language $confidence\")\n                    }\n                }\n                .addOnFailureListener {\n                    // Model couldn’t be loaded or other internal error.\n                    // ...\n                }\n        // [END get_possible_languages]\n    }\n\n    private fun setConfidenceThreshold() {\n        // [START set_confidence_threshold]\n        val identifierOptions = LanguageIdentificationOptions.Builder()\n                .setConfidenceThreshold(0.5f)\n                .build()\n        val languageIdentifier = LanguageIdentification\n                .getClient(identifierOptions)\n        // [END set_confidence_threshold]\n    }\n\n\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/kotlin/MLKitVisionImage.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit.kotlin\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Context.CAMERA_SERVICE\nimport android.graphics.Bitmap\nimport android.hardware.camera2.CameraAccessException\nimport android.hardware.camera2.CameraCharacteristics\nimport android.hardware.camera2.CameraManager\nimport android.media.Image\nimport android.net.Uri\nimport android.os.Build\nimport android.util.SparseIntArray\nimport android.view.Surface\nimport androidx.annotation.RequiresApi\nimport com.google.mlkit.vision.common.InputImage\nimport java.io.IOException\nimport java.nio.ByteBuffer\n\n\nclass MLKitVisionImage {\n\n    private fun imageFromBitmap(bitmap: Bitmap) {\n        val rotationDegrees = 0\n        // [START image_from_bitmap]\n        val image = InputImage.fromBitmap(bitmap, 0)\n        // [END image_from_bitmap]\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.KITKAT)\n    private fun imageFromMediaImage(mediaImage: Image, rotation: Int) {\n        // [START image_from_media_image]\n        val image = InputImage.fromMediaImage(mediaImage, rotation)\n        // [END image_from_media_image]\n    }\n\n    private fun imageFromBuffer(byteBuffer: ByteBuffer, rotationDegrees: Int) {\n        // [START set_metadata]\n        // TODO How do we document the FrameMetadata developers need to implement?\n        // [END set_metadata]\n        // [START image_from_buffer]\n        val image = InputImage.fromByteBuffer(\n                byteBuffer,\n                /* image width */ 480,\n                /* image height */ 360,\n                rotationDegrees,\n                InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12\n        )\n        // [END image_from_buffer]\n    }\n\n    private fun imageFromArray(byteArray: ByteArray, rotationDegrees: Int) {\n        // [START image_from_array]\n        val image = InputImage.fromByteArray(\n                byteArray,\n                /* image width */ 480,\n                /* image height */ 360,\n                rotationDegrees,\n                InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12\n        )\n\n        // [END image_from_array]\n    }\n\n    private fun imageFromPath(context: Context, uri: Uri) {\n        // [START image_from_path]\n        val image: InputImage\n        try {\n            image = InputImage.fromFilePath(context, uri)\n        } catch (e: IOException) {\n            e.printStackTrace()\n        }\n        // [END image_from_path]\n    }\n\n    // [START get_rotation]\n    /**\n     * Get the angle by which an image must be rotated given the device's current\n     * orientation.\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Throws(CameraAccessException::class)\n    private fun getRotationCompensation(cameraId: String, activity: Activity, isFrontFacing: Boolean): Int {\n        // Get the device's current rotation relative to its \"native\" orientation.\n        // Then, from the ORIENTATIONS table, look up the angle the image must be\n        // rotated to compensate for the device's rotation.\n        val deviceRotation = activity.windowManager.defaultDisplay.rotation\n        var rotationCompensation = ORIENTATIONS.get(deviceRotation)\n\n        // Get the device's sensor orientation.\n        val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager\n        val sensorOrientation = cameraManager\n                .getCameraCharacteristics(cameraId)\n                .get(CameraCharacteristics.SENSOR_ORIENTATION)!!\n\n        if (isFrontFacing) {\n            rotationCompensation = (sensorOrientation + rotationCompensation) % 360\n        } else { // back-facing\n            rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360\n        }\n        return rotationCompensation\n    }\n    // [END get_rotation]\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Throws(CameraAccessException::class)\n    private fun getCompensation(activity: Activity, context: Context, isFrontFacing: Boolean) {\n        // Get the ID of the camera using CameraManager. Then:\n        val rotation = getRotationCompensation(MY_CAMERA_ID, activity, isFrontFacing)\n    }\n\n    companion object {\n\n        private val TAG = \"MLKIT\"\n        private val MY_CAMERA_ID = \"my_camera_id\"\n\n        // [START camera_orientations]\n        private val ORIENTATIONS = SparseIntArray()\n\n        init {\n            ORIENTATIONS.append(Surface.ROTATION_0, 0)\n            ORIENTATIONS.append(Surface.ROTATION_90, 90)\n            ORIENTATIONS.append(Surface.ROTATION_180, 180)\n            ORIENTATIONS.append(Surface.ROTATION_270, 270)\n        }\n        // [END camera_orientations]\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/kotlin/MainActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit.kotlin\n\nimport androidx.appcompat.app.AppCompatActivity\n\nclass MainActivity : AppCompatActivity()\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/kotlin/ObjectDetectionActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit.kotlin\n\nimport android.graphics.Bitmap\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.common.model.LocalModel\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.objects.DetectedObject\nimport com.google.mlkit.vision.objects.ObjectDetection\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions\nimport com.google.mlkit.vision.objects.defaults.PredefinedCategory\n\nclass ObjectDetectionActivity : AppCompatActivity() {\n\n    private fun useDefaultObjectDetector() {\n        // [START create_default_options]\n        // Live detection and tracking\n        var options = ObjectDetectorOptions.Builder()\n                .setDetectorMode(ObjectDetectorOptions.STREAM_MODE)\n                .enableClassification()  // Optional\n                .build()\n\n        // Multiple object detection in static images\n        options = ObjectDetectorOptions.Builder()\n                .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE)\n                .enableMultipleObjects()\n                .enableClassification()  // Optional\n                .build()\n        // [END create_default_options]\n\n        // [START create_detector]\n        val objectDetector = ObjectDetection.getClient(options)\n        // [END create_detector]\n\n        val image = InputImage.fromBitmap(\n                Bitmap.createBitmap(IntArray(100 * 100), 100, 100, Bitmap.Config.ARGB_8888),\n                0)\n\n        // [START process_image]\n        objectDetector.process(image)\n                .addOnSuccessListener { results ->\n                    // Task completed successfully\n                    // ...\n                }\n                .addOnFailureListener { e ->\n                    // Task failed with an exception\n                    // ...\n                }\n        // [END process_image]\n\n        val results = listOf<DetectedObject>()\n        // [START read_results_default]\n        for (detectedObject in results) {\n            val boundingBox = detectedObject.boundingBox\n            val trackingId = detectedObject.trackingId\n            for (label in detectedObject.labels) {\n                val text = label.text\n                if (PredefinedCategory.FOOD == text) {\n                    // ...\n                }\n                val index = label.index\n                if (PredefinedCategory.FOOD_INDEX == index) {\n                    // ...\n                }\n                val confidence = label.confidence\n            }\n        }\n        // [END read_results_default]\n    }\n\n    private fun useCustomObjectDetector() {\n        val image = InputImage.fromBitmap(\n                Bitmap.createBitmap(IntArray(100 * 100), 100, 100, Bitmap.Config.ARGB_8888),\n                0)\n\n        // [START create_local_model]\n        val localModel =\n                LocalModel.Builder()\n                        .setAssetFilePath(\"asset_file_path_to_tflite_model\")\n                        // or .setAbsoluteFilePath(\"absolute_file_path_to_tflite_model\")\n                        .build()\n        // [END create_local_model]\n\n        // [START create_custom_options]\n        // Live detection and tracking\n        var options =\n                CustomObjectDetectorOptions.Builder(localModel)\n                        .setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE)\n                        .enableClassification()\n                        .setClassificationConfidenceThreshold(0.5f)\n                        .setMaxPerObjectLabelCount(3)\n                        .build()\n\n        // Multiple object detection in static images\n        options =\n                CustomObjectDetectorOptions.Builder(localModel)\n                        .setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE)\n                        .enableMultipleObjects()\n                        .enableClassification()\n                        .setClassificationConfidenceThreshold(0.5f)\n                        .setMaxPerObjectLabelCount(3)\n                        .build()\n        // [END create_custom_options]\n\n        val results = listOf<DetectedObject>()\n        // [START read_results_custom]\n        for (detectedObject in results) {\n            val boundingBox = detectedObject.boundingBox\n            val trackingId = detectedObject.trackingId\n            for (label in detectedObject.labels) {\n                val text = label.text\n                val index = label.index\n                val confidence = label.confidence\n            }\n        }\n        // [END read_results_custom]\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/java/com/google/example/mlkit/kotlin/TextRecognitionActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.example.mlkit.kotlin\n\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.text.Text\nimport com.google.mlkit.vision.text.TextRecognition\nimport com.google.mlkit.vision.text.TextRecognizer\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions\n\nclass TextRecognitionActivity : AppCompatActivity() {\n\n    private fun recognizeText(image: InputImage) {\n\n        // [START get_detector_default]\n        val recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)\n        // [END get_detector_default]\n\n        // [START run_detector]\n        val result = recognizer.process(image)\n                .addOnSuccessListener { visionText ->\n                    // Task completed successfully\n                    // [START_EXCLUDE]\n                    // [START get_text]\n                    for (block in visionText.textBlocks) {\n                        val boundingBox = block.boundingBox\n                        val cornerPoints = block.cornerPoints\n                        val text = block.text\n\n                        for (line in block.lines) {\n                            // ...\n                            for (element in line.elements) {\n                                // ...\n                            }\n                        }\n                    }\n                    // [END get_text]\n                    // [END_EXCLUDE]\n                }\n                .addOnFailureListener { e ->\n                    // Task failed with an exception\n                    // ...\n                }\n        // [END run_detector]\n    }\n\n    private fun processTextBlock(result: Text) {\n        // [START mlkit_process_text_block]\n        val resultText = result.text\n        for (block in result.textBlocks) {\n            val blockText = block.text\n            val blockCornerPoints = block.cornerPoints\n            val blockFrame = block.boundingBox\n            for (line in block.lines) {\n                val lineText = line.text\n                val lineCornerPoints = line.cornerPoints\n                val lineFrame = line.boundingBox\n                for (element in line.elements) {\n                    val elementText = element.text\n                    val elementCornerPoints = element.cornerPoints\n                    val elementFrame = element.boundingBox\n                }\n            }\n        }\n        // [END mlkit_process_text_block]\n    }\n\n    private fun getTextRecognizer(): TextRecognizer {\n        // [START mlkit_local_doc_recognizer]\n        return TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)\n        // [END mlkit_local_doc_recognizer]\n    }\n}\n"
  },
  {
    "path": "android/android-snippets/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:id=\"@+id/activity_main\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n        android:paddingRight=\"@dimen/activity_horizontal_margin\"\n        android:paddingTop=\"@dimen/activity_vertical_margin\"\n        android:paddingBottom=\"@dimen/activity_vertical_margin\"\n        tools:context=\".MainActivity\">\n\n    <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Hello World!\"/>\n</RelativeLayout>\n"
  },
  {
    "path": "android/android-snippets/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "android/android-snippets/app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "android/android-snippets/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">MLKit Code Snippets</string>\n</resources>\n"
  },
  {
    "path": "android/android-snippets/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "android/android-snippets/app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "android/android-snippets/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.4.31'\n    repositories {\n        mavenLocal()\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.2.1'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        mavenLocal()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/android-snippets/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Aug 24 22:29:37 PDT 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.3.3-all.zip\n"
  },
  {
    "path": "android/android-snippets/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\nandroid.enableJetifier=true\nandroid.useAndroidX=true\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "android/android-snippets/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/android-snippets/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      http://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/android-snippets/settings.gradle",
    "content": "include ':app'\n"
  },
  {
    "path": "android/automl/LICENSE",
    "content": "   Copyright 2020 Google LLC\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "android/automl/README.md",
    "content": "# ML Kit AutoML Remote Model Quickstart Sample App\n\n* [Read more about training an image classification model using AutoML Vision Edge model](https://firebase.google.com/docs/ml/automl-image-labeling)\n* [Read more about hosting models with Firebase Model deployment](https://firebase.google.com/docs/ml/manage-hosted-models)\n\n## Introduction\n\nThis ML Kit Quickstart App demonstrates how to label images and objects with an\nAutoML Vision Edge trained model, and also how to download models that are\nhosted within Firebase.\n\n## Feature List\nFeatures that are included in this demo app:\n\n* [Custom Image labeling](https://developers.google.com/ml-kit/vision/image-labeling/custom-models/android) - Label images using a custom AutoML VisionEdge trained model that is downloaded from Firebase.\n* [Custom Object Detection and Tracking](https://developers.google.com/ml-kit/vision/object-detection/custom-models/android) - Detect and label object using a custom AutoML VisionEdge trained model that is downloaded from Firebase.\n\n<img src=\"../screenshots/automl-quickstart.png\" width=\"256\"/>\n\n## Getting Started\n\n* In order to setup this app to run, you need to create a Firebase project as\noutlined [here](https://firebase.google.com/docs/android/setup).\n* Run the sample code on your Android device or emulator\n* Try extending the code to add new features and functionality\n* Ensure your device is connected to the Internet to download the remote model\n\n## How to use the app\nThis app supports three usage scenarios: Live Camera, Static Image, and CameraX\nenabled live camera.\n\n### Live Camera Scenario\nThis mode uses the camera preview as input and allows you to label images using\na remotely downloaded AutoML Vision Edge model. There is also a settings page\nthat allows you to configure several options:\n\n* Camera\n    * Preview Size -- Specify the preview size of rear camera manually (Default\n    size is chose appropriately based on screen size)\n    * Enable live viewport -- Prevent the live camera preview from being blocked\n    by API rendering speed.\n* AutoML Image Labeling\n    * AutoML Remote Model Name -- Allows you to specify an AutoML VisionEdge\n    model to remotely download from the Firebase Console\n\n### Static Image Scenario\nThe static image scenario is identical to the live camera scenario, but instead\nrelies on images fed into the app through the gallery.\n\n### CameraX Live Preview scenario\nThe CameraX live preview scenario is very similar to the native live camera\nscenario, but instead relies on CameraX live preview instead of the Camera2 live\npreview. Note: CameraX is only supported on API level 21+.\n\n\n## Support\n\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/google-mlkit)\n\n## License\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/automl/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 34\n\n    defaultConfig {\n        applicationId \"com.google.mlkit.vision.automl.demo\"\n        minSdkVersion 21\n        multiDexEnabled true\n        targetSdkVersion 34\n        // Version code for next release (version 9 is now in Play Store)\n        versionCode 11\n        versionName \"1.11\"\n        vectorDrawables.useSupportLibrary = true\n        setProperty(\"archivesBaseName\", \"vision-automl-remote-model-quickstart\")\n    }\n    buildTypes {\n        proguard {\n            debuggable false\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n            testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardTest-rules.pro', 'proguard.cfg'\n        }\n        testBuildType \"proguard\"\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n        debug {\n            minifyEnabled false\n            proguardFiles 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    // Do NOT compress tflite model files (need to call out to developers!)\n    aaptOptions {\n        noCompress \"tflite\"\n    }\n\n    dexOptions {\n        incremental true\n        javaMaxHeapSize \"4g\"\n    }\n}\n\nrepositories {\n    // Depending on AndroidX Snapshot Builds to get the latest CameraX libs.\n    maven { url 'https://androidx.dev/snapshots/builds/6787662/artifacts/repository/' }\n}\n\ndependencies {\n    // Image labeling with AutoML model support\n    implementation 'com.google.mlkit:image-labeling-custom:17.0.3'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-image-labeling-custom:16.0.0-beta5'\n\n    implementation 'com.google.mlkit:object-detection-custom:17.0.2'\n    implementation 'com.google.mlkit:linkfirebase:17.0.0'\n\n    implementation 'androidx.multidex:multidex:2.0.1'\n    // -------------------------------------------------------\n\n    implementation 'com.google.code.gson:gson:2.8.6'\n    implementation 'com.google.guava:guava:27.1-android'\n\n    // ViewModel and LiveData\n    implementation \"androidx.lifecycle:lifecycle-livedata:2.3.1\"\n    implementation \"androidx.lifecycle:lifecycle-viewmodel:2.3.1\"\n\n    implementation 'androidx.appcompat:appcompat:1.2.0'\n    implementation 'androidx.annotation:annotation:1.2.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'\n\n    // CameraX\n    implementation \"androidx.camera:camera-camera2:1.0.0-SNAPSHOT\"\n    implementation \"androidx.camera:camera-lifecycle:1.0.0-SNAPSHOT\"\n    implementation \"androidx.camera:camera-view:1.0.0-SNAPSHOT\"\n}\n\nconfigurations {\n    // Resolves dependency conflict caused by some dependencies use\n    // com.google.guava:guava and com.google.guava:listenablefuture together.\n    all*.exclude group: 'com.google.guava', module: 'listenablefuture'\n}\n"
  },
  {
    "path": "android/automl/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "android/automl/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.google.mlkit.vision.automl.demo\"\n    android:installLocation=\"auto\">\n\n  <!-- CameraX libraries require minSdkVersion 21, while this quickstart app\n  supports low to 19. Needs to use overrideLibrary to make the merger tool\n  ignore this conflict and import the libraries while keeping the app's lower\n  minSdkVersion value. In code, will check SDK version, before calling CameraX\n  APIs. -->\n  <uses-sdk\n      tools:overrideLibrary=\"\n          androidx.camera.camera2, androidx.camera.core,\n          androidx.camera.view, androidx.camera.lifecycle\" />\n\n  <uses-feature android:name=\"android.hardware.camera\"/>\n\n  <uses-permission android:name=\"android.permission.INTERNET\"/>\n  <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n  <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n  <uses-permission android:name=\"android.permission.CAMERA\"/>\n\n  <application\n      android:name=\"androidx.multidex.MultiDexApplication\"\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:theme=\"@style/Theme.AppCompat\">\n\n    <meta-data\n        android:name=\"com.google.android.gms.version\"\n        android:value=\"@integer/google_play_services_version\"/>\n    <meta-data\n        android:name=\"com.google.mlkit.vision.DEPENDENCIES\"\n        android:value=\"custom_ica\"/>\n\n    <activity\n        android:name=\".ChooserActivity\"\n        android:exported=\"true\"\n        android:theme=\"@style/AppTheme\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\"/>\n        <category android:name=\"android.intent.category.LAUNCHER\"/>\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\".LivePreviewActivity\"\n        android:exported=\"true\"\n        android:theme=\"@style/AppTheme\">\n    </activity>\n\n    <activity\n        android:name=\".CameraXLivePreviewActivity\"\n        android:exported=\"true\"\n        android:theme=\"@style/AppTheme\">\n    </activity>\n\n    <activity\n        android:name=\".StillImageActivity\"\n        android:exported=\"true\"\n        android:theme=\"@style/AppTheme\">\n    </activity>\n\n    <activity\n        android:name=\".preference.SettingsActivity\"\n        android:exported=\"false\"/>\n\n  </application>\n  <queries>\n    <intent>\n      <action android:name=\"android.media.action.IMAGE_CAPTURE\" />\n    </intent>\n  </queries>\n</manifest>\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/BitmapUtils.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport static java.lang.Math.min;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.ImageFormat;\nimport android.graphics.Matrix;\nimport android.graphics.Rect;\nimport android.graphics.YuvImage;\nimport android.media.Image;\nimport android.media.Image.Plane;\nimport android.net.Uri;\nimport android.os.Build.VERSION_CODES;\nimport android.provider.MediaStore;\nimport android.util.Log;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.core.ExperimentalGetImage;\nimport androidx.camera.core.ImageProxy;\nimport androidx.exifinterface.media.ExifInterface;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\n\n/** Utils functions for bitmap conversions. */\npublic final class BitmapUtils {\n  private static final String TAG = \"BitmapUtils\";\n\n  /** Converts NV21 format byte buffer to bitmap. */\n  @Nullable\n  public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {\n    data.rewind();\n    byte[] imageInBuffer = new byte[data.limit()];\n    data.get(imageInBuffer, 0, imageInBuffer.length);\n    try {\n      YuvImage image =\n          new YuvImage(\n              imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);\n      ByteArrayOutputStream stream = new ByteArrayOutputStream();\n      image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 80, stream);\n\n      Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());\n\n      stream.close();\n      return rotateBitmap(bmp, metadata.getRotation(), false, false);\n    } catch (Exception e) {\n      Log.e(\"VisionProcessorBase\", \"Error: \" + e.getMessage());\n    }\n    return null;\n  }\n\n  /** Converts a YUV_420_888 image from CameraX API to a bitmap. */\n  @RequiresApi(VERSION_CODES.LOLLIPOP)\n  @Nullable\n  @ExperimentalGetImage\n  public static Bitmap getBitmap(ImageProxy image) {\n    FrameMetadata frameMetadata =\n        new FrameMetadata.Builder()\n            .setWidth(image.getWidth())\n            .setHeight(image.getHeight())\n            .setRotation(image.getImageInfo().getRotationDegrees())\n            .build();\n\n    ByteBuffer nv21Buffer =\n        yuv420ThreePlanesToNV21(image.getImage().getPlanes(), image.getWidth(), image.getHeight());\n    return getBitmap(nv21Buffer, frameMetadata);\n  }\n\n  /** Rotates a bitmap if it is converted from a bytebuffer. */\n  private static Bitmap rotateBitmap(\n      Bitmap bitmap, int rotationDegrees, boolean flipX, boolean flipY) {\n    Matrix matrix = new Matrix();\n\n    // Rotate the image back to straight.\n    matrix.postRotate(rotationDegrees);\n\n    // Mirror the image along the X or Y axis.\n    matrix.postScale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);\n    Bitmap rotatedBitmap =\n        Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);\n\n    // Recycle the old bitmap if it has changed.\n    if (rotatedBitmap != bitmap) {\n      bitmap.recycle();\n    }\n    return rotatedBitmap;\n  }\n\n  @Nullable\n  public static Bitmap getBitmapFromAsset(Context context, String fileName) {\n    InputStream inputStream = null;\n    try {\n      inputStream = context.getAssets().open(fileName);\n      return BitmapFactory.decodeStream(inputStream);\n    } catch (IOException e) {\n      Log.e(TAG, \"Error reading asset: \" + fileName, e);\n    } finally {\n      if (inputStream != null) {\n        try {\n          inputStream.close();\n        } catch (IOException e) {\n          Log.e(TAG, \"Failed to close input stream: \", e);\n        }\n      }\n    }\n\n    return null;\n  }\n\n  @Nullable\n  public static Bitmap getBitmapFromContentUri(ContentResolver contentResolver, Uri imageUri)\n      throws IOException {\n    Bitmap decodedBitmap = MediaStore.Images.Media.getBitmap(contentResolver, imageUri);\n    if (decodedBitmap == null) {\n      return null;\n    }\n    int orientation = getExifOrientationTag(contentResolver, imageUri);\n\n    int rotationDegrees = 0;\n    boolean flipX = false;\n    boolean flipY = false;\n    // See e.g. https://magnushoff.com/articles/jpeg-orientation/ for a detailed explanation on each\n    // orientation.\n    switch (orientation) {\n      case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:\n        flipX = true;\n        break;\n      case ExifInterface.ORIENTATION_ROTATE_90:\n        rotationDegrees = 90;\n        break;\n      case ExifInterface.ORIENTATION_TRANSPOSE:\n        rotationDegrees = 90;\n        flipX = true;\n        break;\n      case ExifInterface.ORIENTATION_ROTATE_180:\n        rotationDegrees = 180;\n        break;\n      case ExifInterface.ORIENTATION_FLIP_VERTICAL:\n        flipY = true;\n        break;\n      case ExifInterface.ORIENTATION_ROTATE_270:\n        rotationDegrees = -90;\n        break;\n      case ExifInterface.ORIENTATION_TRANSVERSE:\n        rotationDegrees = -90;\n        flipX = true;\n        break;\n      case ExifInterface.ORIENTATION_UNDEFINED:\n      case ExifInterface.ORIENTATION_NORMAL:\n      default:\n        // No transformations necessary in this case.\n    }\n\n    return rotateBitmap(decodedBitmap, rotationDegrees, flipX, flipY);\n  }\n\n  private static int getExifOrientationTag(ContentResolver resolver, Uri imageUri) {\n    // We only support parsing EXIF orientation tag from local file on the device.\n    // See also:\n    // https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html\n    if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())\n        && !ContentResolver.SCHEME_FILE.equals(imageUri.getScheme())) {\n      return 0;\n    }\n\n    ExifInterface exif;\n    try (InputStream inputStream = resolver.openInputStream(imageUri)) {\n      if (inputStream == null) {\n        return 0;\n      }\n\n      exif = new ExifInterface(inputStream);\n    } catch (IOException e) {\n      Log.e(TAG, \"failed to open file to read rotation meta data: \" + imageUri, e);\n      return 0;\n    }\n\n    return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);\n  }\n\n  public static ByteBuffer convertBitmapToNv21Buffer(Bitmap bitmap) {\n    return ByteBuffer.wrap(convertBitmapToNv21Bytes(bitmap));\n  }\n\n  public static byte[] convertBitmapToNv21Bytes(Bitmap bitmap) {\n    int inputWidth = bitmap.getWidth();\n    int inputHeight = bitmap.getHeight();\n    int[] argb = new int[inputWidth * inputHeight];\n\n    bitmap.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);\n\n    byte[] nv21Bytes =\n        new byte\n            [inputHeight * inputWidth\n                + 2 * (int) Math.ceil(inputHeight / 2.0) * (int) Math.ceil(inputWidth / 2.0)];\n    encodeToNv21(nv21Bytes, argb, inputWidth, inputHeight);\n    return nv21Bytes;\n  }\n\n  private static void encodeToNv21(byte[] nv21Bytes, int[] argb, int width, int height) {\n    int frameSize = width * height;\n\n    int yIndex = 0;\n    int uvIndex = frameSize;\n\n    int red;\n    int green;\n    int blue;\n    int y;\n    int u;\n    int v;\n    int index = 0;\n    for (int j = 0; j < height; j++) {\n      for (int i = 0; i < width; i++) {\n\n        // first byte is alpha, but is unused\n        red = (argb[index] & 0xff0000) >> 16;\n        green = (argb[index] & 0xff00) >> 8;\n        blue = (argb[index] & 0xff) >> 0;\n\n        // well known RGB to YUV algorithm\n        y = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;\n        u = ((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128;\n        v = ((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128;\n\n        // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2\n        // meaning for every 4 Y pixels there are 1 V and 1 U.  Note the sampling is every other\n        // pixel AND every other scanline.\n        nv21Bytes[yIndex++] = (byte) ((y < 0) ? 0 : min(255, y));\n        if (j % 2 == 0 && index % 2 == 0) {\n          nv21Bytes[uvIndex++] = (byte) ((v < 0) ? 0 : min(255, v));\n          nv21Bytes[uvIndex++] = (byte) ((u < 0) ? 0 : min(255, u));\n        }\n\n        index++;\n      }\n    }\n  }\n\n  public static ByteBuffer convertBitmapToYv12Buffer(Bitmap bitmap) {\n    return ByteBuffer.wrap(convertBitmapToYv12Bytes(bitmap));\n  }\n\n  public static byte[] convertBitmapToYv12Bytes(Bitmap bitmap) {\n    byte[] nv21Bytes = convertBitmapToNv21Bytes(bitmap);\n    return nv21Toyv12(nv21Bytes);\n  }\n\n  /**\n   * Converts nv21 byte[] to yv12 byte[].\n   *\n   * <p>NV21 (4:2:0) Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y V U V U V U V U V U V U\n   *\n   * <p>YV12 (4:2:0) Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y V V V V V V U U U U U U\n   */\n  private static byte[] nv21Toyv12(byte[] nv21Bytes) {\n    int totalBytes = nv21Bytes.length;\n    int rowSize = totalBytes / 6; // 4+2+0\n    byte[] yv12Bytes = new byte[totalBytes];\n    System.arraycopy(nv21Bytes, 0, yv12Bytes, 0, rowSize * 4);\n    int offSet = totalBytes / 6 * 4;\n    for (int i = 0; i < rowSize; i++) {\n      yv12Bytes[offSet + i] = nv21Bytes[offSet + 2 * i]; // V\n      yv12Bytes[offSet + rowSize + i] = nv21Bytes[offSet + 2 * i + 1]; // U\n    }\n\n    return yv12Bytes;\n  }\n\n  /**\n   * Converts YUV_420_888 to NV21 bytebuffer.\n   *\n   * <p>The NV21 format consists of a single byte array containing the Y, U and V values. For an\n   * image of size S, the first S positions of the array contain all the Y values. The remaining\n   * positions contain interleaved V and U values. U and V are subsampled by a factor of 2 in both\n   * dimensions, so there are S/4 U values and S/4 V values. In summary, the NV21 array will contain\n   * S Y values followed by S/4 VU values: YYYYYYYYYYYYYY(...)YVUVUVUVU(...)VU\n   *\n   * <p>YUV_420_888 is a generic format that can describe any YUV image where U and V are subsampled\n   * by a factor of 2 in both dimensions. {@link Image#getPlanes} returns an array with the Y, U and\n   * V planes. The Y plane is guaranteed not to be interleaved, so we can just copy its values into\n   * the first part of the NV21 array. The U and V planes may already have the representation in the\n   * NV21 format. This happens if the planes share the same buffer, the V buffer is one position\n   * before the U buffer and the planes have a pixelStride of 2. If this is case, we can just copy\n   * them to the NV21 array.\n   */\n  private static ByteBuffer yuv420ThreePlanesToNV21(\n      Plane[] yuv420888planes, int width, int height) {\n    int imageSize = width * height;\n    byte[] out = new byte[imageSize + 2 * (imageSize / 4)];\n\n    if (areUVPlanesNV21(yuv420888planes, width, height)) {\n      // Copy the Y values.\n      yuv420888planes[0].getBuffer().get(out, 0, imageSize);\n\n      ByteBuffer uBuffer = yuv420888planes[1].getBuffer();\n      ByteBuffer vBuffer = yuv420888planes[2].getBuffer();\n      // Get the first V value from the V buffer, since the U buffer does not contain it.\n      vBuffer.get(out, imageSize, 1);\n      // Copy the first U value and the remaining VU values from the U buffer.\n      uBuffer.get(out, imageSize + 1, 2 * imageSize / 4 - 1);\n    } else {\n      // Fallback to copying the UV values one by one, which is slower but also works.\n      // Unpack Y.\n      unpackPlane(yuv420888planes[0], width, height, out, 0, 1);\n      // Unpack U.\n      unpackPlane(yuv420888planes[1], width, height, out, imageSize + 1, 2);\n      // Unpack V.\n      unpackPlane(yuv420888planes[2], width, height, out, imageSize, 2);\n    }\n\n    return ByteBuffer.wrap(out);\n  }\n\n  /** Checks if the UV plane buffers of a YUV_420_888 image are in the NV21 format. */\n  private static boolean areUVPlanesNV21(Plane[] planes, int width, int height) {\n    int imageSize = width * height;\n\n    ByteBuffer uBuffer = planes[1].getBuffer();\n    ByteBuffer vBuffer = planes[2].getBuffer();\n\n    // Backup buffer properties.\n    int vBufferPosition = vBuffer.position();\n    int uBufferLimit = uBuffer.limit();\n\n    // Advance the V buffer by 1 byte, since the U buffer will not contain the first V value.\n    vBuffer.position(vBufferPosition + 1);\n    // Chop off the last byte of the U buffer, since the V buffer will not contain the last U value.\n    uBuffer.limit(uBufferLimit - 1);\n\n    // Check that the buffers are equal and have the expected number of elements.\n    boolean areNV21 =\n        (vBuffer.remaining() == (2 * imageSize / 4 - 2)) && (vBuffer.compareTo(uBuffer) == 0);\n\n    // Restore buffers to their initial state.\n    vBuffer.position(vBufferPosition);\n    uBuffer.limit(uBufferLimit);\n\n    return areNV21;\n  }\n\n  /**\n   * Unpack an image plane into a byte array.\n   *\n   * <p>The input plane data will be copied in 'out', starting at 'offset' and every pixel will be\n   * spaced by 'pixelStride'. Note that there is no row padding on the output.\n   */\n  private static void unpackPlane(\n      Plane plane, int width, int height, byte[] out, int offset, int pixelStride) {\n    ByteBuffer buffer = plane.getBuffer();\n    buffer.rewind();\n\n    // Compute the size of the current plane.\n    // We assume that it has the aspect ratio as the original image.\n    int numRow = (buffer.limit() + plane.getRowStride() - 1) / plane.getRowStride();\n    if (numRow == 0) {\n      return;\n    }\n    int scaleFactor = height / numRow;\n    int numCol = width / scaleFactor;\n\n    // Extract the data in the output buffer.\n    int outputPos = offset;\n    int rowStart = 0;\n    for (int row = 0; row < numRow; row++) {\n      int inputPos = rowStart;\n      for (int col = 0; col < numCol; col++) {\n        out[outputPos] = buffer.get(inputPos);\n        outputPos += pixelStride;\n        inputPos += plane.getPixelStride();\n      }\n      rowStart += plane.getRowStride();\n    }\n  }\n\n  private BitmapUtils() {}\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/CameraImageGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport com.google.mlkit.vision.automl.demo.GraphicOverlay.Graphic;\n\n/** Draw camera image to background. */\npublic class CameraImageGraphic extends Graphic {\n\n  private final Bitmap bitmap;\n\n  public CameraImageGraphic(GraphicOverlay overlay, Bitmap bitmap) {\n    super(overlay);\n    this.bitmap = bitmap;\n  }\n\n  @Override\n  public void draw(Canvas canvas) {\n    canvas.drawBitmap(bitmap, getTransformationMatrix(), null);\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/CameraSource.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.ImageFormat;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.Camera;\nimport android.hardware.Camera.CameraInfo;\nimport android.util.Log;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\nimport android.view.WindowManager;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport com.google.android.gms.common.images.Size;\nimport com.google.mlkit.vision.automl.demo.preference.PreferenceUtils;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.IdentityHashMap;\nimport java.util.List;\n\n/**\n * Manages the camera and allows UI updates on top of it (e.g. overlaying extra Graphics or\n * displaying extra information). This receives preview frames from the camera at a specified rate,\n * sending those frames to child classes' detectors / classifiers as fast as it is able to process.\n */\npublic class CameraSource {\n  @SuppressLint(\"InlinedApi\")\n  public static final int CAMERA_FACING_BACK = CameraInfo.CAMERA_FACING_BACK;\n\n  @SuppressLint(\"InlinedApi\")\n  public static final int CAMERA_FACING_FRONT = CameraInfo.CAMERA_FACING_FRONT;\n\n  public static final int IMAGE_FORMAT = ImageFormat.NV21;\n  public static final int DEFAULT_REQUESTED_CAMERA_PREVIEW_WIDTH = 480;\n  public static final int DEFAULT_REQUESTED_CAMERA_PREVIEW_HEIGHT = 360;\n\n  private static final String TAG = \"MIDemoApp:CameraSource\";\n\n  /**\n   * The dummy surface texture must be assigned a chosen name. Since we never use an OpenGL context,\n   * we can choose any ID we want here. The dummy surface texture is not a crazy hack - it is\n   * actually how the camera team recommends using the camera without a preview.\n   */\n  private static final int DUMMY_TEXTURE_NAME = 100;\n\n  /**\n   * If the absolute difference between a preview size aspect ratio and a picture size aspect ratio\n   * is less than this tolerance, they are considered to be the same aspect ratio.\n   */\n  private static final float ASPECT_RATIO_TOLERANCE = 0.01f;\n\n  private static final float REQUESTED_FPS = 30.0f;\n  private static final boolean REQUESTED_AUTO_FOCUS = true;\n\n  protected Activity activity;\n\n  private Camera camera;\n\n  private int facing = CAMERA_FACING_BACK;\n\n  /** Rotation of the device, and thus the associated preview images captured from the device. */\n  private int rotationDegrees;\n\n  private Size previewSize;\n\n  // These instances need to be held onto to avoid GC of their underlying resources.  Even though\n  // these aren't used outside of the method that creates them, they still must have hard\n  // references maintained to them.\n  private SurfaceTexture dummySurfaceTexture;\n  private final GraphicOverlay graphicOverlay;\n\n  // True if a SurfaceTexture is being used for the preview, false if a SurfaceHolder is being\n  // used for the preview.  We want to be compatible back to Gingerbread, but SurfaceTexture\n  // wasn't introduced until Honeycomb.  Since the interface cannot use a SurfaceTexture, if the\n  // developer wants to display a preview we must use a SurfaceHolder.  If the developer doesn't\n  // want to display a preview we use a SurfaceTexture if we are running at least Honeycomb.\n  private boolean usingSurfaceTexture;\n\n  /**\n   * Dedicated thread and associated runnable for calling into the detector with frames, as the\n   * frames become available from the camera.\n   */\n  private Thread processingThread;\n\n  private final FrameProcessingRunnable processingRunnable;\n\n  private final Object processorLock = new Object();\n  // TODO(b/74400062) Re-enable the annotaion\n  // @GuardedBy(\"processorLock\")\n  private VisionImageProcessor frameProcessor;\n\n  /**\n   * Map to convert between a byte array, received from the camera, and its associated byte buffer.\n   * We use byte buffers internally because this is a more efficient way to call into native code\n   * later (avoids a potential copy).\n   *\n   * <p><b>Note:</b> uses IdentityHashMap here instead of HashMap because the behavior of an array's\n   * equals, hashCode and toString methods is both useless and unexpected. IdentityHashMap enforces\n   * identity ('==') check on the keys.\n   */\n  private final IdentityHashMap<byte[], ByteBuffer> bytesToByteBuffer = new IdentityHashMap<>();\n\n  public CameraSource(Activity activity, GraphicOverlay overlay) {\n    this.activity = activity;\n    graphicOverlay = overlay;\n    graphicOverlay.clear();\n    processingRunnable = new FrameProcessingRunnable();\n  }\n\n  // ==============================================================================================\n  // Public\n  // ==============================================================================================\n\n  /** Stops the camera and releases the resources of the camera and underlying detector. */\n  public void release() {\n    synchronized (processorLock) {\n      stop();\n      cleanScreen();\n\n      if (frameProcessor != null) {\n        frameProcessor.stop();\n      }\n    }\n  }\n\n  /**\n   * Opens the camera and starts sending preview frames to the underlying detector. The preview\n   * frames are not displayed.\n   *\n   * @throws IOException if the camera's preview texture or display could not be initialized\n   */\n  @RequiresPermission(Manifest.permission.CAMERA)\n  public synchronized CameraSource start() throws IOException {\n    if (camera != null) {\n      return this;\n    }\n\n    camera = createCamera();\n    dummySurfaceTexture = new SurfaceTexture(DUMMY_TEXTURE_NAME);\n    camera.setPreviewTexture(dummySurfaceTexture);\n    usingSurfaceTexture = true;\n    camera.startPreview();\n\n    processingThread = new Thread(processingRunnable);\n    processingRunnable.setActive(true);\n    processingThread.start();\n    return this;\n  }\n\n  /**\n   * Opens the camera and starts sending preview frames to the underlying detector. The supplied\n   * surface holder is used for the preview so frames can be displayed to the user.\n   *\n   * @param surfaceHolder the surface holder to use for the preview frames\n   * @throws IOException if the supplied surface holder could not be used as the preview display\n   */\n  @RequiresPermission(Manifest.permission.CAMERA)\n  public synchronized CameraSource start(SurfaceHolder surfaceHolder) throws IOException {\n    if (camera != null) {\n      return this;\n    }\n\n    camera = createCamera();\n    camera.setPreviewDisplay(surfaceHolder);\n    camera.startPreview();\n\n    processingThread = new Thread(processingRunnable);\n    processingRunnable.setActive(true);\n    processingThread.start();\n\n    usingSurfaceTexture = false;\n    return this;\n  }\n\n  /**\n   * Closes the camera and stops sending frames to the underlying frame detector.\n   *\n   * <p>This camera source may be restarted again by calling {@link #start()} or {@link\n   * #start(SurfaceHolder)}.\n   *\n   * <p>Call {@link #release()} instead to completely shut down this camera source and release the\n   * resources of the underlying detector.\n   */\n  public synchronized void stop() {\n    processingRunnable.setActive(false);\n    if (processingThread != null) {\n      try {\n        // Wait for the thread to complete to ensure that we can't have multiple threads\n        // executing at the same time (i.e., which would happen if we called start too\n        // quickly after stop).\n        processingThread.join();\n      } catch (InterruptedException e) {\n        Log.d(TAG, \"Frame processing thread interrupted on release.\");\n      }\n      processingThread = null;\n    }\n\n    if (camera != null) {\n      camera.stopPreview();\n      camera.setPreviewCallbackWithBuffer(null);\n      try {\n        if (usingSurfaceTexture) {\n          camera.setPreviewTexture(null);\n        } else {\n          camera.setPreviewDisplay(null);\n        }\n      } catch (Exception e) {\n        Log.e(TAG, \"Failed to clear camera preview: \" + e);\n      }\n      camera.release();\n      camera = null;\n    }\n\n    // Release the reference to any image buffers, since these will no longer be in use.\n    bytesToByteBuffer.clear();\n  }\n\n  /** Changes the facing of the camera. */\n  public synchronized void setFacing(int facing) {\n    if ((facing != CAMERA_FACING_BACK) && (facing != CAMERA_FACING_FRONT)) {\n      throw new IllegalArgumentException(\"Invalid camera: \" + facing);\n    }\n    this.facing = facing;\n  }\n\n  /** Returns the preview size that is currently in use by the underlying camera. */\n  public Size getPreviewSize() {\n    return previewSize;\n  }\n\n  /**\n   * Returns the selected camera; one of {@link #CAMERA_FACING_BACK} or {@link\n   * #CAMERA_FACING_FRONT}.\n   */\n  public int getCameraFacing() {\n    return facing;\n  }\n\n  /**\n   * Opens the camera and applies the user settings.\n   *\n   * @throws IOException if camera cannot be found or preview cannot be processed\n   */\n  @SuppressLint(\"InlinedApi\")\n  private Camera createCamera() throws IOException {\n    int requestedCameraId = getIdForRequestedCamera(facing);\n    if (requestedCameraId == -1) {\n      throw new IOException(\"Could not find requested camera.\");\n    }\n    Camera camera = Camera.open(requestedCameraId);\n\n    SizePair sizePair = PreferenceUtils.getCameraPreviewSizePair(activity, requestedCameraId);\n    if (sizePair == null) {\n      sizePair =\n          selectSizePair(\n              camera,\n              DEFAULT_REQUESTED_CAMERA_PREVIEW_WIDTH,\n              DEFAULT_REQUESTED_CAMERA_PREVIEW_HEIGHT);\n    }\n\n    if (sizePair == null) {\n      throw new IOException(\"Could not find suitable preview size.\");\n    }\n\n    previewSize = sizePair.preview;\n    Log.v(TAG, \"Camera preview size: \" + previewSize);\n\n    int[] previewFpsRange = selectPreviewFpsRange(camera, REQUESTED_FPS);\n    if (previewFpsRange == null) {\n      throw new IOException(\"Could not find suitable preview frames per second range.\");\n    }\n\n    Camera.Parameters parameters = camera.getParameters();\n\n    Size pictureSize = sizePair.picture;\n    if (pictureSize != null) {\n      Log.v(TAG, \"Camera picture size: \" + pictureSize);\n      parameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());\n    }\n    parameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());\n    parameters.setPreviewFpsRange(\n        previewFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],\n        previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);\n    // Use YV12 so that we can exercise YV12->NV21 auto-conversion logic for OCR detection\n    parameters.setPreviewFormat(IMAGE_FORMAT);\n\n    setRotation(camera, parameters, requestedCameraId);\n\n    if (REQUESTED_AUTO_FOCUS) {\n      if (parameters\n          .getSupportedFocusModes()\n          .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {\n        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);\n      } else {\n        Log.i(TAG, \"Camera auto focus is not supported on this device.\");\n      }\n    }\n\n    camera.setParameters(parameters);\n\n    // Four frame buffers are needed for working with the camera:\n    //\n    //   one for the frame that is currently being executed upon in doing detection\n    //   one for the next pending frame to process immediately upon completing detection\n    //   two for the frames that the camera uses to populate future preview images\n    //\n    // Through trial and error it appears that two free buffers, in addition to the two buffers\n    // used in this code, are needed for the camera to work properly.  Perhaps the camera has\n    // one thread for acquiring images, and another thread for calling into user code.  If only\n    // three buffers are used, then the camera will spew thousands of warning messages when\n    // detection takes a non-trivial amount of time.\n    camera.setPreviewCallbackWithBuffer(new CameraPreviewCallback());\n    camera.addCallbackBuffer(createPreviewBuffer(previewSize));\n    camera.addCallbackBuffer(createPreviewBuffer(previewSize));\n    camera.addCallbackBuffer(createPreviewBuffer(previewSize));\n    camera.addCallbackBuffer(createPreviewBuffer(previewSize));\n\n    return camera;\n  }\n\n  /**\n   * Gets the id for the camera specified by the direction it is facing. Returns -1 if no such\n   * camera was found.\n   *\n   * @param facing the desired camera (front-facing or rear-facing)\n   */\n  private static int getIdForRequestedCamera(int facing) {\n    CameraInfo cameraInfo = new CameraInfo();\n    for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {\n      Camera.getCameraInfo(i, cameraInfo);\n      if (cameraInfo.facing == facing) {\n        return i;\n      }\n    }\n    return -1;\n  }\n\n  /**\n   * Selects the most suitable preview and picture size, given the desired width and height.\n   *\n   * <p>Even though we only need to find the preview size, it's necessary to find both the preview\n   * size and the picture size of the camera together, because these need to have the same aspect\n   * ratio. On some hardware, if you would only set the preview size, you will get a distorted\n   * image.\n   *\n   * @param camera the camera to select a preview size from\n   * @param desiredWidth the desired width of the camera preview frames\n   * @param desiredHeight the desired height of the camera preview frames\n   * @return the selected preview and picture size pair\n   */\n  public static SizePair selectSizePair(Camera camera, int desiredWidth, int desiredHeight) {\n    List<SizePair> validPreviewSizes = generateValidPreviewSizeList(camera);\n\n    // The method for selecting the best size is to minimize the sum of the differences between\n    // the desired values and the actual values for width and height.  This is certainly not the\n    // only way to select the best size, but it provides a decent tradeoff between using the\n    // closest aspect ratio vs. using the closest pixel area.\n    SizePair selectedPair = null;\n    int minDiff = Integer.MAX_VALUE;\n    for (SizePair sizePair : validPreviewSizes) {\n      Size size = sizePair.preview;\n      int diff =\n          Math.abs(size.getWidth() - desiredWidth) + Math.abs(size.getHeight() - desiredHeight);\n      if (diff < minDiff) {\n        selectedPair = sizePair;\n        minDiff = diff;\n      }\n    }\n\n    return selectedPair;\n  }\n\n  /**\n   * Stores a preview size and a corresponding same-aspect-ratio picture size. To avoid distorted\n   * preview images on some devices, the picture size must be set to a size that is the same aspect\n   * ratio as the preview size or the preview may end up being distorted. If the picture size is\n   * null, then there is no picture size with the same aspect ratio as the preview size.\n   */\n  public static class SizePair {\n    public final Size preview;\n    @Nullable public final Size picture;\n\n    SizePair(\n        Camera.Size previewSize,\n        @Nullable Camera.Size pictureSize) {\n      preview = new Size(previewSize.width, previewSize.height);\n      picture = pictureSize != null ? new Size(pictureSize.width, pictureSize.height) : null;\n    }\n\n    public SizePair(Size previewSize, @Nullable Size pictureSize) {\n      preview = previewSize;\n      picture = pictureSize;\n    }\n  }\n\n  /**\n   * Generates a list of acceptable preview sizes. Preview sizes are not acceptable if there is not\n   * a corresponding picture size of the same aspect ratio. If there is a corresponding picture size\n   * of the same aspect ratio, the picture size is paired up with the preview size.\n   *\n   * <p>This is necessary because even if we don't use still pictures, the still picture size must\n   * be set to a size that is the same aspect ratio as the preview size we choose. Otherwise, the\n   * preview images may be distorted on some devices.\n   */\n  public static List<SizePair> generateValidPreviewSizeList(Camera camera) {\n    Camera.Parameters parameters = camera.getParameters();\n    List<Camera.Size> supportedPreviewSizes =\n        parameters.getSupportedPreviewSizes();\n    List<Camera.Size> supportedPictureSizes =\n        parameters.getSupportedPictureSizes();\n    List<SizePair> validPreviewSizes = new ArrayList<>();\n    for (Camera.Size previewSize : supportedPreviewSizes) {\n      float previewAspectRatio = (float) previewSize.width / (float) previewSize.height;\n\n      // By looping through the picture sizes in order, we favor the higher resolutions.\n      // We choose the highest resolution in order to support taking the full resolution\n      // picture later.\n      for (Camera.Size pictureSize : supportedPictureSizes) {\n        float pictureAspectRatio = (float) pictureSize.width / (float) pictureSize.height;\n        if (Math.abs(previewAspectRatio - pictureAspectRatio) < ASPECT_RATIO_TOLERANCE) {\n          validPreviewSizes.add(new SizePair(previewSize, pictureSize));\n          break;\n        }\n      }\n    }\n\n    // If there are no picture sizes with the same aspect ratio as any preview sizes, allow all\n    // of the preview sizes and hope that the camera can handle it.  Probably unlikely, but we\n    // still account for it.\n    if (validPreviewSizes.isEmpty()) {\n      Log.w(TAG, \"No preview sizes have a corresponding same-aspect-ratio picture size\");\n      for (Camera.Size previewSize : supportedPreviewSizes) {\n        // The null picture size will let us know that we shouldn't set a picture size.\n        validPreviewSizes.add(new SizePair(previewSize, null));\n      }\n    }\n\n    return validPreviewSizes;\n  }\n\n  /**\n   * Selects the most suitable preview frames per second range, given the desired frames per second.\n   *\n   * @param camera the camera to select a frames per second range from\n   * @param desiredPreviewFps the desired frames per second for the camera preview frames\n   * @return the selected preview frames per second range\n   */\n  @SuppressLint(\"InlinedApi\")\n  private static int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) {\n    // The camera API uses integers scaled by a factor of 1000 instead of floating-point frame\n    // rates.\n    int desiredPreviewFpsScaled = (int) (desiredPreviewFps * 1000.0f);\n\n    // The method for selecting the best range is to minimize the sum of the differences between\n    // the desired value and the upper and lower bounds of the range.  This may select a range\n    // that the desired value is outside of, but this is often preferred.  For example, if the\n    // desired frame rate is 29.97, the range (30, 30) is probably more desirable than the\n    // range (15, 30).\n    int[] selectedFpsRange = null;\n    int minDiff = Integer.MAX_VALUE;\n    List<int[]> previewFpsRangeList = camera.getParameters().getSupportedPreviewFpsRange();\n    for (int[] range : previewFpsRangeList) {\n      int deltaMin = desiredPreviewFpsScaled - range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];\n      int deltaMax = desiredPreviewFpsScaled - range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX];\n      int diff = Math.abs(deltaMin) + Math.abs(deltaMax);\n      if (diff < minDiff) {\n        selectedFpsRange = range;\n        minDiff = diff;\n      }\n    }\n    return selectedFpsRange;\n  }\n\n  /**\n   * Calculates the correct rotation for the given camera id and sets the rotation in the\n   * parameters. It also sets the camera's display orientation and rotation.\n   *\n   * @param parameters the camera parameters for which to set the rotation\n   * @param cameraId the camera id to set rotation based on\n   */\n  private void setRotation(Camera camera, Camera.Parameters parameters, int cameraId) {\n    WindowManager windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);\n    int degrees = 0;\n    int rotation = windowManager.getDefaultDisplay().getRotation();\n    switch (rotation) {\n      case Surface.ROTATION_0:\n        degrees = 0;\n        break;\n      case Surface.ROTATION_90:\n        degrees = 90;\n        break;\n      case Surface.ROTATION_180:\n        degrees = 180;\n        break;\n      case Surface.ROTATION_270:\n        degrees = 270;\n        break;\n      default:\n        Log.e(TAG, \"Bad rotation value: \" + rotation);\n    }\n\n    CameraInfo cameraInfo = new CameraInfo();\n    Camera.getCameraInfo(cameraId, cameraInfo);\n\n    int displayAngle;\n    if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {\n      this.rotationDegrees = (cameraInfo.orientation + degrees) % 360;\n      displayAngle = (360 - this.rotationDegrees) % 360; // compensate for it being mirrored\n    } else { // back-facing\n      this.rotationDegrees = (cameraInfo.orientation - degrees + 360) % 360;\n      displayAngle = this.rotationDegrees;\n    }\n    Log.d(TAG, \"Display rotation is: \" + rotation);\n    Log.d(TAG, \"Camera face is: \" + cameraInfo.facing);\n    Log.d(TAG, \"Camera rotation is: \" + cameraInfo.orientation);\n    // This value should be one of the degrees that ImageMetadata accepts: 0, 90, 180 or 270.\n    Log.d(TAG, \"RotationDegrees is: \" + this.rotationDegrees);\n\n    camera.setDisplayOrientation(displayAngle);\n    parameters.setRotation(this.rotationDegrees);\n  }\n\n  /**\n   * Creates one buffer for the camera preview callback. The size of the buffer is based off of the\n   * camera preview size and the format of the camera image.\n   *\n   * @return a new preview buffer of the appropriate size for the current camera settings\n   */\n  @SuppressLint(\"InlinedApi\")\n  private byte[] createPreviewBuffer(Size previewSize) {\n    int bitsPerPixel = ImageFormat.getBitsPerPixel(IMAGE_FORMAT);\n    long sizeInBits = (long) previewSize.getHeight() * previewSize.getWidth() * bitsPerPixel;\n    int bufferSize = (int) Math.ceil(sizeInBits / 8.0d) + 1;\n\n    // Creating the byte array this way and wrapping it, as opposed to using .allocate(),\n    // should guarantee that there will be an array to work with.\n    byte[] byteArray = new byte[bufferSize];\n    ByteBuffer buffer = ByteBuffer.wrap(byteArray);\n    if (!buffer.hasArray() || (buffer.array() != byteArray)) {\n      // I don't think that this will ever happen.  But if it does, then we wouldn't be\n      // passing the preview content to the underlying detector later.\n      throw new IllegalStateException(\"Failed to create valid buffer for camera source.\");\n    }\n\n    bytesToByteBuffer.put(byteArray, buffer);\n    return byteArray;\n  }\n\n  // ==============================================================================================\n  // Frame processing\n  // ==============================================================================================\n\n  /** Called when the camera has a new preview frame. */\n  private class CameraPreviewCallback implements Camera.PreviewCallback {\n    @Override\n    public void onPreviewFrame(byte[] data, Camera camera) {\n      processingRunnable.setNextFrame(data, camera);\n    }\n  }\n\n  void setMachineLearningFrameProcessor(VisionImageProcessor processor) {\n    synchronized (processorLock) {\n      cleanScreen();\n      if (frameProcessor != null) {\n        frameProcessor.stop();\n      }\n      frameProcessor = processor;\n    }\n  }\n\n  /**\n   * This runnable controls access to the underlying receiver, calling it to process frames when\n   * available from the camera. This is designed to run detection on frames as fast as possible\n   * (i.e., without unnecessary context switching or waiting on the next frame).\n   *\n   * <p>While detection is running on a frame, new frames may be received from the camera. As these\n   * frames come in, the most recent frame is held onto as pending. As soon as detection and its\n   * associated processing is done for the previous frame, detection on the mostly recently received\n   * frame will immediately start on the same thread.\n   */\n  private class FrameProcessingRunnable implements Runnable {\n\n    // This lock guards all of the member variables below.\n    private final Object lock = new Object();\n    private boolean active = true;\n\n    // These pending variables hold the state associated with the new frame awaiting processing.\n    private ByteBuffer pendingFrameData;\n\n    FrameProcessingRunnable() {}\n\n    /** Marks the runnable as active/not active. Signals any blocked threads to continue. */\n    void setActive(boolean active) {\n      synchronized (lock) {\n        this.active = active;\n        lock.notifyAll();\n      }\n    }\n\n    /**\n     * Sets the frame data received from the camera. This adds the previous unused frame buffer (if\n     * present) back to the camera, and keeps a pending reference to the frame data for future use.\n     */\n    @SuppressWarnings(\"ByteBufferBackingArray\")\n    void setNextFrame(byte[] data, Camera camera) {\n      synchronized (lock) {\n        if (pendingFrameData != null) {\n          camera.addCallbackBuffer(pendingFrameData.array());\n          pendingFrameData = null;\n        }\n\n        if (!bytesToByteBuffer.containsKey(data)) {\n          Log.d(\n              TAG,\n              \"Skipping frame. Could not find ByteBuffer associated with the image \"\n                  + \"data from the camera.\");\n          return;\n        }\n\n        pendingFrameData = bytesToByteBuffer.get(data);\n\n        // Notify the processor thread if it is waiting on the next frame (see below).\n        lock.notifyAll();\n      }\n    }\n\n    /**\n     * As long as the processing thread is active, this executes detection on frames continuously.\n     * The next pending frame is either immediately available or hasn't been received yet. Once it\n     * is available, we transfer the frame info to local variables and run detection on that frame.\n     * It immediately loops back for the next frame without pausing.\n     *\n     * <p>If detection takes longer than the time in between new frames from the camera, this will\n     * mean that this loop will run without ever waiting on a frame, avoiding any context switching\n     * or frame acquisition time latency.\n     *\n     * <p>If you find that this is using more CPU than you'd like, you should probably decrease the\n     * FPS setting above to allow for some idle time in between frames.\n     */\n    @SuppressLint(\"InlinedApi\")\n    @SuppressWarnings({\"GuardedBy\", \"ByteBufferBackingArray\"})\n    @Override\n    public void run() {\n      ByteBuffer data;\n\n      while (true) {\n        synchronized (lock) {\n          while (active && (pendingFrameData == null)) {\n            try {\n              // Wait for the next frame to be received from the camera, since we\n              // don't have it yet.\n              lock.wait();\n            } catch (InterruptedException e) {\n              Log.d(TAG, \"Frame processing loop terminated.\", e);\n              return;\n            }\n          }\n\n          if (!active) {\n            // Exit the loop once this camera source is stopped or released.  We check\n            // this here, immediately after the wait() above, to handle the case where\n            // setActive(false) had been called, triggering the termination of this\n            // loop.\n            return;\n          }\n\n          // Hold onto the frame data locally, so that we can use this for detection\n          // below.  We need to clear pendingFrameData to ensure that this buffer isn't\n          // recycled back to the camera before we are done using that data.\n          data = pendingFrameData;\n          pendingFrameData = null;\n        }\n\n        // The code below needs to run outside of synchronization, because this will allow\n        // the camera to add pending frame(s) while we are running detection on the current\n        // frame.\n\n        try {\n          synchronized (processorLock) {\n            frameProcessor.processByteBuffer(\n                data,\n                new FrameMetadata.Builder()\n                    .setWidth(previewSize.getWidth())\n                    .setHeight(previewSize.getHeight())\n                    .setRotation(rotationDegrees)\n                    .build(),\n                graphicOverlay);\n          }\n        } catch (Exception t) {\n          Log.e(TAG, \"Exception thrown from receiver.\", t);\n        } finally {\n          camera.addCallbackBuffer(data.array());\n        }\n      }\n    }\n  }\n\n  /** Cleans up graphicOverlay and child classes can do their cleanups as well . */\n  private void cleanScreen() {\n    graphicOverlay.clear();\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/CameraSourcePreview.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.SurfaceHolder;\nimport android.view.SurfaceView;\nimport android.view.ViewGroup;\nimport com.google.android.gms.common.images.Size;\nimport com.google.mlkit.vision.automl.demo.preference.PreferenceUtils;\nimport java.io.IOException;\n\n/** Preview the camera image in the screen. */\npublic class CameraSourcePreview extends ViewGroup {\n  private static final String TAG = \"MIDemoApp:Preview\";\n\n  private final Context context;\n  private final SurfaceView surfaceView;\n  private boolean startRequested;\n  private boolean surfaceAvailable;\n  private CameraSource cameraSource;\n\n  private GraphicOverlay overlay;\n\n  public CameraSourcePreview(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    this.context = context;\n    startRequested = false;\n    surfaceAvailable = false;\n\n    surfaceView = new SurfaceView(context);\n    surfaceView.getHolder().addCallback(new SurfaceCallback());\n    addView(surfaceView);\n  }\n\n  private void start(CameraSource cameraSource) throws IOException {\n    this.cameraSource = cameraSource;\n\n    if (this.cameraSource != null) {\n      startRequested = true;\n      startIfReady();\n    }\n  }\n\n  public void start(CameraSource cameraSource, GraphicOverlay overlay) throws IOException {\n    this.overlay = overlay;\n    start(cameraSource);\n  }\n\n  public void stop() {\n    if (cameraSource != null) {\n      cameraSource.stop();\n    }\n  }\n\n  public void release() {\n    if (cameraSource != null) {\n      cameraSource.release();\n      cameraSource = null;\n    }\n    surfaceView.getHolder().getSurface().release();\n  }\n\n  private void startIfReady() throws IOException, SecurityException {\n    if (startRequested && surfaceAvailable) {\n      if (PreferenceUtils.isCameraLiveViewportEnabled(context)) {\n        cameraSource.start(surfaceView.getHolder());\n      } else {\n        cameraSource.start();\n      }\n      requestLayout();\n\n      if (overlay != null) {\n        Size size = cameraSource.getPreviewSize();\n        int min = Math.min(size.getWidth(), size.getHeight());\n        int max = Math.max(size.getWidth(), size.getHeight());\n        boolean isImageFlipped = cameraSource.getCameraFacing() == CameraSource.CAMERA_FACING_FRONT;\n        if (isPortraitMode()) {\n          // Swap width and height sizes when in portrait, since it will be rotated by 90 degrees.\n          // The camera preview and the image being processed have the same size.\n          overlay.setImageSourceInfo(min, max, isImageFlipped);\n        } else {\n          overlay.setImageSourceInfo(max, min, isImageFlipped);\n        }\n        overlay.clear();\n      }\n      startRequested = false;\n    }\n  }\n\n  private class SurfaceCallback implements SurfaceHolder.Callback {\n    @Override\n    public void surfaceCreated(SurfaceHolder surface) {\n      surfaceAvailable = true;\n      try {\n        startIfReady();\n      } catch (IOException e) {\n        Log.e(TAG, \"Could not start camera source.\", e);\n      }\n    }\n\n    @Override\n    public void surfaceDestroyed(SurfaceHolder surface) {\n      surfaceAvailable = false;\n    }\n\n    @Override\n    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}\n  }\n\n  @Override\n  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n    int width = 320;\n    int height = 240;\n    if (cameraSource != null) {\n      Size size = cameraSource.getPreviewSize();\n      if (size != null) {\n        width = size.getWidth();\n        height = size.getHeight();\n      }\n    }\n\n    // Swap width and height sizes when in portrait, since it will be rotated 90 degrees\n    if (isPortraitMode()) {\n      int tmp = width;\n      width = height;\n      height = tmp;\n    }\n\n    final int layoutWidth = right - left;\n    final int layoutHeight = bottom - top;\n\n    // Computes height and width for potentially doing fit width.\n    int childWidth = layoutWidth;\n    int childHeight = (int) (((float) layoutWidth / (float) width) * height);\n\n    // If height is too tall using fit width, does fit height instead.\n    if (childHeight > layoutHeight) {\n      childHeight = layoutHeight;\n      childWidth = (int) (((float) layoutHeight / (float) height) * width);\n    }\n\n    for (int i = 0; i < getChildCount(); ++i) {\n      getChildAt(i).layout(0, 0, childWidth, childHeight);\n      Log.d(TAG, \"Assigned view: \" + i);\n    }\n  }\n\n  private boolean isPortraitMode() {\n    int orientation = context.getResources().getConfiguration().orientation;\n    if (orientation == Configuration.ORIENTATION_LANDSCAPE) {\n      return false;\n    }\n    if (orientation == Configuration.ORIENTATION_PORTRAIT) {\n      return true;\n    }\n\n    Log.d(TAG, \"isPortraitMode returning false by default\");\n    return false;\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/CameraXLivePreviewActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.content.Intent;\nimport android.os.Build.VERSION_CODES;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.util.Size;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.CompoundButton;\nimport android.widget.ImageView;\nimport android.widget.Spinner;\nimport android.widget.Toast;\nimport android.widget.ToggleButton;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.core.CameraInfoUnavailableException;\nimport androidx.camera.core.CameraSelector;\nimport androidx.camera.core.ImageAnalysis;\nimport androidx.camera.core.Preview;\nimport androidx.camera.lifecycle.ProcessCameraProvider;\nimport androidx.camera.view.PreviewView;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory;\nimport com.google.android.gms.common.annotation.KeepName;\nimport com.google.mlkit.common.MlKitException;\nimport com.google.mlkit.common.model.CustomRemoteModel;\nimport com.google.mlkit.linkfirebase.FirebaseModelSource;\nimport com.google.mlkit.vision.automl.demo.automl.AutoMLImageLabelerProcessor;\nimport com.google.mlkit.vision.automl.demo.automl.AutoMLImageLabelerProcessor.Mode;\nimport com.google.mlkit.vision.automl.demo.object.ObjectDetectorProcessor;\nimport com.google.mlkit.vision.automl.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.automl.demo.preference.SettingsActivity;\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** Live preview demo app for ML Kit APIs using CameraX. */\n@KeepName\n@RequiresApi(VERSION_CODES.LOLLIPOP)\npublic final class CameraXLivePreviewActivity extends AppCompatActivity\n    implements OnItemSelectedListener, CompoundButton.OnCheckedChangeListener {\n  private static final String TAG = \"CameraXLivePreview\";\n  private static final String CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling\";\n  private static final String CUSTOM_AUTOML_OBJECT_DETECTION = \"Custom AutoML Object Detection\";\n\n  private static final String STATE_SELECTED_MODEL = \"selected_model\";\n  private static final String STATE_LENS_FACING = \"lens_facing\";\n\n  private PreviewView previewView;\n  private GraphicOverlay graphicOverlay;\n\n  @Nullable private ProcessCameraProvider cameraProvider;\n  @Nullable private Preview previewUseCase;\n  @Nullable private ImageAnalysis analysisUseCase;\n  @Nullable private VisionImageProcessor imageProcessor;\n  private boolean needUpdateGraphicOverlayImageSourceInfo;\n\n  private String selectedModel = CUSTOM_AUTOML_LABELING;\n  private int lensFacing = CameraSelector.LENS_FACING_BACK;\n  private CameraSelector cameraSelector;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    Log.d(TAG, \"onCreate\");\n\n    if (savedInstanceState != null) {\n      selectedModel = savedInstanceState.getString(STATE_SELECTED_MODEL, CUSTOM_AUTOML_LABELING);\n      lensFacing = savedInstanceState.getInt(STATE_LENS_FACING, CameraSelector.LENS_FACING_BACK);\n    }\n    cameraSelector = new CameraSelector.Builder().requireLensFacing(lensFacing).build();\n\n    setContentView(R.layout.activity_camerax_live_preview);\n    previewView = findViewById(R.id.preview_view);\n    if (previewView == null) {\n      Log.d(TAG, \"previewView is null\");\n    }\n    graphicOverlay = findViewById(R.id.graphic_overlay);\n    if (graphicOverlay == null) {\n      Log.d(TAG, \"graphicOverlay is null\");\n    }\n\n    Spinner spinner = findViewById(R.id.spinner);\n    List<String> options = new ArrayList<>();\n    options.add(CUSTOM_AUTOML_LABELING);\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION);\n\n    // Creating adapter for spinner\n    ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // attaching data adapter to spinner\n    spinner.setAdapter(dataAdapter);\n    spinner.setOnItemSelectedListener(this);\n\n    ToggleButton facingSwitch = findViewById(R.id.facing_switch);\n    facingSwitch.setOnCheckedChangeListener(this);\n\n    new ViewModelProvider(this, AndroidViewModelFactory.getInstance(getApplication()))\n        .get(CameraXViewModel.class)\n        .getProcessCameraProvider()\n        .observe(\n            this,\n            provider -> {\n              cameraProvider = provider;\n              bindAllCameraUseCases();\n            });\n\n    ImageView settingsButton = findViewById(R.id.settings_button);\n    settingsButton.setOnClickListener(\n        v -> {\n          Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);\n          intent.putExtra(\n              SettingsActivity.EXTRA_LAUNCH_SOURCE,\n              SettingsActivity.LaunchSource.CAMERAX_LIVE_PREVIEW);\n          startActivity(intent);\n        });\n  }\n\n  @Override\n  protected void onSaveInstanceState(@NonNull Bundle bundle) {\n    super.onSaveInstanceState(bundle);\n    bundle.putString(STATE_SELECTED_MODEL, selectedModel);\n    bundle.putInt(STATE_LENS_FACING, lensFacing);\n  }\n\n  @Override\n  public synchronized void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {\n    // An item was selected. You can retrieve the selected item using\n    // parent.getItemAtPosition(pos)\n    selectedModel = parent.getItemAtPosition(pos).toString();\n    Log.d(TAG, \"Selected model: \" + selectedModel);\n    bindAnalysisUseCase();\n  }\n\n  @Override\n  public void onNothingSelected(AdapterView<?> parent) {\n    // Do nothing.\n  }\n\n  @Override\n  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n    Log.d(TAG, \"Set facing\");\n    if (cameraProvider == null) {\n      return;\n    }\n\n    int newLensFacing =\n        lensFacing == CameraSelector.LENS_FACING_FRONT\n            ? CameraSelector.LENS_FACING_BACK\n            : CameraSelector.LENS_FACING_FRONT;\n    CameraSelector newCameraSelector =\n        new CameraSelector.Builder().requireLensFacing(newLensFacing).build();\n    try {\n      if (cameraProvider.hasCamera(newCameraSelector)) {\n        lensFacing = newLensFacing;\n        cameraSelector = newCameraSelector;\n        bindAllCameraUseCases();\n        return;\n      }\n    } catch (CameraInfoUnavailableException e) {\n      // Falls through\n    }\n    Toast.makeText(\n            getApplicationContext(),\n            \"This device does not have lens with facing: \" + newLensFacing,\n            Toast.LENGTH_SHORT)\n        .show();\n  }\n\n  @Override\n  public void onResume() {\n    super.onResume();\n    bindAllCameraUseCases();\n  }\n\n  @Override\n  protected void onPause() {\n    super.onPause();\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n  }\n\n  @Override\n  public void onDestroy() {\n    super.onDestroy();\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n  }\n\n  private void bindAllCameraUseCases() {\n    bindPreviewUseCase();\n    bindAnalysisUseCase();\n  }\n\n  private void bindPreviewUseCase() {\n    if (!PreferenceUtils.isCameraLiveViewportEnabled(this)) {\n      return;\n    }\n    if (cameraProvider == null) {\n      return;\n    }\n    if (previewUseCase != null) {\n      cameraProvider.unbind(previewUseCase);\n    }\n\n    Preview.Builder builder = new Preview.Builder();\n    Size targetResolution = PreferenceUtils.getCameraXTargetResolution(this, lensFacing);\n    if (targetResolution != null) {\n      builder.setTargetResolution(targetResolution);\n    }\n    previewUseCase = builder.build();\n    previewUseCase.setSurfaceProvider(previewView.getSurfaceProvider());\n    cameraProvider.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector, previewUseCase);\n  }\n\n  private void bindAnalysisUseCase() {\n    if (cameraProvider == null) {\n      return;\n    }\n    if (analysisUseCase != null) {\n      cameraProvider.unbind(analysisUseCase);\n    }\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n\n    try {\n      String autoMLRemoteModelName = PreferenceUtils.getAutoMLRemoteModelName(this);\n      switch (selectedModel) {\n        case CUSTOM_AUTOML_LABELING:\n          Log.i(TAG, \"Create Custom AutoML Image Label Processor\");\n          CustomRemoteModel customRemoteModel =\n              new CustomRemoteModel.Builder(\n                      new FirebaseModelSource.Builder(autoMLRemoteModelName).build())\n                  .build();\n          CustomImageLabelerOptions customImageLabelerOptions =\n              new CustomImageLabelerOptions.Builder(customRemoteModel)\n                  .setConfidenceThreshold(0)\n                  .build();\n          imageProcessor =\n              new AutoMLImageLabelerProcessor(\n                  this, customRemoteModel, customImageLabelerOptions, Mode.LIVE_PREVIEW);\n          break;\n        case CUSTOM_AUTOML_OBJECT_DETECTION:\n          Log.i(TAG, \"Using Custom AutoML Object Detector Processor\");\n          CustomRemoteModel customODTRemoteModel =\n              new CustomRemoteModel.Builder(\n                      new FirebaseModelSource.Builder(autoMLRemoteModelName).build())\n                  .build();\n          CustomObjectDetectorOptions customAutoMLODTOptions =\n              new CustomObjectDetectorOptions.Builder(customODTRemoteModel)\n                  .setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE)\n                  .enableClassification()\n                  .setClassificationConfidenceThreshold(0)\n                  .setMaxPerObjectLabelCount(1)\n                  .build();\n          imageProcessor =\n              new ObjectDetectorProcessor(this, customODTRemoteModel, customAutoMLODTOptions);\n          break;\n        default:\n          throw new IllegalStateException(\"Invalid model name\");\n      }\n    } catch (RuntimeException e) {\n      Log.e(TAG, \"Can not create image processor: \" + selectedModel, e);\n      Toast.makeText(\n              getApplicationContext(),\n              \"Can not create image processor: \" + e.getLocalizedMessage(),\n              Toast.LENGTH_LONG)\n          .show();\n      return;\n    }\n\n    ImageAnalysis.Builder builder = new ImageAnalysis.Builder();\n    Size targetResolution = PreferenceUtils.getCameraXTargetResolution(this, lensFacing);\n    if (targetResolution != null) {\n      builder.setTargetResolution(targetResolution);\n    }\n    analysisUseCase = builder.build();\n\n    needUpdateGraphicOverlayImageSourceInfo = true;\n    analysisUseCase.setAnalyzer(\n        // imageProcessor.processImageProxy will use another thread to run the detection underneath,\n        // thus we can just runs the analyzer itself on main thread.\n        ContextCompat.getMainExecutor(this),\n        imageProxy -> {\n          if (needUpdateGraphicOverlayImageSourceInfo) {\n            boolean isImageFlipped = lensFacing == CameraSelector.LENS_FACING_FRONT;\n            int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();\n            if (rotationDegrees == 0 || rotationDegrees == 180) {\n              graphicOverlay.setImageSourceInfo(\n                  imageProxy.getWidth(), imageProxy.getHeight(), isImageFlipped);\n            } else {\n              graphicOverlay.setImageSourceInfo(\n                  imageProxy.getHeight(), imageProxy.getWidth(), isImageFlipped);\n            }\n            needUpdateGraphicOverlayImageSourceInfo = false;\n          }\n          try {\n            imageProcessor.processImageProxy(imageProxy, graphicOverlay);\n          } catch (MlKitException e) {\n            Log.e(TAG, \"Failed to process image. Error: \" + e.getLocalizedMessage());\n            Toast.makeText(getApplicationContext(), e.getLocalizedMessage(), Toast.LENGTH_SHORT)\n                .show();\n          }\n        });\n\n    cameraProvider.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector, analysisUseCase);\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/CameraXViewModel.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.app.Application;\nimport android.os.Build.VERSION_CODES;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.lifecycle.ProcessCameraProvider;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport java.util.concurrent.ExecutionException;\n\n/** View model for interacting with CameraX. */\n@RequiresApi(VERSION_CODES.LOLLIPOP)\npublic final class CameraXViewModel extends AndroidViewModel {\n\n  private static final String TAG = \"CameraXViewModel\";\n  private MutableLiveData<ProcessCameraProvider> cameraProviderLiveData;\n\n  /**\n   * Create an instance which interacts with the camera service via the given application context.\n   */\n  public CameraXViewModel(@NonNull Application application) {\n    super(application);\n  }\n\n  LiveData<ProcessCameraProvider> getProcessCameraProvider() {\n    if (cameraProviderLiveData == null) {\n      cameraProviderLiveData = new MutableLiveData<>();\n\n      ListenableFuture<ProcessCameraProvider> cameraProviderFuture =\n          ProcessCameraProvider.getInstance(getApplication());\n      cameraProviderFuture.addListener(\n          () -> {\n            try {\n              cameraProviderLiveData.setValue(cameraProviderFuture.get());\n            } catch (ExecutionException | InterruptedException e) {\n              // Handle any errors (including cancellation) here.\n              Log.e(TAG, \"Unhandled exception\", e);\n            }\n          },\n          ContextCompat.getMainExecutor(getApplication()));\n    }\n\n    return cameraProviderLiveData;\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/ChooserActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Build.VERSION;\nimport android.os.Build.VERSION_CODES;\nimport android.os.Bundle;\nimport android.os.StrictMode;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback;\nimport androidx.core.content.ContextCompat;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Demo app chooser which takes care of runtime permission requesting and allow you pick from all\n * available testing Activities.\n */\npublic final class ChooserActivity extends AppCompatActivity\n    implements OnRequestPermissionsResultCallback, AdapterView.OnItemClickListener {\n  private static final String TAG = \"ChooserActivity\";\n  private static final int PERMISSION_REQUESTS = 1;\n  private static final String[] REQUIRED_RUNTIME_PERMISSIONS = {\n    Manifest.permission.CAMERA,\n    Manifest.permission.WRITE_EXTERNAL_STORAGE,\n    Manifest.permission.READ_EXTERNAL_STORAGE\n  };\n\n  @SuppressWarnings(\"NewApi\") // CameraX is only available on API 21+\n  private static final Class<?>[] CLASSES =\n      VERSION.SDK_INT < VERSION_CODES.LOLLIPOP\n          ? new Class<?>[] {\n            LivePreviewActivity.class, StillImageActivity.class,\n          }\n          : new Class<?>[] {\n            LivePreviewActivity.class, StillImageActivity.class, CameraXLivePreviewActivity.class,\n          };\n\n  private static final int[] DESCRIPTION_IDS =\n      VERSION.SDK_INT < VERSION_CODES.LOLLIPOP\n          ? new int[] {\n            R.string.desc_camera_source_activity, R.string.desc_still_image_activity,\n          }\n          : new int[] {\n            R.string.desc_camera_source_activity,\n            R.string.desc_still_image_activity,\n            R.string.desc_camerax_live_preview_activity,\n          };\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n\n    if (BuildConfig.DEBUG) {\n      StrictMode.setThreadPolicy(\n          new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());\n      StrictMode.setVmPolicy(\n          new StrictMode.VmPolicy.Builder()\n              .detectLeakedSqlLiteObjects()\n              .detectLeakedClosableObjects()\n              .penaltyLog()\n              .penaltyDeath()\n              .build());\n    }\n    super.onCreate(savedInstanceState);\n    Log.d(TAG, \"onCreate\");\n\n    setContentView(R.layout.activity_chooser);\n\n    // Set up ListView and Adapter\n    ListView listView = findViewById(R.id.test_activity_list_view);\n\n    MyArrayAdapter adapter = new MyArrayAdapter(this, android.R.layout.simple_list_item_2, CLASSES);\n    adapter.setDescriptionIds(DESCRIPTION_IDS);\n\n    listView.setAdapter(adapter);\n    listView.setOnItemClickListener(this);\n\n    if (!allPermissionsGranted()) {\n      getRuntimePermissions();\n    }\n  }\n\n  @Override\n  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n    Class<?> clicked = CLASSES[position];\n    startActivity(new Intent(this, clicked));\n  }\n\n  private boolean allPermissionsGranted() {\n    for (String permission : REQUIRED_RUNTIME_PERMISSIONS) {\n      if (!isPermissionGranted(this, permission)) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  private void getRuntimePermissions() {\n    List<String> allNeededPermissions = new ArrayList<>();\n    for (String permission : REQUIRED_RUNTIME_PERMISSIONS) {\n      if (!isPermissionGranted(this, permission)) {\n        allNeededPermissions.add(permission);\n      }\n    }\n\n    if (!allNeededPermissions.isEmpty()) {\n      ActivityCompat.requestPermissions(\n          this, allNeededPermissions.toArray(new String[0]), PERMISSION_REQUESTS);\n    }\n  }\n\n  private static boolean isPermissionGranted(Context context, String permission) {\n    if (ContextCompat.checkSelfPermission(context, permission)\n        == PackageManager.PERMISSION_GRANTED) {\n      Log.i(TAG, \"Permission granted: \" + permission);\n      return true;\n    }\n    Log.i(TAG, \"Permission NOT granted: \" + permission);\n    return false;\n  }\n\n  private static class MyArrayAdapter extends ArrayAdapter<Class<?>> {\n\n    private final Context context;\n    private final Class<?>[] classes;\n    private int[] descriptionIds;\n\n    MyArrayAdapter(Context context, int resource, Class<?>[] objects) {\n      super(context, resource, objects);\n\n      this.context = context;\n      classes = objects;\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n      View view = convertView;\n\n      if (convertView == null) {\n        LayoutInflater inflater =\n            (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);\n        view = inflater.inflate(android.R.layout.simple_list_item_2, null);\n      }\n\n      ((TextView) view.findViewById(android.R.id.text1)).setText(classes[position].getSimpleName());\n      ((TextView) view.findViewById(android.R.id.text2)).setText(descriptionIds[position]);\n\n      return view;\n    }\n\n    void setDescriptionIds(int[] descriptionIds) {\n      this.descriptionIds = descriptionIds;\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/FrameMetadata.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\n/** Describing a frame info. */\npublic class FrameMetadata {\n\n  private final int width;\n  private final int height;\n  private final int rotation;\n\n  public int getWidth() {\n    return width;\n  }\n\n  public int getHeight() {\n    return height;\n  }\n\n  public int getRotation() {\n    return rotation;\n  }\n\n  private FrameMetadata(int width, int height, int rotation) {\n    this.width = width;\n    this.height = height;\n    this.rotation = rotation;\n  }\n\n  /** Builder of {@link FrameMetadata}. */\n  public static class Builder {\n\n    private int width;\n    private int height;\n    private int rotation;\n\n    public Builder setWidth(int width) {\n      this.width = width;\n      return this;\n    }\n\n    public Builder setHeight(int height) {\n      this.height = height;\n      return this;\n    }\n\n    public Builder setRotation(int rotation) {\n      this.rotation = rotation;\n      return this;\n    }\n\n    public FrameMetadata build() {\n      return new FrameMetadata(width, height, rotation);\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/GraphicOverlay.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Matrix;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport com.google.common.base.Preconditions;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * A view which renders a series of custom graphics to be overlayed on top of an associated preview\n * (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove\n * them, triggering the appropriate drawing and invalidation within the view.\n *\n * <p>Supports scaling and mirroring of the graphics relative the camera's preview properties. The\n * idea is that detection items are expressed in terms of an image size, but need to be scaled up\n * to the full view size, and also mirrored in the case of the front-facing camera.\n *\n * <p>Associated {@link Graphic} items should use the following methods to convert to view\n * coordinates for the graphics that are drawn:\n *\n * <ol>\n *   <li>{@link Graphic#scale(float)} adjusts the size of the supplied value from the image scale\n *       to the view scale.\n *   <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n *       coordinate from the image's coordinate system to the view coordinate system.\n * </ol>\n */\npublic class GraphicOverlay extends View {\n  private final Object lock = new Object();\n  private final List<Graphic> graphics = new ArrayList<>();\n  // Matrix for transforming from image coordinates to overlay view coordinates.\n  private final Matrix transformationMatrix = new Matrix();\n\n  private int imageWidth;\n  private int imageHeight;\n  // The factor of overlay View size to image size. Anything in the image coordinates need to be\n  // scaled by this amount to fit with the area of overlay View.\n  private float scaleFactor = 1.0f;\n  // The number of horizontal pixels needed to be cropped on each side to fit the image with the\n  // area of overlay View after scaling.\n  private float postScaleWidthOffset;\n  // The number of vertical pixels needed to be cropped on each side to fit the image with the\n  // area of overlay View after scaling.\n  private float postScaleHeightOffset;\n  private boolean isImageFlipped;\n  private boolean needUpdateTransformation = true;\n\n  /**\n   * Base class for a custom graphics object to be rendered within the graphic overlay. Subclass\n   * this and implement the {@link Graphic#draw(Canvas)} method to define the graphics element. Add\n   * instances to the overlay using {@link GraphicOverlay#add(Graphic)}.\n   */\n  public abstract static class Graphic {\n    private GraphicOverlay overlay;\n\n    public Graphic(GraphicOverlay overlay) {\n      this.overlay = overlay;\n    }\n\n    /**\n     * Draw the graphic on the supplied canvas. Drawing should use the following methods to convert\n     * to view coordinates for the graphics that are drawn:\n     *\n     * <ol>\n     *   <li>{@link Graphic#scale(float)} adjusts the size of the supplied value from the image\n     *       scale to the view scale.\n     *   <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n     *       coordinate from the image's coordinate system to the view coordinate system.\n     * </ol>\n     *\n     * @param canvas drawing canvas\n     */\n    public abstract void draw(Canvas canvas);\n\n    /**\n     * Adjusts the supplied value from the image scale to the view scale.\n     */\n    public float scale(float imagePixel) {\n      return imagePixel * overlay.scaleFactor;\n    }\n\n    /** Returns the application context of the app. */\n    public Context getApplicationContext() {\n      return overlay.getContext().getApplicationContext();\n    }\n\n    public boolean isImageFlipped() {\n      return overlay.isImageFlipped;\n    }\n\n    /**\n     * Adjusts the x coordinate from the image's coordinate system to the view coordinate system.\n     */\n    public float translateX(float x) {\n      if (overlay.isImageFlipped) {\n        return overlay.getWidth() - (scale(x) - overlay.postScaleWidthOffset);\n      } else {\n        return scale(x) - overlay.postScaleWidthOffset;\n      }\n    }\n\n    /**\n     * Adjusts the y coordinate from the image's coordinate system to the view coordinate system.\n     */\n    public float translateY(float y) {\n      return scale(y) - overlay.postScaleHeightOffset;\n    }\n\n    /**\n     * Returns a {@link Matrix} for transforming from image coordinates to overlay view coordinates.\n     */\n    public Matrix getTransformationMatrix() {\n      return overlay.transformationMatrix;\n    }\n\n    public void postInvalidate() {\n      overlay.postInvalidate();\n    }\n  }\n\n  public GraphicOverlay(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    addOnLayoutChangeListener(\n        (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->\n            needUpdateTransformation = true);\n  }\n\n  /** Removes all graphics from the overlay. */\n  public void clear() {\n    synchronized (lock) {\n      graphics.clear();\n    }\n    postInvalidate();\n  }\n\n  /** Adds a graphic to the overlay. */\n  public void add(Graphic graphic) {\n    synchronized (lock) {\n      graphics.add(graphic);\n    }\n  }\n\n  /** Removes a graphic from the overlay. */\n  public void remove(Graphic graphic) {\n    synchronized (lock) {\n      graphics.remove(graphic);\n    }\n    postInvalidate();\n  }\n\n  /**\n   * Sets the source information of the image being processed by detectors, including size and\n   * whether it is flipped, which informs how to transform image coordinates later.\n   *\n   * @param imageWidth the width of the image sent to ML Kit detectors\n   * @param imageHeight the height of the image sent to ML Kit detectors\n   * @param isFlipped whether the image is flipped. Should set it to true when the image is from the\n   *     front camera.\n   */\n  public void setImageSourceInfo(int imageWidth, int imageHeight, boolean isFlipped) {\n    Preconditions.checkState(imageWidth > 0, \"image width must be positive\");\n    Preconditions.checkState(imageHeight > 0, \"image height must be positive\");\n    synchronized (lock) {\n      this.imageWidth = imageWidth;\n      this.imageHeight = imageHeight;\n      this.isImageFlipped = isFlipped;\n      needUpdateTransformation = true;\n    }\n    postInvalidate();\n  }\n\n  public int getImageWidth() {\n    return imageWidth;\n  }\n\n  public int getImageHeight() {\n    return imageHeight;\n  }\n\n  private void updateTransformationIfNeeded() {\n    if (!needUpdateTransformation || imageWidth <= 0 || imageHeight <= 0) {\n      return;\n    }\n    float viewAspectRatio = (float) getWidth() / getHeight();\n    float imageAspectRatio = (float) imageWidth / imageHeight;\n    postScaleWidthOffset = 0;\n    postScaleHeightOffset = 0;\n    if (viewAspectRatio > imageAspectRatio) {\n      // The image needs to be vertically cropped to be displayed in this view.\n      scaleFactor = (float) getWidth() / imageWidth;\n      postScaleHeightOffset = ((float) getWidth() / imageAspectRatio - getHeight()) / 2;\n    } else {\n      // The image needs to be horizontally cropped to be displayed in this view.\n      scaleFactor = (float) getHeight() / imageHeight;\n      postScaleWidthOffset = ((float) getHeight() * imageAspectRatio - getWidth()) / 2;\n    }\n\n    transformationMatrix.reset();\n    transformationMatrix.setScale(scaleFactor, scaleFactor);\n    transformationMatrix.postTranslate(-postScaleWidthOffset, -postScaleHeightOffset);\n\n    if (isImageFlipped) {\n      transformationMatrix.postScale(-1f, 1f, getWidth() / 2f, getHeight() / 2f);\n    }\n\n    needUpdateTransformation = false;\n  }\n\n  /** Draws the overlay with its associated graphic objects. */\n  @Override\n  protected void onDraw(Canvas canvas) {\n    super.onDraw(canvas);\n\n    synchronized (lock) {\n      updateTransformationIfNeeded();\n\n      for (Graphic graphic : graphics) {\n        graphic.draw(canvas);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/InferenceInfoGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport androidx.annotation.Nullable;\n\n/** Graphic instance for rendering inference info (latency, FPS, resolution) in an overlay view. */\npublic class InferenceInfoGraphic extends GraphicOverlay.Graphic {\n\n  private static final int TEXT_COLOR = Color.WHITE;\n  private static final float TEXT_SIZE = 60.0f;\n\n  private final Paint textPaint;\n  private final GraphicOverlay overlay;\n  private final double latency;\n\n  // Only valid when a stream of input images is being processed. Null for single image mode.\n  @Nullable private final Integer framesPerSecond;\n\n  public InferenceInfoGraphic(\n      GraphicOverlay overlay, double latency, @Nullable Integer framesPerSecond) {\n    super(overlay);\n    this.overlay = overlay;\n    this.latency = latency;\n    this.framesPerSecond = framesPerSecond;\n    textPaint = new Paint();\n    textPaint.setColor(TEXT_COLOR);\n    textPaint.setTextSize(TEXT_SIZE);\n    postInvalidate();\n  }\n\n  @Override\n  public synchronized void draw(Canvas canvas) {\n    float x = TEXT_SIZE * 0.5f;\n    float y = TEXT_SIZE * 1.5f;\n\n    canvas.drawText(\n        \"InputImage size: \" + overlay.getImageHeight() + \"x\" + overlay.getImageWidth(),\n        x,\n        y,\n        textPaint);\n\n    // Draw FPS (if valid) and inference latency\n    if (framesPerSecond != null) {\n      canvas.drawText(\n          \"FPS: \" + framesPerSecond + \", latency: \" + latency + \" ms\", x, y + TEXT_SIZE, textPaint);\n    } else {\n      canvas.drawText(\"Latency: \" + latency + \" ms\", x, y + TEXT_SIZE, textPaint);\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/LivePreviewActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.CompoundButton;\nimport android.widget.ImageView;\nimport android.widget.Spinner;\nimport android.widget.Toast;\nimport android.widget.ToggleButton;\nimport com.google.android.gms.common.annotation.KeepName;\nimport com.google.mlkit.common.model.CustomRemoteModel;\nimport com.google.mlkit.linkfirebase.FirebaseModelSource;\nimport com.google.mlkit.vision.automl.demo.automl.AutoMLImageLabelerProcessor;\nimport com.google.mlkit.vision.automl.demo.automl.AutoMLImageLabelerProcessor.Mode;\nimport com.google.mlkit.vision.automl.demo.object.ObjectDetectorProcessor;\nimport com.google.mlkit.vision.automl.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.automl.demo.preference.SettingsActivity;\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** Live preview demo for ML Kit APIs. */\n@KeepName\npublic final class LivePreviewActivity extends AppCompatActivity\n    implements OnItemSelectedListener, CompoundButton.OnCheckedChangeListener {\n  private static final String CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling\";\n  private static final String CUSTOM_AUTOML_OBJECT_DETECTION = \"Custom AutoML Object Detection\";\n\n  private static final String TAG = \"LivePreviewActivity\";\n\n  private CameraSource cameraSource = null;\n  private CameraSourcePreview preview;\n  private GraphicOverlay graphicOverlay;\n  private String selectedModel = CUSTOM_AUTOML_LABELING;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    Log.d(TAG, \"onCreate\");\n\n    setContentView(R.layout.activity_live_preview);\n\n    preview = findViewById(R.id.preview);\n    if (preview == null) {\n      Log.d(TAG, \"Preview is null\");\n    }\n    graphicOverlay = findViewById(R.id.graphic_overlay);\n    if (graphicOverlay == null) {\n      Log.d(TAG, \"graphicOverlay is null\");\n    }\n\n    Spinner spinner = findViewById(R.id.spinner);\n    List<String> options = new ArrayList<>();\n    options.add(CUSTOM_AUTOML_LABELING);\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION);\n\n    // Creating adapter for spinner\n    ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // attaching data adapter to spinner\n    spinner.setAdapter(dataAdapter);\n    spinner.setOnItemSelectedListener(this);\n\n    ToggleButton facingSwitch = findViewById(R.id.facing_switch);\n    facingSwitch.setOnCheckedChangeListener(this);\n\n    ImageView settingsButton = findViewById(R.id.settings_button);\n    settingsButton.setOnClickListener(\n      v -> {\n        Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);\n        intent.putExtra(SettingsActivity.EXTRA_LAUNCH_SOURCE,\n          SettingsActivity.LaunchSource.LIVE_PREVIEW);\n        startActivity(intent);\n      });\n\n    createCameraSource(selectedModel);\n  }\n\n  @Override\n  public synchronized void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {\n    // An item was selected. You can retrieve the selected item using\n    // parent.getItemAtPosition(pos)\n    selectedModel = parent.getItemAtPosition(pos).toString();\n    Log.d(TAG, \"Selected model: \" + selectedModel);\n    preview.stop();\n    createCameraSource(selectedModel);\n    startCameraSource();\n  }\n\n  @Override\n  public void onNothingSelected(AdapterView<?> parent) {\n    // Do nothing.\n  }\n\n  @Override\n  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n    Log.d(TAG, \"Set facing\");\n    if (cameraSource != null) {\n      if (isChecked) {\n        cameraSource.setFacing(CameraSource.CAMERA_FACING_FRONT);\n      } else {\n        cameraSource.setFacing(CameraSource.CAMERA_FACING_BACK);\n      }\n    }\n    preview.stop();\n    startCameraSource();\n  }\n\n  private void createCameraSource(String model) {\n    // If there's no existing cameraSource, create one.\n    if (cameraSource == null) {\n      cameraSource = new CameraSource(this, graphicOverlay);\n    }\n\n    String autoMLRemoteModelName = PreferenceUtils.getAutoMLRemoteModelName(this);\n    try {\n      switch (model) {\n        case CUSTOM_AUTOML_LABELING:\n          Log.i(TAG, \"Create Custom AutoML Image Label Processor\");\n          CustomRemoteModel customRemoteModel =\n              new CustomRemoteModel.Builder(\n                      new FirebaseModelSource.Builder(autoMLRemoteModelName).build())\n                  .build();\n          CustomImageLabelerOptions customImageLabelerOptions =\n              new CustomImageLabelerOptions.Builder(customRemoteModel)\n                  .setConfidenceThreshold(0)\n                  .build();\n          cameraSource.setMachineLearningFrameProcessor(\n              new AutoMLImageLabelerProcessor(\n                  this, customRemoteModel, customImageLabelerOptions, Mode.LIVE_PREVIEW));\n          break;\n        case CUSTOM_AUTOML_OBJECT_DETECTION:\n          Log.i(TAG, \"Using Custom AutoML Object Detector Processor\");\n          CustomRemoteModel customODTRemoteModel =\n              new CustomRemoteModel.Builder(\n                      new FirebaseModelSource.Builder(autoMLRemoteModelName).build())\n                  .build();\n          CustomObjectDetectorOptions customAutoMLODTOptions =\n              new CustomObjectDetectorOptions.Builder(customODTRemoteModel)\n                  .setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE)\n                  .enableClassification()\n                  .setClassificationConfidenceThreshold(0)\n                  .setMaxPerObjectLabelCount(1)\n                  .build();\n          cameraSource.setMachineLearningFrameProcessor(\n              new ObjectDetectorProcessor(this, customODTRemoteModel, customAutoMLODTOptions));\n          break;\n        default:\n          Log.e(TAG, \"Unknown model: \" + model);\n      }\n    } catch (RuntimeException e) {\n      Log.e(TAG, \"Can not create image processor: \" + model, e);\n      Toast.makeText(\n              getApplicationContext(),\n              \"Can not create image processor: \" + e.getMessage(),\n              Toast.LENGTH_LONG)\n          .show();\n    }\n  }\n\n  /**\n   * Starts or restarts the camera source, if it exists. If the camera source doesn't exist yet\n   * (e.g., because onResume was called before the camera source was created), this will be called\n   * again when the camera source is created.\n   */\n  private void startCameraSource() {\n    if (cameraSource != null) {\n      try {\n        if (preview == null) {\n          Log.d(TAG, \"resume: Preview is null\");\n        }\n        if (graphicOverlay == null) {\n          Log.d(TAG, \"resume: graphOverlay is null\");\n        }\n        preview.start(cameraSource, graphicOverlay);\n      } catch (IOException e) {\n        Log.e(TAG, \"Unable to start camera source.\", e);\n        cameraSource.release();\n        cameraSource = null;\n      }\n    }\n  }\n\n  @Override\n  public void onResume() {\n    super.onResume();\n    Log.d(TAG, \"onResume\");\n    createCameraSource(selectedModel);\n    startCameraSource();\n  }\n\n  /** Stops the camera. */\n  @Override\n  protected void onPause() {\n    super.onPause();\n    preview.stop();\n  }\n\n  @Override\n  public void onDestroy() {\n    super.onDestroy();\n    if (cameraSource != null) {\n      cameraSource.release();\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/ScopedExecutor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport androidx.annotation.NonNull;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Wraps an existing executor to provide a {@link #shutdown} method that allows subsequent\n * cancellation of submitted runnables.\n */\npublic class ScopedExecutor implements Executor {\n\n  private final Executor executor;\n  private final AtomicBoolean shutdown = new AtomicBoolean();\n\n  public ScopedExecutor(@NonNull Executor executor) {\n    this.executor = executor;\n  }\n\n  @Override\n  public void execute(@NonNull Runnable command) {\n    // Return early if this object has been shut down.\n    if (shutdown.get()) {\n      return;\n    }\n    executor.execute(\n        () -> {\n          // Check again in case it has been shut down in the mean time.\n          if (shutdown.get()) {\n            return;\n          }\n          command.run();\n        });\n  }\n\n  /**\n   * After this method is called, no runnables that have been submitted or are subsequently\n   * submitted will start to execute, turning this executor into a no-op.\n   *\n   * <p>Runnables that have already started to execute will continue.\n   */\n  public void shutdown() {\n    shutdown.set(true);\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/StillImageActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport static java.lang.Math.max;\n\nimport android.content.ContentValues;\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.provider.MediaStore;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.util.Pair;\nimport android.view.MenuInflater;\nimport android.view.View;\nimport android.view.ViewTreeObserver.OnGlobalLayoutListener;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.ImageView;\nimport android.widget.PopupMenu;\nimport android.widget.Spinner;\nimport android.widget.Toast;\nimport com.google.android.gms.common.annotation.KeepName;\nimport com.google.mlkit.common.model.CustomRemoteModel;\nimport com.google.mlkit.linkfirebase.FirebaseModelSource;\nimport com.google.mlkit.vision.automl.demo.automl.AutoMLImageLabelerProcessor;\nimport com.google.mlkit.vision.automl.demo.automl.AutoMLImageLabelerProcessor.Mode;\nimport com.google.mlkit.vision.automl.demo.object.ObjectDetectorProcessor;\nimport com.google.mlkit.vision.automl.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.automl.demo.preference.SettingsActivity;\nimport com.google.mlkit.vision.automl.demo.preference.SettingsActivity.LaunchSource;\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** Activity demonstrating different image detector features with a still image from camera. */\n@KeepName\npublic final class StillImageActivity extends AppCompatActivity {\n\n  private static final String TAG = \"StillImageActivity\";\n\n  private static final String CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling\";\n  private static final String CUSTOM_AUTOML_OBJECT_DETECTION = \"Custom AutoML Object Detection\";\n\n  private static final String SIZE_SCREEN = \"w:screen\"; // Match screen width\n  private static final String SIZE_1024_768 = \"w:1024\"; // ~1024*768 in a normal ratio\n  private static final String SIZE_640_480 = \"w:640\"; // ~640*480 in a normal ratio\n\n  private static final String KEY_IMAGE_URI = \"com.google.mlkit.vision.automl.demo.KEY_IMAGE_URI\";\n  private static final String KEY_SELECTED_SIZE =\n      \"com.google.mlkit.vision.automl.demo.KEY_SELECTED_SIZE\";\n\n  private static final int REQUEST_IMAGE_CAPTURE = 1001;\n  private static final int REQUEST_CHOOSE_IMAGE = 1002;\n\n  private ImageView preview;\n  private GraphicOverlay graphicOverlay;\n  private String selectedMode = CUSTOM_AUTOML_LABELING;\n  private String selectedSize = SIZE_SCREEN;\n\n  boolean isLandScape;\n\n  private Uri imageUri;\n  private int imageMaxWidth;\n  private int imageMaxHeight;\n  private VisionImageProcessor imageProcessor;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    setContentView(R.layout.activity_still_image);\n\n    findViewById(R.id.select_image_button)\n        .setOnClickListener(\n            view -> {\n              // Menu for selecting either: a) take new photo b) select from existing\n              PopupMenu popup = new PopupMenu(StillImageActivity.this, view);\n              popup.setOnMenuItemClickListener(\n                  menuItem -> {\n                    int itemId = menuItem.getItemId();\n                    if (itemId == R.id.select_images_from_local) {\n                      startChooseImageIntentForResult();\n                      return true;\n                    } else if (itemId == R.id.take_photo_using_camera) {\n                      startCameraIntentForResult();\n                      return true;\n                    }\n                    return false;\n                  });\n              MenuInflater inflater = popup.getMenuInflater();\n              inflater.inflate(R.menu.camera_button_menu, popup.getMenu());\n              popup.show();\n            });\n    preview = findViewById(R.id.preview);\n    graphicOverlay = findViewById(R.id.graphic_overlay);\n\n    populateFeatureSelector();\n    populateSizeSelector();\n\n    isLandScape =\n        (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);\n\n    if (savedInstanceState != null) {\n      imageUri = savedInstanceState.getParcelable(KEY_IMAGE_URI);\n      selectedSize = savedInstanceState.getString(KEY_SELECTED_SIZE);\n    }\n\n    View rootView = findViewById(R.id.root);\n    rootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {\n      @Override\n      public void onGlobalLayout() {\n        rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);\n        imageMaxWidth = rootView.getWidth();\n        imageMaxHeight = rootView.getHeight() - findViewById(R.id.control).getHeight();\n        if (SIZE_SCREEN.equals(selectedSize)) {\n          tryReloadAndDetectInImage();\n        }\n      }\n    });\n\n    ImageView settingsButton = findViewById(R.id.settings_button);\n    settingsButton.setOnClickListener(\n        v -> {\n          Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);\n          intent.putExtra(SettingsActivity.EXTRA_LAUNCH_SOURCE, LaunchSource.STILL_IMAGE);\n          startActivity(intent);\n        });\n  }\n\n  @Override\n  public void onResume() {\n    super.onResume();\n    Log.d(TAG, \"onResume\");\n    createImageProcessor();\n    tryReloadAndDetectInImage();\n  }\n\n  private void populateFeatureSelector() {\n    Spinner featureSpinner = findViewById(R.id.feature_selector);\n    List<String> options = new ArrayList<>();\n    options.add(CUSTOM_AUTOML_LABELING);\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION);\n\n    // Creating adapter for featureSpinner\n    ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // attaching data adapter to spinner\n    featureSpinner.setAdapter(dataAdapter);\n    featureSpinner.setOnItemSelectedListener(\n        new OnItemSelectedListener() {\n\n          @Override\n          public void onItemSelected(\n              AdapterView<?> parentView, View selectedItemView, int pos, long id) {\n            selectedMode = parentView.getItemAtPosition(pos).toString();\n            createImageProcessor();\n            tryReloadAndDetectInImage();\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> arg0) {}\n        });\n  }\n\n  private void populateSizeSelector() {\n    Spinner sizeSpinner = findViewById(R.id.size_selector);\n    List<String> options = new ArrayList<>();\n    options.add(SIZE_SCREEN);\n    options.add(SIZE_1024_768);\n    options.add(SIZE_640_480);\n\n    // Creating adapter for featureSpinner\n    ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // attaching data adapter to spinner\n    sizeSpinner.setAdapter(dataAdapter);\n    sizeSpinner.setOnItemSelectedListener(\n        new OnItemSelectedListener() {\n\n          @Override\n          public void onItemSelected(\n              AdapterView<?> parentView, View selectedItemView, int pos, long id) {\n            selectedSize = parentView.getItemAtPosition(pos).toString();\n            createImageProcessor();\n            tryReloadAndDetectInImage();\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> arg0) {}\n        });\n  }\n\n  @Override\n  public void onSaveInstanceState(Bundle outState) {\n    super.onSaveInstanceState(outState);\n    outState.putParcelable(KEY_IMAGE_URI, imageUri);\n    outState.putString(KEY_SELECTED_SIZE, selectedSize);\n  }\n\n  private void startCameraIntentForResult() {\n    // Clean up last time's image\n    imageUri = null;\n    preview.setImageBitmap(null);\n\n    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);\n    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {\n      ContentValues values = new ContentValues();\n      values.put(MediaStore.Images.Media.TITLE, \"New Picture\");\n      values.put(MediaStore.Images.Media.DESCRIPTION, \"From Camera\");\n      imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);\n      takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);\n      startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);\n    }\n  }\n\n  private void startChooseImageIntentForResult() {\n    Intent intent = new Intent();\n    intent.setType(\"image/*\");\n    intent.setAction(Intent.ACTION_GET_CONTENT);\n    startActivityForResult(Intent.createChooser(intent, \"Select Picture\"), REQUEST_CHOOSE_IMAGE);\n  }\n\n  @Override\n  protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {\n      tryReloadAndDetectInImage();\n    } else if (requestCode == REQUEST_CHOOSE_IMAGE && resultCode == RESULT_OK) {\n      // In this case, imageUri is returned by the chooser, save it.\n      imageUri = data.getData();\n      tryReloadAndDetectInImage();\n    } else {\n      super.onActivityResult(requestCode, resultCode, data);\n    }\n  }\n\n  private void tryReloadAndDetectInImage() {\n    Log.d(TAG, \"Try reload and detect image\");\n    try {\n      if (imageUri == null) {\n        return;\n      }\n\n      if (SIZE_SCREEN.equals(selectedSize) && imageMaxWidth == 0) {\n        // UI layout has not finished yet, will reload once it's ready.\n        return;\n      }\n\n      Bitmap imageBitmap = BitmapUtils.getBitmapFromContentUri(getContentResolver(), imageUri);\n      if (imageBitmap == null) {\n        return;\n      }\n\n      // Clear the overlay first\n      graphicOverlay.clear();\n\n      // Get the dimensions of the image view\n      Pair<Integer, Integer> targetedSize = getTargetedWidthHeight();\n\n      // Determine how much to scale down the image\n      float scaleFactor =\n          max(\n              (float) imageBitmap.getWidth() / (float) targetedSize.first,\n              (float) imageBitmap.getHeight() / (float) targetedSize.second);\n\n      Bitmap resizedBitmap =\n          Bitmap.createScaledBitmap(\n              imageBitmap,\n              (int) (imageBitmap.getWidth() / scaleFactor),\n              (int) (imageBitmap.getHeight() / scaleFactor),\n              true);\n\n      preview.setImageBitmap(resizedBitmap);\n\n      if (imageProcessor != null) {\n        graphicOverlay.setImageSourceInfo(\n            resizedBitmap.getWidth(), resizedBitmap.getHeight(), /* isFlipped= */ false);\n        imageProcessor.processBitmap(resizedBitmap, graphicOverlay);\n      } else {\n        Log.e(TAG, \"Null imageProcessor, please check adb logs for imageProcessor creation error\");\n      }\n    } catch (IOException e) {\n      Log.e(TAG, \"Error retrieving saved image\");\n      imageUri = null;\n    }\n  }\n\n  private Pair<Integer, Integer> getTargetedWidthHeight() {\n    int targetWidth;\n    int targetHeight;\n\n    switch (selectedSize) {\n      case SIZE_SCREEN:\n        targetWidth = imageMaxWidth;\n        targetHeight = imageMaxHeight;\n        break;\n      case SIZE_640_480:\n        targetWidth = isLandScape ? 640 : 480;\n        targetHeight = isLandScape ? 480 : 640;\n        break;\n      case SIZE_1024_768:\n        targetWidth = isLandScape ? 1024 : 768;\n        targetHeight = isLandScape ? 768 : 1024;\n        break;\n      default:\n        throw new IllegalStateException(\"Unknown size\");\n    }\n\n    return new Pair<>(targetWidth, targetHeight);\n  }\n\n  private void createImageProcessor() {\n    try {\n      String autoMLRemoteModelName = PreferenceUtils.getAutoMLRemoteModelName(this);\n      switch (selectedMode) {\n        case CUSTOM_AUTOML_LABELING:\n          Log.i(TAG, \"Create Custom AutoML Image Label Processor\");\n          CustomRemoteModel customRemoteModel =\n              new CustomRemoteModel.Builder(\n                      new FirebaseModelSource.Builder(autoMLRemoteModelName).build())\n                  .build();\n          CustomImageLabelerOptions customImageLabelerOptions =\n              new CustomImageLabelerOptions.Builder(customRemoteModel)\n                  .setConfidenceThreshold(0)\n                  .build();\n          imageProcessor =\n              new AutoMLImageLabelerProcessor(\n                  this, customRemoteModel, customImageLabelerOptions, Mode.STILL_IMAGE);\n          break;\n        case CUSTOM_AUTOML_OBJECT_DETECTION:\n          Log.i(TAG, \"Using Custom AutoML Object Detector Processor\");\n          CustomRemoteModel customODTRemoteModel =\n              new CustomRemoteModel.Builder(\n                      new FirebaseModelSource.Builder(autoMLRemoteModelName).build())\n                  .build();\n          CustomObjectDetectorOptions customAutoMLODTOptions =\n              new CustomObjectDetectorOptions.Builder(customODTRemoteModel)\n                  .setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE)\n                  .enableClassification()\n                  .setClassificationConfidenceThreshold(0)\n                  .setMaxPerObjectLabelCount(1)\n                  .build();\n          imageProcessor =\n              new ObjectDetectorProcessor(this, customODTRemoteModel, customAutoMLODTOptions);\n          break;\n        default:\n          Log.e(TAG, \"Unknown selectedMode: \" + selectedMode);\n      }\n    } catch (RuntimeException e) {\n      Log.e(TAG, \"Can not create image processor: \" + selectedMode, e);\n      Toast.makeText(\n              getApplicationContext(),\n              \"Can not create image processor: \" + e.getMessage(),\n              Toast.LENGTH_LONG)\n          .show();\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/VisionImageProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.graphics.Bitmap;\nimport androidx.camera.core.ImageProxy;\nimport com.google.mlkit.common.MlKitException;\nimport java.nio.ByteBuffer;\n\n/** An interface to process the images with different vision detectors and custom image models. */\npublic interface VisionImageProcessor {\n\n  /** Processes a bitmap image. */\n  void processBitmap(Bitmap bitmap, GraphicOverlay graphicOverlay);\n\n  /** Processes ByteBuffer image data, e.g. used for Camera1 live preview case. */\n  void processByteBuffer(\n      ByteBuffer data, FrameMetadata frameMetadata, GraphicOverlay graphicOverlay)\n      throws MlKitException;\n\n  /** Processes ImageProxy image data, e.g. used for CameraX live preview case. */\n  void processImageProxy(ImageProxy image, GraphicOverlay graphicOverlay)\n      throws MlKitException;\n\n  /** Stops the underlying machine learning model and release resources. */\n  void stop();\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/VisionProcessorBase.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo;\n\nimport android.app.ActivityManager;\nimport android.app.ActivityManager.MemoryInfo;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.Build.VERSION_CODES;\nimport android.os.SystemClock;\nimport android.util.Log;\nimport android.widget.Toast;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.core.ExperimentalGetImage;\nimport androidx.camera.core.ImageProxy;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskExecutors;\nimport com.google.mlkit.vision.automl.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.common.InputImage;\nimport java.nio.ByteBuffer;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\n/**\n * Abstract base class for vision frame processors. Subclasses need to implement {@link\n * #onSuccess(Object, GraphicOverlay)} to define what they want to with the detection results and\n * {@link #detectInImage(InputImage)} to specify the detector object.\n *\n * @param <T> The type of the detected feature.\n */\npublic abstract class VisionProcessorBase<T> implements VisionImageProcessor {\n\n  protected static final String MANUAL_TESTING_LOG = \"LogTagForTest\";\n  private static final String TAG = \"VisionProcessorBase\";\n\n  private final ActivityManager activityManager;\n  private final Timer fpsTimer = new Timer();\n  private final ScopedExecutor executor;\n  private final Toast toast;\n\n  // Whether this processor is already shut down\n  private boolean isShutdown;\n\n  // Used to calculate latency, running in the same thread, no sync needed.\n  private int numRuns = 0;\n  private long totalRunMs = 0;\n  private long maxRunMs = 0;\n  private long minRunMs = Long.MAX_VALUE;\n\n  // Frame count that have been processed so far in an one second interval to calculate FPS.\n  private int frameProcessedInOneSecondInterval = 0;\n  private int framesPerSecond = 0;\n\n  // To keep the latest images and its metadata.\n  @GuardedBy(\"this\")\n  private ByteBuffer latestImage;\n\n  @GuardedBy(\"this\")\n  private FrameMetadata latestImageMetaData;\n  // To keep the images and metadata in process.\n  @GuardedBy(\"this\")\n  private ByteBuffer processingImage;\n\n  @GuardedBy(\"this\")\n  private FrameMetadata processingMetaData;\n\n  protected VisionProcessorBase(Context context) {\n    activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n    executor = new ScopedExecutor(TaskExecutors.MAIN_THREAD);\n    fpsTimer.scheduleAtFixedRate(\n        new TimerTask() {\n          @Override\n          public void run() {\n            framesPerSecond = frameProcessedInOneSecondInterval;\n            frameProcessedInOneSecondInterval = 0;\n          }\n        },\n        /* delay= */ 0,\n        /* period= */ 1000);\n    toast = Toast.makeText(context, \"\", Toast.LENGTH_LONG);\n  }\n\n  // -----------------Code for processing single still image----------------------------------------\n  @Override\n  public void processBitmap(Bitmap bitmap, final GraphicOverlay graphicOverlay) {\n    requestDetectInImage(\n        InputImage.fromBitmap(bitmap, 0),\n        graphicOverlay,\n        /* originalCameraImage= */ null,\n        /* shouldShowFps= */ false);\n  }\n\n  // -----------------Code for processing live preview frame from Camera1 API-----------------------\n  @Override\n  public synchronized void processByteBuffer(\n      ByteBuffer data, final FrameMetadata frameMetadata, final GraphicOverlay graphicOverlay) {\n    latestImage = data;\n    latestImageMetaData = frameMetadata;\n    if (processingImage == null && processingMetaData == null) {\n      processLatestImage(graphicOverlay);\n    }\n  }\n\n  private synchronized void processLatestImage(final GraphicOverlay graphicOverlay) {\n    processingImage = latestImage;\n    processingMetaData = latestImageMetaData;\n    latestImage = null;\n    latestImageMetaData = null;\n    if (processingImage != null && processingMetaData != null && !isShutdown) {\n      processImage(processingImage, processingMetaData, graphicOverlay);\n    }\n  }\n\n  private void processImage(\n      ByteBuffer data, final FrameMetadata frameMetadata, final GraphicOverlay graphicOverlay) {\n    // If live viewport is on (that is the underneath surface view takes care of the camera preview\n    // drawing), skip the unnecessary bitmap creation that used for the manual preview drawing.\n    Bitmap bitmap =\n        PreferenceUtils.isCameraLiveViewportEnabled(graphicOverlay.getContext())\n            ? null\n            : BitmapUtils.getBitmap(data, frameMetadata);\n\n    requestDetectInImage(\n            InputImage.fromByteBuffer(\n                data,\n                frameMetadata.getWidth(),\n                frameMetadata.getHeight(),\n                frameMetadata.getRotation(),\n                InputImage.IMAGE_FORMAT_NV21),\n            graphicOverlay,\n            bitmap,\n            /* shouldShowFps= */ true)\n        .addOnSuccessListener(executor, results -> processLatestImage(graphicOverlay));\n  }\n\n  // -----------------Code for processing live preview frame from CameraX API-----------------------\n  @Override\n  @RequiresApi(VERSION_CODES.LOLLIPOP)\n  @ExperimentalGetImage\n  public void processImageProxy(ImageProxy image, GraphicOverlay graphicOverlay) {\n    if (isShutdown) {\n      image.close();\n      return;\n    }\n\n    Bitmap bitmap = null;\n    if (!PreferenceUtils.isCameraLiveViewportEnabled(graphicOverlay.getContext())) {\n      bitmap = BitmapUtils.getBitmap(image);\n    }\n\n    requestDetectInImage(\n            InputImage.fromMediaImage(image.getImage(), image.getImageInfo().getRotationDegrees()),\n            graphicOverlay,\n            /* originalCameraImage= */ bitmap,\n            /* shouldShowFps= */ true)\n        // When the image is from CameraX analysis use case, must call image.close() on received\n        // images when finished using them. Otherwise, new images may not be received or the camera\n        // may stall.\n        .addOnCompleteListener(results -> image.close());\n  }\n\n  // -----------------Common processing logic-------------------------------------------------------\n  private Task<T> requestDetectInImage(\n      final InputImage image,\n      final GraphicOverlay graphicOverlay,\n      @Nullable final Bitmap originalCameraImage,\n      boolean shouldShowFps) {\n    final long startMs = SystemClock.elapsedRealtime();\n    return detectInImage(image)\n        .addOnSuccessListener(\n            executor,\n            results -> {\n              long currentLatencyMs = SystemClock.elapsedRealtime() - startMs;\n              numRuns++;\n              frameProcessedInOneSecondInterval++;\n              totalRunMs += currentLatencyMs;\n              maxRunMs = Math.max(currentLatencyMs, maxRunMs);\n              minRunMs = Math.min(currentLatencyMs, minRunMs);\n\n              // Only log inference info once per second. When frameProcessedInOneSecondInterval is\n              // equal to 1, it means this is the first frame processed during the current second.\n              if (frameProcessedInOneSecondInterval == 1) {\n                Log.d(TAG, \"Max latency is: \" + maxRunMs);\n                Log.d(TAG, \"Min latency is: \" + minRunMs);\n                Log.d(TAG, \"Num of Runs: \" + numRuns + \", Avg latency is: \" + totalRunMs / numRuns);\n                MemoryInfo mi = new MemoryInfo();\n                activityManager.getMemoryInfo(mi);\n                long availableMegs = mi.availMem / 0x100000L;\n                Log.d(TAG, \"Memory available in system: \" + availableMegs + \" MB\");\n              }\n\n              graphicOverlay.clear();\n              if (originalCameraImage != null) {\n                graphicOverlay.add(new CameraImageGraphic(graphicOverlay, originalCameraImage));\n              }\n              VisionProcessorBase.this.onSuccess(results, graphicOverlay);\n              graphicOverlay.add(\n                  new InferenceInfoGraphic(\n                      graphicOverlay, currentLatencyMs, shouldShowFps ? framesPerSecond : null));\n              graphicOverlay.postInvalidate();\n            })\n        .addOnFailureListener(\n            executor,\n            e -> {\n              graphicOverlay.clear();\n              graphicOverlay.postInvalidate();\n              String error = \"Failed to process. Error: \" + e.getLocalizedMessage();\n              toast.setText(error + \"\\nCause: \" + e.getCause());\n              toast.show();\n              Log.d(TAG, error);\n              e.printStackTrace();\n              VisionProcessorBase.this.onFailure(e);\n            });\n  }\n\n  @Override\n  public void stop() {\n    executor.shutdown();\n    isShutdown = true;\n    numRuns = 0;\n    totalRunMs = 0;\n    fpsTimer.cancel();\n  }\n\n  protected abstract Task<T> detectInImage(InputImage image);\n\n  protected abstract void onSuccess(@NonNull T results, @NonNull GraphicOverlay graphicOverlay);\n\n  protected abstract void onFailure(@NonNull Exception e);\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/automl/AutoMLImageLabelerProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.automl;\n\nimport android.content.Context;\nimport android.util.Log;\nimport android.widget.Toast;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport com.google.mlkit.common.model.DownloadConditions;\nimport com.google.mlkit.common.model.RemoteModel;\nimport com.google.mlkit.common.model.RemoteModelManager;\nimport com.google.mlkit.vision.automl.demo.GraphicOverlay;\nimport com.google.mlkit.vision.automl.demo.VisionProcessorBase;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.label.ImageLabel;\nimport com.google.mlkit.vision.label.ImageLabeler;\nimport com.google.mlkit.vision.label.ImageLabelerOptionsBase;\nimport com.google.mlkit.vision.label.ImageLabeling;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** AutoML image labeler demo. */\npublic class AutoMLImageLabelerProcessor extends VisionProcessorBase<List<ImageLabel>> {\n\n  private static final String TAG = \"AutoMLProcessor\";\n  private final ImageLabeler imageLabeler;\n  private final Context context;\n  private final Task<?> modelDownloadingTask;\n\n  private final Mode mode;\n\n  public AutoMLImageLabelerProcessor(\n      Context context, RemoteModel remoteModel, ImageLabelerOptionsBase options, Mode mode) {\n    super(context);\n    this.mode = mode;\n    this.context = context;\n    imageLabeler = ImageLabeling.getClient(options);\n\n    DownloadConditions downloadConditions = new DownloadConditions.Builder().requireWifi().build();\n    modelDownloadingTask =\n        RemoteModelManager.getInstance()\n            .download(remoteModel, downloadConditions)\n            .addOnFailureListener(\n                ignored ->\n                    Toast.makeText(\n                            context,\n                            \"Model download failed for AutoMLImageLabelerImpl,\"\n                                + \" please check your connection.\",\n                            Toast.LENGTH_LONG)\n                        .show());\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    imageLabeler.close();\n  }\n\n  @Override\n  protected Task<List<ImageLabel>> detectInImage(InputImage image) {\n    if (!modelDownloadingTask.isComplete()) {\n      if (mode == Mode.LIVE_PREVIEW) {\n        Log.i(TAG, \"Model download is in progress. Skip detecting image.\");\n        return Tasks.forResult(new ArrayList<>());\n      } else {\n        Log.i(TAG, \"Model download is in progress. Waiting...\");\n        return modelDownloadingTask.continueWithTask(task -> processImageOnDownloadComplete(image));\n      }\n    } else {\n      return processImageOnDownloadComplete(image);\n    }\n  }\n\n  private Task<List<ImageLabel>> processImageOnDownloadComplete(InputImage image) {\n    if (modelDownloadingTask != null && modelDownloadingTask.isSuccessful()) {\n      if (imageLabeler == null) {\n        Log.e(TAG, \"image labeler has not been initialized; Skipped.\");\n        Toast.makeText(context, \"no initialized Labeler.\", Toast.LENGTH_SHORT).show();\n      }\n      return imageLabeler.process(image);\n    } else {\n      String downloadingError = \"Error downloading remote model.\";\n      Log.e(TAG, downloadingError, modelDownloadingTask.getException());\n      Toast.makeText(context, downloadingError, Toast.LENGTH_SHORT).show();\n      return Tasks.forException(\n          new Exception(\"Failed to download remote model.\", modelDownloadingTask.getException()));\n    }\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull List<ImageLabel> labels, @NonNull GraphicOverlay graphicOverlay) {\n    graphicOverlay.add(new LabelGraphic(graphicOverlay, labels));\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.w(TAG, \"Label detection failed.\", e);\n  }\n\n  /**\n   * The detection mode of the processor. Different modes will have different behavior on whether or\n   * not waiting for the model download complete.\n   */\n  public enum Mode {\n    STILL_IMAGE,\n    LIVE_PREVIEW\n  }\n}\n\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/automl/LabelGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.automl;\n\nimport static com.google.common.primitives.Floats.max;\nimport static java.lang.Math.max;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport com.google.mlkit.vision.automl.demo.GraphicOverlay;\nimport com.google.mlkit.vision.label.ImageLabel;\nimport java.util.List;\nimport java.util.Locale;\n\n/** Graphic instance for rendering a label within an associated graphic overlay view. */\npublic class LabelGraphic extends GraphicOverlay.Graphic {\n\n  private static final float TEXT_SIZE = 70.0f;\n  private static final String LABEL_FORMAT = \"%.2f%% confidence (index: %d)\";\n\n  private final Paint textPaint;\n  private final Paint labelPaint;\n  private final GraphicOverlay overlay;\n\n  private final List<ImageLabel> labels;\n\n  public LabelGraphic(GraphicOverlay overlay, List<ImageLabel> labels) {\n    super(overlay);\n    this.overlay = overlay;\n    this.labels = labels;\n    textPaint = new Paint();\n    textPaint.setColor(Color.WHITE);\n    textPaint.setTextSize(TEXT_SIZE);\n\n    labelPaint = new Paint();\n    labelPaint.setColor(Color.BLACK);\n    labelPaint.setStyle(Paint.Style.FILL);\n    labelPaint.setAlpha(200);\n  }\n\n  @Override\n  public synchronized void draw(Canvas canvas) {\n    // First try to find maxWidth and totalHeight in order to draw to the center of the screen.\n    float maxWidth = 0;\n    float totalHeight = labels.size() * 2 * TEXT_SIZE;\n    for (ImageLabel label : labels) {\n      float line1Width = textPaint.measureText(label.getText());\n      float line2Width = textPaint.measureText(\n        String.format(Locale.US, LABEL_FORMAT, label.getConfidence() * 100, label.getIndex()));\n      maxWidth = max(maxWidth, line1Width, line2Width);\n    }\n    float x = max(0, overlay.getWidth() / 2.0f - maxWidth / 2.0f);\n    float y = max(200, overlay.getHeight() / 2.0f - totalHeight / 2.0f);\n\n    if (!labels.isEmpty()) {\n      float padding = 20;\n      canvas.drawRect(x - padding,\n              y - padding,\n              x + maxWidth + padding,\n              y + totalHeight + padding,\n              labelPaint);\n    }\n\n    for (ImageLabel label : labels) {\n      if (y + TEXT_SIZE * 2 > overlay.getHeight()) {\n        break;\n      }\n      canvas.drawText(label.getText(), x, y + TEXT_SIZE, textPaint);\n      y += TEXT_SIZE;\n      canvas.drawText(\n        String.format(Locale.US, LABEL_FORMAT, label.getConfidence() * 100, label.getIndex()),\n        x, y + TEXT_SIZE, textPaint);\n      y += TEXT_SIZE;\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/object/ObjectDetectorProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.object;\n\nimport android.content.Context;\nimport android.util.Log;\nimport android.widget.Toast;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport com.google.mlkit.common.model.DownloadConditions;\nimport com.google.mlkit.common.model.RemoteModel;\nimport com.google.mlkit.common.model.RemoteModelManager;\nimport com.google.mlkit.vision.automl.demo.GraphicOverlay;\nimport com.google.mlkit.vision.automl.demo.VisionProcessorBase;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.objects.DetectedObject;\nimport com.google.mlkit.vision.objects.ObjectDetection;\nimport com.google.mlkit.vision.objects.ObjectDetector;\nimport com.google.mlkit.vision.objects.ObjectDetectorOptionsBase;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** A processor to run object detector. */\npublic class ObjectDetectorProcessor extends VisionProcessorBase<List<DetectedObject>> {\n\n  private static final String TAG = \"ObjectDetectorProcessor\";\n  private final ObjectDetector detector;\n  private final Context context;\n  private final Task<?> modelDownloadingTask;\n  private final int detectorMode;\n\n  public ObjectDetectorProcessor(\n      Context context, RemoteModel remoteModel, ObjectDetectorOptionsBase options) {\n    super(context);\n    this.detectorMode = options.getDetectorMode();\n    this.context = context;\n    detector = ObjectDetection.getClient(options);\n\n    DownloadConditions downloadConditions = new DownloadConditions.Builder().requireWifi().build();\n    modelDownloadingTask =\n        RemoteModelManager.getInstance()\n            .download(remoteModel, downloadConditions)\n            .addOnFailureListener(\n                ignored ->\n                    Toast.makeText(\n                            context,\n                            \"Model download failed, please check your connection.\",\n                            Toast.LENGTH_LONG)\n                        .show());\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    detector.close();\n  }\n\n  @Override\n  protected Task<List<DetectedObject>> detectInImage(InputImage image) {\n    if (!modelDownloadingTask.isComplete()) {\n      if (detectorMode == ObjectDetectorOptionsBase.STREAM_MODE) {\n        Log.i(TAG, \"Model download is in progress. Skip detecting image.\");\n        return Tasks.forResult(new ArrayList<>());\n      } else {\n        Log.i(TAG, \"Model download is in progress. Waiting...\");\n        return modelDownloadingTask.continueWithTask(task -> processImageOnDownloadComplete(image));\n      }\n    } else {\n      return processImageOnDownloadComplete(image);\n    }\n  }\n\n  private Task<List<DetectedObject>> processImageOnDownloadComplete(InputImage image) {\n    if (modelDownloadingTask != null && modelDownloadingTask.isSuccessful()) {\n      if (detector == null) {\n        Log.e(TAG, \"object detector has not been initialized; Skipped.\");\n        Toast.makeText(context, \"no initialized Detector.\", Toast.LENGTH_SHORT).show();\n      }\n      return detector.process(image);\n    } else {\n      String downloadingError = \"Error downloading remote model.\";\n      Log.e(TAG, downloadingError, modelDownloadingTask.getException());\n      Toast.makeText(context, downloadingError, Toast.LENGTH_SHORT).show();\n      return Tasks.forException(\n          new Exception(\"Failed to download remote model.\", modelDownloadingTask.getException()));\n    }\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull List<DetectedObject> results, @NonNull GraphicOverlay graphicOverlay) {\n    for (DetectedObject object : results) {\n      graphicOverlay.add(new ObjectGraphic(graphicOverlay, object));\n    }\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.e(TAG, \"Object detection failed!\", e);\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/object/ObjectGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.object;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport com.google.mlkit.vision.automl.demo.GraphicOverlay;\nimport com.google.mlkit.vision.automl.demo.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.objects.DetectedObject;\nimport com.google.mlkit.vision.objects.DetectedObject.Label;\nimport java.util.Locale;\n\n/** Draw the detected object info in preview. */\npublic class ObjectGraphic extends Graphic {\n\n  private static final float TEXT_SIZE = 54.0f;\n  private static final float STROKE_WIDTH = 4.0f;\n  private static final int NUM_COLORS = 10;\n  private static final int[][] COLORS =\n      new int[][] {\n        // {Text color, background color}\n        {Color.BLACK, Color.WHITE},\n        {Color.WHITE, Color.MAGENTA},\n        {Color.BLACK, Color.LTGRAY},\n        {Color.WHITE, Color.RED},\n        {Color.WHITE, Color.BLUE},\n        {Color.WHITE, Color.DKGRAY},\n        {Color.BLACK, Color.CYAN},\n        {Color.BLACK, Color.YELLOW},\n        {Color.WHITE, Color.BLACK},\n        {Color.BLACK, Color.GREEN}\n      };\n  private static final String LABEL_FORMAT = \"%.2f%% confidence (index: %d)\";\n\n  private final DetectedObject object;\n  private final Paint[] boxPaints;\n  private final Paint[] textPaints;\n  private final Paint[] labelPaints;\n\n  ObjectGraphic(GraphicOverlay overlay, DetectedObject object) {\n    super(overlay);\n\n    this.object = object;\n\n    int numColors = COLORS.length;\n    textPaints = new Paint[numColors];\n    boxPaints = new Paint[numColors];\n    labelPaints = new Paint[numColors];\n    for (int i = 0; i < numColors; i++) {\n      textPaints[i] = new Paint();\n      textPaints[i].setColor(COLORS[i][0] /* text color */);\n      textPaints[i].setTextSize(TEXT_SIZE);\n\n      boxPaints[i] = new Paint();\n      boxPaints[i].setColor(COLORS[i][1] /* background color */);\n      boxPaints[i].setStyle(Paint.Style.STROKE);\n      boxPaints[i].setStrokeWidth(STROKE_WIDTH);\n\n      labelPaints[i] = new Paint();\n      labelPaints[i].setColor(COLORS[i][1] /* background color */);\n      labelPaints[i].setStyle(Paint.Style.FILL);\n    }\n  }\n\n  @Override\n  public void draw(Canvas canvas) {\n    // Decide color based on object tracking ID\n    int colorID =\n        object.getTrackingId() == null ? 0 : Math.abs(object.getTrackingId() % NUM_COLORS);\n    float textWidth = textPaints[colorID].measureText(\"Tracking ID: \" + object.getTrackingId());\n    float lineHeight = TEXT_SIZE + STROKE_WIDTH;\n    float yLabelOffset = -lineHeight;\n\n    // Calculate width and height of label box\n    for (Label label : object.getLabels()) {\n      textWidth = Math.max(textWidth, textPaints[colorID].measureText(label.getText()));\n      textWidth =\n          Math.max(\n              textWidth,\n              textPaints[colorID].measureText(\n                  String.format(\n                      Locale.US, LABEL_FORMAT, label.getConfidence() * 100, label.getIndex())));\n      yLabelOffset -= 2 * lineHeight;\n    }\n\n    // Draws the bounding box.\n    RectF rect = new RectF(object.getBoundingBox());\n    // If the image is flipped, the left will be translated to right, and the right to left.\n    float x0 = translateX(rect.left);\n    float x1 = translateX(rect.right);\n    rect.left = Math.min(x0, x1);\n    rect.right = Math.max(x0, x1);\n    rect.top = translateY(rect.top);\n    rect.bottom = translateY(rect.bottom);\n    canvas.drawRect(rect, boxPaints[colorID]);\n\n    // Draws other object info.\n    canvas.drawRect(\n        rect.left - STROKE_WIDTH,\n        rect.top + yLabelOffset,\n        rect.left + textWidth + (2 * STROKE_WIDTH),\n        rect.top,\n        labelPaints[colorID]);\n    yLabelOffset += TEXT_SIZE;\n    canvas.drawText(\n        \"Tracking ID: \" + object.getTrackingId(),\n        rect.left,\n        rect.top + yLabelOffset,\n        textPaints[colorID]);\n    yLabelOffset += lineHeight;\n\n    for (Label label : object.getLabels()) {\n      canvas.drawText(label.getText(), rect.left, rect.top + yLabelOffset, textPaints[colorID]);\n      yLabelOffset += lineHeight;\n      canvas.drawText(\n          String.format(Locale.US, LABEL_FORMAT, label.getConfidence() * 100, label.getIndex()),\n          rect.left,\n          rect.top + yLabelOffset,\n          textPaints[colorID]);\n\n      yLabelOffset += lineHeight;\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/preference/CameraXLivePreviewPreferenceFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.preference;\n\nimport android.content.Context;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.camera2.CameraAccessException;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.hardware.camera2.CameraManager;\nimport android.hardware.camera2.params.StreamConfigurationMap;\nimport android.os.Build.VERSION_CODES;\nimport android.preference.ListPreference;\nimport android.preference.PreferenceCategory;\nimport android.util.Size;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.StringRes;\nimport androidx.camera.core.CameraSelector;\nimport com.google.mlkit.vision.automl.demo.R;\nimport java.util.Arrays;\nimport java.util.List;\n\n/** Configures CameraX live preview demo settings. */\n@RequiresApi(VERSION_CODES.LOLLIPOP)\npublic class CameraXLivePreviewPreferenceFragment extends LivePreviewPreferenceFragment {\n\n  @Override\n  void setUpCameraPreferences() {\n    PreferenceCategory cameraPreference =\n        (PreferenceCategory) findPreference(getString(R.string.pref_category_key_camera));\n\n    cameraPreference.removePreference(\n        findPreference(getString(R.string.pref_key_rear_camera_preview_size)));\n    cameraPreference.removePreference(\n        findPreference(getString(R.string.pref_key_front_camera_preview_size)));\n    setUpCameraXTargetAnalysisSizePreference(\n        R.string.pref_key_camerax_rear_camera_target_resolution, CameraSelector.LENS_FACING_BACK);\n    setUpCameraXTargetAnalysisSizePreference(\n        R.string.pref_key_camerax_front_camera_target_resolution, CameraSelector.LENS_FACING_FRONT);\n  }\n\n  private void setUpCameraXTargetAnalysisSizePreference(\n      @StringRes int previewSizePrefKeyId, int lensFacing) {\n    ListPreference pref = (ListPreference) findPreference(getString(previewSizePrefKeyId));\n    CameraCharacteristics cameraCharacteristics =\n        getCameraCharacteristics(getActivity(), lensFacing);\n    String[] entries;\n    if (cameraCharacteristics != null) {\n      StreamConfigurationMap map =\n          cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);\n      Size[] outputSizes = map.getOutputSizes(SurfaceTexture.class);\n      entries = new String[outputSizes.length];\n      for (int i = 0; i < outputSizes.length; i++) {\n        entries[i] = outputSizes[i].toString();\n      }\n    } else {\n      entries =\n          new String[] {\n            \"2000x2000\",\n            \"1600x1600\",\n            \"1200x1200\",\n            \"1000x1000\",\n            \"800x800\",\n            \"600x600\",\n            \"400x400\",\n            \"200x200\",\n            \"100x100\",\n          };\n    }\n    pref.setEntries(entries);\n    pref.setEntryValues(entries);\n    pref.setSummary(pref.getEntry() == null ? \"Default\" : pref.getEntry());\n    pref.setOnPreferenceChangeListener(\n        (preference, newValue) -> {\n          String newStringValue = (String) newValue;\n          pref.setSummary(newStringValue);\n          PreferenceUtils.saveString(getActivity(), previewSizePrefKeyId, newStringValue);\n          return true;\n        });\n  }\n\n  @Nullable\n  public static CameraCharacteristics getCameraCharacteristics(\n      Context context, Integer lensFacing) {\n    CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);\n    try {\n      List<String> cameraList = Arrays.asList(cameraManager.getCameraIdList());\n      for (String availableCameraId : cameraList) {\n        CameraCharacteristics availableCameraCharacteristics =\n            cameraManager.getCameraCharacteristics(availableCameraId);\n        Integer availableLensFacing =\n            availableCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);\n        if (availableLensFacing == null) {\n          continue;\n        }\n        if (availableLensFacing.equals(lensFacing)) {\n          return availableCameraCharacteristics;\n        }\n      }\n    } catch (CameraAccessException e) {\n      // Accessing camera ID info got error\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/preference/LivePreviewPreferenceFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.preference;\n\nimport android.hardware.Camera;\nimport android.os.Bundle;\nimport android.preference.ListPreference;\nimport android.preference.PreferenceCategory;\nimport android.preference.PreferenceFragment;\nimport androidx.annotation.StringRes;\nimport com.google.mlkit.vision.automl.demo.CameraSource;\nimport com.google.mlkit.vision.automl.demo.CameraSource.SizePair;\nimport com.google.mlkit.vision.automl.demo.R;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/** Configures live preview demo settings. */\npublic class LivePreviewPreferenceFragment extends PreferenceFragment {\n\n  @Override\n  public void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    addPreferencesFromResource(R.xml.preference_live_preview_automl);\n    setUpCameraPreferences();\n    PreferenceUtils.setUpRemoteModelNamePreferences(this);\n  }\n\n  void setUpCameraPreferences() {\n    PreferenceCategory cameraPreference =\n        (PreferenceCategory) findPreference(getString(R.string.pref_category_key_camera));\n    cameraPreference.removePreference(\n        findPreference(getString(R.string.pref_key_camerax_rear_camera_target_resolution)));\n    cameraPreference.removePreference(\n        findPreference(getString(R.string.pref_key_camerax_front_camera_target_resolution)));\n      setUpCameraPreviewSizePreference(\n          R.string.pref_key_rear_camera_preview_size,\n          R.string.pref_key_rear_camera_picture_size,\n          CameraSource.CAMERA_FACING_BACK);\n      setUpCameraPreviewSizePreference(\n          R.string.pref_key_front_camera_preview_size,\n          R.string.pref_key_front_camera_picture_size,\n          CameraSource.CAMERA_FACING_FRONT);\n  }\n\n  private void setUpCameraPreviewSizePreference(\n      @StringRes int previewSizePrefKeyId, @StringRes int pictureSizePrefKeyId, int cameraId) {\n    ListPreference previewSizePreference =\n        (ListPreference) findPreference(getString(previewSizePrefKeyId));\n\n    Camera camera = null;\n    try {\n      camera = Camera.open(cameraId);\n\n      List<SizePair> previewSizeList = CameraSource.generateValidPreviewSizeList(camera);\n      String[] previewSizeStringValues = new String[previewSizeList.size()];\n      Map<String, String> previewToPictureSizeStringMap = new HashMap<>();\n      for (int i = 0; i < previewSizeList.size(); i++) {\n        SizePair sizePair = previewSizeList.get(i);\n        previewSizeStringValues[i] = sizePair.preview.toString();\n        if (sizePair.picture != null) {\n          previewToPictureSizeStringMap.put(\n              sizePair.preview.toString(), sizePair.picture.toString());\n        }\n      }\n      previewSizePreference.setEntries(previewSizeStringValues);\n      previewSizePreference.setEntryValues(previewSizeStringValues);\n\n      if (previewSizePreference.getEntry() == null) {\n        // First time of opening the Settings page.\n        SizePair sizePair =\n            CameraSource.selectSizePair(\n                camera,\n                CameraSource.DEFAULT_REQUESTED_CAMERA_PREVIEW_WIDTH,\n                CameraSource.DEFAULT_REQUESTED_CAMERA_PREVIEW_HEIGHT);\n        String previewSizeString = sizePair.preview.toString();\n        previewSizePreference.setValue(previewSizeString);\n        previewSizePreference.setSummary(previewSizeString);\n        PreferenceUtils.saveString(\n            getActivity(),\n            pictureSizePrefKeyId,\n            sizePair.picture != null ? sizePair.picture.toString() : null);\n      } else {\n        previewSizePreference.setSummary(previewSizePreference.getEntry());\n      }\n\n      previewSizePreference.setOnPreferenceChangeListener(\n          (preference, newValue) -> {\n            String newPreviewSizeStringValue = (String) newValue;\n            previewSizePreference.setSummary(newPreviewSizeStringValue);\n            PreferenceUtils.saveString(\n                getActivity(),\n                pictureSizePrefKeyId,\n                previewToPictureSizeStringMap.get(newPreviewSizeStringValue));\n            return true;\n          });\n\n    } catch (RuntimeException e) {\n      // If there's no camera for the given camera id, hide the corresponding preference.\n      ((PreferenceCategory) findPreference(getString(R.string.pref_category_key_camera)))\n          .removePreference(previewSizePreference);\n    } finally {\n      if (camera != null) {\n        camera.release();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/preference/PreferenceUtils.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.preference;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.os.Build.VERSION_CODES;\nimport android.preference.EditTextPreference;\nimport android.preference.PreferenceFragment;\nimport android.preference.PreferenceManager;\nimport android.widget.Toast;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.StringRes;\nimport androidx.camera.core.CameraSelector;\nimport com.google.android.gms.common.images.Size;\nimport com.google.common.base.Preconditions;\nimport com.google.mlkit.vision.automl.demo.CameraSource;\nimport com.google.mlkit.vision.automl.demo.CameraSource.SizePair;\nimport com.google.mlkit.vision.automl.demo.R;\n\n/** Utility class to retrieve shared preferences. */\npublic final class PreferenceUtils {\n\n  static void saveString(Context context, @StringRes int prefKeyId, @Nullable String value) {\n    PreferenceManager.getDefaultSharedPreferences(context)\n        .edit()\n        .putString(context.getString(prefKeyId), value)\n        .apply();\n  }\n\n  @Nullable\n  public static SizePair getCameraPreviewSizePair(Context context, int cameraId) {\n    Preconditions.checkArgument(\n        cameraId == CameraSource.CAMERA_FACING_BACK\n            || cameraId == CameraSource.CAMERA_FACING_FRONT);\n    String previewSizePrefKey;\n    String pictureSizePrefKey;\n    if (cameraId == CameraSource.CAMERA_FACING_BACK) {\n      previewSizePrefKey = context.getString(R.string.pref_key_rear_camera_preview_size);\n      pictureSizePrefKey = context.getString(R.string.pref_key_rear_camera_picture_size);\n    } else {\n      previewSizePrefKey = context.getString(R.string.pref_key_front_camera_preview_size);\n      pictureSizePrefKey = context.getString(R.string.pref_key_front_camera_picture_size);\n    }\n\n    try {\n      SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n      return new SizePair(\n          Size.parseSize(sharedPreferences.getString(previewSizePrefKey, null)),\n          Size.parseSize(sharedPreferences.getString(pictureSizePrefKey, null)));\n    } catch (RuntimeException e) {\n      return null;\n    }\n  }\n\n  @RequiresApi(VERSION_CODES.LOLLIPOP)\n  @Nullable\n  public static android.util.Size getCameraXTargetResolution(Context context, int lensfacing) {\n    Preconditions.checkArgument(\n        lensfacing == CameraSelector.LENS_FACING_BACK\n            || lensfacing == CameraSelector.LENS_FACING_FRONT);\n    String prefKey =\n        lensfacing == CameraSelector.LENS_FACING_BACK\n            ? context.getString(R.string.pref_key_camerax_rear_camera_target_resolution)\n            : context.getString(R.string.pref_key_camerax_front_camera_target_resolution);\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    try {\n      return android.util.Size.parseSize(sharedPreferences.getString(prefKey, null));\n    } catch (RuntimeException e) {\n      return null;\n    }\n  }\n\n  public static boolean isCameraLiveViewportEnabled(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_camera_live_viewport);\n    return sharedPreferences.getBoolean(prefKey, false);\n  }\n\n  public static String getAutoMLRemoteModelName(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String modelNamePrefKey = context.getString(R.string.pref_key_automl_remote_model_name);\n    String defaultModelName = \"mlkit_flowers\";\n    String remoteModelName = sharedPreferences.getString(modelNamePrefKey, defaultModelName);\n    if (remoteModelName.isEmpty()) {\n      remoteModelName = defaultModelName;\n    }\n    return remoteModelName;\n  }\n\n  public static void setUpRemoteModelNamePreferences(PreferenceFragment preferenceFragment) {\n    EditTextPreference autoMLRemoteModelNamePref =\n        (EditTextPreference)\n            preferenceFragment.findPreference(\n                preferenceFragment.getString(R.string.pref_key_automl_remote_model_name));\n    autoMLRemoteModelNamePref.setSummary(autoMLRemoteModelNamePref.getText());\n    autoMLRemoteModelNamePref.setOnPreferenceChangeListener(\n        (preference, newValue) -> {\n          String modelName = (String) newValue;\n          if (!modelName.isEmpty()) {\n            autoMLRemoteModelNamePref.setSummary((String) newValue);\n            return true;\n          }\n\n          Toast.makeText(\n                  preferenceFragment.getActivity(),\n                  R.string.pref_key_automl_remote_model_name,\n                  Toast.LENGTH_LONG)\n              .show();\n          return false;\n        });\n  }\n\n  private PreferenceUtils() {}\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/preference/SettingsActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.preference;\n\nimport android.os.Bundle;\nimport android.preference.PreferenceFragment;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.app.AppCompatActivity;\nimport com.google.mlkit.vision.automl.demo.R;\n\n/**\n * Hosts the preference fragment to configure settings for a demo activity that specified by the\n * {@link LaunchSource}.\n */\npublic class SettingsActivity extends AppCompatActivity {\n\n  public static final String EXTRA_LAUNCH_SOURCE = \"extra_launch_source\";\n\n  /** Specifies where this activity is launched from. */\n  @SuppressWarnings(\"NewApi\") // CameraX is only available on API 21+\n  public enum LaunchSource {\n    LIVE_PREVIEW(R.string.pref_screen_title_live_preview, LivePreviewPreferenceFragment.class),\n    STILL_IMAGE(R.string.pref_screen_title_still_image, StillImagePreferenceFragment.class),\n    CAMERAX_LIVE_PREVIEW(\n        R.string.pref_screen_title_camerax_live_preview,\n        CameraXLivePreviewPreferenceFragment.class);\n\n    private final int titleResId;\n    private final Class<? extends PreferenceFragment> prefFragmentClass;\n\n    LaunchSource(int titleResId, Class<? extends PreferenceFragment> prefFragmentClass) {\n      this.titleResId = titleResId;\n      this.prefFragmentClass = prefFragmentClass;\n    }\n  }\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    setContentView(R.layout.activity_settings);\n\n    LaunchSource launchSource =\n        (LaunchSource) getIntent().getSerializableExtra(EXTRA_LAUNCH_SOURCE);\n    ActionBar actionBar = getSupportActionBar();\n    if (actionBar != null) {\n      actionBar.setTitle(launchSource.titleResId);\n    }\n\n    try {\n      getFragmentManager()\n          .beginTransaction()\n          .replace(\n              R.id.settings_container,\n              launchSource.prefFragmentClass.getDeclaredConstructor().newInstance())\n          .commit();\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/java/com/google/mlkit/vision/automl/demo/preference/StillImagePreferenceFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.automl.demo.preference;\n\nimport android.os.Bundle;\nimport android.preference.PreferenceFragment;\nimport com.google.mlkit.vision.automl.demo.R;\n\n/** Configures still image demo settings. */\npublic class StillImagePreferenceFragment extends PreferenceFragment {\n\n  @Override\n  public void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    addPreferencesFromResource(R.xml.preference_still_image);\n    PreferenceUtils.setUpRemoteModelNamePreferences(this);\n  }\n}\n"
  },
  {
    "path": "android/automl/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:ignore=\"NewApi\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportWidth=\"172.43\"\n    android:viewportHeight=\"129.06\">\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#abccfc\"\n        android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n    <path\n        android:fillColor=\"#abccfc\"\n        android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/automl/app/src/main/res/drawable-hdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3.333333492dp\"\n    android:insetLeft=\"3.333333492dp\"\n    android:insetBottom=\"7.333333492dp\"\n    android:insetRight=\"3.333333492dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/automl/app/src/main/res/drawable-mdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3dp\"\n    android:insetLeft=\"3dp\"\n    android:insetBottom=\"7dp\"\n    android:insetRight=\"3dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/automl/app/src/main/res/drawable-xhdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3.5dp\"\n    android:insetLeft=\"3.5dp\"\n    android:insetBottom=\"7.5dp\"\n    android:insetRight=\"3.5dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/automl/app/src/main/res/drawable-xxhdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3.666666746dp\"\n    android:insetLeft=\"3.666666746dp\"\n    android:insetBottom=\"7.666666985dp\"\n    android:insetRight=\"3.666666746dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/automl/app/src/main/res/drawable-xxxhdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3.75dp\"\n    android:insetLeft=\"3.75dp\"\n    android:insetBottom=\"7.75dp\"\n    android:insetRight=\"3.75dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout/activity_camerax_live_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <androidx.camera.view.PreviewView\n      android:id=\"@+id/preview_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintTop_toTopOf=\"parent\"\n      app:layout_constraintBottom_toTopOf=\"@+id/control\"/>\n\n  <com.google.mlkit.vision.automl.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintLeft_toLeftOf=\"@id/preview_view\"\n      app:layout_constraintRight_toRightOf=\"@id/preview_view\"\n      app:layout_constraintTop_toTopOf=\"@id/preview_view\"\n      app:layout_constraintBottom_toBottomOf=\"@id/preview_view\"/>\n\n  <include\n      android:id=\"@+id/settings_button\"\n      layout=\"@layout/settings_style\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      app:layout_constraintRight_toRightOf=\"@id/preview_view\"\n      app:layout_constraintTop_toTopOf=\"@id/preview_view\" />\n\n  <LinearLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"60dp\"\n      app:layout_constraintTop_toBottomOf=\"@id/preview_view\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      android:background=\"#000\"\n      android:orientation=\"horizontal\">\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"0dp\"\n        android:layout_weight=\"1\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"/>\n\n  </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout/activity_chooser.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:orientation=\"vertical\">\n\n  <ImageView\n      android:id=\"@+id/imageView\"\n      android:contentDescription=\"@string/app_name\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"50dp\"\n      android:layout_marginTop=\"32dp\"\n      app:srcCompat=\"@drawable/logo_mlkit\" />\n\n  <TextView\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:paddingTop=\"32dp\"\n      android:paddingBottom=\"32dp\"\n      android:fontFamily=\"google-sans\"\n      android:gravity=\"center_horizontal\"\n      android:text=\"@string/app_name\"\n      android:textColor=\"@color/white\"\n      android:textSize=\"18sp\"/>\n\n  <ListView\n      android:id=\"@+id/test_activity_list_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"/>\n</LinearLayout>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout/activity_live_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:ignore=\"RtlHardcoded\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#000\"\n    android:keepScreenOn=\"true\"\n    android:orientation=\"vertical\">\n\n  <com.google.mlkit.vision.automl.demo.CameraSourcePreview\n      android:id=\"@+id/preview\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_alignParentLeft=\"true\"\n      android:layout_alignParentTop=\"true\">\n\n    <com.google.mlkit.vision.automl.demo.GraphicOverlay\n        android:id=\"@+id/graphic_overlay\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentTop=\"true\"/>\n  </com.google.mlkit.vision.automl.demo.CameraSourcePreview>\n\n  <include\n      layout=\"@layout/settings_style\"\n      android:id=\"@+id/settings_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_alignParentTop=\"true\"\n      android:layout_alignParentEnd=\"true\"\n      android:layout_alignParentRight=\"true\"/>\n\n  <LinearLayout\n      android:id=\"@+id/control\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"60dp\"\n      android:layout_alignParentBottom=\"true\"\n      android:layout_alignParentLeft=\"true\"\n      android:layout_toRightOf=\"@id/preview\"\n      android:background=\"#000\"\n      android:orientation=\"horizontal\">\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"0dp\"\n        android:layout_weight=\"1\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"/>\n\n  </LinearLayout>\n\n</RelativeLayout>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout/activity_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/settings_container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n</LinearLayout>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout/activity_still_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <ImageView\n      android:id=\"@+id/preview\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:adjustViewBounds=\"true\"\n      app:layout_constraintBottom_toTopOf=\"@+id/control\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintTop_toTopOf=\"parent\" />\n\n  <com.google.mlkit.vision.automl.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintLeft_toLeftOf=\"@id/preview\"\n      app:layout_constraintRight_toRightOf=\"@id/preview\"\n      app:layout_constraintTop_toTopOf=\"@id/preview\"\n      app:layout_constraintBottom_toBottomOf=\"@id/preview\"/>\n\n  <LinearLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      android:background=\"#000\"\n      android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/select_image_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_margin=\"12dp\"\n        android:text=\"@string/select_image\"/>\n\n    <LinearLayout\n        android:id=\"@+id/control2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        android:background=\"#000\"\n        android:orientation=\"horizontal\">\n\n      <Spinner\n          android:id=\"@+id/size_selector\"\n          android:layout_width=\"0dp\"\n          android:layout_weight=\"1\"\n          android:layout_height=\"wrap_content\"\n          android:layout_gravity=\"center\"/>\n\n      <Spinner\n          android:id=\"@+id/feature_selector\"\n          android:layout_width=\"0dp\"\n          android:layout_weight=\"1\"\n          android:layout_height=\"wrap_content\"\n          android:layout_gravity=\"center\"/>\n    </LinearLayout>\n  </LinearLayout>\n\n  <include\n      layout=\"@layout/settings_style\"\n      android:id=\"@+id/settings_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      app:layout_constraintRight_toRightOf=\"@id/root\"\n      app:layout_constraintTop_toTopOf=\"@id/root\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout/settings_style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ImageView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"12dp\"\n    android:contentDescription=\"@string/menu_item_settings\"\n    android:src=\"@drawable/ic_settings_white_24dp\"/>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout/spinner_style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TextView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:textStyle=\"bold\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"1dip\"\n    android:gravity=\"center\"\n    android:textColor=\"#FFF\"\n    android:textSize=\"16sp\"/>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout/toggle_style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item\n      android:drawable=\"@drawable/ic_switch_camera_white_48dp\"\n      android:state_checked=\"true\"/>\n  <item\n      android:drawable=\"@drawable/ic_switch_camera_white_48dp\"\n      android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout-land/activity_camerax_live_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <androidx.camera.view.PreviewView\n      android:id=\"@+id/preview_view\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintEnd_toStartOf=\"@+id/control\"/>\n\n  <com.google.mlkit.vision.automl.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toStartOf=\"@id/preview_view\"\n      app:layout_constraintEnd_toEndOf=\"@id/preview_view\" />\n\n  <FrameLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"220dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toEndOf=\"@id/preview_view\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      android:background=\"#000\">\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"top\"/>\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"bottom|start\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <ImageView\n        android:id=\"@+id/settings_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:padding=\"12dp\"\n        android:contentDescription=\"@string/menu_item_settings\"\n        android:src=\"@drawable/ic_settings_white_24dp\"/>\n  </FrameLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/automl/app/src/main/res/layout-land/activity_live_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"horizontal\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#000\"\n    android:keepScreenOn=\"true\">\n\n  <com.google.mlkit.vision.automl.demo.CameraSourcePreview\n      android:id=\"@+id/preview\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\">\n\n    <com.google.mlkit.vision.automl.demo.GraphicOverlay\n        android:id=\"@+id/graphic_overlay\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n  </com.google.mlkit.vision.automl.demo.CameraSourcePreview>\n\n  <FrameLayout\n      android:id=\"@+id/control\"\n      android:layout_width=\"220dp\"\n      android:layout_height=\"match_parent\"\n      android:layout_alignParentRight=\"true\"\n      android:layout_alignParentTop=\"true\"\n      android:background=\"#000\" >\n\n      <Spinner\n          android:id=\"@+id/spinner\"\n          android:layout_width=\"match_parent\"\n          android:layout_height=\"wrap_content\"\n          android:layout_gravity=\"center_horizontal\" />\n\n      <ToggleButton\n          android:id=\"@+id/facing_switch\"\n          android:layout_width=\"48dp\"\n          android:layout_height=\"48dp\"\n          android:layout_gravity=\"bottom|start\"\n          android:background=\"@layout/toggle_style\"\n          android:textOff=\"\"\n          android:textOn=\"\"\n          android:checked=\"false\" />\n\n      <include\n          layout=\"@layout/settings_style\"\n          android:id=\"@+id/settings_button\"\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\"\n          android:layout_gravity=\"bottom|end\"/>\n\n  </FrameLayout>\n\n</RelativeLayout>\n"
  },
  {
    "path": "android/automl/app/src/main/res/menu/camera_button_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n  <item android:id=\"@+id/select_images_from_local\"\n      android:title=\"Select image from album\"\n      android:orderInCategory=\"100\"\n      app:showAsAction=\"never\" />\n  <item android:id=\"@+id/take_photo_using_camera\"\n      android:title=\"Take photo\"\n      android:orderInCategory=\"100\"\n      app:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "android/automl/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#4CAF50</color>\n    <color name=\"colorPrimaryDark\">#388E3C</color>\n    <color name=\"colorAccent\">#7C4DFF</color>\n\n    <color name=\"blue_grey_400\">#78909C</color>\n    <color name=\"light_grey_400\">#E6E6E6</color>\n    <color name=\"light_green_700\">#689F38</color>\n    <color name=\"gray\">#BFBFBF</color>\n    <color name=\"white\">#FFFFFF</color>\n    <color name=\"blue\">#4286f4</color>\n    <color name=\"red\">#f44242</color>\n</resources>\n"
  },
  {
    "path": "android/automl/app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"padding_standard\">10dp</dimen>\n</resources>\n"
  },
  {
    "path": "android/automl/app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <string name=\"app_name\">MLKit-AutoML-Remote</string>\n  <string name=\"ok\">OK</string>\n  <string name=\"permission_camera_rationale\">Access to the camera is needed for detection</string>\n  <string name=\"no_camera_permission\">This application cannot run because it does not have the camera permission.  The application will now exit.</string>\n  <string name=\"low_storage_error\">Face detector dependencies cannot be downloaded due to low device storage</string>\n  <string name=\"toggle_turn_on\">Front</string>\n  <string name=\"toggle_turn_off\">Back</string>\n  <string name=\"desc_camera_source_activity\">Vision detectors demo with live camera preview</string>\n  <string name=\"desc_still_image_activity\">Vision detectors demo with a still image</string>\n  <string name=\"desc_camerax_live_preview_activity\">Vision detectors demo with live preview using CameraX. Note that CameraX is only supported on API 21+</string>\n  <string name=\"download_error\">Download error</string>\n  <string name=\"start_over\">Start over</string>\n  <string name=\"menu_item_settings\">Settings</string>\n  <string name=\"select_image\">Select image</string>\n\n  <!-- Settings related strings. -->\n  <string name=\"pref_screen_title_live_preview\">Live preview settings</string>\n  <string name=\"pref_screen_title_still_image\">Still image settings</string>\n  <string name=\"pref_screen_title_camerax_live_preview\">CameraX live preview settings</string>\n  <string name=\"pref_category_face_detection\">Face Detection</string>\n  <string name=\"pref_category_object_detection\">Object Detection / Custom Object Detection</string>\n  <string name=\"pref_category_automl\">AutoML Image Labeling</string>\n  <string name=\"pref_category_pose_detection\">Pose Detection</string>\n\n  <!-- Strings for camera settings. -->\n  <string name=\"pref_category_key_camera\" translatable=\"false\">pckc</string>\n  <string name=\"pref_category_title_camera\">Camera</string>\n  <string name=\"pref_key_rear_camera_preview_size\" translatable=\"false\">rcpvs</string>\n  <string name=\"pref_key_rear_camera_picture_size\" translatable=\"false\">rcpts</string>\n  <string name=\"pref_key_front_camera_preview_size\" translatable=\"false\">fcpvs</string>\n  <string name=\"pref_key_front_camera_picture_size\" translatable=\"false\">fcpts</string>\n  <string name=\"pref_key_camerax_rear_camera_target_resolution\" translatable=\"false\">crctas</string>\n  <string name=\"pref_key_camerax_front_camera_target_resolution\" translatable=\"false\">cfctas</string>\n  <string name=\"pref_key_camera_live_viewport\" translatable=\"false\">clv</string>\n  <string name=\"pref_title_rear_camera_preview_size\">Rear camera preview size</string>\n  <string name=\"pref_title_front_camera_preview_size\">Front camera preview size</string>\n  <string name=\"pref_title_camerax_rear_camera_target_resolution\">CameraX rear camera target resolution</string>\n  <string name=\"pref_title_camerax_front_camera_target_resolution\">CameraX front camera target resolution</string>\n  <string name=\"pref_title_camera_live_viewport\">Enable live viewport</string>\n  <string name=\"pref_summary_camera_live_viewport\">Do not block camera preview drawing on detection</string>\n\n\n  <!-- Strings for automl remote model name preference. -->\n  <string name=\"pref_title_automl_remote_model_name\">AutoML Remote Model Name</string>\n  <string name=\"pref_key_automl_remote_model_name\" translatable=\"false\">armn</string>\n  <string name=\"pref_dialog_message_automl_remote_model_name\">Remote model name in the Firebase Console.</string>\n</resources>\n"
  },
  {
    "path": "android/automl/app/src/main/res/values/styles.xml",
    "content": "<resources>\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.NoActionBar\"/>\n</resources>\n"
  },
  {
    "path": "android/automl/app/src/main/res/xml/preference_live_preview_automl.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n  <PreferenceCategory\n      android:enabled=\"true\"\n      android:key=\"@string/pref_category_key_camera\"\n      android:title=\"@string/pref_category_title_camera\">\n\n    <ListPreference\n        android:key=\"@string/pref_key_rear_camera_preview_size\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_rear_camera_preview_size\"/>\n\n    <ListPreference\n        android:key=\"@string/pref_key_front_camera_preview_size\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_front_camera_preview_size\"/>\n\n   <ListPreference\n        android:key=\"@string/pref_key_camerax_rear_camera_target_resolution\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_camerax_rear_camera_target_resolution\"/>\n\n   <ListPreference\n        android:key=\"@string/pref_key_camerax_front_camera_target_resolution\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_camerax_front_camera_target_resolution\"/>\n\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_camera_live_viewport\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_camera_live_viewport\"\n        android:title=\"@string/pref_title_camera_live_viewport\"/>\n\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_automl\">\n\n    <EditTextPreference\n        android:defaultValue=\"mlkit_flowers\"\n        android:dialogMessage=\"@string/pref_dialog_message_automl_remote_model_name\"\n        android:key=\"@string/pref_key_automl_remote_model_name\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_automl_remote_model_name\"/>\n  </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "android/automl/app/src/main/res/xml/preference_still_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n  <PreferenceCategory android:title=\"@string/pref_category_automl\">\n\n    <EditTextPreference\n        android:defaultValue=\"mlkit_flowers\"\n        android:dialogMessage=\"@string/pref_dialog_message_automl_remote_model_name\"\n        android:key=\"@string/pref_key_automl_remote_model_name\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_automl_remote_model_name\"/>\n  </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "android/automl/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.7.20'\n\n    repositories {\n        mavenLocal()\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.4.2'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/automl/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.5-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "android/automl/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n"
  },
  {
    "path": "android/automl/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/automl/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/automl/settings.gradle",
    "content": "rootProject.name='ML Kit AutoML'\ninclude ':app'\n"
  },
  {
    "path": "android/codescanner/LICENSE",
    "content": "   Copyright 2022 Google LLC\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "android/codescanner/README.md",
    "content": "# Google Code Scanner API Quickstart\n\n* [Read more about Google Code Scanner API](https://developers.google.com/ml-kit/code-scanner)\n\n## Introduction\n\nThe Google Code Scanner API Quickstart app demonstrates how to use the code\nscanner feature to scan codes without requiring to request camera permission.\n\n## Getting Started\n\n* Run the sample code on your Android device or emulator\n* Tap on the SCAN BARCODE button.\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/code-scanner)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2022 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/codescanner/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 31\n    defaultConfig {\n        applicationId \"com.google.mlkit.samples.codescanner\"\n        minSdkVersion 21\n        targetSdkVersion 31\n        versionCode 1\n        versionName \"1.0\"\n        setProperty(\"archivesBaseName\", \"code-scanner-sample\")\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        debug {\n            isDefault true\n            minifyEnabled false\n            proguardFiles 'proguard-rules.pro'\n        }\n        proguard {\n            debuggable false\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n            testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardTest-rules.pro', 'proguard.cfg'\n        }\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n        }\n        testBuildType \"proguard\"\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    implementation project(':internal:chooserx')\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'com.google.android.material:material:1.5.0'\n\n    implementation 'com.google.android.gms:play-services-code-scanner:16.1.0'\n\n    androidTestImplementation 'androidx.test:rules:1.4.0'\n    androidTestImplementation 'androidx.test:runner:1.4.0'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.3'\n    androidTestImplementation 'com.google.truth:truth:1.0.1'\n}\n"
  },
  {
    "path": "android/codescanner/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.google.mlkit.samples.codescanner\"\n    tools:overrideLibrary=\"com.google.android.gms.base\">\n\n  <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>\n  <uses-permission android:name=\"android.permission.INTERNET\"/>\n\n  <application\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:taskAffinity=\"\"\n      android:theme=\"@style/AppTheme\">\n\n    <meta-data\n        android:name=\"com.google.android.gms.version\"\n        android:value=\"@integer/google_play_services_version\" />\n\n    <meta-data\n        android:name=\"com.google.mlkit.vision.DEPENDENCIES\"\n        android:value=\"barcode_ui\"/>\n\n    <activity\n        android:name=\".EntryChoiceActivity\"\n        android:exported=\"true\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\".java.MainActivity\"\n        android:exported=\"false\" />\n\n    <activity\n        android:name=\".kotlin.MainActivity\"\n        android:exported=\"false\" />\n\n  </application>\n</manifest>\n"
  },
  {
    "path": "android/codescanner/app/src/main/java/com/google/mlkit/samples/codescanner/EntryChoiceActivity.kt",
    "content": "/*\n * Copyright 2022 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.codescanner\n\nimport android.content.Intent\nimport com.google.mlkit.samples.codescanner.kotlin.MainActivity\nimport com.mlkit.example.internal.BaseEntryChoiceActivity\nimport com.mlkit.example.internal.Choice\n\nclass EntryChoiceActivity : BaseEntryChoiceActivity() {\n\n  override fun getChoices(): List<Choice> {\n    return listOf(\n      Choice(\n        \"Java\",\n        \"Run the Google Code Scanner demo written in Java.\",\n        Intent(this, com.google.mlkit.samples.codescanner.java.MainActivity::class.java)\n      ),\n      Choice(\n        \"Kotlin\",\n        \"Run the Google Code Scanner demo written in Kotlin.\",\n        Intent(this, com.google.mlkit.samples.codescanner.kotlin.MainActivity::class.java)\n      )\n    )\n  }\n}\n"
  },
  {
    "path": "android/codescanner/app/src/main/java/com/google/mlkit/samples/codescanner/java/MainActivity.java",
    "content": "/*\n * Copyright 2022 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.codescanner.java;\n\nimport android.annotation.SuppressLint;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.view.View;\nimport android.widget.CheckBox;\nimport android.widget.TextView;\nimport com.google.mlkit.common.MlKitException;\nimport com.google.mlkit.samples.codescanner.R;\nimport com.google.mlkit.vision.barcode.common.Barcode;\nimport com.google.mlkit.vision.codescanner.GmsBarcodeScanner;\nimport com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions;\nimport com.google.mlkit.vision.codescanner.GmsBarcodeScanning;\nimport java.util.Locale;\n\n/** Demonstrates the code scanner powered by Google Play Services. */\npublic class MainActivity extends AppCompatActivity {\n\n  private static final String KEY_ALLOW_MANUAL_INPUT = \"allow_manual_input\";\n  private static final String KEY_ENABLE_AUTO_ZOOM = \"enable_auto_zoom\";\n\n  private boolean allowManualInput;\n  private boolean enableAutoZoom;\n  private TextView barcodeResultView;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n\n    barcodeResultView = findViewById(R.id.barcode_result_view);\n  }\n\n  public void onAllowManualInputCheckboxClicked(View view) {\n    allowManualInput = ((CheckBox) view).isChecked();\n  }\n\n  public void onEnableAutoZoomCheckboxClicked(View view) {\n    enableAutoZoom = ((CheckBox) view).isChecked();\n  }\n\n  public void onScanButtonClicked(View view) {\n    GmsBarcodeScannerOptions.Builder optionsBuilder = new GmsBarcodeScannerOptions.Builder();\n    if (allowManualInput) {\n      optionsBuilder.allowManualInput();\n    }\n    if (enableAutoZoom) {\n      optionsBuilder.enableAutoZoom();\n    }\n    GmsBarcodeScanner gmsBarcodeScanner =\n        GmsBarcodeScanning.getClient(this, optionsBuilder.build());\n    gmsBarcodeScanner\n        .startScan()\n        .addOnSuccessListener(barcode -> barcodeResultView.setText(getSuccessfulMessage(barcode)))\n        .addOnFailureListener(\n            e -> barcodeResultView.setText(getErrorMessage(e)))\n        .addOnCanceledListener(\n            () -> barcodeResultView.setText(getString(R.string.error_scanner_cancelled)));\n  }\n\n  @Override\n  protected void onSaveInstanceState(Bundle savedInstanceState) {\n    savedInstanceState.putBoolean(KEY_ALLOW_MANUAL_INPUT, allowManualInput);\n    savedInstanceState.putBoolean(KEY_ENABLE_AUTO_ZOOM, enableAutoZoom);\n    super.onSaveInstanceState(savedInstanceState);\n  }\n\n  @Override\n  protected void onRestoreInstanceState(Bundle savedInstanceState) {\n    super.onRestoreInstanceState(savedInstanceState);\n    allowManualInput = savedInstanceState.getBoolean(KEY_ALLOW_MANUAL_INPUT);\n    enableAutoZoom = savedInstanceState.getBoolean(KEY_ENABLE_AUTO_ZOOM);\n  }\n\n  private String getSuccessfulMessage(Barcode barcode) {\n    String barcodeValue =\n        String.format(\n            Locale.US,\n            \"Display Value: %s\\nRaw Value: %s\\nFormat: %s\\nValue Type: %s\",\n            barcode.getDisplayValue(),\n            barcode.getRawValue(),\n            barcode.getFormat(),\n            barcode.getValueType());\n    return getString(R.string.barcode_result, barcodeValue);\n  }\n\n  @SuppressLint(\"SwitchIntDef\")\n  private String getErrorMessage(Exception e) {\n    if (e instanceof MlKitException) {\n      switch (((MlKitException) e).getErrorCode()) {\n        case MlKitException.CODE_SCANNER_CAMERA_PERMISSION_NOT_GRANTED:\n          return getString(R.string.error_camera_permission_not_granted);\n        case MlKitException.CODE_SCANNER_APP_NAME_UNAVAILABLE:\n          return getString(R.string.error_app_name_unavailable);\n        default:\n          return getString(R.string.error_default_message, e);\n      }\n    } else {\n      return e.getMessage();\n    }\n  }\n}\n"
  },
  {
    "path": "android/codescanner/app/src/main/java/com/google/mlkit/samples/codescanner/kotlin/MainActivity.kt",
    "content": "/*\n * Copyright 2022 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.codescanner.kotlin\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.view.View\nimport android.widget.CheckBox\nimport android.widget.TextView\nimport com.google.mlkit.common.MlKitException\nimport com.google.mlkit.samples.codescanner.R\nimport com.google.mlkit.vision.barcode.common.Barcode\nimport com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions\nimport com.google.mlkit.vision.codescanner.GmsBarcodeScanning\nimport java.util.Locale\n\n/** Demonstrates the code scanner powered by Google Play Services. */\nclass MainActivity : AppCompatActivity() {\n\n  private var allowManualInput = false\n  private var enableAutoZoom = false\n  private var barcodeResultView: TextView? = null\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_main)\n    barcodeResultView = findViewById(R.id.barcode_result_view)\n  }\n\n  fun onAllowManualInputCheckboxClicked(view: View) {\n    allowManualInput = (view as CheckBox).isChecked\n  }\n\n  fun onEnableAutoZoomCheckboxClicked(view: View) {\n    enableAutoZoom = (view as CheckBox).isChecked\n  }\n\n  fun onScanButtonClicked(view: View) {\n    val optionsBuilder = GmsBarcodeScannerOptions.Builder()\n    if (allowManualInput) {\n      optionsBuilder.allowManualInput()\n    }\n    if (enableAutoZoom) {\n      optionsBuilder.enableAutoZoom()\n    }\n    val gmsBarcodeScanner = GmsBarcodeScanning.getClient(this, optionsBuilder.build())\n    gmsBarcodeScanner\n      .startScan()\n      .addOnSuccessListener { barcode: Barcode ->\n        barcodeResultView!!.text = getSuccessfulMessage(barcode)\n      }\n      .addOnFailureListener { e: Exception -> barcodeResultView!!.text = getErrorMessage(e) }\n      .addOnCanceledListener {\n        barcodeResultView!!.text = getString(R.string.error_scanner_cancelled)\n      }\n  }\n\n  override fun onSaveInstanceState(savedInstanceState: Bundle) {\n    savedInstanceState.putBoolean(KEY_ALLOW_MANUAL_INPUT, allowManualInput)\n    savedInstanceState.putBoolean(KEY_ENABLE_AUTO_ZOOM, enableAutoZoom)\n    super.onSaveInstanceState(savedInstanceState)\n  }\n\n  override fun onRestoreInstanceState(savedInstanceState: Bundle) {\n    super.onRestoreInstanceState(savedInstanceState)\n    allowManualInput = savedInstanceState.getBoolean(KEY_ALLOW_MANUAL_INPUT)\n    enableAutoZoom = savedInstanceState.getBoolean(KEY_ENABLE_AUTO_ZOOM)\n  }\n\n  private fun getSuccessfulMessage(barcode: Barcode): String {\n    val barcodeValue =\n      String.format(\n        Locale.US,\n        \"Display Value: %s\\nRaw Value: %s\\nFormat: %s\\nValue Type: %s\",\n        barcode.displayValue,\n        barcode.rawValue,\n        barcode.format,\n        barcode.valueType\n      )\n    return getString(R.string.barcode_result, barcodeValue)\n  }\n\n  private fun getErrorMessage(e: Exception): String? {\n    return if (e is MlKitException) {\n      when (e.errorCode) {\n        MlKitException.CODE_SCANNER_CAMERA_PERMISSION_NOT_GRANTED ->\n          getString(R.string.error_camera_permission_not_granted)\n        MlKitException.CODE_SCANNER_APP_NAME_UNAVAILABLE ->\n          getString(R.string.error_app_name_unavailable)\n        else -> getString(R.string.error_default_message, e)\n      }\n    } else {\n      e.message\n    }\n  }\n\n  companion object {\n    private const val KEY_ALLOW_MANUAL_INPUT = \"allow_manual_input\"\n    private const val KEY_ENABLE_AUTO_ZOOM = \"enable_auto_zoom\"\n  }\n}\n"
  },
  {
    "path": "android/codescanner/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportWidth=\"172.43\"\n    android:viewportHeight=\"129.06\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#ff9933\"\n      android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#ffff99\"\n      android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#ff9933\"\n      android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#ffff99\"\n      android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#ff9933\"\n      android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/codescanner/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:padding=\"16dp\"\n    android:orientation=\"vertical\">\n\n  <CheckBox\n      android:id=\"@+id/allow_manual_input\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:onClick=\"onAllowManualInputCheckboxClicked\"\n      android:text=\"@string/allow_manual_input\" />\n  <CheckBox\n      android:id=\"@+id/enable_auto_zoom\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:onClick=\"onEnableAutoZoomCheckboxClicked\"\n      android:text=\"@string/enable_auto_zoom\" />\n  <Button\n      android:id=\"@+id/scan_barcode_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:onClick=\"onScanButtonClicked\"\n      android:text=\"@string/scan_barcode_button\" />\n  <TextView\n      android:id=\"@+id/barcode_result_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:text=\"\" />\n</LinearLayout>\n"
  },
  {
    "path": "android/codescanner/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"colorPrimary\">@color/blue</color>\n  <color name=\"colorPrimaryDark\">@color/darkBlue</color>\n  <color name=\"colorAccent\">@color/red</color>\n  <color name=\"blue\">#3681E6</color>\n  <color name=\"darkBlue\">#2F5FC0</color>\n  <color name=\"red\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "android/codescanner/app/src/main/res/values/strings.xml",
    "content": "<resources>\n  <string name=\"app_name\" translatable=\"false\">Code Scanner Demo</string>\n  <string name=\"allow_manual_input\" translatable=\"false\">Allow input code manually</string>\n  <string name=\"enable_auto_zoom\" translatable=\"false\">Enable auto-zoom feature</string>\n  <string name=\"scan_barcode_button\" translatable=\"false\">Scan Barcode</string>\n  <string name=\"barcode_result\" translatable=\"false\">Barcode detected.\\n%1$s</string>\n  <string name=\"error_scanner_cancelled\" translatable=\"false\">Code scanner is cancelled.</string>\n  <string name=\"error_camera_permission_not_granted\" translatable=\"false\">Camera permission is not granted.</string>\n  <string name=\"error_app_name_unavailable\" translatable=\"false\">App name is not set.</string>\n  <string name=\"error_default_message\" translatable=\"false\">Failed to scan code: %1$s</string>\n</resources>\n"
  },
  {
    "path": "android/codescanner/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n  <!-- Base application theme. -->\n  <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.DarkActionBar\">\n    <item name=\"colorPrimary\">@color/blue</item>\n    <item name=\"colorPrimaryDark\">@color/darkBlue</item>\n    <item name=\"colorAccent\">@color/red</item>\n  </style>\n\n</resources>\n"
  },
  {
    "path": "android/codescanner/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.4.31'\n\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.2.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        google()\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "android/codescanner/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.8-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "android/codescanner/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "android/codescanner/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/codescanner/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/codescanner/settings.gradle",
    "content": "rootProject.name= \"mlkit_code_scanner_sample\"\ninclude ':app'\ninclude ':internal:chooserx'\nproject(':internal:chooserx').projectDir = file('../internal/chooserx')"
  },
  {
    "path": "android/digitalink/README.md",
    "content": "# ML Kit Digital Ink Recognition Quickstart\n\n- [Read more about ML Kit Digital Ink Recognition](https://developers.google.com/ml-kit/vision/digital-ink-recognition/android)\n\n## Introduction\n\nThe ML Kit Digital Ink Recognition Quickstart app demonstrates how to use the\nDigital Ink Recognition feature of ML Kit to perform digital ink recognition\nin your application.\n\n## Getting Started\n\n* Run the sample code on your Android device or emulator\n* Draw on the screen and see your handwriting recognized and turned into text\n* Try extending the code to add new features and functionality\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/guides)\n* [API Reference](https://developers.google.com/ml-kit/reference)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/digitalink/app/build.gradle",
    "content": "apply plugin: \"com.android.application\"\napply plugin: 'kotlin-android'\n\nandroid {\n    namespace \"com.google.mlkit.samples.vision.digitalink.recognition\"\n    compileSdkVersion 34\n    defaultConfig {\n        applicationId \"com.google.mlkit.samples.vision.digitalink.recognition\"\n        minSdkVersion 23\n        targetSdkVersion 34\n        multiDexEnabled true\n        versionCode 1\n        versionName \"1.0\"\n        setProperty(\"archivesBaseName\", \"vision-digital-ink\")\n        testApplicationId \"com.google.mlkit.vision.digitalink.recognition\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n        }\n        debug {\n            minifyEnabled false\n            proguardFiles 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_17\n        targetCompatibility JavaVersion.VERSION_17\n    }\n    buildFeatures {\n        viewBinding true\n    }\n}\n\ndependencies {\n    implementation \"com.google.auto.value:auto-value-annotations:1.6.5\"\n    annotationProcessor \"com.google.auto.value:auto-value:1.6.3\"\n    implementation 'androidx.core:core-ktx:1.3.1'\n    implementation 'androidx.multidex:multidex:2.0.1'\n    implementation 'com.google.guava:guava:28.0-android'\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n\n    implementation 'androidx.appcompat:appcompat:1.2.0'\n\n    implementation 'com.google.mlkit:digital-ink-recognition:19.0.0'\n}\n"
  },
  {
    "path": "android/digitalink/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "android/digitalink/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.samples.vision.digitalink.recognition\" android:versionCode=\"1\"\n    android:versionName=\"1.0\">\n\n  <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n  <!-- For downloading -->\n  <uses-permission android:name=\"android.permission.INTERNET\" />\n  <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n  <application android:name=\"androidx.multidex.MultiDexApplication\"\n      android:icon=\"@mipmap/ic_launcher\" android:label=\"@string/app_name\"\n      android:theme=\"@style/Theme.AppCompat.Light.DarkActionBar\">\n\n    <activity\n        android:name=\"com.google.mlkit.samples.vision.digitalink.recognition.DigitalInkMainActivity\"\n        android:label=\"@string/title_activity_main\"\n        android:exported=\"true\"\n        android:screenOrientation=\"portrait\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n    <!-- Replace the activity declaration above with the following one for trying out the kotlin version of the app.\n    <activity\n       android:name=\"com.google.mlkit.samples.vision.digitalink.recognition.kotlin.DigitalInkMainActivity\"\n       android:label=\"@string/title_activity_main\"\n       android:exported=\"true\"\n       android:screenOrientation=\"portrait\" >\n       <intent-filter>\n           <action android:name=\"android.intent.action.MAIN\" />\n\n           <category android:name=\"android.intent.category.LAUNCHER\" />\n       </intent-filter>\n    </activity>\n    -->\n  </application>\n\n</manifest>\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/DigitalInkMainActivity.java",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition;\n\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.Spinner;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\nimport com.google.android.gms.tasks.Task;\nimport com.google.common.collect.ImmutableMap;\nimport com.google.common.collect.ImmutableSortedSet;\nimport com.google.mlkit.samples.vision.digitalink.recognition.StrokeManager.DownloadedModelsChangedListener;\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognitionModelIdentifier;\nimport java.util.Locale;\nimport java.util.Set;\n\n/** Main activity which creates a StrokeManager and connects it to the DrawingView. */\npublic class DigitalInkMainActivity extends AppCompatActivity\n    implements DownloadedModelsChangedListener {\n  private static final String TAG = \"MLKDI.Activity\";\n  private static final String GESTURE_EXTENSION = \"-x-gesture\";\n  private static final ImmutableMap<String, String> NON_TEXT_MODELS =\n      ImmutableMap.of(\n          \"zxx-Zsym-x-autodraw\",\n          \"Autodraw\",\n          \"zxx-Zsye-x-emoji\",\n          \"Emoji\",\n          \"zxx-Zsym-x-shapes\",\n          \"Shapes\");\n  @VisibleForTesting final StrokeManager strokeManager = new StrokeManager();\n  private ArrayAdapter<ModelLanguageContainer> languageAdapter;\n\n  @Override\n  public void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_digital_ink_main);\n\n    Spinner languageSpinner = findViewById(R.id.languages_spinner);\n\n    DrawingView drawingView = findViewById(R.id.drawing_view);\n    StatusTextView statusTextView = findViewById(R.id.status_text_view);\n    drawingView.setStrokeManager(strokeManager);\n    statusTextView.setStrokeManager(strokeManager);\n\n    strokeManager.setStatusChangedListener(statusTextView);\n    strokeManager.setContentChangedListener(drawingView);\n    strokeManager.setDownloadedModelsChangedListener(this);\n    strokeManager.setClearCurrentInkAfterRecognition(true);\n    strokeManager.setTriggerRecognitionAfterInput(false);\n\n    languageAdapter = populateLanguageAdapter();\n    languageAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    languageSpinner.setAdapter(languageAdapter);\n    strokeManager.refreshDownloadedModelsStatus();\n\n    languageSpinner.setOnItemSelectedListener(\n        new OnItemSelectedListener() {\n          @Override\n          public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n            String languageCode =\n                ((ModelLanguageContainer) parent.getAdapter().getItem(position)).getLanguageTag();\n            if (languageCode == null) {\n              return;\n            }\n            Log.i(TAG, \"Selected language: \" + languageCode);\n            strokeManager.setActiveModel(languageCode);\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> parent) {\n            Log.i(TAG, \"No language selected\");\n          }\n        });\n\n    strokeManager.reset();\n  }\n\n  public void downloadClick(View v) {\n    Task<Void> unused = strokeManager.download();\n  }\n\n  public void recognizeClick(View v) {\n    Task<String> unused = strokeManager.recognize();\n  }\n\n  public void clearClick(View v) {\n    strokeManager.reset();\n    DrawingView drawingView = findViewById(R.id.drawing_view);\n    drawingView.clear();\n  }\n\n  public void deleteClick(View v) {\n    Task<Void> unused = strokeManager.deleteActiveModel();\n  }\n\n    private static class ModelLanguageContainer implements Comparable<ModelLanguageContainer> {\n    private final String label;\n    @Nullable private final String languageTag;\n    private boolean downloaded;\n\n    private ModelLanguageContainer(String label, @Nullable String languageTag) {\n      this.label = label;\n      this.languageTag = languageTag;\n    }\n\n    /**\n     * Populates and returns a real model identifier, with label, language tag and downloaded\n     * status.\n     */\n    public static ModelLanguageContainer createModelContainer(String label, String languageTag) {\n      // Offset the actual language labels for better readability\n      return new ModelLanguageContainer(label, languageTag);\n    }\n\n    /** Populates and returns a label only, without a language tag. */\n    public static ModelLanguageContainer createLabelOnly(String label) {\n      return new ModelLanguageContainer(label, null);\n    }\n\n    public String getLanguageTag() {\n      return languageTag;\n    }\n\n    public void setDownloaded(boolean downloaded) {\n      this.downloaded = downloaded;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n      if (languageTag == null) {\n        return label;\n      } else if (downloaded) {\n        return \"   [D] \" + label;\n      } else {\n        return \"   \" + label;\n      }\n    }\n\n    @Override\n    public int compareTo(ModelLanguageContainer o) {\n      return label.compareTo(o.label);\n    }\n  }\n\n  @Override\n  public void onDownloadedModelsChanged(Set<String> downloadedLanguageTags) {\n    for (int i = 0; i < languageAdapter.getCount(); i++) {\n      ModelLanguageContainer container = languageAdapter.getItem(i);\n      container.setDownloaded(downloadedLanguageTags.contains(container.languageTag));\n    }\n    languageAdapter.notifyDataSetChanged();\n  }\n\n  private ArrayAdapter<ModelLanguageContainer> populateLanguageAdapter() {\n    ArrayAdapter<ModelLanguageContainer> languageAdapter =\n        new ArrayAdapter<>(this, android.R.layout.simple_spinner_item);\n    languageAdapter.add(ModelLanguageContainer.createLabelOnly(\"Select language\"));\n    languageAdapter.add(ModelLanguageContainer.createLabelOnly(\"Non-text Models\"));\n\n    // Manually add non-text models first\n    for (String languageTag : NON_TEXT_MODELS.keySet()) {\n      languageAdapter.add(\n          ModelLanguageContainer.createModelContainer(\n              NON_TEXT_MODELS.get(languageTag), languageTag));\n    }\n    languageAdapter.add(ModelLanguageContainer.createLabelOnly(\"Text Models\"));\n\n    ImmutableSortedSet.Builder<ModelLanguageContainer> textModels =\n        ImmutableSortedSet.naturalOrder();\n    for (DigitalInkRecognitionModelIdentifier modelIdentifier :\n        DigitalInkRecognitionModelIdentifier.allModelIdentifiers()) {\n      if (NON_TEXT_MODELS.containsKey(modelIdentifier.getLanguageTag())) {\n        continue;\n      }\n      if (modelIdentifier.getLanguageTag().endsWith(GESTURE_EXTENSION)) {\n        continue;\n      }\n\n      textModels.add(buildModelContainer(modelIdentifier, \"Script\"));\n    }\n    languageAdapter.addAll(textModels.build());\n\n    languageAdapter.add(ModelLanguageContainer.createLabelOnly(\"Gesture Models\"));\n\n    ImmutableSortedSet.Builder<ModelLanguageContainer> gestureModels =\n        ImmutableSortedSet.naturalOrder();\n    for (DigitalInkRecognitionModelIdentifier modelIdentifier :\n        DigitalInkRecognitionModelIdentifier.allModelIdentifiers()) {\n      if (!modelIdentifier.getLanguageTag().endsWith(GESTURE_EXTENSION)) {\n        continue;\n      }\n\n      gestureModels.add(buildModelContainer(modelIdentifier, \"Script gesture classifier\"));\n    }\n    languageAdapter.addAll(gestureModels.build());\n    return languageAdapter;\n  }\n\n  private static ModelLanguageContainer buildModelContainer(\n      DigitalInkRecognitionModelIdentifier modelIdentifier, String labelSuffix) {\n    StringBuilder label = new StringBuilder();\n    label.append(new Locale(modelIdentifier.getLanguageSubtag()).getDisplayName());\n    if (modelIdentifier.getRegionSubtag() != null) {\n      label.append(\" (\").append(modelIdentifier.getRegionSubtag()).append(\")\");\n    }\n\n    if (modelIdentifier.getScriptSubtag() != null) {\n      label.append(\", \").append(modelIdentifier.getScriptSubtag()).append(\" \").append(labelSuffix);\n    }\n    return ModelLanguageContainer.createModelContainer(\n        label.toString(), modelIdentifier.getLanguageTag());\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/DrawingView.java",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.graphics.Rect;\nimport android.text.TextPaint;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.util.TypedValue;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport com.google.mlkit.samples.vision.digitalink.recognition.StrokeManager.ContentChangedListener;\nimport com.google.mlkit.vision.digitalink.common.Point;\nimport com.google.mlkit.vision.digitalink.common.Stroke;\nimport com.google.mlkit.vision.digitalink.recognition.Ink;\nimport java.util.List;\n\n/**\n * Main view for rendering content.\n *\n * <p>The view accepts touch inputs, renders them on screen, and passes the content to the\n * StrokeManager. The view is also able to draw content from the StrokeManager.\n */\npublic class DrawingView extends View implements ContentChangedListener {\n  private static final String TAG = \"MLKD.DrawingView\";\n  private static final int STROKE_WIDTH_DP = 3;\n  private static final int MIN_BB_WIDTH = 10;\n  private static final int MIN_BB_HEIGHT = 10;\n  private static final int MAX_BB_WIDTH = 256;\n  private static final int MAX_BB_HEIGHT = 256;\n\n  private final Paint recognizedStrokePaint;\n  private final TextPaint textPaint;\n  private final Paint currentStrokePaint;\n  private final Paint canvasPaint;\n\n  private final Path currentStroke;\n  private Canvas drawCanvas;\n  private Bitmap canvasBitmap;\n  private StrokeManager strokeManager;\n\n  public DrawingView(Context context) {\n    this(context, null);\n  }\n\n  public DrawingView(Context context, AttributeSet attributeSet) {\n    super(context, attributeSet);\n    currentStrokePaint = new Paint();\n    currentStrokePaint.setColor(0xFFFF00FF); // pink.\n    currentStrokePaint.setAntiAlias(true);\n    // Set stroke width based on display density.\n    currentStrokePaint.setStrokeWidth(\n        TypedValue.applyDimension(\n            TypedValue.COMPLEX_UNIT_DIP, STROKE_WIDTH_DP, getResources().getDisplayMetrics()));\n    currentStrokePaint.setStyle(Paint.Style.STROKE);\n    currentStrokePaint.setStrokeJoin(Paint.Join.ROUND);\n    currentStrokePaint.setStrokeCap(Paint.Cap.ROUND);\n\n    recognizedStrokePaint = new Paint(currentStrokePaint);\n    recognizedStrokePaint.setColor(0xFFFFCCFF); // pale pink.\n\n    textPaint = new TextPaint();\n    textPaint.setColor(0xFF33CC33); // green.\n\n    currentStroke = new Path();\n    canvasPaint = new Paint(Paint.DITHER_FLAG);\n  }\n\n  private static Rect computeBoundingBox(Ink ink) {\n    float top = Float.MAX_VALUE;\n    float left = Float.MAX_VALUE;\n    float bottom = Float.MIN_VALUE;\n    float right = Float.MIN_VALUE;\n    for (Stroke s : ink.getStrokes()) {\n      for (Point p : s.getPointsInGlobalCoordinates()) {\n        top = Math.min(top, p.getY());\n        left = Math.min(left, p.getX());\n        bottom = Math.max(bottom, p.getY());\n        right = Math.max(right, p.getX());\n      }\n    }\n    float centerX = (left + right) / 2;\n    float centerY = (top + bottom) / 2;\n    Rect bb = new Rect((int) left, (int) top, (int) right, (int) bottom);\n    // Enforce a minimum size of the bounding box such that recognitions for small inks are readable\n    bb.union(\n        (int) (centerX - MIN_BB_WIDTH / 2),\n        (int) (centerY - MIN_BB_HEIGHT / 2),\n        (int) (centerX + MIN_BB_WIDTH / 2),\n        (int) (centerY + MIN_BB_HEIGHT / 2));\n    // Enforce a maximum size of the bounding box, to ensure Emoji characters get displayed\n    // correctly\n    if (bb.width() > MAX_BB_WIDTH) {\n      bb.set(bb.centerX() - MAX_BB_WIDTH / 2, bb.top, bb.centerX() + MAX_BB_WIDTH / 2, bb.bottom);\n    }\n    if (bb.height() > MAX_BB_HEIGHT) {\n      bb.set(bb.left, bb.centerY() - MAX_BB_HEIGHT / 2, bb.right, bb.centerY() + MAX_BB_HEIGHT / 2);\n    }\n    return bb;\n  }\n\n  void setStrokeManager(StrokeManager strokeManager) {\n    this.strokeManager = strokeManager;\n  }\n\n  @Override\n  protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {\n    Log.i(TAG, \"onSizeChanged\");\n    canvasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n    drawCanvas = new Canvas(canvasBitmap);\n    invalidate();\n  }\n\n  public void redrawContent() {\n    clear();\n    Ink currentInk = strokeManager.getCurrentInk();\n    drawInk(currentInk, currentStrokePaint);\n\n    List<RecognitionTask.RecognizedInk> content = strokeManager.getContent();\n    for (RecognitionTask.RecognizedInk ri : content) {\n      drawInk(ri.ink, recognizedStrokePaint);\n      final Rect bb = computeBoundingBox(ri.ink);\n      drawTextIntoBoundingBox(ri.text, bb, textPaint);\n    }\n    invalidate();\n  }\n\n  private void drawTextIntoBoundingBox(String text, Rect bb, TextPaint textPaint) {\n    final float arbitraryFixedSize = 20.f;\n    // Set an arbitrary text size to learn how high the text will be.\n    textPaint.setTextSize(arbitraryFixedSize);\n    textPaint.setTextScaleX(1.f);\n\n    // Now determine the size of the rendered text with these settings.\n    Rect r = new Rect();\n    textPaint.getTextBounds(text, 0, text.length(), r);\n\n    // Adjust height such that target height is met.\n    float textSize = arbitraryFixedSize * (float) bb.height() / (float) r.height();\n    textPaint.setTextSize(textSize);\n\n    // Redetermine the size of the rendered text with the new settings.\n    textPaint.getTextBounds(text, 0, text.length(), r);\n\n    // Adjust scaleX to squeeze the text.\n    textPaint.setTextScaleX((float) bb.width() / (float) r.width());\n\n    // And finally draw the text.\n    drawCanvas.drawText(text, bb.left, bb.bottom, textPaint);\n  }\n\n  private void drawInk(Ink ink, Paint paint) {\n    for (Stroke s : ink.getStrokes()) {\n      drawStroke(s, paint);\n    }\n  }\n\n  private void drawStroke(Stroke s, Paint paint) {\n    Log.i(TAG, \"drawstroke\");\n    Path path = null;\n    for (Point p : s.getPointsInGlobalCoordinates()) {\n      if (path == null) {\n        path = new Path();\n        path.moveTo(p.getX(), p.getY());\n      } else {\n        path.lineTo(p.getX(), p.getY());\n      }\n    }\n    drawCanvas.drawPath(path, paint);\n  }\n\n  public void clear() {\n    currentStroke.reset();\n    onSizeChanged(\n        canvasBitmap.getWidth(),\n        canvasBitmap.getHeight(),\n        canvasBitmap.getWidth(),\n        canvasBitmap.getHeight());\n  }\n\n  @Override\n  protected void onDraw(Canvas canvas) {\n    canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);\n    canvas.drawPath(currentStroke, currentStrokePaint);\n  }\n\n  @Override\n  public boolean onTouchEvent(MotionEvent event) {\n    int action = event.getActionMasked();\n    float x = event.getX();\n    float y = event.getY();\n\n    switch (action) {\n      case MotionEvent.ACTION_DOWN:\n        currentStroke.moveTo(x, y);\n        break;\n      case MotionEvent.ACTION_MOVE:\n        currentStroke.lineTo(x, y);\n        break;\n      case MotionEvent.ACTION_UP:\n        currentStroke.lineTo(x, y);\n        drawCanvas.drawPath(currentStroke, currentStrokePaint);\n        currentStroke.reset();\n        break;\n      default:\n        break;\n    }\n    boolean unused = strokeManager.addNewTouchEvent(event);\n    invalidate();\n    return true;\n  }\n\n  @Override\n  public void onContentChanged() {\n    redrawContent();\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/ModelManager.java",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition;\n\nimport android.util.Log;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport com.google.mlkit.common.MlKitException;\nimport com.google.mlkit.common.model.DownloadConditions;\nimport com.google.mlkit.common.model.RemoteModelManager;\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognition;\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognitionModel;\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognitionModelIdentifier;\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognizer;\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognizerOptions;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/** Class to manage model downloading, deletion, and selection. */\npublic class ModelManager {\n\n  private static final String TAG = \"MLKD.ModelManager\";\n  private DigitalInkRecognitionModel model;\n  private DigitalInkRecognizer recognizer;\n  final RemoteModelManager remoteModelManager = RemoteModelManager.getInstance();\n\n  public String setModel(String languageTag) {\n    // Clear the old model and recognizer.\n    model = null;\n    if (recognizer != null) {\n      recognizer.close();\n    }\n    recognizer = null;\n\n    // Try to parse the languageTag and get a model from it.\n    DigitalInkRecognitionModelIdentifier modelIdentifier;\n    try {\n      modelIdentifier = DigitalInkRecognitionModelIdentifier.fromLanguageTag(languageTag);\n    } catch (MlKitException e) {\n      Log.e(TAG, \"Failed to parse language '\" + languageTag + \"'\");\n      return \"\";\n    }\n    if (modelIdentifier == null) {\n      return \"No model for language: \" + languageTag;\n    }\n\n    // Initialize the model and recognizer.\n    model = DigitalInkRecognitionModel.builder(modelIdentifier).build();\n    recognizer =\n        DigitalInkRecognition.getClient(DigitalInkRecognizerOptions.builder(model).build());\n    Log.i(\n        TAG,\n        \"Model set for language '\"\n            + languageTag\n            + \"' ('\"\n            + modelIdentifier.getLanguageTag()\n            + \"').\");\n    return \"Model set for language: \" + languageTag;\n  }\n\n  public DigitalInkRecognizer getRecognizer() {\n    return recognizer;\n  }\n\n  public Task<Boolean> checkIsModelDownloaded() {\n    return remoteModelManager.isModelDownloaded(model);\n  }\n\n  public Task<String> deleteActiveModel() {\n    if (model == null) {\n      Log.i(TAG, \"Model not set\");\n      return Tasks.forResult(\"Model not set\");\n    }\n    return checkIsModelDownloaded()\n        .onSuccessTask(\n            result -> {\n              if (!result) {\n                return Tasks.forResult(\"Model not downloaded yet\");\n              }\n              return remoteModelManager\n                  .deleteDownloadedModel(model)\n                  .onSuccessTask(\n                      aVoid -> {\n                        Log.i(TAG, \"Model successfully deleted\");\n                        return Tasks.forResult(\"Model successfully deleted\");\n                      });\n            })\n        .addOnFailureListener(e -> Log.e(TAG, \"Error while model deletion: \" + e));\n  }\n\n  public Task<Set<String>> getDownloadedModelLanguages() {\n    return remoteModelManager\n        .getDownloadedModels(DigitalInkRecognitionModel.class)\n        .onSuccessTask(\n            (remoteModels) -> {\n              Set<String> result = new HashSet<>();\n              for (DigitalInkRecognitionModel model : remoteModels) {\n                result.add(model.getModelIdentifier().getLanguageTag());\n              }\n              Log.i(TAG, \"Downloaded models for languages:\" + result);\n              return Tasks.forResult(result);\n            });\n  }\n\n  public Task<String> download() {\n    if (model == null) {\n      return Tasks.forResult(\"Model not selected.\");\n    }\n    return remoteModelManager\n        .download(model, new DownloadConditions.Builder().build())\n        .onSuccessTask(\n            aVoid -> {\n              Log.i(TAG, \"Model download succeeded.\");\n              return Tasks.forResult(\"Downloaded model successfully\");\n            })\n        .addOnFailureListener(e -> Log.e(TAG, \"Error while downloading the model: \" + e));\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/RecognitionTask.java",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition;\n\nimport android.util.Log;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognizer;\nimport com.google.mlkit.vision.digitalink.recognition.Ink;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/** Task to run asynchronously to obtain recognition results. */\npublic class RecognitionTask {\n\n  private static final String TAG = \"MLKD.RecognitionTask\";\n  private final DigitalInkRecognizer recognizer;\n  private final Ink ink;\n  @Nullable private RecognizedInk currentResult;\n  private final AtomicBoolean cancelled;\n  private final AtomicBoolean done;\n\n  public RecognitionTask(DigitalInkRecognizer recognizer, Ink ink) {\n    this.recognizer = recognizer;\n    this.ink = ink;\n    this.currentResult = null;\n    cancelled = new AtomicBoolean(false);\n    done = new AtomicBoolean(false);\n  }\n\n  public void cancel() {\n    cancelled.set(true);\n  }\n\n  public boolean done() {\n    return done.get();\n  }\n\n  @Nullable\n  public RecognizedInk result() {\n    return this.currentResult;\n  }\n\n  /** Helper class that stores an ink along with the corresponding recognized text. */\n  public static class RecognizedInk {\n    public final Ink ink;\n    public final String text;\n\n    RecognizedInk(Ink ink, String text) {\n      this.ink = ink;\n      this.text = text;\n    }\n  }\n\n  public Task<String> run() {\n    Log.i(TAG, \"RecoTask.run\");\n    return recognizer\n        .recognize(this.ink)\n        .onSuccessTask(\n            result -> {\n              if (cancelled.get() || result.getCandidates().isEmpty()) {\n                return Tasks.forResult(null);\n              }\n              currentResult = new RecognizedInk(ink, result.getCandidates().get(0).getText());\n              Log.i(TAG, \"result: \" + currentResult.text);\n              done.set(true);\n              return Tasks.forResult(currentResult.text);\n            });\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/StatusTextView.java",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition;\n\nimport android.content.Context;\nimport androidx.appcompat.widget.AppCompatTextView;\nimport android.util.AttributeSet;\nimport androidx.annotation.NonNull;\nimport com.google.mlkit.samples.vision.digitalink.recognition.StrokeManager.StatusChangedListener;\n\n/**\n * Status bar for the test app.\n *\n * <p>It is updated upon status changes announced by the StrokeManager.\n */\npublic class StatusTextView extends AppCompatTextView implements StatusChangedListener {\n\n  private StrokeManager strokeManager;\n\n  public StatusTextView(@NonNull Context context) {\n    super(context);\n  }\n\n  public StatusTextView(Context context, AttributeSet attributeSet) {\n    super(context, attributeSet);\n  }\n\n  @Override\n  public void onStatusChanged() {\n    this.setText(this.strokeManager.getStatus());\n  }\n\n  void setStrokeManager(StrokeManager strokeManager) {\n    this.strokeManager = strokeManager;\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/StrokeManager.java",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition;\n\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.MotionEvent;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport com.google.mlkit.vision.digitalink.recognition.Ink;\nimport com.google.mlkit.vision.digitalink.recognition.Ink.Point;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/** Manages the recognition logic and the content that has been added to the current page. */\npublic class StrokeManager {\n\n  /** Interface to register to be notified of changes in the recognized content. */\n  public interface ContentChangedListener {\n\n    /** This method is called when the recognized content changes. */\n    void onContentChanged();\n  }\n\n  /** Interface to register to be notified of changes in the status. */\n  public interface StatusChangedListener {\n\n    /** This method is called when the recognized content changes. */\n    void onStatusChanged();\n  }\n\n  /** Interface to register to be notified of changes in the downloaded model state. */\n  public interface DownloadedModelsChangedListener {\n\n    /** This method is called when the downloaded models changes. */\n    void onDownloadedModelsChanged(Set<String> downloadedLanguageTags);\n  }\n\n  @VisibleForTesting static final long CONVERSION_TIMEOUT_MS = 1000;\n  private static final String TAG = \"MLKD.StrokeManager\";\n  // This is a constant that is used as a message identifier to trigger the timeout.\n  private static final int TIMEOUT_TRIGGER = 1;\n  // For handling recognition and model downloading.\n  private RecognitionTask recognitionTask = null;\n  @VisibleForTesting ModelManager modelManager = new ModelManager();\n  // Managing the recognition queue.\n  private final List<RecognitionTask.RecognizedInk> content = new ArrayList<>();\n  // Managing ink currently drawn.\n  private Ink.Stroke.Builder strokeBuilder = Ink.Stroke.builder();\n  private Ink.Builder inkBuilder = Ink.builder();\n  private boolean stateChangedSinceLastRequest = false;\n  @Nullable private ContentChangedListener contentChangedListener = null;\n  @Nullable private StatusChangedListener statusChangedListener = null;\n  @Nullable private DownloadedModelsChangedListener downloadedModelsChangedListener = null;\n\n  private boolean triggerRecognitionAfterInput = true;\n  private boolean clearCurrentInkAfterRecognition = true;\n  private String status = \"\";\n\n  public void setTriggerRecognitionAfterInput(boolean shouldTrigger) {\n    triggerRecognitionAfterInput = shouldTrigger;\n  }\n\n  public void setClearCurrentInkAfterRecognition(boolean shouldClear) {\n    clearCurrentInkAfterRecognition = shouldClear;\n  }\n\n  // Handler to handle the UI Timeout.\n  // This handler is only used to trigger the UI timeout. Each time a UI interaction happens,\n  // the timer is reset by clearing the queue on this handler and sending a new delayed message (in\n  // addNewTouchEvent).\n  private final Handler uiHandler =\n      new Handler(\n          msg -> {\n            if (msg.what == TIMEOUT_TRIGGER) {\n              Log.i(TAG, \"Handling timeout trigger.\");\n              commitResult();\n              return true;\n            }\n            // In the current use this statement is never reached because we only ever send\n            // TIMEOUT_TRIGGER messages to this handler.\n            // This line is necessary because otherwise Java's static analysis doesn't allow for\n            // compiling. Returning false indicates that a message wasn't handled.\n            return false;\n          });\n\n  private void setStatus(String newStatus) {\n    status = newStatus;\n    if (statusChangedListener != null) {\n      statusChangedListener.onStatusChanged();\n    }\n  }\n\n  private void commitResult() {\n    if (recognitionTask.done() && recognitionTask.result() != null) {\n      content.add(recognitionTask.result());\n      setStatus(\"Successful recognition: \" + recognitionTask.result().text);\n      if (clearCurrentInkAfterRecognition) {\n        resetCurrentInk();\n      }\n      if (contentChangedListener != null) {\n        contentChangedListener.onContentChanged();\n      }\n    }\n  }\n\n  public void reset() {\n    Log.i(TAG, \"reset\");\n    resetCurrentInk();\n    content.clear();\n    if (recognitionTask != null && !recognitionTask.done()) {\n      recognitionTask.cancel();\n    }\n    setStatus(\"\");\n  }\n\n  private void resetCurrentInk() {\n    inkBuilder = Ink.builder();\n    strokeBuilder = Ink.Stroke.builder();\n    stateChangedSinceLastRequest = false;\n  }\n\n  public Ink getCurrentInk() {\n    return inkBuilder.build();\n  }\n\n  /**\n   * This method is called when a new touch event happens on the drawing client and notifies the\n   * StrokeManager of new content being added.\n   *\n   * <p>This method takes care of triggering the UI timeout and scheduling recognitions on the\n   * background thread.\n   *\n   * @return whether the touch event was handled.\n   */\n  public boolean addNewTouchEvent(MotionEvent event) {\n    int action = event.getActionMasked();\n    float x = event.getX();\n    float y = event.getY();\n    long t = System.currentTimeMillis();\n\n    // A new event happened -> clear all pending timeout messages.\n    uiHandler.removeMessages(TIMEOUT_TRIGGER);\n\n    switch (action) {\n      case MotionEvent.ACTION_DOWN:\n      case MotionEvent.ACTION_MOVE:\n        strokeBuilder.addPoint(Point.create(x, y, t));\n        break;\n      case MotionEvent.ACTION_UP:\n        strokeBuilder.addPoint(Point.create(x, y, t));\n        inkBuilder.addStroke(strokeBuilder.build());\n        strokeBuilder = Ink.Stroke.builder();\n        stateChangedSinceLastRequest = true;\n        if (triggerRecognitionAfterInput) {\n          Task<String> unused = recognize();\n        }\n        break;\n      default:\n        // Indicate touch event wasn't handled.\n        return false;\n    }\n\n    return true;\n  }\n\n  // Listeners to update the drawing and status.\n  public void setContentChangedListener(ContentChangedListener contentChangedListener) {\n    this.contentChangedListener = contentChangedListener;\n  }\n\n  public void setStatusChangedListener(StatusChangedListener statusChangedListener) {\n    this.statusChangedListener = statusChangedListener;\n  }\n\n  public void setDownloadedModelsChangedListener(\n      DownloadedModelsChangedListener downloadedModelsChangedListener) {\n    this.downloadedModelsChangedListener = downloadedModelsChangedListener;\n  }\n\n  public List<RecognitionTask.RecognizedInk> getContent() {\n    return content;\n  }\n\n  public String getStatus() {\n    return status;\n  }\n\n  // Model downloading / deleting / setting.\n\n  public void setActiveModel(String languageTag) {\n    setStatus(modelManager.setModel(languageTag));\n  }\n\n  public Task<Void> deleteActiveModel() {\n    return modelManager\n        .deleteActiveModel()\n        .addOnSuccessListener(unused -> refreshDownloadedModelsStatus())\n        .onSuccessTask(\n            status -> {\n              setStatus(status);\n              return Tasks.forResult(null);\n            });\n  }\n\n  public Task<Void> download() {\n    setStatus(\"Download started.\");\n    return modelManager\n        .download()\n        .addOnSuccessListener(unused -> refreshDownloadedModelsStatus())\n        .onSuccessTask(\n            status -> {\n              setStatus(status);\n              return Tasks.forResult(null);\n            });\n  }\n\n  // Recognition-related.\n\n  public Task<String> recognize() {\n\n    if (!stateChangedSinceLastRequest || inkBuilder.isEmpty()) {\n      setStatus(\"No recognition, ink unchanged or empty\");\n      return Tasks.forResult(null);\n    }\n    if (modelManager.getRecognizer() == null) {\n      setStatus(\"Recognizer not set\");\n      return Tasks.forResult(null);\n    }\n\n    return modelManager\n        .checkIsModelDownloaded()\n        .onSuccessTask(\n            result -> {\n              if (!result) {\n                setStatus(\"Model not downloaded yet\");\n                return Tasks.forResult(null);\n              }\n\n              stateChangedSinceLastRequest = false;\n              recognitionTask =\n                  new RecognitionTask(modelManager.getRecognizer(), inkBuilder.build());\n              uiHandler.sendMessageDelayed(\n                  uiHandler.obtainMessage(TIMEOUT_TRIGGER), CONVERSION_TIMEOUT_MS);\n              return recognitionTask.run();\n            });\n  }\n\n  public void refreshDownloadedModelsStatus() {\n    modelManager\n        .getDownloadedModelLanguages()\n        .addOnSuccessListener(\n            downloadedLanguageTags -> {\n              if (downloadedModelsChangedListener != null) {\n                downloadedModelsChangedListener.onDownloadedModelsChanged(downloadedLanguageTags);\n              }\n            });\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/kotlin/DigitalInkMainActivity.kt",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition.kotlin\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.view.View\nimport android.widget.AdapterView\nimport android.widget.AdapterView.OnItemSelectedListener\nimport android.widget.ArrayAdapter\nimport android.widget.Spinner\nimport androidx.annotation.VisibleForTesting\nimport com.google.common.collect.ImmutableMap\nimport com.google.common.collect.ImmutableSortedSet\nimport com.google.mlkit.samples.vision.digitalink.recognition.R\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognitionModelIdentifier\nimport java.util.Locale\n\n/** Main activity which creates a StrokeManager and connects it to the DrawingView. */\nclass DigitalInkMainActivity : AppCompatActivity(), StrokeManager.DownloadedModelsChangedListener {\n  @JvmField @VisibleForTesting val strokeManager = StrokeManager()\n  private lateinit var languageAdapter: ArrayAdapter<ModelLanguageContainer>\n\n  public override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_digital_ink_main_kotlin)\n    val languageSpinner = findViewById<Spinner>(R.id.languages_spinner)\n    val drawingView = findViewById<DrawingView>(R.id.drawing_view)\n    val statusTextView = findViewById<StatusTextView>(R.id.status_text_view)\n    drawingView.setStrokeManager(strokeManager)\n    statusTextView.setStrokeManager(strokeManager)\n    strokeManager.setStatusChangedListener(statusTextView)\n    strokeManager.setContentChangedListener(drawingView)\n    strokeManager.setDownloadedModelsChangedListener(this)\n    strokeManager.setClearCurrentInkAfterRecognition(true)\n    strokeManager.setTriggerRecognitionAfterInput(false)\n    languageAdapter = populateLanguageAdapter()\n    languageAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n    languageSpinner.adapter = languageAdapter\n    strokeManager.refreshDownloadedModelsStatus()\n\n    languageSpinner.onItemSelectedListener =\n      object : OnItemSelectedListener {\n        override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {\n          val languageCode =\n            (parent.adapter.getItem(position) as ModelLanguageContainer).languageTag ?: return\n          Log.i(TAG, \"Selected language: $languageCode\")\n          strokeManager.setActiveModel(languageCode)\n        }\n\n        override fun onNothingSelected(parent: AdapterView<*>?) {\n          Log.i(TAG, \"No language selected\")\n        }\n      }\n    strokeManager.reset()\n  }\n\n  fun downloadClick(v: View?) {\n    val unused = strokeManager.download()\n  }\n\n  fun recognizeClick(v: View?) {\n    val unused = strokeManager.recognize()\n  }\n\n  fun clearClick(v: View?) {\n    strokeManager.reset()\n    val drawingView = findViewById<DrawingView>(R.id.drawing_view)\n    drawingView.clear()\n  }\n\n  fun deleteClick(v: View?) {\n    val unused = strokeManager.deleteActiveModel()\n  }\n\n  private class ModelLanguageContainer\n  private constructor(private val label: String, val languageTag: String?) :\n    Comparable<ModelLanguageContainer> {\n\n    var downloaded: Boolean = false\n\n    override fun toString(): String {\n      return when {\n        languageTag == null -> label\n        downloaded -> \"   [D] $label\"\n        else -> \"   $label\"\n      }\n    }\n\n    override fun compareTo(other: ModelLanguageContainer): Int {\n      return label.compareTo(other.label)\n    }\n\n    companion object {\n      /** Populates and returns a real model identifier, with label and language tag. */\n      fun createModelContainer(label: String, languageTag: String?): ModelLanguageContainer {\n        // Offset the actual language labels for better readability\n        return ModelLanguageContainer(label, languageTag)\n      }\n\n      /** Populates and returns a label only, without a language tag. */\n      fun createLabelOnly(label: String): ModelLanguageContainer {\n        return ModelLanguageContainer(label, null)\n      }\n    }\n  }\n\n  private fun populateLanguageAdapter(): ArrayAdapter<ModelLanguageContainer> {\n    val languageAdapter =\n      ArrayAdapter<ModelLanguageContainer>(this, android.R.layout.simple_spinner_item)\n    languageAdapter.add(ModelLanguageContainer.createLabelOnly(\"Select language\"))\n    languageAdapter.add(ModelLanguageContainer.createLabelOnly(\"Non-text Models\"))\n\n    // Manually add non-text models first\n    for (languageTag in NON_TEXT_MODELS.keys) {\n      languageAdapter.add(\n        ModelLanguageContainer.createModelContainer(NON_TEXT_MODELS[languageTag]!!, languageTag)\n      )\n    }\n    languageAdapter.add(ModelLanguageContainer.createLabelOnly(\"Text Models\"))\n    val textModels = ImmutableSortedSet.naturalOrder<ModelLanguageContainer>()\n    for (modelIdentifier in DigitalInkRecognitionModelIdentifier.allModelIdentifiers()) {\n      if (NON_TEXT_MODELS.containsKey(modelIdentifier.languageTag)) {\n        continue\n      }\n      if (modelIdentifier.languageTag.endsWith(Companion.GESTURE_EXTENSION)) {\n        continue\n      }\n      textModels.add(buildModelContainer(modelIdentifier, \"Script\"))\n    }\n    languageAdapter.addAll(textModels.build())\n    languageAdapter.add(ModelLanguageContainer.createLabelOnly(\"Gesture Models\"))\n    val gestureModels = ImmutableSortedSet.naturalOrder<ModelLanguageContainer>()\n    for (modelIdentifier in DigitalInkRecognitionModelIdentifier.allModelIdentifiers()) {\n      if (!modelIdentifier.languageTag.endsWith(Companion.GESTURE_EXTENSION)) {\n        continue\n      }\n      gestureModels.add(buildModelContainer(modelIdentifier, \"Script gesture classifier\"))\n    }\n    languageAdapter.addAll(gestureModels.build())\n    return languageAdapter\n  }\n\n  private fun buildModelContainer(\n    modelIdentifier: DigitalInkRecognitionModelIdentifier,\n    labelSuffix: String\n  ): ModelLanguageContainer {\n    val label = StringBuilder()\n    label.append(Locale(modelIdentifier.languageSubtag).displayName)\n    if (modelIdentifier.regionSubtag != null) {\n      label.append(\" (\").append(modelIdentifier.regionSubtag).append(\")\")\n    }\n    if (modelIdentifier.scriptSubtag != null) {\n      label.append(\", \").append(modelIdentifier.scriptSubtag).append(\" \").append(labelSuffix)\n    }\n    return ModelLanguageContainer.createModelContainer(\n      label.toString(),\n      modelIdentifier.languageTag\n    )\n  }\n\n  override fun onDownloadedModelsChanged(downloadedLanguageTags: Set<String>) {\n    for (i in 0 until languageAdapter.count) {\n      val container = languageAdapter.getItem(i)!!\n      container.downloaded = downloadedLanguageTags.contains(container.languageTag)\n    }\n    languageAdapter.notifyDataSetChanged()\n  }\n\n  companion object {\n    private const val TAG = \"MLKDI.Activity\"\n    private val NON_TEXT_MODELS =\n      ImmutableMap.of(\n        \"zxx-Zsym-x-autodraw\",\n        \"Autodraw\",\n        \"zxx-Zsye-x-emoji\",\n        \"Emoji\",\n        \"zxx-Zsym-x-shapes\",\n        \"Shapes\"\n      )\n    private const val GESTURE_EXTENSION = \"-x-gesture\"\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/kotlin/DrawingView.kt",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition.kotlin\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.Paint\nimport android.graphics.Path\nimport android.graphics.Rect\nimport android.text.TextPaint\nimport android.util.AttributeSet\nimport android.util.Log\nimport android.util.TypedValue\nimport android.view.MotionEvent\nimport android.view.View\nimport com.google.mlkit.samples.vision.digitalink.recognition.kotlin.StrokeManager.ContentChangedListener\nimport com.google.mlkit.vision.digitalink.common.Stroke\nimport com.google.mlkit.vision.digitalink.recognition.Ink\n\n/**\n * Main view for rendering content.\n *\n * The view accepts touch inputs, renders them on screen, and passes the content to the\n * StrokeManager. The view is also able to draw content from the StrokeManager.\n */\nclass DrawingView @JvmOverloads constructor(context: Context?, attributeSet: AttributeSet? = null) :\n  View(context, attributeSet), ContentChangedListener {\n  private val recognizedStrokePaint: Paint\n  private val textPaint: TextPaint\n  private val currentStrokePaint: Paint\n  private val canvasPaint: Paint\n  private val currentStroke: Path\n  private lateinit var drawCanvas: Canvas\n  private lateinit var canvasBitmap: Bitmap\n  private lateinit var strokeManager: StrokeManager\n  fun setStrokeManager(strokeManager: StrokeManager) {\n    this.strokeManager = strokeManager\n  }\n\n  override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {\n    Log.i(TAG, \"onSizeChanged\")\n    canvasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)\n    drawCanvas = Canvas(canvasBitmap)\n    invalidate()\n  }\n\n  fun redrawContent() {\n    clear()\n    val currentInk = strokeManager.currentInk\n    drawInk(currentInk, currentStrokePaint)\n    val content = strokeManager.getContent()\n    for (ri in content) {\n      drawInk(ri.ink, recognizedStrokePaint)\n      val bb = computeBoundingBox(ri.ink)\n      drawTextIntoBoundingBox(ri.text ?: \"\", bb, textPaint)\n    }\n    invalidate()\n  }\n\n  private fun drawTextIntoBoundingBox(text: String, bb: Rect, textPaint: TextPaint) {\n    val arbitraryFixedSize = 20f\n    // Set an arbitrary text size to learn how high the text will be.\n    textPaint.textSize = arbitraryFixedSize\n    textPaint.textScaleX = 1f\n\n    // Now determine the size of the rendered text with these settings.\n    val r = Rect()\n    textPaint.getTextBounds(text, 0, text.length, r)\n\n    // Adjust height such that target height is met.\n    val textSize = arbitraryFixedSize * bb.height().toFloat() / r.height().toFloat()\n    textPaint.textSize = textSize\n\n    // Redetermine the size of the rendered text with the new settings.\n    textPaint.getTextBounds(text, 0, text.length, r)\n\n    // Adjust scaleX to squeeze the text.\n    textPaint.textScaleX = bb.width().toFloat() / r.width().toFloat()\n\n    // And finally draw the text.\n    drawCanvas.drawText(text, bb.left.toFloat(), bb.bottom.toFloat(), textPaint)\n  }\n\n  private fun drawInk(ink: Ink, paint: Paint) {\n    for (s in ink.strokes) {\n      drawStroke(s, paint)\n    }\n  }\n\n  private fun drawStroke(s: Stroke, paint: Paint) {\n    Log.i(TAG, \"drawstroke\")\n    var path: Path = Path()\n    path.moveTo(s.pointsInGlobalCoordinates[0].x, s.pointsInGlobalCoordinates[0].y)\n    for (p in s.pointsInGlobalCoordinates.drop(1)) {\n      path.lineTo(p.x, p.y)\n    }\n    drawCanvas.drawPath(path, paint)\n  }\n\n  fun clear() {\n    currentStroke.reset()\n    onSizeChanged(canvasBitmap.width, canvasBitmap.height, canvasBitmap.width, canvasBitmap.height)\n  }\n\n  override fun onDraw(canvas: Canvas) {\n    canvas.drawBitmap(canvasBitmap, 0f, 0f, canvasPaint)\n    canvas.drawPath(currentStroke, currentStrokePaint)\n  }\n\n  override fun onTouchEvent(event: MotionEvent): Boolean {\n    val action = event.actionMasked\n    val x = event.x\n    val y = event.y\n    when (action) {\n      MotionEvent.ACTION_DOWN -> currentStroke.moveTo(x, y)\n      MotionEvent.ACTION_MOVE -> currentStroke.lineTo(x, y)\n      MotionEvent.ACTION_UP -> {\n        currentStroke.lineTo(x, y)\n        drawCanvas.drawPath(currentStroke, currentStrokePaint)\n        currentStroke.reset()\n      }\n      else -> {}\n    }\n    val unused = strokeManager.addNewTouchEvent(event)\n    invalidate()\n    return true\n  }\n\n  override fun onContentChanged() {\n    redrawContent()\n  }\n\n  companion object {\n    private const val TAG = \"MLKD.DrawingView\"\n    private const val STROKE_WIDTH_DP = 3\n    private const val MIN_BB_WIDTH = 10\n    private const val MIN_BB_HEIGHT = 10\n    private const val MAX_BB_WIDTH = 256\n    private const val MAX_BB_HEIGHT = 256\n    private fun computeBoundingBox(ink: Ink): Rect {\n      var top = Float.MAX_VALUE\n      var left = Float.MAX_VALUE\n      var bottom = Float.MIN_VALUE\n      var right = Float.MIN_VALUE\n      for (s in ink.strokes) {\n        for (p in s.pointsInGlobalCoordinates) {\n          top = Math.min(top, p.y)\n          left = Math.min(left, p.x)\n          bottom = Math.max(bottom, p.y)\n          right = Math.max(right, p.x)\n        }\n      }\n      val centerX = (left + right) / 2\n      val centerY = (top + bottom) / 2\n      val bb = Rect(left.toInt(), top.toInt(), right.toInt(), bottom.toInt())\n      // Enforce a minimum size of the bounding box such that recognitions for small inks are\n      // readable\n      bb.union(\n        (centerX - MIN_BB_WIDTH / 2).toInt(),\n        (centerY - MIN_BB_HEIGHT / 2).toInt(),\n        (centerX + MIN_BB_WIDTH / 2).toInt(),\n        (centerY + MIN_BB_HEIGHT / 2).toInt()\n      )\n      // Enforce a maximum size of the bounding box, to ensure Emoji characters get displayed\n      // correctly\n      if (bb.width() > MAX_BB_WIDTH) {\n        bb[bb.centerX() - MAX_BB_WIDTH / 2, bb.top, bb.centerX() + MAX_BB_WIDTH / 2] = bb.bottom\n      }\n      if (bb.height() > MAX_BB_HEIGHT) {\n        bb[bb.left, bb.centerY() - MAX_BB_HEIGHT / 2, bb.right] = bb.centerY() + MAX_BB_HEIGHT / 2\n      }\n      return bb\n    }\n  }\n\n  init {\n    currentStrokePaint = Paint()\n    currentStrokePaint.color = -0xff01 // pink.\n    currentStrokePaint.isAntiAlias = true\n    // Set stroke width based on display density.\n    currentStrokePaint.strokeWidth =\n      TypedValue.applyDimension(\n        TypedValue.COMPLEX_UNIT_DIP,\n        STROKE_WIDTH_DP.toFloat(),\n        resources.displayMetrics\n      )\n    currentStrokePaint.style = Paint.Style.STROKE\n    currentStrokePaint.strokeJoin = Paint.Join.ROUND\n    currentStrokePaint.strokeCap = Paint.Cap.ROUND\n    recognizedStrokePaint = Paint(currentStrokePaint)\n    recognizedStrokePaint.color = -0x3301 // pale pink.\n    textPaint = TextPaint()\n    textPaint.color = -0xcc33cd // green.\n    currentStroke = Path()\n    canvasPaint = Paint(Paint.DITHER_FLAG)\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/kotlin/ModelManager.kt",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition.kotlin\n\nimport android.util.Log\nimport com.google.android.gms.tasks.SuccessContinuation\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.Tasks\nimport com.google.mlkit.common.MlKitException\nimport com.google.mlkit.common.model.DownloadConditions\nimport com.google.mlkit.common.model.RemoteModelManager\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognition\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognitionModel\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognitionModelIdentifier\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognizer\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognizerOptions\nimport java.util.HashSet\n\n/** Class to manage model downloading, deletion, and selection. */\nclass ModelManager {\n  private var model: DigitalInkRecognitionModel? = null\n  var recognizer: DigitalInkRecognizer? = null\n  val remoteModelManager = RemoteModelManager.getInstance()\n  fun setModel(languageTag: String): String {\n    // Clear the old model and recognizer.\n    model = null\n    recognizer?.close()\n    recognizer = null\n\n    // Try to parse the languageTag and get a model from it.\n    val modelIdentifier: DigitalInkRecognitionModelIdentifier?\n    modelIdentifier =\n      try {\n        DigitalInkRecognitionModelIdentifier.fromLanguageTag(languageTag)\n      } catch (e: MlKitException) {\n        Log.e(TAG, \"Failed to parse language '$languageTag'\")\n        return \"\"\n      } ?: return \"No model for language: $languageTag\"\n\n    // Initialize the model and recognizer.\n    model = DigitalInkRecognitionModel.builder(modelIdentifier).build()\n    recognizer =\n      DigitalInkRecognition.getClient(DigitalInkRecognizerOptions.builder(model!!).build())\n    Log.i(TAG, \"Model set for language '$languageTag' ('$modelIdentifier.languageTag').\")\n    return \"Model set for language: $languageTag\"\n  }\n\n  fun checkIsModelDownloaded(): Task<Boolean?> {\n    return remoteModelManager.isModelDownloaded(model!!)\n  }\n\n  fun deleteActiveModel(): Task<String?> {\n    if (model == null) {\n      Log.i(TAG, \"Model not set\")\n      return Tasks.forResult(\"Model not set\")\n    }\n    return checkIsModelDownloaded()\n      .onSuccessTask { result: Boolean? ->\n        if (!result!!) {\n          return@onSuccessTask Tasks.forResult(\"Model not downloaded yet\")\n        }\n        remoteModelManager.deleteDownloadedModel(model!!).onSuccessTask { _: Void? ->\n          Log.i(TAG, \"Model successfully deleted\")\n          Tasks.forResult(\"Model successfully deleted\")\n        }\n      }\n      .addOnFailureListener { e: Exception -> Log.e(TAG, \"Error while model deletion: $e\") }\n  }\n\n  val downloadedModelLanguages: Task<Set<String>>\n    get() =\n      remoteModelManager\n        .getDownloadedModels(DigitalInkRecognitionModel::class.java)\n        .onSuccessTask(\n          SuccessContinuation { remoteModels: Set<DigitalInkRecognitionModel>? ->\n            val result: MutableSet<String> = HashSet()\n            for (model in remoteModels!!) {\n              result.add(model.modelIdentifier.languageTag)\n            }\n            Log.i(TAG, \"Downloaded models for languages:$result\")\n            Tasks.forResult<Set<String>>(result.toSet())\n          }\n        )\n\n  fun download(): Task<String?> {\n    return if (model == null) {\n      Tasks.forResult(\"Model not selected.\")\n    } else\n      remoteModelManager\n        .download(model!!, DownloadConditions.Builder().build())\n        .onSuccessTask { _: Void? ->\n          Log.i(TAG, \"Model download succeeded.\")\n          Tasks.forResult(\"Downloaded model successfully\")\n        }\n        .addOnFailureListener { e: Exception ->\n          Log.e(TAG, \"Error while downloading the model: $e\")\n        }\n  }\n\n  companion object {\n    private const val TAG = \"MLKD.ModelManager\"\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/kotlin/RecognitionTask.kt",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition.kotlin\n\nimport android.util.Log\nimport com.google.android.gms.tasks.SuccessContinuation\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.Tasks\nimport com.google.mlkit.vision.digitalink.common.RecognitionResult\nimport com.google.mlkit.vision.digitalink.recognition.DigitalInkRecognizer\nimport com.google.mlkit.vision.digitalink.recognition.Ink\nimport java.util.concurrent.atomic.AtomicBoolean\n\n/** Task to run asynchronously to obtain recognition results. */\nclass RecognitionTask(private val recognizer: DigitalInkRecognizer?, private val ink: Ink) {\n  private var currentResult: RecognizedInk? = null\n  private val cancelled: AtomicBoolean\n  private val done: AtomicBoolean\n  fun cancel() {\n    cancelled.set(true)\n  }\n\n  fun done(): Boolean {\n    return done.get()\n  }\n\n  fun result(): RecognizedInk? {\n    return currentResult\n  }\n\n  /** Helper class that stores an ink along with the corresponding recognized text. */\n  class RecognizedInk internal constructor(val ink: Ink, val text: String?)\n\n  fun run(): Task<String?> {\n    Log.i(TAG, \"RecoTask.run\")\n    return recognizer!!\n      .recognize(ink)\n      .onSuccessTask(\n        SuccessContinuation { result: RecognitionResult? ->\n          if (cancelled.get() || result == null || result.candidates.isEmpty()) {\n            return@SuccessContinuation Tasks.forResult<String?>(null)\n          }\n          currentResult = RecognizedInk(ink, result.candidates[0].text)\n          Log.i(TAG, \"result: \" + currentResult!!.text)\n          done.set(true)\n          return@SuccessContinuation Tasks.forResult<String?>(currentResult!!.text)\n        }\n      )\n  }\n\n  companion object {\n    private const val TAG = \"MLKD.RecognitionTask\"\n  }\n\n  init {\n    cancelled = AtomicBoolean(false)\n    done = AtomicBoolean(false)\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/kotlin/StatusTextView.kt",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition.kotlin\n\nimport android.content.Context\nimport androidx.appcompat.widget.AppCompatTextView\nimport android.util.AttributeSet\nimport com.google.mlkit.samples.vision.digitalink.recognition.kotlin.StrokeManager.StatusChangedListener\n\n/**\n * Status bar for the test app.\n *\n * It is updated upon status changes announced by the StrokeManager.\n */\nclass StatusTextView : AppCompatTextView, StatusChangedListener {\n  private var strokeManager: StrokeManager? = null\n\n  constructor(context: Context) : super(context) {}\n  constructor(context: Context?, attributeSet: AttributeSet?) : super(context!!, attributeSet) {}\n\n  override fun onStatusChanged() {\n    this.text = strokeManager!!.status\n  }\n\n  fun setStrokeManager(strokeManager: StrokeManager?) {\n    this.strokeManager = strokeManager\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/java/com/google/mlkit/samples/vision/digitalink/recognition/kotlin/StrokeManager.kt",
    "content": "package com.google.mlkit.samples.vision.digitalink.recognition.kotlin\n\nimport android.os.Handler\nimport android.os.Message\nimport android.util.Log\nimport android.view.MotionEvent\nimport androidx.annotation.VisibleForTesting\nimport com.google.android.gms.tasks.SuccessContinuation\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.Tasks\nimport com.google.mlkit.samples.vision.digitalink.recognition.kotlin.RecognitionTask.RecognizedInk\nimport com.google.mlkit.vision.digitalink.recognition.Ink\nimport com.google.mlkit.vision.digitalink.recognition.Ink.Stroke\nimport java.util.ArrayList\n\n/** Manages the recognition logic and the content that has been added to the current page. */\nclass StrokeManager {\n  /** Interface to register to be notified of changes in the recognized content. */\n  interface ContentChangedListener {\n    /** This method is called when the recognized content changes. */\n    fun onContentChanged()\n  }\n\n  /** Interface to register to be notified of changes in the status. */\n  interface StatusChangedListener {\n    /** This method is called when the recognized content changes. */\n    fun onStatusChanged()\n  }\n\n  /** Interface to register to be notified of changes in the downloaded model state. */\n  interface DownloadedModelsChangedListener {\n    /** This method is called when the downloaded models changes. */\n    fun onDownloadedModelsChanged(downloadedLanguageTags: Set<String>)\n  }\n\n  // For handling recognition and model downloading.\n  private var recognitionTask: RecognitionTask? = null\n\n  @JvmField @VisibleForTesting var modelManager = ModelManager()\n\n  // Managing the recognition queue.\n  private val content: MutableList<RecognizedInk> = ArrayList()\n\n  // Managing ink currently drawn.\n  private var strokeBuilder = Stroke.builder()\n  private var inkBuilder = Ink.builder()\n  private var stateChangedSinceLastRequest = false\n  private var contentChangedListener: ContentChangedListener? = null\n  private var statusChangedListener: StatusChangedListener? = null\n  private var downloadedModelsChangedListener: DownloadedModelsChangedListener? = null\n  private var triggerRecognitionAfterInput = true\n  private var clearCurrentInkAfterRecognition = true\n  var status: String? = \"\"\n    private set(newStatus) {\n      field = newStatus\n      statusChangedListener?.onStatusChanged()\n    }\n\n  fun setTriggerRecognitionAfterInput(shouldTrigger: Boolean) {\n    triggerRecognitionAfterInput = shouldTrigger\n  }\n\n  fun setClearCurrentInkAfterRecognition(shouldClear: Boolean) {\n    clearCurrentInkAfterRecognition = shouldClear\n  }\n\n  // Handler to handle the UI Timeout.\n  // This handler is only used to trigger the UI timeout. Each time a UI interaction happens,\n  // the timer is reset by clearing the queue on this handler and sending a new delayed message (in\n  // addNewTouchEvent).\n  private val uiHandler =\n    Handler(\n      Handler.Callback { msg: Message ->\n        if (msg.what == TIMEOUT_TRIGGER) {\n          Log.i(TAG, \"Handling timeout trigger.\")\n          commitResult()\n          return@Callback true\n        }\n        false\n      }\n    )\n\n  private fun commitResult() {\n    recognitionTask!!.result()?.let {\n      content.add(it)\n      status = \"Successful recognition: \" + it.text\n      if (clearCurrentInkAfterRecognition) {\n        resetCurrentInk()\n      }\n\n      contentChangedListener?.onContentChanged()\n    }\n  }\n\n  fun reset() {\n    Log.i(TAG, \"reset\")\n    resetCurrentInk()\n    content.clear()\n    recognitionTask?.cancel()\n    status = \"\"\n  }\n\n  private fun resetCurrentInk() {\n    inkBuilder = Ink.builder()\n    strokeBuilder = Stroke.builder()\n    stateChangedSinceLastRequest = false\n  }\n\n  val currentInk: Ink\n    get() = inkBuilder.build()\n\n  /**\n   * This method is called when a new touch event happens on the drawing client and notifies the\n   * StrokeManager of new content being added.\n   *\n   * This method takes care of triggering the UI timeout and scheduling recognitions on the\n   * background thread.\n   *\n   * @return whether the touch event was handled.\n   */\n  fun addNewTouchEvent(event: MotionEvent): Boolean {\n    val action = event.actionMasked\n    val x = event.x\n    val y = event.y\n    val t = System.currentTimeMillis()\n\n    // A new event happened -> clear all pending timeout messages.\n    uiHandler.removeMessages(TIMEOUT_TRIGGER)\n    when (action) {\n      MotionEvent.ACTION_DOWN,\n      MotionEvent.ACTION_MOVE -> strokeBuilder.addPoint(Ink.Point.create(x, y, t))\n      MotionEvent.ACTION_UP -> {\n        strokeBuilder.addPoint(Ink.Point.create(x, y, t))\n        inkBuilder.addStroke(strokeBuilder.build())\n        strokeBuilder = Stroke.builder()\n        stateChangedSinceLastRequest = true\n        if (triggerRecognitionAfterInput) {\n          val unused = recognize()\n        }\n      }\n      else -> // Indicate touch event wasn't handled.\n      return false\n    }\n    return true\n  }\n\n  // Listeners to update the drawing and status.\n  fun setContentChangedListener(contentChangedListener: ContentChangedListener?) {\n    this.contentChangedListener = contentChangedListener\n  }\n\n  fun setStatusChangedListener(statusChangedListener: StatusChangedListener?) {\n    this.statusChangedListener = statusChangedListener\n  }\n\n  fun setDownloadedModelsChangedListener(\n    downloadedModelsChangedListener: DownloadedModelsChangedListener?\n  ) {\n    this.downloadedModelsChangedListener = downloadedModelsChangedListener\n  }\n\n  fun getContent(): List<RecognizedInk> {\n    return content\n  }\n\n  // Model downloading / deleting / setting.\n  fun setActiveModel(languageTag: String) {\n    status = modelManager.setModel(languageTag)\n  }\n\n  fun deleteActiveModel(): Task<Nothing?> {\n    return modelManager\n      .deleteActiveModel()\n      .addOnSuccessListener { refreshDownloadedModelsStatus() }\n      .onSuccessTask(\n        SuccessContinuation { status: String? ->\n          this.status = status\n          return@SuccessContinuation Tasks.forResult(null)\n        }\n      )\n  }\n\n  fun download(): Task<Nothing?> {\n    status = \"Download started.\"\n    return modelManager\n      .download()\n      .addOnSuccessListener { refreshDownloadedModelsStatus() }\n      .onSuccessTask(\n        SuccessContinuation { status: String? ->\n          this.status = status\n          return@SuccessContinuation Tasks.forResult(null)\n        }\n      )\n  }\n\n  // Recognition-related.\n  fun recognize(): Task<String?> {\n    if (!stateChangedSinceLastRequest || inkBuilder.isEmpty) {\n      status = \"No recognition, ink unchanged or empty\"\n      return Tasks.forResult(null)\n    }\n    if (modelManager.recognizer == null) {\n      status = \"Recognizer not set\"\n      return Tasks.forResult(null)\n    }\n    return modelManager.checkIsModelDownloaded().onSuccessTask { result: Boolean? ->\n      if (!result!!) {\n        status = \"Model not downloaded yet\"\n        return@onSuccessTask Tasks.forResult<String?>(null)\n      }\n      stateChangedSinceLastRequest = false\n      recognitionTask = RecognitionTask(modelManager.recognizer, inkBuilder.build())\n      uiHandler.sendMessageDelayed(uiHandler.obtainMessage(TIMEOUT_TRIGGER), CONVERSION_TIMEOUT_MS)\n      recognitionTask!!.run()\n    }\n  }\n\n  fun refreshDownloadedModelsStatus() {\n    modelManager.downloadedModelLanguages.addOnSuccessListener { downloadedLanguageTags: Set<String>\n      ->\n      downloadedModelsChangedListener?.onDownloadedModelsChanged(downloadedLanguageTags)\n    }\n  }\n\n  companion object {\n    @JvmField @VisibleForTesting val CONVERSION_TIMEOUT_MS: Long = 1000\n    private const val TAG = \"MLKD.StrokeManager\"\n\n    // This is a constant that is used as a message identifier to trigger the timeout.\n    private const val TIMEOUT_TRIGGER = 1\n  }\n}\n"
  },
  {
    "path": "android/digitalink/app/src/main/res/layout/activity_digital_ink_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.google.mlkit.samples.vision.digitalink.recognition.DrawingView\n        android:id=\"@+id/drawing_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"200dp\"\n        android:layout_weight=\"1\"\n        android:background=\"#80FFFFFF\" />\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n            <com.google.mlkit.samples.vision.digitalink.recognition.StatusTextView\n                android:id=\"@+id/status_text_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Status text...\"\n                android:textIsSelectable=\"true\" />\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"60dp\"\n                android:orientation=\"horizontal\">\n                <Button\n                    android:id=\"@+id/download_button\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:onClick=\"downloadClick\"\n                    android:text=\"Download\" />\n                <Button\n                    android:id=\"@+id/recognize_button\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:onClick=\"recognizeClick\"\n                    android:text=\"Recognize\" />\n                <Button\n                    android:id=\"@+id/clear_button\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:onClick=\"clearClick\"\n                    android:text=\"Clear\" />\n            </LinearLayout>\n        </LinearLayout>\n    </FrameLayout>\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"60dp\"\n            android:orientation=\"horizontal\">\n            <Spinner\n                android:id=\"@+id/languages_spinner\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"3\" />\n            <Button\n                android:id=\"@+id/delete_button\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:onClick=\"deleteClick\"\n                android:text=\"Delete model\" />\n        </LinearLayout>\n    </FrameLayout>\n</LinearLayout>\n"
  },
  {
    "path": "android/digitalink/app/src/main/res/layout/activity_digital_ink_main_kotlin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.google.mlkit.samples.vision.digitalink.recognition.kotlin.DrawingView\n        android:id=\"@+id/drawing_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"200dp\"\n        android:layout_weight=\"1\"\n        android:background=\"#80FFFFFF\" />\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n            <com.google.mlkit.samples.vision.digitalink.recognition.kotlin.StatusTextView\n                android:id=\"@+id/status_text_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Status text...\"\n                android:textIsSelectable=\"true\" />\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"60dp\"\n                android:orientation=\"horizontal\">\n                <Button\n                    android:id=\"@+id/download_button\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:onClick=\"downloadClick\"\n                    android:text=\"Download\" />\n                <Button\n                    android:id=\"@+id/recognize_button\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:onClick=\"recognizeClick\"\n                    android:text=\"Recognize\" />\n                <Button\n                    android:id=\"@+id/clear_button\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:onClick=\"clearClick\"\n                    android:text=\"Clear\" />\n            </LinearLayout>\n        </LinearLayout>\n    </FrameLayout>\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"60dp\"\n            android:orientation=\"horizontal\">\n            <Spinner\n                android:id=\"@+id/languages_spinner\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"3\" />\n            <Button\n                android:id=\"@+id/delete_button\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:onClick=\"deleteClick\"\n                android:text=\"Delete model\" />\n        </LinearLayout>\n    </FrameLayout>\n</LinearLayout>\n"
  },
  {
    "path": "android/digitalink/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#6200EE</color>\n    <color name=\"colorPrimaryDark\">#3700B3</color>\n    <color name=\"colorAccent\">#03DAC5</color>\n</resources>"
  },
  {
    "path": "android/digitalink/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\" translatable=\"false\">ML Kit Digital Ink Recognition Demo</string>\n    <string name=\"title_activity_main\" translatable=\"false\">ML Kit Digital Ink Recognition Demo</string>\n    <string name=\"clear\" translatable=\"false\">Clear</string>\n</resources>\n"
  },
  {
    "path": "android/digitalink/app/src/main/res/values/styles.xml",
    "content": "<resources>\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "android/digitalink/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n    ext.kotlin_version = \"2.1.0\"\n    repositories {\n        mavenCentral()\n        mavenLocal()\n        google()\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:8.1.1\"\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        mavenCentral()\n        mavenLocal()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/digitalink/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Jan 24 22:29:24 UTC 2022\ndistributionBase=GRADLE_USER_HOME\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.7.1-bin.zip\ndistributionPath=wrapper/dists\nzipStorePath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\n"
  },
  {
    "path": "android/digitalink/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\norg.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "android/digitalink/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/digitalink/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/digitalink/settings.gradle",
    "content": "include ':app'\nrootProject.name = \"ML Kit Digital Ink Recognition Demo\""
  },
  {
    "path": "android/documentscanner/LICENSE",
    "content": "   Copyright 2024 Google LLC\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "android/documentscanner/README.md",
    "content": "# ML Kit Document Scanner API Quickstart\n\n* [Read more about ML Kit Document Scanner API](https://developers.google.com/ml-kit/vision/doc-scanner)\n\n## Introduction\n\nThe ML Kit Document Scanner API Quickstart app demonstrates how to use the\ndocument scanner feature to scan documents without app requesting camera\npermission.\n\n## Getting Started\n\n* Run the sample code on your Android device.\n* Tap on the SCAN button.\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/vision/doc-scanner)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2024 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/documentscanner/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 34\n    defaultConfig {\n        applicationId \"com.google.mlkit.samples.documentscanner\"\n        minSdkVersion 21\n        targetSdkVersion 34\n        versionCode 1\n        versionName \"1.0\"\n        setProperty(\"archivesBaseName\", \"document-scanner-sample\")\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        debug {\n            isDefault true\n            minifyEnabled false\n            proguardFiles 'proguard-rules.pro'\n        }\n        proguard {\n            debuggable false\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n            testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardTest-rules.pro', 'proguard.cfg'\n        }\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n        }\n        testBuildType \"proguard\"\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    lintOptions {\n        disable \"Instantiatable\"\n    }\n}\n\ndependencies {\n    implementation project(':internal:chooserx')\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'com.google.android.material:material:1.5.0'\n    implementation 'com.github.bumptech.glide:glide:4.15.0'\n    annotationProcessor 'com.github.bumptech.glide:compiler:4.15.0'\n\n    implementation 'com.google.android.gms:play-services-mlkit-document-scanner:16.0.0-beta1'\n\n    androidTestImplementation 'androidx.test:rules:1.4.0'\n    androidTestImplementation 'androidx.test:runner:1.4.0'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.3'\n    androidTestImplementation 'com.google.truth:truth:1.0.1'\n}\n"
  },
  {
    "path": "android/documentscanner/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.google.mlkit.samples.documentscanner\">\n\n  <application\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:taskAffinity=\"\"\n      android:theme=\"@style/AppTheme\">\n\n    <meta-data\n        android:name=\"com.google.android.gms.version\"\n        android:value=\"@integer/google_play_services_version\" />\n\n    <meta-data\n        android:name=\"com.google.mlkit.vision.DEPENDENCIES\"\n        android:value=\"document_ui\"/>\n\n    <activity\n        android:name=\".EntryChoiceActivity\"\n        android:exported=\"true\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\".java.MainActivity\"\n        android:exported=\"false\" />\n\n    <activity\n        android:name=\".kotlin.MainActivity\"\n        android:exported=\"false\" />\n\n    <provider\n        android:name=\"androidx.core.content.FileProvider\"\n        android:authorities=\"${applicationId}.provider\"\n        android:exported=\"false\"\n        android:grantUriPermissions=\"true\">\n        <meta-data\n            android:name=\"android.support.FILE_PROVIDER_PATHS\"\n            android:resource=\"@xml/file_paths\" />\n    </provider>\n\n  </application>\n</manifest>\n"
  },
  {
    "path": "android/documentscanner/app/src/main/java/com/google/mlkit/samples/documentscanner/EntryChoiceActivity.kt",
    "content": "/*\n * Copyright 2024 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.documentscanner\n\nimport android.content.Intent\nimport com.google.mlkit.samples.documentscanner.kotlin.MainActivity\nimport com.mlkit.example.internal.BaseEntryChoiceActivity\nimport com.mlkit.example.internal.Choice\n\nclass EntryChoiceActivity : BaseEntryChoiceActivity() {\n\n  override fun getChoices(): List<Choice> {\n    return listOf(\n      Choice(\n        \"Java\",\n        \"Run the Google Document Scanner demo written in Java.\",\n        Intent(this, com.google.mlkit.samples.documentscanner.java.MainActivity::class.java)\n      ),\n      Choice(\n        \"Kotlin\",\n        \"Run the Google Document Scanner demo written in Kotlin.\",\n        Intent(this, com.google.mlkit.samples.documentscanner.kotlin.MainActivity::class.java)\n      )\n    )\n  }\n}\n"
  },
  {
    "path": "android/documentscanner/app/src/main/java/com/google/mlkit/samples/documentscanner/java/MainActivity.java",
    "content": "/*\n * Copyright 2024 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.documentscanner.java;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.CheckBox;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport androidx.activity.result.ActivityResult;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.IntentSenderRequest;\nimport androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult;\nimport androidx.core.content.FileProvider;\nimport com.bumptech.glide.Glide;\nimport com.google.mlkit.samples.documentscanner.R;\nimport com.google.mlkit.vision.documentscanner.GmsDocumentScannerOptions;\nimport com.google.mlkit.vision.documentscanner.GmsDocumentScanning;\nimport com.google.mlkit.vision.documentscanner.GmsDocumentScanningResult;\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** Demonstrates the document scanner powered by Google Play services. */\npublic class MainActivity extends AppCompatActivity {\n\n  private static final String TAG = \"MainActivity\";\n\n  private static final String FULL_MODE = \"FULL\";\n  private static final String BASE_MODE = \"BASE\";\n  private static final String BASE_MODE_WITH_FILTER = \"BASE_WITH_FILTER\";\n  private String selectedMode = FULL_MODE;\n\n  private TextView resultInfo;\n  private ImageView firstPageView;\n  private EditText pageLimitInputView;\n  private ActivityResultLauncher<IntentSenderRequest> scannerLauncher;\n  private boolean enableGalleryImport = true;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n\n    resultInfo = findViewById(R.id.result_info);\n    firstPageView = findViewById(R.id.first_page_view);\n    pageLimitInputView = findViewById(R.id.page_limit_input);\n\n    scannerLauncher =\n        registerForActivityResult(new StartIntentSenderForResult(), this::handleActivityResult);\n    populateModeSelector();\n  }\n\n  public void onEnableGalleryImportCheckboxClicked(View view) {\n    enableGalleryImport = ((CheckBox) view).isChecked();\n  }\n\n  public void onScanButtonClicked(View view) {\n    resultInfo.setText(null);\n    Glide.with(this).clear(firstPageView);\n\n    GmsDocumentScannerOptions.Builder options =\n        new GmsDocumentScannerOptions.Builder()\n            .setResultFormats(\n                GmsDocumentScannerOptions.RESULT_FORMAT_JPEG,\n                GmsDocumentScannerOptions.RESULT_FORMAT_PDF)\n            .setGalleryImportAllowed(enableGalleryImport);\n\n    switch (selectedMode) {\n      case FULL_MODE:\n        options.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_FULL);\n        break;\n      case BASE_MODE:\n        options.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_BASE);\n        break;\n      case BASE_MODE_WITH_FILTER:\n        options.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_BASE_WITH_FILTER);\n        break;\n      default:\n        Log.e(TAG, \"Unknown selectedMode: \" + selectedMode);\n    }\n\n    String pageLimitInputText = pageLimitInputView.getText().toString();\n    if (!pageLimitInputText.isEmpty()) {\n      try {\n        int pageLimit = Integer.parseInt(pageLimitInputText);\n        options.setPageLimit(pageLimit);\n      } catch (RuntimeException e) {\n        resultInfo.setText(e.getMessage());\n        return;\n      }\n    }\n\n    GmsDocumentScanning.getClient(options.build())\n        .getStartScanIntent(this)\n        .addOnSuccessListener(\n            intentSender ->\n                scannerLauncher.launch(new IntentSenderRequest.Builder(intentSender).build()))\n        .addOnFailureListener(\n            e -> resultInfo.setText(getString(R.string.error_default_message, e.getMessage())));\n  }\n\n  private void populateModeSelector() {\n    Spinner featureSpinner = findViewById(R.id.mode_selector);\n    List<String> options = new ArrayList<>();\n    options.add(FULL_MODE);\n    options.add(BASE_MODE);\n    options.add(BASE_MODE_WITH_FILTER);\n\n    // Creating adapter for featureSpinner\n    ArrayAdapter<String> dataAdapter =\n        new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // Attaching data adapter to spinner\n    featureSpinner.setAdapter(dataAdapter);\n    featureSpinner.setOnItemSelectedListener(\n        new OnItemSelectedListener() {\n\n          @Override\n          public void onItemSelected(\n              AdapterView<?> parentView, View selectedItemView, int pos, long id) {\n            selectedMode = parentView.getItemAtPosition(pos).toString();\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> arg0) {}\n        });\n  }\n\n  private void handleActivityResult(ActivityResult activityResult) {\n    int resultCode = activityResult.getResultCode();\n    GmsDocumentScanningResult result =\n        GmsDocumentScanningResult.fromActivityResultIntent(activityResult.getData());\n    if (resultCode == Activity.RESULT_OK && result != null) {\n      resultInfo.setText(getString(R.string.scan_result, result));\n\n      if (!result.getPages().isEmpty()) {\n        Glide.with(this).load(result.getPages().get(0).getImageUri()).into(firstPageView);\n      }\n\n      if (result.getPdf() != null) {\n        File file = new File(result.getPdf().getUri().getPath());\n        Uri externalUri = FileProvider.getUriForFile(this, getPackageName() + \".provider\", file);\n\n        Intent viewIntent = new Intent(Intent.ACTION_VIEW);\n        viewIntent.setDataAndType(externalUri, \"application/pdf\");\n        viewIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n\n        startActivity(Intent.createChooser(viewIntent, \"view pdf\"));\n      }\n    } else if (resultCode == Activity.RESULT_CANCELED) {\n      resultInfo.setText(getString(R.string.error_scanner_cancelled));\n    } else {\n      resultInfo.setText(getString(R.string.error_default_message));\n    }\n  }\n}\n"
  },
  {
    "path": "android/documentscanner/app/src/main/java/com/google/mlkit/samples/documentscanner/kotlin/MainActivity.kt",
    "content": "/*\n * Copyright 2024 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.documentscanner.kotlin\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.content.IntentSender\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.view.View\nimport android.widget.AdapterView\nimport android.widget.ArrayAdapter\nimport android.widget.CheckBox\nimport android.widget.EditText\nimport android.widget.ImageView\nimport android.widget.Spinner\nimport android.widget.TextView\nimport androidx.activity.result.ActivityResult\nimport androidx.activity.result.ActivityResultLauncher\nimport androidx.activity.result.IntentSenderRequest\nimport androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult\nimport androidx.core.content.FileProvider\nimport com.bumptech.glide.Glide\nimport com.google.mlkit.samples.documentscanner.R\nimport com.google.mlkit.vision.documentscanner.GmsDocumentScannerOptions\nimport com.google.mlkit.vision.documentscanner.GmsDocumentScanning\nimport com.google.mlkit.vision.documentscanner.GmsDocumentScanningResult\nimport java.io.File\n\n/** Demonstrates the document scanner powered by Google Play services. */\nclass MainActivity : AppCompatActivity() {\n\n  private lateinit var resultInfo: TextView\n  private lateinit var firstPageView: ImageView\n  private lateinit var pageLimitInputView: EditText\n  private lateinit var scannerLauncher: ActivityResultLauncher<IntentSenderRequest>\n  private var enableGalleryImport = true\n  private val FULL_MODE = \"FULL\"\n  private val BASE_MODE = \"BASE\"\n  private val BASE_MODE_WITH_FILTER = \"BASE_WITH_FILTER\"\n  private var selectedMode = FULL_MODE\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_main)\n    resultInfo = findViewById<TextView>(R.id.result_info)!!\n    firstPageView = findViewById<ImageView>(R.id.first_page_view)!!\n    pageLimitInputView = findViewById(R.id.page_limit_input)\n\n    scannerLauncher =\n      registerForActivityResult(StartIntentSenderForResult()) { result ->\n        handleActivityResult(result)\n      }\n    populateModeSelector()\n  }\n\n  fun onEnableGalleryImportCheckboxClicked(view: View) {\n    enableGalleryImport = (view as CheckBox).isChecked\n  }\n\n  @Suppress(\"UNUSED_PARAMETER\")\n  fun onScanButtonClicked(unused: View) {\n    resultInfo.text = null\n    Glide.with(this).clear(firstPageView)\n\n    val options =\n      GmsDocumentScannerOptions.Builder()\n        .setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_BASE)\n        .setResultFormats(GmsDocumentScannerOptions.RESULT_FORMAT_PDF)\n        .setGalleryImportAllowed(enableGalleryImport)\n\n    when (selectedMode) {\n      FULL_MODE -> options.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_FULL)\n      BASE_MODE -> options.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_BASE)\n      BASE_MODE_WITH_FILTER ->\n        options.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_BASE_WITH_FILTER)\n      else -> Log.e(TAG, \"Unknown selectedMode: $selectedMode\")\n    }\n\n    val pageLimitInputText = pageLimitInputView.text.toString()\n    if (pageLimitInputText.isNotEmpty()) {\n      try {\n        val pageLimit = pageLimitInputText.toInt()\n        options.setPageLimit(pageLimit)\n      } catch (e: Throwable) {\n        resultInfo.text = e.message\n        return\n      }\n    }\n\n    GmsDocumentScanning.getClient(options.build())\n      .getStartScanIntent(this)\n      .addOnSuccessListener { intentSender: IntentSender ->\n        scannerLauncher.launch(IntentSenderRequest.Builder(intentSender).build())\n      }\n      .addOnFailureListener() { e: Exception ->\n        resultInfo.setText(getString(R.string.error_default_message, e.message))\n      }\n  }\n\n  private fun populateModeSelector() {\n    val featureSpinner = findViewById<Spinner>(R.id.mode_selector)\n    val options: MutableList<String> = ArrayList()\n    options.add(FULL_MODE)\n    options.add(BASE_MODE)\n    options.add(BASE_MODE_WITH_FILTER)\n\n    // Creating adapter for featureSpinner\n    val dataAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, options)\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n    // Attaching data adapter to spinner\n    featureSpinner.adapter = dataAdapter\n    featureSpinner.onItemSelectedListener =\n      object : AdapterView.OnItemSelectedListener {\n        override fun onItemSelected(\n          parentView: AdapterView<*>,\n          selectedItemView: View,\n          pos: Int,\n          id: Long\n        ) {\n          selectedMode = parentView.getItemAtPosition(pos).toString()\n        }\n\n        override fun onNothingSelected(arg0: AdapterView<*>?) {}\n      }\n  }\n\n  private fun handleActivityResult(activityResult: ActivityResult) {\n    val resultCode = activityResult.resultCode\n    val result = GmsDocumentScanningResult.fromActivityResultIntent(activityResult.data)\n    if (resultCode == Activity.RESULT_OK && result != null) {\n      resultInfo.setText(getString(R.string.scan_result, result))\n\n      val pages = result.pages\n      if (pages != null && pages.isNotEmpty()) {\n        Glide.with(this).load(pages[0].imageUri).into(firstPageView)\n      }\n\n      result.pdf?.uri?.path?.let { path ->\n        val externalUri = FileProvider.getUriForFile(this, packageName + \".provider\", File(path))\n        val shareIntent =\n          Intent(Intent.ACTION_SEND).apply {\n            putExtra(Intent.EXTRA_STREAM, externalUri)\n            type = \"application/pdf\"\n            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)\n          }\n        startActivity(Intent.createChooser(shareIntent, \"share pdf\"))\n      }\n    } else if (resultCode == Activity.RESULT_CANCELED) {\n      resultInfo.text = getString(R.string.error_scanner_cancelled)\n    } else {\n      resultInfo.text = getString(R.string.error_default_message)\n    }\n  }\n\n  companion object {\n    private const val TAG = \"MainActivity\"\n  }\n}\n"
  },
  {
    "path": "android/documentscanner/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportWidth=\"172.43\"\n    android:viewportHeight=\"129.06\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#ff9933\"\n      android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#ffff99\"\n      android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#ff9933\"\n      android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#ffff99\"\n      android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#ff9933\"\n      android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/documentscanner/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:padding=\"16dp\"\n    android:orientation=\"vertical\">\n  <LinearLayout\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"horizontal\">\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/label_mode_selector\" />\n    <Spinner\n        android:id=\"@+id/mode_selector\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"/>\n  </LinearLayout>\n\n  <LinearLayout\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"horizontal\">\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/label_enable_gallery_import\" />\n    <CheckBox\n        android:id=\"@+id/enable_gallery_import\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:onClick=\"onEnableGalleryImportCheckboxClicked\"\n        android:checked=\"true\"\n        android:text=\"\" />\n  </LinearLayout>\n\n  <LinearLayout\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"horizontal\">\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/label_set_page_limit\" />\n    <EditText\n        android:id=\"@+id/page_limit_input\"\n        android:layout_width=\"100dp\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"number\"\n        android:autofillHints=\"\" />\n </LinearLayout>\n\n  <Button\n      android:id=\"@+id/scan_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:onClick=\"onScanButtonClicked\"\n      android:text=\"@string/scan_button\" />\n\n  <TextView\n      android:id=\"@+id/result_info\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:text=\"\" />\n\n  <ImageView\n      android:id=\"@+id/first_page_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:contentDescription=\"@string/first_page_view\"\n      android:scaleType=\"fitCenter\" />\n</LinearLayout>\n"
  },
  {
    "path": "android/documentscanner/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"colorPrimary\">@color/blue</color>\n  <color name=\"colorPrimaryDark\">@color/darkBlue</color>\n  <color name=\"colorAccent\">@color/red</color>\n  <color name=\"blue\">#3681E6</color>\n  <color name=\"darkBlue\">#2F5FC0</color>\n  <color name=\"red\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "android/documentscanner/app/src/main/res/values/strings.xml",
    "content": "<resources>\n  <string name=\"app_name\" translatable=\"false\">Document Scanner Demo</string>\n  <string name=\"scan_button\" translatable=\"false\">Scan</string>\n  <string name=\"scan_result\" translatable=\"false\">Scan result:\\n%1$s</string>\n  <string name=\"error_scanner_cancelled\" translatable=\"false\">Scanner is cancelled.</string>\n  <string name=\"error_default_message\" translatable=\"false\">Failed to scan: %1$s</string>\n  <string name=\"label_mode_selector\" translatable=\"false\">Scanner feature mode: </string>\n  <string name=\"label_enable_gallery_import\" translatable=\"false\">Enable gallery import: </string>\n  <string name=\"label_set_page_limit\" translatable=\"false\">Set page limit per scan: </string>\n  <string name=\"first_page_view\" translatable=\"false\">First page of the scanned document</string>\n</resources>\n"
  },
  {
    "path": "android/documentscanner/app/src/main/res/values/styles.xml",
    "content": "<resources>\n  <!-- Base application theme. -->\n  <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.DarkActionBar\">\n    <item name=\"colorPrimary\">@color/blue</item>\n    <item name=\"colorPrimaryDark\">@color/darkBlue</item>\n    <item name=\"colorAccent\">@color/red</item>\n  </style>\n</resources>\n"
  },
  {
    "path": "android/documentscanner/app/src/main/res/xml/file_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <cache-path name=\"cache_files\" path=\".\"/>\n</paths>\n"
  },
  {
    "path": "android/documentscanner/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.7.20'\n\n    repositories {\n        mavenLocal()\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.4.2'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        google()\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "android/documentscanner/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.0-bin.zip\nnetworkTimeout=10000\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "android/documentscanner/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "android/documentscanner/gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\nAPP_HOME=$( cd \"${APP_HOME:-./}\" && pwd -P ) || exit\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n# Collect all arguments for the java command;\n#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of\n#     shell script including quotes and variable substitutions, so put them in\n#     double quotes to make sure that they get re-expanded; and\n#   * put everything else in single quotes, so that it's not re-expanded.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/documentscanner/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/documentscanner/settings.gradle",
    "content": "rootProject.name= \"mlkit_document_scanner_sample\"\ninclude ':app'\ninclude ':internal:chooserx'\nproject(':internal:chooserx').projectDir = file('../internal/chooserx')\n"
  },
  {
    "path": "android/entityextraction/README.md",
    "content": "# ML Kit Entity Extraction Quickstart\n\n* [Read more about ML Kit Entity Extraction API](https://developers.google.com/ml-kit/language/entity-extraction)\n\n## Introduction\n\nThe ML Kit Entity Extraction Android Quickstart app demonstrates how to use the\nML Kit\nEntity Extraction feature to recognize structured data in\ntext.\n\n## Getting Started\n\n* Run the sample code on your Android device or emulator\n* Type messages to identify languages\n* Try extending the code to add new features and functionality\n\n## How to use the app\n\n-   Enter text in the input box and hit \"Trigger Entity Extraction\".\n-   If any entities are found in the text, they will show up on the bottom of\nthe screen.\n-   Click the download arrow in the top right corner to ensure the correct\nlanguage model has been downloaded.\n\n### Examples\n\n<table>\n<tr><th>Input text</th><th>Detected entities</th></tr>\n\n<tr><td>Meet me at <b>1600 Amphitheatre Parkway, Mountain View, CA, 94043</b>\nLet’s organize a meeting to discuss.</td>\n<td>Entity 1 type: Address<br>\nEntity 1 text: \"1600 Ampitheatre Parkway, Mountain View, CA 94043\"</td></tr>\n\n<tr><td>You can contact the test team <b>tomorrow</b> at <b>info@google.com</b>\nto determine the best timeline.</td>\n<td>Entity 1 type: Date-Time<br>\nEntity 1 text: = \"June 24th, 2020\"<br><br>\n\nEntity 2 type: Email address<br>\nEntity 2 text: info@google.com</td></tr>\n\n<tr><td>Your order has shipped from Google. To follow the progress of your\ndelivery please use this tracking number: <b>9612804152073070474837</b></td>\n<td>Entity type: Tracking number<br>\nEntity text: \"9612804152073070474837\"</td></tr>\n\n<tr><td>Call the restaurant at <b>555-555-1234</b> to pay for dinner. My card\nnumber is <b>4111 1111 1111 1111</b>.</td>\n<td>Entity 1 type: Phone number<br>\nEntity 1 text: \"555-555-1234\"<br><br>\n\nEntity 2 type: Payment card<br>\nEntity 2 text: \"4111 1111 1111 1111\"</td></tr>\n\n</table>\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/language/entity-extraction/android)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/entityextraction/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-parcelize'\n\nandroid {\n    namespace \"com.google.mlkit.samples.nl.entityextraction\"\n    compileSdkVersion 34\n\n    defaultConfig {\n        applicationId \"com.google.mlkit.samples.nl.entityextraction\"\n        minSdkVersion 26\n        targetSdkVersion 34\n        multiDexEnabled true\n        versionCode 1\n        versionName \"1.0\"\n        setProperty(\"archivesBaseName\", \"nl-entity-extraction\")\n    }\n\n    buildTypes {\n        proguard {\n            debuggable false\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n            testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardTest-rules.pro', 'proguard.cfg'\n        }\n        testBuildType \"proguard\"\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_21\n        targetCompatibility JavaVersion.VERSION_21\n    }\n    lintOptions {\n        disable \"Instantiatable\"\n    }\n    viewBinding {\n        enabled = true\n    }\n}\n\ndependencies {\n    implementation project(':internal:chooserx')\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'com.google.mlkit:entity-extraction:16.0.0-beta6'\n\n    // Optional dependency used for the Snackbar\n    implementation 'com.google.android.material:material:1.2.0'\n}\n"
  },
  {
    "path": "android/entityextraction/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.samples.nl.entityextraction\">\n\n  <application\n      android:allowBackup=\"true\"\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:theme=\"@style/AppTheme\">\n\n    <activity\n        android:name=\".EntryChoiceActivity\"\n        android:exported=\"true\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\".java.MainActivityJava\"\n        android:exported=\"true\" />\n\n    <activity\n        android:name=\".java.ModelsActivityJava\"\n        android:exported=\"true\" />\n\n    <activity\n        android:name=\".kotlin.MainActivityKotlin\"\n        android:exported=\"true\" />\n\n    <activity\n        android:name=\".kotlin.ModelsActivityKotlin\"\n        android:exported=\"true\" />\n\n  </application>\n\n</manifest>\n\n"
  },
  {
    "path": "android/entityextraction/app/src/main/java/com/google/mlkit/samples/nl/entityextraction/EntryChoiceActivity.kt",
    "content": "package com.google.mlkit.samples.nl.entityextraction\n\nimport android.content.Intent\nimport com.google.mlkit.samples.nl.entityextraction.java.MainActivityJava\nimport com.google.mlkit.samples.nl.entityextraction.kotlin.MainActivityKotlin\nimport com.mlkit.example.internal.BaseEntryChoiceActivity\nimport com.mlkit.example.internal.Choice\n\nclass EntryChoiceActivity : BaseEntryChoiceActivity() {\n\n  override fun getChoices(): List<Choice> {\n    return listOf(\n      Choice(\n        \"Java\",\n        \"Run the ML Kit Entity Extraction quickstart written in Java.\",\n        Intent(this, MainActivityJava::class.java)\n      ),\n      Choice(\n        \"Kotlin\",\n        \"Run the ML Kit Entity Extraction quickstart written in Kotlin.\",\n        Intent(this, MainActivityKotlin::class.java)\n      )\n    )\n  }\n}\n"
  },
  {
    "path": "android/entityextraction/app/src/main/java/com/google/mlkit/samples/nl/entityextraction/java/MainActivityJava.java",
    "content": "package com.google.mlkit.samples.nl.entityextraction.java;\n\nimport static com.google.mlkit.nl.entityextraction.DateTimeEntity.GRANULARITY_DAY;\nimport static com.google.mlkit.nl.entityextraction.DateTimeEntity.GRANULARITY_HOUR;\nimport static com.google.mlkit.nl.entityextraction.DateTimeEntity.GRANULARITY_MINUTE;\nimport static com.google.mlkit.nl.entityextraction.DateTimeEntity.GRANULARITY_MONTH;\nimport static com.google.mlkit.nl.entityextraction.DateTimeEntity.GRANULARITY_SECOND;\nimport static com.google.mlkit.nl.entityextraction.DateTimeEntity.GRANULARITY_WEEK;\nimport static com.google.mlkit.nl.entityextraction.DateTimeEntity.GRANULARITY_YEAR;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.telephony.PhoneNumberUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.TextView;\nimport android.widget.Toast;\nimport androidx.annotation.NonNull;\nimport com.google.mlkit.nl.entityextraction.DateTimeEntity;\nimport com.google.mlkit.nl.entityextraction.DateTimeEntity.DateTimeGranularity;\nimport com.google.mlkit.nl.entityextraction.Entity;\nimport com.google.mlkit.nl.entityextraction.EntityAnnotation;\nimport com.google.mlkit.nl.entityextraction.EntityExtraction;\nimport com.google.mlkit.nl.entityextraction.EntityExtractionParams;\nimport com.google.mlkit.nl.entityextraction.EntityExtractor;\nimport com.google.mlkit.nl.entityextraction.EntityExtractorOptions;\nimport com.google.mlkit.nl.entityextraction.EntityExtractorOptions.ModelIdentifier;\nimport com.google.mlkit.nl.entityextraction.FlightNumberEntity;\nimport com.google.mlkit.nl.entityextraction.IbanEntity;\nimport com.google.mlkit.nl.entityextraction.MoneyEntity;\nimport com.google.mlkit.nl.entityextraction.PaymentCardEntity;\nimport com.google.mlkit.nl.entityextraction.TrackingNumberEntity;\nimport com.google.mlkit.samples.nl.entityextraction.R;\nimport java.text.DateFormat;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\n\n/** Default launcher activity. */\npublic class MainActivityJava extends AppCompatActivity {\n\n  private static final String TAG = \"MainActivityJava\";\n  private static final String CURRENT_MODEL_KEY = \"current_model_key\";\n  public static final int REQUEST_CODE = 1;\n\n  @ModelIdentifier private String currentModel = EntityExtractorOptions.ENGLISH;\n  private EntityExtractor entityExtractor;\n  private TextView currentModelView;\n  private EditText input;\n  private TextView output;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    if (savedInstanceState != null) {\n      currentModel =\n          savedInstanceState.getString(CURRENT_MODEL_KEY, EntityExtractorOptions.ENGLISH);\n    }\n    setContentView(R.layout.activity_main);\n\n    EntityExtractorOptions options = new EntityExtractorOptions.Builder(currentModel).build();\n    entityExtractor = EntityExtraction.getClient(options);\n    getLifecycle().addObserver(entityExtractor);\n\n    currentModelView = findViewById(R.id.current_model);\n    currentModelView.setText(\n        getString(R.string.current_model, currentModel.toUpperCase(Locale.US)));\n    TextView currentLocaleView = findViewById(R.id.current_locale);\n    currentLocaleView.setText(getString(R.string.current_locale, Locale.getDefault()));\n    input = findViewById(R.id.text_input);\n    output = findViewById(R.id.output);\n    Button extractionButton = findViewById(R.id.button);\n\n    extractionButton.setOnClickListener(\n        v -> {\n          String newInput = input.getText().toString();\n          if (newInput.isEmpty()) {\n            Toast.makeText(MainActivityJava.this, R.string.empty_input, Toast.LENGTH_LONG).show();\n            return;\n          }\n          extractEntities(newInput);\n        });\n  }\n\n  public void extractEntities(final String input) {\n    output.setText(R.string.wait_message);\n\n    entityExtractor\n        .downloadModelIfNeeded()\n        .onSuccessTask(ignored -> entityExtractor.annotate(getEntityExtractionParams(input)))\n        .addOnFailureListener(\n            e -> {\n              Log.e(TAG, \"Annotation failed\", e);\n              output.setText(getString(R.string.entity_extraction_error));\n            })\n        .addOnSuccessListener(\n            result -> {\n              if (result.isEmpty()) {\n                output.setText(getString(R.string.no_entity_detected));\n                return;\n              }\n              output.setText(getString(R.string.entities_detected));\n              output.append(\"\\n\");\n              for (EntityAnnotation entityAnnotation : result) {\n                List<Entity> entities = entityAnnotation.getEntities();\n                String annotatedText = entityAnnotation.getAnnotatedText();\n                for (Entity entity : entities) {\n                  displayEntityInfo(annotatedText, entity);\n                  output.append(\"\\n\");\n                }\n              }\n            });\n  }\n\n  private static EntityExtractionParams getEntityExtractionParams(String input) {\n    return new EntityExtractionParams.Builder(input).build();\n  }\n\n  @Override\n  public boolean onCreateOptionsMenu(Menu menu) {\n    getMenuInflater().inflate(R.menu.menu_choose_model, menu);\n    return true;\n  }\n\n  @Override\n  public boolean onOptionsItemSelected(MenuItem item) {\n    if (item.getItemId() == R.id.action_btn) {\n      startActivityForResult(new Intent(this, ModelsActivityJava.class), REQUEST_CODE);\n      return true;\n    }\n    return super.onOptionsItemSelected(item);\n  }\n\n  @Override\n  public void onActivityResult(int request, int result, Intent intent) {\n    super.onActivityResult(request, result, intent);\n    if (request == REQUEST_CODE && result == RESULT_OK) {\n      output.setText(\"\");\n      String newModel = intent.getStringExtra(ModelsActivityJava.MODEL_KEY);\n      currentModel = newModel;\n      currentModelView.setText(\n          getString(R.string.current_model, currentModel.toUpperCase(Locale.US)));\n      entityExtractor =\n          EntityExtraction.getClient(new EntityExtractorOptions.Builder(newModel).build());\n    }\n  }\n\n  @Override\n  public void onSaveInstanceState(@NonNull Bundle outState) {\n    super.onSaveInstanceState(outState);\n    outState.putString(CURRENT_MODEL_KEY, currentModel);\n  }\n\n  private void displayEntityInfo(String annotatedText, Entity entity) {\n    switch (entity.getType()) {\n      case Entity.TYPE_ADDRESS:\n        displayAddressInfo(annotatedText);\n        break;\n      case Entity.TYPE_DATE_TIME:\n        displayDateTimeInfo(entity, annotatedText);\n        break;\n      case Entity.TYPE_EMAIL:\n        displayEmailInfo(annotatedText);\n        break;\n      case Entity.TYPE_FLIGHT_NUMBER:\n        displayFlightNoInfo(entity, annotatedText);\n        break;\n      case Entity.TYPE_IBAN:\n        displayIbanInfo(entity, annotatedText);\n        break;\n      case Entity.TYPE_ISBN:\n        displayIsbnInfo(entity, annotatedText);\n        break;\n      case Entity.TYPE_MONEY:\n        displayMoneyEntityInfo(entity, annotatedText);\n        break;\n      case Entity.TYPE_PAYMENT_CARD:\n        displayPaymentCardInfo(entity, annotatedText);\n        break;\n      case Entity.TYPE_PHONE:\n        displayPhoneInfo(annotatedText);\n        break;\n      case Entity.TYPE_TRACKING_NUMBER:\n        displayTrackingNoInfo(entity, annotatedText);\n        break;\n      case Entity.TYPE_URL:\n        displayUrlInfo(annotatedText);\n        break;\n      default:\n        displayDefaultInfo(annotatedText);\n        break;\n    }\n  }\n\n  private void displayAddressInfo(String annotatedText) {\n    output.append(getString(R.string.address_entity_info, annotatedText));\n  }\n\n  private void displayEmailInfo(String annotatedText) {\n    output.append(getString(R.string.email_entity_info, annotatedText));\n  }\n\n  private void displayPhoneInfo(String annotatedText) {\n    output.append(\n        getString(\n            R.string.phone_entity_info_formatted,\n            annotatedText,\n            PhoneNumberUtils.formatNumber(annotatedText)));\n  }\n\n  private void displayDefaultInfo(String annotatedText) {\n    output.append(getString(R.string.unknown_entity_info, annotatedText));\n  }\n\n  private void displayUrlInfo(String annotatedText) {\n    output.append(getString(R.string.url_entity_info, annotatedText));\n  }\n\n  private void displayDateTimeInfo(Entity entity, String annotatedText) {\n    output.append(\n        getString(\n            R.string.date_time_entity_info,\n            annotatedText,\n            DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG)\n                .format(new Date(entity.asDateTimeEntity().getTimestampMillis())),\n            convertGranularityToString(entity)));\n  }\n\n  private String convertGranularityToString(Entity entity) {\n    DateTimeEntity dateTimeEntity = entity.asDateTimeEntity();\n    @DateTimeGranularity int granularity = dateTimeEntity.getDateTimeGranularity();\n    switch (granularity) {\n      case GRANULARITY_YEAR:\n        return getString(R.string.granularity_year);\n      case GRANULARITY_MONTH:\n        return getString(R.string.granularity_month);\n      case GRANULARITY_WEEK:\n        return getString(R.string.granularity_week);\n      case GRANULARITY_DAY:\n        return getString(R.string.granularity_day);\n      case GRANULARITY_HOUR:\n        return getString(R.string.granularity_hour);\n      case GRANULARITY_MINUTE:\n        return getString(R.string.granularity_minute);\n      case GRANULARITY_SECOND:\n        return getString(R.string.granularity_second);\n      default:\n        return getString(R.string.granularity_unknown);\n    }\n  }\n\n  private void displayTrackingNoInfo(Entity entity, String annotatedText) {\n    TrackingNumberEntity trackingNumberEntity = entity.asTrackingNumberEntity();\n    output.append(\n        getString(\n            R.string.tracking_number_entity_info,\n            annotatedText,\n            trackingNumberEntity.getParcelCarrier(),\n            trackingNumberEntity.getParcelTrackingNumber()));\n  }\n\n  private void displayPaymentCardInfo(Entity entity, String annotatedText) {\n    PaymentCardEntity paymentCardEntity = entity.asPaymentCardEntity();\n    output.append(\n        getString(\n            R.string.payment_card_entity_info,\n            annotatedText,\n            paymentCardEntity.getPaymentCardNetwork(),\n            paymentCardEntity.getPaymentCardNumber()));\n  }\n\n  private void displayIsbnInfo(Entity entity, String annotatedText) {\n    output.append(\n        getString(R.string.isbn_entity_info, annotatedText, entity.asIsbnEntity().getIsbn()));\n  }\n\n  private void displayIbanInfo(Entity entity, String annotatedText) {\n    IbanEntity ibanEntity = entity.asIbanEntity();\n    output.append(\n        getString(\n            R.string.iban_entity_info,\n            annotatedText,\n            ibanEntity.getIban(),\n            ibanEntity.getIbanCountryCode()));\n  }\n\n  private void displayFlightNoInfo(Entity entity, String annotatedText) {\n    FlightNumberEntity flightNumberEntity = entity.asFlightNumberEntity();\n    output.append(\n        getString(\n            R.string.flight_number_entity_info,\n            annotatedText,\n            flightNumberEntity.getAirlineCode(),\n            flightNumberEntity.getFlightNumber()));\n  }\n\n  private void displayMoneyEntityInfo(Entity entity, String annotatedText) {\n    MoneyEntity moneyEntity = entity.asMoneyEntity();\n    output.append(\n        getString(\n            R.string.money_entity_info,\n            annotatedText,\n            moneyEntity.getUnnormalizedCurrency(),\n            moneyEntity.getIntegerPart(),\n            moneyEntity.getFractionalPart()));\n  }\n}\n"
  },
  {
    "path": "android/entityextraction/app/src/main/java/com/google/mlkit/samples/nl/entityextraction/java/ModelsActivityJava.java",
    "content": "package com.google.mlkit.samples.nl.entityextraction.java;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.material.snackbar.Snackbar;\nimport com.google.mlkit.common.model.DownloadConditions;\nimport com.google.mlkit.common.model.RemoteModelManager;\nimport com.google.mlkit.nl.entityextraction.EntityExtractionRemoteModel;\nimport com.google.mlkit.nl.entityextraction.EntityExtractorOptions;\nimport com.google.mlkit.samples.nl.entityextraction.R;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\n\n/** Activity for user to select models. */\npublic class ModelsActivityJava extends AppCompatActivity {\n\n  private static final String TAG = \"ModelsActivityJava\";\n  public static final String MODEL_KEY = \"model\";\n\n  private ListView listView;\n  private final RemoteModelManager remoteModelManager = RemoteModelManager.getInstance();\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_models);\n\n    listView = findViewById(R.id.models_list_view);\n    List</* @ModelIdentifier */ String> languages = EntityExtractorOptions.getAllModelIdentifiers();\n    LanguageAdapter languageAdapter = new LanguageAdapter(languages);\n    listView.setAdapter(languageAdapter);\n\n    listView.setOnItemClickListener(\n        (parent, view, position, id) -> {\n          Intent intent = new Intent(ModelsActivityJava.this, MainActivityJava.class);\n          intent.putExtra(MODEL_KEY, listView.getItemAtPosition(position).toString());\n          setResult(RESULT_OK, intent);\n          finish();\n        });\n  }\n\n  class LanguageAdapter extends BaseAdapter {\n\n    private final List<String> languageList;\n    private final Set<String> downloadedModels = new HashSet<>();\n    private final List<String> downloadingModels = new ArrayList<>();\n\n    @Nullable private Snackbar downloadsSnackbar;\n\n    public LanguageAdapter(List<String> languageList) {\n      this.languageList = languageList;\n      Task<Set<EntityExtractionRemoteModel>> downloadedModelsTask =\n          remoteModelManager.getDownloadedModels(EntityExtractionRemoteModel.class);\n      downloadedModelsTask\n          .addOnFailureListener(e -> Log.w(TAG, \"DownloadedModels failed with exception\", e))\n          .addOnSuccessListener(\n              models -> {\n                downloadedModels.clear();\n                for (EntityExtractionRemoteModel model : models) {\n                  downloadedModels.add(model.getModelIdentifier());\n                }\n                notifyDataSetChanged();\n              });\n    }\n\n    @Override\n    public int getCount() {\n      return languageList.size();\n    }\n\n    @Override\n    public String getItem(int position) {\n      return languageList.get(position);\n    }\n\n    @Override\n    public long getItemId(int position) {\n      return position;\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n      if (convertView == null) {\n        convertView =\n            LayoutInflater.from(ModelsActivityJava.this).inflate(R.layout.list_item, parent, false);\n      }\n      TextView textView = convertView.findViewById(R.id.text_view_item);\n      String modelIdentifier = getItem(position);\n      textView.setText(modelIdentifier);\n      ImageView imageView = convertView.findViewById(R.id.image_view_item);\n\n      EntityExtractionRemoteModel remoteModel =\n          new EntityExtractionRemoteModel.Builder(modelIdentifier).build();\n      if (downloadedModels.contains(modelIdentifier)) {\n        imageView.setImageResource(R.drawable.ic_baseline_delete_gray_32);\n        imageView.setOnClickListener(\n            view ->\n                remoteModelManager\n                    .deleteDownloadedModel(remoteModel)\n                    .addOnFailureListener(\n                        e -> Log.w(TAG, \"Deleting model failed with exception\", e))\n                    .addOnSuccessListener(\n                        aVoid -> {\n                          downloadedModels.remove(modelIdentifier);\n                          notifyDataSetChanged();\n                        }));\n      } else {\n        imageView.setImageResource(R.drawable.ic_baseline_get_app_gray_32);\n        imageView.setOnClickListener(\n            view -> {\n              downloadingModels.add(modelIdentifier);\n              updateSnackbar();\n              remoteModelManager\n                  .download(remoteModel, new DownloadConditions.Builder().build())\n                  .addOnFailureListener(\n                      e -> Log.w(TAG, \"Downloading model failed with exception\", e))\n                  .addOnSuccessListener(\n                      aVoid -> {\n                        downloadedModels.add(modelIdentifier);\n                        notifyDataSetChanged();\n                      })\n                  .addOnCompleteListener(\n                      r -> {\n                        downloadingModels.remove(modelIdentifier);\n                        updateSnackbar();\n                      });\n            });\n      }\n      return convertView;\n    }\n\n    private void updateSnackbar() {\n      if (downloadingModels.isEmpty()) {\n        if (downloadsSnackbar != null) {\n          downloadsSnackbar.dismiss();\n        }\n        return;\n      }\n      if (downloadsSnackbar == null) {\n        downloadsSnackbar = Snackbar.make(listView, \"\", Snackbar.LENGTH_INDEFINITE);\n      }\n      downloadsSnackbar.setText(getSnackbarMessage());\n      downloadsSnackbar.show();\n    }\n\n    private String getSnackbarMessage() {\n      return getResources()\n          .getQuantityString(\n              R.plurals.snackbar_message,\n              downloadingModels.size(),\n              getFormattedListOfDownloadingModels());\n    }\n\n    private String getFormattedListOfDownloadingModels() {\n      List<String> uppercasedDownloadingModels = new ArrayList<>();\n      for (String downloadingModel : downloadingModels) {\n        uppercasedDownloadingModels.add(downloadingModel.toUpperCase(Locale.US));\n      }\n      return TextUtils.join(\", \", uppercasedDownloadingModels);\n    }\n  }\n}\n"
  },
  {
    "path": "android/entityextraction/app/src/main/java/com/google/mlkit/samples/nl/entityextraction/kotlin/MainActivityKotlin.kt",
    "content": "package com.google.mlkit.samples.nl.entityextraction.kotlin\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.telephony.PhoneNumberUtils\nimport android.util.Log\nimport android.view.Menu\nimport android.view.MenuItem\nimport android.widget.Button\nimport android.widget.EditText\nimport android.widget.TextView\nimport android.widget.Toast\nimport com.google.mlkit.nl.entityextraction.DateTimeEntity\nimport com.google.mlkit.nl.entityextraction.Entity\nimport com.google.mlkit.nl.entityextraction.EntityAnnotation\nimport com.google.mlkit.nl.entityextraction.EntityExtraction\nimport com.google.mlkit.nl.entityextraction.EntityExtractionParams\nimport com.google.mlkit.nl.entityextraction.EntityExtractor\nimport com.google.mlkit.nl.entityextraction.EntityExtractorOptions\nimport com.google.mlkit.nl.entityextraction.EntityExtractorOptions.ModelIdentifier\nimport com.google.mlkit.samples.nl.entityextraction.R\nimport java.text.DateFormat\nimport java.util.Date\nimport java.util.Locale\n\n/** Default launcher activity. */\nclass MainActivityKotlin : AppCompatActivity() {\n\n  companion object {\n    private const val TAG = \"MainActivityKotlin\"\n    private const val CURRENT_MODEL_KEY = \"current_model_key\"\n    const val REQUEST_CODE = 1\n\n    private fun getEntityExtractionParams(input: String): EntityExtractionParams {\n      return EntityExtractionParams.Builder(input).build()\n    }\n  }\n\n  @ModelIdentifier private var currentModel: String = EntityExtractorOptions.ENGLISH\n\n  private lateinit var entityExtractor: EntityExtractor\n  private lateinit var currentModelView: TextView\n  private lateinit var input: EditText\n  private lateinit var output: TextView\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_main)\n\n    currentModel =\n      savedInstanceState?.getString(CURRENT_MODEL_KEY, EntityExtractorOptions.ENGLISH)\n        ?: EntityExtractorOptions.ENGLISH\n\n    val options = EntityExtractorOptions.Builder(currentModel).build()\n    entityExtractor = EntityExtraction.getClient(options)\n    lifecycle.addObserver(entityExtractor)\n\n    currentModelView = findViewById(R.id.current_model)\n    currentModelView.text = getString(R.string.current_model, currentModel.uppercase(Locale.US))\n    val currentLocaleView: TextView = findViewById(R.id.current_locale)\n    currentLocaleView.text = getString(R.string.current_locale, Locale.getDefault())\n    input = findViewById(R.id.text_input)\n    output = findViewById(R.id.output)\n\n    findViewById<Button>(R.id.button).setOnClickListener {\n      val newInput = input.text.toString()\n      if (newInput.isEmpty()) {\n        Toast.makeText(this@MainActivityKotlin, R.string.empty_input, Toast.LENGTH_LONG).show()\n        return@setOnClickListener\n      }\n      extractEntities(newInput)\n    }\n  }\n\n  fun extractEntities(input: String) {\n    output.setText(R.string.wait_message)\n    entityExtractor\n      .downloadModelIfNeeded()\n      .onSuccessTask { entityExtractor.annotate(getEntityExtractionParams(input)) }\n      .addOnFailureListener { e: Exception? ->\n        Log.e(TAG, \"Annotation failed\", e)\n        output.text = getString(R.string.entity_extraction_error)\n      }\n      .addOnSuccessListener { result: List<EntityAnnotation> ->\n        if (result.isEmpty()) {\n          output.text = getString(R.string.no_entity_detected)\n          return@addOnSuccessListener\n        }\n        output.text = getString(R.string.entities_detected).plus(\"\\n\")\n        for (entityAnnotation in result) {\n          val entities = entityAnnotation.entities\n          val annotatedText = entityAnnotation.annotatedText\n          for (entity in entities) {\n            displayEntityInfo(annotatedText, entity)\n            output.append(\"\\n\")\n          }\n        }\n      }\n  }\n\n  override fun onCreateOptionsMenu(menu: Menu): Boolean {\n    menuInflater.inflate(R.menu.menu_choose_model, menu)\n    return true\n  }\n\n  override fun onOptionsItemSelected(item: MenuItem): Boolean {\n    if (item.itemId == R.id.action_btn) {\n      startActivityForResult(Intent(this, ModelsActivityKotlin::class.java), REQUEST_CODE)\n      return true\n    }\n    return super.onOptionsItemSelected(item)\n  }\n\n  override fun onSaveInstanceState(bundle: Bundle) {\n    super.onSaveInstanceState(bundle)\n    bundle.putString(CURRENT_MODEL_KEY, currentModel)\n  }\n\n  public override fun onActivityResult(request: Int, result: Int, intent: Intent?) {\n    super.onActivityResult(request, result, intent)\n    if (request == REQUEST_CODE && result == Activity.RESULT_OK) {\n      output.text = \"\"\n      val newModel = intent!!.getStringExtra(ModelsActivityKotlin.MODEL_KEY)\n      if (newModel != null) {\n        currentModel = newModel\n      }\n      currentModelView.text = getString(R.string.current_model, currentModel.uppercase(Locale.US))\n      entityExtractor =\n        EntityExtraction.getClient(EntityExtractorOptions.Builder(currentModel).build())\n    }\n  }\n\n  private fun displayEntityInfo(annotatedText: String, entity: Entity) {\n    when (entity.type) {\n      Entity.TYPE_ADDRESS -> displayAddressInfo(annotatedText)\n      Entity.TYPE_DATE_TIME -> displayDateTimeInfo(entity, annotatedText)\n      Entity.TYPE_EMAIL -> displayEmailInfo(annotatedText)\n      Entity.TYPE_FLIGHT_NUMBER -> displayFlightNoInfo(entity, annotatedText)\n      Entity.TYPE_IBAN -> displayIbanInfo(entity, annotatedText)\n      Entity.TYPE_ISBN -> displayIsbnInfo(entity, annotatedText)\n      Entity.TYPE_MONEY -> displayMoneyEntityInfo(entity, annotatedText)\n      Entity.TYPE_PAYMENT_CARD -> displayPaymentCardInfo(entity, annotatedText)\n      Entity.TYPE_PHONE -> displayPhoneInfo(annotatedText)\n      Entity.TYPE_TRACKING_NUMBER -> displayTrackingNoInfo(entity, annotatedText)\n      Entity.TYPE_URL -> displayUrlInfo(annotatedText)\n      else -> displayDefaultInfo(annotatedText)\n    }\n  }\n\n  private fun displayAddressInfo(annotatedText: String) {\n    output.append(getString(R.string.address_entity_info, annotatedText))\n  }\n\n  private fun displayEmailInfo(annotatedText: String) {\n    output.append(getString(R.string.email_entity_info, annotatedText))\n  }\n\n  private fun displayPhoneInfo(annotatedText: String) {\n    output.append(\n      getString(\n        R.string.phone_entity_info_formatted,\n        annotatedText,\n        PhoneNumberUtils.formatNumber(annotatedText),\n      )\n    )\n  }\n\n  private fun displayDefaultInfo(annotatedText: String) {\n    output.append(getString(R.string.unknown_entity_info, annotatedText))\n  }\n\n  private fun displayUrlInfo(annotatedText: String) {\n    output.append(getString(R.string.url_entity_info, annotatedText))\n  }\n\n  private fun displayDateTimeInfo(entity: Entity, annotatedText: String) {\n    val dateTimeFormat =\n      DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG)\n        .format(Date(entity.asDateTimeEntity()!!.timestampMillis))\n    output.append(\n      getString(\n        R.string.date_time_entity_info,\n        annotatedText,\n        dateTimeFormat,\n        convertGranularityToString(entity),\n      )\n    )\n  }\n\n  private fun convertGranularityToString(entity: Entity): String {\n    val dateTimeEntity = entity.asDateTimeEntity()\n    return when (dateTimeEntity!!.dateTimeGranularity) {\n      DateTimeEntity.GRANULARITY_YEAR -> getString(R.string.granularity_year)\n      DateTimeEntity.GRANULARITY_MONTH -> getString(R.string.granularity_month)\n      DateTimeEntity.GRANULARITY_WEEK -> getString(R.string.granularity_week)\n      DateTimeEntity.GRANULARITY_DAY -> getString(R.string.granularity_day)\n      DateTimeEntity.GRANULARITY_HOUR -> getString(R.string.granularity_hour)\n      DateTimeEntity.GRANULARITY_MINUTE -> getString(R.string.granularity_minute)\n      DateTimeEntity.GRANULARITY_SECOND -> getString(R.string.granularity_second)\n      else -> getString(R.string.granularity_unknown)\n    }\n  }\n\n  private fun displayTrackingNoInfo(entity: Entity, annotatedText: String) {\n    val trackingNumberEntity = entity.asTrackingNumberEntity()\n    output.append(\n      getString(\n        R.string.tracking_number_entity_info,\n        annotatedText,\n        trackingNumberEntity!!.parcelCarrier,\n        trackingNumberEntity.parcelTrackingNumber,\n      )\n    )\n  }\n\n  private fun displayPaymentCardInfo(entity: Entity, annotatedText: String) {\n    val paymentCardEntity = entity.asPaymentCardEntity()\n    output.append(\n      getString(\n        R.string.payment_card_entity_info,\n        annotatedText,\n        paymentCardEntity!!.paymentCardNetwork,\n        paymentCardEntity.paymentCardNumber,\n      )\n    )\n  }\n\n  private fun displayIsbnInfo(entity: Entity, annotatedText: String) {\n    output.append(getString(R.string.isbn_entity_info, annotatedText, entity.asIsbnEntity()!!.isbn))\n  }\n\n  private fun displayIbanInfo(entity: Entity, annotatedText: String) {\n    val ibanEntity = entity.asIbanEntity()\n    output.append(\n      getString(\n        R.string.iban_entity_info,\n        annotatedText,\n        ibanEntity!!.iban,\n        ibanEntity.ibanCountryCode,\n      )\n    )\n  }\n\n  private fun displayFlightNoInfo(entity: Entity, annotatedText: String) {\n    val flightNumberEntity = entity.asFlightNumberEntity()\n    output.append(\n      getString(\n        R.string.flight_number_entity_info,\n        annotatedText,\n        flightNumberEntity!!.airlineCode,\n        flightNumberEntity.flightNumber,\n      )\n    )\n  }\n\n  private fun displayMoneyEntityInfo(entity: Entity, annotatedText: String) {\n    val moneyEntity = entity.asMoneyEntity()\n    output.append(\n      getString(\n        R.string.money_entity_info,\n        annotatedText,\n        moneyEntity!!.unnormalizedCurrency,\n        moneyEntity.integerPart,\n        moneyEntity.fractionalPart,\n      )\n    )\n  }\n}\n"
  },
  {
    "path": "android/entityextraction/app/src/main/java/com/google/mlkit/samples/nl/entityextraction/kotlin/ModelsActivityKotlin.kt",
    "content": "package com.google.mlkit.samples.nl.entityextraction.kotlin\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.AdapterView.OnItemClickListener\nimport android.widget.BaseAdapter\nimport android.widget.ImageView\nimport android.widget.ListView\nimport android.widget.TextView\nimport com.google.android.material.snackbar.Snackbar\nimport com.google.mlkit.common.model.DownloadConditions\nimport com.google.mlkit.common.model.RemoteModelManager\nimport com.google.mlkit.nl.entityextraction.EntityExtractionRemoteModel\nimport com.google.mlkit.nl.entityextraction.EntityExtractorOptions\nimport com.google.mlkit.samples.nl.entityextraction.R\nimport java.util.Locale\n\nclass ModelsActivityKotlin : AppCompatActivity() {\n\n  companion object {\n    private const val TAG = \"ModelsActivityKotlin\"\n    const val MODEL_KEY = \"model\"\n  }\n\n  private lateinit var listView: ListView\n  private val remoteModelManager = RemoteModelManager.getInstance()\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_models)\n\n    listView = findViewById(R.id.models_list_view)\n    val languages = EntityExtractorOptions.getAllModelIdentifiers()\n    val languageAdapter = LanguageAdapter(languages)\n    listView.adapter = languageAdapter\n\n    listView.onItemClickListener = OnItemClickListener { _, _, position, _ ->\n      val intent = Intent(this@ModelsActivityKotlin, MainActivityKotlin::class.java)\n      intent.putExtra(MODEL_KEY, listView.getItemAtPosition(position).toString())\n      setResult(Activity.RESULT_OK, intent)\n      finish()\n    }\n  }\n\n  internal inner class LanguageAdapter(private val languageList: List<String>) : BaseAdapter() {\n    init {\n      val downloadedModelsTask =\n        remoteModelManager.getDownloadedModels(EntityExtractionRemoteModel::class.java)\n      downloadedModelsTask\n        .addOnFailureListener { e: Exception? ->\n          Log.w(TAG, \"DownloadedModels failed with exception\", e)\n        }\n        .addOnSuccessListener { models: Set<EntityExtractionRemoteModel> ->\n          downloadedModels.clear()\n          for (model in models) {\n            downloadedModels.add(model.modelIdentifier)\n          }\n          notifyDataSetChanged()\n        }\n    }\n\n    private val downloadedModels: MutableSet<String> = HashSet()\n    private val downloadingModels: MutableList<String> = ArrayList()\n    private var downloadsSnackbar: Snackbar? = null\n\n    override fun getCount(): Int {\n      return languageList.size\n    }\n\n    override fun getItem(position: Int): String {\n      return languageList[position]\n    }\n\n    override fun getItemId(position: Int): Long {\n      return position.toLong()\n    }\n\n    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {\n      var view = convertView\n      if (view == null) {\n        view =\n          LayoutInflater.from(this@ModelsActivityKotlin).inflate(R.layout.list_item, parent, false)\n      }\n      val textView = view!!.findViewById<TextView>(R.id.text_view_item)\n      val modelIdentifier = getItem(position)\n      textView.text = modelIdentifier\n      val imageView = view.findViewById<ImageView>(R.id.image_view_item)\n\n      val remoteModel = EntityExtractionRemoteModel.Builder(modelIdentifier).build()\n      if (downloadedModels.contains(modelIdentifier)) {\n        imageView.setImageResource(R.drawable.ic_baseline_delete_gray_32)\n        imageView.setOnClickListener {\n          remoteModelManager\n            .deleteDownloadedModel(remoteModel)\n            .addOnFailureListener { e: Exception? ->\n              Log.w(TAG, \"Deleting model failed with exception\", e)\n            }\n            .addOnSuccessListener {\n              downloadedModels.remove(modelIdentifier)\n              notifyDataSetChanged()\n            }\n        }\n      } else {\n        imageView.setImageResource(R.drawable.ic_baseline_get_app_gray_32)\n        imageView.setOnClickListener {\n          downloadingModels.add(modelIdentifier)\n          updateSnackbar()\n          remoteModelManager\n            .download(remoteModel, DownloadConditions.Builder().build())\n            .addOnFailureListener { e: Exception? ->\n              Log.w(TAG, \"Downloading model failed with exception\", e)\n            }\n            .addOnSuccessListener {\n              downloadedModels.add(modelIdentifier)\n              notifyDataSetChanged()\n            }\n            .addOnCompleteListener {\n              downloadingModels.remove(modelIdentifier)\n              updateSnackbar()\n            }\n        }\n      }\n      return view\n    }\n\n    private fun updateSnackbar() {\n      if (downloadingModels.isEmpty()) {\n        downloadsSnackbar?.dismiss()\n        return\n      }\n      downloadsSnackbar =\n        (downloadsSnackbar ?: Snackbar.make(listView, \"\", Snackbar.LENGTH_INDEFINITE)).apply {\n          setText(getSnackbarMessage())\n          show()\n        }\n    }\n\n    private fun getSnackbarMessage(): String =\n      resources.getQuantityString(\n        R.plurals.snackbar_message,\n        downloadingModels.size,\n        getFormattedListOfDownloadingModels(),\n      )\n\n    private fun getFormattedListOfDownloadingModels(): String {\n      return downloadingModels.map { it.uppercase(Locale.US) }.joinToString { \", \" }\n    }\n  }\n}\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/drawable/ic_baseline_delete_gray_32.xml",
    "content": "<vector android:height=\"32dp\" android:tint=\"#606060\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"32dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#606060\" android:pathData=\"M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z\"/>\n</vector>\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/drawable/ic_baseline_get_app_gray_32.xml",
    "content": "<vector android:height=\"32dp\" android:tint=\"#606060\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"32dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#666666\" android:pathData=\"M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z\"/>\n</vector>\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/drawable/ic_baseline_get_app_white_32.xml",
    "content": "<vector android:height=\"32dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"32dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#FFFFFF\" android:pathData=\"M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z\"/>\n</vector>\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportWidth=\"172.43\"\n    android:viewportHeight=\"129.06\">\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#66ff99\"\n      android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#66ff99\"\n      android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".java.MainActivityJava\">\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:paddingLeft=\"16dp\"\n      android:paddingRight=\"16dp\"\n      android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/current_model\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"16dp\"\n        android:text=\"@string/current_model\" />\n\n    <TextView\n        android:id=\"@+id/current_locale\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"4dp\"\n        android:text=\"@string/current_locale\" />\n\n    <EditText\n        android:id=\"@+id/text_input\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"16dp\"\n        android:layout_marginBottom=\"24dp\"\n        android:freezesText=\"true\"\n        android:hint=\"@string/input\"\n        android:inputType=\"text\" />\n    <Button\n        android:id=\"@+id/button\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"40dp\"\n        android:text=\"@string/entity_extraction_trigger_btn\" />\n    <TextView\n        android:id=\"@+id/output\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:freezesText=\"true\"\n        android:singleLine=\"false\" />\n  </LinearLayout>\n</ScrollView>\n\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/layout/activity_models.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n  <TextView\n      android:id=\"@+id/myTextView\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:text=\"@string/models_view\"\n      android:textStyle=\"bold\"\n      android:textSize=\"24sp\"\n      android:gravity=\"center\"\n      android:paddingVertical=\"16dp\" />\n\n  <ListView\n      android:id=\"@+id/models_list_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"/>\n</LinearLayout>\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/layout/list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"horizontal\">\n  <TextView\n      android:id=\"@+id/text_view_item\"\n      android:layout_margin=\"24dp\"\n      android:layout_width=\"0dp\"\n      android:layout_weight=\"1\"\n      android:layout_height=\"wrap_content\"\n      android:textAllCaps=\"true\"\n      android:textSize=\"16sp\"\n      android:layout_gravity=\"center_vertical\"/>\n  <ImageView\n      android:id=\"@+id/image_view_item\"\n      android:layout_width=\"32dp\"\n      android:layout_height=\"32dp\"\n      android:layout_gravity=\"center_vertical\"\n      android:layout_marginLeft=\"24dp\"\n      android:layout_marginRight=\"24dp\" />\n</LinearLayout>\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/menu/menu_choose_model.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n  <item\n      android:id=\"@+id/action_btn\"\n      android:icon=\"@drawable/ic_baseline_get_app_white_32\"\n      android:title=\"@string/choose_model_btn\"\n      app:showAsAction=\"always\" />\n\n</menu>\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"colorPrimary\">@color/blue</color>\n  <color name=\"colorPrimaryDark\">@color/darkBlue</color>\n  <color name=\"colorAccent\">@color/red</color>\n\n  <color name=\"blue\">#3681E6</color>\n  <color name=\"darkBlue\">#2F5FC0</color>\n  <color name=\"red\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/values/strings.xml",
    "content": "<resources>\n  <!-- Application name -->\n  <string name=\"app_name\">MLKit-EntityExtraction</string>\n  <string name=\"current_model\">Current model: %s</string>\n  <!-- String to show current locale [CHAR_LIMIT=NONE] -->\n  <string name=\"current_locale\">Current locale: %s</string>\n  <!-- Placeholder for input box -->\n  <string name=\"input\">Enter your input</string>\n  <!-- Action string for entity extraction button -->\n  <string name=\"entity_extraction_trigger_btn\">Trigger Entity Extraction</string>\n  <!-- Message to be displayed for EE triggered with empty input -->\n  <string name=\"empty_input\">Please enter a text.</string>\n  <!-- Placeholder for EE error -->\n  <string name=\"entity_extraction_error\">Annotation failed.</string>\n  <!-- Waiting message for the output box once EE is triggered -->\n  <string name=\"wait_message\">Working…\\nMake sure network is on for the first time to download model</string>\n  <!-- String of info to be displayed for a money type entity -->\n  <string name=\"money_entity_info\">Money entity detected: %1$s.\n    \\nCurrency: %2$s, integer: %3$d, decimal: %4$d.\\n</string>\n  <!-- String of info to be displayed for a flight number type entity -->\n  <string name=\"flight_number_entity_info\">Flight number entity detected: %1$s.\n    \\nAirline code: %2$s, flight number: %3$s.\\n</string>\n  <!-- String of info to be displayed for an IBAN type entity -->\n  <string name=\"iban_entity_info\">Iban entity detected: %1$s.\n    \\nIban country code: %2$s, iban: %3$s.\\n</string>\n  <!-- String of info to be displayed for an ISBN type entity -->\n  <string name=\"isbn_entity_info\">Isbn entity detected: %1$s.\\nIsbn:  %2$s.\\n</string>\n  <!-- String of info to be displayed for a payment card type entity -->\n  <string name=\"payment_card_entity_info\">Payment card entity detected: %1$s.\\n\n    Payment card network: %2$d, payment card number: %3$s.\\n</string>\n  <!-- String of info to be displayed for a tracking number type entity -->\n  <string name=\"tracking_number_entity_info\">Tracking number entity detected: %1$s.\\n\n    Parcel carrier: %2$d, tracking number: %3$s.\\n</string>\n  <!-- String of info to be displayed for a date time type entity -->\n  <string name=\"date_time_entity_info\">Date_time entity detected: %1$s.\n    \\n%2$s (granularity: %3$s).\\n</string>\n  <!-- String of info to be displayed for an address type entity -->\n  <string name=\"address_entity_info\">Address entity detected: %1$s.\\n</string>\n  <!-- String of info to be displayed for a phone number type entity -->\n  <string name=\"phone_entity_info\">Phone number entity detected: %1$s.\\n</string>\n  <!-- String of info to be displayed for a phone number type entity, including formatted phone number -->\n  <string name=\"phone_entity_info_formatted\">Phone number entity detected: %1$s (formatted by libphonenumber: %2$s).\\n</string>\n  <!-- String of info to be displayed for no entities detected -->\n  <string name=\"no_entity_detected\">There are no entities detected.\\n</string>\n  <!-- String of info to be displayed for a URL type entity -->\n  <string name=\"url_entity_info\">URL entity detected: %1$s.\\n</string>\n  <!-- String of info to be displayed for an email type entity -->\n  <string name=\"email_entity_info\">Email entity detected: %1$s.\\n</string>\n  <!-- String of info to be displayed for an unknown type entity -->\n  <string name=\"unknown_entity_info\">Unknown entity detected: %1$s.\\n</string>\n  <!-- Message to be displayed when entities are detected -->\n  <string name=\"entities_detected\">Entities detected:</string>\n  <!-- String representing unknown granularity type, used to construct date_time entity info-->\n  <string name=\"granularity_unknown\">Unknown</string>\n  <!-- String representing year granularity type, used to construct date_time entity info-->\n  <string name=\"granularity_year\">Year</string>\n  <!-- String representing month granularity type, used to construct date_time entity info-->\n  <string name=\"granularity_month\">Month</string>\n  <!-- String representing week granularity type, used to construct date_time entity info-->\n  <string name=\"granularity_week\">Week</string>\n  <!-- String representing day granularity type, used to construct date_time entity info-->\n  <string name=\"granularity_day\">Day</string>\n  <!-- String representing hour granularity type, used to construct date_time entity info-->\n  <string name=\"granularity_hour\">Hour</string>\n  <!-- String representing minute granularity type, used to construct date_time entity info-->\n  <string name=\"granularity_minute\">Minute</string>\n  <!-- String representing second granularity type, used to construct date_time entity info-->\n  <string name=\"granularity_second\">Second</string>\n  <!-- String title for action button that opens models screen-->\n  <string name=\"choose_model_btn\">Choose a model</string>\n  <!-- String title for models list-->\n  <string name=\"models_view\">Choose a model from the list:</string>\n  <!-- String used to display the downloading models list in a snackbar-->\n  <plurals name=\"snackbar_message\">\n    <item quantity=\"one\">Downloading model %1$s</item>\n    <item quantity=\"other\">Downloading models %1$s</item>\n  </plurals>\n</resources>\n\n"
  },
  {
    "path": "android/entityextraction/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n  <!-- Base application theme. -->\n  <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.DarkActionBar\">\n    <!-- Customize your theme here. -->\n    <item name=\"colorPrimary\">@color/blue</item>\n    <item name=\"colorPrimaryDark\">@color/darkBlue</item>\n    <item name=\"colorAccent\">@color/red</item>\n  </style>\n\n</resources>\n"
  },
  {
    "path": "android/entityextraction/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '2.1.0'\n\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:8.10.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        google()\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "android/entityextraction/gradle.properties",
    "content": "android.useAndroidX=true\nandroid.enableJetifier=true\n\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# Uses one worker to build. This helps resolve build OOM issue.\norg.gradle.workers.max=1\n"
  },
  {
    "path": "android/entityextraction/settings.gradle",
    "content": "rootProject.name = \"mlkit_entity_extraction_sample\"\ninclude ':app'\ninclude ':internal:chooserx'\nproject(':internal:chooserx').projectDir = file('../internal/chooserx')\n\n"
  },
  {
    "path": "android/genai/README.md",
    "content": "# ML Kit GenAI APIs Quickstart\n\n* [Read more about ML Kit GenAI APIs](https://developers.google.com/ml-kit/genai)\n\n## Introduction\n\nThis sample app demonstrates how to use the following GenAI APIs:\n\n- [Image Description](https://developers.google.com/ml-kit/genai/image-description/android) - Provides short descriptions for images.\n\n- [Proofreading](https://developers.google.com/ml-kit/genai/proofreading/android) - Polishes short content by refining grammar and fixing spelling errors.\n\n- [Rewriting](https://developers.google.com/ml-kit/genai/rewriting/android) - Rewords content in different styles, such as formally, concise, or even with emojis.\n\n- [Summarization](https://developers.google.com/ml-kit/genai/summarization/android) - Summarizes articles and chat conversations into 1-3 bullet points.\n\n- [Prompt](https://developers.google.com/ml-kit/genai/prompt/android) - Generates text content based on a custom text-only or multimodal prompt.\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/genai)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2025 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements. See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership. The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License. You may obtain a copy of\nthe License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/genai/app/build.gradle",
    "content": "/*\n * Copyright 2025 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\napply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\n\nandroid {\n  namespace = \"com.google.mlkit.genai.demo\"\n  compileSdk 34\n\n  defaultConfig {\n    applicationId \"com.google.mlkit.genai.demo\"\n    minSdk 31\n    targetSdk 34\n    versionCode 1\n    versionName '1.0'\n\n    testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'\n  }\n\n  buildTypes {\n    configureEach {\n      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n    }\n    release {\n      minifyEnabled true\n      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n    }\n    debug {\n      isDefault true\n      minifyEnabled false\n      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n    }\n    testBuildType \"debug\"\n  }\n  compileOptions {\n    sourceCompatibility JavaVersion.VERSION_17\n    targetCompatibility JavaVersion.VERSION_17\n  }\n  kotlinOptions {\n    jvmTarget = \"17\"\n  }\n\n}\n\ndependencies {\n  implementation 'com.google.mlkit:genai-image-description:1.0.0-beta1'\n  implementation 'com.google.mlkit:genai-prompt:1.0.0-beta1'\n  implementation 'com.google.mlkit:genai-proofreading:1.0.0-beta1'\n  implementation 'com.google.mlkit:genai-rewriting:1.0.0-beta1'\n  implementation 'com.google.mlkit:genai-summarization:1.0.0-beta1'\n\n  implementation 'androidx.concurrent:concurrent-futures:1.3.0'\n  implementation 'androidx.preference:preference-ktx:1.2.1'\n  implementation 'androidx.recyclerview:recyclerview:1.3.2'\n  implementation 'com.google.android.material:material:1.12.0'\n  implementation 'com.google.guava:guava:32.0.1-jre'\n  implementation 'com.opencsv:opencsv:4.6'\n  implementation 'com.github.bumptech.glide:glide:5.0.5'\n  annotationProcessor 'com.github.bumptech.glide:compiler:5.0.5'\n\n  androidTestImplementation 'androidx.test:rules:1.6.1'\n  androidTestImplementation 'androidx.test:runner:1.6.2'\n  androidTestImplementation 'androidx.test.ext:junit:1.2.1'\n  androidTestImplementation 'com.google.truth:truth:1.1.3'\n}\n"
  },
  {
    "path": "android/genai/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.genai.demo\">\n\n  <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n  <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n  <application\n      android:label=\"@string/app_name\"\n      android:supportsRtl=\"true\"\n      android:taskAffinity = \"\"\n      android:theme=\"@style/Theme.Demo\">\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.EntryChoiceActivity\"\n        android:exported=\"true\"\n        android:screenOrientation=\"portrait\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.kotlin.SummarizationActivity\"\n        android:label=\"@string/summarization_entry_title_kotlin\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.java.SummarizationActivity\"\n        android:label=\"@string/summarization_entry_title_java\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.kotlin.RewritingActivity\"\n        android:label=\"@string/rewriting_entry_title_kotlin\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.java.RewritingActivity\"\n        android:label=\"@string/rewriting_entry_title_java\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.kotlin.ProofreadingActivity\"\n        android:label=\"@string/proofreading_entry_title_kotlin\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.java.ProofreadingActivity\"\n        android:label=\"@string/proofreading_entry_title_java\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.kotlin.ImageDescriptionActivity\"\n        android:label=\"@string/image_description_entry_title_kotlin\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.java.ImageDescriptionActivity\"\n        android:label=\"@string/image_description_entry_title_java\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.kotlin.OpenPromptActivity\"\n        android:label=\"@string/open_prompt_entry_title_kotlin\"\n        android:screenOrientation=\"portrait\" />\n\n    <activity\n        android:name=\"com.google.mlkit.genai.demo.java.OpenPromptActivity\"\n        android:label=\"@string/open_prompt_entry_title_java\"\n        android:screenOrientation=\"portrait\" />\n\n  </application>\n\n</manifest>\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/ContentAdapter.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo\n\nimport android.content.res.ColorStateList\nimport android.graphics.Color\nimport android.graphics.Typeface\nimport androidx.recyclerview.widget.RecyclerView\nimport androidx.recyclerview.widget.RecyclerView.ViewHolder\nimport android.text.SpannableStringBuilder\nimport android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE\nimport android.text.style.StyleSpan\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport com.bumptech.glide.Glide\nimport com.google.mlkit.genai.demo.ContentItem.CacheRequestItem\nimport com.google.mlkit.genai.demo.ContentItem.ImageItem\nimport com.google.mlkit.genai.demo.ContentItem.TextAndImagesItem\nimport com.google.mlkit.genai.demo.ContentItem.TextItem\nimport com.google.mlkit.genai.demo.ContentItem.TextWithPrefixCacheItem\nimport com.google.mlkit.genai.demo.ContentItem.TextWithPromptPrefixItem\n\n/** A recycler view adapter for displaying the request and response views. */\nclass ContentAdapter : RecyclerView.Adapter<ViewHolder>() {\n  private var recyclerView: RecyclerView? = null\n\n  private val contentList: MutableList<ContentItem> = ArrayList()\n\n  fun addContent(content: ContentItem) {\n    contentList.add(content)\n    notifyItemInserted(contentList.size - 1)\n    recyclerView?.post { recyclerView?.smoothScrollToPosition(contentList.size - 1) }\n  }\n\n  fun updateStreamingResponse(response: String) {\n    contentList[contentList.size - 1] = TextItem.fromStreamingResponse(response)\n    notifyDataSetChanged()\n    recyclerView?.post { recyclerView?.smoothScrollToPosition(contentList.size - 1) }\n  }\n\n  override fun getItemViewType(position: Int): Int {\n    return contentList[position].viewType\n  }\n\n  override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {\n    super.onAttachedToRecyclerView(recyclerView)\n    this.recyclerView = recyclerView\n  }\n\n  override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {\n    val layoutInflater = LayoutInflater.from(viewGroup.context)\n    return when (viewType) {\n      VIEW_TYPE_REQUEST_TEXT ->\n        TextViewHolder(layoutInflater.inflate(R.layout.row_item_request_text, viewGroup, false))\n      VIEW_TYPE_REQUEST_IMAGE ->\n        ImageViewHolder(layoutInflater.inflate(R.layout.row_item_request_image, viewGroup, false))\n      VIEW_TYPE_RESPONSE,\n      VIEW_TYPE_RESPONSE_STREAMING,\n      VIEW_TYPE_RESPONSE_ERROR ->\n        TextViewHolder(layoutInflater.inflate(R.layout.row_item_response, viewGroup, false))\n      VIEW_TYPE_REQUEST_TEXT_AND_IMAGES ->\n        TextAndImagesViewHolder(\n          layoutInflater.inflate(R.layout.row_item_request_text_and_images, viewGroup, false)\n        )\n      VIEW_TYPE_REQUEST_TEXT_WITH_PROMPT_PREFIX ->\n        TextWithPromptPrefixViewHolder(\n          layoutInflater.inflate(R.layout.row_item_request_text, viewGroup, false)\n        )\n      VIEW_TYPE_CACHE_REQUEST ->\n        CacheRequestViewHolder(\n          layoutInflater.inflate(R.layout.row_item_request_text, viewGroup, false)\n        )\n      VIEW_TYPE_REQUEST_TEXT_WITH_PREFIX_CACHE ->\n        TextWithPrefixCacheViewHolder(\n          layoutInflater.inflate(R.layout.row_item_request_text, viewGroup, false)\n        )\n      else -> throw IllegalArgumentException(\"Invalid view type $viewType\")\n    }\n  }\n\n  override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {\n    (viewHolder as ContentViewHolder).bind(contentList[position])\n  }\n\n  override fun onViewRecycled(holder: ViewHolder) {\n    super.onViewRecycled(holder)\n    if (holder is ImageViewHolder) {\n      Glide.with(holder.itemView).clear(holder.contentImageView)\n    } else if (holder is TextAndImagesViewHolder) {\n      for (i in 0 until holder.imageContainer.childCount) {\n        val view = holder.imageContainer.getChildAt(i)\n        if (view is ImageView) {\n          Glide.with(view).clear(view)\n        }\n      }\n    }\n  }\n\n  override fun getItemCount(): Int {\n    return contentList.size\n  }\n\n  interface ContentViewHolder {\n    fun bind(item: ContentItem)\n  }\n\n  /** Hosts text request or response item view. */\n  class TextViewHolder(itemView: View) : ViewHolder(itemView), ContentViewHolder {\n\n    private val contentTextView: TextView = itemView.findViewById(R.id.content_text_view)\n    private val metadataTextView: TextView? = itemView.findViewById(R.id.metadata_text_view)\n    private val defaultTextColors: ColorStateList = contentTextView.textColors\n\n    override fun bind(item: ContentItem) {\n      if (item is TextItem) {\n        contentTextView.setTextColor(defaultTextColors)\n        metadataTextView?.visibility = View.GONE\n\n        if (item.viewType == VIEW_TYPE_RESPONSE_ERROR) {\n          contentTextView.text = item.text\n          contentTextView.setTextColor(Color.RED)\n        } else if (item.viewType == VIEW_TYPE_RESPONSE_STREAMING) {\n          contentTextView.text =\n            SpannableStringBuilder().apply {\n              append(STREAMING_INDICATOR)\n              setSpan(StyleSpan(Typeface.BOLD), 0, length, SPAN_EXCLUSIVE_EXCLUSIVE)\n              append(item.text)\n            }\n        } else {\n          contentTextView.text = item.text\n          if (item.metadata != null) {\n            metadataTextView?.apply {\n              text = item.metadata\n              visibility = View.VISIBLE\n            }\n          }\n        }\n      }\n    }\n  }\n\n  /** Hosts image request item view. */\n  class ImageViewHolder(itemView: View) : ViewHolder(itemView), ContentViewHolder {\n\n    val contentImageView: ImageView = itemView.findViewById(R.id.content_image_view)\n\n    override fun bind(item: ContentItem) {\n      if (item is ImageItem) {\n        Glide.with(itemView).load(item.imageUri).into(contentImageView)\n      }\n    }\n  }\n\n  /** Hosts combined text and image request item view. */\n  class TextAndImagesViewHolder(itemView: View) : ViewHolder(itemView), ContentViewHolder {\n    private val messageText: TextView = itemView.findViewById(R.id.chat_message_text)\n    val imageContainer: LinearLayout = itemView.findViewById(R.id.image_container)\n    private val bubbleLayout: LinearLayout = itemView.findViewById(R.id.chat_bubble_layout)\n\n    private val defaultTextColors: ColorStateList = messageText.textColors\n\n    override fun bind(item: ContentItem) {\n      if (item !is TextAndImagesItem) {\n        return\n      }\n      if (!item.text.isEmpty()) {\n        messageText.text = item.text\n        messageText.visibility = View.VISIBLE\n      } else {\n        messageText.visibility = View.GONE\n      }\n\n      imageContainer.removeAllViews()\n      if (item.imageUris.isNotEmpty()) {\n        imageContainer.visibility = View.VISIBLE\n        for (uri in item.imageUris) {\n          val imageView = ImageView(imageContainer.context)\n          val layoutParams = LinearLayout.LayoutParams(400, 400)\n          layoutParams.setMargins(0, 0, 16, 0)\n          imageView.layoutParams = layoutParams\n          Glide.with(imageView).load(uri).into(imageView)\n          imageView.scaleType = ImageView.ScaleType.CENTER_CROP\n          imageContainer.addView(imageView)\n        }\n      } else {\n        imageContainer.visibility = View.GONE\n      }\n\n      bubbleLayout.setBackgroundResource(R.drawable.request_item_background)\n      messageText.setTextColor(defaultTextColors)\n    }\n  }\n\n  /** Hosts text request with prompt prefix item view. */\n  class TextWithPromptPrefixViewHolder(itemView: View) : ViewHolder(itemView), ContentViewHolder {\n    private val contentTextView: TextView = itemView.findViewById(R.id.content_text_view)\n    private val defaultTextColors: ColorStateList = contentTextView.textColors\n\n    override fun bind(item: ContentItem) {\n      if (item !is TextWithPromptPrefixItem) {\n        return\n      }\n      contentTextView.setTextColor(defaultTextColors)\n\n      contentTextView.text =\n        contentTextView.context.getString(\n          R.string.message_format_prefix_and_suffix,\n          item.promptPrefix,\n          item.dynamicSuffix,\n        )\n    }\n  }\n\n  /** Hosts text request with prefix cache item view. */\n  class TextWithPrefixCacheViewHolder(itemView: View) : ViewHolder(itemView), ContentViewHolder {\n    private val contentTextView: TextView = itemView.findViewById(R.id.content_text_view)\n    private val defaultTextColors: ColorStateList = contentTextView.textColors\n\n    override fun bind(item: ContentItem) {\n      if (item !is TextWithPrefixCacheItem) {\n        return\n      }\n      contentTextView.setTextColor(defaultTextColors)\n\n      contentTextView.text =\n        contentTextView.context.getString(\n          R.string.message_format_cache_name_and_suffix,\n          item.cacheName,\n          item.dynamicSuffix,\n        )\n    }\n  }\n\n  /** Hosts cache request item view. */\n  class CacheRequestViewHolder(itemView: View) : ViewHolder(itemView), ContentViewHolder {\n    private val contentTextView: TextView = itemView.findViewById(R.id.content_text_view)\n    private val defaultTextColors: ColorStateList = contentTextView.textColors\n\n    override fun bind(item: ContentItem) {\n      if (item !is CacheRequestItem) {\n        return\n      }\n      contentTextView.setTextColor(defaultTextColors)\n\n      contentTextView.text =\n        contentTextView.context.getString(\n          R.string.message_format_cache_request,\n          item.cacheName,\n          item.prefixToCache,\n        )\n    }\n  }\n\n  companion object {\n    const val VIEW_TYPE_REQUEST_TEXT: Int = 0\n    const val VIEW_TYPE_REQUEST_IMAGE: Int = 1\n    const val VIEW_TYPE_RESPONSE: Int = 2\n    const val VIEW_TYPE_RESPONSE_STREAMING: Int = 3\n    const val VIEW_TYPE_RESPONSE_ERROR: Int = 4\n    const val VIEW_TYPE_REQUEST_TEXT_AND_IMAGES: Int = 5\n    const val VIEW_TYPE_REQUEST_TEXT_WITH_PROMPT_PREFIX: Int = 6\n    const val VIEW_TYPE_CACHE_REQUEST: Int = 7\n    const val VIEW_TYPE_REQUEST_TEXT_WITH_PREFIX_CACHE: Int = 8\n\n    const val STREAMING_INDICATOR: String = \"STREAMING...\\n\"\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/ContentItem.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo\n\nimport android.net.Uri\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_CACHE_REQUEST\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_REQUEST_IMAGE\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_REQUEST_TEXT\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_REQUEST_TEXT_AND_IMAGES\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_REQUEST_TEXT_WITH_PREFIX_CACHE\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_REQUEST_TEXT_WITH_PROMPT_PREFIX\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_RESPONSE\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_RESPONSE_ERROR\nimport com.google.mlkit.genai.demo.ContentAdapter.Companion.VIEW_TYPE_RESPONSE_STREAMING\n\n/**\n * Represents a generic content item that can be rendered in a RecyclerView and holds GenAI API\n * request or response data.\n */\nsealed interface ContentItem {\n\n  val viewType: Int\n\n  /** A content item that contains only text. */\n  data class TextItem(val text: String, val metadata: String? = null, override val viewType: Int) :\n    ContentItem {\n    companion object {\n      fun fromRequest(request: String): TextItem = TextItem(request, null, VIEW_TYPE_REQUEST_TEXT)\n\n      fun fromResponse(response: String, metadata: String?): TextItem =\n        TextItem(response, metadata, VIEW_TYPE_RESPONSE)\n\n      fun fromErrorResponse(response: String): TextItem =\n        TextItem(response, null, VIEW_TYPE_RESPONSE_ERROR)\n\n      fun fromStreamingResponse(response: String): TextItem =\n        TextItem(response, null, VIEW_TYPE_RESPONSE_STREAMING)\n    }\n  }\n\n  /** A content item that contains only one image. */\n  data class ImageItem(val imageUri: Uri, override val viewType: Int) : ContentItem {\n    companion object {\n      fun fromRequest(imageUri: Uri): ImageItem = ImageItem(imageUri, VIEW_TYPE_REQUEST_IMAGE)\n    }\n  }\n\n  /** A content item that contains both text and one or more images. */\n  data class TextAndImagesItem(\n    val text: String,\n    val imageUris: List<Uri>,\n    override val viewType: Int,\n  ) : ContentItem {\n    companion object {\n      fun fromRequest(text: String, imageUris: List<Uri>): TextAndImagesItem =\n        TextAndImagesItem(text, imageUris, VIEW_TYPE_REQUEST_TEXT_AND_IMAGES)\n    }\n  }\n\n  /** A content item that contains a prompt prefix and a dynamic suffix. */\n  data class TextWithPromptPrefixItem(\n    val promptPrefix: String,\n    val dynamicSuffix: String,\n    override val viewType: Int,\n  ) : ContentItem {\n    companion object {\n      fun fromRequest(promptPrefix: String, dynamicSuffix: String): TextWithPromptPrefixItem =\n        TextWithPromptPrefixItem(\n          promptPrefix,\n          dynamicSuffix,\n          VIEW_TYPE_REQUEST_TEXT_WITH_PROMPT_PREFIX,\n        )\n    }\n  }\n\n  /** A content item that contains a prefix cache name and a dynamic suffix. */\n  data class TextWithPrefixCacheItem(\n    val cacheName: String,\n    val dynamicSuffix: String,\n    override val viewType: Int,\n  ) : ContentItem {\n    companion object {\n      fun fromRequest(cacheName: String, dynamicSuffix: String): TextWithPrefixCacheItem =\n        TextWithPrefixCacheItem(\n          cacheName,\n          dynamicSuffix,\n          VIEW_TYPE_REQUEST_TEXT_WITH_PREFIX_CACHE,\n        )\n    }\n  }\n\n  /** A content item that contains a cache request. */\n  data class CacheRequestItem(\n    val cacheName: String,\n    val prefixToCache: String,\n    override val viewType: Int,\n  ) : ContentItem {\n    companion object {\n      fun fromRequest(cacheName: String, prefixToCache: String): CacheRequestItem =\n        CacheRequestItem(cacheName, prefixToCache, VIEW_TYPE_CACHE_REQUEST)\n    }\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/EntryChoiceActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.TextView\nimport com.google.mlkit.genai.demo.java.OpenPromptActivity as OpenPromptActivityJava\nimport com.google.mlkit.genai.demo.kotlin.ImageDescriptionActivity\nimport com.google.mlkit.genai.demo.kotlin.OpenPromptActivity\nimport com.google.mlkit.genai.demo.kotlin.ProofreadingActivity\nimport com.google.mlkit.genai.demo.kotlin.RewritingActivity\nimport com.google.mlkit.genai.demo.kotlin.SummarizationActivity\n\n/** Entry activity to choose which ML Kit GenAI API to demo. */\nclass EntryChoiceActivity : AppCompatActivity() {\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_entry_choice)\n\n    val activityItems =\n      listOf(\n        ActivityItem(R.string.summarization_entry_title_kotlin, SummarizationActivity::class.java),\n        ActivityItem(\n          R.string.summarization_entry_title_java,\n          com.google.mlkit.genai.demo.java.SummarizationActivity::class.java,\n        ),\n        ActivityItem(R.string.rewriting_entry_title_kotlin, RewritingActivity::class.java),\n        ActivityItem(\n          R.string.rewriting_entry_title_java,\n          com.google.mlkit.genai.demo.java.RewritingActivity::class.java,\n        ),\n        ActivityItem(R.string.proofreading_entry_title_kotlin, ProofreadingActivity::class.java),\n        ActivityItem(\n          R.string.proofreading_entry_title_java,\n          com.google.mlkit.genai.demo.java.ProofreadingActivity::class.java,\n        ),\n        ActivityItem(\n          R.string.image_description_entry_title_kotlin,\n          ImageDescriptionActivity::class.java,\n        ),\n        ActivityItem(\n          R.string.image_description_entry_title_java,\n          com.google.mlkit.genai.demo.java.ImageDescriptionActivity::class.java,\n        ),\n        ActivityItem(R.string.open_prompt_entry_title_kotlin, OpenPromptActivity::class.java),\n        ActivityItem(R.string.open_prompt_entry_title_java, OpenPromptActivityJava::class.java),\n      )\n\n    val recyclerView: RecyclerView = findViewById(R.id.entry_recycler_view)\n    recyclerView.layoutManager = LinearLayoutManager(this)\n    recyclerView.adapter = ActivityAdapter(this, activityItems)\n  }\n\n  class ActivityAdapter(private val context: Context, private val items: List<ActivityItem>) :\n    RecyclerView.Adapter<ActivityAdapter.ViewHolder>() {\n\n    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {\n      val titleTextView: TextView = view.findViewById(R.id.title_text_view)\n    }\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {\n      val layoutInflater = LayoutInflater.from(parent.context)\n      return ViewHolder(layoutInflater.inflate(R.layout.entry_choice_item, parent, false))\n    }\n\n    override fun onBindViewHolder(holder: ViewHolder, position: Int) {\n      val item = items[position]\n      holder.titleTextView.setText(item.titleResId)\n      holder.itemView.setOnClickListener {\n        context.startActivity(Intent(context, item.activityClass))\n      }\n    }\n\n    override fun getItemCount(): Int = items.size\n  }\n\n  data class ActivityItem(val titleResId: Int, val activityClass: Class<*>)\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/GenerationConfigDialog.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.genai.demo\n\nimport android.app.Activity\nimport android.app.AlertDialog\nimport android.app.Dialog\nimport android.os.Bundle\nimport androidx.fragment.app.DialogFragment\nimport android.widget.EditText\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.getStoredCandidateCount\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.getStoredMaxOutputTokens\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.getStoredSeed\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.getStoredTemperature\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.getStoredTopK\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.setCandidateCount\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.setMaxOutputTokens\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.setSeed\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.setTemperature\nimport com.google.mlkit.genai.demo.GenerationConfigUtils.setTopK\nimport java.text.NumberFormat\nimport java.text.ParseException\n\nclass GenerationConfigDialog : DialogFragment() {\n  interface OnConfigUpdateListener {\n    fun onConfigUpdated()\n  }\n\n  private lateinit var temperatureEditText: EditText\n  private lateinit var topKEditText: EditText\n  private lateinit var seedEditText: EditText\n  private lateinit var maxOutputTokensEditText: EditText\n  private lateinit var candidateCountEditText: EditText\n  private val numberFormat = NumberFormat.getInstance()\n\n  override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {\n    val activity: Activity = requireActivity()\n    val builder = AlertDialog.Builder(activity)\n\n    val view = layoutInflater.inflate(R.layout.dialog_generation_config, null)\n    temperatureEditText = view.findViewById<EditText>(R.id.temperature_edit_text)\n    temperatureEditText.setText(numberFormat.format(getStoredTemperature(activity)))\n    topKEditText = view.findViewById<EditText>(R.id.top_k_edit_text)\n    topKEditText.setText(numberFormat.format(getStoredTopK(activity)))\n    seedEditText = view.findViewById<EditText>(R.id.seed_edit_text)\n    seedEditText.setText(numberFormat.format(getStoredSeed(activity)))\n    maxOutputTokensEditText = view.findViewById<EditText>(R.id.max_output_tokens_edit_text)\n    maxOutputTokensEditText.setText(numberFormat.format(getStoredMaxOutputTokens(activity)))\n    candidateCountEditText = view.findViewById<EditText>(R.id.candidate_count_edit_text)\n    candidateCountEditText.setText(numberFormat.format(getStoredCandidateCount(activity)))\n\n    builder\n      .setView(view)\n      .setPositiveButton(R.string.button_save, null)\n      .setNegativeButton(R.string.button_cancel, null)\n    return builder.create()\n  }\n\n  override fun onStart() {\n    super.onStart()\n    val dialog = dialog as AlertDialog?\n    dialog?.let {\n      val positiveButton = it.getButton(Dialog.BUTTON_POSITIVE)\n      positiveButton.setOnClickListener {\n        if (validateInputs()) {\n          saveConfig()\n          if (activity is OnConfigUpdateListener) {\n            (activity as OnConfigUpdateListener).onConfigUpdated()\n          }\n          dismiss()\n        }\n      }\n    }\n  }\n\n  private fun getNumberFromString(text: String): Number? {\n    return try {\n      numberFormat.parse(text)\n    } catch (e: ParseException) {\n      null\n    }\n  }\n\n  private fun validateInputs(): Boolean {\n    var isValid = true\n\n    val tempValue = getNumberFromString(temperatureEditText.text.toString())?.toFloat()\n    if (tempValue == null || tempValue < 0.0f || tempValue > 1.0f) {\n      temperatureEditText.error = \"Must be a floating point number between 0.0 and 1.0\"\n      isValid = false\n    }\n\n    val topKValue = getNumberFromString(topKEditText.text.toString())?.toInt()\n    if (topKValue == null || topKValue < 1) {\n      topKEditText.error = \"Must be a positive integer (>0)\"\n      isValid = false\n    }\n\n    val seedValue = getNumberFromString(seedEditText.text.toString())?.toInt()\n    if (seedValue == null || seedValue < 0) {\n      seedEditText.error = \"Must be a non-negative integer (>=0)\"\n      isValid = false\n    }\n\n    val maxTokensValue = getNumberFromString(maxOutputTokensEditText.text.toString())?.toInt()\n    if (maxTokensValue == null || maxTokensValue < 1) {\n      maxOutputTokensEditText.error = \"Must be a positive integer (>0)\"\n      isValid = false\n    }\n\n    val candidateCountValue = getNumberFromString(candidateCountEditText.text.toString())?.toInt()\n    if (candidateCountValue == null || candidateCountValue !in 1..8) {\n      candidateCountEditText.error = \"Must be an integer between 1 and 8 (>=1 and <=8)\"\n      isValid = false\n    }\n\n    return isValid\n  }\n\n  private fun saveConfig() {\n    val activity = requireActivity()\n    val temperature =\n      checkNotNull(getNumberFromString(temperatureEditText.text.toString())) {\n        \"Temperature should not be null after validation\"\n      }\n    setTemperature(activity, temperature.toFloat())\n\n    val topK =\n      checkNotNull(getNumberFromString(topKEditText.text.toString())) {\n        \"TopK should not be null after validation\"\n      }\n    setTopK(activity, topK.toInt())\n\n    val seed =\n      checkNotNull(getNumberFromString(seedEditText.text.toString())) {\n        \"Seed should not be null after validation\"\n      }\n    setSeed(activity, seed.toInt())\n\n    val maxOutputTokens =\n      checkNotNull(getNumberFromString(maxOutputTokensEditText.text.toString())) {\n        \"MaxOutputTokens should not be null after validation\"\n      }\n    setMaxOutputTokens(activity, maxOutputTokens.toInt())\n\n    val candidateCount =\n      checkNotNull(getNumberFromString(candidateCountEditText.text.toString())) {\n        \"CandidateCount should not be null after validation\"\n      }\n    setCandidateCount(activity, candidateCount.toInt())\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/GenerationConfigUtils.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.genai.demo\n\nimport android.content.Context\nimport androidx.core.content.edit\nimport androidx.preference.PreferenceManager\n\nobject GenerationConfigUtils {\n  internal fun getStoredTemperature(context: Context): Float =\n    PreferenceManager.getDefaultSharedPreferences(context)\n      .getFloat(context.getString(R.string.pref_key_temperature), 0.2f)\n\n  @JvmStatic\n  fun getTemperature(context: Context): Float? {\n    if (getUseDefaultConfig(context)) {\n      return null\n    }\n    return getStoredTemperature(context)\n  }\n\n  @JvmStatic\n  fun setTemperature(context: Context, temperature: Float) {\n    PreferenceManager.getDefaultSharedPreferences(context).edit {\n      putFloat(context.getString(R.string.pref_key_temperature), temperature)\n    }\n  }\n\n  internal fun getStoredTopK(context: Context): Int =\n    PreferenceManager.getDefaultSharedPreferences(context)\n      .getInt(context.getString(R.string.pref_key_top_k), 16)\n\n  @JvmStatic\n  fun getTopK(context: Context): Int? {\n    if (getUseDefaultConfig(context)) {\n      return null\n    }\n    return getStoredTopK(context)\n  }\n\n  @JvmStatic\n  fun setTopK(context: Context, topK: Int) {\n    PreferenceManager.getDefaultSharedPreferences(context).edit {\n      putInt(context.getString(R.string.pref_key_top_k), topK)\n    }\n  }\n\n  internal fun getStoredSeed(context: Context): Int =\n    PreferenceManager.getDefaultSharedPreferences(context)\n      .getInt(context.getString(R.string.pref_key_seed), 0)\n\n  @JvmStatic\n  fun getSeed(context: Context): Int? {\n    if (getUseDefaultConfig(context)) {\n      return null\n    }\n    return getStoredSeed(context)\n  }\n\n  @JvmStatic\n  fun setSeed(context: Context, seed: Int) {\n    PreferenceManager.getDefaultSharedPreferences(context).edit {\n      putInt(context.getString(R.string.pref_key_seed), seed)\n    }\n  }\n\n  internal fun getStoredMaxOutputTokens(context: Context): Int =\n    PreferenceManager.getDefaultSharedPreferences(context)\n      .getInt(context.getString(R.string.pref_key_max_output_tokens), 256)\n\n  @JvmStatic\n  fun getMaxOutputTokens(context: Context): Int? {\n    if (getUseDefaultConfig(context)) {\n      return null\n    }\n    return getStoredMaxOutputTokens(context)\n  }\n\n  @JvmStatic\n  fun setMaxOutputTokens(context: Context, maxTokenCount: Int) {\n    PreferenceManager.getDefaultSharedPreferences(context).edit {\n      putInt(context.getString(R.string.pref_key_max_output_tokens), maxTokenCount)\n    }\n  }\n\n  internal fun getStoredCandidateCount(context: Context): Int =\n    PreferenceManager.getDefaultSharedPreferences(context)\n      .getInt(context.getString(R.string.pref_key_candidate_count), 1)\n\n  @JvmStatic\n  fun getCandidateCount(context: Context): Int? {\n    if (getUseDefaultConfig(context)) {\n      return null\n    }\n    return getStoredCandidateCount(context)\n  }\n\n  @JvmStatic\n  fun setCandidateCount(context: Context, candidateCount: Int) {\n    PreferenceManager.getDefaultSharedPreferences(context).edit {\n      putInt(context.getString(R.string.pref_key_candidate_count), candidateCount)\n    }\n  }\n\n  @JvmStatic\n  fun getUseDefaultConfig(context: Context): Boolean {\n    return PreferenceManager.getDefaultSharedPreferences(context)\n      .getBoolean(context.getString(R.string.pref_key_use_default_config), false)\n  }\n\n  @JvmStatic\n  fun setUseDefaultConfig(context: Context, useDefaultConfig: Boolean) {\n    PreferenceManager.getDefaultSharedPreferences(context).edit {\n      putBoolean(context.getString(R.string.pref_key_use_default_config), useDefaultConfig)\n    }\n  }\n\n  @JvmStatic\n  fun getUseExplicitCache(context: Context): Boolean {\n    return PreferenceManager.getDefaultSharedPreferences(context)\n      .getBoolean(context.getString(R.string.pref_key_use_explicit_cache), false)\n  }\n\n  @JvmStatic\n  fun setUseExplicitCache(context: Context, useExplicitCache: Boolean) {\n    PreferenceManager.getDefaultSharedPreferences(context).edit {\n      putBoolean(context.getString(R.string.pref_key_use_explicit_cache), useExplicitCache)\n    }\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/java/BaseActivity.java",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.genai.demo.java;\n\nimport static java.util.Objects.requireNonNull;\n\nimport android.app.AlertDialog;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts.CreateDocument;\nimport androidx.activity.result.contract.ActivityResultContracts.GetContent;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\nimport com.google.common.util.concurrent.FutureCallback;\nimport com.google.common.util.concurrent.Futures;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport com.google.mlkit.genai.common.DownloadCallback;\nimport com.google.mlkit.genai.common.FeatureStatus;\nimport com.google.mlkit.genai.common.GenAiException;\nimport com.google.mlkit.genai.common.StreamingCallback;\nimport com.google.mlkit.genai.demo.ContentAdapter;\nimport com.google.mlkit.genai.demo.ContentItem;\nimport com.google.mlkit.genai.demo.ContentItem.TextItem;\nimport com.google.mlkit.genai.demo.R;\nimport com.google.mlkit.genai.prompt.CountTokensResponse;\nimport com.opencsv.CSVReader;\nimport com.opencsv.CSVWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.text.SimpleDateFormat;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Executors;\nimport java.util.function.Consumer;\n\n/** Base Activity for ML Kit GenAI APIs. */\nabstract class BaseActivity<RequestT extends ContentItem> extends AppCompatActivity {\n\n  private static final String TAG = BaseActivity.class.getSimpleName();\n  private static final long MEGABYTE = 1024 * 1024L;\n  private static final long MIN_INFERENCE_INTERVAL_MS = 6000;\n\n  private TextView debugInfoTextView;\n\n  private boolean modelDownloaded;\n  private long totalBytesToDownload;\n\n  private boolean streaming = true;\n  private boolean hasFirstStreamingResult;\n  private long firstTokenLatency;\n\n  @Nullable private Uri batchInputUri;\n  private boolean batchRunCancelled;\n  private int batchProcessingIndex;\n\n  private ActivityResultLauncher<String> createBatchOutputFileLauncher;\n  private ActivityResultLauncher<String> chooseBatchInputLauncher;\n\n  private final ContentAdapter contentAdapter = new ContentAdapter();\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(getLayoutResId());\n\n    debugInfoTextView = findViewById(R.id.debug_info_text_view);\n\n    RecyclerView contentRecyclerView = findViewById(R.id.content_recycler_view);\n    contentRecyclerView.setLayoutManager(new LinearLayoutManager(this));\n    contentRecyclerView.setAdapter(contentAdapter);\n\n    createBatchOutputFileLauncher =\n        registerForActivityResult(\n            new CreateDocument(\"text/csv\"),\n            batchOutputUri -> {\n              if (batchInputUri != null && batchOutputUri != null) {\n                batchRun(batchInputUri, batchOutputUri);\n              }\n            });\n    chooseBatchInputLauncher =\n        registerForActivityResult(\n            new GetContent(),\n            uri -> {\n              if (uri != null) {\n                batchInputUri = uri;\n                SimpleDateFormat dateFormat =\n                    new SimpleDateFormat(\"yyyy-MM-dd_HH:mm:ss\", Locale.getDefault());\n                String outputFileName =\n                    \"mlkit_genai_result_\" + dateFormat.format(new Date()) + \".csv\";\n                createBatchOutputFileLauncher.launch(outputFileName);\n              }\n            });\n  }\n\n  @Override\n  protected void onPostCreate(@Nullable Bundle savedInstanceState) {\n    super.onPostCreate(savedInstanceState);\n    Futures.addCallback(\n        getBaseModelName(),\n        new FutureCallback<>() {\n          @Override\n          public void onSuccess(String result) {\n            debugInfoTextView.setVisibility(View.VISIBLE);\n            debugInfoTextView.setText(getString(R.string.base_model_name, result));\n          }\n\n          @Override\n          public void onFailure(@NonNull Throwable t) {\n            Log.e(TAG, \"Failed to get base model name.\", t);\n          }\n        },\n        ContextCompat.getMainExecutor(this));\n  }\n\n  protected void onSend(RequestT request) {\n    contentAdapter.addContent(request);\n    startGeneratingUi();\n    if (modelDownloaded) {\n      runInference(request);\n    } else {\n      checkFeatureStatus(request);\n    }\n  }\n\n  protected abstract int getLayoutResId();\n\n  @Override\n  public boolean onCreateOptionsMenu(Menu menu) {\n    getMenuInflater().inflate(R.menu.menu_main, menu);\n    return true;\n  }\n\n  @Override\n  public boolean onPrepareOptionsMenu(Menu menu) {\n    super.onPrepareOptionsMenu(menu);\n    MenuItem streamingItem = menu.findItem(R.id.action_streaming);\n    if (streamingItem != null) {\n      streamingItem.setChecked(streaming);\n    }\n    // Disable the streaming API submenu in Java activities as it's only for Kotlin Flow.\n    MenuItem streamingApiSubmenu = menu.findItem(R.id.action_streaming_api_submenu);\n    if (streamingApiSubmenu != null) {\n      streamingApiSubmenu.setVisible(false);\n    }\n    return true;\n  }\n\n  @Override\n  public boolean onOptionsItemSelected(MenuItem item) {\n    if (item.getItemId() == R.id.action_streaming) {\n      streaming = !streaming;\n      item.setChecked(streaming);\n      return true;\n    } else if (item.getItemId() == R.id.action_batch_run) {\n      chooseBatchInputLauncher.launch(\"text/csv\");\n      return true;\n    }\n\n    return super.onOptionsItemSelected(item);\n  }\n\n  private void checkFeatureStatus(RequestT request) {\n    Futures.addCallback(\n        checkFeatureStatus(),\n        new FutureCallback<>() {\n          @Override\n          public void onSuccess(Integer featureStatus) {\n            switch (featureStatus) {\n              case FeatureStatus.AVAILABLE -> {\n                modelDownloaded = true;\n                runInference(request);\n              }\n              case FeatureStatus.UNAVAILABLE -> displayErrorMessage(\"Feature is unavailable.\");\n              default -> downloadAndRunInference(request);\n            }\n          }\n\n          @Override\n          public void onFailure(@NonNull Throwable t) {\n            Log.e(TAG, \"Failed to check status.\", t);\n            displayErrorMessage(\"Failed to check status\", t);\n          }\n        },\n        ContextCompat.getMainExecutor(this));\n  }\n\n  @FeatureStatus\n  protected abstract ListenableFuture<Integer> checkFeatureStatus();\n\n  protected abstract ListenableFuture<String> getBaseModelName();\n\n  private void downloadAndRunInference(RequestT request) {\n    Futures.addCallback(\n        downloadFeature(\n            new DownloadCallback() {\n              @Override\n              public void onDownloadStarted(long bytesToDownload) {\n                totalBytesToDownload = bytesToDownload;\n              }\n\n              @Override\n              public void onDownloadFailed(@NonNull GenAiException e) {\n                displayErrorMessage(\"Failed to download model\", e);\n              }\n\n              @Override\n              public void onDownloadProgress(long totalBytesDownloaded) {\n                if (totalBytesToDownload > 0) {\n                  debugInfoTextView.setVisibility(View.VISIBLE);\n                  debugInfoTextView.setText(\n                      String.format(\n                          Locale.ENGLISH,\n                          \"Downloading model:  %d / %d MB (%.2f%%)\",\n                          totalBytesDownloaded / MEGABYTE,\n                          totalBytesToDownload / MEGABYTE,\n                          100.0 * totalBytesDownloaded / totalBytesToDownload));\n                }\n              }\n\n              @Override\n              public void onDownloadCompleted() {\n                modelDownloaded = true;\n                runInference(request);\n              }\n            }),\n        new FutureCallback<>() {\n          @Override\n          public void onSuccess(Void result) {}\n\n          @Override\n          public void onFailure(@NonNull Throwable t) {\n            Log.e(TAG, \"Failed to download feature.\", t);\n            displayErrorMessage(\"Failed to download feature\", t);\n          }\n        },\n        ContextCompat.getMainExecutor(this));\n  }\n\n  protected abstract ListenableFuture<Void> downloadFeature(DownloadCallback callback);\n\n  private void runInference(RequestT request) {\n    ListenableFuture<CountTokensResponse> countTokensFuture = countTokens(request);\n    ListenableFuture<Integer> tokenLimitFuture = getTokenLimit();\n\n    ListenableFuture<List<Object>> combinedFuture =\n        Futures.successfulAsList(countTokensFuture, tokenLimitFuture);\n\n    Futures.addCallback(\n        combinedFuture,\n        new FutureCallback<List<Object>>() {\n          @Override\n          public void onSuccess(List<Object> results) {\n            StringBuilder tokenInfoTextBuilder = new StringBuilder();\n\n            try {\n              CountTokensResponse countTokensResponse = Futures.getDone(countTokensFuture);\n              tokenInfoTextBuilder\n                  .append(\"Input Token count: \")\n                  .append(countTokensResponse.getTotalTokens());\n            } catch (ExecutionException e) {\n              if (!(e.getCause() instanceof UnsupportedOperationException)) {\n                tokenInfoTextBuilder.append(\"Token count failed\");\n                Log.e(TAG, \"Failed to get token count.\", e.getCause());\n              }\n            } catch (RuntimeException e) {\n              tokenInfoTextBuilder.append(\"Token count failed\");\n              Log.e(TAG, \"Failed to get token count.\", e);\n            }\n\n            try {\n              Integer tokenLimit = Futures.getDone(tokenLimitFuture);\n              if (tokenInfoTextBuilder.length() > 0) {\n                tokenInfoTextBuilder.append(\". \");\n              }\n              tokenInfoTextBuilder.append(\"Token limit: \").append(tokenLimit);\n            } catch (ExecutionException e) {\n              if (!(e.getCause() instanceof UnsupportedOperationException)) {\n                if (tokenInfoTextBuilder.length() > 0) {\n                  tokenInfoTextBuilder.append(\". \");\n                }\n                tokenInfoTextBuilder.append(\"Token limit failed\");\n                Log.e(TAG, \"Failed to get token limit.\", e.getCause());\n              }\n            } catch (RuntimeException e) {\n              if (tokenInfoTextBuilder.length() > 0) {\n                tokenInfoTextBuilder.append(\". \");\n              }\n              tokenInfoTextBuilder.append(\"Token limit failed\");\n              Log.e(TAG, \"Failed to get token limit.\", e);\n            }\n\n            String tokenInfoText = tokenInfoTextBuilder.toString();\n            runInferenceWithTokenInfo(request, tokenInfoText);\n          }\n\n          @Override\n          public void onFailure(@NonNull Throwable t) {\n            Log.e(TAG, \"Unexpected failure in combined future.\", t);\n            runInferenceWithTokenInfo(request, \"Token info failed unexpectedly.\");\n          }\n        },\n        ContextCompat.getMainExecutor(BaseActivity.this));\n  }\n\n  private void runInferenceWithTokenInfo(RequestT request, String tokenInfoText) {\n    long startMs = System.currentTimeMillis();\n    if (streaming) {\n      hasFirstStreamingResult = false;\n      StringBuilder resultBuilder = new StringBuilder();\n      Futures.addCallback(\n          runInferenceImpl(\n              request,\n              additionalText ->\n                  runOnUiThread(\n                      () -> {\n                        resultBuilder.append(additionalText);\n                        if (hasFirstStreamingResult) {\n                          contentAdapter.updateStreamingResponse(resultBuilder.toString());\n                        } else {\n                          contentAdapter.addContent(\n                              TextItem.Companion.fromStreamingResponse(resultBuilder.toString()));\n                          hasFirstStreamingResult = true;\n                          firstTokenLatency = Instant.now().minusMillis(startMs).toEpochMilli();\n                        }\n                      })),\n          new FutureCallback<>() {\n            @Override\n            public void onSuccess(List<String> results) {\n              long totalLatency = Instant.now().minusMillis(startMs).toEpochMilli();\n              String debugInfo =\n                  getString(R.string.debug_info_streaming, firstTokenLatency, totalLatency);\n              String latencyMetadata =\n                  tokenInfoText.isEmpty() ? debugInfo : tokenInfoText + \"\\n\" + debugInfo;\n              results.forEach(\n                  result -> {\n                    contentAdapter.addContent(\n                        TextItem.Companion.fromResponse(result, latencyMetadata));\n                  });\n              endGeneratingUi(debugInfo);\n            }\n\n            @Override\n            public void onFailure(@NonNull Throwable t) {\n              Log.d(TAG, \"Streaming result so far:\\n\" + resultBuilder);\n              Log.e(TAG, \"Failed to run inference.\", t);\n              displayErrorMessage(\"Failed to run inference\", t);\n            }\n          },\n          ContextCompat.getMainExecutor(this));\n\n    } else {\n      Futures.addCallback(\n          runInferenceImpl(request, /* streamingCallback= */ null),\n          new FutureCallback<>() {\n            @Override\n            public void onSuccess(List<String> results) {\n              String debugInfo =\n                  getString(R.string.debug_info, Instant.now().minusMillis(startMs).toEpochMilli());\n              String latencyMetadata =\n                  tokenInfoText.isEmpty() ? debugInfo : tokenInfoText + \"\\n\" + debugInfo;\n              results.forEach(\n                  result -> {\n                    contentAdapter.addContent(\n                        TextItem.Companion.fromResponse(result, latencyMetadata));\n                  });\n              endGeneratingUi(debugInfo);\n            }\n\n            @Override\n            public void onFailure(@NonNull Throwable t) {\n              Log.e(TAG, \"Failed to run inference.\", t);\n              displayErrorMessage(\"Failed to run inference\", t);\n            }\n          },\n          ContextCompat.getMainExecutor(this));\n    }\n  }\n\n  protected abstract ListenableFuture<List<String>> runInferenceImpl(\n      RequestT request, @Nullable StreamingCallback streamingCallback);\n\n  protected ListenableFuture<CountTokensResponse> countTokens(RequestT request) {\n    return Futures.immediateFailedFuture(new UnsupportedOperationException());\n  }\n\n  protected ListenableFuture<Integer> getTokenLimit() {\n    return Futures.immediateFailedFuture(new UnsupportedOperationException());\n  }\n\n  protected void setupSpinner(int spinnerId, int arrayId, Consumer<Integer> onItemSelected) {\n    Spinner spinner = findViewById(spinnerId);\n    ArrayAdapter<CharSequence> adapter =\n        ArrayAdapter.createFromResource(this, arrayId, android.R.layout.simple_spinner_item);\n    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    spinner.setAdapter(adapter);\n    spinner.setOnItemSelectedListener(\n        new AdapterView.OnItemSelectedListener() {\n          @Override\n          public void onItemSelected(\n              AdapterView<?> adapterView, @Nullable View view, int position, long id) {\n            onItemSelected.accept(position);\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> adapterView) {}\n        });\n  }\n\n  private void displayErrorMessage(String errorMessage) {\n    displayErrorMessage(errorMessage, /* cause= */ null);\n  }\n\n  private void displayErrorMessage(String errorMessage, @Nullable Throwable cause) {\n    if (cause != null) {\n      errorMessage += \": \" + cause;\n      if (cause.getCause() != null) {\n        errorMessage += \"\\nCause: \" + cause.getCause();\n      }\n    }\n    contentAdapter.addContent(TextItem.Companion.fromErrorResponse(errorMessage));\n    endGeneratingUi(getString(R.string.empty));\n  }\n\n  protected void startGeneratingUi() {\n    debugInfoTextView.setVisibility(View.GONE);\n  }\n\n  protected void endGeneratingUi(String debugInfo) {\n    debugInfoTextView.setText(debugInfo);\n    debugInfoTextView.setVisibility(debugInfo.isEmpty() ? View.GONE : View.VISIBLE);\n  }\n\n  protected void resetProcessor() {\n    modelDownloaded = false;\n  }\n\n  protected abstract List<String> runInferenceForBatchTask(String request);\n\n  /**\n   * Runs inference on batch text requests from an input file.\n   *\n   * <p>The input file must be a CSV file selected via the file picker, with the first column\n   * containing the text requests.\n   *\n   * <p>The output file will also be in CSV format, containing all the content from the input file\n   * with the inference results appended to the end of each row. Each inference result occupies two\n   * additional columns: one for the result text (or error message) and one for the score,\n   * continuing sequentially.\n   */\n  private void batchRun(Uri inputUri, Uri outputUri) {\n    batchRunCancelled = false;\n    AlertDialog processingDialog =\n        new AlertDialog.Builder(this)\n            .setMessage(R.string.batch_run_start_message)\n            .setNegativeButton(R.string.button_cancel, (dialog, which) -> batchRunCancelled = true)\n            .setCancelable(false)\n            .show();\n    processingDialog.setCanceledOnTouchOutside(false);\n\n    var unused =\n        Executors.newSingleThreadExecutor()\n            .submit(\n                () -> {\n                  try (InputStream inputStream = getContentResolver().openInputStream(inputUri);\n                      CSVReader csvReader =\n                          new CSVReader(new InputStreamReader(requireNonNull(inputStream)));\n                      OutputStream outputStream = getContentResolver().openOutputStream(outputUri);\n                      CSVWriter csvWriter =\n                          new CSVWriter(new OutputStreamWriter(requireNonNull(outputStream)))) {\n                    List<String[]> inputRows = csvReader.readAll();\n                    batchProcessingIndex = 0;\n                    for (String[] inputRow : inputRows) {\n                      if (batchRunCancelled) {\n                        break;\n                      }\n\n                      batchProcessingIndex++;\n                      runOnUiThread(\n                          () ->\n                              processingDialog.setMessage(\n                                  \"Processing \" + batchProcessingIndex + \"/\" + inputRows.size()));\n\n                      long startTimeMs = System.currentTimeMillis();\n                      List<String> resultRow = new ArrayList<>(Arrays.asList(inputRow));\n                      List<String> inferenceResult = runInferenceForBatchTask(resultRow.get(0));\n                      // Append the result to the end of input columns.\n                      resultRow.addAll(inferenceResult);\n                      csvWriter.writeNext(resultRow.toArray(new String[0]));\n                      long elapsedTimeMs = System.currentTimeMillis() - startTimeMs;\n                      long remainingTimeMs = MIN_INFERENCE_INTERVAL_MS - elapsedTimeMs;\n                      if (remainingTimeMs > 0) {\n                        Thread.sleep(remainingTimeMs);\n                      }\n                    }\n                  } catch (IOException | InterruptedException e) {\n                    Log.e(TAG, \"Failed to do batch run.\", e);\n                  }\n\n                  runOnUiThread(processingDialog::dismiss);\n                });\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/java/ImageDescriptionActivity.java",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.genai.demo.java;\n\nimport static com.google.common.util.concurrent.Futures.immediateFailedFuture;\nimport static java.util.Objects.requireNonNull;\n\nimport android.graphics.Bitmap;\nimport android.graphics.ImageDecoder;\nimport android.os.Bundle;\nimport androidx.annotation.Nullable;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.widget.Button;\nimport android.widget.Toast;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts.GetContent;\nimport androidx.core.content.ContextCompat;\nimport com.google.common.collect.ImmutableList;\nimport com.google.common.util.concurrent.Futures;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport com.google.mlkit.genai.common.DownloadCallback;\nimport com.google.mlkit.genai.common.StreamingCallback;\nimport com.google.mlkit.genai.demo.ContentItem.ImageItem;\nimport com.google.mlkit.genai.demo.R;\nimport com.google.mlkit.genai.imagedescription.ImageDescriber;\nimport com.google.mlkit.genai.imagedescription.ImageDescriberOptions;\nimport com.google.mlkit.genai.imagedescription.ImageDescription;\nimport com.google.mlkit.genai.imagedescription.ImageDescriptionRequest;\nimport com.google.mlkit.genai.prompt.CountTokensResponse;\nimport java.io.IOException;\nimport java.util.List;\n\n/** Demonstrates the Image Description API usage. */\npublic class ImageDescriptionActivity extends BaseActivity<ImageItem> {\n\n  private Button selectImageButton;\n  private ImageDescriber imageDescriber;\n  private ActivityResultLauncher<String> selectImageLauncher;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    selectImageLauncher =\n        registerForActivityResult(\n            new GetContent(),\n            imageUri -> {\n              if (imageUri != null) {\n                onSend(ImageItem.Companion.fromRequest(imageUri));\n              } else {\n                Toast.makeText(this, \"No image selected\", Toast.LENGTH_SHORT).show();\n              }\n            });\n    selectImageButton = findViewById(R.id.select_image_button);\n    selectImageButton.setOnClickListener(view -> selectImageLauncher.launch(\"image/*\"));\n\n    initImageDescriptor();\n  }\n\n  @Override\n  protected int getLayoutResId() {\n    return R.layout.activity_image_description;\n  }\n\n  @Override\n  public boolean onPrepareOptionsMenu(Menu menu) {\n    MenuItem item = menu.findItem(R.id.action_batch_run);\n    if (item != null) {\n      item.setVisible(false);\n    }\n    return true;\n  }\n\n  @Override\n  protected void onDestroy() {\n    super.onDestroy();\n    if (imageDescriber != null) {\n      imageDescriber.close();\n    }\n  }\n\n  @Override\n  protected ListenableFuture<String> getBaseModelName() {\n    return imageDescriber.getBaseModelName();\n  }\n\n  @Override\n  protected ListenableFuture<Integer> checkFeatureStatus() {\n    return imageDescriber.checkFeatureStatus();\n  }\n\n  @Override\n  protected ListenableFuture<Void> downloadFeature(DownloadCallback callback) {\n    return imageDescriber.downloadFeature(callback);\n  }\n\n  @Override\n  protected ListenableFuture<CountTokensResponse> countTokens(ImageItem request) {\n    return immediateFailedFuture(new UnsupportedOperationException(\"Not supported\"));\n  }\n\n  @Override\n  protected ListenableFuture<Integer> getTokenLimit() {\n    return immediateFailedFuture(new UnsupportedOperationException(\"Not supported\"));\n  }\n\n  @Override\n  protected ListenableFuture<List<String>> runInferenceImpl(\n      ImageItem request, @Nullable StreamingCallback streamingCallback) {\n    try {\n      Bitmap bitmap =\n          ImageDecoder.decodeBitmap(\n              ImageDecoder.createSource(getContentResolver(), request.getImageUri()));\n      ImageDescriptionRequest imageDescriptionRequest =\n          ImageDescriptionRequest.builder(bitmap).build();\n      return Futures.transform(\n          streamingCallback != null\n              ? imageDescriber.runInference(imageDescriptionRequest, streamingCallback)\n              : imageDescriber.runInference(imageDescriptionRequest),\n          result -> ImmutableList.of(requireNonNull(result).getDescription()),\n          ContextCompat.getMainExecutor(this));\n    } catch (IOException e) {\n      return immediateFailedFuture(e);\n    }\n  }\n\n  @Override\n  protected void startGeneratingUi() {\n    super.startGeneratingUi();\n    selectImageButton.setEnabled(false);\n    selectImageButton.setText(R.string.generating);\n  }\n\n  @Override\n  protected void endGeneratingUi(String debugInfo) {\n    super.endGeneratingUi(debugInfo);\n    selectImageButton.setEnabled(true);\n    selectImageButton.setText(R.string.button_select_image);\n  }\n\n  @Override\n  protected List<String> runInferenceForBatchTask(String request) {\n    throw new UnsupportedOperationException(\"Not supported\");\n  }\n\n  private void initImageDescriptor() {\n    if (imageDescriber != null) {\n      imageDescriber.close();\n    }\n    ImageDescriberOptions options = ImageDescriberOptions.builder(this).build();\n    imageDescriber = ImageDescription.getClient(options);\n    resetProcessor();\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/java/OpenPromptActivity.java",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo.java;\n\nimport static com.google.common.util.concurrent.Futures.immediateFailedFuture;\nimport static com.google.common.util.concurrent.Futures.immediateFuture;\n\nimport android.app.AlertDialog;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.EditText;\nimport android.widget.ImageButton;\nimport android.widget.ImageView;\nimport android.widget.Toast;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\nimport com.bumptech.glide.Glide;\nimport com.google.common.collect.ImmutableList;\nimport com.google.common.util.concurrent.FutureCallback;\nimport com.google.common.util.concurrent.Futures;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport com.google.mlkit.genai.common.DownloadCallback;\nimport com.google.mlkit.genai.common.StreamingCallback;\nimport com.google.mlkit.genai.demo.ContentAdapter;\nimport com.google.mlkit.genai.demo.ContentItem;\nimport com.google.mlkit.genai.demo.GenerationConfigDialog;\nimport com.google.mlkit.genai.demo.GenerationConfigUtils;\nimport com.google.mlkit.genai.demo.R;\nimport com.google.mlkit.genai.prompt.CachedContext;\nimport com.google.mlkit.genai.prompt.Candidate;\nimport com.google.mlkit.genai.prompt.CountTokensResponse;\nimport com.google.mlkit.genai.prompt.CreateCachedContextRequest;\nimport com.google.mlkit.genai.prompt.GenerateContentRequest;\nimport com.google.mlkit.genai.prompt.GenerateContentResponse;\nimport com.google.mlkit.genai.prompt.Generation;\nimport com.google.mlkit.genai.prompt.GenerationConfig;\nimport com.google.mlkit.genai.prompt.GenerativeModel;\nimport com.google.mlkit.genai.prompt.ImagePart;\nimport com.google.mlkit.genai.prompt.PromptPrefix;\nimport com.google.mlkit.genai.prompt.TextPart;\nimport com.google.mlkit.genai.prompt.java.CachesFutures;\nimport com.google.mlkit.genai.prompt.java.GenerativeModelFutures;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * An activity that demonstrates a chat-like interface for the Open Prompt API in Java, allowing\n * requests with both text and multiple images, and including generation configuration.\n */\npublic class OpenPromptActivity extends BaseActivity<ContentItem>\n    implements GenerationConfigDialog.OnConfigUpdateListener {\n\n  private static final String TAG = OpenPromptActivity.class.getSimpleName();\n  private static final int ACTION_CLEAR_CACHES = 1000;\n\n  private GenerativeModelFutures generativeModelFutures;\n  private CachesFutures cachesFutures;\n  private EditText requestEditText;\n  private Button sendButton;\n  private ImageButton selectImageButton;\n  private ImageView imagePreview;\n  private Button configButton;\n  private EditText prefixEditText;\n  private CheckBox createCacheCheckBox;\n\n  @Nullable private Uri selectedImageUri = null;\n\n  @Nullable private Float curTemperature = null;\n  @Nullable private Integer curTopK = null;\n  @Nullable private Integer curSeed = null;\n  @Nullable private Integer curMaxOutputTokens = null;\n  @Nullable private Integer curCandidateCount = null;\n  private boolean useDefaultConfig = false;\n  private boolean useExplicitCache = false;\n\n  private final ActivityResultLauncher<String> pickImageLauncher =\n      registerForActivityResult(\n          new ActivityResultContracts.GetContent(),\n          uri -> {\n            if (uri != null) {\n              selectedImageUri = uri;\n              Glide.with(this).load(uri).into(imagePreview);\n              imagePreview.setVisibility(View.VISIBLE);\n              Toast.makeText(this, \"1 image selected\", Toast.LENGTH_SHORT).show();\n            } else {\n              Toast.makeText(this, \"No image selected\", Toast.LENGTH_SHORT).show();\n            }\n          });\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    requestEditText = findViewById(R.id.request_edit_text);\n    sendButton = findViewById(R.id.send_button);\n    selectImageButton = findViewById(R.id.select_image_prompt_button);\n    imagePreview = findViewById(R.id.image_thumbnail_preview_input);\n    configButton = findViewById(R.id.config_button);\n    prefixEditText = findViewById(R.id.prefix_edit_text);\n    createCacheCheckBox = findViewById(R.id.create_cache_checkbox);\n    createCacheCheckBox.setOnCheckedChangeListener(\n        (buttonView, isChecked) -> {\n          prefixEditText.setText(\"\");\n          updateRequestEditTextHint();\n          updatePrefixEditTextState();\n        });\n\n    selectImageButton.setOnClickListener(v -> pickImageLauncher.launch(\"image/*\"));\n\n    // Remove the selected image when the user clicks on the image preview.\n    imagePreview.setOnClickListener(\n        v -> {\n          selectedImageUri = null;\n          Glide.with(this).clear(imagePreview);\n          imagePreview.setVisibility(View.GONE);\n          Toast.makeText(this, \"Image removed\", Toast.LENGTH_SHORT).show();\n        });\n\n    configButton.setOnClickListener(\n        v -> new GenerationConfigDialog().show(getSupportFragmentManager(), null));\n\n    sendButton.setOnClickListener(\n        v -> {\n          if (useExplicitCache) {\n            String cacheName = prefixEditText.getText().toString().trim();\n            if (TextUtils.isEmpty(cacheName)) {\n              Toast.makeText(this, R.string.cache_name_empty, Toast.LENGTH_SHORT).show();\n              return;\n            }\n            String text = requestEditText.getText().toString().trim();\n            if (createCacheCheckBox.isChecked()) {\n              if (TextUtils.isEmpty(text)) {\n                Toast.makeText(this, R.string.prefix_to_cache_empty, Toast.LENGTH_SHORT).show();\n                return;\n              }\n              onSend(ContentItem.CacheRequestItem.Companion.fromRequest(cacheName, text));\n            } else {\n              if (TextUtils.isEmpty(text)) {\n                Toast.makeText(this, R.string.input_message_is_empty, Toast.LENGTH_SHORT).show();\n                return;\n              }\n              onSend(ContentItem.TextWithPrefixCacheItem.Companion.fromRequest(cacheName, text));\n            }\n            requestEditText.setText(\"\");\n            return;\n          }\n\n          String requestText = requestEditText.getText().toString().trim();\n          if (TextUtils.isEmpty(requestText)) {\n            Toast.makeText(this, R.string.input_message_is_empty, Toast.LENGTH_SHORT).show();\n            return;\n          }\n\n          String prefixText = prefixEditText.getText().toString().trim();\n          if (!TextUtils.isEmpty(prefixText) && selectedImageUri != null) {\n            Toast.makeText(this, R.string.warning_prefix_used_with_image, Toast.LENGTH_LONG).show();\n            return;\n          }\n\n          ContentItem requestItem;\n          if (selectedImageUri != null) {\n            requestItem =\n                new ContentItem.TextAndImagesItem(\n                    requestText,\n                    new ArrayList<>(ImmutableList.of(selectedImageUri)),\n                    ContentAdapter.VIEW_TYPE_REQUEST_TEXT_AND_IMAGES);\n          } else if (!TextUtils.isEmpty(prefixText)) {\n            requestItem =\n                ContentItem.TextWithPromptPrefixItem.Companion.fromRequest(prefixText, requestText);\n          } else {\n            requestItem = ContentItem.TextItem.Companion.fromRequest(requestText);\n          }\n          onSend(requestItem);\n          requestEditText.setText(\"\");\n          imagePreview.setVisibility(View.GONE);\n          selectedImageUri = null;\n        });\n\n    onConfigUpdated();\n\n    initGenerator();\n  }\n\n  @Override\n  public void onConfigUpdated() {\n    useDefaultConfig = GenerationConfigUtils.getUseDefaultConfig(getApplicationContext());\n    if (useDefaultConfig) {\n      // Cache cannot be used in the simple utility API.\n      GenerationConfigUtils.setUseExplicitCache(getApplicationContext(), false);\n    }\n    useExplicitCache = GenerationConfigUtils.getUseExplicitCache(getApplicationContext());\n\n    if (useExplicitCache) {\n      prefixEditText.setVisibility(View.VISIBLE);\n      prefixEditText.setHint(R.string.hint_add_cache_name);\n      createCacheCheckBox.setVisibility(View.VISIBLE);\n      configButton.setVisibility(View.VISIBLE);\n      selectImageButton.setVisibility(View.GONE);\n      imagePreview.setVisibility(View.GONE);\n      selectedImageUri = null;\n    } else {\n      prefixEditText.setVisibility(useDefaultConfig ? View.GONE : View.VISIBLE);\n      prefixEditText.setHint(R.string.hint_add_prompt_prefix);\n      createCacheCheckBox.setVisibility(View.GONE);\n      configButton.setVisibility(useDefaultConfig ? View.GONE : View.VISIBLE);\n      selectImageButton.setVisibility(useDefaultConfig ? View.GONE : View.VISIBLE);\n      imagePreview.setVisibility(\n          useDefaultConfig || selectedImageUri == null ? View.GONE : View.VISIBLE);\n    }\n    prefixEditText.setText(\"\");\n    requestEditText.setText(\"\");\n    updateRequestEditTextHint();\n    updatePrefixEditTextState();\n\n    curTemperature = GenerationConfigUtils.getTemperature(getApplicationContext());\n    curTopK = GenerationConfigUtils.getTopK(getApplicationContext());\n    curSeed = GenerationConfigUtils.getSeed(getApplicationContext());\n    curCandidateCount = GenerationConfigUtils.getCandidateCount(getApplicationContext());\n    curMaxOutputTokens = GenerationConfigUtils.getMaxOutputTokens(getApplicationContext());\n  }\n\n  private void updateRequestEditTextHint() {\n    int hintResourceId = R.string.hint_type_a_message;\n    if (useExplicitCache) {\n      if (createCacheCheckBox.isChecked()) {\n        hintResourceId = R.string.hint_add_prefix_to_cache;\n      } else {\n        hintResourceId = R.string.hint_add_suffix_for_inference;\n      }\n    }\n    requestEditText.setHint(hintResourceId);\n  }\n\n  private void showCacheSelectionDialog() {\n    Futures.addCallback(\n        cachesFutures.list(),\n        new FutureCallback<List<CachedContext>>() {\n          @Override\n          public void onSuccess(List<CachedContext> result) {\n            if (result == null || result.isEmpty()) {\n              Toast.makeText(\n                      OpenPromptActivity.this, \"No caches available to select\", Toast.LENGTH_SHORT)\n                  .show();\n              return;\n            }\n            List<String> cacheNamesList = new ArrayList<>();\n            for (CachedContext cache : result) {\n              cacheNamesList.add(cache.getName());\n            }\n            String[] cacheNames = cacheNamesList.toArray(new String[0]);\n            new AlertDialog.Builder(OpenPromptActivity.this)\n                .setTitle(\"Select Cache\")\n                .setItems(cacheNames, (dialog, which) -> prefixEditText.setText(cacheNames[which]))\n                .show();\n          }\n\n          @Override\n          public void onFailure(Throwable t) {\n            Toast.makeText(OpenPromptActivity.this, \"Failed to list caches\", Toast.LENGTH_SHORT)\n                .show();\n          }\n        },\n        ContextCompat.getMainExecutor(this));\n  }\n\n  private void updatePrefixEditTextState() {\n    if (useExplicitCache && !createCacheCheckBox.isChecked()) {\n      prefixEditText.setFocusable(false);\n      prefixEditText.setClickable(true);\n      prefixEditText.setOnClickListener(v -> showCacheSelectionDialog());\n      prefixEditText.setHint(R.string.hint_select_cache_name);\n    } else {\n      prefixEditText.setFocusable(true);\n      prefixEditText.setFocusableInTouchMode(true);\n      prefixEditText.setClickable(false);\n      prefixEditText.setOnClickListener(null);\n      if (useExplicitCache) {\n        prefixEditText.setHint(R.string.hint_add_cache_name);\n      } else {\n        prefixEditText.setHint(R.string.hint_add_prompt_prefix);\n      }\n    }\n  }\n\n  @Override\n  protected int getLayoutResId() {\n    return R.layout.activity_openprompt;\n  }\n\n  @Override\n  protected ListenableFuture<List<String>> runInferenceImpl(\n      ContentItem request, @Nullable StreamingCallback streamingCallback) {\n    if (request instanceof ContentItem.CacheRequestItem cacheRequestItem) {\n      return createCache(cacheRequestItem);\n    }\n    try {\n      ListenableFuture<GenerateContentResponse> inferenceFuture;\n      if (request instanceof ContentItem.TextItem textItem && useDefaultConfig) {\n        // useDefaultConfig is used for the case where user wants to use utility function with\n        // default config values\n        inferenceFuture =\n            (streamingCallback != null)\n                ? generativeModelFutures.generateContent(textItem.getText(), streamingCallback)\n                : generativeModelFutures.generateContent(textItem.getText());\n      } else {\n        GenerateContentRequest genRequest = buildGenerateContentRequest(request);\n        inferenceFuture =\n            (streamingCallback != null)\n                ? generativeModelFutures.generateContent(genRequest, streamingCallback)\n                : generativeModelFutures.generateContent(genRequest);\n      }\n\n      return Futures.transform(\n          inferenceFuture,\n          (GenerateContentResponse result) -> {\n            if (result == null) {\n              return ImmutableList.of();\n            }\n\n            ImmutableList.Builder<String> listBuilder = new ImmutableList.Builder<>();\n            for (Candidate candidate : result.getCandidates()) {\n              String text = candidate.getText();\n              if (candidate.getFinishReason() == Candidate.FinishReason.MAX_TOKENS) {\n                listBuilder.add(text + \"\\n(FinishReason: MAX_TOKENS)\");\n              } else {\n                listBuilder.add(text);\n              }\n            }\n            return listBuilder.build();\n          },\n          ContextCompat.getMainExecutor(this));\n    } catch (RuntimeException e) {\n      return immediateFailedFuture(e);\n    }\n  }\n\n  @Override\n  protected ListenableFuture<CountTokensResponse> countTokens(ContentItem request) {\n    if (request instanceof ContentItem.CacheRequestItem) {\n      // Count tokens does not support for cache request by now.\n      return immediateFuture(new CountTokensResponse(0));\n    }\n    try {\n      GenerateContentRequest genRequest = buildGenerateContentRequest(request);\n      return generativeModelFutures.countTokens(genRequest);\n    } catch (RuntimeException e) {\n      return immediateFailedFuture(e);\n    }\n  }\n\n  @Override\n  protected ListenableFuture<Integer> getTokenLimit() {\n    try {\n      return generativeModelFutures.getTokenLimit();\n    } catch (RuntimeException e) {\n      return immediateFailedFuture(e);\n    }\n  }\n\n  private GenerateContentRequest buildGenerateContentRequest(ContentItem request) {\n    String requestText = \"\";\n    String promptPrefixText = \"\";\n    Bitmap imageBitmap = null;\n    String cachedContextNameText = null;\n    if (request instanceof ContentItem.TextAndImagesItem tiRequest) {\n      if (tiRequest.getText() != null) {\n        requestText = tiRequest.getText();\n      }\n      for (Uri uri : tiRequest.getImageUris()) {\n        try (InputStream inputStream = getContentResolver().openInputStream(uri)) {\n          imageBitmap = BitmapFactory.decodeStream(inputStream);\n        } catch (IOException e) {\n          Log.e(TAG, \"Error decoding image URI: \" + uri, e);\n        }\n      }\n    } else if (request instanceof ContentItem.TextItem textItem) {\n      requestText = textItem.getText();\n    } else if (request instanceof ContentItem.TextWithPromptPrefixItem textWithPromptPrefixItem) {\n      requestText = textWithPromptPrefixItem.getDynamicSuffix();\n      promptPrefixText = textWithPromptPrefixItem.getPromptPrefix();\n    } else if (request instanceof ContentItem.TextWithPrefixCacheItem textWithPrefixCacheItem) {\n      requestText = textWithPrefixCacheItem.getDynamicSuffix();\n      cachedContextNameText = textWithPrefixCacheItem.getCacheName();\n    } else if (request instanceof ContentItem.CacheRequestItem) {\n      throw new IllegalArgumentException(\"CacheRequestItem is for creating cache only.\");\n    }\n\n    GenerateContentRequest.Builder requestBuilder;\n\n    if (imageBitmap != null) {\n      requestBuilder =\n          new GenerateContentRequest.Builder(new ImagePart(imageBitmap), new TextPart(requestText));\n    } else {\n      requestBuilder = new GenerateContentRequest.Builder(new TextPart(requestText));\n      if (useExplicitCache) {\n        requestBuilder.setCachedContextName(cachedContextNameText);\n      } else {\n        requestBuilder.setPromptPrefix(new PromptPrefix(promptPrefixText));\n      }\n    }\n\n    requestBuilder.setTemperature(curTemperature);\n    requestBuilder.setTopK(curTopK);\n    requestBuilder.setSeed(curSeed);\n    requestBuilder.setMaxOutputTokens(curMaxOutputTokens);\n    requestBuilder.setCandidateCount(curCandidateCount);\n\n    return requestBuilder.build();\n  }\n\n  @Override\n  protected List<String> runInferenceForBatchTask(String request) {\n    try {\n      GenerateContentResponse result;\n      if (useDefaultConfig) {\n        // useDefaultConfig is used for the case where user wants to use utility function with\n        // default config values\n        result = generativeModelFutures.generateContent(request).get();\n      } else {\n        result =\n            generativeModelFutures\n                .generateContent(\n                    buildGenerateContentRequest(\n                        ContentItem.TextItem.Companion.fromRequest(request)))\n                .get();\n      }\n      if (result.getCandidates().get(0).getText() != null) {\n        return ImmutableList.of(result.getCandidates().get(0).getText());\n      }\n      return ImmutableList.of();\n    } catch (Exception e) {\n      if (e instanceof InterruptedException) {\n        Thread.currentThread().interrupt();\n      }\n      return ImmutableList.of(\"Failed to run inference: \" + e.getMessage());\n    }\n  }\n\n  @Override\n  protected void startGeneratingUi() {\n    super.startGeneratingUi();\n    sendButton.setText(R.string.generating);\n    sendButton.setEnabled(false);\n    requestEditText.setEnabled(false);\n    selectImageButton.setEnabled(false);\n    configButton.setEnabled(false);\n  }\n\n  @Override\n  protected void endGeneratingUi(String debugInfo) {\n    super.endGeneratingUi(debugInfo);\n    sendButton.setText(R.string.button_send);\n    sendButton.setEnabled(true);\n    requestEditText.setEnabled(true);\n    selectImageButton.setEnabled(true);\n    configButton.setEnabled(true);\n  }\n\n  private void initGenerator() {\n    if (generativeModelFutures != null) {\n      generativeModelFutures.getGenerativeModel().close();\n    }\n    GenerationConfig.Builder optionsBuilder = new GenerationConfig.Builder();\n\n    GenerativeModel generativeModel = Generation.INSTANCE.getClient(optionsBuilder.build());\n    this.generativeModelFutures = GenerativeModelFutures.from(generativeModel);\n    this.cachesFutures = CachesFutures.from(generativeModel);\n    resetProcessor();\n  }\n\n  private ListenableFuture<List<String>> createCache(ContentItem.CacheRequestItem request) {\n    CreateCachedContextRequest cacheRequest =\n        new CreateCachedContextRequest.Builder(\n                request.getCacheName(), new PromptPrefix(request.getPrefixToCache()))\n            .build();\n\n    String cachedSuccessMessage = getString(R.string.prefix_cached) + \": \" + request.getCacheName();\n    return Futures.transform(\n        cachesFutures.create(cacheRequest),\n        response -> ImmutableList.of(cachedSuccessMessage),\n        ContextCompat.getMainExecutor(this));\n  }\n\n  @Override\n  protected ListenableFuture<String> getBaseModelName() {\n    return generativeModelFutures.getBaseModelName();\n  }\n\n  @Override\n  protected ListenableFuture<Integer> checkFeatureStatus() {\n    return generativeModelFutures.checkStatus();\n  }\n\n  @Override\n  protected ListenableFuture<Void> downloadFeature(DownloadCallback callback) {\n    return generativeModelFutures.download(callback);\n  }\n\n  @Override\n  public boolean onCreateOptionsMenu(Menu menu) {\n    if (!super.onCreateOptionsMenu(menu)) {\n      return false;\n    }\n    menu.add(Menu.NONE, ACTION_CLEAR_CACHES, Menu.NONE, \"Clear all prefix caches\");\n    return true;\n  }\n\n  @Override\n  public boolean onPrepareOptionsMenu(Menu menu) {\n    MenuItem item = menu.findItem(R.id.action_simple_api);\n    if (item != null) {\n      item.setVisible(true);\n      item.setChecked(useDefaultConfig);\n    }\n    MenuItem explicitCacheItem = menu.findItem(R.id.action_explicit_cache);\n    if (explicitCacheItem != null) {\n      explicitCacheItem.setVisible(true);\n      explicitCacheItem.setEnabled(!useDefaultConfig);\n      explicitCacheItem.setChecked(useExplicitCache);\n    }\n    return super.onPrepareOptionsMenu(menu);\n  }\n\n  @Override\n  public boolean onOptionsItemSelected(MenuItem item) {\n    if (item.getItemId() == ACTION_CLEAR_CACHES) {\n      if (useExplicitCache) {\n        Futures.addCallback(\n            cachesFutures.list(),\n            generateExplicitCachesClearCallback(),\n            ContextCompat.getMainExecutor(this));\n      } else {\n        Futures.addCallback(\n            generativeModelFutures.clearImplicitCaches(),\n            generateImplicitCachesClearCallback(),\n            ContextCompat.getMainExecutor(this));\n      }\n      return true;\n    } else if (item.getItemId() == R.id.action_simple_api) {\n      boolean newState = !item.isChecked();\n      item.setChecked(newState);\n      GenerationConfigUtils.setUseDefaultConfig(getApplicationContext(), newState);\n      onConfigUpdated();\n      return true;\n    } else if (item.getItemId() == R.id.action_explicit_cache) {\n      boolean newState = !item.isChecked();\n      item.setChecked(newState);\n      GenerationConfigUtils.setUseExplicitCache(getApplicationContext(), newState);\n      onConfigUpdated();\n      return true;\n    }\n    return super.onOptionsItemSelected(item);\n  }\n\n  private FutureCallback<List<CachedContext>> generateExplicitCachesClearCallback() {\n    return new FutureCallback<>() {\n      @Override\n      public void onSuccess(List<CachedContext> result) {\n        if (result != null && !result.isEmpty()) {\n          Log.d(TAG, \"Going to delete explicit caches, size: \" + result.size());\n          List<ListenableFuture<Boolean>> deleteFutures = new ArrayList<>();\n          for (CachedContext cache : result) {\n            String cacheName = cache.getName();\n            ListenableFuture<Boolean> deleteFuture = cachesFutures.delete(cacheName);\n            deleteFutures.add(deleteFuture);\n            Futures.addCallback(\n                deleteFuture,\n                generateExplicitCacheDeleteCallback(cacheName),\n                ContextCompat.getMainExecutor(OpenPromptActivity.this));\n          }\n          var unused =\n              Futures.whenAllComplete(deleteFutures)\n                  .run(\n                      () -> {\n                        prefixEditText.setText(\"\");\n                        Toast.makeText(\n                                OpenPromptActivity.this, \"Caches cleared\", Toast.LENGTH_SHORT)\n                            .show();\n                      },\n                      ContextCompat.getMainExecutor(OpenPromptActivity.this));\n        } else {\n          Toast.makeText(OpenPromptActivity.this, \"No caches to clear\", Toast.LENGTH_SHORT).show();\n        }\n      }\n\n      @Override\n      public void onFailure(Throwable t) {\n        Toast.makeText(OpenPromptActivity.this, \"Failed to list caches\", Toast.LENGTH_SHORT).show();\n      }\n    };\n  }\n\n  private FutureCallback<Boolean> generateExplicitCacheDeleteCallback(String cacheName) {\n    return new FutureCallback<>() {\n      @Override\n      public void onSuccess(Boolean deleted) {\n        if (deleted) {\n          Log.d(TAG, \"Deleted explicit cache: \" + cacheName);\n        } else {\n          Log.d(TAG, \"Failed to delete explicit cache: \" + cacheName);\n        }\n      }\n\n      @Override\n      public void onFailure(Throwable t) {\n        Log.d(TAG, \"Failed to delete explicit cache: \" + cacheName, t);\n      }\n    };\n  }\n\n  private FutureCallback<Void> generateImplicitCachesClearCallback() {\n    return new FutureCallback<Void>() {\n      @Override\n      public void onSuccess(Void result) {\n        Toast.makeText(OpenPromptActivity.this, \"Caches cleared\", Toast.LENGTH_SHORT).show();\n      }\n\n      @Override\n      public void onFailure(Throwable t) {\n        Toast.makeText(OpenPromptActivity.this, \"Failed to clear caches\", Toast.LENGTH_SHORT)\n            .show();\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/java/ProofreadingActivity.java",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.genai.demo.java;\n\nimport static com.google.common.collect.ImmutableList.toImmutableList;\nimport static com.google.common.util.concurrent.Futures.immediateFailedFuture;\nimport static java.util.Objects.requireNonNull;\n\nimport android.os.Bundle;\nimport androidx.annotation.Nullable;\nimport android.util.Log;\nimport androidx.core.content.ContextCompat;\nimport com.google.common.util.concurrent.Futures;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport com.google.mlkit.genai.common.DownloadCallback;\nimport com.google.mlkit.genai.common.FeatureStatus;\nimport com.google.mlkit.genai.common.StreamingCallback;\nimport com.google.mlkit.genai.demo.ContentItem.TextItem;\nimport com.google.mlkit.genai.demo.R;\nimport com.google.mlkit.genai.prompt.CountTokensResponse;\nimport com.google.mlkit.genai.proofreading.Proofreader;\nimport com.google.mlkit.genai.proofreading.ProofreaderOptions;\nimport com.google.mlkit.genai.proofreading.ProofreaderOptions.InputType;\nimport com.google.mlkit.genai.proofreading.ProofreaderOptions.Language;\nimport com.google.mlkit.genai.proofreading.Proofreading;\nimport com.google.mlkit.genai.proofreading.ProofreadingRequest;\nimport com.google.mlkit.genai.proofreading.ProofreadingResult;\nimport com.google.mlkit.genai.proofreading.ProofreadingSuggestion;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\n\n/** Demonstrates the Proofreading API usage. */\npublic class ProofreadingActivity extends TextInputBaseActivity {\n  private static final String TAG = ProofreadingActivity.class.getSimpleName();\n\n  private int inputType = InputType.KEYBOARD;\n  private int language = Language.ENGLISH;\n  private Proofreader proofreader;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    setUpSpinners();\n    initProofreader();\n  }\n\n  @Override\n  protected int getLayoutResId() {\n    return R.layout.activity_proofreading;\n  }\n\n  @Override\n  protected void onDestroy() {\n    super.onDestroy();\n    if (proofreader != null) {\n      proofreader.close();\n    }\n  }\n\n  @Override\n  protected ListenableFuture<String> getBaseModelName() {\n    return proofreader.getBaseModelName();\n  }\n\n  @Override\n  @FeatureStatus\n  protected ListenableFuture<Integer> checkFeatureStatus() {\n    return proofreader.checkFeatureStatus();\n  }\n\n  @Override\n  protected ListenableFuture<Void> downloadFeature(DownloadCallback callback) {\n    return proofreader.downloadFeature(callback);\n  }\n\n  @Override\n  protected ListenableFuture<List<String>> runInferenceImpl(\n      TextItem request, @Nullable StreamingCallback streamingCallback) {\n    ProofreadingRequest proofreadingRequest =\n        ProofreadingRequest.builder(request.getText()).build();\n    return Futures.transform(\n        streamingCallback != null\n            ? proofreader.runInference(proofreadingRequest, streamingCallback)\n            : proofreader.runInference(proofreadingRequest),\n        proofreadingResult ->\n            requireNonNull(proofreadingResult).getResults().stream()\n                .map(ProofreadingSuggestion::getText)\n                .collect(toImmutableList()),\n        ContextCompat.getMainExecutor(this));\n  }\n\n  private void setUpSpinners() {\n    setupSpinner(\n        R.id.input_type_spinner,\n        R.array.proofreading_input_types,\n        position -> {\n          if (position == 1) {\n            inputType = InputType.VOICE;\n          } else {\n            inputType = InputType.KEYBOARD;\n          }\n          initProofreader();\n        });\n\n    setupSpinner(\n        R.id.language_spinner,\n        R.array.proofreading_languages,\n        position -> {\n          switch (position) {\n            case 1 -> language = Language.JAPANESE;\n            case 2 -> language = Language.GERMAN;\n            case 3 -> language = Language.FRENCH;\n            case 4 -> language = Language.ITALIAN;\n            case 5 -> language = Language.SPANISH;\n            case 6 -> language = Language.KOREAN;\n            default -> language = Language.ENGLISH;\n          }\n          initProofreader();\n        });\n  }\n\n  private void initProofreader() {\n    if (proofreader != null) {\n      proofreader.close();\n    }\n    ProofreaderOptions options =\n        ProofreaderOptions.builder(this).setInputType(inputType).setLanguage(language).build();\n    proofreader = Proofreading.getClient(options);\n    resetProcessor();\n  }\n\n  @Override\n  protected ListenableFuture<CountTokensResponse> countTokens(TextItem request) {\n    return immediateFailedFuture(new UnsupportedOperationException(\"Not supported\"));\n  }\n\n  @Override\n  protected ListenableFuture<Integer> getTokenLimit() {\n    return immediateFailedFuture(new UnsupportedOperationException(\"Not supported\"));\n  }\n\n  @Override\n  protected List<String> runInferenceForBatchTask(String request) {\n    try {\n      List<String> outputColumns = new ArrayList<>();\n      ProofreadingResult result =\n          proofreader.runInference(ProofreadingRequest.builder(request).build()).get();\n      for (ProofreadingSuggestion suggestion : result.getResults()) {\n        outputColumns.add(suggestion.getText());\n      }\n      return outputColumns;\n    } catch (ExecutionException | InterruptedException e) {\n      Log.e(TAG, \"Failed to run inference.\", e);\n      return Arrays.asList(\"Failed to run inference: \" + e.getMessage(), \"0\");\n    }\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/java/RewritingActivity.java",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.genai.demo.java;\n\nimport static com.google.common.collect.ImmutableList.toImmutableList;\nimport static com.google.common.util.concurrent.Futures.immediateFailedFuture;\nimport static java.util.Objects.requireNonNull;\n\nimport android.os.Bundle;\nimport androidx.annotation.Nullable;\nimport android.util.Log;\nimport androidx.core.content.ContextCompat;\nimport com.google.common.util.concurrent.Futures;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport com.google.mlkit.genai.common.DownloadCallback;\nimport com.google.mlkit.genai.common.FeatureStatus;\nimport com.google.mlkit.genai.common.StreamingCallback;\nimport com.google.mlkit.genai.demo.ContentItem.TextItem;\nimport com.google.mlkit.genai.demo.R;\nimport com.google.mlkit.genai.prompt.CountTokensResponse;\nimport com.google.mlkit.genai.rewriting.Rewriter;\nimport com.google.mlkit.genai.rewriting.RewriterOptions;\nimport com.google.mlkit.genai.rewriting.RewriterOptions.Language;\nimport com.google.mlkit.genai.rewriting.RewriterOptions.OutputType;\nimport com.google.mlkit.genai.rewriting.Rewriting;\nimport com.google.mlkit.genai.rewriting.RewritingRequest;\nimport com.google.mlkit.genai.rewriting.RewritingResult;\nimport com.google.mlkit.genai.rewriting.RewritingSuggestion;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\n\n/** Demonstrates the Rewriting API usage. */\npublic class RewritingActivity extends TextInputBaseActivity {\n  private static final String TAG = RewritingActivity.class.getSimpleName();\n\n  private int outputType = OutputType.ELABORATE;\n  private int language = Language.ENGLISH;\n  private Rewriter rewriter;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    setUpSpinners();\n    initRewriter();\n  }\n\n  @Override\n  protected int getLayoutResId() {\n    return R.layout.activity_rewrite;\n  }\n\n  @Override\n  protected void onDestroy() {\n    super.onDestroy();\n    if (rewriter != null) {\n      rewriter.close();\n    }\n  }\n\n  @Override\n  protected ListenableFuture<String> getBaseModelName() {\n    return rewriter.getBaseModelName();\n  }\n\n  @Override\n  @FeatureStatus\n  protected ListenableFuture<Integer> checkFeatureStatus() {\n    return rewriter.checkFeatureStatus();\n  }\n\n  @Override\n  protected ListenableFuture<Void> downloadFeature(DownloadCallback callback) {\n    return rewriter.downloadFeature(callback);\n  }\n\n  @Override\n  protected ListenableFuture<CountTokensResponse> countTokens(TextItem request) {\n    return immediateFailedFuture(new UnsupportedOperationException(\"Not supported\"));\n  }\n\n  @Override\n  protected ListenableFuture<Integer> getTokenLimit() {\n    return immediateFailedFuture(new UnsupportedOperationException(\"Not supported\"));\n  }\n\n  @Override\n  protected ListenableFuture<List<String>> runInferenceImpl(\n      TextItem request, @Nullable StreamingCallback streamingCallback) {\n    RewritingRequest rewritingRequest = RewritingRequest.builder(request.getText()).build();\n    return Futures.transform(\n        streamingCallback != null\n            ? rewriter.runInference(rewritingRequest, streamingCallback)\n            : rewriter.runInference(rewritingRequest),\n        rewriteResult ->\n            requireNonNull(rewriteResult).getResults().stream()\n                .map(RewritingSuggestion::getText)\n                .collect(toImmutableList()),\n        ContextCompat.getMainExecutor(this));\n  }\n\n  private void setUpSpinners() {\n    setupSpinner(\n        R.id.output_type_spinner,\n        R.array.rewriting_output_types,\n        position -> {\n          switch (position) {\n            case 1 -> outputType = OutputType.EMOJIFY;\n            case 2 -> outputType = OutputType.SHORTEN;\n            case 3 -> outputType = OutputType.FRIENDLY;\n            case 4 -> outputType = OutputType.PROFESSIONAL;\n            case 5 -> outputType = OutputType.REPHRASE;\n            default -> outputType = OutputType.ELABORATE;\n          }\n          initRewriter();\n        });\n\n    setupSpinner(\n        R.id.language_spinner,\n        R.array.rewriting_languages,\n        position -> {\n          switch (position) {\n            case 1 -> language = Language.JAPANESE;\n            case 2 -> language = Language.GERMAN;\n            case 3 -> language = Language.FRENCH;\n            case 4 -> language = Language.ITALIAN;\n            case 5 -> language = Language.SPANISH;\n            case 6 -> language = Language.KOREAN;\n            default -> language = Language.ENGLISH;\n          }\n          initRewriter();\n        });\n  }\n\n  private void initRewriter() {\n    if (rewriter != null) {\n      rewriter.close();\n    }\n    RewriterOptions options =\n        RewriterOptions.builder(this).setOutputType(outputType).setLanguage(language).build();\n    rewriter = Rewriting.getClient(options);\n    resetProcessor();\n  }\n\n  @Override\n  protected List<String> runInferenceForBatchTask(String request) {\n    try {\n      List<String> outputColumns = new ArrayList<>();\n      RewritingResult result =\n          rewriter.runInference(RewritingRequest.builder(request).build()).get();\n      for (RewritingSuggestion suggestion : result.getResults()) {\n        outputColumns.add(suggestion.getText());\n      }\n      return outputColumns;\n    } catch (ExecutionException | InterruptedException e) {\n      Log.e(TAG, \"Failed to run inference.\", e);\n      return Arrays.asList(\"Failed to run inference: \" + e.getMessage(), \"0\");\n    }\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/java/SummarizationActivity.java",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.genai.demo.java;\n\nimport static com.google.common.util.concurrent.Futures.immediateFailedFuture;\nimport static java.util.Objects.requireNonNull;\n\nimport android.os.Bundle;\nimport androidx.annotation.Nullable;\nimport android.util.Log;\nimport androidx.core.content.ContextCompat;\nimport com.google.common.collect.ImmutableList;\nimport com.google.common.util.concurrent.Futures;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport com.google.mlkit.genai.common.DownloadCallback;\nimport com.google.mlkit.genai.common.FeatureStatus;\nimport com.google.mlkit.genai.common.StreamingCallback;\nimport com.google.mlkit.genai.demo.ContentItem.TextItem;\nimport com.google.mlkit.genai.demo.R;\nimport com.google.mlkit.genai.prompt.CountTokensResponse;\nimport com.google.mlkit.genai.summarization.Summarization;\nimport com.google.mlkit.genai.summarization.SummarizationRequest;\nimport com.google.mlkit.genai.summarization.SummarizationResult;\nimport com.google.mlkit.genai.summarization.Summarizer;\nimport com.google.mlkit.genai.summarization.SummarizerOptions;\nimport com.google.mlkit.genai.summarization.SummarizerOptions.InputType;\nimport com.google.mlkit.genai.summarization.SummarizerOptions.Language;\nimport com.google.mlkit.genai.summarization.SummarizerOptions.OutputType;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\n\n/** Demonstrates the Summarization API usage. */\npublic class SummarizationActivity extends TextInputBaseActivity {\n  private static final String TAG = SummarizationActivity.class.getSimpleName();\n\n  private int inputType = InputType.ARTICLE;\n  private int outputType = OutputType.ONE_BULLET;\n  private int language = Language.ENGLISH;\n  private Summarizer summarizer;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    setUpInputAndOutputTypeSpinners();\n    initSummarizer();\n  }\n\n  @Override\n  protected int getLayoutResId() {\n    return R.layout.activity_summarization;\n  }\n\n  @Override\n  protected void onDestroy() {\n    super.onDestroy();\n    if (summarizer != null) {\n      summarizer.close();\n    }\n  }\n\n  @Override\n  protected ListenableFuture<String> getBaseModelName() {\n    return summarizer.getBaseModelName();\n  }\n\n  @Override\n  @FeatureStatus\n  protected ListenableFuture<Integer> checkFeatureStatus() {\n    return summarizer.checkFeatureStatus();\n  }\n\n  @Override\n  protected ListenableFuture<Void> downloadFeature(DownloadCallback callback) {\n    return summarizer.downloadFeature(callback);\n  }\n\n  @Override\n  protected ListenableFuture<List<String>> runInferenceImpl(\n      TextItem request, @Nullable StreamingCallback streamingCallback) {\n    SummarizationRequest summarizationRequest =\n        SummarizationRequest.builder(request.getText()).build();\n    return Futures.transform(\n        streamingCallback != null\n            ? summarizer.runInference(summarizationRequest, streamingCallback)\n            : summarizer.runInference(summarizationRequest),\n        result -> ImmutableList.of(requireNonNull(result).getSummary()),\n        ContextCompat.getMainExecutor(this));\n  }\n\n  @Override\n  protected ListenableFuture<CountTokensResponse> countTokens(TextItem request) {\n    return immediateFailedFuture(new UnsupportedOperationException(\"Not supported\"));\n  }\n\n  @Override\n  protected ListenableFuture<Integer> getTokenLimit() {\n    return immediateFailedFuture(new UnsupportedOperationException(\"Not supported\"));\n  }\n\n  private void setUpInputAndOutputTypeSpinners() {\n    setupSpinner(\n        R.id.input_type_spinner,\n        R.array.summarization_input_types,\n        position -> {\n          if (position == 1) {\n            inputType = InputType.CONVERSATION;\n          } else {\n            inputType = InputType.ARTICLE;\n          }\n          initSummarizer();\n        });\n\n    setupSpinner(\n        R.id.output_type_spinner,\n        R.array.summarization_output_types,\n        position -> {\n          switch (position) {\n            case 1 -> outputType = OutputType.TWO_BULLETS;\n            case 2 -> outputType = OutputType.THREE_BULLETS;\n            default -> outputType = OutputType.ONE_BULLET;\n          }\n          initSummarizer();\n        });\n\n    setupSpinner(\n        R.id.language_spinner,\n        R.array.summarization_languages,\n        position -> {\n          switch (position) {\n            case 1 -> language = Language.JAPANESE;\n            case 2 -> language = Language.KOREAN;\n            default -> language = Language.ENGLISH;\n          }\n          initSummarizer();\n        });\n  }\n\n  private void initSummarizer() {\n    if (summarizer != null) {\n      summarizer.close();\n    }\n    SummarizerOptions options =\n        SummarizerOptions.builder(this)\n            .setInputType(inputType)\n            .setOutputType(outputType)\n            .setLanguage(language)\n            .build();\n    summarizer = Summarization.getClient(options);\n    resetProcessor();\n  }\n\n  @Override\n  protected List<String> runInferenceForBatchTask(String request) {\n    try {\n      SummarizationResult result =\n          summarizer.runInference(SummarizationRequest.builder(request).build()).get();\n      return ImmutableList.of(result.getSummary());\n    } catch (ExecutionException | InterruptedException e) {\n      Log.e(TAG, \"Failed to run inference.\", e);\n      return Arrays.asList(\"Failed to run inference: \" + e.getMessage(), \"0\");\n    }\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/java/TextInputBaseActivity.java",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.genai.demo.java;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.Toast;\nimport androidx.annotation.Nullable;\nimport com.google.mlkit.genai.demo.ContentItem.TextItem;\nimport com.google.mlkit.genai.demo.R;\n\n/** Base Activity for APIs that accept text input as request. */\nabstract class TextInputBaseActivity extends BaseActivity<TextItem> {\n\n  private EditText requestEditText;\n  private Button sendButton;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    requestEditText = findViewById(R.id.request_edit_text);\n    sendButton = findViewById(R.id.send_button);\n    sendButton.setOnClickListener(\n        view -> {\n          String request = requestEditText.getText().toString();\n          if (TextUtils.isEmpty(request)) {\n            Toast.makeText(this, R.string.input_message_is_empty, Toast.LENGTH_SHORT).show();\n            return;\n          }\n          onSend(TextItem.Companion.fromRequest(request));\n        });\n  }\n\n  @Override\n  protected void startGeneratingUi() {\n    super.startGeneratingUi();\n    sendButton.setEnabled(false);\n    sendButton.setText(R.string.generating);\n    requestEditText.setText(R.string.empty);\n  }\n\n  @Override\n  protected void endGeneratingUi(String debugInfo) {\n    super.endGeneratingUi(debugInfo);\n    sendButton.setEnabled(true);\n    sendButton.setText(R.string.button_send);\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/kotlin/BaseActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo.kotlin\n\nimport android.app.AlertDialog\nimport android.content.DialogInterface\nimport android.net.Uri\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport android.util.Log\nimport android.view.Menu\nimport android.view.MenuItem\nimport android.view.View\nimport android.widget.AdapterView\nimport android.widget.ArrayAdapter\nimport android.widget.Spinner\nimport android.widget.TextView\nimport androidx.activity.result.ActivityResultLauncher\nimport androidx.activity.result.contract.ActivityResultContracts.CreateDocument\nimport androidx.activity.result.contract.ActivityResultContracts.GetContent\nimport androidx.core.content.ContextCompat\nimport androidx.lifecycle.lifecycleScope\nimport com.google.common.util.concurrent.FutureCallback\nimport com.google.common.util.concurrent.Futures\nimport com.google.common.util.concurrent.ListenableFuture\nimport com.google.mlkit.genai.common.DownloadCallback\nimport com.google.mlkit.genai.common.FeatureStatus\nimport com.google.mlkit.genai.common.GenAiException\nimport com.google.mlkit.genai.common.StreamingCallback\nimport com.google.mlkit.genai.demo.ContentAdapter\nimport com.google.mlkit.genai.demo.ContentItem\nimport com.google.mlkit.genai.demo.R\nimport com.google.mlkit.genai.prompt.CountTokensResponse\nimport com.opencsv.CSVReader\nimport com.opencsv.CSVWriter\nimport java.io.InputStreamReader\nimport java.io.OutputStreamWriter\nimport java.text.SimpleDateFormat\nimport java.time.Instant\nimport java.util.Date\nimport java.util.Locale\nimport java.util.concurrent.Executors\nimport kotlinx.coroutines.flow.Flow\nimport kotlinx.coroutines.launch\n\n/** Base Activity for ML Kit GenAI APIs. */\nabstract class BaseActivity<RequestT : ContentItem> : AppCompatActivity() {\n\n  private lateinit var debugInfoTextView: TextView\n  private lateinit var contentAdapter: ContentAdapter\n\n  private var modelDownloaded = false\n  private var totalBytesToDownload = 0L\n\n  private var streaming = true\n  private var useStreamingCallbackApi = false\n  private var hasFirstStreamingResult = false\n  private var firstTokenLatency = 0L\n\n  private var batchInputUri: Uri? = null\n  private var batchRunCancelled = false\n  private var batchProcessingIndex = 0\n\n  private lateinit var createBatchOutputFileLauncher: ActivityResultLauncher<String>\n  private lateinit var chooseBatchInputLauncher: ActivityResultLauncher<String>\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(getLayoutResId())\n\n    debugInfoTextView = findViewById(R.id.debug_info_text_view)\n\n    findViewById<RecyclerView>(R.id.content_recycler_view).apply {\n      layoutManager = LinearLayoutManager(this@BaseActivity)\n      adapter = ContentAdapter().also { contentAdapter = it }\n    }\n\n    createBatchOutputFileLauncher =\n      registerForActivityResult(CreateDocument(\"text/csv\")) { batchOutputUri ->\n        batchInputUri?.let { inputUri -> batchOutputUri?.let { batchRun(inputUri, it) } }\n      }\n    chooseBatchInputLauncher =\n      registerForActivityResult(GetContent()) { uri ->\n        uri?.let {\n          batchInputUri = it\n          val outputFileName =\n            \"mlkit_genai_result_${SimpleDateFormat(\"yyyy-MM-dd_HH:mm:ss\", Locale.getDefault()).format(Date())}.csv\"\n          createBatchOutputFileLauncher.launch(outputFileName)\n        }\n      }\n  }\n\n  override fun onPostCreate(savedInstanceState: Bundle?) {\n    super.onPostCreate(savedInstanceState)\n    Futures.addCallback(\n      getBaseModelName(),\n      object : FutureCallback<String> {\n        override fun onSuccess(result: String) {\n          debugInfoTextView.visibility = View.VISIBLE\n          debugInfoTextView.text = getString(R.string.base_model_name, result)\n        }\n\n        override fun onFailure(t: Throwable) {\n          Log.e(TAG, \"Failed to get base model name.\", t)\n        }\n      },\n      ContextCompat.getMainExecutor(this),\n    )\n  }\n\n  protected fun onSend(request: RequestT) {\n    contentAdapter.addContent(request)\n    startGeneratingUi()\n    if (modelDownloaded) {\n      runInference(request)\n    } else {\n      checkFeatureStatus(request)\n    }\n  }\n\n  protected abstract fun getBaseModelName(): ListenableFuture<String>\n\n  protected abstract fun getLayoutResId(): Int\n\n  override fun onCreateOptionsMenu(menu: Menu): Boolean {\n    menuInflater.inflate(R.menu.menu_main, menu)\n    menu.findItem(R.id.action_streaming)?.isChecked = streaming\n    return true\n  }\n\n  /**\n   * This method is called right before the menu is shown. We use it to dynamically enable/disable\n   * the API submenu and set radio checks.\n   */\n  override fun onPrepareOptionsMenu(menu: Menu): Boolean {\n    super.onPrepareOptionsMenu(menu)\n    val streamingItem = menu.findItem(R.id.action_streaming)\n    val streamingApiSubmenu = menu.findItem(R.id.action_streaming_api_submenu)\n\n    streamingApiSubmenu?.isEnabled = streaming\n    streamingItem?.isChecked = streaming\n\n    if (useStreamingCallbackApi) {\n      menu.findItem(R.id.action_streaming_callback)?.isChecked = true\n    } else {\n      menu.findItem(R.id.action_streaming_flow)?.isChecked = true\n    }\n    return true\n  }\n\n  override fun onOptionsItemSelected(item: MenuItem): Boolean {\n    return when (item.itemId) {\n      R.id.action_streaming -> {\n        streaming = !streaming\n        item.isChecked = streaming\n        invalidateOptionsMenu()\n        true\n      }\n      R.id.action_streaming_flow -> {\n        useStreamingCallbackApi = false\n        item.isChecked = true\n        true\n      }\n      R.id.action_streaming_callback -> {\n        useStreamingCallbackApi = true\n        item.isChecked = true\n        true\n      }\n      R.id.action_batch_run -> {\n        chooseBatchInputLauncher.launch(\"text/csv\")\n        true\n      }\n      else -> super.onOptionsItemSelected(item)\n    }\n  }\n\n  private fun checkFeatureStatus(request: RequestT) {\n    Futures.addCallback(\n      checkFeatureStatus(),\n      object : FutureCallback<Int> {\n        override fun onSuccess(featureStatus: Int) {\n          when (featureStatus) {\n            FeatureStatus.AVAILABLE -> {\n              modelDownloaded = true\n              runInference(request)\n            }\n            FeatureStatus.UNAVAILABLE -> displayErrorMessage(\"Feature is unavailable.\")\n            else -> downloadAndRunInference(request)\n          }\n        }\n\n        override fun onFailure(t: Throwable) {\n          Log.e(TAG, \"Failed to check status.\", t)\n          displayErrorMessage(\"Failed to check status\", t)\n        }\n      },\n      ContextCompat.getMainExecutor(this),\n    )\n  }\n\n  protected abstract fun checkFeatureStatus(): @FeatureStatus ListenableFuture<Int>\n\n  private fun downloadAndRunInference(request: RequestT) {\n    Futures.addCallback(\n      downloadFeature(\n        object : DownloadCallback {\n          override fun onDownloadStarted(bytesToDownload: Long) {\n            totalBytesToDownload = bytesToDownload\n          }\n\n          override fun onDownloadFailed(e: GenAiException) {\n            displayErrorMessage(\"Failed to download model\", e)\n          }\n\n          override fun onDownloadProgress(totalBytesDownloaded: Long) {\n            if (totalBytesToDownload > 0) {\n              debugInfoTextView.run {\n                visibility = View.VISIBLE\n                text =\n                  String.format(\n                    Locale.ENGLISH,\n                    \"Downloading model: %d / %d MB (%.2f%%)\",\n                    totalBytesDownloaded / MEGABYTE,\n                    totalBytesToDownload / MEGABYTE,\n                    100.0 * totalBytesDownloaded / totalBytesToDownload,\n                  )\n              }\n            }\n          }\n\n          override fun onDownloadCompleted() {\n            modelDownloaded = true\n            runInference(request)\n          }\n        }\n      ),\n      object : FutureCallback<Void?> {\n        override fun onSuccess(result: Void?) {}\n\n        override fun onFailure(t: Throwable) {\n          Log.e(TAG, \"Failed to download feature.\", t)\n          displayErrorMessage(\"Failed to download feature\", t)\n        }\n      },\n      ContextCompat.getMainExecutor(this),\n    )\n  }\n\n  protected abstract fun downloadFeature(callback: DownloadCallback): ListenableFuture<Void>\n\n  private fun runInference(request: RequestT) {\n    lifecycleScope.launch {\n      val startMs = System.currentTimeMillis()\n      val tokenInfoTextBuilder = StringBuilder()\n\n      try {\n        val tokenInfo = countTokens(request)\n        tokenInfoTextBuilder.append(\"Input Token count: ${tokenInfo.totalTokens}\")\n      } catch (e: UnsupportedOperationException) {} catch (e: Exception) {\n        Log.e(TAG, \"Failed to get token count.\", e)\n        tokenInfoTextBuilder.append(\"Token count failed\")\n      }\n\n      try {\n        val tokenLimit = getTokenLimit()\n        if (tokenInfoTextBuilder.isNotEmpty()) {\n          tokenInfoTextBuilder.append(\". \")\n        }\n        tokenInfoTextBuilder.append(\"Token limit: $tokenLimit\")\n      } catch (e: UnsupportedOperationException) {\n        // Expected for APIs that don't support token counting.\n      } catch (e: Exception) {\n        Log.e(TAG, \"Failed to get token limit.\", e)\n        if (tokenInfoTextBuilder.isNotEmpty()) {\n          tokenInfoTextBuilder.append(\". \")\n        }\n        tokenInfoTextBuilder.append(\"Token limit failed\")\n      }\n\n      val tokenInfoText = tokenInfoTextBuilder.toString()\n\n      if (streaming) {\n        hasFirstStreamingResult = false\n        val resultBuilder = StringBuilder()\n\n        val onChunk: (String) -> Unit = { additionalText ->\n          runOnUiThread {\n            resultBuilder.append(additionalText)\n            if (hasFirstStreamingResult) {\n              contentAdapter.updateStreamingResponse(resultBuilder.toString())\n            } else {\n              contentAdapter.addContent(\n                ContentItem.TextItem.fromStreamingResponse(resultBuilder.toString())\n              )\n              hasFirstStreamingResult = true\n              firstTokenLatency = Instant.now().minusMillis(startMs).toEpochMilli()\n            }\n          }\n        }\n        val onSuccess: (List<String>) -> Unit = { results ->\n          val totalLatency: Long = Instant.now().minusMillis(startMs).toEpochMilli()\n          val debugInfo = getString(R.string.debug_info_streaming, firstTokenLatency, totalLatency)\n          val latencyMetadata =\n            if (tokenInfoText.isEmpty()) debugInfo else \"$tokenInfoText\\n$debugInfo\"\n          results\n            .filter { it.isNotEmpty() }\n            .forEach { result ->\n              contentAdapter.addContent(ContentItem.TextItem.fromResponse(result, latencyMetadata))\n            }\n          endGeneratingUi(debugInfo)\n        }\n        val onFailure: (Throwable) -> Unit = { t ->\n          Log.d(TAG, \"Streaming result so far:\\n$resultBuilder\")\n          Log.e(TAG, \"Failed to run inference.\", t)\n          displayErrorMessage(\"Failed to run inference\", t)\n        }\n\n        val streamFlow = if (useStreamingCallbackApi) null else runInferenceStreamImpl(request)\n\n        if (streamFlow != null) {\n          try {\n            streamFlow.collect { onChunk(it) }\n            onSuccess(listOf(resultBuilder.toString()))\n          } catch (t: Throwable) {\n            onFailure(t)\n          }\n        } else {\n          Futures.addCallback(\n            runInferenceImpl(request) { additionalText -> onChunk(additionalText) },\n            object : FutureCallback<List<String>> {\n              override fun onSuccess(results: List<String>) {\n                onSuccess(results)\n              }\n\n              override fun onFailure(t: Throwable) {\n                onFailure(t)\n              }\n            },\n            ContextCompat.getMainExecutor(this@BaseActivity),\n          )\n        }\n      } else {\n        Futures.addCallback(\n          runInferenceImpl(request, streamingCallback = null),\n          object : FutureCallback<List<String>> {\n            override fun onSuccess(results: List<String>) {\n              val debugInfo =\n                getString(R.string.debug_info, Instant.now().minusMillis(startMs).toEpochMilli())\n              val latencyMetadata =\n                if (tokenInfoText.isEmpty()) debugInfo else \"$tokenInfoText\\n$debugInfo\"\n              results.forEach { result ->\n                contentAdapter.addContent(\n                  ContentItem.TextItem.fromResponse(result, latencyMetadata)\n                )\n              }\n              endGeneratingUi(debugInfo)\n            }\n\n            override fun onFailure(t: Throwable) {\n              Log.e(TAG, \"Failed to run inference.\", t)\n              displayErrorMessage(\"Failed to run inference\", t)\n            }\n          },\n          ContextCompat.getMainExecutor(this@BaseActivity),\n        )\n      }\n    }\n  }\n\n  protected abstract fun runInferenceImpl(\n    request: RequestT,\n    streamingCallback: StreamingCallback?,\n  ): ListenableFuture<List<String>>\n\n  protected open fun runInferenceStreamImpl(request: RequestT): Flow<String>? = null\n\n  protected open suspend fun countTokens(request: RequestT): CountTokensResponse =\n    throw UnsupportedOperationException(\"Not implemented\")\n\n  protected open suspend fun getTokenLimit(): Int =\n    throw UnsupportedOperationException(\"Not implemented\")\n\n  protected fun setupSpinner(spinnerId: Int, arrayId: Int, onItemSelected: (Int) -> Unit) {\n    val spinner = findViewById<Spinner>(spinnerId)\n    val adapter =\n      ArrayAdapter.createFromResource(this, arrayId, android.R.layout.simple_spinner_item).apply {\n        setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n      }\n\n    spinner.adapter = adapter\n    spinner.onItemSelectedListener =\n      object : AdapterView.OnItemSelectedListener {\n        override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {\n          onItemSelected(position)\n        }\n\n        override fun onNothingSelected(parent: AdapterView<*>) {}\n      }\n  }\n\n  private fun displayErrorMessage(errorMessage: String) {\n    displayErrorMessage(errorMessage, cause = null)\n  }\n\n  private fun displayErrorMessage(errorMessage: String, cause: Throwable?) {\n    var fullErrorMessage = errorMessage\n    if (cause != null) {\n      fullErrorMessage += \": $cause\"\n      if (cause.cause != null) {\n        fullErrorMessage += \"\\nCause: ${cause.cause}\"\n      }\n    }\n    contentAdapter.addContent(ContentItem.TextItem.fromErrorResponse(fullErrorMessage))\n    endGeneratingUi(getString(R.string.empty))\n  }\n\n  protected open fun startGeneratingUi() {\n    debugInfoTextView.visibility = View.GONE\n  }\n\n  protected open fun endGeneratingUi(debugInfo: String) {\n    debugInfoTextView.run {\n      text = debugInfo\n      visibility = if (debugInfo.isEmpty()) View.GONE else View.VISIBLE\n    }\n  }\n\n  protected fun resetProcessor() {\n    modelDownloaded = false\n  }\n\n  protected abstract fun runInferenceForBatchTask(request: String): List<String>\n\n  /**\n   * Runs inference on batch text requests from an input file.\n   *\n   * The input file must be a CSV file selected via the file picker, with the first column\n   * containing the text requests.\n   *\n   * The output file will also be in CSV format, containing all the content from the input file with\n   * the inference results appended to the end of each row. Each inference result occupies two\n   * additional columns: one for the result text (or error message) and one for the score,\n   * continuing sequentially.\n   */\n  private fun batchRun(inputUri: Uri, outputUri: Uri) {\n    batchRunCancelled = false\n    val processingDialog =\n      AlertDialog.Builder(this)\n        .setMessage(R.string.batch_run_start_message)\n        .setNegativeButton(R.string.button_cancel) { _: DialogInterface, _: Int ->\n          batchRunCancelled = true\n        }\n        .setCancelable(false)\n        .show()\n    processingDialog.setCanceledOnTouchOutside(false)\n\n    val unused =\n      Executors.newSingleThreadExecutor().submit {\n        requireNotNull(contentResolver.openInputStream(inputUri)).use { input ->\n          InputStreamReader(input).use { reader ->\n            val csvReader = CSVReader(reader)\n            requireNotNull(contentResolver.openOutputStream(outputUri)).use { output ->\n              OutputStreamWriter(output).use { writer ->\n                val csvWriter = CSVWriter(writer)\n                val inputRows = csvReader.readAll()\n                batchProcessingIndex = 0\n                for (inputRow in inputRows) {\n                  if (batchRunCancelled) {\n                    break\n                  }\n\n                  batchProcessingIndex++\n                  runOnUiThread {\n                    processingDialog.setMessage(\n                      \"Processing $batchProcessingIndex/${inputRows.size}\"\n                    )\n                  }\n\n                  val startTimeMs = System.currentTimeMillis()\n                  val resultRow = buildList {\n                    addAll(inputRow)\n                    addAll(runInferenceForBatchTask(inputRow[0]))\n                  }\n                  csvWriter.writeNext(resultRow.toTypedArray<String>())\n                  val elapsedTimeMs = System.currentTimeMillis() - startTimeMs\n                  val remainingTimeMs = MIN_INFERENCE_INTERVAL_MS - elapsedTimeMs\n                  if (remainingTimeMs > 0) {\n                    Thread.sleep(remainingTimeMs)\n                  }\n                }\n              }\n            }\n          }\n        }\n\n        runOnUiThread { processingDialog.dismiss() }\n      }\n  }\n\n  companion object {\n    private const val TAG = \"TextInputBasedActivity\"\n    private const val MEGABYTE = 1024 * 1024L\n    private const val MIN_INFERENCE_INTERVAL_MS = 6000L\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/kotlin/ImageDescriptionActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo.kotlin\n\nimport android.graphics.ImageDecoder\nimport android.net.Uri\nimport android.os.Bundle\nimport android.view.Menu\nimport android.widget.Button\nimport android.widget.Toast\nimport androidx.activity.result.ActivityResultLauncher\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.core.content.ContextCompat\nimport com.google.common.util.concurrent.Futures\nimport com.google.common.util.concurrent.Futures.immediateFailedFuture\nimport com.google.common.util.concurrent.ListenableFuture\nimport com.google.mlkit.genai.common.DownloadCallback\nimport com.google.mlkit.genai.common.FeatureStatus\nimport com.google.mlkit.genai.common.StreamingCallback\nimport com.google.mlkit.genai.demo.ContentItem\nimport com.google.mlkit.genai.demo.R\nimport com.google.mlkit.genai.imagedescription.ImageDescriber\nimport com.google.mlkit.genai.imagedescription.ImageDescriberOptions\nimport com.google.mlkit.genai.imagedescription.ImageDescription\nimport com.google.mlkit.genai.imagedescription.ImageDescriptionRequest\nimport com.google.mlkit.genai.prompt.CountTokensResponse\nimport java.io.IOException\n\n/** Demonstrates the Image Description API usage. */\nclass ImageDescriptionActivity : BaseActivity<ContentItem.ImageItem>() {\n  private lateinit var selectImageButton: Button\n\n  private var imageDescriber: ImageDescriber? = null\n\n  private lateinit var selectImageLauncher: ActivityResultLauncher<String>\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n\n    selectImageLauncher =\n      registerForActivityResult(ActivityResultContracts.GetContent()) { imageUri: Uri? ->\n        imageUri?.let { onSend(ContentItem.ImageItem.fromRequest(it)) }\n          ?: run { Toast.makeText(this, \"No image selected\", Toast.LENGTH_SHORT).show() }\n      }\n    selectImageButton = findViewById(R.id.select_image_button)\n    selectImageButton.setOnClickListener { selectImageLauncher.launch(\"image/*\") }\n\n    initImageDescriber()\n  }\n\n  override fun getLayoutResId(): Int {\n    return R.layout.activity_image_description\n  }\n\n  override fun onPrepareOptionsMenu(menu: Menu): Boolean {\n    val item = menu.findItem(R.id.action_batch_run)\n    item?.isVisible = false\n    return true\n  }\n\n  override fun onDestroy() {\n    super.onDestroy()\n    imageDescriber?.close()\n  }\n\n  override fun getBaseModelName(): ListenableFuture<String> {\n    return checkNotNull(imageDescriber).baseModelName\n  }\n\n  override fun checkFeatureStatus(): @FeatureStatus ListenableFuture<Int> {\n    return checkNotNull(imageDescriber).checkFeatureStatus()\n  }\n\n  override fun downloadFeature(callback: DownloadCallback): ListenableFuture<Void> {\n    return checkNotNull(imageDescriber).downloadFeature(callback)\n  }\n\n  override fun runInferenceImpl(\n    request: ContentItem.ImageItem,\n    streamingCallback: StreamingCallback?,\n  ): ListenableFuture<List<String>> {\n    try {\n      val bitmap =\n        ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, request.imageUri))\n      val imageDescriptionRequest = ImageDescriptionRequest.builder(bitmap).build()\n      val inferenceFuture =\n        checkNotNull(imageDescriber).let { imageDescriber ->\n          streamingCallback?.let { imageDescriber.runInference(imageDescriptionRequest, it) }\n            ?: imageDescriber.runInference(imageDescriptionRequest)\n        }\n\n      return Futures.transform(\n        inferenceFuture,\n        { imageDescriptionResult -> listOf(imageDescriptionResult.description) },\n        ContextCompat.getMainExecutor(this),\n      )\n    } catch (e: IOException) {\n      return immediateFailedFuture(e)\n    }\n  }\n\n  override fun startGeneratingUi() {\n    super.startGeneratingUi()\n    selectImageButton.isEnabled = false\n    selectImageButton.setText(R.string.generating)\n  }\n\n  override fun endGeneratingUi(debugInfo: String) {\n    super.endGeneratingUi(debugInfo)\n    selectImageButton.isEnabled = true\n    selectImageButton.setText(R.string.button_select_image)\n  }\n\n  override fun runInferenceForBatchTask(request: String): List<String> {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n\n  private fun initImageDescriber() {\n    imageDescriber?.close()\n    val options = ImageDescriberOptions.builder(this).build()\n    imageDescriber = ImageDescription.getClient(options)\n    resetProcessor()\n  }\n\n  override suspend fun countTokens(request: ContentItem.ImageItem): CountTokensResponse {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n\n  override suspend fun getTokenLimit(): Int {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/kotlin/OpenPromptActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo.kotlin\n\nimport android.app.AlertDialog\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.net.Uri\nimport android.os.Bundle\nimport android.text.TextUtils\nimport android.util.Log\nimport android.view.Menu\nimport android.view.MenuItem\nimport android.view.View\nimport android.widget.Button\nimport android.widget.CheckBox\nimport android.widget.EditText\nimport android.widget.ImageButton\nimport android.widget.ImageView\nimport android.widget.Toast\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.concurrent.futures.CallbackToFutureAdapter\nimport androidx.core.content.ContextCompat\nimport androidx.lifecycle.lifecycleScope\nimport com.bumptech.glide.Glide\nimport com.google.common.util.concurrent.ListenableFuture\nimport com.google.mlkit.genai.common.DownloadCallback\nimport com.google.mlkit.genai.common.DownloadStatus\nimport com.google.mlkit.genai.common.StreamingCallback\nimport com.google.mlkit.genai.demo.ContentItem\nimport com.google.mlkit.genai.demo.GenerationConfigDialog\nimport com.google.mlkit.genai.demo.GenerationConfigUtils\nimport com.google.mlkit.genai.demo.R\nimport com.google.mlkit.genai.prompt.Candidate\nimport com.google.mlkit.genai.prompt.Candidate.FinishReason\nimport com.google.mlkit.genai.prompt.CountTokensResponse\nimport com.google.mlkit.genai.prompt.GenerateContentRequest\nimport com.google.mlkit.genai.prompt.GenerateContentResponse\nimport com.google.mlkit.genai.prompt.GenerativeModel\nimport com.google.mlkit.genai.prompt.ImagePart\nimport com.google.mlkit.genai.prompt.PromptPrefix\nimport com.google.mlkit.genai.prompt.TextPart\nimport com.google.mlkit.genai.prompt.createCachedContextRequest\nimport com.google.mlkit.genai.prompt.generateContentRequest\nimport java.io.IOException\nimport kotlinx.coroutines.flow.Flow\nimport kotlinx.coroutines.flow.flow\nimport kotlinx.coroutines.flow.map\nimport kotlinx.coroutines.guava.future\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.runBlocking\n\n/**\n * An activity that demonstrates a chat-like interface for the Open Prompt API, allowing requests\n * with both text and images, and including generation configuration.\n */\nclass OpenPromptActivity :\n  BaseActivity<ContentItem>(), GenerationConfigDialog.OnConfigUpdateListener {\n  private val TAG = \"OpenPromptActivity\"\n  private val ACTION_CLEAR_CACHES = 1000\n\n  private var generativeModel: GenerativeModel? = null\n  private lateinit var requestEditText: EditText\n  private lateinit var sendButton: Button\n  private lateinit var selectImageButton: ImageButton\n  private lateinit var imagePreview: ImageView\n  private lateinit var configButton: Button\n  private lateinit var prefixEditText: EditText\n  private lateinit var createCacheCheckBox: CheckBox\n\n  private var selectedImageUri: Uri? = null\n\n  private var curTemperature: Float? = null\n  private var curTopK: Int? = null\n  private var curSeed: Int? = null\n  private var curMaxOutputTokens: Int? = null\n  private var curCandidateCount: Int? = null\n  private var useDefaultConfig = false\n  private var useExplicitCache = false\n\n  private val pickImageLauncher =\n    registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->\n      if (uri != null) {\n        selectedImageUri = uri\n        Glide.with(this).load(uri).into(imagePreview)\n        imagePreview.visibility = View.VISIBLE\n        Toast.makeText(this, \"1 image selected\", Toast.LENGTH_SHORT).show()\n      } else {\n        Toast.makeText(this, \"No image selected\", Toast.LENGTH_SHORT).show()\n      }\n    }\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    requestEditText = findViewById(R.id.request_edit_text)\n    sendButton = findViewById(R.id.send_button)\n    selectImageButton = findViewById(R.id.select_image_prompt_button)\n    imagePreview = findViewById(R.id.image_thumbnail_preview_input)\n    configButton = findViewById(R.id.config_button)\n    prefixEditText = findViewById(R.id.prefix_edit_text)\n    createCacheCheckBox = findViewById(R.id.create_cache_checkbox)\n    createCacheCheckBox.setOnCheckedChangeListener { _, _ ->\n      prefixEditText.setText(\"\")\n      updateRequestEditTextHint()\n      updatePrefixEditTextState()\n    }\n\n    selectImageButton.setOnClickListener { pickImageLauncher.launch(\"image/*\") }\n\n    // Remove the selected image when the user clicks on the image preview.\n    imagePreview.setOnClickListener {\n      selectedImageUri = null\n      imagePreview.visibility = View.GONE\n      Glide.with(this).clear(imagePreview)\n      Toast.makeText(this, \"Image removed\", Toast.LENGTH_SHORT).show()\n    }\n\n    configButton.setOnClickListener { GenerationConfigDialog().show(supportFragmentManager, null) }\n\n    sendButton.setOnClickListener {\n      if (useExplicitCache) {\n        val cacheName = prefixEditText.text.toString().trim()\n        if (TextUtils.isEmpty(cacheName)) {\n          Toast.makeText(this, R.string.cache_name_empty, Toast.LENGTH_SHORT).show()\n          return@setOnClickListener\n        }\n        val text = requestEditText.text.toString().trim()\n        if (createCacheCheckBox.isChecked) {\n          if (TextUtils.isEmpty(text)) {\n            Toast.makeText(this, R.string.prefix_to_cache_empty, Toast.LENGTH_SHORT).show()\n            return@setOnClickListener\n          }\n          onSend(ContentItem.CacheRequestItem.fromRequest(cacheName, text))\n        } else {\n          if (TextUtils.isEmpty(text)) {\n            Toast.makeText(this, R.string.input_message_is_empty, Toast.LENGTH_SHORT).show()\n            return@setOnClickListener\n          }\n          onSend(ContentItem.TextWithPrefixCacheItem.fromRequest(cacheName, text))\n        }\n        requestEditText.setText(\"\")\n        return@setOnClickListener\n      }\n\n      val requestText = requestEditText.text.toString().trim()\n      if (TextUtils.isEmpty(requestText)) {\n        Toast.makeText(this, R.string.input_message_is_empty, Toast.LENGTH_SHORT).show()\n        return@setOnClickListener\n      }\n\n      val prefixText = prefixEditText.text.toString().trim()\n      if (!TextUtils.isEmpty(prefixText) && selectedImageUri != null) {\n        Toast.makeText(this, R.string.warning_prefix_used_with_image, Toast.LENGTH_LONG).show()\n        return@setOnClickListener\n      }\n\n      val requestItem: ContentItem =\n        if (selectedImageUri != null) {\n          ContentItem.TextAndImagesItem.fromRequest(requestText, arrayListOf(selectedImageUri!!))\n        } else if (!TextUtils.isEmpty(prefixText)) {\n          ContentItem.TextWithPromptPrefixItem.fromRequest(prefixText, requestText)\n        } else {\n          ContentItem.TextItem.fromRequest(requestText)\n        }\n      onSend(requestItem)\n\n      requestEditText.setText(\"\")\n      imagePreview.visibility = View.GONE\n      Glide.with(this).clear(imagePreview)\n      selectedImageUri = null\n    }\n\n    onConfigUpdated()\n\n    initGenerator()\n  }\n\n  override fun onConfigUpdated() {\n    useDefaultConfig = GenerationConfigUtils.getUseDefaultConfig(applicationContext)\n    if (useDefaultConfig) {\n      // Cache cannot be used in the simple utility API.\n      GenerationConfigUtils.setUseExplicitCache(applicationContext, false)\n    }\n    useExplicitCache = GenerationConfigUtils.getUseExplicitCache(applicationContext)\n\n    if (useExplicitCache) {\n      prefixEditText.visibility = View.VISIBLE\n      prefixEditText.setHint(R.string.hint_add_cache_name)\n\n      createCacheCheckBox.visibility = View.VISIBLE\n      configButton.visibility = View.VISIBLE\n      selectImageButton.visibility = View.GONE\n      imagePreview.visibility = View.GONE\n      selectedImageUri = null\n    } else {\n      prefixEditText.visibility = if (useDefaultConfig) View.GONE else View.VISIBLE\n      prefixEditText.setHint(R.string.hint_add_prompt_prefix)\n      createCacheCheckBox.visibility = View.GONE\n      configButton.visibility = if (useDefaultConfig) View.GONE else View.VISIBLE\n      selectImageButton.visibility = if (useDefaultConfig) View.GONE else View.VISIBLE\n      imagePreview.visibility =\n        if (useDefaultConfig || selectedImageUri == null) View.GONE else View.VISIBLE\n    }\n    prefixEditText.setText(\"\")\n    requestEditText.setText(\"\")\n    updateRequestEditTextHint()\n    updatePrefixEditTextState()\n\n    curTemperature = GenerationConfigUtils.getTemperature(applicationContext)\n    curTopK = GenerationConfigUtils.getTopK(applicationContext)\n    curSeed = GenerationConfigUtils.getSeed(applicationContext)\n    curCandidateCount = GenerationConfigUtils.getCandidateCount(applicationContext)\n    curMaxOutputTokens = GenerationConfigUtils.getMaxOutputTokens(applicationContext)\n  }\n\n  private fun updateRequestEditTextHint() {\n    requestEditText.setHint(\n      if (useExplicitCache) {\n        if (createCacheCheckBox.isChecked) {\n          R.string.hint_add_prefix_to_cache\n        } else {\n          R.string.hint_add_suffix_for_inference\n        }\n      } else {\n        R.string.hint_type_a_message\n      }\n    )\n  }\n\n  override fun getLayoutResId(): Int = R.layout.activity_openprompt\n\n  override fun getBaseModelName(): ListenableFuture<String> =\n    lifecycleScope.future { checkNotNull(generativeModel).getBaseModelName() }\n\n  override fun checkFeatureStatus(): ListenableFuture<Int> =\n    lifecycleScope.future { checkNotNull(generativeModel).checkStatus() }\n\n  override fun downloadFeature(callback: DownloadCallback): ListenableFuture<Void> {\n    return CallbackToFutureAdapter.getFuture { completer ->\n      val job =\n        lifecycleScope.launch {\n          try {\n            checkNotNull(generativeModel).download().collect { status ->\n              when (status) {\n                is DownloadStatus.DownloadStarted ->\n                  callback.onDownloadStarted(status.bytesToDownload)\n                is DownloadStatus.DownloadProgress ->\n                  callback.onDownloadProgress(status.totalBytesDownloaded)\n                is DownloadStatus.DownloadFailed -> callback.onDownloadFailed(status.e)\n                is DownloadStatus.DownloadCompleted -> callback.onDownloadCompleted()\n              }\n            }\n            completer.set(null)\n          } catch (e: Exception) {\n            completer.setException(e)\n          }\n        }\n\n      completer.addCancellationListener({ job.cancel() }, ContextCompat.getMainExecutor(this))\n\n      \"downloadFeature\"\n    }\n  }\n\n  override fun runInferenceImpl(\n    request: ContentItem,\n    streamingCallback: StreamingCallback?,\n  ): ListenableFuture<List<String>> {\n    if (request is ContentItem.CacheRequestItem) {\n      return lifecycleScope.future { listOf(createCache(request)) }\n    }\n    return lifecycleScope.future {\n      if (request is ContentItem.TextItem && useDefaultConfig) {\n        // useDefaultConfig is used for the case where user wants to use utility function with\n        // default config values\n        val result =\n          if (streamingCallback != null) {\n            checkNotNull(generativeModel).generateContent(request.text, streamingCallback)\n          } else {\n            checkNotNull(generativeModel).generateContent(request.text)\n          }\n        return@future resultToStrings(result)\n      }\n\n      val genRequest = createGenerateContentRequest(request)\n      val result =\n        if (streamingCallback != null) {\n          checkNotNull(generativeModel).generateContent(genRequest, streamingCallback)\n        } else {\n          checkNotNull(generativeModel).generateContent(genRequest)\n        }\n      resultToStrings(result)\n    }\n  }\n\n  override fun runInferenceStreamImpl(request: ContentItem): Flow<String>? {\n    if (request is ContentItem.CacheRequestItem) {\n      return flow { emit(createCache(request)) }\n    }\n    if (request is ContentItem.TextItem && useDefaultConfig) {\n      // useDefaultConfig is used for the case where user wants to use utility function with\n      // default config values\n      return flow {\n        checkNotNull(generativeModel)\n          .generateContentStream(request.text)\n          .map { result ->\n            val text = result.candidates.first().text\n            val finishReason = result.candidates.first().finishReason\n            if (finishReason == Candidate.FinishReason.MAX_TOKENS) {\n              \"$text\\n(FinishReason: MAX_TOKENS)\"\n            } else {\n              text\n            }\n          }\n          .collect { emit(it) }\n      }\n    }\n    return flow {\n      val genRequest = createGenerateContentRequest(request)\n      checkNotNull(generativeModel)\n        .generateContentStream(genRequest)\n        .map { result ->\n          val text = result.candidates.first().text\n          val finishReason = result.candidates.first().finishReason\n          if (finishReason == Candidate.FinishReason.MAX_TOKENS) {\n            \"$text\\n(FinishReason: MAX_TOKENS)\"\n          } else {\n            text\n          }\n        }\n        .collect { emit(it) }\n    }\n  }\n\n  private fun showCacheSelectionDialog() {\n    lifecycleScope.launch {\n      val caches = checkNotNull(generativeModel).caches.list()\n      if (caches.isEmpty()) {\n        Toast.makeText(this@OpenPromptActivity, \"No caches available to select\", Toast.LENGTH_SHORT)\n          .show()\n        return@launch\n      }\n      val cacheNames = caches.map { it.name }.toTypedArray()\n      AlertDialog.Builder(this@OpenPromptActivity)\n        .setTitle(\"Select Cache\")\n        .setItems(cacheNames) { _, which -> prefixEditText.setText(cacheNames[which]) }\n        .show()\n    }\n  }\n\n  private fun updatePrefixEditTextState() {\n    if (useExplicitCache && !createCacheCheckBox.isChecked) {\n      prefixEditText.isFocusable = false\n      prefixEditText.isClickable = true\n      prefixEditText.setOnClickListener { showCacheSelectionDialog() }\n      prefixEditText.setHint(R.string.hint_select_cache_name)\n    } else {\n      prefixEditText.isFocusable = true\n      prefixEditText.isFocusableInTouchMode = true\n      prefixEditText.isClickable = false\n      prefixEditText.setOnClickListener(null)\n      if (useExplicitCache) {\n        prefixEditText.setHint(R.string.hint_add_cache_name)\n      } else {\n        prefixEditText.setHint(R.string.hint_add_prompt_prefix)\n      }\n    }\n  }\n\n  private suspend fun createCache(request: ContentItem.CacheRequestItem): String {\n    val unused =\n      checkNotNull(generativeModel)\n        .caches\n        .create(createCachedContextRequest(request.cacheName, PromptPrefix(request.prefixToCache)))\n\n    // Return a string to indicate the cache is created successfully.\n    return \"${getString(R.string.prefix_cached)}: ${request.cacheName}\"\n  }\n\n  private fun createGenerateContentRequest(request: ContentItem): GenerateContentRequest {\n    var requestText = \"\"\n    var promptPrefixText = \"\"\n    var imageBitmap: Bitmap? = null\n    var cachedContextNameText: String? = null\n\n    when (request) {\n      is ContentItem.TextItem -> {\n        requestText = request.text\n      }\n      is ContentItem.TextAndImagesItem -> {\n        requestText = request.text\n        for (uri in request.imageUris) {\n          try {\n            contentResolver.openInputStream(uri)?.use { inputStream ->\n              BitmapFactory.decodeStream(inputStream)?.let { bitmap -> imageBitmap = bitmap }\n            }\n          } catch (e: IOException) {\n            Log.e(TAG, \"Error decoding image URI: $uri\", e)\n          }\n        }\n      }\n      is ContentItem.ImageItem -> {\n        try {\n          contentResolver.openInputStream(request.imageUri)?.use { inputStream ->\n            BitmapFactory.decodeStream(inputStream)?.let { bitmap -> imageBitmap = bitmap }\n          }\n        } catch (e: IOException) {\n          Log.e(TAG, \"Error decoding image URI: ${request.imageUri}\", e)\n        }\n      }\n      is ContentItem.TextWithPromptPrefixItem -> {\n        requestText = request.dynamicSuffix\n        promptPrefixText = request.promptPrefix\n      }\n      is ContentItem.TextWithPrefixCacheItem -> {\n        requestText = request.dynamicSuffix\n        cachedContextNameText = request.cacheName\n      }\n      is ContentItem.CacheRequestItem -> {\n        throw IllegalStateException(\"CacheRequestItem is for creating cache only.\")\n      }\n    }\n\n    return if (imageBitmap != null) {\n      generateContentRequest(ImagePart(imageBitmap), TextPart(requestText)) {\n        temperature = curTemperature\n        topK = curTopK\n        seed = curSeed\n        maxOutputTokens = curMaxOutputTokens\n        candidateCount = curCandidateCount\n      }\n    } else {\n      generateContentRequest(TextPart(requestText)) {\n        if (useExplicitCache) {\n          cachedContextName = cachedContextNameText\n        } else {\n          promptPrefix = PromptPrefix(promptPrefixText)\n        }\n        temperature = curTemperature\n        topK = curTopK\n        seed = curSeed\n        maxOutputTokens = curMaxOutputTokens\n        candidateCount = curCandidateCount\n      }\n    }\n  }\n\n  private fun resultToStrings(result: GenerateContentResponse): List<String> =\n    result.candidates.map { candidate ->\n      val text = candidate.text\n      if (candidate.finishReason == Candidate.FinishReason.MAX_TOKENS) {\n        \"$text\\n(FinishReason: MAX_TOKENS)\"\n      } else {\n        text\n      }\n    }\n\n  override fun runInferenceForBatchTask(request: String): List<String> {\n    return runBlocking {\n      val resultText =\n        try {\n          if (useDefaultConfig) {\n            // useDefaultConfig is used for the case where user wants to use utility function with\n            // default config values\n            checkNotNull(generativeModel).generateContent(request).candidates.first().text\n          } else {\n            val genRequest =\n              generateContentRequest(TextPart(request)) {\n                temperature = curTemperature\n                topK = curTopK\n                seed = curSeed\n                maxOutputTokens = curMaxOutputTokens\n                candidateCount = curCandidateCount\n              }\n            checkNotNull(generativeModel).generateContent(genRequest).candidates.first().text\n          }\n        } catch (e: Exception) {\n          \"Failed to run inference: ${e.message}\"\n        }\n      listOf(checkNotNull(resultText))\n    }\n  }\n\n  override suspend fun countTokens(request: ContentItem): CountTokensResponse {\n    if (request is ContentItem.CacheRequestItem) {\n      // Count tokens does not support for cache request by now.\n      return CountTokensResponse(0)\n    }\n    val genRequest = createGenerateContentRequest(request)\n    return checkNotNull(generativeModel).countTokens(genRequest)\n  }\n\n  override suspend fun getTokenLimit(): Int {\n    return checkNotNull(generativeModel).getTokenLimit()\n  }\n\n  override fun startGeneratingUi() {\n    super.startGeneratingUi()\n    sendButton.isEnabled = false\n    requestEditText.isEnabled = false\n    selectImageButton.isEnabled = false\n    sendButton.setText(R.string.generating)\n  }\n\n  override fun endGeneratingUi(debugInfo: String) {\n    super.endGeneratingUi(debugInfo)\n    sendButton.isEnabled = true\n    requestEditText.isEnabled = true\n    selectImageButton.isEnabled = true\n    sendButton.setText(R.string.button_send)\n  }\n\n  private fun initGenerator() {\n    generativeModel?.close()\n    generativeModel = com.google.mlkit.genai.prompt.Generation.getClient()\n    resetProcessor()\n  }\n\n  override fun onCreateOptionsMenu(menu: Menu): Boolean {\n    if (!super.onCreateOptionsMenu(menu)) {\n      return false\n    }\n    menu.add(Menu.NONE, ACTION_CLEAR_CACHES, Menu.NONE, \"Clear all prefix caches\")\n    return true\n  }\n\n  override fun onPrepareOptionsMenu(menu: Menu): Boolean {\n    menu.findItem(R.id.action_simple_api)?.apply {\n      isVisible = true\n      isChecked = useDefaultConfig\n    }\n    menu.findItem(R.id.action_explicit_cache)?.apply {\n      isVisible = true\n      isChecked = useExplicitCache\n      isEnabled = !useDefaultConfig\n    }\n    return super.onPrepareOptionsMenu(menu)\n  }\n\n  override fun onOptionsItemSelected(item: MenuItem): Boolean {\n    when (item.itemId) {\n      ACTION_CLEAR_CACHES -> {\n        lifecycleScope.launch {\n          if (useExplicitCache) {\n            val caches = checkNotNull(generativeModel).caches.list()\n            if (caches.isNotEmpty()) {\n              Log.d(TAG, \"Going to delete explicit caches, size: ${caches.size}\")\n              for (cacheName in caches.map { it.name }) {\n                if (checkNotNull(generativeModel).caches.delete(cacheName)) {\n                  Log.d(TAG, \"Deleted explicit cache: $cacheName\")\n                } else {\n                  Log.d(TAG, \"Failed to delete explicit cache: $cacheName\")\n                }\n              }\n              prefixEditText.setText(\"\")\n            }\n          } else {\n            checkNotNull(generativeModel).clearImplicitCaches()\n            Log.d(TAG, \"Cleared implicit caches\")\n          }\n          Toast.makeText(this@OpenPromptActivity, \"Caches cleared\", Toast.LENGTH_SHORT).show()\n        }\n        return true\n      }\n      R.id.action_simple_api -> {\n        val newState = !item.isChecked\n        item.isChecked = newState\n        GenerationConfigUtils.setUseDefaultConfig(applicationContext, newState)\n        onConfigUpdated()\n        return true\n      }\n      R.id.action_explicit_cache -> {\n        val newState = !item.isChecked\n        item.isChecked = newState\n        GenerationConfigUtils.setUseExplicitCache(applicationContext, newState)\n        onConfigUpdated()\n        return true\n      }\n    }\n    return super.onOptionsItemSelected(item)\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/kotlin/ProofreadingActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo.kotlin\n\nimport android.os.Bundle\nimport androidx.core.content.ContextCompat\nimport com.google.common.util.concurrent.Futures\nimport com.google.common.util.concurrent.ListenableFuture\nimport com.google.mlkit.genai.common.DownloadCallback\nimport com.google.mlkit.genai.common.FeatureStatus\nimport com.google.mlkit.genai.common.StreamingCallback\nimport com.google.mlkit.genai.demo.ContentItem\nimport com.google.mlkit.genai.demo.R\nimport com.google.mlkit.genai.prompt.CountTokensResponse\nimport com.google.mlkit.genai.proofreading.Proofreader\nimport com.google.mlkit.genai.proofreading.ProofreaderOptions.InputType\nimport com.google.mlkit.genai.proofreading.ProofreaderOptions.Language\nimport com.google.mlkit.genai.proofreading.ProofreaderOptions.builder\nimport com.google.mlkit.genai.proofreading.Proofreading\nimport com.google.mlkit.genai.proofreading.ProofreadingRequest\n\n/** Demonstrates the Proofreading API usage. */\nclass ProofreadingActivity : TextInputBaseActivity() {\n  private var inputType = InputType.KEYBOARD\n  private var language = Language.ENGLISH\n  private var proofreader: Proofreader? = null\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n\n    setUpSpinners()\n    initProofreader()\n  }\n\n  override fun getLayoutResId(): Int {\n    return R.layout.activity_proofreading\n  }\n\n  override fun runInferenceForBatchTask(request: String): List<String> {\n    return try {\n      buildList {\n        val result =\n          checkNotNull(proofreader).runInference(ProofreadingRequest.builder(request).build()).get()\n        for (suggestion in result.results) {\n          add(suggestion.text)\n        }\n      }\n    } catch (e: Exception) {\n      listOf(\"Failed to run inference: ${e.message}\", \"0\")\n    }\n  }\n\n  override fun onDestroy() {\n    super.onDestroy()\n    proofreader?.close()\n  }\n\n  override fun getBaseModelName(): ListenableFuture<String> {\n    return checkNotNull(proofreader).baseModelName\n  }\n\n  override fun checkFeatureStatus(): @FeatureStatus ListenableFuture<Int> {\n    return checkNotNull(proofreader).checkFeatureStatus()\n  }\n\n  override fun downloadFeature(callback: DownloadCallback): ListenableFuture<Void> {\n    return checkNotNull(proofreader).downloadFeature(callback)\n  }\n\n  override fun runInferenceImpl(\n    request: ContentItem.TextItem,\n    streamingCallback: StreamingCallback?,\n  ): ListenableFuture<List<String>> {\n    val proofreadingRequest = ProofreadingRequest.builder(request.text).build()\n    val inferenceFuture =\n      checkNotNull(proofreader).let { proofreader ->\n        streamingCallback?.let { proofreader.runInference(proofreadingRequest, it) }\n          ?: proofreader.runInference(proofreadingRequest)\n      }\n\n    return Futures.transform(\n      inferenceFuture,\n      { proofreadingResult -> proofreadingResult.results.map { it.text } },\n      ContextCompat.getMainExecutor(this),\n    )\n  }\n\n  private fun setUpSpinners() {\n    setupSpinner(R.id.input_type_spinner, R.array.proofreading_input_types) { position ->\n      inputType =\n        when (position) {\n          0 -> InputType.KEYBOARD\n          1 -> InputType.VOICE\n          else -> inputType\n        }\n      initProofreader()\n    }\n\n    setupSpinner(R.id.language_spinner, R.array.proofreading_languages) { position ->\n      language =\n        when (position) {\n          0 -> Language.ENGLISH\n          1 -> Language.JAPANESE\n          2 -> Language.GERMAN\n          3 -> Language.FRENCH\n          4 -> Language.ITALIAN\n          5 -> Language.SPANISH\n          6 -> Language.KOREAN\n          else -> language\n        }\n      initProofreader()\n    }\n  }\n\n  private fun initProofreader() {\n    proofreader?.close()\n    val options = builder(this).setInputType(inputType).setLanguage(language).build()\n    proofreader = Proofreading.getClient(options)\n    resetProcessor()\n  }\n\n  override suspend fun countTokens(request: ContentItem.TextItem): CountTokensResponse {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n\n  override suspend fun getTokenLimit(): Int {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/kotlin/RewritingActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo.kotlin\n\nimport android.os.Bundle\nimport androidx.core.content.ContextCompat\nimport com.google.common.util.concurrent.Futures\nimport com.google.common.util.concurrent.ListenableFuture\nimport com.google.mlkit.genai.common.DownloadCallback\nimport com.google.mlkit.genai.common.FeatureStatus\nimport com.google.mlkit.genai.common.StreamingCallback\nimport com.google.mlkit.genai.demo.ContentItem\nimport com.google.mlkit.genai.demo.R\nimport com.google.mlkit.genai.prompt.CountTokensResponse\nimport com.google.mlkit.genai.rewriting.Rewriter\nimport com.google.mlkit.genai.rewriting.RewriterOptions\nimport com.google.mlkit.genai.rewriting.RewriterOptions.Language\nimport com.google.mlkit.genai.rewriting.RewriterOptions.OutputType\nimport com.google.mlkit.genai.rewriting.Rewriting\nimport com.google.mlkit.genai.rewriting.RewritingRequest\n\n/** Demonstrates the Rewriting API usage. */\nclass RewritingActivity : TextInputBaseActivity() {\n  private var outputType = OutputType.ELABORATE\n  private var language = Language.ENGLISH\n  private var rewriter: Rewriter? = null\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n\n    setUpSpinners()\n    initRewriter()\n  }\n\n  override fun getLayoutResId(): Int {\n    return R.layout.activity_rewrite\n  }\n\n  override fun runInferenceForBatchTask(request: String): List<String> {\n    return try {\n      buildList {\n        val result =\n          checkNotNull(rewriter).runInference(RewritingRequest.builder(request).build()).get()\n        for (suggestion in result.results) {\n          add(suggestion.text)\n        }\n      }\n    } catch (e: Exception) {\n      listOf(\"Failed to run inference: ${e.message}\", \"0\")\n    }\n  }\n\n  override fun onDestroy() {\n    super.onDestroy()\n    rewriter?.close()\n  }\n\n  override fun getBaseModelName(): ListenableFuture<String> {\n    return checkNotNull(rewriter).baseModelName\n  }\n\n  override fun checkFeatureStatus(): @FeatureStatus ListenableFuture<Int> {\n    return checkNotNull(rewriter).checkFeatureStatus()\n  }\n\n  override fun downloadFeature(callback: DownloadCallback): ListenableFuture<Void> {\n    return checkNotNull(rewriter).downloadFeature(callback)\n  }\n\n  override fun runInferenceImpl(\n    request: ContentItem.TextItem,\n    streamingCallback: StreamingCallback?,\n  ): ListenableFuture<List<String>> {\n    val rewritingRequest = RewritingRequest.builder(request.text).build()\n    val inferenceFuture =\n      checkNotNull(rewriter).let { rewriter ->\n        streamingCallback?.let { rewriter.runInference(rewritingRequest, it) }\n          ?: rewriter.runInference(rewritingRequest)\n      }\n\n    return Futures.transform(\n      inferenceFuture,\n      { rewriteResult -> rewriteResult.results.map { it.text } },\n      ContextCompat.getMainExecutor(this),\n    )\n  }\n\n  private fun setUpSpinners() {\n    setupSpinner(R.id.output_type_spinner, R.array.rewriting_output_types) { position ->\n      outputType =\n        when (position) {\n          0 -> OutputType.ELABORATE\n          1 -> OutputType.EMOJIFY\n          2 -> OutputType.SHORTEN\n          3 -> OutputType.FRIENDLY\n          4 -> OutputType.PROFESSIONAL\n          5 -> OutputType.REPHRASE\n          else -> outputType\n        }\n      initRewriter()\n    }\n    setupSpinner(R.id.language_spinner, R.array.rewriting_languages) { position ->\n      language =\n        when (position) {\n          0 -> Language.ENGLISH\n          1 -> Language.JAPANESE\n          2 -> Language.GERMAN\n          3 -> Language.FRENCH\n          4 -> Language.ITALIAN\n          5 -> Language.SPANISH\n          6 -> Language.KOREAN\n          else -> language\n        }\n      initRewriter()\n    }\n  }\n\n  private fun initRewriter() {\n    rewriter?.close()\n    val options =\n      RewriterOptions.builder(this).setOutputType(outputType).setLanguage(language).build()\n    rewriter = Rewriting.getClient(options)\n    resetProcessor()\n  }\n\n  override suspend fun countTokens(request: ContentItem.TextItem): CountTokensResponse {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n\n  override suspend fun getTokenLimit(): Int {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/kotlin/SummarizationActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo.kotlin\n\nimport android.os.Bundle\nimport androidx.core.content.ContextCompat\nimport com.google.common.util.concurrent.Futures\nimport com.google.common.util.concurrent.ListenableFuture\nimport com.google.mlkit.genai.common.DownloadCallback\nimport com.google.mlkit.genai.common.FeatureStatus\nimport com.google.mlkit.genai.common.StreamingCallback\nimport com.google.mlkit.genai.demo.ContentItem\nimport com.google.mlkit.genai.demo.R\nimport com.google.mlkit.genai.prompt.CountTokensResponse\nimport com.google.mlkit.genai.summarization.Summarization\nimport com.google.mlkit.genai.summarization.SummarizationRequest\nimport com.google.mlkit.genai.summarization.SummarizationResult\nimport com.google.mlkit.genai.summarization.Summarizer\nimport com.google.mlkit.genai.summarization.SummarizerOptions\nimport com.google.mlkit.genai.summarization.SummarizerOptions.InputType\nimport com.google.mlkit.genai.summarization.SummarizerOptions.Language\nimport com.google.mlkit.genai.summarization.SummarizerOptions.OutputType\n\n/** Demonstrates the Summarization API usage. */\nclass SummarizationActivity : TextInputBaseActivity() {\n  private var inputType = InputType.ARTICLE\n  private var outputType = OutputType.ONE_BULLET\n  private var language = Language.ENGLISH\n  private var summarizer: Summarizer? = null\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n\n    setUpInputAndOutputTypeSpinners()\n    initSummarizer()\n  }\n\n  override fun getLayoutResId(): Int {\n    return R.layout.activity_summarization\n  }\n\n  override fun runInferenceForBatchTask(request: String): List<String> {\n    try {\n      val result =\n        checkNotNull(summarizer).runInference(SummarizationRequest.builder(request).build()).get()\n      return listOf(result.summary)\n    } catch (e: Exception) {\n      return listOf(\"Failed to run inference: ${e.message}\")\n    }\n  }\n\n  override fun onDestroy() {\n    super.onDestroy()\n    summarizer?.close()\n  }\n\n  override fun getBaseModelName(): ListenableFuture<String> {\n    return checkNotNull(summarizer).baseModelName\n  }\n\n  override fun checkFeatureStatus(): @FeatureStatus ListenableFuture<Int> {\n    return checkNotNull(summarizer).checkFeatureStatus()\n  }\n\n  override fun downloadFeature(callback: DownloadCallback): ListenableFuture<Void> {\n    return checkNotNull(summarizer).downloadFeature(callback)\n  }\n\n  override fun runInferenceImpl(\n    request: ContentItem.TextItem,\n    streamingCallback: StreamingCallback?,\n  ): ListenableFuture<List<String>> {\n    val summarizeRequest = SummarizationRequest.builder(request.text).build()\n    val inferenceFuture =\n      checkNotNull(summarizer).let { summarizer ->\n        streamingCallback?.let { summarizer.runInference(summarizeRequest, it) }\n          ?: summarizer.runInference(summarizeRequest)\n      }\n\n    return Futures.transform<SummarizationResult, List<String>>(\n      inferenceFuture,\n      { summarizeResult -> listOf(summarizeResult.summary) },\n      ContextCompat.getMainExecutor(this),\n    )\n  }\n\n  private fun setUpInputAndOutputTypeSpinners() {\n    setupSpinner(R.id.input_type_spinner, R.array.summarization_input_types) { position ->\n      inputType =\n        when (position) {\n          0 -> InputType.ARTICLE\n          1 -> InputType.CONVERSATION\n          else -> inputType\n        }\n      initSummarizer()\n    }\n    setupSpinner(R.id.output_type_spinner, R.array.summarization_output_types) { position ->\n      outputType =\n        when (position) {\n          0 -> OutputType.ONE_BULLET\n          1 -> OutputType.TWO_BULLETS\n          2 -> OutputType.THREE_BULLETS\n          else -> outputType\n        }\n      initSummarizer()\n    }\n    setupSpinner(R.id.language_spinner, R.array.summarization_languages) { position ->\n      language =\n        when (position) {\n          0 -> Language.ENGLISH\n          1 -> Language.JAPANESE\n          2 -> Language.KOREAN\n          else -> language\n        }\n      initSummarizer()\n    }\n  }\n\n  private fun initSummarizer() {\n    summarizer?.close()\n    val options =\n      SummarizerOptions.builder(this)\n        .setInputType(inputType)\n        .setOutputType(outputType)\n        .setLanguage(language)\n        .build()\n    summarizer = Summarization.getClient(options)\n    resetProcessor()\n  }\n\n  override suspend fun countTokens(request: ContentItem.TextItem): CountTokensResponse {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n\n  override suspend fun getTokenLimit(): Int {\n    throw UnsupportedOperationException(\"Not supported\")\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/java/com/google/mlkit/genai/demo/kotlin/TextInputBaseActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.demo.kotlin\n\nimport android.os.Bundle\nimport android.text.TextUtils\nimport android.widget.Button\nimport android.widget.EditText\nimport android.widget.Toast\nimport com.google.mlkit.genai.demo.ContentItem\nimport com.google.mlkit.genai.demo.R\n\n/** Base Activity for APIs that accept text input as request. */\nabstract class TextInputBaseActivity : BaseActivity<ContentItem.TextItem>() {\n\n  private lateinit var requestEditText: EditText\n  private lateinit var sendButton: Button\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n\n    requestEditText = findViewById(R.id.request_edit_text)\n\n    sendButton = findViewById(R.id.send_button)\n    sendButton.setOnClickListener {\n      val request = requestEditText.text.toString()\n      if (TextUtils.isEmpty(request)) {\n        Toast.makeText(this, R.string.input_message_is_empty, Toast.LENGTH_SHORT).show()\n        return@setOnClickListener\n      }\n      onSend(ContentItem.TextItem.fromRequest(request))\n    }\n  }\n\n  override fun startGeneratingUi() {\n    super.startGeneratingUi()\n    sendButton.isEnabled = false\n    sendButton.setText(R.string.generating)\n    requestEditText.setText(R.string.empty)\n  }\n\n  override fun endGeneratingUi(debugInfo: String) {\n    super.endGeneratingUi(debugInfo)\n    sendButton.isEnabled = true\n    sendButton.setText(R.string.button_send)\n  }\n}\n"
  },
  {
    "path": "android/genai/app/src/main/res/drawable/edit_text_background_chat.xml",
    "content": "<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n    <solid android:color=\"#000000\" /> <corners android:radius=\"24dp\" /> <stroke android:width=\"1dp\" android:color=\"#444444\" /> </shape>\n"
  },
  {
    "path": "android/genai/app/src/main/res/drawable/ic_add_photo.xml",
    "content": "<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z\"/>\n</vector>\n"
  },
  {
    "path": "android/genai/app/src/main/res/drawable/ic_send.xml",
    "content": "<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z\"/>\n</vector>\n"
  },
  {
    "path": "android/genai/app/src/main/res/drawable/list_item_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\" >\n    <stroke android:width=\"3dip\" android:color=\"@color/blue\"/>\n    <corners android:bottomRightRadius=\"16dp\"\n        android:bottomLeftRadius=\"16dp\"\n        android:topLeftRadius=\"16dp\"\n        android:topRightRadius=\"16dp\" />\n</shape>\n"
  },
  {
    "path": "android/genai/app/src/main/res/drawable/request_item_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\" >\n    <stroke android:width=\"3dip\" android:color=\"@color/purple_200\"/>\n    <corners android:bottomRightRadius=\"16dp\"\n        android:bottomLeftRadius=\"16dp\"\n        android:topLeftRadius=\"16dp\"\n        android:topRightRadius=\"16dp\" />\n</shape>\n"
  },
  {
    "path": "android/genai/app/src/main/res/drawable/response_item_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\" >\n    <stroke android:width=\"3dip\" android:color=\"@color/material_grey_600\"/>\n    <corners android:bottomRightRadius=\"16dp\"\n        android:bottomLeftRadius=\"16dp\"\n        android:topLeftRadius=\"16dp\"\n        android:topRightRadius=\"16dp\" />\n</shape>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/activity_entry_choice.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/entry_recycler_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n</LinearLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/activity_image_description.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"4dp\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:id=\"@+id/debug_info_text_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:visibility=\"gone\" />\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/content_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      android:layout_weight=\"1\" />\n\n  <Button\n      android:id=\"@+id/select_image_button\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:text=\"@string/button_select_image\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/activity_openprompt.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:keepScreenOn=\"true\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"4dp\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:id=\"@+id/debug_info_text_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:visibility=\"gone\" />\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:gravity=\"center_vertical\"\n      android:orientation=\"horizontal\">\n\n    <Button\n      android:id=\"@+id/config_button\"\n      style=\"?attr/materialButtonOutlinedStyle\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"8dp\"\n      android:text=\"@string/button_change_config\" />\n  </LinearLayout>\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/content_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      android:layout_weight=\"1\"\n      android:clipToPadding=\"false\"\n      android:paddingTop=\"8dp\"/>\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:background=\"?android:attr/windowBackground\"\n      android:gravity=\"center_vertical\"\n      android:orientation=\"horizontal\"\n      android:paddingStart=\"8dp\"\n      android:paddingTop=\"8dp\"\n      android:paddingEnd=\"8dp\"\n      android:paddingBottom=\"8dp\">\n\n    <EditText\n        android:id=\"@+id/prefix_edit_text\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:background=\"@drawable/edit_text_background_chat\"\n        android:hint=\"@string/hint_add_prompt_prefix\"\n        android:importantForAutofill=\"no\"\n        android:inputType=\"textMultiLine|textCapSentences\"\n        android:maxLines=\"5\"\n        android:minHeight=\"48dp\"\n        android:paddingStart=\"12dp\"\n        android:paddingTop=\"10dp\"\n        android:paddingEnd=\"12dp\"\n        android:paddingBottom=\"10dp\"\n        android:textColor=\"#FFFFFF\"\n        android:textColorHint=\"#CCCCCC\"\n        tools:ignore=\"LabelFor\" />\n\n    <CheckBox\n        android:id=\"@+id/create_cache_checkbox\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"48dp\"\n        android:text=\"@string/create_cache\"\n        android:layout_marginStart=\"8dp\"\n        android:visibility=\"gone\"/>\n  </LinearLayout>\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:orientation=\"horizontal\"\n      android:gravity=\"center_vertical\"\n      android:paddingTop=\"8dp\"\n      android:paddingBottom=\"8dp\"\n      android:paddingStart=\"8dp\"\n      android:paddingEnd=\"8dp\"\n      android:background=\"?android:attr/windowBackground\">\n\n    <ImageButton\n        android:id=\"@+id/select_image_prompt_button\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:src=\"@drawable/ic_add_photo\" android:background=\"?attr/selectableItemBackgroundBorderless\"\n        android:contentDescription=\"@string/button_add_image_to_prompt\"\n        android:scaleType=\"centerInside\"\n        android:padding=\"8dp\"\n        android:layout_marginEnd=\"8dp\"/>\n\n    <ImageView\n        android:id=\"@+id/image_thumbnail_preview_input\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        android:scaleType=\"centerCrop\"\n        android:visibility=\"gone\"\n        android:layout_marginEnd=\"8dp\"\n        android:contentDescription=\"@string/selected_image_thumbnail_preview\"/>\n\n    <EditText\n        android:id=\"@+id/request_edit_text\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:minHeight=\"48dp\"\n        android:layout_weight=\"1\"\n        android:hint=\"@string/hint_type_a_message\"\n        android:importantForAutofill=\"no\"\n        android:inputType=\"textMultiLine|textCapSentences\"\n        android:maxLines=\"5\"\n        android:background=\"@drawable/edit_text_background_chat\"\n        android:paddingStart=\"12dp\"\n        android:paddingEnd=\"12dp\"\n        android:paddingTop=\"10dp\"\n        android:paddingBottom=\"10dp\"\n        android:textColor=\"#FFFFFF\"\n        android:textColorHint=\"#CCCCCC\"\n        tools:ignore=\"LabelFor\" />\n\n    <Button\n        android:id=\"@+id/send_button\"\n        android:layout_width=\"wrap_content\"\n        android:minWidth=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:text=\"@string/button_send\"\n        android:paddingStart=\"12dp\"\n        android:paddingEnd=\"12dp\"\n        android:layout_marginStart=\"8dp\"/>\n  </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/activity_proofreading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:keepScreenOn=\"true\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"4dp\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:id=\"@+id/debug_info_text_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:visibility=\"gone\"/>\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:gravity=\"center_vertical\"\n      android:orientation=\"horizontal\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/input_type_label\" />\n\n    <Spinner\n        android:id=\"@+id/input_type_spinner\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/language_label\" />\n\n    <Spinner\n        android:id=\"@+id/language_spinner\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n  </LinearLayout>\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/content_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      android:layout_weight=\"1\" />\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:orientation=\"horizontal\">\n\n    <EditText\n        android:id=\"@+id/request_edit_text\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:importantForAutofill=\"no\"\n        android:inputType=\"textMultiLine\"\n        tools:ignore=\"LabelFor\" />\n\n    <Button\n        android:id=\"@+id/send_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/button_send\" />\n\n  </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/activity_rewrite.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:keepScreenOn=\"true\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"4dp\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:id=\"@+id/debug_info_text_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:visibility=\"gone\"/>\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:gravity=\"center_vertical\"\n      android:orientation=\"horizontal\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/output_type_label\" />\n\n    <Spinner\n        android:id=\"@+id/output_type_spinner\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/language_label\" />\n\n    <Spinner\n        android:id=\"@+id/language_spinner\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n  </LinearLayout>\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/content_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      android:layout_weight=\"1\" />\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:orientation=\"horizontal\">\n\n    <EditText\n        android:id=\"@+id/request_edit_text\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:importantForAutofill=\"no\"\n        android:inputType=\"textMultiLine\"\n        tools:ignore=\"LabelFor\" />\n\n    <Button\n        android:id=\"@+id/send_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/button_send\" />\n\n  </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/activity_summarization.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:keepScreenOn=\"true\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"4dp\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:id=\"@+id/debug_info_text_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:visibility=\"gone\" />\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:padding=\"4dp\"\n      android:gravity=\"center_vertical\"\n      android:orientation=\"horizontal\">\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n      <TextView\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\"\n          android:paddingStart=\"8dp\"\n          android:text=\"@string/input_type_label\" />\n\n      <Spinner\n          android:id=\"@+id/input_type_spinner\"\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n      <TextView\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\"\n          android:paddingStart=\"8dp\"\n          android:text=\"@string/output_type_label\" />\n\n      <Spinner\n          android:id=\"@+id/output_type_spinner\"\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n      <TextView\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\"\n          android:paddingStart=\"8dp\"\n          android:text=\"@string/language_label\" />\n\n      <Spinner\n          android:id=\"@+id/language_spinner\"\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n  </LinearLayout>\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/content_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      android:layout_weight=\"1\" />\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:orientation=\"horizontal\">\n\n    <EditText\n        android:id=\"@+id/request_edit_text\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:importantForAutofill=\"no\"\n        android:inputType=\"textMultiLine\"\n        tools:ignore=\"LabelFor\" />\n\n    <Button\n        android:id=\"@+id/send_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/button_send\" />\n\n  </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/dialog_generation_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2024 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/generation_config\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n  <com.google.android.material.textfield.TextInputLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:hint=\"@string/hint_temperature\">\n\n    <com.google.android.material.textfield.TextInputEditText\n        android:id=\"@+id/temperature_edit_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"numberDecimal\" />\n\n  </com.google.android.material.textfield.TextInputLayout>\n\n  <com.google.android.material.textfield.TextInputLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:hint=\"@string/hint_top_k\">\n\n    <com.google.android.material.textfield.TextInputEditText\n        android:id=\"@+id/top_k_edit_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"numberSigned\" />\n\n  </com.google.android.material.textfield.TextInputLayout>\n\n  <com.google.android.material.textfield.TextInputLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:hint=\"@string/hint_seed\">\n\n    <com.google.android.material.textfield.TextInputEditText\n        android:id=\"@+id/seed_edit_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"numberDecimal\" />\n\n  </com.google.android.material.textfield.TextInputLayout>\n\n  <com.google.android.material.textfield.TextInputLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:hint=\"@string/hint_max_output_tokens\">\n\n    <com.google.android.material.textfield.TextInputEditText\n        android:id=\"@+id/max_output_tokens_edit_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"numberSigned\" />\n\n  </com.google.android.material.textfield.TextInputLayout>\n\n  <com.google.android.material.textfield.TextInputLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:hint=\"@string/hint_candidate_count\">\n\n    <com.google.android.material.textfield.TextInputEditText\n        android:id=\"@+id/candidate_count_edit_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"number\" />\n\n  </com.google.android.material.textfield.TextInputLayout>\n\n</LinearLayout>\n\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/entry_choice_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<com.google.android.material.card.MaterialCardView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"8dp\"\n    android:padding=\"16dp\"\n    android:radius=\"8dp\"\n    android:elevation=\"4dp\">\n\n  <TextView\n      android:id=\"@+id/title_text_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:textColor=\"?android:textColorPrimary\"\n      android:textSize=\"22sp\"\n      android:padding=\"8dp\" />\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/row_item_request_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<com.google.android.material.card.MaterialCardView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"16dp\"\n    android:radius=\"16dp\"\n    android:elevation=\"8dp\">\n\n  <ImageView\n      android:id=\"@+id/content_image_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"200dp\"\n      android:scaleType=\"centerInside\"\n      android:contentDescription=\"@null\"/>\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/row_item_request_text.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"48dp\"\n    android:layout_marginEnd=\"4dp\"\n    android:layout_marginVertical=\"8dp\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:id=\"@+id/content_text_view\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_gravity=\"end\"\n      android:padding=\"8dp\"\n      android:textIsSelectable=\"true\"\n      android:background=\"@drawable/request_item_background\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/row_item_request_text_and_images.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2024 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingStart=\"48dp\"\n    android:paddingEnd=\"4dp\"\n    android:paddingTop=\"8dp\"\n    android:paddingBottom=\"8dp\"\n    android:clipToPadding=\"false\">\n\n    <LinearLayout\n        android:id=\"@+id/chat_bubble_layout\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:layout_gravity=\"end\"\n        android:background=\"@drawable/request_item_background\"\n        android:padding=\"10dp\">\n\n        <HorizontalScrollView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:requiresFadingEdge=\"horizontal\"\n            android:fadingEdgeLength=\"32dp\">\n\n            <LinearLayout\n                android:id=\"@+id/image_container\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                android:visibility=\"gone\" />\n        </HorizontalScrollView>\n\n        <TextView\n            android:id=\"@+id/chat_message_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"8dp\"\n            android:textIsSelectable=\"true\"\n            android:visibility=\"gone\" />\n    </LinearLayout>\n\n</FrameLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/layout/row_item_response.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"4dp\"\n    android:layout_marginEnd=\"48dp\"\n    android:layout_marginVertical=\"8dp\"\n    android:orientation=\"vertical\"\n    android:padding=\"8dp\"\n    android:background=\"@drawable/response_item_background\">\n\n  <TextView\n      android:id=\"@+id/content_text_view\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:textIsSelectable=\"true\" />\n\n  <TextView\n      android:id=\"@+id/metadata_text_view\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginTop=\"4dp\"\n      android:textColor=\"#808080\"\n      android:textIsSelectable=\"true\"\n      android:visibility=\"gone\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "android/genai/app/src/main/res/menu/menu_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n  <item\n      android:id=\"@+id/action_streaming\"\n      android:title=\"@string/streaming\"\n      android:checkable=\"true\"\n      android:checked=\"true\"\n      app:showAsAction=\"never\" />\n  <item\n      android:id=\"@+id/action_streaming_api_submenu\"\n      android:title=\"@string/streaming_api\"\n      app:showAsAction=\"never\">\n      <menu>\n          <group android:checkableBehavior=\"single\">\n              <item\n                  android:id=\"@+id/action_streaming_flow\"\n                  android:title=\"@string/kotlin_flow\"\n                  android:checked=\"true\" />\n              <item\n                  android:id=\"@+id/action_streaming_callback\"\n                  android:title=\"@string/streaming_callback\" />\n          </group>\n      </menu>\n  </item>\n  <item\n      android:id=\"@+id/action_batch_run\"\n      android:title=\"@string/batch_run\"\n      app:showAsAction=\"never\" />\n  <item\n      android:id=\"@+id/action_simple_api\"\n      android:title=\"@string/action_simple_api\"\n      android:checkable=\"true\"\n      android:checked=\"false\"\n      android:visible=\"false\"\n      app:showAsAction=\"never\" />\n  <item\n      android:id=\"@+id/action_explicit_cache\"\n      android:title=\"@string/action_explicit_cache\"\n      android:checkable=\"true\"\n      android:checked=\"false\"\n      android:visible=\"false\"\n      app:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "android/genai/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<resources>\n  <color name=\"purple_200\">#FFBB86FC</color>\n  <color name=\"purple_500\">#FF6200EE</color>\n  <color name=\"purple_700\">#FF3700B3</color>\n  <color name=\"teal_200\">#FF03DAC5</color>\n  <color name=\"teal_700\">#FF018786</color>\n  <color name=\"black\">#FF000000</color>\n  <color name=\"blue\">#FF4286f4</color>\n  <color name=\"white\">#FFFFFFFF</color>\n</resources>\n"
  },
  {
    "path": "android/genai/app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<resources>\n  <string name=\"app_name\" translatable=\"false\">MLKit-GenAI</string>\n  <string name=\"summarization_entry_title_kotlin\" translatable=\"false\">Summarization API (Kotlin)</string>\n  <string name=\"summarization_entry_title_java\" translatable=\"false\">Summarization API (Java)</string>\n  <string name=\"rewriting_entry_title_kotlin\" translatable=\"false\">Rewriting API (Kotlin)</string>\n  <string name=\"rewriting_entry_title_java\" translatable=\"false\">Rewriting API (Java)</string>\n  <string name=\"proofreading_entry_title_kotlin\" translatable=\"false\">Proofreading API (Kotlin)</string>\n  <string name=\"proofreading_entry_title_java\" translatable=\"false\">Proofreading API (Java)</string>\n  <string name=\"image_description_entry_title_kotlin\" translatable=\"false\">Image Description API (Kotlin)</string>\n  <string name=\"image_description_entry_title_java\" translatable=\"false\">Image Description API (Java)</string>\n  <string name=\"open_prompt_entry_title_kotlin\" translatable=\"false\">Open Prompt API (Kotlin)</string>\n  <string name=\"open_prompt_entry_title_java\" translatable=\"false\">Open Prompt API (Java)</string>\n  <string name=\"button_send\" translatable=\"false\">Send</string>\n  <string name=\"button_select_image\" translatable=\"false\">Select Image</string>\n  <string name=\"button_cancel\" translatable=\"false\">Cancel</string>\n  <string name=\"generating\" translatable=\"false\">Generating...</string>\n  <string name=\"input_message_is_empty\" translatable=\"false\">Please enter a non empty message</string>\n  <string name=\"debug_info\" translatable=\"false\">Latency: %d ms</string>\n  <string name=\"debug_info_streaming\" translatable=\"false\">Latency: first token %d ms, total %d ms</string>\n  <string name=\"base_model_name\" translatable=\"false\">Base model name: %s</string>\n  <string name=\"streaming\" translatable=\"false\">Streaming</string>\n  <string name=\"streaming_api\" translatable=\"false\">Streaming API</string>\n  <string name=\"kotlin_flow\" translatable=\"false\">Kotlin Flow</string>\n  <string name=\"streaming_callback\" translatable=\"false\">Streaming Callback</string>\n  <string name=\"batch_run\" translatable=\"false\">Batch Run</string>\n  <string name=\"batch_run_start_message\" translatable=\"false\">Start processing...</string>\n  <string name=\"empty\" translatable=\"false\"/>\n  <string name=\"input_type_label\" translatable=\"false\">Input:</string>\n  <string name=\"output_type_label\" translatable=\"false\">Output:</string>\n  <string name=\"language_label\" translatable=\"false\">Language:</string>\n  <string name=\"button_change_config\" translatable=\"false\">Change config</string>\n  <string name=\"hint_temperature\" translatable=\"false\">Temperature</string>\n  <string name=\"hint_top_k\" translatable=\"false\">TopK</string>\n  <string name=\"hint_seed\" translatable=\"false\">Seed</string>\n  <string name=\"hint_max_output_tokens\" translatable=\"false\">MaxOutputTokens</string>\n  <string name=\"hint_candidate_count\" translatable=\"false\">CandidateCount</string>\n  <string name=\"pref_key_temperature\" translatable=\"false\">pk_temp</string>\n  <string name=\"pref_key_top_k\" translatable=\"false\">pk_topk</string>\n  <string name=\"pref_key_max_output_tokens\" translatable=\"false\">pk_mot</string>\n  <string name=\"pref_key_seed\" translatable=\"false\">pk_seed</string>\n  <string name=\"pref_key_candidate_count\" translatable=\"false\">pk_cc</string>\n  <string name=\"pref_key_use_default_config\" translatable=\"false\">pk_udc</string>\n  <string name=\"pref_key_use_explicit_cache\" translatable=\"false\">pk_uec</string>\n  <string name=\"action_simple_api\" translatable=\"false\">Use Simple Utility API</string>\n  <string name=\"action_explicit_cache\" translatable=\"false\">Use Explicit Prefix Cache</string>\n  <string name=\"selected_image_preview_for_prompt\" translatable=\"false\">Selected Image Preview for Prompt</string>\n  <string name=\"button_add_image\" translatable=\"false\">Add Image to Prompt</string>\n  <string name=\"button_save\" translatable=\"false\">Save</string>\n  <string name=\"button_add_image_to_prompt\" translatable=\"false\">Add Image to Prompt</string>\n  <string name=\"selected_image_thumbnail_preview\" translatable=\"false\">Selected Image Thumbnail Preview</string>\n  <string name=\"hint_type_a_message\" translatable=\"false\">Ask Open Prompt API</string>\n  <string name=\"hint_add_prompt_prefix\" translatable=\"false\">Optional: enter prompt prefix for lower latency</string>\n  <string name=\"hint_add_cache_name\" translatable=\"false\">Enter cache name</string>\n  <string name=\"hint_add_prefix_to_cache\" translatable=\"false\">Enter prefix to cache</string>\n  <string name=\"hint_add_suffix_for_inference\" translatable=\"false\">Enter suffix for inference</string>\n  <string name=\"hint_select_cache_name\" translatable=\"false\">Select cache name for inference</string>\n  <string name=\"create_cache\" translatable=\"false\">Create cache</string>\n  <string name=\"prefix_to_cache_empty\" translatable=\"false\">Prefix to cache cannot be empty</string>\n  <string name=\"warning_prefix_used_with_image\" translatable=\"false\">Prompt Prefix cannot be used with image input.</string>\n  <string name=\"message_format_prefix_and_suffix\" translatable=\"false\">Prefix:\\n%1$s\\n\\nSuffix:\\n%2$s</string>\n  <string name=\"message_format_cache_name_and_suffix\" translatable=\"false\">Cache Name:\\n%1$s\\n\\nSuffix:\\n%2$s</string>\n  <string name=\"message_format_cache_request\" translatable=\"false\">Cache Name:\\n%1$s\\n\\nPrefix to Cache:\\n%2$s</string>\n  <string name=\"cache_name_empty\" translatable=\"false\">Cache name cannot be empty</string>\n  <string name=\"prefix_cached\" translatable=\"false\">Prefix cached</string>\n  <string-array name=\"summarization_input_types\" translatable=\"false\">\n    <item>Article</item>\n    <item>Conversation</item>\n  </string-array>\n  <string-array name=\"summarization_output_types\" translatable=\"false\">\n    <item>One Bullet</item>\n    <item>Two Bullets</item>\n    <item>Three Bullets</item>\n  </string-array>\n  <string-array name=\"summarization_languages\" translatable=\"false\">\n    <item>English</item>\n    <item>Japanese</item>\n    <item>Korean</item>\n  </string-array>\n  <string-array name=\"rewriting_output_types\" translatable=\"false\">\n    <item>Elaborate</item>\n    <item>Emojify</item>\n    <item>Shorten</item>\n    <item>Friendly</item>\n    <item>Professional</item>\n    <item>Rephrase</item>\n  </string-array>\n  <string-array name=\"rewriting_languages\" translatable=\"false\">\n    <item>English</item>\n    <item>Japanese</item>\n    <item>German</item>\n    <item>French</item>\n    <item>Italian</item>\n    <item>Spanish</item>\n    <item>Korean</item>\n  </string-array>\n  <string-array name=\"proofreading_input_types\" translatable=\"false\">\n    <item>Keyboard</item>\n    <item>Voice</item>\n  </string-array>\n  <string-array name=\"proofreading_languages\" translatable=\"false\">\n    <item>English</item>\n    <item>Japanese</item>\n    <item>German</item>\n    <item>French</item>\n    <item>Italian</item>\n    <item>Spanish</item>\n    <item>Korean</item>\n  </string-array>\n</resources>\n"
  },
  {
    "path": "android/genai/app/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n  <!-- Base application theme. -->\n  <style name=\"Theme.Demo\" parent=\"Theme.MaterialComponents.DayNight.DarkActionBar\">\n    <!-- Primary brand color. -->\n    <item name=\"colorPrimary\">@color/purple_500</item>\n    <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n    <item name=\"colorOnPrimary\">@color/white</item>\n    <!-- Secondary brand color. -->\n    <item name=\"colorSecondary\">@color/teal_200</item>\n    <item name=\"colorSecondaryVariant\">@color/teal_700</item>\n    <item name=\"colorOnSecondary\">@color/black</item>\n    <!-- Status bar color. -->\n    <item name=\"android:statusBarColor\">?attr/colorPrimaryVariant</item>\n  </style>\n</resources>\n"
  },
  {
    "path": "android/genai/build.gradle",
    "content": "/*\n * Copyright 2025 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n  ext.kotlin_version = '2.1.0'\n\n  repositories {\n    google()\n    mavenCentral()\n  }\n  dependencies {\n    classpath 'com.android.tools.build:gradle:8.9.1'\n    classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n    // NOTE: Do not place your application dependencies here; they belong\n    // in the individual module build.gradle files\n  }\n}\n\nallprojects {\n  repositories {\n    google()\n    mavenCentral()\n    mavenLocal()\n  }\n}\n\ntasks.register('clean', Delete) {\n  delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/genai/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. For more details, visit\n# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\n# Enables namespacing of each library's R class so that its R class includes only the\n# resources declared in the library itself and none from the library's dependencies,\n# thereby reducing the size of the R class for that library\nandroid.nonTransitiveRClass=true\n"
  },
  {
    "path": "android/genai/settings.gradle",
    "content": "/*\n * Copyright 2025 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nrootProject.name = \"ML Kit GenAI API demo\"\ninclude ':app'\n"
  },
  {
    "path": "android/internal/chooserx/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    namespace \"com.mlkit.example.internal\"\n    compileSdkVersion 31\n\n    defaultConfig {\n        minSdkVersion 19\n        targetSdkVersion 31\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        proguard {\n            debuggable false\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n        }\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    implementation 'com.google.android.material:material:1.2.0'\n    implementation 'androidx.recyclerview:recyclerview:1.1.0'\n    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'\n}\n"
  },
  {
    "path": "android/internal/chooserx/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "android/internal/chooserx/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"com.mlkit.example.internal\">\n</manifest>\n"
  },
  {
    "path": "android/internal/chooserx/src/main/java/com/mlkit/example/internal/BaseEntryChoiceActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.mlkit.example.internal;\n\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\nimport java.util.List;\n\npublic abstract class BaseEntryChoiceActivity extends AppCompatActivity {\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_entry_choice);\n\n    RecyclerView recyclerView = findViewById(R.id.choices_recycler);\n    recyclerView.setLayoutManager(new LinearLayoutManager(this));\n    recyclerView.setAdapter(new ChoiceAdapter(this, getChoices()));\n  }\n\n  protected abstract List<Choice> getChoices();\n}\n"
  },
  {
    "path": "android/internal/chooserx/src/main/java/com/mlkit/example/internal/Choice.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.mlkit.example.internal;\n\nimport android.content.Intent;\n\npublic class Choice {\n\n  public final String title;\n  public final String description;\n  public final Intent launchIntent;\n\n  public Choice(String title, String description, Intent launchIntent) {\n    this.title = title;\n    this.description = description;\n    this.launchIntent = launchIntent;\n  }\n}\n"
  },
  {
    "path": "android/internal/chooserx/src/main/java/com/mlkit/example/internal/ChoiceAdapter.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.mlkit.example.internal;\n\nimport android.app.Activity;\nimport androidx.recyclerview.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.TextView;\nimport androidx.annotation.NonNull;\nimport java.util.List;\n\npublic class ChoiceAdapter extends RecyclerView.Adapter<ChoiceAdapter.ViewHolder> {\n\n  private final Activity activity;\n  private final List<Choice> choices;\n\n  public ChoiceAdapter(Activity activity, List<Choice> choices) {\n    this.activity = activity;\n    this.choices = choices;\n  }\n\n  @NonNull\n  @Override\n  public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n    View view =\n        LayoutInflater.from(parent.getContext()).inflate(R.layout.item_choice, parent, false);\n    return new ViewHolder(view);\n  }\n\n  @Override\n  public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n    Choice choice = choices.get(position);\n    holder.bind(choice);\n  }\n\n  @Override\n  public int getItemCount() {\n    return choices.size();\n  }\n\n  public class ViewHolder extends RecyclerView.ViewHolder {\n\n    private final TextView titleText;\n    private final TextView descText;\n    private final Button launchButton;\n\n    public ViewHolder(View itemView) {\n      super(itemView);\n      titleText = itemView.findViewById(R.id.item_title);\n      descText = itemView.findViewById(R.id.item_description);\n      launchButton = itemView.findViewById(R.id.item_launch_button);\n    }\n\n    public void bind(final Choice choice) {\n      titleText.setText(choice.title);\n      descText.setText(choice.description);\n      launchButton.setOnClickListener(\n          new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n              activity.startActivity(choice.launchIntent);\n            }\n          });\n    }\n  }\n}\n"
  },
  {
    "path": "android/internal/chooserx/src/main/res/layout/activity_entry_choice.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.mlkit.example.internal.BaseEntryChoiceActivity\"\n    android:paddingTop=\"8dp\"\n    android:paddingBottom=\"8dp\"\n    android:clipToPadding=\"false\">\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/choices_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        tools:listitem=\"@layout/item_choice\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/internal/chooserx/src/main/res/layout/item_choice.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2020 Google LLC. All rights reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:clipToPadding=\"false\"\n    android:paddingBottom=\"8dp\"\n    android:paddingLeft=\"8dp\"\n    android:paddingRight=\"8dp\">\n\n    <com.google.android.material.card.MaterialCardView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\">\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <TextView\n                android:id=\"@+id/item_title\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"16dp\"\n                android:layout_marginStart=\"16dp\"\n                android:layout_marginTop=\"8dp\"\n                android:textSize=\"16sp\"\n                android:textStyle=\"bold\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintHorizontal_bias=\"0\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:text=\"Choice Title\" />\n\n\n            <TextView\n                android:id=\"@+id/item_description\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"16dp\"\n                android:layout_marginRight=\"16dp\"\n                android:layout_marginTop=\"8dp\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintHorizontal_bias=\"0\"\n                app:layout_constraintStart_toStartOf=\"@+id/item_title\"\n                app:layout_constraintTop_toBottomOf=\"@+id/item_title\"\n                tools:text=\"Choice Description\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/item_launch_button\"\n                style=\"@style/Widget.MaterialComponents.Button.TextButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"8dp\"\n                android:text=\"Open\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintTop_toBottomOf=\"@+id/item_description\" />\n\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n    </com.google.android.material.card.MaterialCardView>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/internal/lint/build.gradle",
    "content": "apply plugin: 'java-library'\napply plugin: \"kotlin\"\n\ntargetCompatibility = JavaVersion.VERSION_1_7\nsourceCompatibility = JavaVersion.VERSION_1_7\n\ndependencies {\n    compileOnly \"com.android.tools.lint:lint-api:26.5.3\"\n    compileOnly \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61\"\n    testImplementation \"com.android.tools.lint:lint:26.5.3\"\n    testImplementation \"com.android.tools.lint:lint-tests:26.5.3\"\n}\n\njar {\n    manifest {\n        attributes(\"Lint-Registry-v2\": \"com.mlkit.lint.QuickstartIssueRegistry\")\n    }\n}\n"
  },
  {
    "path": "android/internal/lint/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Feb 03 13:16:03 PST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.4.1-all.zip\n"
  },
  {
    "path": "android/internal/lint/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/internal/lint/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/internal/lint/src/main/java/com/mlkit/lint/HungarianNotationDetector.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.mlkit.lint\n\nimport com.android.tools.lint.client.api.UElementHandler\nimport com.android.tools.lint.detector.api.Category\nimport com.android.tools.lint.detector.api.Detector\nimport com.android.tools.lint.detector.api.Implementation\nimport com.android.tools.lint.detector.api.Issue\nimport com.android.tools.lint.detector.api.JavaContext\nimport com.android.tools.lint.detector.api.Scope\nimport com.android.tools.lint.detector.api.Severity\nimport org.jetbrains.uast.UField\n\nval ISSUE_HUNGARIAN_NOTATION = Issue.create(\n        \"HungarianNotation\",\n        \"Using mHungarianNotation in a Kotlin file!\",\n        \"mFriends don’t let sFriends use Hungarian notation! -Jake Wharton\",\n        Category.MESSAGES,\n        9,\n        Severity.ERROR,\n        Implementation(\n                HungarianNotationDetector::class.java,\n                Scope.JAVA_FILE_SCOPE))\n\nclass HungarianNotationDetector : Detector(), Detector.UastScanner {\n\n    override fun getApplicableUastTypes() = listOf(UField::class.java)\n\n    override fun createUastHandler(context: JavaContext) = HungarianNotationHandler(context)\n\n    class HungarianNotationHandler(private val context: JavaContext) : UElementHandler() {\n\n        override fun visitField(node: UField) {\n            val varName = node.name\n            val isKotlin = context.file.name.endsWith(\"kt\")\n            val isHungarian = varName.matches(RE_HUNGARIAN)\n\n            if (isKotlin && isHungarian) {\n                node.uastAnchor?.let {\n                    context.report(ISSUE_HUNGARIAN_NOTATION, node, context.getLocation(it), SHORT_MESSAGE)\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val SHORT_MESSAGE = \"Invalid Field Name: hungarian notation in a Kotlin file.\"\n\n        val RE_HUNGARIAN = Regex(\"^m[A-Z].*\")\n    }\n}\n"
  },
  {
    "path": "android/internal/lint/src/main/java/com/mlkit/lint/InvalidImportDetector.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.mlkit.lint\n\nimport com.android.tools.lint.client.api.UElementHandler\nimport com.android.tools.lint.detector.api.Category\nimport com.android.tools.lint.detector.api.Detector\nimport com.android.tools.lint.detector.api.Implementation\nimport com.android.tools.lint.detector.api.Issue\nimport com.android.tools.lint.detector.api.JavaContext\nimport com.android.tools.lint.detector.api.Scope\nimport com.android.tools.lint.detector.api.Severity\nimport org.jetbrains.uast.UImportStatement\n\nval ISSUE_INVALID_IMPORT = Issue.create(\n        \"SuspiciousImport\",\n        \"importing files from the `java` package in a kotlin file\",\n        \"Importing files from the java package is usually not intentional; it sometimes happens when \" +\n                \"you have classes with the same name in both `java` and `kotlin` package.\",\n        Category.CORRECTNESS,\n        9,\n        Severity.ERROR,\n        Implementation(\n                InvalidImportDetector::class.java,\n                Scope.JAVA_FILE_SCOPE))\n\nclass InvalidImportDetector : Detector(), Detector.UastScanner {\n\n    override fun getApplicableUastTypes() = listOf(UImportStatement::class.java)\n\n    override fun createUastHandler(context: JavaContext) = InvalidImportHandler(context)\n\n    class InvalidImportHandler(private val context: JavaContext) : UElementHandler() {\n\n        override fun visitImportStatement(node: UImportStatement) {\n            var importedPackageName = \"\"\n            val classPackageName = context.uastFile?.packageName.toString()\n\n            node.importReference?.let {\n                importedPackageName = it.asSourceString()\n            }\n\n            val classPackageSubFolders = classPackageName.split(\".\")\n            val importedPackageSubFolders = importedPackageName.split(\".\")\n\n            var i = 0\n            while (i < classPackageSubFolders.size && i < importedPackageSubFolders.size) {\n                if (classPackageSubFolders[i] == \"kotlin\" && importedPackageSubFolders[i] == \"java\") {\n                    node.importReference?.let {\n                        context.report(ISSUE_INVALID_IMPORT, node, context.getLocation(it), SHORT_MESSAGE)\n                    }\n                }\n                i++\n            }\n        }\n    }\n\n    companion object {\n        const val SHORT_MESSAGE = \"Invalid Import: java package imported from kotlin package.\"\n    }\n}\n"
  },
  {
    "path": "android/internal/lint/src/main/java/com/mlkit/lint/QuickstartIssueRegistry.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.mlkit.lint\n\nimport com.android.tools.lint.client.api.IssueRegistry\nimport com.android.tools.lint.detector.api.CURRENT_API\nimport com.android.tools.lint.detector.api.Issue\n\n@Suppress(\"unused\")\nclass QuickstartIssueRegistry : IssueRegistry() {\n\n    override val api = CURRENT_API\n\n    override val issues: List<Issue>\n        get() = listOf(ISSUE_INVALID_IMPORT, ISSUE_HUNGARIAN_NOTATION)\n}\n"
  },
  {
    "path": "android/internal/lint/src/test/java/com/mlkit/lint/InvalidImportDetectorTest.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.mlkit.lint\n\nimport com.android.tools.lint.checks.infrastructure.LintDetectorTest.java\nimport com.android.tools.lint.checks.infrastructure.TestLintTask.lint\nimport com.mlkit.lint.InvalidImportDetector.Companion.SHORT_MESSAGE\nimport org.junit.Test\n\nclass InvalidImportDetectorTest {\n\n    private val javaPackage = java(\"\"\"\n      package com.google.mlkit.java;\n\n      public final class Hello {\n        public static final class drawable {\n        }\n      }\"\"\").indented()\n\n    @Test\n    fun normalRImport() {\n        lint()\n                .files(javaPackage, java(\"\"\"\n          package com.google.mlkit.kotlin;\n\n          import com.google.mlkit.Hello;\n\n          class Example {\n          }\"\"\").indented())\n                .issues(ISSUE_INVALID_IMPORT)\n                .run()\n                .expectClean()\n    }\n\n    @Test\n    fun wrongImport() {\n        lint()\n                .files(javaPackage, java(\"\"\"\n          package com.google.mlkit.kotlin;\n\n          import com.google.mlkit.java.Hello;\n\n          class Example {\n          }\"\"\").indented())\n                .issues(ISSUE_INVALID_IMPORT)\n                .run()\n                .expect(\"\"\"\n          |src/com/google/mlkit/kotlin/Example.java:3: Error: $SHORT_MESSAGE [SuspiciousImport]\n          |import com.google.mlkit.java.Hello;\n          |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~\n          |1 errors, 0 warnings\"\"\".trimMargin())\n    }\n}\n"
  },
  {
    "path": "android/internal/lintchecks/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 29\n\n    defaultConfig {\n        minSdkVersion 16\n        targetSdkVersion 29\n    }\n}\n\ndependencies {\n    lintChecks project(\":internal:lint\")\n}\n"
  },
  {
    "path": "android/internal/lintchecks/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Feb 03 13:15:08 PST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.4.1-all.zip\n"
  },
  {
    "path": "android/internal/lintchecks/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/internal/lintchecks/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/internal/lintchecks/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "android/internal/lintchecks/src/main/AndroidManifest.xml",
    "content": "<!--\n  ~ Copyright 2018 Google LLC. All rights reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<manifest package=\"com.mlkit.lintchecks\" />\n"
  },
  {
    "path": "android/langid/README.md",
    "content": "# ML Kit Language ID Quickstart\n\n* [Read more about ML Kit Language ID](https://developers.google.com/ml-kit/language/identification)\n\n## Introduction\n\nThe ML Kit Language ID Android Quickstart app demonstrates how to use the Language\nID feature of ML Kit to identify the language of text in your application.\n\n## Getting Started\n\n* Run the sample code on your Android device or emulator\n* Type messages to identify languages\n* Try extending the code to add new features and functionality\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/language/identification/android)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/langid/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion 34\n    defaultConfig {\n        applicationId \"com.google.mlkit.samples.nl.languageid\"\n        minSdkVersion 21\n        targetSdkVersion 34\n        versionCode 1\n        versionName \"1.0\"\n        setProperty(\"archivesBaseName\", \"nl-langid\")\n    }\n    buildTypes {\n        proguard {\n            debuggable false\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n            testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardTest-rules.pro', 'proguard.cfg'\n        }\n        testBuildType \"proguard\"\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    lintOptions {\n        disable \"Instantiatable\"\n    }\n}\n\ndependencies {\n    implementation project(':internal:chooserx')\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'com.google.android.material:material:1.2.1'\n\n    implementation 'com.google.mlkit:language-id:17.0.6'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-language-id:17.0.0'\n}\n"
  },
  {
    "path": "android/langid/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "android/langid/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.google.mlkit.samples.nl.languageid\"\n    tools:overrideLibrary=\"com.google.android.gms.base\">\n\n  <application\n      android:allowBackup=\"true\"\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:theme=\"@style/AppTheme\">\n\n    <!-- Optional: Add it to automatically download ML model to device after\n      your app is installed.-->\n    <meta-data\n        android:name=\"com.google.mlkit.vision.DEPENDENCIES\"\n        android:value=\"langid\"/>\n\n    <activity\n        android:name=\".EntryChoiceActivity\"\n        android:exported=\"true\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\".java.MainActivityJava\"\n        android:exported=\"true\" />\n\n    <activity\n        android:name=\".kotlin.MainActivityKotlin\"\n        android:exported=\"true\" />\n\n  </application>\n</manifest>\n"
  },
  {
    "path": "android/langid/app/src/main/java/com/google/mlkit/samples/nl/languageid/EntryChoiceActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.languageid\n\nimport android.content.Intent\nimport com.google.mlkit.samples.nl.languageid.java.MainActivityJava\nimport com.google.mlkit.samples.nl.languageid.kotlin.MainActivityKotlin\nimport com.mlkit.example.internal.BaseEntryChoiceActivity\nimport com.mlkit.example.internal.Choice\n\nclass EntryChoiceActivity : BaseEntryChoiceActivity() {\n\n  override fun getChoices(): List<Choice> {\n    return listOf(\n      Choice(\n        \"Java\",\n        \"Run the ML Kit Language ID quickstart written in Java.\",\n        Intent(\n          this,\n          MainActivityJava::class.java\n        )\n      ),\n      Choice(\n        \"Kotlin\",\n        \"Run the ML Kit Language ID quickstart written in Kotlin.\",\n        Intent(\n          this,\n          MainActivityKotlin::class.java\n        )\n      )\n    )\n  }\n}\n"
  },
  {
    "path": "android/langid/app/src/main/java/com/google/mlkit/samples/nl/languageid/java/MainActivityJava.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.languageid.java;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.EditText;\nimport android.widget.TextView;\nimport android.widget.Toast;\nimport com.google.mlkit.nl.languageid.IdentifiedLanguage;\nimport com.google.mlkit.nl.languageid.LanguageIdentification;\nimport com.google.mlkit.nl.languageid.LanguageIdentifier;\nimport com.google.mlkit.samples.nl.languageid.R;\n\n/** Default launcher activity. */\npublic class MainActivityJava extends AppCompatActivity {\n\n  private static final String TAG = \"MyActivity\";\n\n  private EditText textBox;\n  private TextView language;\n  private TextView input;\n  private LanguageIdentifier languageIdentifier;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n\n    languageIdentifier = LanguageIdentification.getClient();\n    getLifecycle().addObserver(languageIdentifier);\n    textBox = findViewById(R.id.text_input);\n    input = findViewById(R.id.last_input);\n    language = findViewById(R.id.text_output);\n\n    findViewById(R.id.button)\n        .setOnClickListener(\n            v -> {\n              hideKeyboard();\n              String input = getInputText();\n              if (input.isEmpty()) {\n                return;\n              }\n\n              identifyLanguage(input);\n            });\n\n    findViewById(R.id.button_possible)\n        .setOnClickListener(\n            v -> {\n              hideKeyboard();\n              String input = getInputText();\n              if (input.isEmpty()) {\n                return;\n              }\n\n              identifyPossibleLanguages(input);\n            });\n\n    findViewById(R.id.clear_text).setOnClickListener(v -> textBox.getText().clear());\n  }\n\n  private void hideKeyboard() {\n    InputMethodManager inputMethodManager =\n        (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);\n    View view = getCurrentFocus();\n    if (inputMethodManager != null && view != null) {\n      inputMethodManager.hideSoftInputFromWindow(\n          view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n  }\n\n  private String getInputText() {\n    String input = textBox.getText().toString();\n    if (input.isEmpty()) {\n      Toast.makeText(MainActivityJava.this, R.string.empty_text_message, Toast.LENGTH_LONG).show();\n      return input;\n    }\n    return input;\n  }\n\n  /**\n   * Identify a language.\n   *\n   * @param inputText Input string to find language of.\n   */\n  private void identifyLanguage(final String inputText) {\n    language.setText(R.string.wait_message);\n\n    languageIdentifier\n        .identifyLanguage(inputText)\n        .addOnSuccessListener(\n            identifiedLanguage -> {\n              input.setText(getString(R.string.input, inputText));\n              language.setText(getString(R.string.language, identifiedLanguage));\n            })\n        .addOnFailureListener(\n            e -> {\n              Log.e(TAG, \"Language identification error\", e);\n              input.setText(getString(R.string.input, inputText));\n              language.setText(\"\");\n              Toast.makeText(\n                      MainActivityJava.this,\n                      getString(R.string.language_id_error)\n                          + \"\\nError: \"\n                          + e.getLocalizedMessage()\n                          + \"\\nCause: \"\n                          + e.getCause(),\n                      Toast.LENGTH_LONG)\n                  .show();\n            });\n  }\n\n  /**\n   * Identify all possible languages.\n   *\n   * @param inputText Input string to find language of.\n   */\n  private void identifyPossibleLanguages(final String inputText) {\n    language.setText(R.string.wait_message);\n\n    languageIdentifier\n        .identifyPossibleLanguages(inputText)\n        .addOnSuccessListener(\n            identifiedLanguages -> {\n              input.setText(getString(R.string.input, inputText));\n\n              String output = \"\";\n              for (IdentifiedLanguage identifiedLanguage : identifiedLanguages) {\n                output +=\n                    identifiedLanguage.getLanguageTag()\n                        + \" (\"\n                        + identifiedLanguage.getConfidence()\n                        + \"), \";\n              }\n              language.setText(\n                  getString(R.string.language, output.substring(0, output.length() - 2)));\n            })\n        .addOnFailureListener(\n            e -> {\n              Log.e(TAG, \"Language identification error\", e);\n              input.setText(getString(R.string.input, inputText));\n              language.setText(\"\");\n              Toast.makeText(\n                      MainActivityJava.this,\n                      getString(R.string.language_id_error)\n                          + \"\\nError: \"\n                          + e.getLocalizedMessage()\n                          + \"\\nCause: \"\n                          + e.getCause(),\n                      Toast.LENGTH_LONG)\n                  .show();\n            });\n  }\n}\n"
  },
  {
    "path": "android/langid/app/src/main/java/com/google/mlkit/samples/nl/languageid/kotlin/MainActivityKotlin.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.languageid.kotlin\n\nimport android.content.Context\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.Button\nimport android.widget.EditText\nimport android.widget.TextView\nimport android.widget.Toast\nimport com.google.mlkit.nl.languageid.LanguageIdentification\nimport com.google.mlkit.nl.languageid.LanguageIdentifier\nimport com.google.mlkit.samples.nl.languageid.R\n\n/** Default launcher activity. */\nclass MainActivityKotlin : AppCompatActivity() {\n  private lateinit var textBox: EditText\n  private lateinit var language: TextView\n  private lateinit var input: TextView\n  private lateinit var languageIdentifier: LanguageIdentifier\n\n  companion object {\n    private const val TAG = \"MyActivity\"\n  }\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_main)\n\n    languageIdentifier = LanguageIdentification.getClient()\n    lifecycle.addObserver(languageIdentifier)\n    textBox = findViewById(R.id.text_input)\n\n    input = findViewById(R.id.last_input)\n    language = findViewById(R.id.text_output)\n    findViewById<Button>(R.id.button).setOnClickListener { _ ->\n      hideKeyboard()\n      val input = getInputText()\n      if (input.isEmpty()) {\n        return@setOnClickListener\n      }\n\n      identifyLanguage(input)\n    }\n    findViewById<Button>(R.id.button_possible).setOnClickListener { _ ->\n      hideKeyboard()\n      val input = getInputText()\n      if (input.isEmpty()) {\n        return@setOnClickListener\n      }\n\n      identifyPossibleLanguages(input)\n    }\n    findViewById<Button>(R.id.clear_text).setOnClickListener { _ -> textBox.text.clear() }\n  }\n\n  private fun hideKeyboard() {\n    val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager\n    val view = getCurrentFocus()\n    if (inputMethodManager != null && view != null) {\n      inputMethodManager.hideSoftInputFromWindow(\n        view.getWindowToken(),\n        InputMethodManager.HIDE_NOT_ALWAYS\n      )\n    }\n  }\n\n  private fun getInputText(): String {\n    val input = textBox.getText().toString()\n    if (input.isEmpty()) {\n      Toast.makeText(this@MainActivityKotlin, R.string.empty_text_message, Toast.LENGTH_LONG).show()\n      return input\n    }\n    return input\n  }\n\n  /**\n   * Identify a language.\n   *\n   * @param inputText Input string to find language of.\n   */\n  private fun identifyLanguage(inputText: String) {\n    language.text = getString(R.string.wait_message)\n    languageIdentifier\n      .identifyLanguage(inputText)\n      .addOnSuccessListener { identifiedLanguage ->\n        input.text = getString(R.string.input, inputText)\n        language.text = getString(R.string.language, identifiedLanguage)\n      }\n      .addOnFailureListener { e ->\n        Log.e(TAG, \"Language identification error\", e)\n        input.text = getString(R.string.input, inputText)\n        language.text = \"\"\n        Toast.makeText(\n            this@MainActivityKotlin,\n            getString(R.string.language_id_error) +\n              \"\\nError: \" +\n              e.getLocalizedMessage() +\n              \"\\nCause: \" +\n              e.cause,\n            Toast.LENGTH_LONG\n          )\n          .show()\n      }\n  }\n\n  /**\n   * Identify all possible languages.\n   *\n   * @param inputText Input string to find language of.\n   */\n  private fun identifyPossibleLanguages(inputText: String) {\n    language.text = getString(R.string.wait_message)\n    languageIdentifier\n      .identifyPossibleLanguages(inputText)\n      .addOnSuccessListener { identifiedLanguages ->\n        input.text = getString(R.string.input, inputText)\n\n        var output = \"\"\n        for (identifiedLanguage in identifiedLanguages) {\n          output += identifiedLanguage.languageTag + \" (\" + identifiedLanguage.confidence + \"), \"\n        }\n        language.text = getString(R.string.language, output.substring(0, output.length - 2))\n      }\n      .addOnFailureListener { e ->\n        Log.e(TAG, \"Language identification error\", e)\n        input.text = getString(R.string.input, inputText)\n        language.text = \"\"\n        Toast.makeText(\n            this@MainActivityKotlin,\n            getString(R.string.language_id_error) +\n              \"\\nError: \" +\n              e.getLocalizedMessage() +\n              \"\\nCause: \" +\n              e.cause,\n            Toast.LENGTH_LONG\n          )\n          .show()\n      }\n  }\n}\n"
  },
  {
    "path": "android/langid/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportWidth=\"172.43\"\n    android:viewportHeight=\"129.06\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#66ff99\"\n      android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#66ff99\"\n      android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/langid/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".MainActivityJava\">\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:orientation=\"vertical\">\n\n  <EditText\n      android:id=\"@+id/text_input\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"16dp\"\n      android:layout_marginTop=\"16dp\"\n      android:layout_marginEnd=\"16dp\"\n      android:layout_marginBottom=\"24dp\"\n      android:hint=\"@string/edit_text\"\n      android:inputType=\"text\" />\n  <Button\n      android:id=\"@+id/button\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"16dp\"\n      android:layout_marginEnd=\"16dp\"\n      android:layout_marginBottom=\"40dp\"\n      android:text=\"@string/identify_language_button\" />\n  <Button\n      android:id=\"@+id/button_possible\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"16dp\"\n      android:layout_marginEnd=\"16dp\"\n      android:layout_marginBottom=\"40dp\"\n      android:text=\"@string/identify_possible_languages_button\" />\n  <Button\n      android:id=\"@+id/clear_text\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"16dp\"\n      android:layout_marginEnd=\"16dp\"\n      android:layout_marginBottom=\"40dp\"\n      android:text=\"@string/clear_text_button\" />\n  <TextView\n      android:id=\"@+id/last_input\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"16dp\"\n      android:layout_marginEnd=\"16dp\"\n      android:freezesText=\"true\" />\n  <TextView\n      android:id=\"@+id/text_output\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"16dp\"\n      android:layout_marginEnd=\"16dp\"\n      android:freezesText=\"true\" />\n  <TextView\n      android:id=\"@+id/content\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginTop=\"32dp\"\n      android:layout_marginBottom=\"32dp\"\n      android:layout_marginStart=\"16dp\"\n      android:layout_marginEnd=\"16dp\"\n      android:text=\"@string/language_id_context\" />\n  </LinearLayout>\n</ScrollView>\n"
  },
  {
    "path": "android/langid/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"colorPrimary\">@color/blue</color>\n  <color name=\"colorPrimaryDark\">@color/darkBlue</color>\n  <color name=\"colorAccent\">@color/red</color>\n\n  <color name=\"blue\">#3681E6</color>\n  <color name=\"darkBlue\">#2F5FC0</color>\n  <color name=\"red\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "android/langid/app/src/main/res/values/strings.xml",
    "content": "<resources>\n  <string name=\"app_name\">MLKit-LanguageID</string>\n  <string name=\"edit_text\">Enter your text (≥ 20 bytes for accurate results)</string>\n  <string name=\"identify_language_button\">Identify language</string>\n  <string name=\"identify_possible_languages_button\">Identify possible languages</string>\n  <string name=\"clear_text_button\">Clear text</string>\n  <string name=\"language\">Identified language(s): %1$s</string>\n  <string name=\"input\">Your input: %1$s</string>\n  <string name=\"empty_text_message\">Please enter your text in order to identify the language.</string>\n  <string name=\"wait_message\">Waiting…</string>\n  <string name=\"language_id_error\">Failed to identify language</string>\n  <string name=\"language_id_context\">ML Kit sample app to provide basic knowledge on using Language Identification API on Android.\\nEnter your text in the text box above and press button to trigger the API.</string>\n</resources>\n"
  },
  {
    "path": "android/langid/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n  <!-- Base application theme. -->\n  <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.DarkActionBar\">\n    <!-- Customize your theme here. -->\n    <item name=\"colorPrimary\">@color/blue</item>\n    <item name=\"colorPrimaryDark\">@color/darkBlue</item>\n    <item name=\"colorAccent\">@color/red</item>\n  </style>\n\n</resources>\n"
  },
  {
    "path": "android/langid/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.9.0'\n\n    repositories {\n        mavenLocal()\n        mavenCentral()\n        google()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.3.1'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        mavenCentral()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/langid/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Jan 24 22:44:42 UTC 2022\ndistributionBase=GRADLE_USER_HOME\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.5-bin.zip\ndistributionPath=wrapper/dists\nzipStorePath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\n"
  },
  {
    "path": "android/langid/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\n\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "android/langid/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n\n"
  },
  {
    "path": "android/langid/gradlew.bat",
    "content": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\n@rem you may not use this file except in compliance with the License.\n@rem You may obtain a copy of the License at\n@rem\n@rem      http://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "android/langid/settings.gradle",
    "content": "rootProject.name= \"mlkit_language_id_sample\"\ninclude ':app'\ninclude ':internal:chooserx'\nproject(':internal:chooserx').projectDir = file('../internal/chooserx')\n"
  },
  {
    "path": "android/material-showcase/.editorconfig",
    "content": "[*.{java,kt}]\nmax_line_length = 120\n"
  },
  {
    "path": "android/material-showcase/README.md",
    "content": "[![Build Status](https://travis-ci.org/firebase/mlkit-material-android.svg?branch=master)](https://travis-ci.org/firebase/mlkit-material-android)\n\n# ML Kit Vision Showcase App with Material Design\n\nThis app demonstrates how to build an end-to-end user experience with\n[Google ML Kit APIs](https://developers.google.com/ml-kit/guides) and following the\n[new Material for ML design guidelines](https://material.io/design/machine-learning/).\n\nThe goal of this app is to showcase an ideal ML Kit driven end to end solution for various ML Kit vision APIs and use cases. The following use cases are covered:\n* Visual search using the Object Detection & Tracking API - An end to end workflow for object detection and product search\n* “Wild Bird” search using the Object Detection & Tracking API - An end to end workflow for object detection and search using a custom TensorFlow Lite model\n* Barcode detection - An end to end barcode scanning solution\n\n<img src=\"screenshots/live_odt.gif\" width=\"256\"/> <img src=\"screenshots/static_odt.gif\" width=\"256\"/>\n<img src=\"screenshots/live_barcode.gif\" width=\"256\"/>\n\n## Steps to run the app\n\n* Clone this repo locally\n* Build and run it on an Android device\n\n## How to use the app\n\nThis app supports two usage scenarios: Live Camera and Static Image.\n\n### Live Camera scenario\n\nIt uses the camera preview as input and contains three workflow: object detection & visual search,\nobject detection & custom classification, and barcode detection. There's also a Settings page to\nallow you to configure several options:\n- Camera\n  - Preview Size - Specify the preview size of rear camera manually (Default size is chose appropriately based on screen size)\n- Object detection\n    - Enable Multiple Objects -- Enable multiple objects to be detected at once.\n    - Enable classification -- Enable coarse classification\n- Product search\n    - Enable auto search -- If enabled, search request will be fired automatically once object is detected and confirmed, otherwise a search button will appear to trigger search manually\n    - Confirmation time in manual search -- Required time that an manually-detected object needs to be in focus before it is confirmed.\n    - Confirmation time in auto search -- Required time that an auto-detected object needs to be in focus before it is confirmed.\n- Barcode detection\n    - Barcode reticle width -- Size of barcode reticle width relative to the camera preview width\n    - Barcode reticle height -- Size of the barcode reticle height relative to the camera preview height\n    - Enable Barcode size check -- Will prompt user to \"move closer\" if the detected barcode is too small\n    - Delay loading result -- Simulates a case where the detected barcode requires further processing before displaying the result.\n\n### Static Image scenario\n\nDuring this scenario, the app will prompt the user to select an image from the “Image Picker” (gallery), detect objects in the selected image, and then perform visual search on those objects. There are well designed UI components (overlay dots, card carousel etc.) to indicate the detected objects and search results.\n\n### Visual Search\n\nPlease note that the visual search functionality in this app will not work since there is no real search backend setup for this repository. However, it should be easy to hook up your  own search service (e.g. [Product Search](https://cloud.google.com/vision/product-search/docs)) by only replacing the [SearchEngine](https://github.com/googlesamples/mlkit/blob/master/android/material-showcase/app/src/main/java/com/google/mlkit/md/productsearch/SearchEngine.kt) class implementation.\n\n\n## License\n© Google, 2020. Licensed under an [Apache-2](./LICENSE) license.\n"
  },
  {
    "path": "android/material-showcase/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 31\n    defaultConfig {\n        applicationId \"com.google.mlkit.md\"\n        minSdkVersion 19\n        targetSdkVersion 31\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n        vectorDrawables.useSupportLibrary = true\n        multiDexEnabled true\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = \"1.8\"\n    }\n\n    aaptOptions {\n        noCompress \"tflite\"\n    }\n\n    sourceSets.main {\n        assets.srcDirs = ['assets']\n    }\n}\n\nandroidExtensions {\n    experimental = true\n}\n\ndependencies {\n    implementation 'com.android.volley:volley:1.2.1'\n    implementation 'com.google.android.material:material:1.4.0'\n    implementation \"androidx.lifecycle:lifecycle-extensions:2.2.0\"\n    implementation \"androidx.annotation:annotation:1.3.0\"\n    implementation \"androidx.core:core-ktx:1.7.0\"\n    implementation \"androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0\"\n    implementation 'androidx.preference:preference-ktx:1.1.1'\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n\n    // Barcode model\n    implementation 'com.google.mlkit:barcode-scanning:17.0.3'\n\n    // Object feature and model\n    implementation 'com.google.mlkit:object-detection:17.0.0'\n    // Custom model\n    implementation 'com.google.mlkit:object-detection-custom:17.0.0'\n\n    api 'com.google.guava:guava:30.1-jre'\n}\n"
  },
  {
    "path": "android/material-showcase/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "android/material-showcase/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.google.mlkit.md\"\n    android:installLocation=\"auto\">\n\n  <uses-feature android:name=\"android.hardware.camera\"/>\n\n  <uses-permission android:name=\"android.permission.INTERNET\"/>\n  <uses-permission android:name=\"android.permission.CAMERA\"/>\n\n  <application\n      android:allowBackup=\"false\"\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:supportsRtl=\"true\"\n      android:theme=\"@style/AppTheme\"\n      tools:ignore=\"GoogleAppIndexingWarning\">\n\n    <meta-data\n        android:name=\"com.google.android.gms.version\"\n        android:value=\"@integer/google_play_services_version\"/>\n\n    <activity\n        android:name=\"com.google.mlkit.md.MainActivity\"\n        android:exported=\"true\"\n        android:screenOrientation=\"portrait\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\"/>\n        <category android:name=\"android.intent.category.LAUNCHER\"/>\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\"com.google.mlkit.md.LiveObjectDetectionActivity\"\n        android:exported=\"false\"\n        android:screenOrientation=\"portrait\">\n    </activity>\n\n    <activity\n        android:name=\"com.google.mlkit.md.LiveBarcodeScanningActivity\"\n        android:exported=\"false\"\n        android:screenOrientation=\"portrait\">\n    </activity>\n\n    <activity\n        android:name=\"com.google.mlkit.md.StaticObjectDetectionActivity\"\n        android:exported=\"false\"\n        android:screenOrientation=\"portrait\">\n    </activity>\n\n    <activity\n        android:name=\"com.google.mlkit.md.CustomModelObjectDetectionActivity\"\n        android:exported=\"false\"\n        android:screenOrientation=\"portrait\">\n    </activity>\n\n    <activity\n        android:name=\"com.google.mlkit.md.settings.SettingsActivity\"\n        android:exported=\"false\"\n        android:label=\"@string/settings_title\"\n        android:screenOrientation=\"portrait\">\n    </activity>\n\n  </application>\n\n</manifest>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/CustomModelObjectDetectionActivity.kt",
    "content": "package com.google.mlkit.md\n\n/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.animation.AnimatorInflater\nimport android.animation.AnimatorSet\nimport android.content.Intent\nimport android.graphics.Bitmap\nimport android.graphics.Color\nimport android.hardware.Camera\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.view.View.OnClickListener\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.lifecycle.Observer\nimport androidx.lifecycle.ViewModelProviders\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.bottomsheet.BottomSheetBehavior\nimport com.google.android.material.chip.Chip\nimport com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\nimport com.google.common.base.Objects\nimport com.google.common.collect.ImmutableList\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.WorkflowModel\nimport com.google.mlkit.md.camera.WorkflowModel.WorkflowState\nimport com.google.mlkit.md.camera.CameraSource\nimport com.google.mlkit.md.camera.CameraSourcePreview\nimport com.google.mlkit.md.objectdetection.MultiObjectProcessor\nimport com.google.mlkit.md.objectdetection.ProminentObjectProcessor\nimport com.google.mlkit.md.productsearch.BottomSheetScrimView\nimport com.google.mlkit.md.productsearch.Product\nimport com.google.mlkit.md.productsearch.ProductAdapter\nimport com.google.mlkit.md.settings.PreferenceUtils\nimport com.google.mlkit.md.settings.SettingsActivity\nimport java.io.IOException\n\n/** Demonstrates the object detection and custom classification workflow using camera preview.\n *  Modeled after LiveObjectDetectionActivity.java */\nclass CustomModelObjectDetectionActivity : AppCompatActivity(), OnClickListener {\n\n    private var cameraSource: CameraSource? = null\n    private var preview: CameraSourcePreview? = null\n    private var graphicOverlay: GraphicOverlay? = null\n    private var settingsButton: View? = null\n    private var flashButton: View? = null\n    private var promptChip: Chip? = null\n    private var promptChipAnimator: AnimatorSet? = null\n    private var searchButton: ExtendedFloatingActionButton? = null\n    private var searchButtonAnimator: AnimatorSet? = null\n    private var workflowModel: WorkflowModel? = null\n    private var currentWorkflowState: WorkflowState? = null\n\n    private var bottomSheetBehavior: BottomSheetBehavior<View>? = null\n    private var bottomSheetScrimView: BottomSheetScrimView? = null\n    private var productRecyclerView: RecyclerView? = null\n    private var bottomSheetTitleView: TextView? = null\n    private var objectThumbnailForBottomSheet: Bitmap? = null\n    private var slidingSheetUpFromHiddenState: Boolean = false\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        setContentView(R.layout.activity_live_object)\n        preview = findViewById(R.id.camera_preview)\n        graphicOverlay = findViewById<GraphicOverlay>(R.id.camera_preview_graphic_overlay).apply {\n            setOnClickListener(this@CustomModelObjectDetectionActivity)\n            cameraSource = CameraSource(this)\n        }\n        promptChip = findViewById(R.id.bottom_prompt_chip)\n        promptChipAnimator =\n            (AnimatorInflater.loadAnimator(this, R.animator.bottom_prompt_chip_enter) as AnimatorSet).apply {\n                setTarget(promptChip)\n            }\n        searchButton = findViewById<ExtendedFloatingActionButton>(R.id.product_search_button).apply {\n            setOnClickListener(this@CustomModelObjectDetectionActivity)\n        }\n        searchButtonAnimator =\n            (AnimatorInflater.loadAnimator(this, R.animator.search_button_enter) as AnimatorSet).apply {\n                setTarget(searchButton)\n            }\n        setUpBottomSheet()\n        findViewById<View>(R.id.close_button).setOnClickListener(this)\n        flashButton = findViewById<View>(R.id.flash_button).apply {\n            setOnClickListener(this@CustomModelObjectDetectionActivity)\n        }\n        settingsButton = findViewById<View>(R.id.settings_button).apply {\n            setOnClickListener(this@CustomModelObjectDetectionActivity)\n        }\n        setUpWorkflowModel()\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        workflowModel?.markCameraFrozen()\n        settingsButton?.isEnabled = true\n        bottomSheetBehavior?.state = BottomSheetBehavior.STATE_HIDDEN\n        currentWorkflowState = WorkflowState.NOT_STARTED\n        cameraSource?.setFrameProcessor(\n            if (PreferenceUtils.isMultipleObjectsMode(this)) {\n                MultiObjectProcessor(\n                    graphicOverlay!!, workflowModel!!,\n                    CUSTOM_MODEL_PATH\n                )\n            } else {\n                ProminentObjectProcessor(\n                    graphicOverlay!!, workflowModel!!,\n                    CUSTOM_MODEL_PATH\n                )\n            }\n        )\n        workflowModel?.setWorkflowState(WorkflowState.DETECTING)\n    }\n\n    override fun onPause() {\n        super.onPause()\n        currentWorkflowState = WorkflowState.NOT_STARTED\n        stopCameraPreview()\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        cameraSource?.release()\n        cameraSource = null\n    }\n\n    override fun onBackPressed() {\n        if (bottomSheetBehavior?.state != BottomSheetBehavior.STATE_HIDDEN) {\n            bottomSheetBehavior?.setState(BottomSheetBehavior.STATE_HIDDEN)\n        } else {\n            super.onBackPressed()\n        }\n    }\n\n    override fun onClick(view: View) {\n        when (view.id) {\n            R.id.product_search_button -> {\n                searchButton?.isEnabled = false\n                workflowModel?.onSearchButtonClicked()\n            }\n            R.id.bottom_sheet_scrim_view -> bottomSheetBehavior?.setState(BottomSheetBehavior.STATE_HIDDEN)\n            R.id.close_button -> onBackPressed()\n            R.id.flash_button -> {\n                if (flashButton?.isSelected == true) {\n                    flashButton?.isSelected = false\n                    cameraSource?.updateFlashMode(Camera.Parameters.FLASH_MODE_OFF)\n                } else {\n                    flashButton?.isSelected = true\n                    cameraSource?.updateFlashMode(Camera.Parameters.FLASH_MODE_TORCH)\n                }\n            }\n            R.id.settings_button -> {\n                settingsButton?.isEnabled = false\n                startActivity(Intent(this, SettingsActivity::class.java))\n            }\n        }\n    }\n\n    private fun startCameraPreview() {\n        val cameraSource = this.cameraSource ?: return\n        val workflowModel = this.workflowModel ?: return\n        if (!workflowModel.isCameraLive) {\n            try {\n                workflowModel.markCameraLive()\n                preview?.start(cameraSource)\n            } catch (e: IOException) {\n                Log.e(TAG, \"Failed to start camera preview!\", e)\n                cameraSource.release()\n                this.cameraSource = null\n            }\n        }\n    }\n\n    private fun stopCameraPreview() {\n        if (workflowModel?.isCameraLive == true) {\n            workflowModel!!.markCameraFrozen()\n            flashButton?.isSelected = false\n            preview?.stop()\n        }\n    }\n\n    private fun setUpBottomSheet() {\n        bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.bottom_sheet))\n        bottomSheetBehavior?.setBottomSheetCallback(\n            object : BottomSheetBehavior.BottomSheetCallback() {\n                override fun onStateChanged(bottomSheet: View, newState: Int) {\n                    Log.d(TAG, \"Bottom sheet new state: $newState\")\n                    bottomSheetScrimView?.visibility =\n                        if (newState == BottomSheetBehavior.STATE_HIDDEN) View.GONE else View.VISIBLE\n                    graphicOverlay?.clear()\n\n                    when (newState) {\n                        BottomSheetBehavior.STATE_HIDDEN -> workflowModel?.setWorkflowState(WorkflowState.DETECTING)\n                        BottomSheetBehavior.STATE_COLLAPSED,\n                        BottomSheetBehavior.STATE_EXPANDED,\n                        BottomSheetBehavior.STATE_HALF_EXPANDED -> slidingSheetUpFromHiddenState = false\n                        BottomSheetBehavior.STATE_DRAGGING, BottomSheetBehavior.STATE_SETTLING -> {\n                        }\n                    }\n                }\n\n                override fun onSlide(bottomSheet: View, slideOffset: Float) {\n                    val searchedObject = workflowModel!!.searchedObject.value\n                    if (searchedObject == null || java.lang.Float.isNaN(slideOffset)) {\n                        return\n                    }\n\n                    val graphicOverlay = graphicOverlay ?: return\n                    val bottomSheetBehavior = bottomSheetBehavior ?: return\n                    val collapsedStateHeight = bottomSheetBehavior.peekHeight.coerceAtMost(bottomSheet.height)\n                    val bottomBitmap = objectThumbnailForBottomSheet ?: return\n                    if (slidingSheetUpFromHiddenState) {\n                        val thumbnailSrcRect = graphicOverlay.translateRect(searchedObject.boundingBox)\n                        bottomSheetScrimView?.updateWithThumbnailTranslateAndScale(\n                            bottomBitmap,\n                            collapsedStateHeight,\n                            slideOffset,\n                            thumbnailSrcRect\n                        )\n                    } else {\n                        bottomSheetScrimView?.updateWithThumbnailTranslate(\n                            bottomBitmap, collapsedStateHeight, slideOffset, bottomSheet\n                        )\n                    }\n                }\n            })\n\n        bottomSheetScrimView = findViewById<BottomSheetScrimView>(R.id.bottom_sheet_scrim_view).apply {\n            setOnClickListener(this@CustomModelObjectDetectionActivity)\n        }\n\n        bottomSheetTitleView = findViewById(R.id.bottom_sheet_title)\n        productRecyclerView = findViewById<RecyclerView>(R.id.product_recycler_view).apply {\n            setHasFixedSize(true)\n            layoutManager = LinearLayoutManager(this@CustomModelObjectDetectionActivity)\n            adapter = ProductAdapter(ImmutableList.of())\n        }\n    }\n\n    private fun setUpWorkflowModel() {\n        workflowModel = ViewModelProviders.of(this).get(WorkflowModel::class.java).apply {\n\n            // Observes the workflow state changes, if happens, update the overlay view indicators and\n            // camera preview state.\n            workflowState.observe(this@CustomModelObjectDetectionActivity, Observer { workflowState ->\n                if (workflowState == null || Objects.equal(currentWorkflowState, workflowState)) {\n                    return@Observer\n                }\n                currentWorkflowState = workflowState\n                Log.d(TAG, \"Current workflow state: ${workflowState.name}\")\n\n                if (PreferenceUtils.isAutoSearchEnabled(this@CustomModelObjectDetectionActivity)) {\n                    stateChangeInAutoSearchMode(workflowState)\n                } else {\n                    stateChangeInManualSearchMode(workflowState)\n                }\n            })\n\n            // Observes changes on the object to search, if happens, show detected object labels as\n            // product search results.\n            objectToSearch.observe(this@CustomModelObjectDetectionActivity, Observer { detectObject ->\n                val productList: List<Product> = detectObject.labels.map { label ->\n                    Product(\"\" /* imageUrl */, label.text, \"\" /* subtitle */)\n                }\n                workflowModel?.onSearchCompleted(detectObject, productList)\n            })\n\n            // Observes changes on the object that has search completed, if happens, show the bottom sheet\n            // to present search result.\n            searchedObject.observe(this@CustomModelObjectDetectionActivity, Observer { searchedObject ->\n                objectThumbnailForBottomSheet = searchedObject.getObjectThumbnail()\n                bottomSheetTitleView?.text = getString(R.string.buttom_sheet_custom_model_title)\n                productRecyclerView?.adapter = ProductAdapter(searchedObject.productList)\n                slidingSheetUpFromHiddenState = true\n                bottomSheetBehavior?.peekHeight =\n                    preview?.height?.div(2) ?: BottomSheetBehavior.PEEK_HEIGHT_AUTO\n                bottomSheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED\n            })\n        }\n    }\n\n    private fun stateChangeInAutoSearchMode(workflowState: WorkflowState) {\n        val wasPromptChipGone = promptChip!!.visibility == View.GONE\n\n        searchButton?.visibility = View.GONE\n        when (workflowState) {\n            WorkflowState.DETECTING, WorkflowState.DETECTED, WorkflowState.CONFIRMING -> {\n                promptChip?.visibility = View.VISIBLE\n                promptChip?.setText(\n                    if (workflowState == WorkflowState.CONFIRMING)\n                        R.string.prompt_hold_camera_steady\n                    else\n                        R.string.prompt_point_at_a_bird\n                )\n                startCameraPreview()\n            }\n            WorkflowState.CONFIRMED -> {\n                promptChip?.visibility = View.VISIBLE\n                promptChip?.setText(R.string.prompt_searching)\n                stopCameraPreview()\n            }\n            WorkflowState.SEARCHING -> {\n                promptChip?.visibility = View.GONE\n                stopCameraPreview()\n            }\n            WorkflowState.SEARCHED -> {\n                stopCameraPreview()\n            }\n            else -> promptChip?.visibility = View.GONE\n        }\n\n        val shouldPlayPromptChipEnteringAnimation = wasPromptChipGone && promptChip?.visibility == View.VISIBLE\n        if (shouldPlayPromptChipEnteringAnimation && promptChipAnimator?.isRunning == false) {\n            promptChipAnimator?.start()\n        }\n    }\n\n    private fun stateChangeInManualSearchMode(workflowState: WorkflowState) {\n        val wasPromptChipGone = promptChip?.visibility == View.GONE\n        val wasSearchButtonGone = searchButton?.visibility == View.GONE\n\n        when (workflowState) {\n            WorkflowState.DETECTING, WorkflowState.DETECTED, WorkflowState.CONFIRMING -> {\n                promptChip?.visibility = View.VISIBLE\n                promptChip?.setText(R.string.prompt_point_at_an_object)\n                searchButton?.visibility = View.GONE\n                startCameraPreview()\n            }\n            WorkflowState.CONFIRMED -> {\n                promptChip?.visibility = View.GONE\n                searchButton?.visibility = View.VISIBLE\n                searchButton?.isEnabled = true\n                searchButton?.setBackgroundColor(Color.WHITE)\n                startCameraPreview()\n            }\n            WorkflowState.SEARCHING -> {\n                promptChip?.visibility = View.GONE\n                searchButton?.visibility = View.VISIBLE\n                searchButton?.isEnabled = false\n                searchButton?.setBackgroundColor(Color.GRAY)\n                stopCameraPreview()\n            }\n            WorkflowState.SEARCHED -> {\n                promptChip?.visibility = View.GONE\n                searchButton?.visibility = View.GONE\n                stopCameraPreview()\n            }\n            else -> {\n                promptChip?.visibility = View.GONE\n                searchButton?.visibility = View.GONE\n            }\n        }\n\n        val shouldPlayPromptChipEnteringAnimation = wasPromptChipGone && promptChip?.visibility == View.VISIBLE\n        promptChipAnimator?.let {\n            if (shouldPlayPromptChipEnteringAnimation && !it.isRunning) it.start()\n        }\n\n        val shouldPlaySearchButtonEnteringAnimation = wasSearchButtonGone && searchButton?.visibility == View.VISIBLE\n        searchButtonAnimator?.let {\n            if (shouldPlaySearchButtonEnteringAnimation && !it.isRunning) it.start()\n        }\n    }\n\n    companion object {\n        private const val TAG = \"CustomModelODActivity\"\n        private const val CUSTOM_MODEL_PATH = \"custom_models/bird_classifier.tflite\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/InputInfo.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md\n\nimport android.graphics.Bitmap\nimport com.google.mlkit.md.camera.FrameMetadata\nimport java.nio.ByteBuffer\n\ninterface InputInfo {\n    fun getBitmap(): Bitmap\n}\n\nclass CameraInputInfo(\n    private val frameByteBuffer: ByteBuffer,\n    private val frameMetadata: FrameMetadata\n) : InputInfo {\n\n    private var bitmap: Bitmap? = null\n\n    @Synchronized\n    override fun getBitmap(): Bitmap {\n        return bitmap ?: let {\n            bitmap = Utils.convertToBitmap(\n                frameByteBuffer, frameMetadata.width, frameMetadata.height, frameMetadata.rotation\n            )\n            bitmap!!\n        }\n    }\n}\n\nclass BitmapInputInfo(private val bitmap: Bitmap) : InputInfo {\n    override fun getBitmap(): Bitmap {\n        return bitmap\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/LiveBarcodeScanningActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md\n\nimport android.animation.AnimatorInflater\nimport android.animation.AnimatorSet\nimport android.content.Intent\nimport android.hardware.Camera\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.view.View.OnClickListener\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.lifecycle.Observer\nimport androidx.lifecycle.ViewModelProviders\nimport com.google.android.material.chip.Chip\nimport com.google.common.base.Objects\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.WorkflowModel\nimport com.google.mlkit.md.camera.WorkflowModel.WorkflowState\nimport com.google.mlkit.md.barcodedetection.BarcodeField\nimport com.google.mlkit.md.barcodedetection.BarcodeProcessor\nimport com.google.mlkit.md.barcodedetection.BarcodeResultFragment\nimport com.google.mlkit.md.camera.CameraSource\nimport com.google.mlkit.md.camera.CameraSourcePreview\nimport com.google.mlkit.md.settings.SettingsActivity\nimport java.io.IOException\nimport java.util.ArrayList\n\n/** Demonstrates the barcode scanning workflow using camera preview.  */\nclass LiveBarcodeScanningActivity : AppCompatActivity(), OnClickListener {\n\n    private var cameraSource: CameraSource? = null\n    private var preview: CameraSourcePreview? = null\n    private var graphicOverlay: GraphicOverlay? = null\n    private var settingsButton: View? = null\n    private var flashButton: View? = null\n    private var promptChip: Chip? = null\n    private var promptChipAnimator: AnimatorSet? = null\n    private var workflowModel: WorkflowModel? = null\n    private var currentWorkflowState: WorkflowState? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        setContentView(R.layout.activity_live_barcode)\n        preview = findViewById(R.id.camera_preview)\n        graphicOverlay = findViewById<GraphicOverlay>(R.id.camera_preview_graphic_overlay).apply {\n            setOnClickListener(this@LiveBarcodeScanningActivity)\n            cameraSource = CameraSource(this)\n        }\n\n        promptChip = findViewById(R.id.bottom_prompt_chip)\n        promptChipAnimator =\n            (AnimatorInflater.loadAnimator(this, R.animator.bottom_prompt_chip_enter) as AnimatorSet).apply {\n                setTarget(promptChip)\n            }\n\n        findViewById<View>(R.id.close_button).setOnClickListener(this)\n        flashButton = findViewById<View>(R.id.flash_button).apply {\n            setOnClickListener(this@LiveBarcodeScanningActivity)\n        }\n        settingsButton = findViewById<View>(R.id.settings_button).apply {\n            setOnClickListener(this@LiveBarcodeScanningActivity)\n        }\n\n        setUpWorkflowModel()\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        workflowModel?.markCameraFrozen()\n        settingsButton?.isEnabled = true\n        currentWorkflowState = WorkflowState.NOT_STARTED\n        cameraSource?.setFrameProcessor(BarcodeProcessor(graphicOverlay!!, workflowModel!!))\n        workflowModel?.setWorkflowState(WorkflowState.DETECTING)\n    }\n\n    override fun onPostResume() {\n        super.onPostResume()\n        BarcodeResultFragment.dismiss(supportFragmentManager)\n    }\n\n    override fun onPause() {\n        super.onPause()\n        currentWorkflowState = WorkflowState.NOT_STARTED\n        stopCameraPreview()\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        cameraSource?.release()\n        cameraSource = null\n    }\n\n    override fun onClick(view: View) {\n        when (view.id) {\n            R.id.close_button -> onBackPressed()\n            R.id.flash_button -> {\n                flashButton?.let {\n                    if (it.isSelected) {\n                        it.isSelected = false\n                        cameraSource?.updateFlashMode(Camera.Parameters.FLASH_MODE_OFF)\n                    } else {\n                        it.isSelected = true\n                        cameraSource!!.updateFlashMode(Camera.Parameters.FLASH_MODE_TORCH)\n                    }\n                }\n            }\n            R.id.settings_button -> {\n                settingsButton?.isEnabled = false\n                startActivity(Intent(this, SettingsActivity::class.java))\n            }\n        }\n    }\n\n    private fun startCameraPreview() {\n        val workflowModel = this.workflowModel ?: return\n        val cameraSource = this.cameraSource ?: return\n        if (!workflowModel.isCameraLive) {\n            try {\n                workflowModel.markCameraLive()\n                preview?.start(cameraSource)\n            } catch (e: IOException) {\n                Log.e(TAG, \"Failed to start camera preview!\", e)\n                cameraSource.release()\n                this.cameraSource = null\n            }\n        }\n    }\n\n    private fun stopCameraPreview() {\n        val workflowModel = this.workflowModel ?: return\n        if (workflowModel.isCameraLive) {\n            workflowModel.markCameraFrozen()\n            flashButton?.isSelected = false\n            preview?.stop()\n        }\n    }\n\n    private fun setUpWorkflowModel() {\n        workflowModel = ViewModelProviders.of(this).get(WorkflowModel::class.java)\n\n        // Observes the workflow state changes, if happens, update the overlay view indicators and\n        // camera preview state.\n        workflowModel!!.workflowState.observe(this, Observer { workflowState ->\n            if (workflowState == null || Objects.equal(currentWorkflowState, workflowState)) {\n                return@Observer\n            }\n\n            currentWorkflowState = workflowState\n            Log.d(TAG, \"Current workflow state: ${currentWorkflowState!!.name}\")\n\n            val wasPromptChipGone = promptChip?.visibility == View.GONE\n\n            when (workflowState) {\n                WorkflowState.DETECTING -> {\n                    promptChip?.visibility = View.VISIBLE\n                    promptChip?.setText(R.string.prompt_point_at_a_barcode)\n                    startCameraPreview()\n                }\n                WorkflowState.CONFIRMING -> {\n                    promptChip?.visibility = View.VISIBLE\n                    promptChip?.setText(R.string.prompt_move_camera_closer)\n                    startCameraPreview()\n                }\n                WorkflowState.SEARCHING -> {\n                    promptChip?.visibility = View.VISIBLE\n                    promptChip?.setText(R.string.prompt_searching)\n                    stopCameraPreview()\n                }\n                WorkflowState.DETECTED, WorkflowState.SEARCHED -> {\n                    promptChip?.visibility = View.GONE\n                    stopCameraPreview()\n                }\n                else -> promptChip?.visibility = View.GONE\n            }\n\n            val shouldPlayPromptChipEnteringAnimation = wasPromptChipGone && promptChip?.visibility == View.VISIBLE\n            promptChipAnimator?.let {\n                if (shouldPlayPromptChipEnteringAnimation && !it.isRunning) it.start()\n            }\n        })\n\n        workflowModel?.detectedBarcode?.observe(this, Observer { barcode ->\n            if (barcode != null) {\n                val barcodeFieldList = ArrayList<BarcodeField>()\n                barcodeFieldList.add(BarcodeField(\"Raw Value\", barcode.rawValue ?: \"\"))\n                BarcodeResultFragment.show(supportFragmentManager, barcodeFieldList)\n            }\n        })\n    }\n\n    companion object {\n        private const val TAG = \"LiveBarcodeActivity\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/LiveObjectDetectionActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md\n\nimport android.animation.AnimatorInflater\nimport android.animation.AnimatorSet\nimport android.content.Intent\nimport android.graphics.Bitmap\nimport android.graphics.Color\nimport android.hardware.Camera\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.view.View.OnClickListener\nimport android.widget.ProgressBar\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.lifecycle.Observer\nimport androidx.lifecycle.ViewModelProviders\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.bottomsheet.BottomSheetBehavior\nimport com.google.android.material.chip.Chip\nimport com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\nimport com.google.common.base.Objects\nimport com.google.common.collect.ImmutableList\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.WorkflowModel\nimport com.google.mlkit.md.camera.WorkflowModel.WorkflowState\nimport com.google.mlkit.md.camera.CameraSource\nimport com.google.mlkit.md.camera.CameraSourcePreview\nimport com.google.mlkit.md.objectdetection.MultiObjectProcessor\nimport com.google.mlkit.md.objectdetection.ProminentObjectProcessor\nimport com.google.mlkit.md.productsearch.BottomSheetScrimView\nimport com.google.mlkit.md.productsearch.ProductAdapter\nimport com.google.mlkit.md.productsearch.SearchEngine\nimport com.google.mlkit.md.settings.PreferenceUtils\nimport com.google.mlkit.md.settings.SettingsActivity\nimport java.io.IOException\n\n/** Demonstrates the object detection and visual search workflow using camera preview.  */\nclass LiveObjectDetectionActivity : AppCompatActivity(), OnClickListener {\n\n    private var cameraSource: CameraSource? = null\n    private var preview: CameraSourcePreview? = null\n    private var graphicOverlay: GraphicOverlay? = null\n    private var settingsButton: View? = null\n    private var flashButton: View? = null\n    private var promptChip: Chip? = null\n    private var promptChipAnimator: AnimatorSet? = null\n    private var searchButton: ExtendedFloatingActionButton? = null\n    private var searchButtonAnimator: AnimatorSet? = null\n    private var searchProgressBar: ProgressBar? = null\n    private var workflowModel: WorkflowModel? = null\n    private var currentWorkflowState: WorkflowState? = null\n    private var searchEngine: SearchEngine? = null\n\n    private var bottomSheetBehavior: BottomSheetBehavior<View>? = null\n    private var bottomSheetScrimView: BottomSheetScrimView? = null\n    private var productRecyclerView: RecyclerView? = null\n    private var bottomSheetTitleView: TextView? = null\n    private var objectThumbnailForBottomSheet: Bitmap? = null\n    private var slidingSheetUpFromHiddenState: Boolean = false\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        searchEngine = SearchEngine(applicationContext)\n\n        setContentView(R.layout.activity_live_object)\n        preview = findViewById(R.id.camera_preview)\n        graphicOverlay = findViewById<GraphicOverlay>(R.id.camera_preview_graphic_overlay).apply {\n            setOnClickListener(this@LiveObjectDetectionActivity)\n            cameraSource = CameraSource(this)\n        }\n        promptChip = findViewById(R.id.bottom_prompt_chip)\n        promptChipAnimator =\n            (AnimatorInflater.loadAnimator(this, R.animator.bottom_prompt_chip_enter) as AnimatorSet).apply {\n                setTarget(promptChip)\n            }\n        searchButton = findViewById<ExtendedFloatingActionButton>(R.id.product_search_button).apply {\n            setOnClickListener(this@LiveObjectDetectionActivity)\n        }\n        searchButtonAnimator =\n            (AnimatorInflater.loadAnimator(this, R.animator.search_button_enter) as AnimatorSet).apply {\n                setTarget(searchButton)\n            }\n        searchProgressBar = findViewById(R.id.search_progress_bar)\n        setUpBottomSheet()\n        findViewById<View>(R.id.close_button).setOnClickListener(this)\n        flashButton = findViewById<View>(R.id.flash_button).apply {\n            setOnClickListener(this@LiveObjectDetectionActivity)\n        }\n        settingsButton = findViewById<View>(R.id.settings_button).apply {\n            setOnClickListener(this@LiveObjectDetectionActivity)\n        }\n        setUpWorkflowModel()\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        workflowModel?.markCameraFrozen()\n        settingsButton?.isEnabled = true\n        bottomSheetBehavior?.state = BottomSheetBehavior.STATE_HIDDEN\n        currentWorkflowState = WorkflowState.NOT_STARTED\n        cameraSource?.setFrameProcessor(\n            if (PreferenceUtils.isMultipleObjectsMode(this)) {\n                MultiObjectProcessor(graphicOverlay!!, workflowModel!!)\n            } else {\n                ProminentObjectProcessor(graphicOverlay!!, workflowModel!!)\n            }\n        )\n        workflowModel?.setWorkflowState(WorkflowState.DETECTING)\n    }\n\n    override fun onPause() {\n        super.onPause()\n        currentWorkflowState = WorkflowState.NOT_STARTED\n        stopCameraPreview()\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        cameraSource?.release()\n        cameraSource = null\n        searchEngine?.shutdown()\n    }\n\n    override fun onBackPressed() {\n        if (bottomSheetBehavior?.state != BottomSheetBehavior.STATE_HIDDEN) {\n            bottomSheetBehavior?.setState(BottomSheetBehavior.STATE_HIDDEN)\n        } else {\n            super.onBackPressed()\n        }\n    }\n\n    override fun onClick(view: View) {\n        when (view.id) {\n            R.id.product_search_button -> {\n                searchButton?.isEnabled = false\n                workflowModel?.onSearchButtonClicked()\n            }\n            R.id.bottom_sheet_scrim_view -> bottomSheetBehavior?.setState(BottomSheetBehavior.STATE_HIDDEN)\n            R.id.close_button -> onBackPressed()\n            R.id.flash_button -> {\n                if (flashButton?.isSelected == true) {\n                    flashButton?.isSelected = false\n                    cameraSource?.updateFlashMode(Camera.Parameters.FLASH_MODE_OFF)\n                } else {\n                    flashButton?.isSelected = true\n                    cameraSource?.updateFlashMode(Camera.Parameters.FLASH_MODE_TORCH)\n                }\n            }\n            R.id.settings_button -> {\n                settingsButton?.isEnabled = false\n                startActivity(Intent(this, SettingsActivity::class.java))\n            }\n        }\n    }\n\n    private fun startCameraPreview() {\n        val cameraSource = this.cameraSource ?: return\n        val workflowModel = this.workflowModel ?: return\n        if (!workflowModel.isCameraLive) {\n            try {\n                workflowModel.markCameraLive()\n                preview?.start(cameraSource)\n            } catch (e: IOException) {\n                Log.e(TAG, \"Failed to start camera preview!\", e)\n                cameraSource.release()\n                this.cameraSource = null\n            }\n        }\n    }\n\n    private fun stopCameraPreview() {\n        if (workflowModel?.isCameraLive == true) {\n            workflowModel!!.markCameraFrozen()\n            flashButton?.isSelected = false\n            preview?.stop()\n        }\n    }\n\n    private fun setUpBottomSheet() {\n        bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.bottom_sheet))\n        bottomSheetBehavior?.setBottomSheetCallback(\n            object : BottomSheetBehavior.BottomSheetCallback() {\n                override fun onStateChanged(bottomSheet: View, newState: Int) {\n                    Log.d(TAG, \"Bottom sheet new state: $newState\")\n                    bottomSheetScrimView?.visibility =\n                        if (newState == BottomSheetBehavior.STATE_HIDDEN) View.GONE else View.VISIBLE\n                    graphicOverlay?.clear()\n\n                    when (newState) {\n                        BottomSheetBehavior.STATE_HIDDEN -> workflowModel?.setWorkflowState(WorkflowState.DETECTING)\n                        BottomSheetBehavior.STATE_COLLAPSED,\n                        BottomSheetBehavior.STATE_EXPANDED,\n                        BottomSheetBehavior.STATE_HALF_EXPANDED -> slidingSheetUpFromHiddenState = false\n                        BottomSheetBehavior.STATE_DRAGGING, BottomSheetBehavior.STATE_SETTLING -> {\n                        }\n                    }\n                }\n\n                override fun onSlide(bottomSheet: View, slideOffset: Float) {\n                    val searchedObject = workflowModel!!.searchedObject.value\n                    if (searchedObject == null || java.lang.Float.isNaN(slideOffset)) {\n                        return\n                    }\n\n                    val graphicOverlay = graphicOverlay ?: return\n                    val bottomSheetBehavior = bottomSheetBehavior ?: return\n                    val collapsedStateHeight = bottomSheetBehavior.peekHeight.coerceAtMost(bottomSheet.height)\n                    val bottomBitmap = objectThumbnailForBottomSheet ?: return\n                    if (slidingSheetUpFromHiddenState) {\n                        val thumbnailSrcRect = graphicOverlay.translateRect(searchedObject.boundingBox)\n                        bottomSheetScrimView?.updateWithThumbnailTranslateAndScale(\n                            bottomBitmap,\n                            collapsedStateHeight,\n                            slideOffset,\n                            thumbnailSrcRect\n                        )\n                    } else {\n                        bottomSheetScrimView?.updateWithThumbnailTranslate(\n                            bottomBitmap, collapsedStateHeight, slideOffset, bottomSheet\n                        )\n                    }\n                }\n            })\n\n        bottomSheetScrimView = findViewById<BottomSheetScrimView>(R.id.bottom_sheet_scrim_view).apply {\n            setOnClickListener(this@LiveObjectDetectionActivity)\n        }\n\n        bottomSheetTitleView = findViewById(R.id.bottom_sheet_title)\n        productRecyclerView = findViewById<RecyclerView>(R.id.product_recycler_view).apply {\n            setHasFixedSize(true)\n            layoutManager = LinearLayoutManager(this@LiveObjectDetectionActivity)\n            adapter = ProductAdapter(ImmutableList.of())\n        }\n    }\n\n    private fun setUpWorkflowModel() {\n        workflowModel = ViewModelProviders.of(this).get(WorkflowModel::class.java).apply {\n\n            // Observes the workflow state changes, if happens, update the overlay view indicators and\n            // camera preview state.\n            workflowState.observe(this@LiveObjectDetectionActivity, Observer { workflowState ->\n                if (workflowState == null || Objects.equal(currentWorkflowState, workflowState)) {\n                    return@Observer\n                }\n                currentWorkflowState = workflowState\n                Log.d(TAG, \"Current workflow state: ${workflowState.name}\")\n\n                if (PreferenceUtils.isAutoSearchEnabled(this@LiveObjectDetectionActivity)) {\n                    stateChangeInAutoSearchMode(workflowState)\n                } else {\n                    stateChangeInManualSearchMode(workflowState)\n                }\n            })\n\n            // Observes changes on the object to search, if happens, fire product search request.\n            objectToSearch.observe(this@LiveObjectDetectionActivity, Observer { detectObject ->\n                searchEngine!!.search(detectObject) { detectedObject, products ->\n                    workflowModel?.onSearchCompleted(detectedObject, products)\n                }\n            })\n\n            // Observes changes on the object that has search completed, if happens, show the bottom sheet\n            // to present search result.\n            searchedObject.observe(this@LiveObjectDetectionActivity, Observer { nullableSearchedObject ->\n                val searchedObject = nullableSearchedObject ?: return@Observer\n                val productList = searchedObject.productList\n                objectThumbnailForBottomSheet = searchedObject.getObjectThumbnail()\n                bottomSheetTitleView?.text = resources\n                    .getQuantityString(\n                        R.plurals.bottom_sheet_title, productList.size, productList.size\n                    )\n                productRecyclerView?.adapter = ProductAdapter(productList)\n                slidingSheetUpFromHiddenState = true\n                bottomSheetBehavior?.peekHeight =\n                    preview?.height?.div(2) ?: BottomSheetBehavior.PEEK_HEIGHT_AUTO\n                bottomSheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED\n            })\n        }\n    }\n\n    private fun stateChangeInAutoSearchMode(workflowState: WorkflowState) {\n        val wasPromptChipGone = promptChip!!.visibility == View.GONE\n\n        searchButton?.visibility = View.GONE\n        searchProgressBar?.visibility = View.GONE\n        when (workflowState) {\n            WorkflowState.DETECTING, WorkflowState.DETECTED, WorkflowState.CONFIRMING -> {\n                promptChip?.visibility = View.VISIBLE\n                promptChip?.setText(\n                    if (workflowState == WorkflowState.CONFIRMING)\n                        R.string.prompt_hold_camera_steady\n                    else\n                        R.string.prompt_point_at_an_object\n                )\n                startCameraPreview()\n            }\n            WorkflowState.CONFIRMED -> {\n                promptChip?.visibility = View.VISIBLE\n                promptChip?.setText(R.string.prompt_searching)\n                stopCameraPreview()\n            }\n            WorkflowState.SEARCHING -> {\n                searchProgressBar?.visibility = View.VISIBLE\n                promptChip?.visibility = View.VISIBLE\n                promptChip?.setText(R.string.prompt_searching)\n                stopCameraPreview()\n            }\n            WorkflowState.SEARCHED -> {\n                promptChip?.visibility = View.GONE\n                stopCameraPreview()\n            }\n            else -> promptChip?.visibility = View.GONE\n        }\n\n        val shouldPlayPromptChipEnteringAnimation = wasPromptChipGone && promptChip?.visibility == View.VISIBLE\n        if (shouldPlayPromptChipEnteringAnimation && promptChipAnimator?.isRunning == false) {\n            promptChipAnimator?.start()\n        }\n    }\n\n    private fun stateChangeInManualSearchMode(workflowState: WorkflowState) {\n        val wasPromptChipGone = promptChip?.visibility == View.GONE\n        val wasSearchButtonGone = searchButton?.visibility == View.GONE\n\n        searchProgressBar?.visibility = View.GONE\n        when (workflowState) {\n            WorkflowState.DETECTING, WorkflowState.DETECTED, WorkflowState.CONFIRMING -> {\n                promptChip?.visibility = View.VISIBLE\n                promptChip?.setText(R.string.prompt_point_at_an_object)\n                searchButton?.visibility = View.GONE\n                startCameraPreview()\n            }\n            WorkflowState.CONFIRMED -> {\n                promptChip?.visibility = View.GONE\n                searchButton?.visibility = View.VISIBLE\n                searchButton?.isEnabled = true\n                searchButton?.setBackgroundColor(Color.WHITE)\n                startCameraPreview()\n            }\n            WorkflowState.SEARCHING -> {\n                promptChip?.visibility = View.GONE\n                searchButton?.visibility = View.VISIBLE\n                searchButton?.isEnabled = false\n                searchButton?.setBackgroundColor(Color.GRAY)\n                searchProgressBar!!.visibility = View.VISIBLE\n                stopCameraPreview()\n            }\n            WorkflowState.SEARCHED -> {\n                promptChip?.visibility = View.GONE\n                searchButton?.visibility = View.GONE\n                stopCameraPreview()\n            }\n            else -> {\n                promptChip?.visibility = View.GONE\n                searchButton?.visibility = View.GONE\n            }\n        }\n\n        val shouldPlayPromptChipEnteringAnimation = wasPromptChipGone && promptChip?.visibility == View.VISIBLE\n        promptChipAnimator?.let {\n            if (shouldPlayPromptChipEnteringAnimation && !it.isRunning) it.start()\n        }\n\n        val shouldPlaySearchButtonEnteringAnimation = wasSearchButtonGone && searchButton?.visibility == View.VISIBLE\n        searchButtonAnimator?.let {\n            if (shouldPlaySearchButtonEnteringAnimation && !it.isRunning) it.start()\n        }\n    }\n\n    companion object {\n        private const val TAG = \"LiveObjectActivity\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/MainActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.TextView\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.app.AppCompatDelegate\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\n\n/** Entry activity to select the detection mode.  */\nclass MainActivity : AppCompatActivity() {\n\n    private enum class DetectionMode(val titleResId: Int, val subtitleResId: Int) {\n        ODT_LIVE(R.string.mode_odt_live_title, R.string.mode_odt_live_subtitle),\n        ODT_STATIC(R.string.mode_odt_static_title, R.string.mode_odt_static_subtitle),\n        BARCODE_LIVE(R.string.mode_barcode_live_title, R.string.mode_barcode_live_subtitle),\n        CUSTOM_MODEL_LIVE(R.string.custom_model_live_title, R.string.custom_model_live_subtitle)\n    }\n\n    override fun onCreate(bundle: Bundle?) {\n        super.onCreate(bundle)\n\n        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)\n        setContentView(R.layout.activity_main)\n        findViewById<RecyclerView>(R.id.mode_recycler_view).apply {\n            setHasFixedSize(true)\n            layoutManager = LinearLayoutManager(this@MainActivity)\n            adapter = ModeItemAdapter(DetectionMode.values())\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        if (!Utils.allPermissionsGranted(this)) {\n            Utils.requestRuntimePermissions(this)\n        }\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == Utils.REQUEST_CODE_PHOTO_LIBRARY &&\n            resultCode == Activity.RESULT_OK &&\n            data != null\n        ) {\n            val intent = Intent(this, StaticObjectDetectionActivity::class.java)\n            intent.data = data.data\n            startActivity(intent)\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    private inner class ModeItemAdapter internal constructor(private val detectionModes: Array<DetectionMode>) :\n        RecyclerView.Adapter<ModeItemAdapter.ModeItemViewHolder>() {\n\n        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ModeItemViewHolder {\n            return ModeItemViewHolder(\n                LayoutInflater.from(parent.context)\n                    .inflate(\n                        R.layout.detection_mode_item, parent, false\n                    )\n            )\n        }\n\n        override fun onBindViewHolder(modeItemViewHolder: ModeItemViewHolder, position: Int) =\n            modeItemViewHolder.bindDetectionMode(detectionModes[position])\n\n        override fun getItemCount(): Int = detectionModes.size\n\n        private inner class ModeItemViewHolder internal constructor(view: View) : RecyclerView.ViewHolder(view) {\n\n            private val titleView: TextView = view.findViewById(R.id.mode_title)\n            private val subtitleView: TextView = view.findViewById(R.id.mode_subtitle)\n\n            internal fun bindDetectionMode(detectionMode: DetectionMode) {\n                titleView.setText(detectionMode.titleResId)\n                subtitleView.setText(detectionMode.subtitleResId)\n                itemView.setOnClickListener {\n                    val activity = this@MainActivity\n                    when (detectionMode) {\n                        DetectionMode.ODT_LIVE ->\n                            activity.startActivity(Intent(activity, LiveObjectDetectionActivity::class.java))\n                        DetectionMode.ODT_STATIC -> Utils.openImagePicker(activity)\n                        DetectionMode.BARCODE_LIVE ->\n                            activity.startActivity(Intent(activity, LiveBarcodeScanningActivity::class.java))\n                        DetectionMode.CUSTOM_MODEL_LIVE ->\n                            activity.startActivity(Intent(activity, CustomModelObjectDetectionActivity::class.java))\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/ScopedExecutor.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md\n\nimport java.util.concurrent.Executor\nimport java.util.concurrent.atomic.AtomicBoolean\n\n/**\n * Wraps an existing executor to provide a [.shutdown] method that allows subsequent\n * cancellation of submitted runnables.\n */\nclass ScopedExecutor(private val executor: Executor) : Executor {\n    private val shutdown = AtomicBoolean()\n    override fun execute(command: Runnable) {\n        // Return early if this object has been shut down.\n        if (shutdown.get()) {\n            return\n        }\n        executor.execute {\n\n            // Check again in case it has been shut down in the mean time.\n            if (shutdown.get()) {\n                return@execute\n            }\n            command.run()\n        }\n    }\n\n    /**\n     * After this method is called, no runnables that have been submitted or are subsequently\n     * submitted will start to execute, turning this executor into a no-op.\n     *\n     *\n     * Runnables that have already started to execute will continue.\n     */\n    fun shutdown() {\n        shutdown.set(true)\n    }\n}"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/StaticObjectDetectionActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md\n\nimport android.animation.AnimatorInflater\nimport android.animation.AnimatorSet\nimport android.app.Activity\nimport android.content.Intent\nimport android.content.res.Resources\nimport android.graphics.Bitmap\nimport android.graphics.PointF\nimport android.graphics.Rect\nimport android.graphics.RectF\nimport android.net.Uri\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.FrameLayout\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.annotation.MainThread\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.bottomsheet.BottomSheetBehavior\nimport com.google.android.material.chip.Chip\nimport com.google.common.collect.ImmutableList\nimport com.google.mlkit.md.productsearch.BottomSheetScrimView\nimport com.google.mlkit.md.objectdetection.DetectedObjectInfo\nimport com.google.mlkit.md.objectdetection.StaticObjectDotView\nimport com.google.mlkit.md.productsearch.PreviewCardAdapter\nimport com.google.mlkit.md.productsearch.Product\nimport com.google.mlkit.md.productsearch.ProductAdapter\nimport com.google.mlkit.md.productsearch.SearchEngine\nimport com.google.mlkit.md.productsearch.SearchedObject\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions\nimport com.google.mlkit.vision.objects.DetectedObject\nimport com.google.mlkit.vision.objects.ObjectDetection\nimport com.google.mlkit.vision.objects.ObjectDetector\nimport java.io.IOException\nimport java.lang.NullPointerException\nimport java.util.TreeMap\n\n/** Demonstrates the object detection and visual search workflow using static image.  */\nclass StaticObjectDetectionActivity : AppCompatActivity(), View.OnClickListener {\n\n    private val searchedObjectMap = TreeMap<Int, SearchedObject>()\n\n    private var loadingView: View? = null\n    private var bottomPromptChip: Chip? = null\n    private var inputImageView: ImageView? = null\n    private var previewCardCarousel: RecyclerView? = null\n    private var dotViewContainer: ViewGroup? = null\n\n    private var bottomSheetBehavior: BottomSheetBehavior<View>? = null\n    private var bottomSheetScrimView: BottomSheetScrimView? = null\n    private var bottomSheetTitleView: TextView? = null\n    private var productRecyclerView: RecyclerView? = null\n\n    private var inputBitmap: Bitmap? = null\n    private var searchedObjectForBottomSheet: SearchedObject? = null\n    private var dotViewSize: Int = 0\n    private var detectedObjectNum = 0\n    private var currentSelectedObjectIndex = 0\n\n    private var detector: ObjectDetector? = null\n    private var searchEngine: SearchEngine? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        searchEngine = SearchEngine(applicationContext)\n\n        setContentView(R.layout.activity_static_object)\n\n        loadingView = findViewById<View>(R.id.loading_view).apply {\n            setOnClickListener(this@StaticObjectDetectionActivity)\n        }\n\n        bottomPromptChip = findViewById(R.id.bottom_prompt_chip)\n        inputImageView = findViewById(R.id.input_image_view)\n\n        previewCardCarousel = findViewById<RecyclerView>(R.id.card_recycler_view).apply {\n            setHasFixedSize(true)\n            layoutManager = LinearLayoutManager(this@StaticObjectDetectionActivity, RecyclerView.HORIZONTAL, false)\n            addItemDecoration(\n                CardItemDecoration(\n                    resources\n                )\n            )\n        }\n\n        dotViewContainer = findViewById(R.id.dot_view_container)\n        dotViewSize = resources.getDimensionPixelOffset(R.dimen.static_image_dot_view_size)\n\n        setUpBottomSheet()\n\n        findViewById<View>(R.id.close_button).setOnClickListener(this)\n        findViewById<View>(R.id.photo_library_button).setOnClickListener(this)\n\n        detector = ObjectDetection.getClient(\n            ObjectDetectorOptions.Builder()\n                .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE)\n                .enableMultipleObjects()\n                .build()\n        )\n        intent.data?.let(::detectObjects)\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        try {\n            detector?.close()\n        } catch (e: IOException) {\n            Log.e(TAG, \"Failed to close the detector!\", e)\n        }\n\n        searchEngine?.shutdown()\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == Utils.REQUEST_CODE_PHOTO_LIBRARY && resultCode == Activity.RESULT_OK) {\n            data?.data?.let(::detectObjects)\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    override fun onBackPressed() {\n        if (bottomSheetBehavior?.state != BottomSheetBehavior.STATE_HIDDEN) {\n            bottomSheetBehavior?.setState(BottomSheetBehavior.STATE_HIDDEN)\n        } else {\n            super.onBackPressed()\n        }\n    }\n\n    override fun onClick(view: View) {\n        when (view.id) {\n            R.id.close_button -> onBackPressed()\n            R.id.photo_library_button -> Utils.openImagePicker(this)\n            R.id.bottom_sheet_scrim_view -> bottomSheetBehavior?.state = BottomSheetBehavior.STATE_HIDDEN\n        }\n    }\n\n    private fun showSearchResults(searchedObject: SearchedObject) {\n        searchedObjectForBottomSheet = searchedObject\n        val productList = searchedObject.productList\n        bottomSheetTitleView?.text = resources\n            .getQuantityString(\n                R.plurals.bottom_sheet_title, productList.size, productList.size\n            )\n        productRecyclerView?.adapter = ProductAdapter(productList)\n        bottomSheetBehavior?.peekHeight = (inputImageView?.parent as View).height / 2\n        bottomSheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED\n    }\n\n    private fun setUpBottomSheet() {\n        bottomSheetBehavior = BottomSheetBehavior.from(findViewById<View>(R.id.bottom_sheet)).apply {\n            setBottomSheetCallback(\n                object : BottomSheetBehavior.BottomSheetCallback() {\n                    override fun onStateChanged(bottomSheet: View, newState: Int) {\n                        Log.d(TAG, \"Bottom sheet new state: $newState\")\n                        bottomSheetScrimView?.visibility =\n                            if (newState == BottomSheetBehavior.STATE_HIDDEN) View.GONE else View.VISIBLE\n                    }\n\n                    override fun onSlide(bottomSheet: View, slideOffset: Float) {\n                        if (java.lang.Float.isNaN(slideOffset)) {\n                            return\n                        }\n\n                        val collapsedStateHeight = bottomSheetBehavior!!.peekHeight.coerceAtMost(bottomSheet.height)\n                        val searchedObjectForBottomSheet = searchedObjectForBottomSheet\n                            ?: return\n                        bottomSheetScrimView?.updateWithThumbnailTranslate(\n                            searchedObjectForBottomSheet.getObjectThumbnail(),\n                            collapsedStateHeight,\n                            slideOffset,\n                            bottomSheet\n                        )\n                    }\n                }\n            )\n            state = BottomSheetBehavior.STATE_HIDDEN\n        }\n\n        bottomSheetScrimView = findViewById<BottomSheetScrimView>(R.id.bottom_sheet_scrim_view).apply {\n            setOnClickListener(this@StaticObjectDetectionActivity)\n        }\n\n        bottomSheetTitleView = findViewById(R.id.bottom_sheet_title)\n        productRecyclerView = findViewById<RecyclerView>(R.id.product_recycler_view)?.apply {\n            setHasFixedSize(true)\n            layoutManager = LinearLayoutManager(this@StaticObjectDetectionActivity)\n            adapter = ProductAdapter(ImmutableList.of())\n        }\n    }\n\n    private fun detectObjects(imageUri: Uri) {\n        inputImageView?.setImageDrawable(null)\n        bottomPromptChip?.visibility = View.GONE\n        previewCardCarousel?.adapter = PreviewCardAdapter(ImmutableList.of()) { showSearchResults(it) }\n        previewCardCarousel?.clearOnScrollListeners()\n        dotViewContainer?.removeAllViews()\n        currentSelectedObjectIndex = 0\n\n        try {\n            inputBitmap = Utils.loadImage(\n                this, imageUri,\n                MAX_IMAGE_DIMENSION\n            )\n        } catch (e: IOException) {\n            Log.e(TAG, \"Failed to load file: $imageUri\", e)\n            showBottomPromptChip(\"Failed to load file!\")\n            return\n        }\n\n        inputImageView?.setImageBitmap(inputBitmap)\n        loadingView?.visibility = View.VISIBLE\n        val image = InputImage.fromBitmap(inputBitmap!!, 0)\n        detector?.process(image)\n            ?.addOnSuccessListener { objects -> onObjectsDetected(BitmapInputInfo(inputBitmap!!), objects) }\n            ?.addOnFailureListener { onObjectsDetected(BitmapInputInfo(inputBitmap!!), ImmutableList.of()) }\n    }\n\n    @MainThread\n    private fun onObjectsDetected(image: InputInfo, objects: List<DetectedObject>) {\n        detectedObjectNum = objects.size\n        Log.d(TAG, \"Detected objects num: $detectedObjectNum\")\n        if (detectedObjectNum == 0) {\n            loadingView?.visibility = View.GONE\n            showBottomPromptChip(getString(R.string.static_image_prompt_detected_no_results))\n        } else {\n            searchedObjectMap.clear()\n            for (i in objects.indices) {\n                searchEngine?.search(DetectedObjectInfo(objects[i], i, image)) { detectedObject, products ->\n                    onSearchCompleted(detectedObject, products)\n                }\n            }\n        }\n    }\n\n    private fun onSearchCompleted(detectedObject: DetectedObjectInfo, productList: List<Product>) {\n        Log.d(TAG, \"Search completed for object index: ${detectedObject.objectIndex}\")\n        searchedObjectMap[detectedObject.objectIndex] = SearchedObject(resources, detectedObject, productList)\n        if (searchedObjectMap.size < detectedObjectNum) {\n            // Hold off showing the result until the search of all detected objects completes.\n            return\n        }\n\n        showBottomPromptChip(getString(R.string.static_image_prompt_detected_results))\n        loadingView?.visibility = View.GONE\n        previewCardCarousel?.adapter =\n            PreviewCardAdapter(ImmutableList.copyOf(searchedObjectMap.values)) { showSearchResults(it) }\n        previewCardCarousel?.addOnScrollListener(\n            object : RecyclerView.OnScrollListener() {\n                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {\n                    Log.d(TAG, \"New card scroll state: $newState\")\n                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {\n                        for (i in 0 until recyclerView.childCount) {\n                            val childView = recyclerView.getChildAt(i)\n                            if (childView.x >= 0) {\n                                val cardIndex = recyclerView.getChildAdapterPosition(childView)\n                                if (cardIndex != currentSelectedObjectIndex) {\n                                    selectNewObject(cardIndex)\n                                }\n                                break\n                            }\n                        }\n                    }\n                }\n            })\n\n        for (searchedObject in searchedObjectMap.values) {\n            val dotView = createDotView(searchedObject)\n            dotView.setOnClickListener {\n                if (searchedObject.objectIndex == currentSelectedObjectIndex) {\n                    showSearchResults(searchedObject)\n                } else {\n                    selectNewObject(searchedObject.objectIndex)\n                    showSearchResults(searchedObject)\n                    previewCardCarousel!!.smoothScrollToPosition(searchedObject.objectIndex)\n                }\n            }\n\n            dotViewContainer?.addView(dotView)\n            val animatorSet = AnimatorInflater.loadAnimator(this, R.animator.static_image_dot_enter) as AnimatorSet\n            animatorSet.setTarget(dotView)\n            animatorSet.start()\n        }\n    }\n\n    private fun createDotView(searchedObject: SearchedObject): StaticObjectDotView {\n        val viewCoordinateScale: Float\n        val horizontalGap: Float\n        val verticalGap: Float\n        val inputImageView = inputImageView ?: throw NullPointerException()\n        val inputBitmap = inputBitmap ?: throw NullPointerException()\n        val inputImageViewRatio = inputImageView.width.toFloat() / inputImageView.height\n        val inputBitmapRatio = inputBitmap.width.toFloat() / inputBitmap.height\n        if (inputBitmapRatio <= inputImageViewRatio) { // Image content fills height\n            viewCoordinateScale = inputImageView.height.toFloat() / inputBitmap.height\n            horizontalGap = (inputImageView.width - inputBitmap.width * viewCoordinateScale) / 2\n            verticalGap = 0f\n        } else { // Image content fills width\n            viewCoordinateScale = inputImageView.width.toFloat() / inputBitmap.width\n            horizontalGap = 0f\n            verticalGap = (inputImageView.height - inputBitmap.height * viewCoordinateScale) / 2\n        }\n\n        val boundingBox = searchedObject.boundingBox\n        val boxInViewCoordinate = RectF(\n            boundingBox.left * viewCoordinateScale + horizontalGap,\n            boundingBox.top * viewCoordinateScale + verticalGap,\n            boundingBox.right * viewCoordinateScale + horizontalGap,\n            boundingBox.bottom * viewCoordinateScale + verticalGap\n        )\n        val initialSelected = searchedObject.objectIndex == 0\n        val dotView = StaticObjectDotView(this, initialSelected)\n        val layoutParams = FrameLayout.LayoutParams(dotViewSize, dotViewSize)\n        val dotCenter = PointF(\n            (boxInViewCoordinate.right + boxInViewCoordinate.left) / 2,\n            (boxInViewCoordinate.bottom + boxInViewCoordinate.top) / 2\n        )\n        layoutParams.setMargins(\n            (dotCenter.x - dotViewSize / 2f).toInt(),\n            (dotCenter.y - dotViewSize / 2f).toInt(),\n            0,\n            0\n        )\n        dotView.layoutParams = layoutParams\n        return dotView\n    }\n\n    private fun selectNewObject(objectIndex: Int) {\n        val dotViewToDeselect = dotViewContainer!!.getChildAt(currentSelectedObjectIndex) as StaticObjectDotView\n        dotViewToDeselect.playAnimationWithSelectedState(false)\n\n        currentSelectedObjectIndex = objectIndex\n\n        val selectedDotView = dotViewContainer!!.getChildAt(currentSelectedObjectIndex) as StaticObjectDotView\n        selectedDotView.playAnimationWithSelectedState(true)\n    }\n\n    private fun showBottomPromptChip(message: String) {\n        bottomPromptChip?.visibility = View.VISIBLE\n        bottomPromptChip?.text = message\n    }\n\n    private class CardItemDecoration constructor(resources: Resources) : RecyclerView.ItemDecoration() {\n\n        private val cardSpacing: Int = resources.getDimensionPixelOffset(R.dimen.preview_card_spacing)\n\n        override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {\n            val adapterPosition = parent.getChildAdapterPosition(view)\n            outRect.left = if (adapterPosition == 0) cardSpacing * 2 else cardSpacing\n            val adapter = parent.adapter ?: return\n            if (adapterPosition == adapter.itemCount - 1) {\n                outRect.right = cardSpacing\n            }\n        }\n    }\n\n    companion object {\n        private const val TAG = \"StaticObjectActivity\"\n        private const val MAX_IMAGE_DIMENSION = 1024\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/TaskExt.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md\n\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.OnCanceledListener\nimport com.google.android.gms.tasks.OnCompleteListener\nimport com.google.android.gms.tasks.OnFailureListener\nimport com.google.android.gms.tasks.OnSuccessListener\nimport java.util.concurrent.Executor\n\n/**\n * Quality-of-life helper to allow using trailing lambda syntax for adding a success listener to a\n * [Task].\n */\nfun <TResult> Task<TResult>.addOnSuccessListener(executor: Executor,\n                                                 listener: (TResult) -> Unit): Task<TResult> {\n    return addOnSuccessListener(executor, OnSuccessListener(listener))\n}\n\n/**\n * Quality-of-life helper to allow using trailing lambda syntax for adding a failure listener to a\n * [Task].\n */\nfun <TResult> Task<TResult>.addOnFailureListener(executor: Executor,\n                                                 listener: (Exception) -> Unit): Task<TResult> {\n    return addOnFailureListener(executor, OnFailureListener(listener))\n}\n\n/**\n * Quality-of-life helper to allow using trailing lambda syntax for adding a completion listener to\n * a [Task].\n */\nfun <TResult> Task<TResult>.addOnCompleteListener(executor: Executor,\n                                                  listener: (Task<TResult>) -> Unit): Task<TResult> {\n    return addOnCompleteListener(executor, OnCompleteListener(listener))\n}\n\n/**\n * Quality-of-life helper to allow using trailing lambda syntax for adding a cancellation listener\n * to a [Task].\n */\nfun <TResult> Task<TResult>.addOnCanceledListener(executor: Executor,\n                                                  listener: () -> Unit): Task<TResult> {\n    return addOnCanceledListener(executor, OnCanceledListener(listener))\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/Utils.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md\n\nimport android.app.Activity\nimport android.content.ContentResolver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.content.res.Configuration\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.graphics.Canvas\nimport android.graphics.Matrix\nimport android.graphics.Paint\nimport android.graphics.PorterDuff\nimport android.graphics.PorterDuffXfermode\nimport android.graphics.Rect\nimport android.graphics.RectF\nimport android.graphics.YuvImage\nimport android.hardware.Camera\nimport android.net.Uri\nimport android.util.Log\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat.checkSelfPermission\nimport androidx.exifinterface.media.ExifInterface\nimport com.google.mlkit.md.camera.CameraSizePair\nimport com.google.mlkit.vision.common.InputImage\nimport java.io.ByteArrayOutputStream\nimport java.io.IOException\nimport java.io.InputStream\nimport java.nio.ByteBuffer\nimport java.util.ArrayList\nimport kotlin.math.abs\n\n/** Utility class to provide helper methods.  */\nobject Utils {\n\n    /**\n     * If the absolute difference between aspect ratios is less than this tolerance, they are\n     * considered to be the same aspect ratio.\n     */\n    const val ASPECT_RATIO_TOLERANCE = 0.01f\n\n    internal const val REQUEST_CODE_PHOTO_LIBRARY = 1\n\n    private const val TAG = \"Utils\"\n\n    internal fun requestRuntimePermissions(activity: Activity) {\n\n        val allNeededPermissions = getRequiredPermissions(activity).filter {\n            checkSelfPermission(activity, it) != PackageManager.PERMISSION_GRANTED\n        }\n\n        if (allNeededPermissions.isNotEmpty()) {\n            ActivityCompat.requestPermissions(\n                activity, allNeededPermissions.toTypedArray(), /* requestCode= */ 0\n            )\n        }\n    }\n\n    internal fun allPermissionsGranted(context: Context): Boolean = getRequiredPermissions(\n        context\n    )\n        .all { checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED }\n\n    private fun getRequiredPermissions(context: Context): Array<String> {\n        return try {\n            val info = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)\n            val ps = info.requestedPermissions\n            if (ps != null && ps.isNotEmpty()) ps else arrayOf()\n        } catch (e: Exception) {\n            arrayOf()\n        }\n    }\n\n    fun isPortraitMode(context: Context): Boolean =\n        context.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT\n\n    /**\n     * Generates a list of acceptable preview sizes. Preview sizes are not acceptable if there is not\n     * a corresponding picture size of the same aspect ratio. If there is a corresponding picture size\n     * of the same aspect ratio, the picture size is paired up with the preview size.\n     *\n     *\n     * This is necessary because even if we don't use still pictures, the still picture size must\n     * be set to a size that is the same aspect ratio as the preview size we choose. Otherwise, the\n     * preview images may be distorted on some devices.\n     */\n    fun generateValidPreviewSizeList(camera: Camera): List<CameraSizePair> {\n        val parameters = camera.parameters\n        val supportedPreviewSizes = parameters.supportedPreviewSizes\n        val supportedPictureSizes = parameters.supportedPictureSizes\n        val validPreviewSizes = ArrayList<CameraSizePair>()\n        for (previewSize in supportedPreviewSizes) {\n            val previewAspectRatio = previewSize.width.toFloat() / previewSize.height.toFloat()\n\n            // By looping through the picture sizes in order, we favor the higher resolutions.\n            // We choose the highest resolution in order to support taking the full resolution\n            // picture later.\n            for (pictureSize in supportedPictureSizes) {\n                val pictureAspectRatio = pictureSize.width.toFloat() / pictureSize.height.toFloat()\n                if (abs(previewAspectRatio - pictureAspectRatio) < ASPECT_RATIO_TOLERANCE) {\n                    validPreviewSizes.add(CameraSizePair(previewSize, pictureSize))\n                    break\n                }\n            }\n        }\n\n        // If there are no picture sizes with the same aspect ratio as any preview sizes, allow all of\n        // the preview sizes and hope that the camera can handle it.  Probably unlikely, but we still\n        // account for it.\n        if (validPreviewSizes.isEmpty()) {\n            Log.w(TAG, \"No preview sizes have a corresponding same-aspect-ratio picture size.\")\n            for (previewSize in supportedPreviewSizes) {\n                // The null picture size will let us know that we shouldn't set a picture size.\n                validPreviewSizes.add(CameraSizePair(previewSize, null))\n            }\n        }\n\n        return validPreviewSizes\n    }\n\n    fun getCornerRoundedBitmap(srcBitmap: Bitmap, cornerRadius: Int): Bitmap {\n        val dstBitmap = Bitmap.createBitmap(srcBitmap.width, srcBitmap.height, Bitmap.Config.ARGB_8888)\n        val canvas = Canvas(dstBitmap)\n        val paint = Paint()\n        paint.isAntiAlias = true\n        val rectF = RectF(0f, 0f, srcBitmap.width.toFloat(), srcBitmap.height.toFloat())\n        canvas.drawRoundRect(rectF, cornerRadius.toFloat(), cornerRadius.toFloat(), paint)\n        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)\n        canvas.drawBitmap(srcBitmap, 0f, 0f, paint)\n        return dstBitmap\n    }\n\n    /** Convert NV21 format byte buffer to bitmap. */\n    fun convertToBitmap(data: ByteBuffer, width: Int, height: Int, rotationDegrees: Int): Bitmap? {\n        data.rewind()\n        val imageInBuffer = ByteArray(data.limit())\n        data.get(imageInBuffer, 0, imageInBuffer.size)\n        try {\n            val image = YuvImage(\n                imageInBuffer, InputImage.IMAGE_FORMAT_NV21, width, height, null\n            )\n            val stream = ByteArrayOutputStream()\n            image.compressToJpeg(Rect(0, 0, width, height), 80, stream)\n            val bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size())\n            stream.close()\n\n            // Rotate the image back to straight.\n            val matrix = Matrix()\n            matrix.postRotate(rotationDegrees.toFloat())\n            return Bitmap.createBitmap(bmp, 0, 0, bmp.width, bmp.height, matrix, true)\n        } catch (e: java.lang.Exception) {\n            Log.e(TAG, \"Error: \" + e.message)\n        }\n        return null\n    }\n\n    internal fun openImagePicker(activity: Activity) {\n        val intent = Intent(Intent.ACTION_GET_CONTENT)\n        intent.addCategory(Intent.CATEGORY_OPENABLE)\n        intent.type = \"image/*\"\n        activity.startActivityForResult(intent, REQUEST_CODE_PHOTO_LIBRARY)\n    }\n\n    @Throws(IOException::class)\n    internal fun loadImage(context: Context, imageUri: Uri, maxImageDimension: Int): Bitmap? {\n        var inputStreamForSize: InputStream? = null\n        var inputStreamForImage: InputStream? = null\n        try {\n            inputStreamForSize = context.contentResolver.openInputStream(imageUri)\n            var opts = BitmapFactory.Options()\n            opts.inJustDecodeBounds = true\n            BitmapFactory.decodeStream(inputStreamForSize, null, opts)/* outPadding= */\n            val inSampleSize = Math.max(opts.outWidth / maxImageDimension, opts.outHeight / maxImageDimension)\n\n            opts = BitmapFactory.Options()\n            opts.inSampleSize = inSampleSize\n            inputStreamForImage = context.contentResolver.openInputStream(imageUri)\n            val decodedBitmap = BitmapFactory.decodeStream(inputStreamForImage, null, opts)/* outPadding= */\n            return maybeTransformBitmap(\n                context.contentResolver,\n                imageUri,\n                decodedBitmap\n            )\n        } finally {\n            inputStreamForSize?.close()\n            inputStreamForImage?.close()\n        }\n    }\n\n    private fun maybeTransformBitmap(resolver: ContentResolver, uri: Uri, bitmap: Bitmap?): Bitmap? {\n        val matrix: Matrix? = when (getExifOrientationTag(resolver, uri)) {\n            ExifInterface.ORIENTATION_UNDEFINED, ExifInterface.ORIENTATION_NORMAL ->\n                // Set the matrix to be null to skip the image transform.\n                null\n            ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> Matrix().apply { postScale(-1.0f, 1.0f) }\n\n            ExifInterface.ORIENTATION_ROTATE_90 -> Matrix().apply { postRotate(90f) }\n            ExifInterface.ORIENTATION_TRANSPOSE -> Matrix().apply { postScale(-1.0f, 1.0f) }\n            ExifInterface.ORIENTATION_ROTATE_180 -> Matrix().apply { postRotate(180.0f) }\n            ExifInterface.ORIENTATION_FLIP_VERTICAL -> Matrix().apply { postScale(1.0f, -1.0f) }\n            ExifInterface.ORIENTATION_ROTATE_270 -> Matrix().apply { postRotate(-90.0f) }\n            ExifInterface.ORIENTATION_TRANSVERSE -> Matrix().apply {\n                postRotate(-90.0f)\n                postScale(-1.0f, 1.0f)\n            }\n            else ->\n                // Set the matrix to be null to skip the image transform.\n                null\n        }\n\n        return if (matrix != null) {\n            Bitmap.createBitmap(bitmap!!, 0, 0, bitmap.width, bitmap.height, matrix, true)\n        } else {\n            bitmap\n        }\n    }\n\n    private fun getExifOrientationTag(resolver: ContentResolver, imageUri: Uri): Int {\n        if (ContentResolver.SCHEME_CONTENT != imageUri.scheme && ContentResolver.SCHEME_FILE != imageUri.scheme) {\n            return 0\n        }\n\n        var exif: ExifInterface? = null\n        try {\n            resolver.openInputStream(imageUri)?.use { inputStream -> exif = ExifInterface(inputStream) }\n        } catch (e: IOException) {\n            Log.e(TAG, \"Failed to open file to read rotation meta data: $imageUri\", e)\n        }\n\n        return if (exif != null) {\n            exif!!.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)\n        } else {\n            ExifInterface.ORIENTATION_UNDEFINED\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/barcodedetection/BarcodeConfirmingGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.barcodedetection\n\nimport android.graphics.Canvas\nimport android.graphics.Path\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.settings.PreferenceUtils\nimport com.google.mlkit.vision.barcode.common.Barcode\n\n/** Guides user to move camera closer to confirm the detected barcode.  */\ninternal class BarcodeConfirmingGraphic(overlay: GraphicOverlay, private val barcode: Barcode) :\n    BarcodeGraphicBase(overlay) {\n\n    override fun draw(canvas: Canvas) {\n        super.draw(canvas)\n\n        // Draws a highlighted path to indicate the current progress to meet size requirement.\n        val sizeProgress = PreferenceUtils.getProgressToMeetBarcodeSizeRequirement(overlay, barcode)\n        val path = Path()\n        if (sizeProgress > 0.95f) {\n            // To have a completed path with all corners rounded.\n            path.moveTo(boxRect.left, boxRect.top)\n            path.lineTo(boxRect.right, boxRect.top)\n            path.lineTo(boxRect.right, boxRect.bottom)\n            path.lineTo(boxRect.left, boxRect.bottom)\n            path.close()\n        } else {\n            path.moveTo(boxRect.left, boxRect.top + boxRect.height() * sizeProgress)\n            path.lineTo(boxRect.left, boxRect.top)\n            path.lineTo(boxRect.left + boxRect.width() * sizeProgress, boxRect.top)\n\n            path.moveTo(boxRect.right, boxRect.bottom - boxRect.height() * sizeProgress)\n            path.lineTo(boxRect.right, boxRect.bottom)\n            path.lineTo(boxRect.right - boxRect.width() * sizeProgress, boxRect.bottom)\n        }\n        canvas.drawPath(path, pathPaint)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/barcodedetection/BarcodeField.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.barcodedetection\n\nimport android.os.Parcelable\nimport kotlinx.android.parcel.Parcelize\n\n/** Information about a barcode field.  */\n@Parcelize\ndata class BarcodeField(val label: String, val value: String) : Parcelable\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/barcodedetection/BarcodeFieldAdapter.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.barcodedetection\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.barcodedetection.BarcodeFieldAdapter.BarcodeFieldViewHolder\n\n/** Presents a list of field info in the detected barcode.  */\ninternal class BarcodeFieldAdapter(private val barcodeFieldList: List<BarcodeField>) :\n    RecyclerView.Adapter<BarcodeFieldViewHolder>() {\n\n    internal class BarcodeFieldViewHolder private constructor(view: View) : RecyclerView.ViewHolder(view) {\n\n        private val labelView: TextView = view.findViewById(R.id.barcode_field_label)\n        private val valueView: TextView = view.findViewById(R.id.barcode_field_value)\n\n        fun bindBarcodeField(barcodeField: BarcodeField) {\n            labelView.text = barcodeField.label\n            valueView.text = barcodeField.value\n        }\n\n        companion object {\n\n            fun create(parent: ViewGroup): BarcodeFieldViewHolder {\n                val view = LayoutInflater.from(parent.context).inflate(R.layout.barcode_field, parent, false)\n                return BarcodeFieldViewHolder(view)\n            }\n        }\n    }\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BarcodeFieldViewHolder =\n        BarcodeFieldViewHolder.create(parent)\n\n    override fun onBindViewHolder(holder: BarcodeFieldViewHolder, position: Int) =\n        holder.bindBarcodeField(barcodeFieldList[position])\n\n    override fun getItemCount(): Int =\n        barcodeFieldList.size\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/barcodedetection/BarcodeGraphicBase.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.barcodedetection\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.CornerPathEffect\nimport android.graphics.Paint\nimport android.graphics.Paint.Style\nimport android.graphics.PorterDuff\nimport android.graphics.PorterDuffXfermode\nimport android.graphics.RectF\nimport androidx.core.content.ContextCompat\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.GraphicOverlay.Graphic\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.settings.PreferenceUtils\n\ninternal abstract class BarcodeGraphicBase(overlay: GraphicOverlay) : Graphic(overlay) {\n\n    private val boxPaint: Paint = Paint().apply {\n        color = ContextCompat.getColor(context, R.color.barcode_reticle_stroke)\n        style = Style.STROKE\n        strokeWidth = context.resources.getDimensionPixelOffset(R.dimen.barcode_reticle_stroke_width).toFloat()\n    }\n\n    private val scrimPaint: Paint = Paint().apply {\n        color = ContextCompat.getColor(context, R.color.barcode_reticle_background)\n    }\n\n    private val eraserPaint: Paint = Paint().apply {\n        strokeWidth = boxPaint.strokeWidth\n        xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)\n    }\n\n    val boxCornerRadius: Float =\n        context.resources.getDimensionPixelOffset(R.dimen.barcode_reticle_corner_radius).toFloat()\n\n    val pathPaint: Paint = Paint().apply {\n        color = Color.WHITE\n        style = Style.STROKE\n        strokeWidth = boxPaint.strokeWidth\n        pathEffect = CornerPathEffect(boxCornerRadius)\n    }\n\n    val boxRect: RectF = PreferenceUtils.getBarcodeReticleBox(overlay)\n\n    override fun draw(canvas: Canvas) {\n        // Draws the dark background scrim and leaves the box area clear.\n        canvas.drawRect(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat(), scrimPaint)\n        // As the stroke is always centered, so erase twice with FILL and STROKE respectively to clear\n        // all area that the box rect would occupy.\n        eraserPaint.style = Style.FILL\n        canvas.drawRoundRect(boxRect, boxCornerRadius, boxCornerRadius, eraserPaint)\n        eraserPaint.style = Style.STROKE\n        canvas.drawRoundRect(boxRect, boxCornerRadius, boxCornerRadius, eraserPaint)\n        // Draws the box.\n        canvas.drawRoundRect(boxRect, boxCornerRadius, boxCornerRadius, boxPaint)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/barcodedetection/BarcodeLoadingGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.barcodedetection\n\nimport android.animation.ValueAnimator\nimport android.graphics.Canvas\nimport android.graphics.Path\nimport android.graphics.Point\nimport android.graphics.PointF\nimport com.google.mlkit.md.camera.GraphicOverlay\n\n/** Draws the graphic to indicate the barcode result is in loading.  */\ninternal class BarcodeLoadingGraphic(overlay: GraphicOverlay, private val loadingAnimator: ValueAnimator) :\n    BarcodeGraphicBase(overlay) {\n\n    private val boxClockwiseCoordinates: Array<PointF> = arrayOf(\n        PointF(boxRect.left, boxRect.top),\n        PointF(boxRect.right, boxRect.top),\n        PointF(boxRect.right, boxRect.bottom),\n        PointF(boxRect.left, boxRect.bottom)\n    )\n    private val coordinateOffsetBits: Array<Point> = arrayOf(\n        Point(1, 0),\n        Point(0, 1),\n        Point(-1, 0),\n        Point(0, -1)\n    )\n    private val lastPathPoint = PointF()\n\n    override fun draw(canvas: Canvas) {\n        super.draw(canvas)\n\n        val boxPerimeter = (boxRect.width() + boxRect.height()) * 2\n        val path = Path()\n        // The distance between the box's left-top corner and the starting point of white colored path.\n        var offsetLen = boxPerimeter * loadingAnimator.animatedValue as Float % boxPerimeter\n        var i = 0\n        while (i < 4) {\n            val edgeLen = if (i % 2 == 0) boxRect.width() else boxRect.height()\n            if (offsetLen <= edgeLen) {\n                lastPathPoint.x = boxClockwiseCoordinates[i].x + coordinateOffsetBits[i].x * offsetLen\n                lastPathPoint.y = boxClockwiseCoordinates[i].y + coordinateOffsetBits[i].y * offsetLen\n                path.moveTo(lastPathPoint.x, lastPathPoint.y)\n                break\n            }\n\n            offsetLen -= edgeLen\n            i++\n        }\n\n        // Computes the path based on the determined starting point and path length.\n        var pathLen = boxPerimeter * 0.3f\n        for (j in 0..3) {\n            val index = (i + j) % 4\n            val nextIndex = (i + j + 1) % 4\n            // The length between path's current end point and reticle box's next coordinate point.\n            val lineLen = Math.abs(boxClockwiseCoordinates[nextIndex].x - lastPathPoint.x) +\n                    Math.abs(boxClockwiseCoordinates[nextIndex].y - lastPathPoint.y)\n            if (lineLen >= pathLen) {\n                path.lineTo(\n                    lastPathPoint.x + pathLen * coordinateOffsetBits[index].x,\n                    lastPathPoint.y + pathLen * coordinateOffsetBits[index].y\n                )\n                break\n            }\n\n            lastPathPoint.x = boxClockwiseCoordinates[nextIndex].x\n            lastPathPoint.y = boxClockwiseCoordinates[nextIndex].y\n            path.lineTo(lastPathPoint.x, lastPathPoint.y)\n            pathLen -= lineLen\n        }\n\n        canvas.drawPath(path, pathPaint)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/barcodedetection/BarcodeProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.barcodedetection\n\nimport android.animation.ValueAnimator\nimport android.util.Log\nimport androidx.annotation.MainThread\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.md.InputInfo\nimport com.google.mlkit.md.camera.CameraReticleAnimator\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.WorkflowModel\nimport com.google.mlkit.md.camera.WorkflowModel.WorkflowState\nimport com.google.mlkit.md.camera.FrameProcessorBase\nimport com.google.mlkit.md.settings.PreferenceUtils\nimport com.google.mlkit.vision.barcode.BarcodeScanning\nimport com.google.mlkit.vision.barcode.common.Barcode\nimport com.google.mlkit.vision.common.InputImage\nimport java.io.IOException\n\n/** A processor to run the barcode detector.  */\nclass BarcodeProcessor(graphicOverlay: GraphicOverlay, private val workflowModel: WorkflowModel) :\n    FrameProcessorBase<List<Barcode>>() {\n\n    private val scanner = BarcodeScanning.getClient()\n    private val cameraReticleAnimator: CameraReticleAnimator = CameraReticleAnimator(graphicOverlay)\n\n    override fun detectInImage(image: InputImage): Task<List<Barcode>> =\n        scanner.process(image)\n\n    @MainThread\n    override fun onSuccess(\n        inputInfo: InputInfo,\n        results: List<Barcode>,\n        graphicOverlay: GraphicOverlay\n    ) {\n\n        if (!workflowModel.isCameraLive) return\n\n        Log.d(TAG, \"Barcode result size: ${results.size}\")\n\n        // Picks the barcode, if exists, that covers the center of graphic overlay.\n\n        val barcodeInCenter = results.firstOrNull { barcode ->\n            val boundingBox = barcode.boundingBox ?: return@firstOrNull false\n            val box = graphicOverlay.translateRect(boundingBox)\n            box.contains(graphicOverlay.width / 2f, graphicOverlay.height / 2f)\n        }\n\n        graphicOverlay.clear()\n        if (barcodeInCenter == null) {\n            cameraReticleAnimator.start()\n            graphicOverlay.add(BarcodeReticleGraphic(graphicOverlay, cameraReticleAnimator))\n            workflowModel.setWorkflowState(WorkflowState.DETECTING)\n        } else {\n            cameraReticleAnimator.cancel()\n            val sizeProgress = PreferenceUtils.getProgressToMeetBarcodeSizeRequirement(graphicOverlay, barcodeInCenter)\n            if (sizeProgress < 1) {\n                // Barcode in the camera view is too small, so prompt user to move camera closer.\n                graphicOverlay.add(BarcodeConfirmingGraphic(graphicOverlay, barcodeInCenter))\n                workflowModel.setWorkflowState(WorkflowState.CONFIRMING)\n            } else {\n                // Barcode size in the camera view is sufficient.\n                if (PreferenceUtils.shouldDelayLoadingBarcodeResult(graphicOverlay.context)) {\n                    val loadingAnimator = createLoadingAnimator(graphicOverlay, barcodeInCenter)\n                    loadingAnimator.start()\n                    graphicOverlay.add(BarcodeLoadingGraphic(graphicOverlay, loadingAnimator))\n                    workflowModel.setWorkflowState(WorkflowState.SEARCHING)\n                } else {\n                    workflowModel.setWorkflowState(WorkflowState.DETECTED)\n                    workflowModel.detectedBarcode.setValue(barcodeInCenter)\n                }\n            }\n        }\n        graphicOverlay.invalidate()\n    }\n\n    private fun createLoadingAnimator(graphicOverlay: GraphicOverlay, barcode: Barcode): ValueAnimator {\n        val endProgress = 1.1f\n        return ValueAnimator.ofFloat(0f, endProgress).apply {\n            duration = 2000\n            addUpdateListener {\n                if ((animatedValue as Float).compareTo(endProgress) >= 0) {\n                    graphicOverlay.clear()\n                    workflowModel.setWorkflowState(WorkflowState.SEARCHED)\n                    workflowModel.detectedBarcode.setValue(barcode)\n                } else {\n                    graphicOverlay.invalidate()\n                }\n            }\n        }\n    }\n\n    override fun onFailure(e: Exception) {\n        Log.e(TAG, \"Barcode detection failed!\", e)\n    }\n\n    override fun stop() {\n        super.stop()\n        try {\n            scanner.close()\n        } catch (e: IOException) {\n            Log.e(TAG, \"Failed to close barcode detector!\", e)\n        }\n    }\n\n    companion object {\n        private const val TAG = \"BarcodeProcessor\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/barcodedetection/BarcodeResultFragment.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.barcodedetection\n\nimport android.content.DialogInterface\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.fragment.app.FragmentManager\nimport androidx.lifecycle.ViewModelProviders\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.bottomsheet.BottomSheetDialogFragment\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.camera.WorkflowModel\nimport com.google.mlkit.md.camera.WorkflowModel.WorkflowState\n\n/** Displays the bottom sheet to present barcode fields contained in the detected barcode.  */\nclass BarcodeResultFragment : BottomSheetDialogFragment() {\n\n    override fun onCreateView(\n        layoutInflater: LayoutInflater,\n        viewGroup: ViewGroup?,\n        bundle: Bundle?\n    ): View {\n        val view = layoutInflater.inflate(R.layout.barcode_bottom_sheet, viewGroup)\n\n        val arguments = arguments\n        val barcodeFieldList: ArrayList<BarcodeField> =\n            if (arguments?.containsKey(ARG_BARCODE_FIELD_LIST) == true) {\n                arguments.getParcelableArrayList(ARG_BARCODE_FIELD_LIST) ?: ArrayList()\n            } else {\n                Log.e(TAG, \"No barcode field list passed in!\")\n                ArrayList()\n            }\n\n        view.findViewById<RecyclerView>(R.id.barcode_field_recycler_view).apply {\n            setHasFixedSize(true)\n            layoutManager = LinearLayoutManager(activity)\n            adapter = BarcodeFieldAdapter(barcodeFieldList)\n        }\n\n        return view\n    }\n\n    override fun onDismiss(dialogInterface: DialogInterface) {\n        activity?.let {\n            // Back to working state after the bottom sheet is dismissed.\n            ViewModelProviders.of(it).get(WorkflowModel::class.java).setWorkflowState(WorkflowState.DETECTING)\n        }\n        super.onDismiss(dialogInterface)\n    }\n\n    companion object {\n\n        private const val TAG = \"BarcodeResultFragment\"\n        private const val ARG_BARCODE_FIELD_LIST = \"arg_barcode_field_list\"\n\n        fun show(fragmentManager: FragmentManager, barcodeFieldArrayList: ArrayList<BarcodeField>) {\n            val barcodeResultFragment = BarcodeResultFragment()\n            barcodeResultFragment.arguments = Bundle().apply {\n                putParcelableArrayList(ARG_BARCODE_FIELD_LIST, barcodeFieldArrayList)\n            }\n            barcodeResultFragment.show(fragmentManager, TAG)\n        }\n\n        fun dismiss(fragmentManager: FragmentManager) {\n            (fragmentManager.findFragmentByTag(TAG) as BarcodeResultFragment?)?.dismiss()\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/barcodedetection/BarcodeReticleGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.barcodedetection\n\nimport android.graphics.Canvas\nimport android.graphics.Paint\nimport android.graphics.Paint.Style\nimport android.graphics.RectF\nimport androidx.core.content.ContextCompat\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.camera.CameraReticleAnimator\n\n/**\n * A camera reticle that locates at the center of canvas to indicate the system is active but has\n * not detected a barcode yet.\n */\ninternal class BarcodeReticleGraphic(overlay: GraphicOverlay, private val animator: CameraReticleAnimator) :\n    BarcodeGraphicBase(overlay) {\n\n    private val ripplePaint: Paint\n    private val rippleSizeOffset: Int\n    private val rippleStrokeWidth: Int\n    private val rippleAlpha: Int\n\n    init {\n        val resources = overlay.resources\n        ripplePaint = Paint()\n        ripplePaint.style = Style.STROKE\n        ripplePaint.color = ContextCompat.getColor(context, R.color.reticle_ripple)\n        rippleSizeOffset = resources.getDimensionPixelOffset(R.dimen.barcode_reticle_ripple_size_offset)\n        rippleStrokeWidth = resources.getDimensionPixelOffset(R.dimen.barcode_reticle_ripple_stroke_width)\n        rippleAlpha = ripplePaint.alpha\n    }\n\n    override fun draw(canvas: Canvas) {\n        super.draw(canvas)\n        // Draws the ripple to simulate the breathing animation effect.\n        ripplePaint.alpha = (rippleAlpha * animator.rippleAlphaScale).toInt()\n        ripplePaint.strokeWidth = rippleStrokeWidth * animator.rippleStrokeWidthScale\n        val offset = rippleSizeOffset * animator.rippleSizeScale\n        val rippleRect = RectF(\n            boxRect.left - offset,\n            boxRect.top - offset,\n            boxRect.right + offset,\n            boxRect.bottom + offset\n        )\n        canvas.drawRoundRect(rippleRect, boxCornerRadius, boxCornerRadius, ripplePaint)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/CameraReticleAnimator.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\nimport android.animation.AnimatorSet\nimport android.animation.ValueAnimator\nimport androidx.interpolator.view.animation.FastOutSlowInInterpolator\n\n/** Custom animator for the object or barcode reticle in live camera.  */\nclass CameraReticleAnimator(graphicOverlay: GraphicOverlay) {\n\n    /** Returns the scale value of ripple alpha ranges in [0, 1].  */\n    var rippleAlphaScale = 0f\n        private set\n\n    /** Returns the scale value of ripple size ranges in [0, 1].  */\n    var rippleSizeScale = 0f\n        private set\n\n    /** Returns the scale value of ripple stroke width ranges in [0, 1].  */\n    var rippleStrokeWidthScale = 1f\n        private set\n\n    private val animatorSet: AnimatorSet\n\n    init {\n        val rippleFadeInAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(DURATION_RIPPLE_FADE_IN_MS)\n        rippleFadeInAnimator.addUpdateListener { animation ->\n            rippleAlphaScale = animation.animatedValue as Float\n            graphicOverlay.postInvalidate()\n        }\n\n        val rippleFadeOutAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(DURATION_RIPPLE_FADE_OUT_MS)\n        rippleFadeOutAnimator.startDelay = START_DELAY_RIPPLE_FADE_OUT_MS\n        rippleFadeOutAnimator.addUpdateListener { animation ->\n            rippleAlphaScale = animation.animatedValue as Float\n            graphicOverlay.postInvalidate()\n        }\n\n        val rippleExpandAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(DURATION_RIPPLE_EXPAND_MS)\n        rippleExpandAnimator.startDelay = START_DELAY_RIPPLE_EXPAND_MS\n        rippleExpandAnimator.interpolator = FastOutSlowInInterpolator()\n        rippleExpandAnimator.addUpdateListener { animation ->\n            rippleSizeScale = animation.animatedValue as Float\n            graphicOverlay.postInvalidate()\n        }\n\n        val rippleStrokeWidthShrinkAnimator =\n            ValueAnimator.ofFloat(1f, 0.5f).setDuration(DURATION_RIPPLE_STROKE_WIDTH_SHRINK_MS)\n        rippleStrokeWidthShrinkAnimator.startDelay = START_DELAY_RIPPLE_STROKE_WIDTH_SHRINK_MS\n        rippleStrokeWidthShrinkAnimator.interpolator = FastOutSlowInInterpolator()\n        rippleStrokeWidthShrinkAnimator.addUpdateListener { animation ->\n            rippleStrokeWidthScale = animation.animatedValue as Float\n            graphicOverlay.postInvalidate()\n        }\n\n        val fakeAnimatorForRestartDelay = ValueAnimator.ofInt(0, 0).setDuration(DURATION_RESTART_DORMANCY_MS)\n        fakeAnimatorForRestartDelay.startDelay = START_DELAY_RESTART_DORMANCY_MS\n        animatorSet = AnimatorSet()\n        animatorSet.playTogether(\n            rippleFadeInAnimator,\n            rippleFadeOutAnimator,\n            rippleExpandAnimator,\n            rippleStrokeWidthShrinkAnimator,\n            fakeAnimatorForRestartDelay\n        )\n    }\n\n    fun start() {\n        if (!animatorSet.isRunning) animatorSet.start()\n    }\n\n    fun cancel() {\n        animatorSet.cancel()\n        rippleAlphaScale = 0f\n        rippleSizeScale = 0f\n        rippleStrokeWidthScale = 1f\n    }\n\n    companion object {\n\n        private const val DURATION_RIPPLE_FADE_IN_MS: Long = 333\n        private const val DURATION_RIPPLE_FADE_OUT_MS: Long = 500\n        private const val DURATION_RIPPLE_EXPAND_MS: Long = 833\n        private const val DURATION_RIPPLE_STROKE_WIDTH_SHRINK_MS: Long = 833\n        private const val DURATION_RESTART_DORMANCY_MS: Long = 1333\n        private const val START_DELAY_RIPPLE_FADE_OUT_MS: Long = 667\n        private const val START_DELAY_RIPPLE_EXPAND_MS: Long = 333\n        private const val START_DELAY_RIPPLE_STROKE_WIDTH_SHRINK_MS: Long = 333\n        private const val START_DELAY_RESTART_DORMANCY_MS: Long = 1167\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/CameraSizePair.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\nimport android.hardware.Camera\nimport com.google.android.gms.common.images.Size\n\n/**\n * Stores a preview size and a corresponding same-aspect-ratio picture size. To avoid distorted\n * preview images on some devices, the picture size must be set to a size that is the same aspect\n * ratio as the preview size or the preview may end up being distorted. If the picture size is null,\n * then there is no picture size with the same aspect ratio as the preview size.\n */\nclass CameraSizePair {\n    val preview: Size\n    val picture: Size?\n\n    constructor(previewSize: Camera.Size, pictureSize: Camera.Size?) {\n        preview = Size(previewSize.width, previewSize.height)\n        picture = pictureSize?.let { Size(it.width, it.height) }\n    }\n\n    constructor(previewSize: Size, pictureSize: Size?) {\n        preview = previewSize\n        picture = pictureSize\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/CameraSource.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\nimport android.content.Context\nimport android.graphics.ImageFormat\nimport android.hardware.Camera\nimport android.hardware.Camera.CameraInfo\nimport android.hardware.Camera.Parameters\nimport android.util.Log\nimport android.view.Surface\nimport android.view.SurfaceHolder\nimport android.view.WindowManager\nimport com.google.android.gms.common.images.Size\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.Utils\nimport com.google.mlkit.md.settings.PreferenceUtils\nimport java.io.IOException\nimport java.nio.ByteBuffer\nimport java.util.IdentityHashMap\nimport kotlin.math.abs\nimport kotlin.math.ceil\n\n/**\n * Manages the camera and allows UI updates on top of it (e.g. overlaying extra Graphics). This\n * receives preview frames from the camera at a specified rate, sends those frames to detector as\n * fast as it is able to process.\n *\n *\n * This camera source makes a best effort to manage processing on preview frames as fast as\n * possible, while at the same time minimizing lag. As such, frames may be dropped if the detector\n * is unable to keep up with the rate of frames generated by the camera.\n */\n@Suppress(\"DEPRECATION\")\nclass CameraSource(private val graphicOverlay: GraphicOverlay) {\n\n    private var camera: Camera? = null\n    private var rotationDegrees: Int = 0\n\n    /** Returns the preview size that is currently in use by the underlying camera.  */\n    internal var previewSize: Size? = null\n        private set\n\n    /**\n     * Dedicated thread and associated runnable for calling into the detector with frames, as the\n     * frames become available from the camera.\n     */\n    private var processingThread: Thread? = null\n    private val processingRunnable = FrameProcessingRunnable()\n\n    private val processorLock = Object()\n    private var frameProcessor: FrameProcessor? = null\n\n    /**\n     * Map to convert between a byte array, received from the camera, and its associated byte buffer.\n     * We use byte buffers internally because this is a more efficient way to call into native code\n     * later (avoids a potential copy).\n     *\n     *\n     * **Note:** uses IdentityHashMap here instead of HashMap because the behavior of an array's\n     * equals, hashCode and toString methods is both useless and unexpected. IdentityHashMap enforces\n     * identity ('==') check on the keys.\n     */\n    private val bytesToByteBuffer = IdentityHashMap<ByteArray, ByteBuffer>()\n    private val context: Context = graphicOverlay.context\n\n    /**\n     * Opens the camera and starts sending preview frames to the underlying detector. The supplied\n     * surface holder is used for the preview so frames can be displayed to the user.\n     *\n     * @param surfaceHolder the surface holder to use for the preview frames.\n     * @throws IOException if the supplied surface holder could not be used as the preview display.\n     */\n    @Synchronized\n    @Throws(IOException::class)\n    internal fun start(surfaceHolder: SurfaceHolder) {\n        if (camera != null) return\n\n        camera = createCamera().apply {\n            setPreviewDisplay(surfaceHolder)\n            startPreview()\n        }\n\n        processingThread = Thread(processingRunnable).apply {\n            processingRunnable.setActive(true)\n            start()\n        }\n    }\n\n    /**\n     * Closes the camera and stops sending frames to the underlying frame detector.\n     *\n     *\n     * This camera source may be restarted again by calling [.start].\n     *\n     *\n     * Call [.release] instead to completely shut down this camera source and release the\n     * resources of the underlying detector.\n     */\n    @Synchronized\n    internal fun stop() {\n        processingRunnable.setActive(false)\n        processingThread?.let {\n            try {\n                // Waits for the thread to complete to ensure that we can't have multiple threads executing\n                // at the same time (i.e., which would happen if we called start too quickly after stop).\n                it.join()\n            } catch (e: InterruptedException) {\n                Log.e(TAG, \"Frame processing thread interrupted on stop.\")\n            }\n            processingThread = null\n        }\n\n        camera?.let {\n            it.stopPreview()\n            it.setPreviewCallbackWithBuffer(null)\n            try {\n                it.setPreviewDisplay(null)\n            } catch (e: Exception) {\n                Log.e(TAG, \"Failed to clear camera preview: $e\")\n            }\n            it.release()\n            camera = null\n        }\n\n        // Release the reference to any image buffers, since these will no longer be in use.\n        bytesToByteBuffer.clear()\n    }\n\n    /** Stops the camera and releases the resources of the camera and underlying detector.  */\n    fun release() {\n        graphicOverlay.clear()\n        synchronized(processorLock) {\n            stop()\n            frameProcessor?.stop()\n        }\n    }\n\n    fun setFrameProcessor(processor: FrameProcessor) {\n        graphicOverlay.clear()\n        synchronized(processorLock) {\n            frameProcessor?.stop()\n            frameProcessor = processor\n        }\n    }\n\n    fun updateFlashMode(flashMode: String) {\n        val parameters = camera?.parameters\n        parameters?.flashMode = flashMode\n        camera?.parameters = parameters\n    }\n\n    /**\n     * Opens the camera and applies the user settings.\n     *\n     * @throws IOException if camera cannot be found or preview cannot be processed.\n     */\n    @Throws(IOException::class)\n    private fun createCamera(): Camera {\n        val camera = Camera.open() ?: throw IOException(\"There is no back-facing camera.\")\n        val parameters = camera.parameters\n        setPreviewAndPictureSize(camera, parameters)\n        setRotation(camera, parameters)\n\n        val previewFpsRange = selectPreviewFpsRange(camera)\n            ?: throw IOException(\"Could not find suitable preview frames per second range.\")\n        parameters.setPreviewFpsRange(\n            previewFpsRange[Parameters.PREVIEW_FPS_MIN_INDEX],\n            previewFpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]\n        )\n\n        parameters.previewFormat = IMAGE_FORMAT\n\n        if (parameters.supportedFocusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {\n            parameters.focusMode = Parameters.FOCUS_MODE_CONTINUOUS_VIDEO\n        } else {\n            Log.i(TAG, \"Camera auto focus is not supported on this device.\")\n        }\n\n        camera.parameters = parameters\n\n        camera.setPreviewCallbackWithBuffer(processingRunnable::setNextFrame)\n\n        // Four frame buffers are needed for working with the camera:\n        //\n        //   one for the frame that is currently being executed upon in doing detection\n        //   one for the next pending frame to process immediately upon completing detection\n        //   two for the frames that the camera uses to populate future preview images\n        //\n        // Through trial and error it appears that two free buffers, in addition to the two buffers\n        // used in this code, are needed for the camera to work properly. Perhaps the camera has one\n        // thread for acquiring images, and another thread for calling into user code. If only three\n        // buffers are used, then the camera will spew thousands of warning messages when detection\n        // takes a non-trivial amount of time.\n        previewSize?.let {\n            camera.addCallbackBuffer(createPreviewBuffer(it))\n            camera.addCallbackBuffer(createPreviewBuffer(it))\n            camera.addCallbackBuffer(createPreviewBuffer(it))\n            camera.addCallbackBuffer(createPreviewBuffer(it))\n        }\n\n        return camera\n    }\n\n    @Throws(IOException::class)\n    private fun setPreviewAndPictureSize(camera: Camera, parameters: Parameters) {\n\n        // Gives priority to the preview size specified by the user if exists.\n        val sizePair: CameraSizePair = PreferenceUtils.getUserSpecifiedPreviewSize(context) ?: run {\n            // Camera preview size is based on the landscape mode, so we need to also use the aspect\n            // ration of display in the same mode for comparison.\n            val displayAspectRatioInLandscape: Float =\n                if (Utils.isPortraitMode(graphicOverlay.context)) {\n                    graphicOverlay.height.toFloat() / graphicOverlay.width\n                } else {\n                    graphicOverlay.width.toFloat() / graphicOverlay.height\n                }\n            selectSizePair(camera, displayAspectRatioInLandscape)\n        } ?: throw IOException(\"Could not find suitable preview size.\")\n\n        previewSize = sizePair.preview.also {\n            Log.v(TAG, \"Camera preview size: $it\")\n            parameters.setPreviewSize(it.width, it.height)\n            PreferenceUtils.saveStringPreference(context, R.string.pref_key_rear_camera_preview_size, it.toString())\n        }\n\n        sizePair.picture?.let { pictureSize ->\n            Log.v(TAG, \"Camera picture size: $pictureSize\")\n            parameters.setPictureSize(pictureSize.width, pictureSize.height)\n            PreferenceUtils.saveStringPreference(\n                context, R.string.pref_key_rear_camera_picture_size, pictureSize.toString()\n            )\n        }\n    }\n\n    /**\n     * Calculates the correct rotation for the given camera id and sets the rotation in the\n     * parameters. It also sets the camera's display orientation and rotation.\n     *\n     * @param parameters the camera parameters for which to set the rotation.\n     */\n    private fun setRotation(camera: Camera, parameters: Parameters) {\n        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager\n        val degrees = when (val deviceRotation = windowManager.defaultDisplay.rotation) {\n            Surface.ROTATION_0 -> 0\n            Surface.ROTATION_90 -> 90\n            Surface.ROTATION_180 -> 180\n            Surface.ROTATION_270 -> 270\n            else -> {\n                Log.e(TAG, \"Bad device rotation value: $deviceRotation\")\n                0\n            }\n        }\n\n        val cameraInfo = CameraInfo()\n        Camera.getCameraInfo(CAMERA_FACING_BACK, cameraInfo)\n        val angle = (cameraInfo.orientation - degrees + 360) % 360\n        this.rotationDegrees = angle\n        camera.setDisplayOrientation(angle)\n        parameters.setRotation(angle)\n    }\n\n    /**\n     * Creates one buffer for the camera preview callback. The size of the buffer is based off of the\n     * camera preview size and the format of the camera image.\n     *\n     * @return a new preview buffer of the appropriate size for the current camera settings.\n     */\n    private fun createPreviewBuffer(previewSize: Size): ByteArray {\n        val bitsPerPixel = ImageFormat.getBitsPerPixel(IMAGE_FORMAT)\n        val sizeInBits = previewSize.height.toLong() * previewSize.width.toLong() * bitsPerPixel.toLong()\n        val bufferSize = ceil(sizeInBits / 8.0).toInt() + 1\n\n        // Creating the byte array this way and wrapping it, as opposed to using .allocate(),\n        // should guarantee that there will be an array to work with.\n        val byteArray = ByteArray(bufferSize)\n        val byteBuffer = ByteBuffer.wrap(byteArray)\n        check(!(!byteBuffer.hasArray() || !byteBuffer.array()!!.contentEquals(byteArray))) {\n            // This should never happen. If it does, then we wouldn't be passing the preview content to\n            // the underlying detector later.\n            \"Failed to create valid buffer for camera source.\"\n        }\n\n        bytesToByteBuffer[byteArray] = byteBuffer\n        return byteArray\n    }\n\n    /**\n     * This runnable controls access to the underlying receiver, calling it to process frames when\n     * available from the camera. This is designed to run detection on frames as fast as possible\n     * (i.e., without unnecessary context switching or waiting on the next frame).\n     *\n     *\n     * While detection is running on a frame, new frames may be received from the camera. As these\n     * frames come in, the most recent frame is held onto as pending. As soon as detection and its\n     * associated processing is done for the previous frame, detection on the mostly recently received\n     * frame will immediately start on the same thread.\n     */\n    private inner class FrameProcessingRunnable internal constructor() : Runnable {\n\n        // This lock guards all of the member variables below.\n        private val lock = Object()\n        private var active = true\n\n        // These pending variables hold the state associated with the new frame awaiting processing.\n        private var pendingFrameData: ByteBuffer? = null\n\n        /** Marks the runnable as active/not active. Signals any blocked threads to continue.  */\n        internal fun setActive(active: Boolean) {\n            synchronized(lock) {\n                this.active = active\n                lock.notifyAll()\n            }\n        }\n\n        /**\n         * Sets the frame data received from the camera. This adds the previous unused frame buffer (if\n         * present) back to the camera, and keeps a pending reference to the frame data for future use.\n         */\n        internal fun setNextFrame(data: ByteArray, camera: Camera) {\n            synchronized(lock) {\n                pendingFrameData?.let {\n                    camera.addCallbackBuffer(it.array())\n                    pendingFrameData = null\n                }\n\n                if (!bytesToByteBuffer.containsKey(data)) {\n                    Log.d(\n                        TAG,\n                        \"Skipping frame. Could not find ByteBuffer associated with the image data from the camera.\"\n                    )\n                    return\n                }\n\n                pendingFrameData = bytesToByteBuffer[data]\n\n                // Notify the processor thread if it is waiting on the next frame (see below).\n                lock.notifyAll()\n            }\n        }\n\n        /**\n         * As long as the processing thread is active, this executes detection on frames continuously.\n         * The next pending frame is either immediately available or hasn't been received yet. Once it\n         * is available, we transfer the frame info to local variables and run detection on that frame.\n         * It immediately loops back for the next frame without pausing.\n         *\n         *\n         * If detection takes longer than the time in between new frames from the camera, this will\n         * mean that this loop will run without ever waiting on a frame, avoiding any context switching\n         * or frame acquisition time latency.\n         *\n         *\n         * If you find that this is using more CPU than you'd like, you should probably decrease the\n         * FPS setting above to allow for some idle time in between frames.\n         */\n        override fun run() {\n            var data: ByteBuffer?\n\n            while (true) {\n                synchronized(lock) {\n                    while (active && pendingFrameData == null) {\n                        try {\n                            // Wait for the next frame to be received from the camera, since we don't have it yet.\n                            lock.wait()\n                        } catch (e: InterruptedException) {\n                            Log.e(TAG, \"Frame processing loop terminated.\", e)\n                            return\n                        }\n                    }\n\n                    if (!active) {\n                        // Exit the loop once this camera source is stopped or released.  We check this here,\n                        // immediately after the wait() above, to handle the case where setActive(false) had\n                        // been called, triggering the termination of this loop.\n                        return\n                    }\n\n                    // Hold onto the frame data locally, so that we can use this for detection\n                    // below.  We need to clear pendingFrameData to ensure that this buffer isn't\n                    // recycled back to the camera before we are done using that data.\n                    data = pendingFrameData\n                    pendingFrameData = null\n                }\n\n                try {\n                    synchronized(processorLock) {\n                        val frameMetadata = FrameMetadata(previewSize!!.width, previewSize!!.height, rotationDegrees)\n                        data?.let {\n                            frameProcessor?.process(it, frameMetadata, graphicOverlay)\n                        }\n                    }\n                } catch (t: Exception) {\n                    Log.e(TAG, \"Exception thrown from receiver.\", t)\n                } finally {\n                    data?.let {\n                        camera?.addCallbackBuffer(it.array())\n                    }\n                }\n            }\n        }\n    }\n\n    companion object {\n\n        const val CAMERA_FACING_BACK = CameraInfo.CAMERA_FACING_BACK\n\n        private const val TAG = \"CameraSource\"\n\n        private const val IMAGE_FORMAT = ImageFormat.NV21\n        private const val MIN_CAMERA_PREVIEW_WIDTH = 400\n        private const val MAX_CAMERA_PREVIEW_WIDTH = 1300\n        private const val DEFAULT_REQUESTED_CAMERA_PREVIEW_WIDTH = 640\n        private const val DEFAULT_REQUESTED_CAMERA_PREVIEW_HEIGHT = 360\n        private const val REQUESTED_CAMERA_FPS = 30.0f\n\n        /**\n         * Selects the most suitable preview and picture size, given the display aspect ratio in landscape\n         * mode.\n         *\n         *\n         * It's firstly trying to pick the one that has closest aspect ratio to display view with its\n         * width be in the specified range [[.MIN_CAMERA_PREVIEW_WIDTH], [ ][.MAX_CAMERA_PREVIEW_WIDTH]]. If there're multiple candidates, choose the one having longest\n         * width.\n         *\n         *\n         * If the above looking up failed, chooses the one that has the minimum sum of the differences\n         * between the desired values and the actual values for width and height.\n         *\n         *\n         * Even though we only need to find the preview size, it's necessary to find both the preview\n         * size and the picture size of the camera together, because these need to have the same aspect\n         * ratio. On some hardware, if you would only set the preview size, you will get a distorted\n         * image.\n         *\n         * @param camera the camera to select a preview size from\n         * @return the selected preview and picture size pair\n         */\n        private fun selectSizePair(camera: Camera, displayAspectRatioInLandscape: Float): CameraSizePair? {\n            val validPreviewSizes = Utils.generateValidPreviewSizeList(camera)\n\n            var selectedPair: CameraSizePair? = null\n            // Picks the preview size that has closest aspect ratio to display view.\n            var minAspectRatioDiff = Float.MAX_VALUE\n\n            for (sizePair in validPreviewSizes) {\n                val previewSize = sizePair.preview\n                if (previewSize.width < MIN_CAMERA_PREVIEW_WIDTH || previewSize.width > MAX_CAMERA_PREVIEW_WIDTH) {\n                    continue\n                }\n\n                val previewAspectRatio = previewSize.width.toFloat() / previewSize.height.toFloat()\n                val aspectRatioDiff = abs(displayAspectRatioInLandscape - previewAspectRatio)\n                if (abs(aspectRatioDiff - minAspectRatioDiff) < Utils.ASPECT_RATIO_TOLERANCE) {\n                    if (selectedPair == null || selectedPair.preview.width < sizePair.preview.width) {\n                        selectedPair = sizePair\n                    }\n                } else if (aspectRatioDiff < minAspectRatioDiff) {\n                    minAspectRatioDiff = aspectRatioDiff\n                    selectedPair = sizePair\n                }\n            }\n\n            if (selectedPair == null) {\n                // Picks the one that has the minimum sum of the differences between the desired values and\n                // the actual values for width and height.\n                var minDiff = Integer.MAX_VALUE\n                for (sizePair in validPreviewSizes) {\n                    val size = sizePair.preview\n                    val diff =\n                        abs(size.width - DEFAULT_REQUESTED_CAMERA_PREVIEW_WIDTH) +\n                                abs(size.height - DEFAULT_REQUESTED_CAMERA_PREVIEW_HEIGHT)\n                    if (diff < minDiff) {\n                        selectedPair = sizePair\n                        minDiff = diff\n                    }\n                }\n            }\n\n            return selectedPair\n        }\n\n        /**\n         * Selects the most suitable preview frames per second range.\n         *\n         * @param camera the camera to select a frames per second range from\n         * @return the selected preview frames per second range\n         */\n        private fun selectPreviewFpsRange(camera: Camera): IntArray? {\n            // The camera API uses integers scaled by a factor of 1000 instead of floating-point frame\n            // rates.\n            val desiredPreviewFpsScaled = (REQUESTED_CAMERA_FPS * 1000f).toInt()\n\n            // The method for selecting the best range is to minimize the sum of the differences between\n            // the desired value and the upper and lower bounds of the range.  This may select a range\n            // that the desired value is outside of, but this is often preferred.  For example, if the\n            // desired frame rate is 29.97, the range (30, 30) is probably more desirable than the\n            // range (15, 30).\n            var selectedFpsRange: IntArray? = null\n            var minDiff = Integer.MAX_VALUE\n            for (range in camera.parameters.supportedPreviewFpsRange) {\n                val deltaMin = desiredPreviewFpsScaled - range[Parameters.PREVIEW_FPS_MIN_INDEX]\n                val deltaMax = desiredPreviewFpsScaled - range[Parameters.PREVIEW_FPS_MAX_INDEX]\n                val diff = abs(deltaMin) + abs(deltaMax)\n                if (diff < minDiff) {\n                    selectedFpsRange = range\n                    minDiff = diff\n                }\n            }\n            return selectedFpsRange\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/CameraSourcePreview.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.util.Log\nimport android.view.SurfaceHolder\nimport android.view.SurfaceView\nimport android.widget.FrameLayout\nimport com.google.android.gms.common.images.Size\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.Utils\nimport java.io.IOException\n\n/** Preview the camera image in the screen.  */\nclass CameraSourcePreview(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) {\n\n    private val surfaceView: SurfaceView = SurfaceView(context).apply {\n        holder.addCallback(SurfaceCallback())\n        addView(this)\n    }\n    private var graphicOverlay: GraphicOverlay? = null\n    private var startRequested = false\n    private var surfaceAvailable = false\n    private var cameraSource: CameraSource? = null\n    private var cameraPreviewSize: Size? = null\n\n    override fun onFinishInflate() {\n        super.onFinishInflate()\n        graphicOverlay = findViewById(R.id.camera_preview_graphic_overlay)\n    }\n\n    @Throws(IOException::class)\n    fun start(cameraSource: CameraSource) {\n        this.cameraSource = cameraSource\n        startRequested = true\n        startIfReady()\n    }\n\n    fun stop() {\n        cameraSource?.let {\n            it.stop()\n            cameraSource = null\n            startRequested = false\n        }\n    }\n\n    @Throws(IOException::class)\n    private fun startIfReady() {\n        if (startRequested && surfaceAvailable) {\n            cameraSource?.start(surfaceView.holder)\n            requestLayout()\n            graphicOverlay?.let { overlay ->\n                cameraSource?.let {\n                    overlay.setCameraInfo(it)\n                }\n                overlay.clear()\n            }\n            startRequested = false\n        }\n    }\n\n    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {\n        val layoutWidth = right - left\n        val layoutHeight = bottom - top\n\n        cameraSource?.previewSize?.let { cameraPreviewSize = it }\n\n        val previewSizeRatio = cameraPreviewSize?.let { size ->\n            if (Utils.isPortraitMode(context)) {\n                // Camera's natural orientation is landscape, so need to swap width and height.\n                size.height.toFloat() / size.width\n            } else {\n                size.width.toFloat() / size.height\n            }\n        } ?: layoutWidth.toFloat() / layoutHeight.toFloat()\n\n        // Match the width of the child view to its parent.\n        val childHeight = (layoutWidth / previewSizeRatio).toInt()\n        if (childHeight <= layoutHeight) {\n            for (i in 0 until childCount) {\n                getChildAt(i).layout(0, 0, layoutWidth, childHeight)\n            }\n        } else {\n            // When the child view is too tall to be fitted in its parent: If the child view is\n            // static overlay view container (contains views such as bottom prompt chip), we apply\n            // the size of the parent view to it. Otherwise, we offset the top/bottom position\n            // equally to position it in the center of the parent.\n            val excessLenInHalf = (childHeight - layoutHeight) / 2\n            for (i in 0 until childCount) {\n                val childView = getChildAt(i)\n                when (childView.id) {\n                    R.id.static_overlay_container -> {\n                        childView.layout(0, 0, layoutWidth, layoutHeight)\n                    }\n                    else -> {\n                        childView.layout(\n                            0, -excessLenInHalf, layoutWidth, layoutHeight + excessLenInHalf\n                        )\n                    }\n                }\n            }\n        }\n\n        try {\n            startIfReady()\n        } catch (e: IOException) {\n            Log.e(TAG, \"Could not start camera source.\", e)\n        }\n    }\n\n    private inner class SurfaceCallback : SurfaceHolder.Callback {\n        override fun surfaceCreated(surface: SurfaceHolder) {\n            surfaceAvailable = true\n            try {\n                startIfReady()\n            } catch (e: IOException) {\n                Log.e(TAG, \"Could not start camera source.\", e)\n            }\n        }\n\n        override fun surfaceDestroyed(surface: SurfaceHolder) {\n            surfaceAvailable = false\n        }\n\n        override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {\n        }\n    }\n\n    companion object {\n        private const val TAG = \"CameraSourcePreview\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/FrameMetadata.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\n/** Metadata info of a camera frame.  */\nclass FrameMetadata(val width: Int, val height: Int, val rotation: Int)\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/FrameProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\nimport java.nio.ByteBuffer\n\n/** An interface to process the input camera frame and perform detection on it.  */\ninterface FrameProcessor {\n\n    /** Processes the input frame with the underlying detector.  */\n    fun process(data: ByteBuffer, frameMetadata: FrameMetadata, graphicOverlay: GraphicOverlay)\n\n    /** Stops the underlying detector and release resources.  */\n    fun stop()\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/FrameProcessorBase.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.annotation.GuardedBy\nimport com.google.android.gms.tasks.OnFailureListener\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.TaskExecutors\nimport com.google.mlkit.md.addOnFailureListener\nimport com.google.mlkit.md.addOnSuccessListener\nimport com.google.mlkit.md.CameraInputInfo\nimport com.google.mlkit.md.InputInfo\nimport com.google.mlkit.md.ScopedExecutor\nimport com.google.mlkit.vision.common.InputImage\nimport java.nio.ByteBuffer\n\n/** Abstract base class of [FrameProcessor].  */\nabstract class FrameProcessorBase<T> : FrameProcessor {\n\n    // To keep the latest frame and its metadata.\n    @GuardedBy(\"this\")\n    private var latestFrame: ByteBuffer? = null\n\n    @GuardedBy(\"this\")\n    private var latestFrameMetaData: FrameMetadata? = null\n\n    // To keep the frame and metadata in process.\n    @GuardedBy(\"this\")\n    private var processingFrame: ByteBuffer? = null\n\n    @GuardedBy(\"this\")\n    private var processingFrameMetaData: FrameMetadata? = null\n    private val executor = ScopedExecutor(TaskExecutors.MAIN_THREAD)\n\n    @Synchronized\n    override fun process(\n        data: ByteBuffer,\n        frameMetadata: FrameMetadata,\n        graphicOverlay: GraphicOverlay\n    ) {\n        latestFrame = data\n        latestFrameMetaData = frameMetadata\n        if (processingFrame == null && processingFrameMetaData == null) {\n            processLatestFrame(graphicOverlay)\n        }\n    }\n\n    @Synchronized\n    private fun processLatestFrame(graphicOverlay: GraphicOverlay) {\n        processingFrame = latestFrame\n        processingFrameMetaData = latestFrameMetaData\n        latestFrame = null\n        latestFrameMetaData = null\n        val frame = processingFrame ?: return\n        val frameMetaData = processingFrameMetaData ?: return\n        val image = InputImage.fromByteBuffer(\n            frame,\n            frameMetaData.width,\n            frameMetaData.height,\n            frameMetaData.rotation,\n            InputImage.IMAGE_FORMAT_NV21\n        )\n        val startMs = SystemClock.elapsedRealtime()\n        detectInImage(image)\n            .addOnSuccessListener(executor) { results: T ->\n                Log.d(TAG, \"Latency is: ${SystemClock.elapsedRealtime() - startMs}\")\n                this@FrameProcessorBase.onSuccess(CameraInputInfo(frame, frameMetaData), results, graphicOverlay)\n                processLatestFrame(graphicOverlay)\n            }\n            .addOnFailureListener(executor) { e -> OnFailureListener { this@FrameProcessorBase.onFailure(it) } }\n    }\n\n    override fun stop() {\n        executor.shutdown()\n    }\n\n    protected abstract fun detectInImage(image: InputImage): Task<T>\n\n    /** Be called when the detection succeeds.  */\n    protected abstract fun onSuccess(\n        inputInfo: InputInfo,\n        results: T,\n        graphicOverlay: GraphicOverlay\n    )\n\n    protected abstract fun onFailure(e: Exception)\n\n    companion object {\n        private const val TAG = \"FrameProcessorBase\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/GraphicOverlay.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\nimport android.content.Context\nimport android.graphics.Canvas\nimport android.graphics.Rect\nimport android.graphics.RectF\nimport android.util.AttributeSet\nimport android.view.View\nimport com.google.mlkit.md.Utils\nimport java.util.ArrayList\n\n/**\n * A view which renders a series of custom graphics to be overlaid on top of an associated preview\n * (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove\n * them, triggering the appropriate drawing and invalidation within the view.\n *\n *\n * Supports scaling and mirroring of the graphics relative the camera's preview properties. The\n * idea is that detection items are expressed in terms of a preview size, but need to be scaled up\n * to the full view size, and also mirrored in the case of the front-facing camera.\n *\n *\n * Associated [Graphic] items should use [.translateX] and [ ][.translateY] to convert to view coordinate from the preview's coordinate.\n */\nclass GraphicOverlay(context: Context, attrs: AttributeSet) : View(context, attrs) {\n    private val lock = Any()\n\n    private var previewWidth: Int = 0\n    private var widthScaleFactor = 1.0f\n    private var previewHeight: Int = 0\n    private var heightScaleFactor = 1.0f\n    private val graphics = ArrayList<Graphic>()\n\n    /**\n     * Base class for a custom graphics object to be rendered within the graphic overlay. Subclass\n     * this and implement the [Graphic.draw] method to define the graphics element. Add\n     * instances to the overlay using [GraphicOverlay.add].\n     */\n    abstract class Graphic protected constructor(protected val overlay: GraphicOverlay) {\n        protected val context: Context = overlay.context\n\n        /** Draws the graphic on the supplied canvas.  */\n        abstract fun draw(canvas: Canvas)\n    }\n\n    /** Removes all graphics from the overlay.  */\n    fun clear() {\n        synchronized(lock) {\n            graphics.clear()\n        }\n        postInvalidate()\n    }\n\n    /** Adds a graphic to the overlay.  */\n    fun add(graphic: Graphic) {\n        synchronized(lock) {\n            graphics.add(graphic)\n        }\n    }\n\n    /**\n     * Sets the camera attributes for size and facing direction, which informs how to transform image\n     * coordinates later.\n     */\n    fun setCameraInfo(cameraSource: CameraSource) {\n        val previewSize = cameraSource.previewSize ?: return\n        if (Utils.isPortraitMode(context)) {\n            // Swap width and height when in portrait, since camera's natural orientation is landscape.\n            previewWidth = previewSize.height\n            previewHeight = previewSize.width\n        } else {\n            previewWidth = previewSize.width\n            previewHeight = previewSize.height\n        }\n    }\n\n    fun translateX(x: Float): Float = x * widthScaleFactor\n    fun translateY(y: Float): Float = y * heightScaleFactor\n\n    /**\n     * Adjusts the `rect`'s coordinate from the preview's coordinate system to the view\n     * coordinate system.\n     */\n    fun translateRect(rect: Rect) = RectF(\n        translateX(rect.left.toFloat()),\n        translateY(rect.top.toFloat()),\n        translateX(rect.right.toFloat()),\n        translateY(rect.bottom.toFloat())\n    )\n\n    /** Draws the overlay with its associated graphic objects.  */\n    override fun onDraw(canvas: Canvas) {\n        super.onDraw(canvas)\n\n        if (previewWidth > 0 && previewHeight > 0) {\n            widthScaleFactor = width.toFloat() / previewWidth\n            heightScaleFactor = height.toFloat() / previewHeight\n        }\n\n        synchronized(lock) {\n            graphics.forEach { it.draw(canvas) }\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/camera/WorkflowModel.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.camera\n\nimport android.app.Application\nimport android.content.Context\nimport androidx.annotation.MainThread\nimport androidx.lifecycle.AndroidViewModel\nimport androidx.lifecycle.MutableLiveData\nimport com.google.mlkit.md.objectdetection.DetectedObjectInfo\nimport com.google.mlkit.md.productsearch.Product\nimport com.google.mlkit.md.productsearch.SearchedObject\nimport com.google.mlkit.md.settings.PreferenceUtils\nimport com.google.mlkit.vision.barcode.common.Barcode\nimport java.util.HashSet\n\n/** View model for handling application workflow based on camera preview.  */\nclass WorkflowModel(application: Application) : AndroidViewModel(application) {\n\n    val workflowState = MutableLiveData<WorkflowState>()\n    val objectToSearch = MutableLiveData<DetectedObjectInfo>()\n    val searchedObject = MutableLiveData<SearchedObject>()\n    val detectedBarcode = MutableLiveData<Barcode>()\n\n    private val objectIdsToSearch = HashSet<Int>()\n\n    var isCameraLive = false\n        private set\n\n    private var confirmedObject: DetectedObjectInfo? = null\n\n    private val context: Context\n        get() = getApplication<Application>().applicationContext\n\n    /**\n     * State set of the application workflow.\n     */\n    enum class WorkflowState {\n        NOT_STARTED,\n        DETECTING,\n        DETECTED,\n        CONFIRMING,\n        CONFIRMED,\n        SEARCHING,\n        SEARCHED\n    }\n\n    @MainThread\n    fun setWorkflowState(workflowState: WorkflowState) {\n        if (workflowState != WorkflowState.CONFIRMED &&\n            workflowState != WorkflowState.SEARCHING &&\n            workflowState != WorkflowState.SEARCHED\n        ) {\n            confirmedObject = null\n        }\n        this.workflowState.value = workflowState\n    }\n\n    @MainThread\n    fun confirmingObject(confirmingObject: DetectedObjectInfo, progress: Float) {\n        val isConfirmed = progress.compareTo(1f) == 0\n        if (isConfirmed) {\n            confirmedObject = confirmingObject\n            if (PreferenceUtils.isAutoSearchEnabled(context)) {\n                setWorkflowState(WorkflowState.SEARCHING)\n                triggerSearch(confirmingObject)\n            } else {\n                setWorkflowState(WorkflowState.CONFIRMED)\n            }\n        } else {\n            setWorkflowState(WorkflowState.CONFIRMING)\n        }\n    }\n\n    @MainThread\n    fun onSearchButtonClicked() {\n        confirmedObject?.let {\n            setWorkflowState(WorkflowState.SEARCHING)\n            triggerSearch(it)\n        }\n    }\n\n    private fun triggerSearch(detectedObject: DetectedObjectInfo) {\n        val objectId = detectedObject.objectId ?: throw NullPointerException()\n        if (objectIdsToSearch.contains(objectId)) {\n            // Already in searching.\n            return\n        }\n\n        objectIdsToSearch.add(objectId)\n        objectToSearch.value = detectedObject\n    }\n\n    fun markCameraLive() {\n        isCameraLive = true\n        objectIdsToSearch.clear()\n    }\n\n    fun markCameraFrozen() {\n        isCameraLive = false\n    }\n\n    fun onSearchCompleted(detectedObject: DetectedObjectInfo, products: List<Product>) {\n        val lConfirmedObject = confirmedObject\n        if (detectedObject != lConfirmedObject) {\n            // Drops the search result from the object that has lost focus.\n            return\n        }\n\n        objectIdsToSearch.remove(detectedObject.objectId)\n        setWorkflowState(WorkflowState.SEARCHED)\n\n        searchedObject.value = SearchedObject(context.resources, lConfirmedObject, products)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/DetectedObjectInfo.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.CompressFormat\nimport android.graphics.Rect\nimport android.util.Log\nimport com.google.mlkit.md.InputInfo\nimport com.google.mlkit.vision.objects.DetectedObject\nimport java.io.ByteArrayOutputStream\nimport java.io.IOException\n\n/**\n * Holds the detected object and its related image info.\n */\nclass DetectedObjectInfo(\n    private val detectedObject: DetectedObject,\n    val objectIndex: Int,\n    private val inputInfo: InputInfo\n) {\n\n    private var bitmap: Bitmap? = null\n    private var jpegBytes: ByteArray? = null\n\n    val objectId: Int? = detectedObject.trackingId\n    val boundingBox: Rect = detectedObject.boundingBox\n    val labels: List<DetectedObject.Label> = detectedObject.labels\n\n    val imageData: ByteArray?\n        @Synchronized get() {\n            if (jpegBytes == null) {\n                try {\n                    ByteArrayOutputStream().use { stream ->\n                        getBitmap().compress(CompressFormat.JPEG, /* quality= */ 100, stream)\n                        jpegBytes = stream.toByteArray()\n                    }\n                } catch (e: IOException) {\n                    Log.e(TAG, \"Error getting object image data!\")\n                }\n            }\n            return jpegBytes\n        }\n\n    @Synchronized\n    fun getBitmap(): Bitmap {\n        return bitmap ?: let {\n            val boundingBox = detectedObject.boundingBox\n            val createdBitmap = Bitmap.createBitmap(\n                inputInfo.getBitmap(),\n                boundingBox.left,\n                boundingBox.top,\n                boundingBox.width(),\n                boundingBox.height()\n            )\n            if (createdBitmap.width > MAX_IMAGE_WIDTH) {\n                val dstHeight = (MAX_IMAGE_WIDTH.toFloat() / createdBitmap.width * createdBitmap.height).toInt()\n                bitmap = Bitmap.createScaledBitmap(createdBitmap, MAX_IMAGE_WIDTH, dstHeight, /* filter= */ false)\n            }\n            createdBitmap\n        }\n    }\n\n    companion object {\n        private const val TAG = \"DetectedObject\"\n        private const val MAX_IMAGE_WIDTH = 640\n        private const val INVALID_LABEL = \"N/A\"\n\n        fun hasValidLabels(detectedObject: DetectedObject): Boolean {\n            return detectedObject.labels.isNotEmpty() &&\n                    detectedObject.labels.none { label -> label.text == INVALID_LABEL }\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/MultiObjectProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.graphics.PointF\nimport android.util.Log\nimport android.util.SparseArray\nimport androidx.annotation.MainThread\nimport androidx.core.util.forEach\nimport androidx.core.util.set\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.md.camera.CameraReticleAnimator\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.camera.WorkflowModel\nimport com.google.mlkit.md.camera.FrameProcessorBase\nimport com.google.mlkit.md.settings.PreferenceUtils\nimport com.google.mlkit.common.model.LocalModel\nimport com.google.mlkit.md.InputInfo\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions\nimport com.google.mlkit.vision.objects.DetectedObject\nimport com.google.mlkit.vision.objects.ObjectDetection\nimport com.google.mlkit.vision.objects.ObjectDetector\nimport com.google.mlkit.vision.objects.ObjectDetectorOptionsBase\nimport java.io.IOException\nimport java.util.ArrayList\nimport kotlin.math.hypot\n\n/** A processor to run object detector in multi-objects mode.  */\nclass MultiObjectProcessor(\n    graphicOverlay: GraphicOverlay,\n    private val workflowModel: WorkflowModel,\n    private val customModelPath: String? = null\n) :\n    FrameProcessorBase<List<DetectedObject>>() {\n    private val confirmationController: ObjectConfirmationController = ObjectConfirmationController(graphicOverlay)\n    private val cameraReticleAnimator: CameraReticleAnimator = CameraReticleAnimator(graphicOverlay)\n    private val objectSelectionDistanceThreshold: Int = graphicOverlay\n        .resources\n        .getDimensionPixelOffset(R.dimen.object_selection_distance_threshold)\n    private val detector: ObjectDetector\n\n    // Each new tracked object plays appearing animation exactly once.\n    private val objectDotAnimatorArray = SparseArray<ObjectDotAnimator>()\n\n    init {\n        val options: ObjectDetectorOptionsBase\n        val isClassificationEnabled = PreferenceUtils.isClassificationEnabled(graphicOverlay.context)\n\n        if (customModelPath != null) {\n            val localModel = LocalModel.Builder()\n                .setAssetFilePath(customModelPath)\n                .build()\n            options = CustomObjectDetectorOptions.Builder(localModel)\n                .setDetectorMode(ObjectDetectorOptions.STREAM_MODE)\n                .enableClassification() // Always enable classification for custom models\n                .build()\n        } else {\n            val optionsBuilder = ObjectDetectorOptions.Builder()\n                .setDetectorMode(ObjectDetectorOptions.STREAM_MODE)\n            if (isClassificationEnabled) {\n                optionsBuilder.enableClassification()\n            }\n            options = optionsBuilder.build()\n        }\n\n        this.detector = ObjectDetection.getClient(options)\n    }\n\n    override fun stop() {\n        super.stop()\n        try {\n            detector.close()\n        } catch (e: IOException) {\n            Log.e(TAG, \"Failed to close object detector!\", e)\n        }\n    }\n\n    override fun detectInImage(image: InputImage): Task<List<DetectedObject>> {\n        return detector.process(image)\n    }\n\n    @MainThread\n    override fun onSuccess(\n        inputInfo: InputInfo,\n        results: List<DetectedObject>,\n        graphicOverlay: GraphicOverlay\n    ) {\n        var objects = results\n        if (!workflowModel.isCameraLive) {\n            return\n        }\n\n        if (customModelPath != null) {\n            objects = results.filter { result -> DetectedObjectInfo.hasValidLabels(result) }\n        } else if (PreferenceUtils.isClassificationEnabled(graphicOverlay.context)) {\n            val qualifiedObjects = ArrayList<DetectedObject>()\n            for (result in objects) {\n                qualifiedObjects.add(result)\n            }\n            objects = qualifiedObjects\n        }\n\n        removeAnimatorsFromUntrackedObjects(objects)\n\n        graphicOverlay.clear()\n\n        var selectedObject: DetectedObjectInfo? = null\n        for (i in objects.indices) {\n            val result = objects[i]\n            if (selectedObject == null && shouldSelectObject(graphicOverlay, result)) {\n                selectedObject = DetectedObjectInfo(result, i, inputInfo)\n                // Starts the object confirmation once an object is regarded as selected.\n                confirmationController.confirming(result.trackingId)\n                graphicOverlay.add(ObjectConfirmationGraphic(graphicOverlay, confirmationController))\n\n                graphicOverlay.add(\n                    ObjectGraphicInMultiMode(\n                        graphicOverlay, selectedObject, confirmationController\n                    )\n                )\n            } else {\n                if (confirmationController.isConfirmed) {\n                    // Don't render other objects when an object is in confirmed state.\n                    continue\n                }\n\n                val trackingId = result.trackingId ?: return\n                val objectDotAnimator = objectDotAnimatorArray.get(trackingId) ?: let {\n                    ObjectDotAnimator(graphicOverlay).apply {\n                        start()\n                        objectDotAnimatorArray[trackingId] = this\n                    }\n                }\n                graphicOverlay.add(\n                    ObjectDotGraphic(\n                        graphicOverlay, DetectedObjectInfo(result, i, inputInfo), objectDotAnimator\n                    )\n                )\n            }\n        }\n\n        if (selectedObject == null) {\n            confirmationController.reset()\n            graphicOverlay.add(ObjectReticleGraphic(graphicOverlay, cameraReticleAnimator))\n            cameraReticleAnimator.start()\n        } else {\n            cameraReticleAnimator.cancel()\n        }\n\n        graphicOverlay.invalidate()\n\n        if (selectedObject != null) {\n            workflowModel.confirmingObject(selectedObject, confirmationController.progress)\n        } else {\n            workflowModel.setWorkflowState(\n                if (objects.isEmpty()) {\n                    WorkflowModel.WorkflowState.DETECTING\n                } else {\n                    WorkflowModel.WorkflowState.DETECTED\n                }\n            )\n        }\n    }\n\n    private fun removeAnimatorsFromUntrackedObjects(detectedObjects: List<DetectedObject>) {\n        val trackingIds = detectedObjects.mapNotNull { it.trackingId }\n        // Stop and remove animators from the objects that have lost tracking.\n        val removedTrackingIds = ArrayList<Int>()\n        objectDotAnimatorArray.forEach { key, value ->\n            if (!trackingIds.contains(key)) {\n                value.cancel()\n                removedTrackingIds.add(key)\n            }\n        }\n        removedTrackingIds.forEach {\n            objectDotAnimatorArray.remove(it)\n        }\n    }\n\n    private fun shouldSelectObject(graphicOverlay: GraphicOverlay, visionObject: DetectedObject): Boolean {\n        // Considers an object as selected when the camera reticle touches the object dot.\n        val box = graphicOverlay.translateRect(visionObject.boundingBox)\n        val objectCenter = PointF((box.left + box.right) / 2f, (box.top + box.bottom) / 2f)\n        val reticleCenter = PointF(graphicOverlay.width / 2f, graphicOverlay.height / 2f)\n        val distance =\n            hypot((objectCenter.x - reticleCenter.x).toDouble(), (objectCenter.y - reticleCenter.y).toDouble())\n        return distance < objectSelectionDistanceThreshold\n    }\n\n    override fun onFailure(e: Exception) {\n        Log.e(TAG, \"Object detection failed!\", e)\n    }\n\n    companion object {\n\n        private const val TAG = \"MultiObjectProcessor\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/ObjectConfirmationController.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.os.CountDownTimer\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.settings.PreferenceUtils\n\n/**\n * Controls the progress of object confirmation before performing additional operation on the\n * detected object.\n */\ninternal class ObjectConfirmationController\n/**\n * @param graphicOverlay Used to refresh camera overlay when the confirmation progress updates.\n */\n    (graphicOverlay: GraphicOverlay) {\n\n    private val countDownTimer: CountDownTimer\n\n    private var objectId: Int? = null\n\n    /** Returns the confirmation progress described as a float value in the range of [0, 1].  */\n    var progress = 0f\n        private set\n\n    val isConfirmed: Boolean\n        get() = progress.compareTo(1f) == 0\n\n    init {\n        val confirmationTimeMs = PreferenceUtils.getConfirmationTimeMs(graphicOverlay.context).toLong()\n        countDownTimer = object : CountDownTimer(confirmationTimeMs, /* countDownInterval= */ 20) {\n            override fun onTick(millisUntilFinished: Long) {\n                progress = (confirmationTimeMs - millisUntilFinished).toFloat() / confirmationTimeMs\n                graphicOverlay.invalidate()\n            }\n\n            override fun onFinish() {\n                progress = 1f\n            }\n        }\n    }\n\n    fun confirming(objectId: Int?) {\n        if (objectId == this.objectId) {\n            // Do nothing if it's already in confirming.\n            return\n        }\n\n        reset()\n        this.objectId = objectId\n        countDownTimer.start()\n    }\n\n    fun reset() {\n        countDownTimer.cancel()\n        objectId = null\n        progress = 0f\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/ObjectConfirmationGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.graphics.Canvas\nimport android.graphics.Paint\nimport android.graphics.Paint.Cap\nimport android.graphics.Paint.Style\nimport android.graphics.RectF\nimport androidx.core.content.ContextCompat\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.GraphicOverlay.Graphic\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.settings.PreferenceUtils\n\n/**\n * Similar to the camera reticle but with additional progress ring to indicate an object is getting\n * confirmed for a follow up processing, e.g. product search.\n */\nclass ObjectConfirmationGraphic internal constructor(\n    overlay: GraphicOverlay,\n    private val confirmationController: ObjectConfirmationController\n) : Graphic(overlay) {\n\n    private val outerRingFillPaint: Paint\n    private val outerRingStrokePaint: Paint\n    private val innerRingPaint: Paint\n    private val progressRingStrokePaint: Paint\n    private val outerRingFillRadius: Int\n    private val outerRingStrokeRadius: Int\n    private val innerRingStrokeRadius: Int\n\n    init {\n\n        val resources = overlay.resources\n        outerRingFillPaint = Paint().apply {\n            style = Style.FILL\n            color = ContextCompat.getColor(context, R.color.object_reticle_outer_ring_fill)\n        }\n\n        outerRingStrokePaint = Paint().apply {\n            style = Style.STROKE\n            strokeWidth = resources.getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_stroke_width).toFloat()\n            strokeCap = Cap.ROUND\n            color = ContextCompat.getColor(context, R.color.object_reticle_outer_ring_stroke)\n        }\n\n        progressRingStrokePaint = Paint().apply {\n            style = Style.STROKE\n            strokeWidth = resources.getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_stroke_width).toFloat()\n            strokeCap = Cap.ROUND\n            color = ContextCompat.getColor(context, R.color.white)\n        }\n\n        innerRingPaint = Paint()\n        if (PreferenceUtils.isMultipleObjectsMode(overlay.context)) {\n            innerRingPaint.style = Style.FILL\n            innerRingPaint.color = ContextCompat.getColor(context, R.color.object_reticle_inner_ring)\n        } else {\n            innerRingPaint.style = Style.STROKE\n            innerRingPaint.strokeWidth =\n                resources.getDimensionPixelOffset(R.dimen.object_reticle_inner_ring_stroke_width).toFloat()\n            innerRingPaint.strokeCap = Cap.ROUND\n            innerRingPaint.color = ContextCompat.getColor(context, R.color.white)\n        }\n\n        outerRingFillRadius = resources.getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_fill_radius)\n        outerRingStrokeRadius = resources.getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_stroke_radius)\n        innerRingStrokeRadius = resources.getDimensionPixelOffset(R.dimen.object_reticle_inner_ring_stroke_radius)\n    }\n\n    override fun draw(canvas: Canvas) {\n        val cx = canvas.width / 2f\n        val cy = canvas.height / 2f\n        canvas.drawCircle(cx, cy, outerRingFillRadius.toFloat(), outerRingFillPaint)\n        canvas.drawCircle(cx, cy, outerRingStrokeRadius.toFloat(), outerRingStrokePaint)\n        canvas.drawCircle(cx, cy, innerRingStrokeRadius.toFloat(), innerRingPaint)\n\n        val progressRect = RectF(\n            cx - outerRingStrokeRadius,\n            cy - outerRingStrokeRadius,\n            cx + outerRingStrokeRadius,\n            cy + outerRingStrokeRadius\n        )\n        val sweepAngle = confirmationController.progress * 360\n        canvas.drawArc(\n            progressRect,\n            /* startAngle= */ 0f,\n            sweepAngle,\n            /* useCenter= */ false,\n            progressRingStrokePaint\n        )\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/ObjectDotAnimator.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.animation.AnimatorSet\nimport android.animation.ValueAnimator\nimport androidx.core.view.animation.PathInterpolatorCompat\nimport androidx.interpolator.view.animation.FastOutSlowInInterpolator\nimport com.google.mlkit.md.camera.GraphicOverlay\n\n/**\n * Custom animator for the object dot.\n */\ninternal class ObjectDotAnimator(graphicOverlay: GraphicOverlay) {\n\n    private val animatorSet: AnimatorSet\n\n    /** Returns the scale value of dot radius ranges in [0, 1].  */\n    var radiusScale = 0f\n        private set\n\n    /** Returns the scale value of dot alpha ranges in [0, 1].  */\n    var alphaScale = 0f\n        private set\n\n    init {\n        val dotScaleUpAnimator = ValueAnimator.ofFloat(0f, 1.3f)\n            .setDuration(DURATION_DOT_SCALE_UP_MS)\n        dotScaleUpAnimator.interpolator = FastOutSlowInInterpolator()\n        dotScaleUpAnimator.addUpdateListener { animation ->\n            radiusScale = animation.animatedValue as Float\n            graphicOverlay.postInvalidate()\n        }\n\n        val dotScaleDownAnimator = ValueAnimator.ofFloat(1.3f, 1f)\n            .setDuration(DURATION_DOT_SCALE_DOWN_MS)\n        dotScaleDownAnimator.startDelay = START_DELAY_DOT_SCALE_DOWN_MS\n        dotScaleDownAnimator.interpolator = PathInterpolatorCompat\n            .create(0.4f, 0f, 0f, 1f)\n        dotScaleDownAnimator.addUpdateListener { animation ->\n            radiusScale = animation.animatedValue as Float\n            graphicOverlay.postInvalidate()\n        }\n\n        val dotFadeInAnimator = ValueAnimator.ofFloat(0f, 1f)\n            .setDuration(DURATION_DOT_FADE_IN_MS)\n        dotFadeInAnimator.addUpdateListener { animation ->\n            alphaScale = animation.animatedValue as Float\n            graphicOverlay.postInvalidate()\n        }\n\n        animatorSet = AnimatorSet()\n        animatorSet.playTogether(dotScaleUpAnimator, dotScaleDownAnimator, dotFadeInAnimator)\n    }\n\n    fun start() {\n        if (!animatorSet.isRunning) {\n            animatorSet.start()\n        }\n    }\n\n    fun cancel() {\n        animatorSet.cancel()\n        radiusScale = 0f\n        alphaScale = 0f\n    }\n\n    companion object {\n        // All these time constants are in millisecond unit.\n        private const val DURATION_DOT_SCALE_UP_MS: Long = 217\n        private const val DURATION_DOT_SCALE_DOWN_MS: Long = 783\n        private const val DURATION_DOT_FADE_IN_MS: Long = 150\n        private const val START_DELAY_DOT_SCALE_DOWN_MS: Long = 217\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/ObjectDotGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport android.graphics.Paint.Style\nimport android.graphics.PointF\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.GraphicOverlay.Graphic\nimport com.google.mlkit.md.R\n\n/** A dot to indicate a detected object used by multiple objects detection mode.  */\ninternal class ObjectDotGraphic(\n    overlay: GraphicOverlay,\n    detectedObject: DetectedObjectInfo,\n    private val animator: ObjectDotAnimator\n) : Graphic(overlay) {\n    private val paint: Paint\n    private val center: PointF\n    private val dotRadius: Int\n    private val dotAlpha: Int\n\n    init {\n\n        val box = detectedObject.boundingBox\n        center = PointF(\n            overlay.translateX((box.left + box.right) / 2f),\n            overlay.translateY((box.top + box.bottom) / 2f)\n        )\n\n        paint = Paint().apply {\n            style = Style.FILL\n            color = Color.WHITE\n        }\n\n        dotRadius = context.resources.getDimensionPixelOffset(R.dimen.object_dot_radius)\n        dotAlpha = paint.alpha\n    }\n\n    override fun draw(canvas: Canvas) {\n        paint.alpha = (dotAlpha * animator.alphaScale).toInt()\n        canvas.drawCircle(center.x, center.y, dotRadius * animator.radiusScale, paint)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/ObjectGraphicInMultiMode.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.LinearGradient\nimport android.graphics.Paint\nimport android.graphics.Paint.Style\nimport android.graphics.PorterDuff\nimport android.graphics.PorterDuffXfermode\nimport android.graphics.RectF\nimport android.graphics.Shader.TileMode\nimport androidx.annotation.ColorInt\nimport androidx.core.content.ContextCompat\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.GraphicOverlay.Graphic\nimport com.google.mlkit.md.R\n\n/**\n * Draws the detected detectedObject info over the camera preview for multiple objects detection mode.\n */\ninternal class ObjectGraphicInMultiMode(\n    overlay: GraphicOverlay,\n    private val detectedObject: DetectedObjectInfo,\n    private val confirmationController: ObjectConfirmationController\n) : Graphic(overlay) {\n\n    private val boxPaint: Paint\n    private val scrimPaint: Paint\n    private val eraserPaint: Paint\n\n    @ColorInt\n    private val boxGradientStartColor: Int\n\n    @ColorInt\n    private val boxGradientEndColor: Int\n    private val boxCornerRadius: Int\n    private val minBoxLen: Int\n\n    init {\n        val resources = context.resources\n        boxPaint = Paint().apply {\n            style = Style.STROKE\n            strokeWidth = resources.getDimensionPixelOffset(\n                if (confirmationController.isConfirmed) {\n                    R.dimen.bounding_box_confirmed_stroke_width\n                } else {\n                    R.dimen.bounding_box_stroke_width\n                }\n            ).toFloat()\n            color = Color.WHITE\n        }\n\n        boxGradientStartColor = ContextCompat.getColor(context, R.color.bounding_box_gradient_start)\n        boxGradientEndColor = ContextCompat.getColor(context, R.color.bounding_box_gradient_end)\n        boxCornerRadius = resources.getDimensionPixelOffset(R.dimen.bounding_box_corner_radius)\n\n        scrimPaint = Paint().apply {\n            shader = LinearGradient(\n                0f,\n                0f,\n                overlay.width.toFloat(),\n                overlay.height.toFloat(),\n                ContextCompat.getColor(context, R.color.object_confirmed_bg_gradient_start),\n                ContextCompat.getColor(context, R.color.object_confirmed_bg_gradient_end),\n                TileMode.MIRROR\n            )\n        }\n\n        eraserPaint = Paint().apply {\n            xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)\n        }\n\n        minBoxLen = resources.getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_stroke_radius) * 2\n    }\n\n    override fun draw(canvas: Canvas) {\n        var rect = overlay.translateRect(detectedObject.boundingBox)\n\n        val boxWidth = rect.width() * confirmationController.progress\n        val boxHeight = rect.height() * confirmationController.progress\n        if (boxWidth < minBoxLen || boxHeight < minBoxLen) {\n            // Don't draw the box if its length is too small, otherwise it will intersect with reticle so\n            // the UI looks messy.\n            return\n        }\n\n        val cx = (rect.left + rect.right) / 2\n        val cy = (rect.top + rect.bottom) / 2\n        rect = RectF(\n            cx - boxWidth / 2f,\n            cy - boxHeight / 2f,\n            cx + boxWidth / 2f,\n            cy + boxHeight / 2f\n        )\n\n        if (confirmationController.isConfirmed) {\n            // Draws the dark background scrim and leaves the detectedObject area clear.\n            canvas.drawRect(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat(), scrimPaint)\n            canvas.drawRoundRect(rect, boxCornerRadius.toFloat(), boxCornerRadius.toFloat(), eraserPaint)\n        }\n\n        boxPaint.shader = if (confirmationController.isConfirmed) {\n            null\n        } else {\n            LinearGradient(\n                rect.left,\n                rect.top,\n                rect.left,\n                rect.bottom,\n                boxGradientStartColor,\n                boxGradientEndColor,\n                TileMode.MIRROR\n            )\n        }\n        canvas.drawRoundRect(rect, boxCornerRadius.toFloat(), boxCornerRadius.toFloat(), boxPaint)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/ObjectGraphicInProminentMode.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.LinearGradient\nimport android.graphics.Paint\nimport android.graphics.Paint.Style\nimport android.graphics.PorterDuff\nimport android.graphics.PorterDuffXfermode\nimport android.graphics.Shader.TileMode\nimport androidx.annotation.ColorInt\nimport androidx.core.content.ContextCompat\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.GraphicOverlay.Graphic\nimport com.google.mlkit.md.R\nimport com.google.mlkit.vision.objects.DetectedObject\n\n/**\n * Draws the detected visionObject info over the camera preview for prominent visionObject detection mode.\n */\ninternal class ObjectGraphicInProminentMode(\n    overlay: GraphicOverlay,\n    private val visionObject: DetectedObject,\n    private val confirmationController: ObjectConfirmationController\n) : Graphic(overlay) {\n\n    private val scrimPaint: Paint = Paint()\n    private val eraserPaint: Paint\n    private val boxPaint: Paint\n\n    @ColorInt\n    private val boxGradientStartColor: Int\n\n    @ColorInt\n    private val boxGradientEndColor: Int\n    private val boxCornerRadius: Int\n\n    init {\n        // Sets up a gradient background color at vertical.\n        scrimPaint.shader = if (confirmationController.isConfirmed) {\n            LinearGradient(\n                0f,\n                0f,\n                overlay.width.toFloat(),\n                overlay.height.toFloat(),\n                ContextCompat.getColor(context, R.color.object_confirmed_bg_gradient_start),\n                ContextCompat.getColor(context, R.color.object_confirmed_bg_gradient_end),\n                TileMode.CLAMP\n            )\n        } else {\n            LinearGradient(\n                0f,\n                0f,\n                overlay.width.toFloat(),\n                overlay.height.toFloat(),\n                ContextCompat.getColor(context, R.color.object_detected_bg_gradient_start),\n                ContextCompat.getColor(context, R.color.object_detected_bg_gradient_end),\n                TileMode.CLAMP\n            )\n        }\n\n        eraserPaint = Paint().apply {\n            xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)\n        }\n\n        boxPaint = Paint().apply {\n            style = Style.STROKE\n            strokeWidth = context\n                .resources\n                .getDimensionPixelOffset(\n                    if (confirmationController.isConfirmed) {\n                        R.dimen.bounding_box_confirmed_stroke_width\n                    } else {\n                        R.dimen.bounding_box_stroke_width\n                    }\n                ).toFloat()\n            color = Color.WHITE\n        }\n\n        boxGradientStartColor = ContextCompat.getColor(context, R.color.bounding_box_gradient_start)\n        boxGradientEndColor = ContextCompat.getColor(context, R.color.bounding_box_gradient_end)\n        boxCornerRadius = context.resources.getDimensionPixelOffset(R.dimen.bounding_box_corner_radius)\n    }\n\n    override fun draw(canvas: Canvas) {\n        val rect = overlay.translateRect(visionObject.boundingBox)\n\n        // Draws the dark background scrim and leaves the visionObject area clear.\n        canvas.drawRect(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat(), scrimPaint)\n        canvas.drawRoundRect(rect, boxCornerRadius.toFloat(), boxCornerRadius.toFloat(), eraserPaint)\n\n        // Draws the bounding box with a gradient border color at vertical.\n        boxPaint.shader = if (confirmationController.isConfirmed) {\n            null\n        } else {\n            LinearGradient(\n                rect.left,\n                rect.top,\n                rect.left,\n                rect.bottom,\n                boxGradientStartColor,\n                boxGradientEndColor,\n                TileMode.CLAMP\n            )\n        }\n        canvas.drawRoundRect(rect, boxCornerRadius.toFloat(), boxCornerRadius.toFloat(), boxPaint)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/ObjectReticleGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.graphics.Canvas\nimport android.graphics.Paint\nimport android.graphics.Paint.Cap\nimport android.graphics.Paint.Style\nimport androidx.core.content.ContextCompat\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.camera.GraphicOverlay.Graphic\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.camera.CameraReticleAnimator\n\n/**\n * A camera reticle that locates at the center of canvas to indicate the system is active but has\n * not recognized an object yet.\n */\ninternal class ObjectReticleGraphic(overlay: GraphicOverlay, private val animator: CameraReticleAnimator) :\n    Graphic(overlay) {\n\n    private val outerRingFillPaint: Paint\n    private val outerRingStrokePaint: Paint\n    private val innerRingStrokePaint: Paint\n    private val ripplePaint: Paint\n    private val outerRingFillRadius: Int\n    private val outerRingStrokeRadius: Int\n    private val innerRingStrokeRadius: Int\n    private val rippleSizeOffset: Int\n    private val rippleStrokeWidth: Int\n    private val rippleAlpha: Int\n\n    init {\n\n        val resources = overlay.resources\n        outerRingFillPaint = Paint().apply {\n            style = Style.FILL\n            color = ContextCompat.getColor(context, R.color.object_reticle_outer_ring_fill)\n        }\n\n        outerRingStrokePaint = Paint().apply {\n            style = Style.STROKE\n            strokeWidth = resources.getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_stroke_width).toFloat()\n            strokeCap = Cap.ROUND\n            color = ContextCompat.getColor(context, R.color.object_reticle_outer_ring_stroke)\n        }\n\n        innerRingStrokePaint = Paint().apply {\n            style = Style.STROKE\n            strokeWidth = resources.getDimensionPixelOffset(R.dimen.object_reticle_inner_ring_stroke_width).toFloat()\n            strokeCap = Cap.ROUND\n            color = ContextCompat.getColor(context, R.color.white)\n        }\n\n        ripplePaint = Paint().apply {\n            style = Style.STROKE\n            color = ContextCompat.getColor(context, R.color.reticle_ripple)\n        }\n\n        outerRingFillRadius = resources.getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_fill_radius)\n        outerRingStrokeRadius = resources.getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_stroke_radius)\n        innerRingStrokeRadius = resources.getDimensionPixelOffset(R.dimen.object_reticle_inner_ring_stroke_radius)\n        rippleSizeOffset = resources.getDimensionPixelOffset(R.dimen.object_reticle_ripple_size_offset)\n        rippleStrokeWidth = resources.getDimensionPixelOffset(R.dimen.object_reticle_ripple_stroke_width)\n        rippleAlpha = ripplePaint.alpha\n    }\n\n    override fun draw(canvas: Canvas) {\n        val cx = canvas.width / 2f\n        val cy = canvas.height / 2f\n        canvas.drawCircle(cx, cy, outerRingFillRadius.toFloat(), outerRingFillPaint)\n        canvas.drawCircle(cx, cy, outerRingStrokeRadius.toFloat(), outerRingStrokePaint)\n        canvas.drawCircle(cx, cy, innerRingStrokeRadius.toFloat(), innerRingStrokePaint)\n\n        // Draws the ripple to simulate the breathing animation effect.\n        ripplePaint.alpha = (rippleAlpha * animator.rippleAlphaScale).toInt()\n        ripplePaint.strokeWidth = rippleStrokeWidth * animator.rippleStrokeWidthScale\n        val radius = outerRingStrokeRadius + rippleSizeOffset * animator.rippleSizeScale\n        canvas.drawCircle(cx, cy, radius, ripplePaint)\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/ProminentObjectProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.graphics.RectF\nimport android.util.Log\nimport androidx.annotation.MainThread\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.md.camera.CameraReticleAnimator\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.camera.WorkflowModel\nimport com.google.mlkit.md.camera.WorkflowModel.WorkflowState\nimport com.google.mlkit.md.camera.FrameProcessorBase\nimport com.google.mlkit.md.settings.PreferenceUtils\nimport com.google.mlkit.common.model.LocalModel\nimport com.google.mlkit.md.InputInfo\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.objects.DetectedObject\nimport com.google.mlkit.vision.objects.ObjectDetection\nimport com.google.mlkit.vision.objects.ObjectDetector\nimport com.google.mlkit.vision.objects.ObjectDetectorOptionsBase\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions\nimport java.io.IOException\nimport java.util.ArrayList\n\n/** A processor to run object detector in prominent object only mode.  */\nclass ProminentObjectProcessor(\n  graphicOverlay: GraphicOverlay,\n  private val workflowModel: WorkflowModel,\n  private val customModelPath: String? = null) :\n    FrameProcessorBase<List<DetectedObject>>() {\n\n    private val detector: ObjectDetector\n    private val confirmationController: ObjectConfirmationController = ObjectConfirmationController(graphicOverlay)\n    private val cameraReticleAnimator: CameraReticleAnimator = CameraReticleAnimator(graphicOverlay)\n    private val reticleOuterRingRadius: Int = graphicOverlay\n            .resources\n            .getDimensionPixelOffset(R.dimen.object_reticle_outer_ring_stroke_radius)\n\n    init {\n        val options: ObjectDetectorOptionsBase\n        val isClassificationEnabled = PreferenceUtils.isClassificationEnabled(graphicOverlay.context)\n        if (customModelPath != null) {\n            val localModel = LocalModel.Builder()\n                .setAssetFilePath(customModelPath)\n                .build()\n            options = CustomObjectDetectorOptions.Builder(localModel)\n                .setDetectorMode(ObjectDetectorOptions.STREAM_MODE)\n                .enableClassification() // Always enable classification for custom models\n                .build()\n        } else {\n            val optionsBuilder = ObjectDetectorOptions.Builder()\n                    .setDetectorMode(ObjectDetectorOptions.STREAM_MODE)\n            if (isClassificationEnabled) {\n                optionsBuilder.enableClassification()\n            }\n            options = optionsBuilder.build()\n        }\n\n        this.detector = ObjectDetection.getClient(options)\n    }\n\n    override fun stop() {\n        super.stop()\n        try {\n            detector.close()\n        } catch (e: IOException) {\n            Log.e(TAG, \"Failed to close object detector!\", e)\n        }\n    }\n\n    override fun detectInImage(image: InputImage): Task<List<DetectedObject>> {\n        return detector.process(image)\n    }\n\n    @MainThread\n    override fun onSuccess(\n        inputInfo: InputInfo,\n        results: List<DetectedObject>,\n        graphicOverlay: GraphicOverlay\n    ) {\n        var objects = results\n        if (!workflowModel.isCameraLive) {\n            return\n        }\n\n        if (PreferenceUtils.isClassificationEnabled(graphicOverlay.context)) {\n            val qualifiedObjects = ArrayList<DetectedObject>()\n            qualifiedObjects.addAll(objects)\n            objects = qualifiedObjects\n        }\n\n        val objectIndex = 0\n        val hasValidObjects = objects.isNotEmpty() &&\n            (customModelPath == null || DetectedObjectInfo.hasValidLabels(objects[objectIndex]))\n        if (!hasValidObjects) {\n            confirmationController.reset()\n            workflowModel.setWorkflowState(WorkflowState.DETECTING)\n        } else {\n            val visionObject = objects[objectIndex]\n            if (objectBoxOverlapsConfirmationReticle(graphicOverlay, visionObject)) {\n                // User is confirming the object selection.\n                confirmationController.confirming(visionObject.trackingId)\n                workflowModel.confirmingObject(\n                        DetectedObjectInfo(visionObject, objectIndex, inputInfo), confirmationController.progress\n                )\n            } else {\n                // Object detected but user doesn't want to pick this one.\n                confirmationController.reset()\n                workflowModel.setWorkflowState(WorkflowState.DETECTED)\n            }\n        }\n\n        graphicOverlay.clear()\n        if (!hasValidObjects) {\n            graphicOverlay.add(ObjectReticleGraphic(graphicOverlay, cameraReticleAnimator))\n            cameraReticleAnimator.start()\n        } else {\n            if (objectBoxOverlapsConfirmationReticle(graphicOverlay, objects[0])) {\n                // User is confirming the object selection.\n                cameraReticleAnimator.cancel()\n                graphicOverlay.add(\n                        ObjectGraphicInProminentMode(\n                                graphicOverlay, objects[0], confirmationController\n                        )\n                )\n                if (!confirmationController.isConfirmed &&\n                    PreferenceUtils.isAutoSearchEnabled(graphicOverlay.context)) {\n                    // Shows a loading indicator to visualize the confirming progress if in auto search mode.\n                    graphicOverlay.add(ObjectConfirmationGraphic(graphicOverlay, confirmationController))\n                }\n            } else {\n                // Object is detected but the confirmation reticle is moved off the object box, which\n                // indicates user is not trying to pick this object.\n                graphicOverlay.add(\n                        ObjectGraphicInProminentMode(\n                                graphicOverlay, objects[0], confirmationController\n                        )\n                )\n                graphicOverlay.add(ObjectReticleGraphic(graphicOverlay, cameraReticleAnimator))\n                cameraReticleAnimator.start()\n            }\n        }\n        graphicOverlay.invalidate()\n    }\n\n    private fun objectBoxOverlapsConfirmationReticle(\n        graphicOverlay: GraphicOverlay,\n        visionObject: DetectedObject\n    ): Boolean {\n        val boxRect = graphicOverlay.translateRect(visionObject.boundingBox)\n        val reticleCenterX = graphicOverlay.width / 2f\n        val reticleCenterY = graphicOverlay.height / 2f\n        val reticleRect = RectF(\n                reticleCenterX - reticleOuterRingRadius,\n                reticleCenterY - reticleOuterRingRadius,\n                reticleCenterX + reticleOuterRingRadius,\n                reticleCenterY + reticleOuterRingRadius\n        )\n        return reticleRect.intersect(boxRect)\n    }\n\n    override fun onFailure(e: Exception) {\n        Log.e(TAG, \"Object detection failed!\", e)\n    }\n\n    companion object {\n        private const val TAG = \"ProminentObjProcessor\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/objectdetection/StaticObjectDotView.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.objectdetection\n\nimport android.animation.ValueAnimator\nimport android.content.Context\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport android.view.View\nimport androidx.interpolator.view.animation.FastOutSlowInInterpolator\nimport com.google.mlkit.md.R\n\n/** Represents a detected object by drawing a circle dot at the center of object's bounding box.  */\nclass StaticObjectDotView @JvmOverloads constructor(context: Context, selected: Boolean = false) : View(context) {\n\n    private val paint: Paint = Paint().apply {\n        style = Paint.Style.FILL\n    }\n    private val unselectedDotRadius: Int =\n        context.resources.getDimensionPixelOffset(R.dimen.static_image_dot_radius_unselected)\n    private val radiusOffsetRange: Int\n\n    private var currentRadiusOffset: Float = 0.toFloat()\n\n    init {\n        val selectedDotRadius = context.resources.getDimensionPixelOffset(R.dimen.static_image_dot_radius_selected)\n        radiusOffsetRange = selectedDotRadius - unselectedDotRadius\n        currentRadiusOffset = (if (selected) radiusOffsetRange else 0).toFloat()\n    }\n\n    fun playAnimationWithSelectedState(selected: Boolean) {\n        val radiusOffsetAnimator: ValueAnimator =\n            if (selected) {\n                ValueAnimator.ofFloat(0f, radiusOffsetRange.toFloat())\n                    .setDuration(DOT_SELECTION_ANIMATOR_DURATION_MS).apply {\n                        startDelay = DOT_DESELECTION_ANIMATOR_DURATION_MS\n                    }\n            } else {\n                ValueAnimator.ofFloat(radiusOffsetRange.toFloat(), 0f)\n                    .setDuration(DOT_DESELECTION_ANIMATOR_DURATION_MS)\n            }\n\n        radiusOffsetAnimator.interpolator = FastOutSlowInInterpolator()\n        radiusOffsetAnimator.addUpdateListener { animation ->\n            currentRadiusOffset = animation.animatedValue as Float\n            invalidate()\n        }\n        radiusOffsetAnimator.start()\n    }\n\n    override fun onDraw(canvas: Canvas) {\n        super.onDraw(canvas)\n        val cx = width / 2f\n        val cy = height / 2f\n        paint.color = Color.WHITE\n        canvas.drawCircle(cx, cy, unselectedDotRadius + currentRadiusOffset, paint)\n    }\n\n    companion object {\n        private const val DOT_SELECTION_ANIMATOR_DURATION_MS: Long = 116\n        private const val DOT_DESELECTION_ANIMATOR_DURATION_MS: Long = 67\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/productsearch/BottomSheetScrimView.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.productsearch\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport android.graphics.RectF\nimport android.util.AttributeSet\nimport android.view.View\nimport androidx.core.content.ContextCompat\nimport com.google.common.base.Preconditions.checkArgument\nimport com.google.mlkit.md.R\n\n/** Draws the scrim of bottom sheet with object thumbnail highlighted.  */\nclass BottomSheetScrimView(context: Context, attrs: AttributeSet) : View(context, attrs) {\n\n    private val scrimPaint: Paint\n    private val thumbnailPaint: Paint\n    private val boxPaint: Paint\n    private val thumbnailHeight: Int\n    private val thumbnailMargin: Int\n    private val boxCornerRadius: Int\n\n    private var thumbnailBitmap: Bitmap? = null\n    private var thumbnailRect: RectF? = null\n    private var downPercentInCollapsed: Float = 0f\n\n    init {\n        val resources = context.resources\n        scrimPaint = Paint().apply {\n            color = ContextCompat.getColor(context, R.color.dark)\n        }\n\n        thumbnailPaint = Paint()\n\n        boxPaint = Paint().apply {\n            style = Paint.Style.STROKE\n            strokeWidth = resources.getDimensionPixelOffset(R.dimen.object_thumbnail_stroke_width).toFloat()\n            color = Color.WHITE\n        }\n\n        thumbnailHeight = resources.getDimensionPixelOffset(R.dimen.object_thumbnail_height)\n        thumbnailMargin = resources.getDimensionPixelOffset(R.dimen.object_thumbnail_margin)\n        boxCornerRadius = resources.getDimensionPixelOffset(R.dimen.bounding_box_corner_radius)\n    }\n\n    /**\n     * Translates the object thumbnail up or down along with bottom sheet's sliding movement, with\n     * keeping thumbnail size fixed.\n     */\n    fun updateWithThumbnailTranslate(\n        thumbnailBitmap: Bitmap,\n        collapsedStateHeight: Int,\n        slideOffset: Float,\n        bottomSheet: View\n    ) {\n        this.thumbnailBitmap = thumbnailBitmap\n\n        val currentSheetHeight: Float\n        if (slideOffset < 0) {\n            downPercentInCollapsed = -slideOffset\n            currentSheetHeight = collapsedStateHeight * (1 + slideOffset)\n        } else {\n            downPercentInCollapsed = 0f\n            currentSheetHeight = collapsedStateHeight + (bottomSheet.height - collapsedStateHeight) * slideOffset\n        }\n\n        thumbnailRect = RectF().apply {\n            val thumbnailWidth =\n                thumbnailBitmap.width.toFloat() / thumbnailBitmap.height.toFloat() * thumbnailHeight.toFloat()\n            left = thumbnailMargin.toFloat()\n            top = height.toFloat() - currentSheetHeight - thumbnailMargin.toFloat() - thumbnailHeight.toFloat()\n            right = left + thumbnailWidth\n            bottom = top + thumbnailHeight\n        }\n\n        invalidate()\n    }\n\n    /**\n     * Translates the object thumbnail from original bounding box location to at where the bottom\n     * sheet is settled as COLLAPSED state, with its size scales gradually.\n     *\n     *\n     * It's only used by sliding the sheet up from hidden state to collapsed state.\n     */\n    fun updateWithThumbnailTranslateAndScale(\n        thumbnailBitmap: Bitmap,\n        collapsedStateHeight: Int,\n        slideOffset: Float,\n        srcThumbnailRect: RectF\n    ) {\n        checkArgument(\n            slideOffset <= 0,\n            \"Scale mode works only when the sheet is between hidden and collapsed states.\"\n        )\n\n        this.thumbnailBitmap = thumbnailBitmap\n        this.downPercentInCollapsed = 0f\n\n        thumbnailRect = RectF().apply {\n            val dstX = thumbnailMargin.toFloat()\n            val dstY = (height - collapsedStateHeight - thumbnailMargin - thumbnailHeight).toFloat()\n            val dstHeight = thumbnailHeight.toFloat()\n            val dstWidth = srcThumbnailRect.width() / srcThumbnailRect.height() * dstHeight\n            val dstRect = RectF(dstX, dstY, dstX + dstWidth, dstY + dstHeight)\n\n            val progressToCollapsedState = 1 + slideOffset\n            left = srcThumbnailRect.left + (dstRect.left - srcThumbnailRect.left) * progressToCollapsedState\n            top = srcThumbnailRect.top + (dstRect.top - srcThumbnailRect.top) * progressToCollapsedState\n            right = srcThumbnailRect.right + (dstRect.right - srcThumbnailRect.right) * progressToCollapsedState\n            bottom = srcThumbnailRect.bottom + (dstRect.bottom - srcThumbnailRect.bottom) * progressToCollapsedState\n        }\n\n        invalidate()\n    }\n\n    override fun onDraw(canvas: Canvas) {\n        super.onDraw(canvas)\n\n        // Draws the dark background.\n        val bitmap = thumbnailBitmap ?: return\n        val rect = thumbnailRect ?: return\n        canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), scrimPaint)\n        if (downPercentInCollapsed < DOWN_PERCENT_TO_HIDE_THUMBNAIL) {\n            val alpha = ((1 - downPercentInCollapsed / DOWN_PERCENT_TO_HIDE_THUMBNAIL) * 255).toInt()\n\n            // Draws the object thumbnail.\n            thumbnailPaint.alpha = alpha\n            canvas.drawBitmap(bitmap, null, rect, thumbnailPaint)\n\n            // Draws the bounding box.\n            boxPaint.alpha = alpha\n            canvas.drawRoundRect(rect, boxCornerRadius.toFloat(), boxCornerRadius.toFloat(), boxPaint)\n        }\n    }\n\n    companion object {\n        private const val DOWN_PERCENT_TO_HIDE_THUMBNAIL = 0.42f\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/productsearch/ImageDownloadTask.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.productsearch\n\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.os.AsyncTask\nimport android.text.TextUtils\nimport android.util.Log\nimport android.widget.ImageView\nimport java.net.URL\n\n/** todo: migrate to Coroutines. */\n/** Async task to download the image and then feed into the provided image view.  */\ninternal class ImageDownloadTask(private val imageView: ImageView, private val maxImageWidth: Int) :\n    AsyncTask<String, Void, Bitmap>() {\n\n    override fun doInBackground(vararg urls: String): Bitmap? {\n        if (TextUtils.isEmpty(urls[0])) {\n            return null\n        }\n\n        var bitmap: Bitmap? = null\n        try {\n            val inputStream = URL(urls[0]).openStream()\n            bitmap = BitmapFactory.decodeStream(inputStream)\n            inputStream.close()\n        } catch (e: Exception) {\n            Log.e(TAG, \"Image download failed: ${urls[0]}\")\n        }\n\n        if (bitmap != null && bitmap.width > maxImageWidth) {\n            val dstHeight = (maxImageWidth.toFloat() / bitmap.width * bitmap.height).toInt()\n            bitmap = Bitmap.createScaledBitmap(bitmap, maxImageWidth, dstHeight, /* filter= */ false)\n        }\n        return bitmap\n    }\n\n    override fun onPostExecute(result: Bitmap?) {\n        result?.let {\n            imageView.setImageBitmap(result)\n        }\n    }\n\n    companion object {\n        private const val TAG = \"ImageDownloadTask\"\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/productsearch/PreviewCardAdapter.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.productsearch\n\nimport android.text.TextUtils\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.mlkit.md.R\n\n/** Powers the bottom card carousel for displaying the preview of product search result.  */\nclass PreviewCardAdapter(\n    private val searchedObjectList: List<SearchedObject>,\n    private val previewCordClickedListener: (searchedObject: SearchedObject) -> Any\n) : RecyclerView.Adapter<PreviewCardAdapter.CardViewHolder>() {\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {\n        return CardViewHolder(\n            LayoutInflater.from(parent.context)\n                .inflate(R.layout.products_preview_card, parent, false)\n        )\n    }\n\n    override fun onBindViewHolder(holder: CardViewHolder, position: Int) {\n        val searchedObject = searchedObjectList[position]\n        holder.bindProducts(searchedObject.productList)\n        holder.itemView.setOnClickListener { previewCordClickedListener.invoke(searchedObject) }\n    }\n\n    override fun getItemCount(): Int = searchedObjectList.size\n\n    class CardViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {\n\n        private val imageView: ImageView = itemView.findViewById(R.id.card_image)\n        private val titleView: TextView = itemView.findViewById(R.id.card_title)\n        private val subtitleView: TextView = itemView.findViewById(R.id.card_subtitle)\n        private val imageSize: Int = itemView.resources.getDimensionPixelOffset(R.dimen.preview_card_image_size)\n\n        internal fun bindProducts(products: List<Product>) {\n            if (products.isEmpty()) {\n                imageView.visibility = View.GONE\n                titleView.setText(R.string.static_image_card_no_result_title)\n                subtitleView.setText(R.string.static_image_card_no_result_subtitle)\n            } else {\n                val topProduct = products[0]\n                imageView.visibility = View.VISIBLE\n                imageView.setImageDrawable(null)\n                if (!TextUtils.isEmpty(topProduct.imageUrl)) {\n                    ImageDownloadTask(imageView, imageSize).execute(topProduct.imageUrl)\n                } else {\n                    imageView.setImageResource(R.drawable.logo_google_cloud)\n                }\n                titleView.text = topProduct.title\n                subtitleView.text = itemView\n                    .resources\n                    .getString(R.string.static_image_preview_card_subtitle, products.size - 1)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/productsearch/Product.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.productsearch\n\n/** Information about a product.  */\ndata class Product internal constructor(val imageUrl: String, val title: String, val subtitle: String)\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/productsearch/ProductAdapter.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.productsearch\n\nimport android.text.TextUtils\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.recyclerview.widget.RecyclerView\nimport androidx.recyclerview.widget.RecyclerView.Adapter\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.productsearch.ProductAdapter.ProductViewHolder\n\n/** Presents the list of product items from cloud product search.  */\nclass ProductAdapter(private val productList: List<Product>) : Adapter<ProductViewHolder>() {\n\n    class ProductViewHolder private constructor(view: View) : RecyclerView.ViewHolder(view) {\n\n        private val imageView: ImageView = view.findViewById(R.id.product_image)\n        private val titleView: TextView = view.findViewById(R.id.product_title)\n        private val subtitleView: TextView = view.findViewById(R.id.product_subtitle)\n        private val imageSize: Int = view.resources.getDimensionPixelOffset(R.dimen.product_item_image_size)\n\n        fun bindProduct(product: Product) {\n            imageView.setImageDrawable(null)\n            if (!TextUtils.isEmpty(product.imageUrl)) {\n                ImageDownloadTask(imageView, imageSize).execute(product.imageUrl)\n            } else {\n                imageView.setImageResource(R.drawable.logo_google_cloud)\n            }\n            titleView.text = product.title\n            subtitleView.text = product.subtitle\n        }\n\n        companion object {\n            fun create(parent: ViewGroup) =\n                ProductViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.product_item, parent, false))\n        }\n    }\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder =\n        ProductViewHolder.create(parent)\n\n    override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {\n        holder.bindProduct(productList[position])\n    }\n\n    override fun getItemCount(): Int = productList.size\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/productsearch/SearchEngine.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.productsearch\n\nimport android.content.Context\nimport android.util.Log\nimport com.android.volley.RequestQueue\nimport com.android.volley.toolbox.JsonObjectRequest\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.tasks.Tasks\nimport com.google.mlkit.md.objectdetection.DetectedObjectInfo\nimport java.util.ArrayList\nimport java.util.concurrent.Callable\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\n\n/** A fake search engine to help simulate the complete work flow.  */\nclass SearchEngine(context: Context) {\n\n    private val searchRequestQueue: RequestQueue = Volley.newRequestQueue(context)\n    private val requestCreationExecutor: ExecutorService = Executors.newSingleThreadExecutor()\n\n    fun search(\n        detectedObject: DetectedObjectInfo,\n        listener: (detectedObject: DetectedObjectInfo, productList: List<Product>) -> Unit\n    ) {\n        // Crops the object image out of the full image is expensive, so do it off the UI thread.\n        Tasks.call<JsonObjectRequest>(requestCreationExecutor, Callable { createRequest(detectedObject) })\n            .addOnSuccessListener { productRequest -> searchRequestQueue.add(productRequest.setTag(TAG)) }\n            .addOnFailureListener { e ->\n                Log.e(TAG, \"Failed to create product search request!\", e)\n                // Remove the below dummy code after your own product search backed hooked up.\n                val productList = ArrayList<Product>()\n                for (i in 0..7) {\n                    productList.add(\n                        Product(/* imageUrl= */\"\", \"Product title $i\", \"Product subtitle $i\")\n                    )\n                }\n                listener.invoke(detectedObject, productList)\n            }\n    }\n\n    fun shutdown() {\n        searchRequestQueue.cancelAll(TAG)\n        requestCreationExecutor.shutdown()\n    }\n\n    companion object {\n        private const val TAG = \"SearchEngine\"\n\n        @Throws(Exception::class)\n        private fun createRequest(searchingObject: DetectedObjectInfo): JsonObjectRequest {\n            val objectImageData = searchingObject.imageData\n                ?: throw Exception(\"Failed to get object image data!\")\n\n            // Hooks up with your own product search backend here.\n            throw Exception(\"Hooks up with your own product search backend.\")\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/productsearch/SearchedObject.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.productsearch\n\nimport android.content.res.Resources\nimport android.graphics.Bitmap\nimport android.graphics.Rect\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.Utils\nimport com.google.mlkit.md.objectdetection.DetectedObjectInfo\n\n/** Hosts the detected object info and its search result.  */\nclass SearchedObject(\n    resources: Resources,\n    private val detectedObject: DetectedObjectInfo,\n    val productList: List<Product>\n) {\n\n    private val objectThumbnailCornerRadius: Int = resources.getDimensionPixelOffset(R.dimen.bounding_box_corner_radius)\n    private var objectThumbnail: Bitmap? = null\n\n    val objectIndex: Int\n        get() = detectedObject.objectIndex\n\n    val boundingBox: Rect\n        get() = detectedObject.boundingBox\n\n    @Synchronized\n    fun getObjectThumbnail(): Bitmap = objectThumbnail ?: let {\n        Utils.getCornerRoundedBitmap(detectedObject.getBitmap(), objectThumbnailCornerRadius)\n            .also { objectThumbnail = it }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/settings/PreferenceUtils.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.settings\n\nimport android.content.Context\nimport android.graphics.RectF\nimport android.preference.PreferenceManager\nimport androidx.annotation.StringRes\nimport com.google.android.gms.common.images.Size\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.camera.CameraSizePair\nimport com.google.mlkit.md.camera.GraphicOverlay\nimport com.google.mlkit.vision.barcode.common.Barcode\n\n/** Utility class to retrieve shared preferences. */\nobject PreferenceUtils {\n\n  fun isAutoSearchEnabled(context: Context): Boolean =\n    getBooleanPref(context, R.string.pref_key_enable_auto_search, true)\n\n  fun isMultipleObjectsMode(context: Context): Boolean =\n    getBooleanPref(context, R.string.pref_key_object_detector_enable_multiple_objects, false)\n\n  fun isClassificationEnabled(context: Context): Boolean =\n    getBooleanPref(context, R.string.pref_key_object_detector_enable_classification, false)\n\n  fun saveStringPreference(context: Context, @StringRes prefKeyId: Int, value: String?) {\n    PreferenceManager.getDefaultSharedPreferences(context)\n      .edit()\n      .putString(context.getString(prefKeyId), value)\n      .apply()\n  }\n\n  fun getConfirmationTimeMs(context: Context): Int =\n    when {\n      isMultipleObjectsMode(context) -> 300\n      isAutoSearchEnabled(context) ->\n        getIntPref(context, R.string.pref_key_confirmation_time_in_auto_search, 1500)\n      else -> getIntPref(context, R.string.pref_key_confirmation_time_in_manual_search, 500)\n    }\n\n  fun getProgressToMeetBarcodeSizeRequirement(overlay: GraphicOverlay, barcode: Barcode): Float {\n    val context = overlay.context\n    return if (getBooleanPref(context, R.string.pref_key_enable_barcode_size_check, false)) {\n      val reticleBoxWidth = getBarcodeReticleBox(overlay).width()\n      val barcodeWidth = overlay.translateX(barcode.boundingBox?.width()?.toFloat() ?: 0f)\n      val requiredWidth =\n        reticleBoxWidth * getIntPref(context, R.string.pref_key_minimum_barcode_width, 50) / 100\n      (barcodeWidth / requiredWidth).coerceAtMost(1f)\n    } else {\n      1f\n    }\n  }\n\n  fun getBarcodeReticleBox(overlay: GraphicOverlay): RectF {\n    val context = overlay.context\n    val overlayWidth = overlay.width.toFloat()\n    val overlayHeight = overlay.height.toFloat()\n    val boxWidth =\n      overlayWidth * getIntPref(context, R.string.pref_key_barcode_reticle_width, 80) / 100\n    val boxHeight =\n      overlayHeight * getIntPref(context, R.string.pref_key_barcode_reticle_height, 35) / 100\n    val cx = overlayWidth / 2\n    val cy = overlayHeight / 2\n    return RectF(cx - boxWidth / 2, cy - boxHeight / 2, cx + boxWidth / 2, cy + boxHeight / 2)\n  }\n\n  fun shouldDelayLoadingBarcodeResult(context: Context): Boolean =\n    getBooleanPref(context, R.string.pref_key_delay_loading_barcode_result, true)\n\n  private fun getIntPref(context: Context, @StringRes prefKeyId: Int, defaultValue: Int): Int {\n    val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)\n    val prefKey = context.getString(prefKeyId)\n    return sharedPreferences.getInt(prefKey, defaultValue)\n  }\n\n  fun getUserSpecifiedPreviewSize(context: Context): CameraSizePair? {\n    return try {\n      val previewSizePrefKey = context.getString(R.string.pref_key_rear_camera_preview_size)\n      val pictureSizePrefKey = context.getString(R.string.pref_key_rear_camera_picture_size)\n      val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)\n      CameraSizePair(\n        Size.parseSize(sharedPreferences.getString(previewSizePrefKey, null)!!),\n        Size.parseSize(sharedPreferences.getString(pictureSizePrefKey, null)!!)\n      )\n    } catch (e: Exception) {\n      null\n    }\n  }\n\n  private fun getBooleanPref(\n    context: Context,\n    @StringRes prefKeyId: Int,\n    defaultValue: Boolean\n  ): Boolean =\n    PreferenceManager.getDefaultSharedPreferences(context)\n      .getBoolean(context.getString(prefKeyId), defaultValue)\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/settings/SettingsActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.settings\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.md.R\n\n/** Hosts the preference fragment to configure settings.  */\nclass SettingsActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        setContentView(R.layout.activity_settings)\n        supportActionBar?.setDisplayHomeAsUpEnabled(true)\n        supportFragmentManager\n            .beginTransaction()\n            .replace(R.id.settings_container, SettingsFragment())\n            .commit()\n    }\n\n    override fun onSupportNavigateUp(): Boolean {\n        onBackPressed()\n        return true\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/java/com/google/mlkit/md/settings/SettingsFragment.kt",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.md.settings\n\nimport android.hardware.Camera\nimport android.os.Bundle\nimport androidx.preference.ListPreference\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.mlkit.md.camera.CameraSource\nimport com.google.mlkit.md.R\nimport com.google.mlkit.md.Utils\nimport java.util.HashMap\n\n/** Configures App settings.  */\nclass SettingsFragment : PreferenceFragmentCompat() {\n\n    override fun onCreatePreferences(bundle: Bundle?, rootKey: String?) {\n        setPreferencesFromResource(R.xml.preferences, rootKey)\n        setUpRearCameraPreviewSizePreference()\n    }\n\n    private fun setUpRearCameraPreviewSizePreference() {\n        val previewSizePreference =\n            findPreference<ListPreference>(getString(R.string.pref_key_rear_camera_preview_size))!!\n\n        var camera: Camera? = null\n\n        try {\n            camera = Camera.open(CameraSource.CAMERA_FACING_BACK)\n            val previewSizeList = Utils.generateValidPreviewSizeList(camera!!)\n            val previewSizeStringValues = arrayOfNulls<String>(previewSizeList.size)\n            val previewToPictureSizeStringMap = HashMap<String, String>()\n            for (i in previewSizeList.indices) {\n                val sizePair = previewSizeList[i]\n                previewSizeStringValues[i] = sizePair.preview.toString()\n                if (sizePair.picture != null) {\n                    previewToPictureSizeStringMap[sizePair.preview.toString()] = sizePair.picture.toString()\n                }\n            }\n            previewSizePreference.entries = previewSizeStringValues\n            previewSizePreference.entryValues = previewSizeStringValues\n            previewSizePreference.summary = previewSizePreference.entry\n            previewSizePreference.setOnPreferenceChangeListener { _, newValue ->\n                val newPreviewSizeStringValue = newValue as String\n                val context = activity ?: return@setOnPreferenceChangeListener false\n                previewSizePreference.summary = newPreviewSizeStringValue\n                PreferenceUtils.saveStringPreference(\n                    context,\n                    R.string.pref_key_rear_camera_picture_size,\n                    previewToPictureSizeStringMap[newPreviewSizeStringValue]\n                )\n                true\n            }\n        } catch (e: Exception) {\n            // If there's no camera for the given camera id, hide the corresponding preference.\n            previewSizePreference.parent?.removePreference(previewSizePreference)\n        } finally {\n            camera?.release()\n        }\n    }\n}\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/animator/bottom_prompt_chip_enter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:ordering=\"together\">\n  <objectAnimator\n      android:duration=\"150\"\n      android:interpolator=\"@interpolator/mtrl_linear_out_slow_in\"\n      android:propertyName=\"scaleX\"\n      android:valueFrom=\"0.8\"\n      android:valueTo=\"1\"/>\n  <objectAnimator\n      android:duration=\"150\"\n      android:interpolator=\"@interpolator/mtrl_linear_out_slow_in\"\n      android:propertyName=\"scaleY\"\n      android:valueFrom=\"0.8\"\n      android:valueTo=\"1\"/>\n  <objectAnimator\n      android:duration=\"75\"\n      android:propertyName=\"alpha\"\n      android:valueFrom=\"0\"\n      android:valueTo=\"1\"/>\n</set>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/animator/search_button_enter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:ordering=\"together\">\n  <set android:ordering=\"sequentially\">\n    <objectAnimator\n        android:duration=\"150\"\n        android:interpolator=\"@interpolator/mtrl_fast_out_slow_in\"\n        android:propertyName=\"scaleX\"\n        android:valueFrom=\"0.5\"\n        android:valueTo=\"1.05\"/>\n    <objectAnimator\n        android:duration=\"200\"\n        android:interpolator=\"@interpolator/mtrl_fast_out_slow_in\"\n        android:propertyName=\"scaleX\"\n        android:valueFrom=\"1.05\"\n        android:valueTo=\"1\"/>\n  </set>\n  <set android:ordering=\"sequentially\">\n    <objectAnimator\n        android:duration=\"150\"\n        android:interpolator=\"@interpolator/mtrl_fast_out_slow_in\"\n        android:propertyName=\"scaleY\"\n        android:valueFrom=\"0.5\"\n        android:valueTo=\"1.05\"/>\n    <objectAnimator\n        android:duration=\"200\"\n        android:interpolator=\"@interpolator/mtrl_fast_out_slow_in\"\n        android:propertyName=\"scaleY\"\n        android:valueFrom=\"1.05\"\n        android:valueTo=\"1\"/>\n  </set>\n  <objectAnimator\n      android:duration=\"75\"\n      android:propertyName=\"alpha\"\n      android:valueFrom=\"0\"\n      android:valueTo=\"1\"/>\n</set>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/animator/static_image_dot_enter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:ordering=\"together\">\n  <set android:ordering=\"sequentially\">\n    <objectAnimator\n        android:duration=\"130\"\n        android:interpolator=\"@interpolator/mtrl_fast_out_slow_in\"\n        android:propertyName=\"scaleX\"\n        android:valueFrom=\"0.5\"\n        android:valueTo=\"1.3\"/>\n    <objectAnimator\n        android:duration=\"470\"\n        android:interpolator=\"@interpolator/mtrl_fast_out_slow_in\"\n        android:propertyName=\"scaleX\"\n        android:valueFrom=\"1.3\"\n        android:valueTo=\"1\"/>\n  </set>\n  <set android:ordering=\"sequentially\">\n    <objectAnimator\n        android:duration=\"130\"\n        android:interpolator=\"@interpolator/mtrl_fast_out_slow_in\"\n        android:propertyName=\"scaleY\"\n        android:valueFrom=\"0.5\"\n        android:valueTo=\"1.3\"/>\n    <objectAnimator\n        android:duration=\"470\"\n        android:interpolator=\"@interpolator/mtrl_fast_out_slow_in\"\n        android:propertyName=\"scaleY\"\n        android:valueFrom=\"1.3\"\n        android:valueTo=\"1\"/>\n  </set>\n  <objectAnimator\n      android:duration=\"90\"\n      android:propertyName=\"alpha\"\n      android:valueFrom=\"0\"\n      android:valueTo=\"1\"/>\n</set>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/barcode_field_box.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <stroke\n      android:width=\"1dp\"\n      android:color=\"@color/barcode_field_box_stroke\"/>\n  <corners android:radius=\"4dp\"/>\n  <solid android:color=\"@color/white\"/>\n</shape>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/camera_flash.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item android:drawable=\"@drawable/ic_flash_on_vd_white_24\" android:state_selected=\"true\"/>\n  <item android:drawable=\"@drawable/ic_flash_off_vd_white_24\"/>\n</selector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/ic_close_vd_white_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\">\n  <path\n      android:fillColor=\"@color/white\"\n      android:pathData=\"M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z\"/>\n</vector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/ic_flash_off_vd_white_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24.0\"\n    android:viewportHeight=\"24.0\">\n  <path\n      android:fillColor=\"@color/white\"\n      android:pathData=\"M3.27,3L2,4.27l5,5V13h3v9l3.58,-6.14L17.73,20 19,18.73 3.27,3zM17,10h-4l4,-8H7v2.18l8.46,8.46L17,10z\"/>\n</vector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/ic_flash_on_vd_white_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24.0\"\n    android:viewportHeight=\"24.0\">\n  <path\n      android:fillColor=\"@color/white\"\n      android:pathData=\"M7,2v11h3v9l7,-12h-4l4,-8z\"/>\n</vector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/ic_image_search_vd_black_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\">\n  <path\n      android:fillColor=\"@color/black\"\n      android:pathData=\"M18,13v7L4,20L4,6h5.02c0.05,-0.71 0.22,-1.38 0.48,-2L4,4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-5l-2,-2zM16.5,18h-11l2.75,-3.53 1.96,2.36 2.75,-3.54zM19.3,8.89c0.44,-0.7 0.7,-1.51 0.7,-2.39C20,4.01 17.99,2 15.5,2S11,4.01 11,6.5s2.01,4.5 4.49,4.5c0.88,0 1.7,-0.26 2.39,-0.7L21,13.42 22.42,12 19.3,8.89zM15.5,9C14.12,9 13,7.88 13,6.5S14.12,4 15.5,4 18,5.12 18,6.5 16.88,9 15.5,9z\"/>\n</vector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n  <path\n      android:fillColor=\"#008577\"\n      android:pathData=\"M0,0h108v108h-108z\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M9,0L9,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,0L19,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M29,0L29,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M39,0L39,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M49,0L49,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M59,0L59,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M69,0L69,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M79,0L79,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M89,0L89,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M99,0L99,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,9L108,9\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,19L108,19\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,29L108,29\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,39L108,39\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,49L108,49\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,59L108,59\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,69L108,69\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,79L108,79\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,89L108,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,99L108,99\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,29L89,29\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,39L89,39\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,49L89,49\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,59L89,59\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,69L89,69\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,79L89,79\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M29,19L29,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M39,19L39,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M49,19L49,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M59,19L59,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M69,19L69,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M79,19L79,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/ic_photo_library_vd_white_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\">\n  <path\n      android:fillColor=\"@color/white\"\n      android:pathData=\"M22,16L22,4c0,-1.1 -0.9,-2 -2,-2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zM11,12l2.03,2.71L16,11l4,5L8,16l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6L2,6z\"/>\n</vector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/ic_settings_vd_white_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\">\n  <path\n      android:fillColor=\"@color/white\"\n      android:pathData=\"M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z\"/>\n</vector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:width=\"172dp\"\n  android:height=\"129dp\"\n  android:viewportWidth=\"172.43\"\n  android:viewportHeight=\"129.06\">\n  <path\n    android:fillColor=\"#4285f4\"\n    android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n    android:fillColor=\"#0d47a1\"\n    android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n    android:fillColor=\"#abccfc\"\n    android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n  <path\n    android:fillColor=\"#0d47a1\"\n    android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n    android:fillColor=\"#4285f4\"\n    android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n    android:fillColor=\"#abccfc\"\n    android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n  <path\n    android:fillColor=\"#4285f4\"\n    android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n  <path\n    android:fillColor=\"#0d47a1\"\n    android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n    android:fillColor=\"#0d47a1\"\n    android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n    android:fillColor=\"#0d47a1\"\n    android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n    android:fillColor=\"#0d47a1\"\n    android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/drawable/top_action_bar_scrim.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\" >\n  <gradient\n      android:angle=\"90\"\n      android:startColor=\"@color/transparent\"\n      android:endColor=\"@color/black\"\n      android:type=\"linear\" />\n</shape>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/activity_live_barcode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <com.google.mlkit.md.camera.CameraSourcePreview\n      android:id=\"@+id/camera_preview\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\">\n\n    <include layout=\"@layout/camera_preview_overlay\"/>\n\n  </com.google.mlkit.md.camera.CameraSourcePreview>\n\n  <include\n      layout=\"@layout/top_action_bar_in_live_camera\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_gravity=\"top\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/activity_live_object.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <com.google.mlkit.md.camera.CameraSourcePreview\n      android:id=\"@+id/camera_preview\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\">\n\n    <include layout=\"@layout/camera_preview_overlay\"/>\n\n  </com.google.mlkit.md.camera.CameraSourcePreview>\n\n  <include\n      layout=\"@layout/top_action_bar_in_live_camera\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_gravity=\"top\"/>\n\n  <com.google.mlkit.md.productsearch.BottomSheetScrimView\n      android:id=\"@+id/bottom_sheet_scrim_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:visibility=\"gone\"/>\n\n  <include\n      android:id=\"@+id/bottom_sheet\"\n      layout=\"@layout/product_bottom_sheet\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      app:behavior_hideable=\"true\"\n      app:layout_behavior=\"com.google.android.material.bottomsheet.BottomSheetBehavior\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:paddingTop=\"@dimen/home_page_title_padding_top\"\n      android:paddingBottom=\"@dimen/home_page_title_padding_bottom\"\n      android:fontFamily=\"google-sans\"\n      android:gravity=\"center_horizontal\"\n      android:text=\"@string/app_name\"\n      android:textColor=\"@color/white\"\n      android:textSize=\"@dimen/home_page_title_size\"/>\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/mode_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:scrollbars=\"vertical\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/activity_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/settings_container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"/>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/activity_static_object.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n  <include\n      layout=\"@layout/top_action_bar_in_static_image\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"@dimen/top_action_bar_height\"\n      android:layout_gravity=\"top\"/>\n\n  <ImageView\n      android:id=\"@+id/input_image_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:layout_marginTop=\"@dimen/top_action_bar_height\"\n      android:layout_marginBottom=\"@dimen/preview_card_carousel_height\"\n      android:paddingStart=\"@dimen/static_image_view_padding_horizontal\"\n      android:paddingEnd=\"@dimen/static_image_view_padding_horizontal\"\n      android:contentDescription=\"@null\"/>\n\n  <FrameLayout\n      android:id=\"@+id/dot_view_container\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:layout_marginTop=\"@dimen/top_action_bar_height\"\n      android:layout_marginBottom=\"@dimen/preview_card_carousel_height\"\n      android:background=\"@color/transparent\"/>\n\n  <com.google.android.material.chip.Chip\n      android:id=\"@+id/bottom_prompt_chip\"\n      style=\"@style/Widget.MaterialComponents.Chip.Entry\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginBottom=\"@dimen/preview_card_carousel_height\"\n      android:layout_gravity=\"bottom|center_horizontal\"\n      android:checkable=\"false\"\n      android:clickable=\"false\"\n      android:fontFamily=\"sans-serif\"\n      android:textColor=\"@color/white\"\n      android:textSize=\"@dimen/bottom_prompt_chip_text_size\"\n      android:visibility=\"gone\"\n      app:chipCornerRadius=\"@dimen/bottom_prompt_chip_corner_radius\"\n      app:chipSurfaceColor=\"@color/dark\"\n      app:closeIconVisible=\"false\"/>\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/card_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"@dimen/preview_card_carousel_height\"\n      android:layout_gravity=\"bottom\"\n      android:paddingBottom=\"@dimen/preview_card_carousel_padding_bottom\"\n      android:paddingTop=\"@dimen/preview_card_carousel_padding_top\"/>\n\n  <FrameLayout\n      android:id=\"@+id/loading_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:background=\"@color/dark\"\n      android:visibility=\"gone\">\n\n    <ProgressBar\n        android:layout_width=\"@dimen/search_progress_bar_size\"\n        android:layout_height=\"@dimen/search_progress_bar_size\"\n        android:layout_gravity=\"center\"\n        android:indeterminate=\"true\"\n        android:indeterminateTint=\"@color/white\"\n        android:indeterminateTintMode=\"src_in\"/>\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/static_image_loading_view_text_margin_bottom\"\n        android:layout_gravity=\"bottom|center_horizontal\"\n        android:text=\"@string/prompt_searching\"\n        android:textColor=\"@color/white\"\n        android:textSize=\"@dimen/static_image_loading_view_text_size\"/>\n\n  </FrameLayout>\n\n  <com.google.mlkit.md.productsearch.BottomSheetScrimView\n      android:id=\"@+id/bottom_sheet_scrim_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:visibility=\"gone\"/>\n\n  <include\n      android:id=\"@+id/bottom_sheet\"\n      layout=\"@layout/product_bottom_sheet\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      app:behavior_hideable=\"true\"\n      app:layout_behavior=\"com.google.android.material.bottomsheet.BottomSheetBehavior\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/barcode_bottom_sheet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingTop=\"@dimen/barcode_bottom_sheet_padding_vertical\"\n    android:paddingBottom=\"@dimen/barcode_bottom_sheet_padding_vertical\"\n    android:background=\"@color/white\"\n    android:orientation=\"vertical\">\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/barcode_field_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:scrollbars=\"vertical\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/barcode_field.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/barcode_field_container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingBottom=\"@dimen/barcode_field_padding_vertical\"\n    android:paddingStart=\"@dimen/barcode_field_padding_horizontal\"\n    android:paddingEnd=\"@dimen/barcode_field_padding_horizontal\"\n    android:background=\"@color/white\">\n\n  <TextView\n      android:id=\"@+id/barcode_field_value\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginTop=\"@dimen/barcode_field_padding_vertical\"\n      android:padding=\"@dimen/barcode_field_value_padding\"\n      android:background=\"@drawable/barcode_field_box\"\n      android:textColor=\"@color/barcode_field_value\"\n      android:textSize=\"@dimen/barcode_field_value_size\"/>\n\n  <TextView\n      android:id=\"@+id/barcode_field_label\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"@dimen/barcode_field_value_padding\"\n      android:padding=\"@dimen/barcode_field_label_padding\"\n      android:background=\"@color/white\"\n      android:textColor=\"@color/black\"\n      android:textSize=\"@dimen/barcode_field_label_size\"/>\n\n</FrameLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/camera_preview_overlay.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merge xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n  <com.google.mlkit.md.camera.GraphicOverlay\n      android:id=\"@+id/camera_preview_graphic_overlay\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"/>\n\n  <FrameLayout\n      android:id=\"@+id/static_overlay_container\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:background=\"@color/transparent\">\n\n    <ProgressBar\n        android:id=\"@+id/search_progress_bar\"\n        android:layout_width=\"@dimen/search_progress_bar_size\"\n        android:layout_height=\"@dimen/search_progress_bar_size\"\n        android:layout_gravity=\"center\"\n        android:indeterminate=\"true\"\n        android:indeterminateTint=\"@color/white\"\n        android:indeterminateTintMode=\"src_in\"\n        android:visibility=\"gone\"/>\n\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/bottom_prompt_chip\"\n        style=\"@style/Widget.MaterialComponents.Chip.Entry\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/bottom_prompt_chip_margin_bottom\"\n        android:layout_gravity=\"bottom|center_horizontal\"\n        android:checkable=\"false\"\n        android:clickable=\"false\"\n        android:fontFamily=\"sans-serif\"\n        android:textColor=\"@color/white\"\n        android:textSize=\"@dimen/bottom_prompt_chip_text_size\"\n        android:visibility=\"gone\"\n        app:chipCornerRadius=\"@dimen/bottom_prompt_chip_corner_radius\"\n        app:chipSurfaceColor=\"@color/dark\"\n        app:closeIconVisible=\"false\"/>\n\n    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n        android:id=\"@+id/product_search_button\"\n        android:textStyle=\"bold\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/search_button_margin_bottom\"\n        android:layout_gravity=\"bottom|center_horizontal\"\n        android:fontFamily=\"sans-serif\"\n        android:text=\"@string/product_search_button\"\n        android:textColor=\"@color/black\"\n        android:textSize=\"@dimen/search_button_text_size\"\n        android:visibility=\"gone\"\n        app:icon=\"@drawable/ic_image_search_vd_black_24\"\n        app:iconTint=\"@color/black\"/>\n  </FrameLayout>\n\n</merge>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/detection_mode_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingStart=\"@dimen/home_page_mode_item_padding_horizontal\"\n    android:paddingEnd=\"@dimen/home_page_mode_item_padding_horizontal\"\n    android:background=\"?android:attr/selectableItemBackground\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:id=\"@+id/mode_title\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:paddingTop=\"@dimen/home_page_mode_item_title_padding_top\"\n      android:paddingBottom=\"@dimen/home_page_mode_item_title_padding_bottom\"\n      android:fontFamily=\"google-sans-medium\"\n      android:textColor=\"@color/white\"\n      android:textSize=\"@dimen/home_page_mode_item_title_size\"/>\n\n  <TextView\n      android:id=\"@+id/mode_subtitle\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:paddingBottom=\"@dimen/home_page_mode_item_subtitle_padding_bottom\"\n      android:fontFamily=\"sans-serif\"\n      android:textColor=\"@color/home_page_mode_item_subtitle\"\n      android:textSize=\"@dimen/home_page_mode_item_subtitle_size\"/>\n\n  <View\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"@dimen/divider_height\"\n      android:background=\"#40FFFFFF\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/product_bottom_sheet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/white\"\n    android:orientation=\"vertical\">\n\n  <TextView\n      android:id=\"@+id/bottom_sheet_title\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_margin=\"@dimen/bottom_sheet_title_margin\"\n      android:ellipsize=\"end\"\n      android:fontFamily=\"sans-serif\"\n      android:maxLines=\"1\"\n      android:textColor=\"@color/black\"\n      android:textSize=\"@dimen/bottom_sheet_title_size\"/>\n\n  <View\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"@dimen/divider_height\"\n      android:background=\"@color/lighter_grey\"/>\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/product_recycler_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:scrollbars=\"vertical\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/product_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingTop=\"@dimen/product_item_padding\"\n    android:paddingStart=\"@dimen/product_item_padding\"\n    android:paddingEnd=\"@dimen/product_item_padding\">\n\n  <ImageView\n      android:id=\"@+id/product_image\"\n      android:layout_width=\"@dimen/product_item_image_size\"\n      android:layout_height=\"@dimen/product_item_image_size\"\n      android:layout_marginEnd=\"@dimen/product_item_image_margin_end\"\n      android:contentDescription=\"@null\"/>\n\n  <TextView\n      android:id=\"@+id/product_title\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_alignTop=\"@+id/product_image\"\n      android:layout_toEndOf=\"@id/product_image\"\n      android:maxLines=\"1\"\n      android:textColor=\"@color/black\"\n      android:textSize=\"@dimen/product_item_title_size\"/>\n\n  <TextView\n      android:id=\"@+id/product_subtitle\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_below=\"@+id/product_title\"\n      android:layout_toEndOf=\"@id/product_image\"\n      android:maxLines=\"2\"\n      android:textColor=\"@color/product_description\"\n      android:textSize=\"@dimen/product_item_subtitle_size\"/>\n\n  <View\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"@dimen/divider_height\"\n      android:layout_marginTop=\"@dimen/product_item_padding\"\n      android:layout_below=\"@+id/product_image\"\n      android:background=\"@color/lighter_grey\"/>\n\n</RelativeLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/products_preview_card.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.google.android.material.card.MaterialCardView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    style=\"@style/Widget.MaterialComponents.CardView\"\n    android:layout_width=\"@dimen/preview_card_width\"\n    android:layout_height=\"@dimen/preview_card_height\"\n    app:cardBackgroundColor=\"@color/white\"\n    app:cardCornerRadius=\"@dimen/preview_card_corner_radius\">\n\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/card_image\"\n        android:layout_width=\"@dimen/preview_card_image_size\"\n        android:layout_height=\"@dimen/preview_card_image_size\"\n        android:layout_margin=\"@dimen/preview_card_image_margin\"\n        android:contentDescription=\"@null\"/>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n      <TextView\n          android:id=\"@+id/card_title\"\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\"\n          android:paddingTop=\"@dimen/preview_card_title_padding_top\"\n          android:fontFamily=\"sans-serif-medium\"\n          android:maxLines=\"2\"\n          android:textColor=\"@color/black\"\n          android:textSize=\"@dimen/preview_card_title_text_size\"/>\n\n      <TextView\n          android:id=\"@+id/card_subtitle\"\n          android:layout_width=\"wrap_content\"\n          android:layout_height=\"wrap_content\"\n          android:paddingTop=\"@dimen/preview_card_subtitle_padding_top\"\n          android:fontFamily=\"sans-serif\"\n          android:maxLines=\"2\"\n          android:textColor=\"@color/dark\"\n          android:textSize=\"@dimen/preview_card_subtitle_text_size\"/>\n\n    </LinearLayout>\n\n  </LinearLayout>\n\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/top_action_bar_in_live_camera.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/top_action_bar_height\"\n    android:paddingStart=\"@dimen/top_action_bar_padding_horizontal\"\n    android:paddingEnd=\"@dimen/top_action_bar_padding_horizontal\"\n    android:background=\"@drawable/top_action_bar_scrim\">\n\n  <ImageView\n      android:id=\"@+id/close_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_gravity=\"start\"\n      android:padding=\"@dimen/top_action_button_padding\"\n      android:contentDescription=\"@string/cd_close_button\"\n      app:srcCompat=\"@drawable/ic_close_vd_white_24\"/>\n\n  <ImageView\n      android:id=\"@+id/settings_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_alignParentEnd=\"true\"\n      android:padding=\"@dimen/top_action_button_padding\"\n      android:contentDescription=\"@string/cd_settings_button\"\n      app:srcCompat=\"@drawable/ic_settings_vd_white_24\"/>\n\n  <ImageView\n      android:id=\"@+id/flash_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_toStartOf=\"@id/settings_button\"\n      android:padding=\"@dimen/top_action_button_padding\"\n      android:contentDescription=\"@string/cd_flash_button\"\n      app:srcCompat=\"@drawable/camera_flash\"/>\n\n</RelativeLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/layout/top_action_bar_in_static_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/top_action_bar_height\"\n    android:paddingStart=\"@dimen/top_action_bar_padding_horizontal\"\n    android:paddingEnd=\"@dimen/top_action_bar_padding_horizontal\"\n    android:background=\"@drawable/top_action_bar_scrim\">\n\n  <ImageView\n      android:id=\"@+id/close_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_gravity=\"start\"\n      android:padding=\"@dimen/top_action_button_padding\"\n      android:contentDescription=\"@string/cd_close_button\"\n      app:srcCompat=\"@drawable/ic_close_vd_white_24\"/>\n\n  <ImageView\n      android:id=\"@+id/photo_library_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_alignParentEnd=\"true\"\n      android:padding=\"@dimen/top_action_button_padding\"\n      android:contentDescription=\"@string/cd_photo_library_button\"\n      app:srcCompat=\"@drawable/ic_photo_library_vd_white_24\"/>\n\n</RelativeLayout>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"transparent\">#00000000</color>\n  <color name=\"white\">#FFFFFFFF</color>\n  <color name=\"black\">#FF000000</color>\n  <color name=\"lighter_grey\">#DDDDDD</color>\n  <color name=\"dark\">#9A000000</color>\n  <color name=\"home_page_mode_item_subtitle\">#CCFFFFFF</color>\n  <color name=\"reticle_ripple\">#9AFFFFFF</color>\n  <color name=\"bounding_box_gradient_start\">#00FFFFFF</color>\n  <color name=\"bounding_box_gradient_end\">@color/white</color>\n  <color name=\"object_detected_bg_gradient_start\">#00000000</color>\n  <color name=\"object_detected_bg_gradient_end\">#66000000</color>\n  <color name=\"object_confirmed_bg_gradient_start\">#40000000</color>\n  <color name=\"object_confirmed_bg_gradient_end\">#A0000000</color>\n  <color name=\"object_reticle_outer_ring_fill\">#1F000000</color>\n  <color name=\"object_reticle_outer_ring_stroke\">#9AFFFFFF</color>\n  <color name=\"object_reticle_inner_ring\">@color/white</color>\n  <color name=\"barcode_reticle_background\">#99000000</color>\n  <color name=\"barcode_reticle_stroke\">#40000000</color>\n  <color name=\"barcode_field_value\">#797979</color>\n  <color name=\"barcode_field_box_stroke\">#757575</color>\n  <color name=\"product_description\">#5F6368</color>\n</resources>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <dimen name=\"home_page_title_size\">18sp</dimen>\n  <dimen name=\"home_page_title_padding_top\">32dp</dimen>\n  <dimen name=\"home_page_title_padding_bottom\">16dp</dimen>\n  <dimen name=\"home_page_mode_item_padding_horizontal\">24dp</dimen>\n  <dimen name=\"home_page_mode_item_title_size\">16sp</dimen>\n  <dimen name=\"home_page_mode_item_title_padding_top\">16dp</dimen>\n  <dimen name=\"home_page_mode_item_title_padding_bottom\">8dp</dimen>\n  <dimen name=\"home_page_mode_item_subtitle_size\">14sp</dimen>\n  <dimen name=\"home_page_mode_item_subtitle_padding_bottom\">24dp</dimen>\n  <dimen name=\"top_action_bar_padding_horizontal\">8dp</dimen>\n  <dimen name=\"top_action_bar_height\">64dp</dimen>\n  <dimen name=\"top_action_button_padding\">12dp</dimen>\n  <dimen name=\"search_progress_bar_size\">48dp</dimen>\n  <dimen name=\"search_button_text_size\">16sp</dimen>\n  <dimen name=\"search_button_margin_bottom\">24dp</dimen>\n  <dimen name=\"bottom_prompt_chip_text_size\">14sp</dimen>\n  <dimen name=\"bottom_prompt_chip_margin_bottom\">28dp</dimen>\n  <dimen name=\"bottom_prompt_chip_corner_radius\">8dp</dimen>\n  <dimen name=\"bottom_sheet_title_margin\">16dp</dimen>\n  <dimen name=\"bottom_sheet_title_size\">16sp</dimen>\n  <dimen name=\"bounding_box_stroke_width\">1dp</dimen>\n  <dimen name=\"bounding_box_confirmed_stroke_width\">2dp</dimen>\n  <dimen name=\"bounding_box_corner_radius\">12dp</dimen>\n  <dimen name=\"product_item_padding\">16dp</dimen>\n  <dimen name=\"product_item_image_size\">80dp</dimen>\n  <dimen name=\"product_item_image_margin_end\">16dp</dimen>\n  <dimen name=\"product_item_title_size\">18sp</dimen>\n  <dimen name=\"product_item_subtitle_size\">14sp</dimen>\n  <dimen name=\"object_reticle_ripple_stroke_width\">4dp</dimen>\n  <dimen name=\"object_reticle_ripple_size_offset\">24dp</dimen>\n  <dimen name=\"object_reticle_outer_ring_fill_radius\">22dp</dimen>\n  <dimen name=\"object_reticle_outer_ring_stroke_radius\">24dp</dimen>\n  <dimen name=\"object_reticle_outer_ring_stroke_width\">4dp</dimen>\n  <dimen name=\"object_reticle_inner_ring_stroke_radius\">14dp</dimen>\n  <dimen name=\"object_reticle_inner_ring_stroke_width\">2dp</dimen>\n  <dimen name=\"object_selection_distance_threshold\">24dp</dimen>\n  <dimen name=\"object_dot_radius\">@dimen/object_reticle_inner_ring_stroke_radius</dimen>\n  <dimen name=\"object_thumbnail_height\">120dp</dimen>\n  <dimen name=\"object_thumbnail_margin\">24dp</dimen>\n  <dimen name=\"object_thumbnail_stroke_width\">@dimen/bounding_box_confirmed_stroke_width</dimen>\n  <dimen name=\"preview_card_carousel_padding_top\">16dp</dimen>\n  <dimen name=\"preview_card_carousel_padding_bottom\">8dp</dimen>\n  <dimen name=\"preview_card_carousel_height\">120dp</dimen>\n  <dimen name=\"preview_card_width\">240dp</dimen>\n  <dimen name=\"preview_card_height\">96dp</dimen>\n  <dimen name=\"preview_card_spacing\">8dp</dimen>\n  <dimen name=\"preview_card_corner_radius\">8dp</dimen>\n  <dimen name=\"preview_card_image_size\">80dp</dimen>\n  <dimen name=\"preview_card_image_margin\">8dp</dimen>\n  <dimen name=\"preview_card_title_text_size\">14sp</dimen>\n  <dimen name=\"preview_card_title_padding_top\">12dp</dimen>\n  <dimen name=\"preview_card_subtitle_text_size\">14sp</dimen>\n  <dimen name=\"preview_card_subtitle_padding_top\">4dp</dimen>\n  <dimen name=\"static_image_dot_view_size\">48dp</dimen>\n  <dimen name=\"static_image_dot_radius_selected\">14dp</dimen>\n  <dimen name=\"static_image_dot_radius_unselected\">10dp</dimen>\n  <dimen name=\"static_image_view_padding_horizontal\">16dp</dimen>\n  <dimen name=\"static_image_loading_view_text_size\">14sp</dimen>\n  <dimen name=\"static_image_loading_view_text_margin_bottom\">32dp</dimen>\n  <dimen name=\"barcode_bottom_sheet_padding_vertical\">12dp</dimen>\n  <dimen name=\"barcode_reticle_ripple_stroke_width\">4dp</dimen>\n  <dimen name=\"barcode_reticle_ripple_size_offset\">40dp</dimen>\n  <dimen name=\"barcode_reticle_stroke_width\">4dp</dimen>\n  <dimen name=\"barcode_reticle_corner_radius\">8dp</dimen>\n  <dimen name=\"barcode_field_padding_horizontal\">24dp</dimen>\n  <dimen name=\"barcode_field_padding_vertical\">12dp</dimen>\n  <dimen name=\"barcode_field_value_size\">16sp</dimen>\n  <dimen name=\"barcode_field_value_padding\">16dp</dimen>\n  <dimen name=\"barcode_field_label_size\">12sp</dimen>\n  <dimen name=\"barcode_field_label_padding\">4dp</dimen>\n  <dimen name=\"divider_height\">1dp</dimen>\n</resources>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <string name=\"app_name\">MLKit Showcase</string>\n\n  <string name=\"entry_java_title\">Java</string>\n  <string name=\"entry_java_subtitle\">Run the MLKit Showcase written in Java.</string>\n  <string name=\"entry_kotlin_title\">Kotlin</string>\n  <string name=\"entry_kotlin_subtitle\">Run the MLKit Showcase written in Kotlin.</string>\n  <string name=\"mode_odt_live_title\">Object Detection: Live Camera</string>\n  <string name=\"mode_odt_live_subtitle\">A device’s live camera can be used to detect objects in an environment.</string>\n  <string name=\"mode_odt_static_title\">Object Detection: Static Image</string>\n  <string name=\"mode_odt_static_subtitle\">One or more objects can be detected from a provided image.</string>\n  <string name=\"mode_barcode_live_title\">Barcode Scanning</string>\n  <string name=\"mode_barcode_live_subtitle\">Read data encoded in most standard barcode formats.</string>\n  <string name=\"custom_model_live_title\">Object Detection: Live Camera with Custom Classification (Birds)</string>\n  <string name=\"custom_model_live_subtitle\">A device\\'s live camera can be used to detect birds in an environment.</string>\n  <string name=\"settings_title\">MLKit Showcase Settings</string>\n  <string name=\"cd_settings_button\">Settings</string>\n  <string name=\"cd_close_button\">Back</string>\n  <string name=\"cd_flash_button\">Toggle camera flash</string>\n  <string name=\"cd_photo_library_button\">Upload image</string>\n  <string name=\"prompt_point_at_an_object\">Point your camera at an object</string>\n  <string name=\"prompt_point_at_a_barcode\">Point your camera at a barcode</string>\n  <string name=\"prompt_point_at_a_bird\">Point your camera at a bird</string>\n  <string name=\"prompt_hold_camera_steady\">Keep camera still for a moment</string>\n  <string name=\"prompt_move_camera_closer\">Move closer to search</string>\n  <string name=\"prompt_searching\">Searching&#8230;</string>\n  <string name=\"product_search_button\">Search object</string>\n  <plurals name=\"bottom_sheet_title\">\n    <item quantity=\"one\">%d match found</item>\n    <item quantity=\"other\">%d matches found</item>\n  </plurals>\n  <string name=\"buttom_sheet_custom_model_title\">Custom object found</string>\n  <string name=\"static_image_prompt_detected_no_results\">No results found</string>\n  <string name=\"static_image_prompt_detected_results\">Tap on a dot to inspect</string>\n  <string name=\"static_image_card_no_result_title\">No result found</string>\n  <string name=\"static_image_card_no_result_subtitle\">Support text place holder</string>\n  <string name=\"static_image_preview_card_subtitle\">+%d more results</string>\n\n  <!-- Strings for camera settings. -->\n  <string name=\"pref_category_camera\">Camera</string>\n  <string name=\"pref_key_rear_camera_preview_size\" translatable=\"false\">rcpvs</string>\n  <string name=\"pref_key_rear_camera_picture_size\" translatable=\"false\">rcpts</string>\n  <string name=\"pref_title_rear_camera_preview_size\">Rear camera preview size</string>\n\n  <!-- Strings for object detection settings. -->\n  <string name=\"pref_category_object_detection\">Object detection</string>\n  <string name=\"pref_key_object_detector_enable_multiple_objects\" translatable=\"false\">odemo</string>\n  <string name=\"pref_title_object_detector_enable_multiple_objects\">Enable multiple objects</string>\n  <string name=\"pref_key_object_detector_enable_classification\" translatable=\"false\">odec</string>\n  <string name=\"pref_title_object_detector_enable_classification\">Enable classification</string>\n\n  <!-- Strings for product search settings. -->\n  <string name=\"pref_category_product_search\">Product search</string>\n  <string name=\"pref_key_enable_auto_search\" translatable=\"false\">pkeas</string>\n  <string name=\"pref_title_enable_auto_search\">Enable auto search</string>\n  <string name=\"pref_key_confirmation_time_in_manual_search\" translatable=\"false\">ctims</string>\n  <string name=\"pref_title_confirmation_time_in_manual_search\">Confirmation time in manual search</string>\n  <string name=\"pref_summary_confirmation_time_in_manual_search\">Ranges from 100ms to 1000ms</string>\n  <string name=\"pref_key_confirmation_time_in_auto_search\" translatable=\"false\">ctias</string>\n  <string name=\"pref_title_confirmation_time_in_auto_search\">Confirmation time in auto search</string>\n  <string name=\"pref_summary_confirmation_time_in_auto_search\">Ranges from 500ms to 2000ms</string>\n\n  <!-- Strings for barcode detection settings. -->\n  <string name=\"pref_category_barcode_detection\">Barcode detection</string>\n  <string name=\"pref_key_barcode_reticle_width\" translatable=\"false\">barcode_brw</string>\n  <string name=\"pref_title_barcode_reticle_width\">Barcode reticle width</string>\n  <string name=\"pref_summary_barcode_reticle_width\" formatted=\"false\">Relative to the camera view width, ranges from 50% to 95%</string>\n  <string name=\"pref_key_barcode_reticle_height\" translatable=\"false\">barcode_brh</string>\n  <string name=\"pref_title_barcode_reticle_height\">Barcode reticle height</string>\n  <string name=\"pref_summary_barcode_reticle_height\" formatted=\"false\">Relative to the camera view height, ranges from 20% to 80%</string>\n  <string name=\"pref_key_enable_barcode_size_check\" translatable=\"false\">barcode_ebsc</string>\n  <string name=\"pref_title_enable_barcode_size_check\">Enable barcode size check</string>\n  <string name=\"pref_summary_enable_barcode_size_check\">Will prompt user to move camera closer if the detected barcode is too small</string>\n  <string name=\"pref_key_minimum_barcode_width\" translatable=\"false\">barcode_mbw</string>\n  <string name=\"pref_title_minimum_barcode_width\">Minimum barcode width</string>\n  <string name=\"pref_summary_minimum_barcode_width\" formatted=\"false\">Relative to the reticle width, ranges from 20% to 80% (only applicable when barcode size check enabled)</string>\n  <string name=\"pref_key_delay_loading_barcode_result\" translatable=\"false\">barcode_dlbr</string>\n  <string name=\"pref_title_delay_loading_barcode_result\">Delay loading barcode result</string>\n  <string name=\"pref_summary_delay_loading_barcode_result\">Will show the loading spinner for 2s</string>\n\n</resources>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.NoActionBar\">\n  </style>\n</resources>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/values-v21/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.NoActionBar\">\n    <item name=\"android:colorPrimary\">@color/white</item>\n    <item name=\"android:colorPrimaryDark\">@color/black</item>\n  </style>\n</resources>\n"
  },
  {
    "path": "android/material-showcase/app/src/main/res/xml/preferences.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.preference.PreferenceScreen\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n  <androidx.preference.PreferenceCategory\n      android:title=\"@string/pref_category_camera\">\n\n    <androidx.preference.ListPreference\n        android:key=\"@string/pref_key_rear_camera_preview_size\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_rear_camera_preview_size\"/>\n\n  </androidx.preference.PreferenceCategory>\n\n  <androidx.preference.PreferenceCategory\n      android:title=\"@string/pref_category_object_detection\">\n\n    <androidx.preference.SwitchPreferenceCompat\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_object_detector_enable_multiple_objects\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_object_detector_enable_multiple_objects\"/>\n\n    <androidx.preference.SwitchPreferenceCompat\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_object_detector_enable_classification\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_object_detector_enable_classification\"/>\n\n  </androidx.preference.PreferenceCategory>\n\n  <androidx.preference.PreferenceCategory\n      android:title=\"@string/pref_category_product_search\">\n\n    <androidx.preference.SwitchPreferenceCompat\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_enable_auto_search\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_enable_auto_search\"/>\n\n    <androidx.preference.SeekBarPreference\n        android:defaultValue=\"500\"\n        android:key=\"@string/pref_key_confirmation_time_in_manual_search\"\n        android:max=\"1000\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_confirmation_time_in_manual_search\"\n        android:title=\"@string/pref_title_confirmation_time_in_manual_search\"\n        app:min=\"100\"\n        app:showSeekBarValue=\"true\"/>\n\n    <androidx.preference.SeekBarPreference\n        android:defaultValue=\"1500\"\n        android:key=\"@string/pref_key_confirmation_time_in_auto_search\"\n        android:max=\"2000\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_confirmation_time_in_auto_search\"\n        android:title=\"@string/pref_title_confirmation_time_in_auto_search\"\n        app:min=\"500\"\n        app:showSeekBarValue=\"true\"/>\n\n  </androidx.preference.PreferenceCategory>\n\n  <androidx.preference.PreferenceCategory\n      android:title=\"@string/pref_category_barcode_detection\">\n\n    <androidx.preference.SeekBarPreference\n        android:defaultValue=\"80\"\n        android:key=\"@string/pref_key_barcode_reticle_width\"\n        android:max=\"95\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_barcode_reticle_width\"\n        android:title=\"@string/pref_title_barcode_reticle_width\"\n        app:min=\"50\"\n        app:showSeekBarValue=\"true\"/>\n\n    <androidx.preference.SeekBarPreference\n        android:defaultValue=\"35\"\n        android:key=\"@string/pref_key_barcode_reticle_height\"\n        android:max=\"80\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_barcode_reticle_height\"\n        android:title=\"@string/pref_title_barcode_reticle_height\"\n        app:min=\"20\"\n        app:showSeekBarValue=\"true\"/>\n\n    <androidx.preference.SwitchPreferenceCompat\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_enable_barcode_size_check\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_enable_barcode_size_check\"\n        android:title=\"@string/pref_title_enable_barcode_size_check\"/>\n\n    <androidx.preference.SeekBarPreference\n        android:defaultValue=\"50\"\n        android:key=\"@string/pref_key_minimum_barcode_width\"\n        android:max=\"80\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_minimum_barcode_width\"\n        android:title=\"@string/pref_title_minimum_barcode_width\"\n        app:min=\"20\"\n        app:showSeekBarValue=\"true\"/>\n\n    <androidx.preference.SwitchPreferenceCompat\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_delay_loading_barcode_result\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_delay_loading_barcode_result\"\n        android:title=\"@string/pref_title_delay_loading_barcode_result\"/>\n\n  </androidx.preference.PreferenceCategory>\n\n</androidx.preference.PreferenceScreen>\n"
  },
  {
    "path": "android/material-showcase/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.5.31'\n    repositories {\n        google()\n        jcenter()\n        mavenLocal()\n\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.0.4'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10\"\n    }\n}\n\nplugins {\n    id 'com.github.ben-manes.versions' version '0.36.0'\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n        mavenLocal()\n    }\n\n    // See: https://github.com/ben-manes/gradle-versions-plugin\n    dependencyUpdates.resolutionStrategy = {\n        componentSelection { rules ->\n            rules.all { selection ->\n                boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm'].any { qualifier ->\n                    selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\\d-]*/\n                }\n                if (rejected) {\n                    selection.reject('Release candidate')\n                }\n            }\n        }\n    }\n}\n\nconfigurations {\n    ktlint\n}\n\ndependencies {\n    ktlint \"com.github.shyiko:ktlint:0.31.0\"\n}\n\ntask(\"ktlint\", type: JavaExec, group: \"verification\") {\n    def outputDir = \"${project.buildDir}/reports/ktlint/\"\n    def inputFiles = project.fileTree(dir: \"src\", include: \"**/*.kt\")\n    def outputFile = \"${outputDir}ktlint-checkstyle-report.xml\"\n\n    // See:\n    // https://medium.com/@vanniktech/making-your-gradle-tasks-incremental-7f26e4ef09c3\n    inputs.files(inputFiles)\n    outputs.dir(outputDir)\n\n    description = \"Check Kotlin code style.\"\n    classpath = configurations.ktlint\n    main = \"com.github.shyiko.ktlint.Main\"\n    args = [\n        \"--format\",\n        \"--android\",\n        \"--reporter=plain\",\n        \"--reporter=checkstyle,output=${outputFile}\",\n        \"**/*.kt\",\n    ]\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/material-showcase/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Sun Jan 31 23:07:35 PST 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.0.2-all.zip\n"
  },
  {
    "path": "android/material-showcase/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "android/material-showcase/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/material-showcase/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/material-showcase/settings.gradle",
    "content": "include ':app'\n"
  },
  {
    "path": "android/smartreply/LICENSE",
    "content": "   Copyright 2020 Google LLC\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "android/smartreply/README.md",
    "content": "# ML Kit Smart Reply Quickstart\n\n* [Read more about ML Kit Smart Reply](https://developers.google.com/ml-kit/language/smart-reply)\n\n## Introduction\n\nThe ML Kit Smart Reply Android Quickstart app demonstrates how to use the Smart\nReply feature of ML Kit to automatically generate replies to conversation\nthreads in your application.\n\n## Getting Started\n\n* Run the sample code on your Android device or emulator\n* Type messages to generate smart replies\n* Try extending the code to add new features and functionality\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/language/smart-reply/android)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/smartreply/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion 34\n    defaultConfig {\n        applicationId \"com.google.mlkit.samples.nl.smartreply\"\n        minSdkVersion 21\n        targetSdkVersion 34\n        versionCode 1\n        versionName \"1.0\"\n        vectorDrawables.useSupportLibrary true\n        multiDexEnabled true\n        setProperty(\"archivesBaseName\", \"nl-smartreply\")\n    }\n    buildTypes {\n        proguard {\n            debuggable false\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n            testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardTest-rules.pro', 'proguard.cfg'\n        }\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    aaptOptions {\n        noCompress 'tflite'\n    }\n    lintOptions {\n        disable \"Instantiatable\"\n    }\n}\n\ndependencies {\n    implementation project(':internal:chooserx')\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n\n    implementation 'androidx.media:media:1.2.1'\n    implementation 'com.google.android.material:material:1.2.1'\n    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'\n    implementation 'androidx.recyclerview:recyclerview:1.1.0'\n    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'\n\n    implementation 'com.google.mlkit:smart-reply:17.0.4'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-smart-reply:16.0.0-beta1'\n\n    implementation 'com.google.guava:guava:27.0.1-android'\n}\n"
  },
  {
    "path": "android/smartreply/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "android/smartreply/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.samples.nl.smartreply\">\n\n  <application\n      android:allowBackup=\"true\"\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:theme=\"@style/AppTheme\">\n\n    <!-- Optional: Add it to automatically download ML model to device after\n      your app is installed.-->\n    <meta-data\n        android:name=\"com.google.mlkit.vision.DEPENDENCIES\"\n        android:value=\"smart_reply\"/>\n\n    <activity\n        android:name=\".EntryChoiceActivity\"\n        android:exported=\"true\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\".java.MainActivityJava\"\n        android:exported=\"true\" />\n\n    <activity\n        android:name=\".kotlin.MainActivityKotlin\"\n        android:exported=\"true\" />\n\n  </application>\n\n</manifest>\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/EntryChoiceActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply\n\nimport android.content.Intent\nimport androidx.appcompat.app.AppCompatDelegate\nimport com.google.mlkit.samples.nl.smartreply.java.MainActivityJava\nimport com.google.mlkit.samples.nl.smartreply.kotlin.MainActivityKotlin\nimport com.mlkit.example.internal.BaseEntryChoiceActivity\nimport com.mlkit.example.internal.Choice\n\nclass EntryChoiceActivity : BaseEntryChoiceActivity() {\n\n  override fun getChoices(): List<Choice> {\n    return listOf(\n      Choice(\n        \"Java\",\n        \"Run the ML Kit Smart Reply quickstart written in Java.\",\n        Intent(this, MainActivityJava::class.java)\n      ),\n      Choice(\n        \"Kotlin\",\n        \"Run the ML Kit Smart Reply quickstart written in Kotlin.\",\n        Intent(this, MainActivityKotlin::class.java)\n      )\n    )\n  }\n\n  companion object {\n    init {\n      AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)\n    }\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/java/MainActivityJava.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.java;\n\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport com.google.mlkit.samples.nl.smartreply.R;\nimport com.google.mlkit.samples.nl.smartreply.java.chat.ChatFragment;\n\n/** Default launcher activity. */\npublic class MainActivityJava extends AppCompatActivity {\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.main_smartreply_activity);\n\n    if (savedInstanceState == null) {\n      getSupportFragmentManager()\n          .beginTransaction()\n          .replace(R.id.container, ChatFragment.newInstance())\n          .commitNow();\n    }\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/java/chat/ChatFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.java.chat;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.os.Bundle;\nimport androidx.fragment.app.Fragment;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.Button;\nimport android.widget.TextView;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.ViewModelProvider;\nimport com.google.mlkit.samples.nl.smartreply.R;\nimport com.google.mlkit.samples.nl.smartreply.java.model.Message;\nimport java.util.ArrayList;\nimport java.util.Calendar;\n\n/** Represents an individual chat message. */\npublic class ChatFragment extends Fragment implements ReplyChipAdapter.ClickListener {\n\n  private ChatViewModel viewModel;\n  private TextView inputText;\n\n  private RecyclerView chatRecycler;\n  private MessageListAdapter chatAdapter;\n\n  private ReplyChipAdapter chipAdapter;\n\n  private TextView emulatedUserText;\n\n  public static ChatFragment newInstance() {\n    return new ChatFragment();\n  }\n\n  @Override\n  public void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setHasOptionsMenu(true);\n  }\n\n  @Nullable\n  @Override\n  public View onCreateView(\n      @NonNull LayoutInflater inflater,\n      @Nullable ViewGroup container,\n      @Nullable Bundle savedInstanceState) {\n    return inflater.inflate(R.layout.chat_fragment, container, false);\n  }\n\n  @SuppressLint(\"ClickableViewAccessibility\")\n  @Override\n  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n    super.onViewCreated(view, savedInstanceState);\n\n    viewModel = new ViewModelProvider(this).get(ChatViewModel.class);\n\n    chatRecycler = view.findViewById(R.id.chatHistory);\n    emulatedUserText = view.findViewById(R.id.switchText);\n    RecyclerView smartRepliesRecycler = view.findViewById(R.id.smartRepliesRecycler);\n    inputText = view.findViewById(R.id.inputText);\n    Button sendButton = view.findViewById(R.id.button);\n    Button switchUserButton = view.findViewById(R.id.switchEmulatedUser);\n\n    // Set up recycler view for chat messages\n    LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());\n    chatRecycler.setLayoutManager(layoutManager);\n    chatAdapter = new MessageListAdapter();\n\n    // Set up recycler view for smart replies\n    LinearLayoutManager chipManager = new LinearLayoutManager(getContext());\n    chipManager.setOrientation(RecyclerView.HORIZONTAL);\n    chipAdapter = new ReplyChipAdapter(this);\n    smartRepliesRecycler.setLayoutManager(chipManager);\n    smartRepliesRecycler.setAdapter(chipAdapter);\n\n    chatRecycler.setAdapter(chatAdapter);\n    chatRecycler.setOnTouchListener(\n        (v, motionEvent) -> {\n          InputMethodManager imm =\n              (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n          imm.hideSoftInputFromWindow(v.getWindowToken(), 0);\n          return false;\n        });\n\n    switchUserButton.setOnClickListener(\n        ignored -> {\n          chatAdapter.setEmulatingRemoteUser(!chatAdapter.getEmulatingRemoteUser());\n          viewModel.switchUser();\n        });\n\n    sendButton.setOnClickListener(\n        ignored -> {\n          String input = inputText.getText().toString();\n          if (TextUtils.isEmpty(input)) {\n            return;\n          }\n\n          viewModel.addMessage(input);\n          inputText.setText(\"\");\n        });\n\n    viewModel\n        .getSuggestions()\n        .observe(getViewLifecycleOwner(), suggestions -> chipAdapter.setSuggestions(suggestions));\n\n    viewModel\n        .getMessages()\n        .observe(\n            getViewLifecycleOwner(),\n            messages -> {\n              chatAdapter.setMessages(messages);\n              if (chatAdapter.getItemCount() > 0) {\n                chatRecycler.smoothScrollToPosition(chatAdapter.getItemCount() - 1);\n              }\n            });\n\n    viewModel\n        .getEmulatingRemoteUser()\n        .observe(\n            getViewLifecycleOwner(),\n            isEmulatingRemoteUser -> {\n              if (isEmulatingRemoteUser) {\n                emulatedUserText.setText(R.string.chatting_as_red);\n                emulatedUserText.setTextColor(getResources().getColor(R.color.red));\n              } else {\n                emulatedUserText.setText(R.string.chatting_as_blue);\n                emulatedUserText.setTextColor(getResources().getColor(R.color.blue));\n              }\n            });\n\n    // Only set initial message for the new ViewModel instance.\n    if (viewModel.getMessages().getValue() == null) {\n      ArrayList<Message> messageList = new ArrayList<>();\n      messageList.add(new Message(\"Hello. How are you?\", false, System.currentTimeMillis()));\n      viewModel.setMessages(messageList);\n    }\n  }\n\n  @Override\n  public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n    super.onCreateOptionsMenu(menu, inflater);\n    inflater.inflate(R.menu.chat_fragment_actions, menu);\n  }\n\n  @Override\n  public boolean onOptionsItemSelected(MenuItem item) {\n    super.onOptionsItemSelected(item);\n    if (item.getItemId() == R.id.generateHistoryBasic) {\n      generateChatHistoryBasic();\n      return true;\n    } else if (item.getItemId() == R.id.generateHistorySensitive) {\n      generateChatHistoryWithSensitiveContent();\n      return true;\n    } else if (item.getItemId() == R.id.clearHistory) {\n      viewModel.setMessages(new ArrayList<>());\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  @Override\n  public void onChipClick(@NonNull String chipText) {\n    inputText.setText(chipText);\n  }\n\n  private void generateChatHistoryBasic() {\n    ArrayList<Message> messageList = new ArrayList<>();\n    Calendar calendar = Calendar.getInstance();\n\n    calendar.set(Calendar.DATE, -1);\n    messageList.add(new Message(\"Hello\", true, calendar.getTimeInMillis()));\n\n    calendar.add(Calendar.MINUTE, 10);\n    messageList.add(new Message(\"Hey\", false, calendar.getTimeInMillis()));\n\n    viewModel.setMessages(messageList);\n  }\n\n  private void generateChatHistoryWithSensitiveContent() {\n    ArrayList<Message> messageList = new ArrayList<>();\n    Calendar calendar = Calendar.getInstance();\n\n    calendar.set(Calendar.DATE, -1);\n    messageList.add(new Message(\"Hi\", false, calendar.getTimeInMillis()));\n\n    calendar.add(Calendar.MINUTE, 10);\n    messageList.add(new Message(\"How are you?\", true, calendar.getTimeInMillis()));\n\n    calendar.add(Calendar.MINUTE, 10);\n    messageList.add(new Message(\"My cat died\", false, calendar.getTimeInMillis()));\n\n    viewModel.setMessages(messageList);\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/java/chat/ChatViewModel.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.java.chat;\n\nimport android.app.Application;\nimport android.util.Log;\nimport android.widget.Toast;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MediatorLiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport com.google.common.collect.Iterables;\nimport com.google.mlkit.nl.smartreply.SmartReply;\nimport com.google.mlkit.nl.smartreply.SmartReplyGenerator;\nimport com.google.mlkit.nl.smartreply.SmartReplySuggestion;\nimport com.google.mlkit.nl.smartreply.SmartReplySuggestionResult;\nimport com.google.mlkit.nl.smartreply.TextMessage;\nimport com.google.mlkit.samples.nl.smartreply.R;\nimport com.google.mlkit.samples.nl.smartreply.java.model.Message;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\n/** View model for chat message. */\npublic class ChatViewModel extends AndroidViewModel {\n\n  private static final String TAG = \"ChatViewModel\";\n  private static final String REMOTE_USER_ID = UUID.randomUUID().toString();\n\n  private final MediatorLiveData<List<SmartReplySuggestion>> suggestions = new MediatorLiveData<>();\n  private final MutableLiveData<List<Message>> messageList = new MutableLiveData<>();\n  private final MutableLiveData<Boolean> emulatingRemoteUser = new MutableLiveData<>();\n  private final SmartReplyGenerator smartReply = SmartReply.getClient();\n\n  public ChatViewModel(Application application) {\n    super(application);\n    initSuggestionsGenerator();\n    emulatingRemoteUser.postValue(false);\n  }\n\n  public LiveData<List<SmartReplySuggestion>> getSuggestions() {\n    return suggestions;\n  }\n\n  public LiveData<List<Message>> getMessages() {\n    return messageList;\n  }\n\n  public LiveData<Boolean> getEmulatingRemoteUser() {\n    return emulatingRemoteUser;\n  }\n\n  void setMessages(List<Message> messages) {\n    clearSuggestions();\n    messageList.postValue(messages);\n  }\n\n  void switchUser() {\n    clearSuggestions();\n    emulatingRemoteUser.postValue(!emulatingRemoteUser.getValue());\n  }\n\n  private void clearSuggestions() {\n    suggestions.postValue(new ArrayList<>());\n  }\n\n  void addMessage(String message) {\n    List<Message> list = messageList.getValue();\n    if (list == null) {\n      list = new ArrayList<>();\n    }\n    list.add(new Message(message, !emulatingRemoteUser.getValue(), System.currentTimeMillis()));\n    clearSuggestions();\n    messageList.postValue(list);\n  }\n\n  private void initSuggestionsGenerator() {\n    suggestions.addSource(\n        emulatingRemoteUser,\n        isEmulatingRemoteUser -> {\n          List<Message> list = messageList.getValue();\n          if (list == null || list.isEmpty()) {\n            return;\n          }\n\n          generateReplies(list, isEmulatingRemoteUser).addOnSuccessListener(suggestions::postValue);\n        });\n\n    suggestions.addSource(\n        messageList,\n        list -> {\n          Boolean isEmulatingRemoteUser = emulatingRemoteUser.getValue();\n          if (isEmulatingRemoteUser == null || list.isEmpty()) {\n            return;\n          }\n\n          generateReplies(list, isEmulatingRemoteUser).addOnSuccessListener(suggestions::postValue);\n        });\n  }\n\n  private Task<List<SmartReplySuggestion>> generateReplies(\n      List<Message> messages, boolean isEmulatingRemoteUser) {\n    Message lastMessage = Iterables.getLast(messages);\n\n    // If the last message in the chat thread is not sent by the \"other\" user, don't generate\n    // smart replies.\n    if (lastMessage.isLocalUser != isEmulatingRemoteUser) {\n      return Tasks.forException(new Exception(\"Not running smart reply!\"));\n    }\n\n    List<TextMessage> chatHistory = new ArrayList<>();\n    for (Message message : messages) {\n      if (message.isLocalUser != isEmulatingRemoteUser) {\n        chatHistory.add(TextMessage.createForLocalUser(message.text, message.timestamp));\n      } else {\n        chatHistory.add(\n            TextMessage.createForRemoteUser(message.text, message.timestamp, REMOTE_USER_ID));\n      }\n    }\n\n    return smartReply\n        .suggestReplies(chatHistory)\n        .continueWith(\n            task -> {\n              SmartReplySuggestionResult result = task.getResult();\n              switch (result.getStatus()) {\n                case SmartReplySuggestionResult.STATUS_NOT_SUPPORTED_LANGUAGE:\n                  // This error happens when the detected language is not English, as that is the\n                  // only supported language in Smart Reply.\n                  Toast.makeText(\n                          getApplication(),\n                          R.string.error_not_supported_language,\n                          Toast.LENGTH_SHORT)\n                      .show();\n                  break;\n                case SmartReplySuggestionResult.STATUS_NO_REPLY:\n                  // This error happens when the inference completed successfully, but no replies\n                  // were returned.\n                  Toast.makeText(getApplication(), R.string.error_no_reply, Toast.LENGTH_SHORT)\n                      .show();\n                  break;\n                default: // fall out\n              }\n              return result.getSuggestions();\n            })\n        .addOnFailureListener(\n            e -> {\n              Log.e(TAG, \"Smart reply error\", e);\n              Toast.makeText(\n                      getApplication(),\n                      \"Smart reply error\"\n                          + \"\\nError: \"\n                          + e.getLocalizedMessage()\n                          + \"\\nCause: \"\n                          + e.getCause(),\n                      Toast.LENGTH_LONG)\n                  .show();\n            });\n  }\n\n  @Override\n  public void onCleared() {\n    super.onCleared();\n    // Instances of smartReply must be closed appropriately, so here we utilize ViewModel's\n    // onCleared() to close the smartReply instance when this ViewModel is no longer in use and\n    // destroyed.\n    smartReply.close();\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/java/chat/MessageListAdapter.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.java.chat;\n\nimport androidx.recyclerview.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport androidx.annotation.NonNull;\nimport com.google.mlkit.samples.nl.smartreply.R;\nimport com.google.mlkit.samples.nl.smartreply.java.model.Message;\nimport java.util.ArrayList;\nimport java.util.List;\n\nclass MessageListAdapter extends RecyclerView.Adapter<MessageListAdapter.MessageViewHolder> {\n\n  private final List<Message> messagesList = new ArrayList<>();\n  private boolean emulatingRemoteUser = false;\n\n  public MessageListAdapter() {}\n\n  @Override\n  @NonNull\n  public MessageListAdapter.MessageViewHolder onCreateViewHolder(\n      @NonNull ViewGroup parent, int viewType) {\n    ViewGroup v =\n        (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);\n    return new MessageViewHolder(v);\n  }\n\n  @Override\n  public void onBindViewHolder(@NonNull MessageViewHolder holder, int position) {\n    Message message = messagesList.get(position);\n    holder.bind(message);\n  }\n\n  @Override\n  public int getItemViewType(int position) {\n    if (messagesList.get(position).isLocalUser != emulatingRemoteUser) {\n      return R.layout.item_message_local;\n    } else {\n      return R.layout.item_message_remote;\n    }\n  }\n\n  @Override\n  public int getItemCount() {\n    return messagesList.size();\n  }\n\n  public void setMessages(List<Message> messages) {\n    messagesList.clear();\n    messagesList.addAll(messages);\n    notifyDataSetChanged();\n  }\n\n  public boolean getEmulatingRemoteUser() {\n    return this.emulatingRemoteUser;\n  }\n\n  public void setEmulatingRemoteUser(boolean emulatingRemoteUser) {\n    this.emulatingRemoteUser = emulatingRemoteUser;\n    notifyDataSetChanged();\n  }\n\n  static class MessageViewHolder extends RecyclerView.ViewHolder {\n\n    private final ImageView icon;\n    private final TextView text;\n\n    MessageViewHolder(View itemView) {\n      super(itemView);\n      icon = itemView.findViewById(R.id.messageAuthor);\n      text = itemView.findViewById(R.id.messageText);\n    }\n\n    private void bind(Message message) {\n      icon.setImageDrawable(message.getIcon(icon.getContext()));\n      text.setText(message.text);\n    }\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/java/chat/ReplyChipAdapter.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.java.chat;\n\nimport androidx.recyclerview.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\nimport androidx.annotation.NonNull;\nimport com.google.mlkit.nl.smartreply.SmartReplySuggestion;\nimport com.google.mlkit.samples.nl.smartreply.R;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** RecyclerView Adapter for reply messages. */\npublic class ReplyChipAdapter extends RecyclerView.Adapter<ReplyChipAdapter.ViewHolder> {\n\n  /** Listener on click. */\n  public interface ClickListener {\n\n    void onChipClick(@NonNull String chipText);\n  }\n\n  private final List<SmartReplySuggestion> suggestions = new ArrayList<>();\n  private final ClickListener listener;\n\n  public ReplyChipAdapter(@NonNull ClickListener listener) {\n    this.listener = listener;\n  }\n\n  @NonNull\n  @Override\n  public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n    View v =\n        LayoutInflater.from(parent.getContext()).inflate(R.layout.smart_reply_chip, parent, false);\n    return new ViewHolder(v);\n  }\n\n  @Override\n  public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n    SmartReplySuggestion suggestion = suggestions.get(position);\n    holder.bind(suggestion);\n  }\n\n  @Override\n  public int getItemCount() {\n    return suggestions.size();\n  }\n\n  public void setSuggestions(List<SmartReplySuggestion> suggestions) {\n    this.suggestions.clear();\n    this.suggestions.addAll(suggestions);\n    notifyDataSetChanged();\n  }\n\n  /** View holder to bind suggestions. */\n  public class ViewHolder extends RecyclerView.ViewHolder {\n\n    private final TextView text;\n\n    public ViewHolder(@NonNull View itemView) {\n      super(itemView);\n      this.text = itemView.findViewById(R.id.smartReplyText);\n    }\n\n    public void bind(final SmartReplySuggestion suggestion) {\n      text.setText(suggestion.getText());\n      itemView.setOnClickListener(view -> listener.onChipClick(suggestion.getText()));\n    }\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/java/model/Message.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.java.model;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.graphics.PorterDuff;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport androidx.annotation.NonNull;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.graphics.drawable.DrawableCompat;\nimport com.google.mlkit.samples.nl.smartreply.R;\n\n/** Represents a chat message. */\npublic class Message {\n\n  public final String text;\n  public final boolean isLocalUser;\n  public final long timestamp;\n\n  public Message(String text, boolean isLocalUser, long timestamp) {\n    this.text = text;\n    this.isLocalUser = isLocalUser;\n    this.timestamp = timestamp;\n  }\n\n  @NonNull\n  public Drawable getIcon(Context context) {\n    Drawable drawable = ContextCompat.getDrawable(context, R.drawable.ic_tag_faces_black_24dp);\n    if (drawable == null) {\n      throw new IllegalStateException(\"Could not get drawable ic_tag_faces_black_24dp\");\n    }\n\n    // See:\n    // https://stackoverflow.com/questions/36731919/drawablecompat-settint-not-working-on-api-19\n    drawable = DrawableCompat.wrap(drawable);\n    int color = isLocalUser ? Color.BLUE : Color.RED;\n    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n      DrawableCompat.setTint(drawable.mutate(), color);\n    } else {\n      drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);\n    }\n\n    return drawable;\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/kotlin/MainActivityKotlin.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.kotlin\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.samples.nl.smartreply.R\nimport com.google.mlkit.samples.nl.smartreply.kotlin.chat.ChatFragment\n\n/** Default launcher activity. */\nclass MainActivityKotlin : AppCompatActivity() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.main_smartreply_activity)\n\n    if (savedInstanceState == null) {\n      supportFragmentManager\n        .beginTransaction()\n        .replace(R.id.container, ChatFragment.newInstance())\n        .commitNow()\n    }\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/kotlin/chat/ChatFragment.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.kotlin.chat\n\nimport android.annotation.SuppressLint\nimport androidx.lifecycle.ViewModelProvider\nimport android.content.Context\nimport android.os.Bundle\nimport androidx.fragment.app.Fragment\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport android.text.TextUtils\nimport android.view.LayoutInflater\nimport android.view.Menu\nimport android.view.MenuInflater\nimport android.view.MenuItem\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.Button\nimport android.widget.TextView\nimport androidx.core.content.ContextCompat\nimport com.google.mlkit.samples.nl.smartreply.R\nimport com.google.mlkit.samples.nl.smartreply.kotlin.model.Message\nimport java.util.ArrayList\nimport java.util.Calendar\n\n/** Represents an individual chat message. */\nclass ChatFragment : Fragment(), ReplyChipAdapter.ClickListener {\n\n  private lateinit var viewModel: ChatViewModel\n  private lateinit var inputText: TextView\n  private lateinit var sendButton: Button\n  private lateinit var switchUserButton: Button\n\n  private lateinit var chatRecycler: RecyclerView\n  private lateinit var chatAdapter: MessageListAdapter\n\n  private lateinit var smartRepliesRecyler: RecyclerView\n  private lateinit var chipAdapter: ReplyChipAdapter\n\n  private lateinit var emulatedUserText: TextView\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setHasOptionsMenu(true)\n  }\n\n  override fun onCreateView(\n    inflater: LayoutInflater,\n    container: ViewGroup?,\n    savedInstanceState: Bundle?\n  ): View? {\n    return inflater.inflate(R.layout.chat_fragment, container, false)\n  }\n\n  @SuppressLint(\"ClickableViewAccessibility\")\n  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n    super.onViewCreated(view, savedInstanceState)\n\n    viewModel = ViewModelProvider(this).get(ChatViewModel::class.java)\n\n    chatRecycler = view.findViewById(R.id.chatHistory)\n    emulatedUserText = view.findViewById(R.id.switchText)\n    smartRepliesRecyler = view.findViewById(R.id.smartRepliesRecycler)\n    inputText = view.findViewById(R.id.inputText)\n    sendButton = view.findViewById(R.id.button)\n    switchUserButton = view.findViewById(R.id.switchEmulatedUser)\n\n    // Set up recycler view for chat messages\n    val layoutManager = LinearLayoutManager(context)\n    chatRecycler.layoutManager = layoutManager\n    chatAdapter = MessageListAdapter()\n\n    // Set up recycler view for smart replies\n    val chipManager = LinearLayoutManager(context)\n    chipManager.orientation = RecyclerView.HORIZONTAL\n    chipAdapter = ReplyChipAdapter(this)\n    smartRepliesRecyler.layoutManager = chipManager\n    smartRepliesRecyler.adapter = chipAdapter\n\n    chatRecycler.adapter = chatAdapter\n    chatRecycler.setOnTouchListener { touchView, _ ->\n      val imm = requireContext().getSystemService(\n        Context.INPUT_METHOD_SERVICE\n      ) as InputMethodManager\n      imm.hideSoftInputFromWindow(touchView.windowToken, 0)\n      false\n    }\n\n    switchUserButton.setOnClickListener {\n      chatAdapter.emulatingRemoteUser = !chatAdapter.emulatingRemoteUser\n      viewModel.switchUser()\n    }\n\n    sendButton.setOnClickListener(\n      View.OnClickListener {\n        val input = inputText.text.toString()\n        if (TextUtils.isEmpty(input)) {\n          return@OnClickListener\n        }\n\n        viewModel.addMessage(input)\n        inputText.text = \"\"\n      }\n    )\n\n    viewModel.getSuggestions().observe(\n      viewLifecycleOwner, { suggestions -> chipAdapter.setSuggestions(suggestions!!) }\n    )\n\n    viewModel.messages.observe(\n      viewLifecycleOwner,\n      { messages ->\n        chatAdapter.setMessages(messages!!)\n        if (chatAdapter.itemCount > 0) {\n          chatRecycler.smoothScrollToPosition(chatAdapter.itemCount - 1)\n        }\n      }\n    )\n\n    viewModel.getEmulatingRemoteUser().observe(\n      viewLifecycleOwner,\n      { isEmulatingRemoteUser ->\n        if (isEmulatingRemoteUser!!) {\n          emulatedUserText.setText(R.string.chatting_as_red)\n          emulatedUserText.setTextColor(ContextCompat.getColor(requireContext(), R.color.red))\n        } else {\n          emulatedUserText.setText(R.string.chatting_as_blue)\n          emulatedUserText.setTextColor(ContextCompat.getColor(requireContext(), R.color.blue))\n        }\n      }\n    )\n\n    // Only set initial message for the new ViewModel instance.\n    if (viewModel.messages.value == null) {\n      val messageList = ArrayList<Message>()\n      messageList.add(Message(\"Hello. How are you?\", false, System.currentTimeMillis()))\n      viewModel.setMessages(messageList)\n    }\n  }\n\n  override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {\n    super.onCreateOptionsMenu(menu, inflater)\n    inflater.inflate(R.menu.chat_fragment_actions, menu)\n  }\n\n  override fun onOptionsItemSelected(item: MenuItem): Boolean {\n    super.onOptionsItemSelected(item)\n    when (item.itemId) {\n      R.id.generateHistoryBasic -> {\n        generateChatHistoryBasic()\n        return true\n      }\n      R.id.generateHistorySensitive -> {\n        generateChatHistoryWithSensitiveContent()\n        return true\n      }\n      R.id.clearHistory -> {\n        viewModel.setMessages(ArrayList())\n        return true\n      }\n    }\n    return false\n  }\n\n  override fun onChipClick(chipText: String) {\n    inputText.text = chipText\n  }\n\n  private fun generateChatHistoryBasic() {\n    val messageList = ArrayList<Message>()\n    val calendar = Calendar.getInstance()\n\n    calendar.set(Calendar.DATE, -1)\n    messageList.add(Message(\"Hello\", true, calendar.timeInMillis))\n\n    calendar.add(Calendar.MINUTE, 10)\n    messageList.add(Message(\"Hey\", false, calendar.timeInMillis))\n\n    viewModel.setMessages(messageList)\n  }\n\n  private fun generateChatHistoryWithSensitiveContent() {\n    val messageList = ArrayList<Message>()\n    val calendar = Calendar.getInstance()\n\n    calendar.set(Calendar.DATE, -1)\n    messageList.add(Message(\"Hi\", false, calendar.timeInMillis))\n\n    calendar.add(Calendar.MINUTE, 10)\n    messageList.add(Message(\"How are you?\", true, calendar.timeInMillis))\n\n    calendar.add(Calendar.MINUTE, 10)\n    messageList.add(Message(\"My cat died\", false, calendar.timeInMillis))\n\n    viewModel.setMessages(messageList)\n  }\n\n  companion object {\n\n    fun newInstance(): ChatFragment {\n      return ChatFragment()\n    }\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/kotlin/chat/ChatViewModel.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.kotlin.chat\n\nimport android.app.Application\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.lifecycle.AndroidViewModel\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MediatorLiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.Observer\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.Tasks\nimport com.google.mlkit.nl.smartreply.SmartReply\nimport com.google.mlkit.nl.smartreply.SmartReplySuggestion\nimport com.google.mlkit.nl.smartreply.SmartReplySuggestionResult\nimport com.google.mlkit.nl.smartreply.TextMessage\nimport com.google.mlkit.samples.nl.smartreply.R\nimport com.google.mlkit.samples.nl.smartreply.kotlin.model.Message\nimport java.util.ArrayList\nimport java.util.UUID\n\nclass ChatViewModel(application: Application) : AndroidViewModel(application) {\n\n  private val remoteUserId = UUID.randomUUID().toString()\n\n  private val suggestions = MediatorLiveData<List<SmartReplySuggestion>>()\n  private val messageList = MutableLiveData<MutableList<Message>>()\n  private val emulatingRemoteUser = MutableLiveData<Boolean>()\n  private val smartReply = SmartReply.getClient()\n\n  val messages: LiveData<MutableList<Message>>\n    get() = messageList\n\n  companion object {\n    private const val TAG = \"ChatViewModel\"\n  }\n\n  init {\n    initSuggestionsGenerator()\n    emulatingRemoteUser.postValue(false)\n  }\n\n  fun getSuggestions(): LiveData<List<SmartReplySuggestion>> {\n    return suggestions\n  }\n\n  fun getEmulatingRemoteUser(): LiveData<Boolean> {\n    return emulatingRemoteUser\n  }\n\n  internal fun setMessages(messages: MutableList<Message>) {\n    clearSuggestions()\n    messageList.postValue(messages)\n  }\n\n  internal fun switchUser() {\n    clearSuggestions()\n    val value = emulatingRemoteUser.value!!\n    emulatingRemoteUser.postValue(!value)\n  }\n\n  private fun clearSuggestions() {\n    suggestions.postValue(ArrayList())\n  }\n\n  internal fun addMessage(message: String) {\n    var list: MutableList<Message>? = messageList.value\n    if (list == null) {\n      list = ArrayList()\n    }\n    val value = emulatingRemoteUser.value!!\n    list.add(Message(message, !value, System.currentTimeMillis()))\n    clearSuggestions()\n    messageList.postValue(list)\n  }\n\n  private fun initSuggestionsGenerator() {\n    suggestions.addSource(\n      emulatingRemoteUser,\n      Observer { isEmulatingRemoteUser ->\n        val list = messageList.value\n        if (list == null || list.isEmpty()) {\n          return@Observer\n        }\n\n        generateReplies(list, isEmulatingRemoteUser!!).addOnSuccessListener { result ->\n          suggestions.postValue(result)\n        }\n      }\n    )\n\n    suggestions.addSource(\n      messageList,\n      Observer { list ->\n        val isEmulatingRemoteUser = emulatingRemoteUser.value\n        if (isEmulatingRemoteUser == null || list!!.isEmpty()) {\n          return@Observer\n        }\n\n        generateReplies(list, isEmulatingRemoteUser).addOnSuccessListener { result ->\n          suggestions.postValue(result)\n        }\n      }\n    )\n  }\n\n  private fun generateReplies(\n    messages: List<Message>,\n    isEmulatingRemoteUser: Boolean\n  ): Task<List<SmartReplySuggestion>> {\n    val lastMessage = messages[messages.size - 1]\n\n    // If the last message in the chat thread is not sent by the \"other\" user, don't generate\n    // smart replies.\n    if (lastMessage.isLocalUser != isEmulatingRemoteUser) {\n      return Tasks.forException(Exception(\"Not running smart reply!\"))\n    }\n\n    val chatHistory = ArrayList<TextMessage>()\n    for (message in messages) {\n      if (message.isLocalUser != isEmulatingRemoteUser) {\n        chatHistory.add(TextMessage.createForLocalUser(message.text, message.timestamp))\n      } else {\n        chatHistory.add(\n          TextMessage.createForRemoteUser(message.text, message.timestamp, remoteUserId)\n        )\n      }\n    }\n\n    return smartReply\n      .suggestReplies(chatHistory)\n      .continueWith { task ->\n        val result = task.result\n        when (result.status) {\n          SmartReplySuggestionResult.STATUS_NOT_SUPPORTED_LANGUAGE ->\n            // This error happens when the detected language is not English, as that is the\n            // only supported language in Smart Reply.\n            Toast.makeText(\n                getApplication(),\n                R.string.error_not_supported_language,\n                Toast.LENGTH_SHORT\n              )\n              .show()\n          SmartReplySuggestionResult.STATUS_NO_REPLY ->\n            // This error happens when the inference completed successfully, but no replies\n            // were returned.\n            Toast.makeText(getApplication(), R.string.error_no_reply, Toast.LENGTH_SHORT).show()\n          else -> {\n            // Do nothing.\n          }\n        }\n        result!!.suggestions\n      }\n      .addOnFailureListener { e ->\n        Log.e(TAG, \"Smart reply error\", e)\n        Toast.makeText(\n            getApplication(),\n            \"Smart reply error\" + \"\\nError: \" + e.getLocalizedMessage() + \"\\nCause: \" + e.cause,\n            Toast.LENGTH_LONG\n          )\n          .show()\n      }\n  }\n\n  override fun onCleared() {\n    super.onCleared()\n    // Instances of smartReply must be closed appropriately, so here we utilize ViewModel's\n    // onCleared() to close the smartReply instance when this ViewModel is no longer in use and\n    // destroyed.\n    smartReply.close()\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/kotlin/chat/MessageListAdapter.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.kotlin.chat\n\nimport androidx.recyclerview.widget.RecyclerView\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport com.google.mlkit.samples.nl.smartreply.R\nimport com.google.mlkit.samples.nl.smartreply.kotlin.model.Message\nimport java.util.ArrayList\n\ninternal class MessageListAdapter : RecyclerView.Adapter<MessageListAdapter.MessageViewHolder>() {\n\n  private val messagesList = ArrayList<Message>()\n\n  var emulatingRemoteUser = false\n    set(emulatingRemoteUser) {\n      field = emulatingRemoteUser\n      notifyDataSetChanged()\n    }\n\n  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {\n    val v = LayoutInflater.from(parent.context).inflate(viewType, parent, false) as ViewGroup\n    return MessageViewHolder(v)\n  }\n\n  override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {\n    val message = messagesList[position]\n    holder.bind(message)\n  }\n\n  override fun getItemViewType(position: Int): Int {\n    return if (\n      messagesList[position].isLocalUser && !emulatingRemoteUser ||\n      !messagesList[position].isLocalUser && emulatingRemoteUser\n    ) {\n      R.layout.item_message_local\n    } else {\n      R.layout.item_message_remote\n    }\n  }\n\n  override fun getItemCount(): Int {\n    return messagesList.size\n  }\n\n  fun setMessages(messages: List<Message>) {\n    messagesList.clear()\n    messagesList.addAll(messages)\n    notifyDataSetChanged()\n  }\n\n  inner class MessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n\n    private val icon: ImageView\n    private val text: TextView\n\n    init {\n      icon = itemView.findViewById(R.id.messageAuthor)\n      text = itemView.findViewById(R.id.messageText)\n    }\n\n    fun bind(message: Message) {\n      icon.setImageDrawable(message.getIcon(icon.context))\n      text.text = message.text\n    }\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/kotlin/chat/ReplyChipAdapter.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.kotlin.chat\n\nimport androidx.recyclerview.widget.RecyclerView\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.TextView\nimport com.google.mlkit.nl.smartreply.SmartReplySuggestion\nimport com.google.mlkit.samples.nl.smartreply.R\nimport java.util.ArrayList\n\nclass ReplyChipAdapter(\n  private val listener: ClickListener\n) : RecyclerView.Adapter<ReplyChipAdapter.ViewHolder>() {\n\n  private val suggestions = ArrayList<SmartReplySuggestion>()\n\n  interface ClickListener {\n\n    fun onChipClick(chipText: String)\n  }\n\n  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {\n    val v = LayoutInflater.from(parent.context).inflate(R.layout.smart_reply_chip, parent, false)\n    return ViewHolder(v)\n  }\n\n  override fun onBindViewHolder(holder: ViewHolder, position: Int) {\n    val suggestion = suggestions[position]\n    holder.bind(suggestion)\n  }\n\n  override fun getItemCount(): Int {\n    return suggestions.size\n  }\n\n  fun setSuggestions(suggestions: List<SmartReplySuggestion>) {\n    this.suggestions.clear()\n    this.suggestions.addAll(suggestions)\n    notifyDataSetChanged()\n  }\n\n  inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n\n    private val text: TextView = itemView.findViewById(R.id.smartReplyText)\n\n    fun bind(suggestion: SmartReplySuggestion) {\n      text.text = suggestion.text\n      itemView.setOnClickListener { listener.onChipClick(suggestion.text) }\n    }\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/java/com/google/mlkit/samples/nl/smartreply/kotlin/model/Message.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.smartreply.kotlin.model\n\nimport android.content.Context\nimport android.graphics.Color\nimport android.graphics.drawable.Drawable\nimport androidx.core.content.ContextCompat\nimport androidx.core.graphics.drawable.DrawableCompat\nimport com.google.mlkit.samples.nl.smartreply.R\n\nclass Message(val text: String, val isLocalUser: Boolean, val timestamp: Long) {\n\n  fun getIcon(context: Context): Drawable {\n    val drawable =\n      ContextCompat.getDrawable(context, R.drawable.ic_tag_faces_black_24dp)\n        ?: throw IllegalStateException(\"Could not get drawable ic_tag_faces_black_24dp\")\n\n    if (isLocalUser) {\n      DrawableCompat.setTint(drawable.mutate(), Color.BLUE)\n    } else {\n      DrawableCompat.setTint(drawable.mutate(), Color.RED)\n    }\n\n    return drawable\n  }\n}\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/drawable/ic_camera_front_black_24dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#000000\"\n      android:pathData=\"M10,20L5,20v2h5v2l3,-3 -3,-3v2zM14,20v2h5v-2h-5zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -1.99,0.9 -1.99,2S10.9,8 12,8zM17,0L7,0C5.9,0 5,0.9 5,2v14c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,2c0,-1.1 -0.9,-2 -2,-2zM7,2h10v10.5c0,-1.67 -3.33,-2.5 -5,-2.5s-5,0.83 -5,2.5L7,2z\" />\n</vector>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#008577\"\n      android:pathData=\"M0,0h108v108h-108z\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M9,0L9,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,0L19,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M29,0L29,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M39,0L39,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M49,0L49,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M59,0L59,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M69,0L69,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M79,0L79,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M89,0L89,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M99,0L99,108\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,9L108,9\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,19L108,19\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,29L108,29\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,39L108,39\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,49L108,49\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,59L108,59\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,69L108,69\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,79L108,79\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,89L108,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M0,99L108,99\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,29L89,29\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,39L89,39\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,49L89,49\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,59L89,59\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,69L89,69\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M19,79L89,79\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M29,19L29,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M39,19L39,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M49,19L49,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M59,19L59,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M69,19L69,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n  <path\n      android:fillColor=\"#00000000\"\n      android:pathData=\"M79,19L79,89\"\n      android:strokeColor=\"#33FFFFFF\"\n      android:strokeWidth=\"0.8\" />\n</vector>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/drawable/ic_tag_faces_black_24dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#000000\"\n      android:pathData=\"M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z\" />\n</vector>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportHeight=\"129.06\"\n    android:viewportWidth=\"172.43\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#66ff99\"\n      android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#66ff99\"\n      android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/drawable/rounded_rectangle_blue.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n  <!-- View background color -->\n  <corners android:radius=\"20dp\"></corners>\n\n  <!-- The radius makes the corners rounded -->\n  <solid android:color=\"#81D4FA\"></solid>\n</shape>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/drawable/rounded_rectangle_gray.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n  <!-- View background color -->\n  <corners android:radius=\"8dp\"></corners>\n\n  <!-- The radius makes the corners rounded -->\n  <solid android:color=\"#CECECE\"></solid>\n</shape>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/drawable/rounded_rectangle_light_gray.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n  <!-- View background color -->\n  <corners android:radius=\"8dp\"></corners>\n\n  <!-- The radius makes the corners rounded -->\n  <solid android:color=\"#E6E6E6\"></solid>\n</shape>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n  <path\n      android:fillType=\"evenOdd\"\n      android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n      android:strokeColor=\"#00000000\"\n      android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n      <gradient\n          android:endX=\"78.5885\"\n          android:endY=\"90.9159\"\n          android:startX=\"48.7653\"\n          android:startY=\"61.0927\"\n          android:type=\"linear\">\n        <item\n            android:color=\"#44000000\"\n            android:offset=\"0.0\" />\n        <item\n            android:color=\"#00000000\"\n            android:offset=\"1.0\" />\n      </gradient>\n    </aapt:attr>\n  </path>\n  <path\n      android:fillColor=\"#FFFFFF\"\n      android:fillType=\"nonZero\"\n      android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n      android:strokeColor=\"#00000000\"\n      android:strokeWidth=\"1\" />\n</vector>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/layout/chat_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/main\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.google.mlkit.samples.nl.smartreply.java.chat.ChatFragment\">\n\n  <TextView\n      android:id=\"@+id/switchText\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginBottom=\"8dp\"\n      android:layout_marginStart=\"8dp\"\n      android:layout_marginLeft=\"8dp\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      app:layout_constraintEnd_toStartOf=\"@id/switchEmulatedUser\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintTop_toBottomOf=\"@id/inputTextLayout\"\n      tools:text=\"Chatting as Alice\" />\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/smartRepliesRecycler\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginBottom=\"4dp\"\n      android:orientation=\"horizontal\"\n      app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n      app:layout_constraintBottom_toTopOf=\"@id/inputTextLayout\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      tools:listitem=\"@layout/smart_reply_chip\" />\n\n  <androidx.recyclerview.widget.RecyclerView\n      android:id=\"@+id/chatHistory\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"0dp\"\n      android:layout_margin=\"8dp\"\n      android:scrollbars=\"vertical\"\n      app:layout_constraintBottom_toTopOf=\"@id/smartRepliesRecycler\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintTop_toTopOf=\"parent\"\n      tools:listitem=\"@layout/item_message_local\" />\n\n  <com.google.android.material.button.MaterialButton\n      android:id=\"@+id/button\"\n      style=\"@style/Widget.MaterialComponents.Button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_margin=\"8dp\"\n      android:text=\"@string/send_message_button_text\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintStart_toEndOf=\"@id/inputTextLayout\"\n      app:layout_constraintTop_toTopOf=\"@id/inputTextLayout\" />\n\n  <com.google.android.material.button.MaterialButton\n      android:id=\"@+id/switchEmulatedUser\"\n      style=\"@style/Widget.MaterialComponents.Button.TextButton\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginBottom=\"8dp\"\n      android:layout_marginEnd=\"8dp\"\n      android:layout_marginRight=\"8dp\"\n      android:text=\"@string/switch_user_button\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintStart_toEndOf=\"@id/switchText\"\n      app:layout_constraintTop_toBottomOf=\"@id/inputTextLayout\" />\n\n  <com.google.android.material.textfield.TextInputLayout\n      android:id=\"@+id/inputTextLayout\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"wrap_content\"\n      android:hint=\"@string/hint_input_text\"\n      app:layout_constraintBottom_toTopOf=\"@id/switchText\"\n      app:layout_constraintEnd_toStartOf=\"@id/button\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintTop_toBottomOf=\"@id/chatHistory\">\n\n    <com.google.android.material.textfield.TextInputEditText\n        android:id=\"@+id/inputText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"8dp\"\n        android:ems=\"10\"\n        android:inputType=\"textCapSentences\" />\n  </com.google.android.material.textfield.TextInputLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/layout/item_message_local.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n  <TextView\n      android:id=\"@+id/messageText\"\n      style=\"@style/Base.TextAppearance.AppCompat.Display1\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginEnd=\"@dimen/margin_message_text_icon\"\n      android:padding=\"8dp\"\n      android:background=\"@drawable/rounded_rectangle_gray\"\n      android:gravity=\"start\"\n      android:textSize=\"14sp\"\n      android:maxEms=\"20\"\n      android:singleLine=\"false\"\n      app:layout_constraintEnd_toStartOf=\"@id/messageAuthor\"\n      app:layout_constraintTop_toTopOf=\"@id/messageAuthor\"\n      tools:text=\"Message text\" />\n\n  <android.widget.ImageView\n      android:id=\"@+id/messageAuthor\"\n      android:layout_width=\"@dimen/message_author_icon_size\"\n      android:layout_height=\"@dimen/message_author_icon_size\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintTop_toTopOf=\"parent\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/layout/item_message_remote.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n  <TextView\n      android:id=\"@+id/messageText\"\n      style=\"@style/Base.TextAppearance.AppCompat.Display1\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"@dimen/margin_message_text_icon\"\n      android:padding=\"8dp\"\n      android:background=\"@drawable/rounded_rectangle_light_gray\"\n      android:gravity=\"start\"\n      android:textSize=\"14sp\"\n      android:maxEms=\"20\"\n      android:singleLine=\"false\"\n      app:layout_constraintStart_toEndOf=\"@id/messageAuthor\"\n      app:layout_constraintTop_toTopOf=\"@id/messageAuthor\" />\n\n  <android.widget.ImageView\n      android:id=\"@+id/messageAuthor\"\n      android:layout_width=\"@dimen/message_author_icon_size\"\n      android:layout_height=\"@dimen/message_author_icon_size\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintTop_toTopOf=\"parent\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/layout/main_smartreply_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.google.mlkit.samples.nl.smartreply.java.MainActivityJava\" />\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/layout/smart_reply_chip.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\">\n\n  <TextView\n      android:id=\"@+id/smartReplyText\"\n      style=\"@style/Base.TextAppearance.AppCompat.Display1\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"8dp\"\n      android:layout_marginEnd=\"8dp\"\n      android:padding=\"8dp\"\n      android:background=\"@drawable/rounded_rectangle_blue\"\n      android:textSize=\"14sp\"\n      app:layout_constraintBottom_toTopOf=\"@id/inputText\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      tools:text=\"Smart reply 1\" />\n\n</FrameLayout>"
  },
  {
    "path": "android/smartreply/app/src/main/res/menu/chat_fragment_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n  <item\n      android:id=\"@+id/generateHistoryBasic\"\n      android:title=\"@string/title_generate_basic_history\"\n      app:showAsAction=\"never\" />\n  <item\n      android:id=\"@+id/generateHistorySensitive\"\n      android:title=\"@string/title_generate_sensitive_history\"\n      app:showAsAction=\"never\" />\n  <item\n      android:id=\"@+id/clearHistory\"\n      android:title=\"@string/title_clear_history\"\n      app:showAsAction=\"never\" />\n</menu>"
  },
  {
    "path": "android/smartreply/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"colorPrimary\">#4285F4</color>\n  <color name=\"colorPrimaryDark\">#3367D6</color>\n  <color name=\"colorAccent\">#F4B400</color>\n\n  <color name=\"blue\">#4286f4</color>\n  <color name=\"red\">#f44242</color>\n</resources>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <dimen name=\"message_author_icon_size\">40dp</dimen>\n  <dimen name=\"margin_message_text_icon\">8dp</dimen>\n</resources>"
  },
  {
    "path": "android/smartreply/app/src/main/res/values/strings.xml",
    "content": "<resources>\n  <string name=\"app_name\">MLKit-SmartReply</string>\n  <string name=\"send_message_button_text\">Send</string>\n  <string name=\"empty_input_message\">Enter some input text first.</string>\n  <string name=\"title_switch_user\">Switch emulated user</string>\n  <string name=\"hint_input_text\">Enter message text</string>\n  <string name=\"title_generate_sensitive_history\">Generate history with sensitive content</string>\n  <string name=\"title_generate_basic_history\">Generate basic history</string>\n  <string name=\"switch_user_button\">SWITCH</string>\n  <string name=\"title_clear_history\">Clear chat history</string>\n  <string name=\"chatting_as_red\">Chatting as Red User</string>\n  <string name=\"chatting_as_blue\">Chatting as Blue User</string>\n\n  <!-- Error toast for when non-English language is used [CHAR_LIMIT=80] -->\n  <string name=\"error_not_supported_language\">A non-English language was\n      detected, therefore no replies were generated.</string>\n  <!-- Error toast for when no smart replies are generated [CHAR_LIMIT=75] -->\n  <string name=\"error_no_reply\">Success! But no appropriate replies were generated.</string>\n</resources>\n"
  },
  {
    "path": "android/smartreply/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n  <!-- Base application theme. -->\n  <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.DarkActionBar\">\n    <!-- Customize your theme here. -->\n    <item name=\"colorPrimary\">@color/colorPrimary</item>\n    <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n    <item name=\"colorAccent\">@color/colorAccent</item>\n  </style>\n\n</resources>\n"
  },
  {
    "path": "android/smartreply/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.9.0'\n\n    repositories {\n        mavenLocal()\n        mavenCentral()\n        google()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.3.1'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        mavenCentral()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/smartreply/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Jan 24 22:50:04 UTC 2022\ndistributionBase=GRADLE_USER_HOME\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.5-bin.zip\ndistributionPath=wrapper/dists\nzipStorePath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\n"
  },
  {
    "path": "android/smartreply/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\nandroid.useAndroidX=true\nandroid.enableJetifier=true"
  },
  {
    "path": "android/smartreply/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/smartreply/gradlew.bat",
    "content": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\n@rem you may not use this file except in compliance with the License.\n@rem You may obtain a copy of the License at\n@rem\n@rem      http://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega"
  },
  {
    "path": "android/smartreply/settings.gradle",
    "content": "rootProject.name = 'mlkit_smart_reply_sample'\ninclude ':app'\ninclude ':internal:chooserx'\nproject(':internal:chooserx').projectDir = file('../internal/chooserx')"
  },
  {
    "path": "android/speech/README.md",
    "content": "# ML Kit GenAI Speech API Quickstart\n\n* [Read more about ML Kit GenAI APIs](https://developers.google.com/ml-kit/genai)\n\n## Introduction\n\nThis sample app demonstrates how to use the GenAI Speech API.\n\n- Type or select the `locale` in demo app.\n- Select the `mode` and `AudioSource` in demo app.\n- Click the `download` button to check feature availability.\n- Click the `recording` button to start real time speech recognition.\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/genai)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2025 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements. See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership. The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License. You may obtain a copy of\nthe License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/speech/app/build.gradle",
    "content": "/*\n * Copyright 2025 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\napply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\n\nandroid {\n  namespace = \"com.google.mlkit.genai.speech.demo\"\n  compileSdk 35\n\n  defaultConfig {\n    applicationId 'com.google.mlkit.genai.speech.demo'\n    minSdk 26\n    targetSdk 35\n    versionCode 1\n    versionName '1.0'\n\n    testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'\n  }\n\n  lint {\n        disable 'NullSafeMutableLiveData'\n  }\n\n  buildTypes {\n    configureEach {\n      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n    }\n    release {\n      minifyEnabled true\n      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n    }\n    debug {\n      isDefault true\n      minifyEnabled false\n      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n    }\n    testBuildType \"debug\"\n  }\n  compileOptions {\n    sourceCompatibility JavaVersion.VERSION_17\n    targetCompatibility JavaVersion.VERSION_17\n  }\n  kotlinOptions {\n    jvmTarget = \"17\"\n  }\n\n}\n\ndependencies {\n  implementation 'com.google.mlkit:genai-speech-recognition:1.0.0-alpha1'\n  implementation 'com.google.android.material:material:1.12.0'\n  implementation 'com.google.guava:guava:32.0.1-jre'\n  implementation 'androidx.concurrent:concurrent-futures:1.3.0'\n  // Coroutines dependencies\n  implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2'\n  implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2'\n  // Lifecycle library\n  implementation \"androidx.lifecycle:lifecycle-runtime-ktx:2.9.4\"\n\n  androidTestImplementation 'androidx.test:rules:1.6.1'\n  androidTestImplementation 'androidx.test:runner:1.6.2'\n  androidTestImplementation 'androidx.test.ext:junit:1.2.1'\n  androidTestImplementation 'com.google.truth:truth:1.1.3'\n}\n"
  },
  {
    "path": "android/speech/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License. -->\n<manifest\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.google.mlkit.genai.speech.demo\">\n    <uses-permission android:name=\"android.permission.RECORD_AUDIO\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <application\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/Theme.SpeechToTextDemo\"\n        tools:targetApi=\"34\">\n        <activity\n            android:name=\".SpeechRecognitionActivity\"\n            android:exported=\"true\"\n            android:label=\"@string/speech_recognition_title\"\n            android:theme=\"@style/Theme.SpeechToTextDemo\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "android/speech/app/src/main/java/com/google/mlkit/genai/speech/demo/SpeechRecognitionActivity.kt",
    "content": "/*\n * Copyright 2025 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.genai.speech.demo\n\nimport android.Manifest\nimport android.content.pm.PackageManager\nimport android.media.AudioFormat\nimport android.media.AudioRecord\nimport android.media.MediaRecorder\nimport android.os.Build\nimport android.os.Bundle\nimport android.os.ParcelFileDescriptor\nimport android.util.Log\nimport android.widget.ArrayAdapter\nimport android.widget.AutoCompleteTextView\nimport android.widget.Button\nimport android.widget.Spinner\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.activity.ComponentActivity\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.lifecycleScope\nimport androidx.lifecycle.repeatOnLifecycle\nimport com.google.mlkit.genai.common.DownloadStatus\nimport com.google.mlkit.genai.common.FeatureStatus\nimport com.google.mlkit.genai.common.audio.AudioSource\nimport com.google.mlkit.genai.speechrecognition.SpeechRecognition\nimport com.google.mlkit.genai.speechrecognition.SpeechRecognizer\nimport com.google.mlkit.genai.speechrecognition.SpeechRecognizerOptions\nimport com.google.mlkit.genai.speechrecognition.SpeechRecognizerRequest\nimport com.google.mlkit.genai.speechrecognition.SpeechRecognizerResponse\nimport com.google.mlkit.genai.speechrecognition.speechRecognizerOptions\nimport com.google.mlkit.genai.speechrecognition.speechRecognizerRequest\nimport java.io.File\nimport java.io.FileOutputStream\nimport java.io.IOException\nimport java.text.DecimalFormat\nimport java.util.IllformedLocaleException\nimport java.util.Locale\nimport kotlinx.coroutines.launch\n\nclass SpeechRecognitionActivity : ComponentActivity() {\n  private var speechRecognizer: SpeechRecognizer? = null\n\n  private lateinit var textView: TextView\n\n  private lateinit var micButton: Button\n\n  private lateinit var downloadButton: Button\n\n  private lateinit var languageSpinner: AutoCompleteTextView\n  private lateinit var modeSpinner: Spinner\n  private lateinit var audioSourceSpinner: Spinner\n\n  private lateinit var pipe: Array<ParcelFileDescriptor>\n  private var recordingThread: Thread? = null\n  private var isRecording = false\n  private var audioRecord: AudioRecord? = null\n  private var audioFile: File? = null\n  private var curText: String = \"\"\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_speech_recognition)\n    textView = findViewById(R.id.text_view)\n    micButton = findViewById(R.id.mic_button)\n    downloadButton = findViewById(R.id.download_button)\n    languageSpinner = findViewById(R.id.language_spinner)\n    modeSpinner = findViewById(R.id.mode_spinner)\n    audioSourceSpinner = findViewById(R.id.audiosource_spinner)\n\n    // setup language spinner\n    val adapter =\n      ArrayAdapter.createFromResource(\n        this,\n        R.array.languages_array,\n        android.R.layout.simple_dropdown_item_1line,\n      )\n    languageSpinner.setAdapter(adapter)\n    languageSpinner.setText(adapter.getItem(0).toString(), false)\n\n    // setup mode spinner\n    val modeAdapter =\n      ArrayAdapter.createFromResource(\n        this,\n        R.array.modes_array,\n        android.R.layout.simple_spinner_item,\n      )\n    modeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n    modeSpinner.adapter = modeAdapter\n    modeSpinner.setSelection(0)\n\n    // setup audio source spinner\n    val audioSourceAdapter =\n      ArrayAdapter.createFromResource(\n        this,\n        R.array.audiosource_array,\n        android.R.layout.simple_spinner_item,\n      )\n    audioSourceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n    audioSourceSpinner.adapter = audioSourceAdapter\n    audioSourceSpinner.setSelection(0)\n\n    micButton.setOnClickListener {\n      Log.i(TAG, \"micButton clicked, isRecording: $isRecording\")\n      if (isRecording) {\n        stopRecording()\n      } else {\n        if (createAndSetSpeechRecognizer()) {\n          Log.i(TAG, \"micButton clicked, check feature status\")\n          lifecycleScope.launch { checkFeatureStatusAndStartRecognition() }\n        }\n      }\n    }\n\n    downloadButton.setOnClickListener {\n      if (createAndSetSpeechRecognizer()) {\n        lifecycleScope.launch { checkFeatureStatusAndDownloadIfNeeded() }\n      }\n    }\n\n    // Request audio recording permission\n    val permissions =\n      arrayOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE)\n    if (\n      ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) !=\n        PackageManager.PERMISSION_GRANTED\n    ) {\n      ActivityCompat.requestPermissions(this, permissions, PERMISSIONS_REQUEST_CODE)\n    }\n  }\n\n  override fun onDestroy() {\n    super.onDestroy()\n    speechRecognizer?.close()\n  }\n\n  override fun onRequestPermissionsResult(\n    requestCode: Int,\n    permissions: Array<out String>,\n    grantResults: IntArray,\n    deviceId: Int,\n  ) {\n    if (requestCode == PERMISSIONS_REQUEST_CODE) {\n      if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n        // Permission granted\n      } else {\n        // Permission denied, show an error or disable functionality\n        Toast.makeText(this, \"Audio recording permission denied\", Toast.LENGTH_SHORT).show()\n      }\n    }\n    super.onRequestPermissionsResult(requestCode, permissions, grantResults, deviceId)\n  }\n\n  private suspend fun processSpeechRecognitionResponse(request: SpeechRecognizerRequest) {\n    speechRecognizer?.startRecognition(request)?.collect { response ->\n      when (response) {\n        is SpeechRecognizerResponse.PartialTextResponse -> {\n          runOnUiThread {\n            textView.text = getString(R.string.text_transcription_format, curText, response.text)\n            micButton.text = getString(R.string.text_stop_recording)\n          }\n        }\n        is SpeechRecognizerResponse.FinalTextResponse -> {\n          runOnUiThread {\n            textView.text = getString(R.string.text_transcription_format, curText, response.text)\n            micButton.text = getString(R.string.text_stop_recording)\n            curText += response.text\n          }\n        }\n        is SpeechRecognizerResponse.CompletedResponse -> {\n          Log.i(TAG, \"CompletedResponse\")\n          stopRecording()\n          runOnUiThread {\n            micButton.text = getString(R.string.text_start_recording)\n            Toast.makeText(this, \"Transcription completed.\", Toast.LENGTH_SHORT).show()\n          }\n          curText = \"\"\n        }\n        is SpeechRecognizerResponse.ErrorResponse -> {\n          Log.i(TAG, \"ErrorResponse\")\n          stopRecording()\n          runOnUiThread {\n            textView.text =\n              getString(R.string.text_error_format, response.e.message, response.e.errorCode)\n            micButton.text = getString(R.string.text_start_recording)\n          }\n          response.e.printStackTrace()\n          curText = \"\"\n        }\n      }\n    }\n  }\n\n  private suspend fun startSpeechRecognition() {\n    runOnUiThread {\n      textView.text = \"\"\n      micButton.text = getString(R.string.text_stop_recording)\n      setControlUiEnabled(false)\n    }\n\n    isRecording = true\n    if (audioSourceSpinner.selectedItem.toString() == SOURCE_MICPHONE) {\n      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {\n        Toast.makeText(this, \"Microphone input requires API level 31 or higher\", Toast.LENGTH_SHORT)\n          .show()\n        stopRecording()\n        return\n      }\n      processSpeechRecognitionResponse(\n        speechRecognizerRequest { audioSource = AudioSource.fromMic() }\n      )\n    } else {\n      // Create a temporary file to store the audio\n      audioFile = File.createTempFile(\"audio_record\", \".pcm\", cacheDir)\n\n      // The following code demonstrates how to stream audio data from the microphone to the\n      // SpeechRecognizer using a ParcelFileDescriptor. For most microphone-based use cases,\n      // it is simpler to use `AudioSource.fromMic()` as shown above.\n      pipe = ParcelFileDescriptor.createPipe()\n      try {\n        val bufferSize =\n          AudioRecord.getMinBufferSize(\n            AUDIO_SAMPLE_RATE,\n            AudioFormat.CHANNEL_IN_MONO,\n            AudioFormat.ENCODING_PCM_16BIT,\n          )\n        if (\n          ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) !=\n            PackageManager.PERMISSION_GRANTED\n        ) {\n          Toast.makeText(this, \"Audio recording permission denied\", Toast.LENGTH_SHORT).show()\n          return\n        }\n        audioRecord =\n          AudioRecord(\n            MediaRecorder.AudioSource.MIC,\n            AUDIO_SAMPLE_RATE,\n            AudioFormat.CHANNEL_IN_MONO,\n            AudioFormat.ENCODING_PCM_16BIT,\n            bufferSize,\n          )\n        audioRecord?.startRecording()\n\n        runOnUiThread { micButton.text = getString(R.string.text_stop_recording) }\n\n        recordingThread = Thread { writeAudioDataToFile(bufferSize) }\n        recordingThread?.start()\n\n        // Start the recording thread first and then start the recognition.\n        processSpeechRecognitionResponse(\n          speechRecognizerRequest { audioSource = AudioSource.fromPfd(pipe[0]) }\n        )\n      } catch (e: IOException) {\n        runOnUiThread {\n          textView.text = getString(R.string.text_error_create_file)\n          micButton.text = getString(R.string.text_start_recording)\n        }\n        isRecording = false\n        return\n      }\n    }\n  }\n\n  private fun writeAudioDataToFile(bufferSize: Int) {\n    val audioData = ByteArray(bufferSize)\n    var fileOutputStream: FileOutputStream? = null\n\n    try {\n      fileOutputStream = FileOutputStream(pipe[1].fileDescriptor)\n      while (isRecording) {\n        // Read audio data into the buffer\n        val read = audioRecord?.read(audioData, 0, bufferSize) ?: 0\n\n        if (read > 0) {\n          Log.i(TAG, \"Write data size: \" + read)\n          // Write the audio data to the file\n          fileOutputStream.write(audioData, 0, read)\n        }\n      }\n    } catch (e: IOException) {\n      e.printStackTrace()\n    } finally {\n      try {\n        fileOutputStream?.close()\n      } catch (e: IOException) {\n        e.printStackTrace()\n      }\n    }\n  }\n\n  private fun stopRecording() {\n    isRecording = false\n    runOnUiThread {\n      micButton.text = getString(R.string.text_start_recording)\n      setControlUiEnabled(true)\n    }\n\n    lifecycleScope.launch { speechRecognizer?.stopRecognition() }\n    if (audioSourceSpinner.selectedItem.toString() == SOURCE_MICPHONE) {\n      return\n    }\n\n    // Stop and release the AudioRecord object\n    audioRecord?.apply {\n      stop()\n      release()\n    }\n    audioRecord = null\n\n    // Stop the recording thread\n    recordingThread?.interrupt()\n    recordingThread = null\n\n    // Close the pipe\n    pipe[0].close()\n    pipe[1].close()\n  }\n\n  private suspend fun checkFeatureStatusAndStartRecognition() {\n    speechRecognizer?.checkStatus()?.let {\n      if (it == FeatureStatus.AVAILABLE) {\n        Log.i(TAG, \"Feature is available, starting recognition.\")\n        startSpeechRecognition()\n      } else {\n        showFeatureStatusToast(it)\n      }\n    }\n  }\n\n  private suspend fun downloadFeature() {\n    var downloadTotalSize: Long = 0\n    repeatOnLifecycle(Lifecycle.State.STARTED) {\n      speechRecognizer?.download()?.collect {\n        when (it) {\n          is DownloadStatus.DownloadStarted -> {\n            downloadTotalSize = it.bytesToDownload\n            Log.i(TAG, \"Download started, total size to download: $downloadTotalSize\")\n            runOnUiThread {\n              Toast.makeText(\n                  this@SpeechRecognitionActivity,\n                  \"Download started...\",\n                  Toast.LENGTH_SHORT,\n                )\n                .show()\n            }\n          }\n          is DownloadStatus.DownloadProgress -> {\n            runOnUiThread {\n              textView.text = formatDownloadProgress(it.totalBytesDownloaded, downloadTotalSize)\n            }\n          }\n          is DownloadStatus.DownloadFailed -> {\n            Log.e(TAG, \"Download failed\\n${it.e}\")\n            runOnUiThread {\n              textView.text = \"\"\n              Toast.makeText(\n                  this@SpeechRecognitionActivity,\n                  \"Download failed: ${it.e.message}\",\n                  Toast.LENGTH_LONG,\n                )\n                .show()\n            }\n          }\n          is DownloadStatus.DownloadCompleted -> {\n            Log.i(TAG, \"Download completed\")\n            runOnUiThread {\n              textView.text = \"\"\n              Toast.makeText(\n                  this@SpeechRecognitionActivity,\n                  \"Download completed!\",\n                  Toast.LENGTH_SHORT,\n                )\n                .show()\n            }\n          }\n        }\n      }\n    }\n  }\n\n  private suspend fun checkFeatureStatusAndDownloadIfNeeded() {\n    speechRecognizer?.checkStatus()?.let {\n      Log.i(TAG, \"Feature status: $it\")\n      if (it == FeatureStatus.DOWNLOADABLE) {\n        Log.i(TAG, \"Feature is downloadable, starting download.\")\n        downloadFeature()\n      } else {\n        showFeatureStatusToast(it)\n      }\n    }\n  }\n\n  private fun createAndSetSpeechRecognizer(): Boolean {\n    try {\n      val languageTag = languageSpinner.text.toString()\n      val selectedLocale = Locale.Builder().setLanguageTag(languageTag).build()\n      Log.i(TAG, \"selectedLocale: ${selectedLocale.toLanguageTag()}\")\n      if (\n        selectedLocale.equals(Locale.ROOT) ||\n          !selectedLocale.toLanguageTag().equals(languageTag, ignoreCase = true)\n      ) {\n        throw IllformedLocaleException(\"Invalid language tag format: ${languageSpinner.text}\")\n      }\n      speechRecognizer?.close()\n      speechRecognizer = createSpeechRecognizer(selectedLocale, getSelectedMode())\n      return true\n    } catch (e: IllformedLocaleException) {\n      Log.e(TAG, \"Invalid language tag format: ${languageSpinner.text}\", e)\n      Toast.makeText(\n          this,\n          \"Invalid language tag format: ${languageSpinner.text}\",\n          Toast.LENGTH_SHORT,\n        )\n        .show()\n      return false\n    }\n  }\n\n  private fun showFeatureStatusToast(status: Int) {\n    runOnUiThread {\n      val message =\n        when (status) {\n          FeatureStatus.DOWNLOADABLE -> \"Feature is not available, please download first.\"\n          FeatureStatus.DOWNLOADING -> \"Download is in progress, please wait...\"\n          FeatureStatus.UNAVAILABLE -> \"Feature is not available in this device.\"\n          FeatureStatus.AVAILABLE -> \"Feature is already available.\"\n          else -> return@runOnUiThread // Should not be called for other statuses\n        }\n      Toast.makeText(this@SpeechRecognitionActivity, message, Toast.LENGTH_SHORT).show()\n    }\n  }\n\n  private fun createSpeechRecognizer(locale: Locale, mode: Int): SpeechRecognizer {\n    return SpeechRecognition.getClient(\n      speechRecognizerOptions {\n        this.locale = locale\n        this.preferredMode = mode\n      }\n    )\n  }\n\n  private fun getSelectedMode(): Int {\n    return if (modeSpinner.selectedItem.toString() == \"Advanced\") {\n      SpeechRecognizerOptions.Mode.MODE_ADVANCED\n    } else {\n      SpeechRecognizerOptions.Mode.MODE_BASIC\n    }\n  }\n\n  private fun setControlUiEnabled(enabled: Boolean) {\n    languageSpinner.isEnabled = enabled\n    modeSpinner.isEnabled = enabled\n    audioSourceSpinner.isEnabled = enabled\n  }\n\n  private fun formatDownloadProgress(downloadedBytes: Long, totalBytes: Long): String {\n    val decimalFormat = DecimalFormat(\"#.#\")\n\n    val downloadedMB = downloadedBytes.toDouble() / (1024 * 1024)\n    val totalMB = totalBytes.toDouble() / (1024 * 1024)\n\n    val downloadedString = decimalFormat.format(downloadedMB)\n    val totalString = decimalFormat.format(totalMB)\n\n    return \"Downloading progress: ${downloadedString}MB / ${totalString}MB\"\n  }\n\n  companion object {\n    private const val TAG = \"SpeechToTextDemo\"\n    private const val PERMISSIONS_REQUEST_CODE = 1001\n    private const val AUDIO_SAMPLE_RATE = 16000\n    private const val SOURCE_MICPHONE = \"Microphone\"\n  }\n}\n"
  },
  {
    "path": "android/speech/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#3DDC84\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "android/speech/app/src/main/res/drawable/ic_launcher_foreground.xml",
    "content": "<!-- Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License. -->\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    android:width=\"108dp\">\n    <path android:pathData=\"M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"85.84757\"\n                android:endY=\"92.4963\"\n                android:startX=\"42.9492\"\n                android:startY=\"49.59793\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\" />\n</vector>\n"
  },
  {
    "path": "android/speech/app/src/main/res/layout/activity_speech_recognition.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n     Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:fitsSystemWindows=\"true\"\n    android:keepScreenOn=\"true\"\n    android:layout_height=\"match_parent\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"vertical\">\n    <LinearLayout\n        android:id=\"@+id/language_layout\"\n        android:gravity=\"center_vertical\"\n        android:layout_height=\"wrap_content\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"20dp\">\n        <TextView\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"wrap_content\"\n            android:paddingEnd=\"10dp\"\n            android:text=\"Locale\"\n            android:textSize=\"20sp\" />\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:layout_width=\"0dp\">\n            <AutoCompleteTextView\n                android:id=\"@+id/language_spinner\"\n                android:layout_height=\"wrap_content\"\n                android:layout_width=\"match_parent\"\n                android:paddingVertical=\"20dp\"\n                android:textSize=\"20sp\" />\n        </com.google.android.material.textfield.TextInputLayout>\n    </LinearLayout>\n    <LinearLayout\n        android:id=\"@+id/mode_layout\"\n        android:gravity=\"center_vertical\"\n        android:layout_below=\"@id/language_layout\"\n        android:layout_height=\"wrap_content\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"20dp\">\n        <TextView\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"wrap_content\"\n            android:paddingEnd=\"10dp\"\n            android:text=\"Mode\"\n            android:textSize=\"20sp\" />\n        <Spinner\n            android:id=\"@+id/mode_spinner\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:layout_width=\"0dp\"\n            android:paddingVertical=\"20dp\"\n            android:textSize=\"20sp\" />\n    </LinearLayout>\n    <LinearLayout\n        android:id=\"@+id/audiosource_layout\"\n        android:gravity=\"center_vertical\"\n        android:layout_below=\"@id/mode_layout\"\n        android:layout_height=\"wrap_content\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"20dp\">\n        <TextView\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"wrap_content\"\n            android:paddingEnd=\"10dp\"\n            android:text=\"AudioSource\"\n            android:textSize=\"20sp\" />\n        <Spinner\n            android:id=\"@+id/audiosource_spinner\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:layout_width=\"0dp\" />\n    </LinearLayout>\n    <ScrollView\n        android:layout_above=\"@id/download_button\"\n        android:layout_below=\"@id/audiosource_layout\"\n        android:layout_height=\"match_parent\"\n        android:layout_width=\"match_parent\">\n        <TextView\n            android:id=\"@+id/text_view\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"match_parent\"\n            android:padding=\"20dp\"\n            android:textSize=\"24sp\" />\n    </ScrollView>\n    <Button\n        android:id=\"@+id/download_button\"\n        android:layout_above=\"@+id/mic_button\"\n        android:layout_height=\"wrap_content\"\n        android:layout_width=\"match_parent\"\n        android:padding=\"20dp\"\n        android:text=\"Download\" />\n    <Button\n        android:id=\"@+id/mic_button\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_height=\"wrap_content\"\n        android:layout_width=\"match_parent\"\n        android:padding=\"20dp\"\n        android:text=\"Start Recording\" />\n</RelativeLayout>\n"
  },
  {
    "path": "android/speech/app/src/main/res/mipmap-anydpi/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License. -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n    <monochrome android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>\n"
  },
  {
    "path": "android/speech/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License. -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n    <monochrome android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>\n"
  },
  {
    "path": "android/speech/app/src/main/res/values/arrays.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License. -->\n<resources>\n    <string-array name=\"languages_array\">\n        <item>en-US</item>\n        <item>en-GB</item>\n        <item>en-IN</item>\n        <item>ar-SA</item>\n        <item>da-DK</item>\n        <item>de-DE</item>\n        <item>es-ES</item>\n        <item>es-US</item>\n        <item>fr-FR</item>\n        <item>hi-IN</item>\n        <item>id-ID</item>\n        <item>it-IT</item>\n        <item>ja-JP</item>\n        <item>ko-KR</item>\n        <item>nb-NO</item>\n        <item>nl-NL</item>\n        <item>pl-PL</item>\n        <item>pt-BR</item>\n        <item>ru-RU</item>\n        <item>sv-SE</item>\n        <item>tr-TR</item>\n        <item>zh-CN</item>\n        <item>zh-TW</item>\n    </string-array>\n    <string-array name=\"modes_array\">\n        <item>Advanced</item>\n        <item>Basic</item>\n    </string-array>\n    <string-array name=\"audiosource_array\">\n        <item>Microphone</item>\n        <item>FileDescriptor</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "android/speech/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License. -->\n<resources>\n    <color name=\"purple_200\">#FFBB86FC</color>\n    <color name=\"purple_500\">#FF6200EE</color>\n    <color name=\"purple_700\">#FF3700B3</color>\n    <color name=\"teal_200\">#FF03DAC5</color>\n    <color name=\"teal_700\">#FF018786</color>\n    <color name=\"black\">#FF000000</color>\n    <color name=\"white\">#FFFFFFFF</color>\n</resources>\n"
  },
  {
    "path": "android/speech/app/src/main/res/values/strings.xml",
    "content": "<!-- Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License. -->\n<resources>\n    <string name=\"app_name\">SpeechDemo</string>\n    <string\n        name=\"text_start_recording\"\n        description=\"Text for the button to start recording. [CHAR LIMIT=NONE]\">Start Recording</string>\n    <string\n        name=\"text_stop_recording\"\n        description=\"Text for the button to stop recording. [CHAR LIMIT=NONE]\">Stop Recording</string>\n    <string\n        name=\"text_status_running\"\n        description=\"Text to indicate app is running. [CHAR LIMIT=NONE]\">Running&#8230;</string>\n    <string\n        name=\"text_transcription_format\"\n        description=\"Text for transcription format. [CHAR LIMIT=NONE]\">%1$s %2$s</string>\n    <string\n        name=\"text_error_create_file\"\n        description=\"Text to indicate error creating file. [CHAR LIMIT=NONE]\">Error creating file</string>\n    <string\n        name=\"text_error_format\"\n        description=\"Text to indicate error creating file. [CHAR LIMIT=NONE]\">Error: %1$s Error code: %2$d</string>\n    <string name=\"speech_recognition_title\">Speech Recognition</string>\n</resources>\n"
  },
  {
    "path": "android/speech/app/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright 2025 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License. -->\n<resources>\n    <style\n        name=\"Theme.SpeechToTextDemo\"\n        parent=\"Theme.MaterialComponents.Light.NoActionBar\" />\n</resources>\n"
  },
  {
    "path": "android/speech/build.gradle",
    "content": "/*\n * Copyright 2025 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n  ext.kotlin_version = '2.1.0'\n\n  repositories {\n    google()\n    mavenCentral()\n  }\n  dependencies {\n    classpath 'com.android.tools.build:gradle:8.7.3'\n    classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n    // NOTE: Do not place your application dependencies here; they belong\n    // in the individual module build.gradle files\n  }\n}\n\nallprojects {\n  repositories {\n    google()\n    mavenCentral()\n    mavenLocal()\n  }\n}\n\ntasks.register('clean', Delete) {\n  delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/speech/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. For more details, visit\n# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\n# Enables namespacing of each library's R class so that its R class includes only the\n# resources declared in the library itself and none from the library's dependencies,\n# thereby reducing the size of the R class for that library\nandroid.nonTransitiveRClass=true\n"
  },
  {
    "path": "android/speech/settings.gradle",
    "content": "/*\n * Copyright 2025 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nrootProject.name = \"ML Kit Speech API demo\"\ninclude ':app'\n"
  },
  {
    "path": "android/translate/LICENSE",
    "content": "   Copyright 2020 Google LLC\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "android/translate/README.md",
    "content": "# ML Kit Translation Quickstart\n\n* [Read more about ML Kit Translation](https://developers.google.com/ml-kit/language/translation)\n\n## Introduction\n\nThe ML Kit Translate Android Quickstart app demonstrates how to use the Translate\nfeature of ML Kit to translate text in your application.\n\n## Getting Started\n\n* Run the sample code on your Android device or emulator\n* Try extending the code to add new features and functionality\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/language/translation/android)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)\n\n## License\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/translate/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 34\n    defaultConfig {\n        applicationId 'com.google.mlkit.samples.nl.translate'\n        minSdkVersion 21\n        targetSdkVersion 34\n        multiDexEnabled true\n        versionCode 1\n        versionName \"1.0\"\n        setProperty(\"archivesBaseName\", \"nl-translate\")\n        vectorDrawables.useSupportLibrary = true\n    }\n\n    buildTypes {\n        proguard {\n            debuggable false\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n        }\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    lintOptions {\n        disable \"Instantiatable\"\n    }\n}\n\ndependencies {\n    implementation project(':internal:chooserx')\n    implementation 'com.google.mlkit:translate:17.0.3'\n\n    // Those dependencies are not required by the SDK. They are used for the sample itself.\n    implementation 'androidx.core:core-ktx:1.3.0'\n    implementation 'androidx.multidex:multidex:2.0.1'\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'androidx.media:media:1.1.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.0.0'\n    implementation 'androidx.recyclerview:recyclerview:1.1.0'\n    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'\n    implementation 'org.apache.commons:commons-collections4:4.4'\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation 'com.google.android.material:material:1.2.0'\n    implementation 'com.google.guava:guava:27.1-android'\n}\n"
  },
  {
    "path": "android/translate/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "android/translate/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.samples.nl.translate\"\n    android:versionCode=\"1\"\n    android:versionName=\"v1\">\n\n  <application\n      android:allowBackup=\"true\"\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:theme=\"@style/AppTheme\">\n\n    <activity\n        android:name=\".EntryChoiceActivity\"\n        android:exported=\"true\"\n        android:label=\"@string/app_name\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n\n    <activity\n        android:name=\".java.MainActivity\"\n        android:exported=\"true\"\n        android:label=\"@string/app_name\">\n    </activity>\n\n    <activity\n        android:name=\".kotlin.MainActivity\"\n        android:exported=\"true\"\n        android:label=\"@string/app_name\">\n    </activity>\n\n  </application>\n\n</manifest>\n"
  },
  {
    "path": "android/translate/app/src/main/java/com/google/mlkit/samples/nl/translate/EntryChoiceActivity.kt",
    "content": "package com.google.mlkit.samples.nl.translate\n\nimport android.content.Intent\nimport androidx.appcompat.app.AppCompatDelegate\nimport com.google.mlkit.samples.nl.translate.java.MainActivity\nimport com.mlkit.example.internal.BaseEntryChoiceActivity\nimport com.mlkit.example.internal.Choice\n\nclass EntryChoiceActivity : BaseEntryChoiceActivity() {\n\n  override fun getChoices(): List<Choice> {\n    return listOf(\n      Choice(\n        \"Java\",\n        \"Run the ML Kit Translate quickstart written in Java.\",\n        Intent(this, MainActivity::class.java)\n      ),\n      Choice(\n        \"Kotlin\",\n        \"Run the ML Kit Translate quickstart written in Kotlin.\",\n        Intent(this, com.google.mlkit.samples.nl.translate.kotlin.MainActivity::class.java)\n      )\n    )\n  }\n\n  companion object {\n    init {\n      AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)\n    }\n  }\n}\n"
  },
  {
    "path": "android/translate/app/src/main/java/com/google/mlkit/samples/nl/translate/java/MainActivity.java",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.translate.java;\n\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport com.google.mlkit.samples.nl.translate.R;\n\npublic class MainActivity extends AppCompatActivity {\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_translate_main);\n\n    if (savedInstanceState == null) {\n      getSupportFragmentManager()\n          .beginTransaction()\n          .replace(R.id.container, TranslateFragment.newInstance())\n          .commitNow();\n    }\n  }\n}\n"
  },
  {
    "path": "android/translate/app/src/main/java/com/google/mlkit/samples/nl/translate/java/TranslateFragment.java",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.translate.java;\n\nimport android.annotation.SuppressLint;\nimport android.os.Bundle;\nimport androidx.fragment.app.Fragment;\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.CompoundButton;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.ToggleButton;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.Observer;\nimport androidx.lifecycle.ViewModelProviders;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.mlkit.samples.nl.translate.R;\nimport java.util.List;\n\n/***\n * Fragment view for handling translations\n */\npublic class TranslateFragment extends Fragment {\n\n  public static TranslateFragment newInstance() {\n    return new TranslateFragment();\n  }\n\n  @Override\n  public void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setHasOptionsMenu(false);\n  }\n\n  @Nullable\n  @Override\n  public View onCreateView(\n      @NonNull LayoutInflater inflater,\n      @Nullable ViewGroup container,\n      @Nullable Bundle savedInstanceState) {\n    return inflater.inflate(R.layout.translate_fragment, container, false);\n  }\n\n  @SuppressLint(\"ClickableViewAccessibility\")\n  @Override\n  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n    super.onViewCreated(view, savedInstanceState);\n    final Button switchButton = view.findViewById(R.id.buttonSwitchLang);\n    final ToggleButton sourceSyncButton = view.findViewById(R.id.buttonSyncSource);\n    final ToggleButton targetSyncButton = view.findViewById(R.id.buttonSyncTarget);\n    final TextInputEditText srcTextView = view.findViewById(R.id.sourceText);\n    final TextView targetTextView = view.findViewById(R.id.targetText);\n    final TextView downloadedModelsTextView = view.findViewById(R.id.downloadedModels);\n    final Spinner sourceLangSelector = view.findViewById(R.id.sourceLangSelector);\n    final Spinner targetLangSelector = view.findViewById(R.id.targetLangSelector);\n\n    final TranslateViewModel viewModel = ViewModelProviders.of(this).get(TranslateViewModel.class);\n\n    // Get available language list and set up source and target language spinners\n    // with default selections.\n    final ArrayAdapter<TranslateViewModel.Language> adapter =\n        new ArrayAdapter<>(\n            getContext(),\n            android.R.layout.simple_spinner_dropdown_item,\n            viewModel.getAvailableLanguages());\n    sourceLangSelector.setAdapter(adapter);\n    targetLangSelector.setAdapter(adapter);\n    sourceLangSelector.setSelection(adapter.getPosition(new TranslateViewModel.Language(\"en\")));\n    targetLangSelector.setSelection(adapter.getPosition(new TranslateViewModel.Language(\"es\")));\n    sourceLangSelector.setOnItemSelectedListener(\n        new AdapterView.OnItemSelectedListener() {\n          @Override\n          public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n            setProgressText(targetTextView);\n            viewModel.sourceLang.setValue(adapter.getItem(position));\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> parent) {\n            targetTextView.setText(\"\");\n          }\n        });\n    targetLangSelector.setOnItemSelectedListener(\n        new AdapterView.OnItemSelectedListener() {\n          @Override\n          public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n            setProgressText(targetTextView);\n            viewModel.targetLang.setValue(adapter.getItem(position));\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> parent) {\n            targetTextView.setText(\"\");\n          }\n        });\n\n    switchButton.setOnClickListener(\n        new View.OnClickListener() {\n          @Override\n          public void onClick(View v) {\n            String targetText = targetTextView.getText().toString();\n            setProgressText(targetTextView);\n            int sourceLangPosition = sourceLangSelector.getSelectedItemPosition();\n            sourceLangSelector.setSelection(targetLangSelector.getSelectedItemPosition());\n            targetLangSelector.setSelection(sourceLangPosition);\n\n            // Also update srcTextView with targetText\n            srcTextView.setText(targetText);\n            viewModel.sourceText.setValue(targetText);\n          }\n        });\n\n    // Set up toggle buttons to delete or download remote models locally.\n    sourceSyncButton.setOnCheckedChangeListener(\n        new CompoundButton.OnCheckedChangeListener() {\n          @Override\n          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n            TranslateViewModel.Language language =\n                adapter.getItem(sourceLangSelector.getSelectedItemPosition());\n            if (isChecked) {\n              viewModel.downloadLanguage(language);\n            } else {\n              viewModel.deleteLanguage(language);\n            }\n          }\n        });\n    targetSyncButton.setOnCheckedChangeListener(\n        new CompoundButton.OnCheckedChangeListener() {\n          @Override\n          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n            TranslateViewModel.Language language =\n                adapter.getItem(targetLangSelector.getSelectedItemPosition());\n            if (isChecked) {\n              viewModel.downloadLanguage(language);\n            } else {\n              viewModel.deleteLanguage(language);\n            }\n          }\n        });\n\n    // Translate input text as it is typed\n    srcTextView.addTextChangedListener(\n        new TextWatcher() {\n          @Override\n          public void beforeTextChanged(CharSequence s, int start, int count, int after) {}\n\n          @Override\n          public void onTextChanged(CharSequence s, int start, int before, int count) {}\n\n          @Override\n          public void afterTextChanged(Editable s) {\n            setProgressText(targetTextView);\n            viewModel.sourceText.postValue(s.toString());\n          }\n        });\n    viewModel.translatedText.observe(\n        getViewLifecycleOwner(),\n        new Observer<TranslateViewModel.ResultOrError>() {\n          @Override\n          public void onChanged(TranslateViewModel.ResultOrError resultOrError) {\n            if (resultOrError.error != null) {\n              srcTextView.setError(resultOrError.error.getLocalizedMessage());\n            } else {\n              targetTextView.setText(resultOrError.result);\n            }\n          }\n        });\n\n    // Update sync toggle button states based on downloaded models list.\n    viewModel.availableModels.observe(\n        getViewLifecycleOwner(),\n        new Observer<List<String>>() {\n          @Override\n          public void onChanged(@Nullable List<String> translateRemoteModels) {\n            String output =\n                getContext().getString(R.string.downloaded_models_label, translateRemoteModels);\n            downloadedModelsTextView.setText(output);\n\n            sourceSyncButton.setChecked(\n                !viewModel.requiresModelDownload(\n                    adapter.getItem(sourceLangSelector.getSelectedItemPosition()),\n                    translateRemoteModels));\n            targetSyncButton.setChecked(\n                !viewModel.requiresModelDownload(\n                    adapter.getItem(targetLangSelector.getSelectedItemPosition()),\n                    translateRemoteModels));\n          }\n        });\n  }\n\n  private void setProgressText(TextView tv) {\n    tv.setText(getContext().getString(R.string.translate_progress));\n  }\n}\n"
  },
  {
    "path": "android/translate/app/src/main/java/com/google/mlkit/samples/nl/translate/java/TranslateViewModel.java",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.translate.java;\n\nimport android.app.Application;\nimport android.util.LruCache;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.MediatorLiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.Observer;\nimport com.google.android.gms.tasks.Continuation;\nimport com.google.android.gms.tasks.OnCompleteListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.Tasks;\nimport com.google.mlkit.common.model.DownloadConditions;\nimport com.google.mlkit.common.model.RemoteModelManager;\nimport com.google.mlkit.nl.translate.TranslateLanguage;\nimport com.google.mlkit.nl.translate.TranslateRemoteModel;\nimport com.google.mlkit.nl.translate.Translation;\nimport com.google.mlkit.nl.translate.Translator;\nimport com.google.mlkit.nl.translate.TranslatorOptions;\nimport com.google.mlkit.samples.nl.translate.R;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\n\n/**\n * Model class for tracking available models and performing live translations\n */\npublic class TranslateViewModel extends AndroidViewModel {\n  // This specifies the number of translators instance we want to keep in our LRU cache.\n  // Each instance of the translator is built with different options based on the source\n  // language and the target language, and since we want to be able to manage the number of\n  // translator instances to keep around, an LRU cache is an easy way to achieve this.\n  private static final int NUM_TRANSLATORS = 3;\n\n  private final RemoteModelManager modelManager;\n  private final LruCache<TranslatorOptions, Translator> translators =\n      new LruCache<TranslatorOptions, Translator>(NUM_TRANSLATORS) {\n        @Override\n        public Translator create(TranslatorOptions options) {\n          return Translation.getClient(options);\n        }\n\n        @Override\n        public void entryRemoved(\n            boolean evicted, TranslatorOptions key, Translator oldValue, Translator newValue) {\n          oldValue.close();\n        }\n      };\n  MutableLiveData<Language> sourceLang = new MutableLiveData<>();\n  MutableLiveData<Language> targetLang = new MutableLiveData<>();\n  MutableLiveData<String> sourceText = new MutableLiveData<>();\n  MediatorLiveData<ResultOrError> translatedText = new MediatorLiveData<>();\n  MutableLiveData<List<String>> availableModels = new MutableLiveData<>();\n\n  HashMap<String, Task<Void>> pendingDownloads = new HashMap<>();\n\n  public TranslateViewModel(@NonNull Application application) {\n    super(application);\n    modelManager = RemoteModelManager.getInstance();\n\n    // Create a translation result or error object.\n    final OnCompleteListener<String> processTranslation =\n        new OnCompleteListener<String>() {\n          @Override\n          public void onComplete(@NonNull Task<String> task) {\n            if (task.isSuccessful()) {\n              translatedText.setValue(new ResultOrError(task.getResult(), null));\n            } else {\n              translatedText.setValue(new ResultOrError(null, task.getException()));\n              task.getException().printStackTrace();\n            }\n            // Update the list of downloaded models as more may have been\n            // automatically downloaded due to requested translation.\n            fetchDownloadedModels();\n          }\n        };\n\n    // Start translation if any of the following change: input text, source lang, target lang.\n    translatedText.addSource(\n        sourceText,\n        new Observer<String>() {\n          @Override\n          public void onChanged(@Nullable String s) {\n            translate().addOnCompleteListener(processTranslation);\n          }\n        });\n    Observer<Language> languageObserver =\n        new Observer<Language>() {\n          @Override\n          public void onChanged(@Nullable Language language) {\n            translate().addOnCompleteListener(processTranslation);\n          }\n        };\n    translatedText.addSource(sourceLang, languageObserver);\n    translatedText.addSource(targetLang, languageObserver);\n\n    // Update the list of downloaded models.\n    fetchDownloadedModels();\n  }\n\n  // Gets a list of all available translation languages.\n  List<Language> getAvailableLanguages() {\n    List<Language> languages = new ArrayList<>();\n    List<String> languageIds = TranslateLanguage.getAllLanguages();\n    for (String languageId : languageIds) {\n      languages.add(new Language(TranslateLanguage.fromLanguageTag(languageId)));\n    }\n    return languages;\n  }\n\n  private TranslateRemoteModel getModel(String languageCode) {\n    return new TranslateRemoteModel.Builder(languageCode).build();\n  }\n\n  // Updates the list of downloaded models available for local translation.\n  private void fetchDownloadedModels() {\n    modelManager\n        .getDownloadedModels(TranslateRemoteModel.class)\n        .addOnSuccessListener(\n            new OnSuccessListener<Set<TranslateRemoteModel>>() {\n              @Override\n              public void onSuccess(Set<TranslateRemoteModel> remoteModels) {\n                List<String> modelCodes = new ArrayList<>(remoteModels.size());\n                for (TranslateRemoteModel model : remoteModels) {\n                  modelCodes.add(model.getLanguage());\n                }\n                Collections.sort(modelCodes);\n                availableModels.setValue(modelCodes);\n              }\n            });\n  }\n\n  // Starts downloading a remote model for local translation.\n  void downloadLanguage(Language language) {\n    TranslateRemoteModel model = getModel(TranslateLanguage.fromLanguageTag(language.getCode()));\n    Task<Void> downloadTask;\n    if (pendingDownloads.containsKey(language.code)) {\n      downloadTask = pendingDownloads.get(language.code);\n      // found existing task. exiting\n      if (downloadTask != null && !downloadTask.isCanceled()) {\n        return;\n      }\n    }\n    downloadTask =\n        modelManager\n            .download(model, new DownloadConditions.Builder().build())\n            .addOnCompleteListener(\n                new OnCompleteListener<Void>() {\n                  @Override\n                  public void onComplete(@NonNull Task<Void> task) {\n                    pendingDownloads.remove(language.getCode());\n                    fetchDownloadedModels();\n                  }\n                });\n    pendingDownloads.put(language.code, downloadTask);\n  }\n\n  // Returns if a new model download task should be started.\n  boolean requiresModelDownload(Language lang, @Nullable List<String> downloadedModels) {\n    if (downloadedModels == null) {\n      return true;\n    }\n    return !downloadedModels.contains(lang.code) && !pendingDownloads.containsKey(lang.code);\n  }\n\n  // Deletes a locally stored translation model.\n  void deleteLanguage(Language language) {\n    TranslateRemoteModel model = getModel(TranslateLanguage.fromLanguageTag(language.getCode()));\n    modelManager\n        .deleteDownloadedModel(model)\n        .addOnCompleteListener(\n            new OnCompleteListener<Void>() {\n              @Override\n              public void onComplete(@NonNull Task<Void> task) {\n                fetchDownloadedModels();\n              }\n            });\n    pendingDownloads.remove(language.code);\n  }\n\n  public Task<String> translate() {\n    final String text = sourceText.getValue();\n    final Language source = sourceLang.getValue();\n    final Language target = targetLang.getValue();\n    if (source == null || target == null || text == null || text.isEmpty()) {\n      return Tasks.forResult(\"\");\n    }\n    String sourceLangCode = TranslateLanguage.fromLanguageTag(source.getCode());\n    String targetLangCode = TranslateLanguage.fromLanguageTag(target.getCode());\n    TranslatorOptions options =\n        new TranslatorOptions.Builder()\n            .setSourceLanguage(sourceLangCode)\n            .setTargetLanguage(targetLangCode)\n            .build();\n    return translators\n        .get(options)\n        .downloadModelIfNeeded()\n        .continueWithTask(\n            new Continuation<Void, Task<String>>() {\n              @Override\n              public Task<String> then(@NonNull Task<Void> task) {\n                if (task.isSuccessful()) {\n                  return translators.get(options).translate(text);\n                } else {\n                  Exception e = task.getException();\n                  if (e == null) {\n                    e = new Exception(getApplication().getString(R.string.unknown_error));\n                  }\n                  return Tasks.forException(e);\n                }\n              }\n            });\n  }\n\n  /** Holds the result of the translation or any error. */\n  static class ResultOrError {\n    final String result;\n    final Exception error;\n\n    ResultOrError(@Nullable String result, @Nullable Exception error) {\n      this.result = result;\n      this.error = error;\n    }\n  }\n\n  /**\n   * Holds the language code (i.e. \"en\") and the corresponding localized full language name (i.e.\n   * \"English\")\n   */\n  static class Language implements Comparable<Language> {\n    private final String code;\n\n    Language(String code) {\n      this.code = code;\n    }\n\n    String getDisplayName() {\n      return new Locale(code).getDisplayName();\n    }\n\n    String getCode() {\n      return code;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n      if (o == this) {\n        return true;\n      }\n\n      if (!(o instanceof Language)) {\n        return false;\n      }\n\n      Language otherLang = (Language) o;\n      return otherLang.code.equals(code);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n      return code + \" - \" + getDisplayName();\n    }\n\n    @Override\n    public int hashCode() {\n      return code.hashCode();\n    }\n\n    @Override\n    public int compareTo(@NonNull Language o) {\n      return this.getDisplayName().compareTo(o.getDisplayName());\n    }\n  }\n\n  @Override\n  protected void onCleared() {\n    super.onCleared();\n    // Each new instance of a translator needs to be closed appropriately. Here we utilize the\n    // ViewModel's onCleared() to clear our LruCache and close each Translator instance when\n    // this ViewModel is no longer used and destroyed.\n    translators.evictAll();\n  }\n}\n"
  },
  {
    "path": "android/translate/app/src/main/java/com/google/mlkit/samples/nl/translate/kotlin/MainActivity.kt",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.translate.kotlin\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport com.google.mlkit.samples.nl.translate.R\n\nclass MainActivity : AppCompatActivity() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_translate_main)\n\n    if (savedInstanceState == null) {\n      supportFragmentManager.beginTransaction()\n        .replace(\n          R.id.container,\n          TranslateFragment.newInstance()\n        )\n        .commitNow()\n    }\n  }\n}\n"
  },
  {
    "path": "android/translate/app/src/main/java/com/google/mlkit/samples/nl/translate/kotlin/TranslateFragment.kt",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage com.google.mlkit.samples.nl.translate.kotlin\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport androidx.fragment.app.Fragment\nimport android.text.Editable\nimport android.text.TextWatcher\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.AdapterView\nimport android.widget.AdapterView.OnItemSelectedListener\nimport android.widget.ArrayAdapter\nimport android.widget.Button\nimport android.widget.Spinner\nimport android.widget.TextView\nimport android.widget.ToggleButton\nimport androidx.lifecycle.ViewModelProviders\nimport com.google.android.material.textfield.TextInputEditText\nimport com.google.mlkit.samples.nl.translate.R\n\n/***\n * Fragment view for handling translations\n */\nclass TranslateFragment : Fragment() {\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setHasOptionsMenu(false)\n  }\n\n  override fun onCreateView(\n    inflater: LayoutInflater,\n    container: ViewGroup?,\n    savedInstanceState: Bundle?,\n  ): View? {\n    return inflater.inflate(R.layout.translate_fragment, container, false)\n  }\n\n  @SuppressLint(\"ClickableViewAccessibility\")\n  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n    super.onViewCreated(view, savedInstanceState)\n    val switchButton = view.findViewById<Button>(R.id.buttonSwitchLang)\n    val sourceSyncButton = view.findViewById<ToggleButton>(R.id.buttonSyncSource)\n    val targetSyncButton = view.findViewById<ToggleButton>(R.id.buttonSyncTarget)\n    val srcTextView: TextInputEditText = view.findViewById(R.id.sourceText)\n    val targetTextView = view.findViewById<TextView>(R.id.targetText)\n    val downloadedModelsTextView = view.findViewById<TextView>(R.id.downloadedModels)\n    val sourceLangSelector = view.findViewById<Spinner>(R.id.sourceLangSelector)\n    val targetLangSelector = view.findViewById<Spinner>(R.id.targetLangSelector)\n    val viewModel = ViewModelProviders.of(this).get(\n      TranslateViewModel::class.java\n    )\n\n    // Get available language list and set up source and target language spinners\n    // with default selections.\n    val adapter = ArrayAdapter(\n      context!!,\n      android.R.layout.simple_spinner_dropdown_item, viewModel.availableLanguages\n    )\n    sourceLangSelector.adapter = adapter\n    targetLangSelector.adapter = adapter\n    sourceLangSelector.setSelection(adapter.getPosition(TranslateViewModel.Language(\"en\")))\n    targetLangSelector.setSelection(adapter.getPosition(TranslateViewModel.Language(\"es\")))\n    sourceLangSelector.onItemSelectedListener = object : OnItemSelectedListener {\n      override fun onItemSelected(\n        parent: AdapterView<*>?,\n        view: View?,\n        position: Int,\n        id: Long,\n      ) {\n        setProgressText(targetTextView)\n        viewModel.sourceLang.setValue(adapter.getItem(position))\n      }\n\n      override fun onNothingSelected(parent: AdapterView<*>?) {\n        targetTextView.text = \"\"\n      }\n    }\n    targetLangSelector.onItemSelectedListener = object : OnItemSelectedListener {\n      override fun onItemSelected(\n        parent: AdapterView<*>?,\n        view: View?,\n        position: Int,\n        id: Long,\n      ) {\n        setProgressText(targetTextView)\n        viewModel.targetLang.setValue(adapter.getItem(position))\n      }\n\n      override fun onNothingSelected(parent: AdapterView<*>?) {\n        targetTextView.text = \"\"\n      }\n    }\n    switchButton.setOnClickListener {\n      val targetText = targetTextView.text.toString()\n      setProgressText(targetTextView)\n      val sourceLangPosition = sourceLangSelector.selectedItemPosition\n      sourceLangSelector.setSelection(targetLangSelector.selectedItemPosition)\n      targetLangSelector.setSelection(sourceLangPosition)\n\n      // Also update srcTextView with targetText\n      srcTextView.setText(targetText)\n      viewModel.sourceText.setValue(targetText)\n    }\n\n    // Set up toggle buttons to delete or download remote models locally.\n    sourceSyncButton.setOnCheckedChangeListener { buttonView, isChecked ->\n      val language = adapter.getItem(sourceLangSelector.selectedItemPosition)\n      if (isChecked) {\n        viewModel.downloadLanguage(language!!)\n      } else {\n        viewModel.deleteLanguage(language!!)\n      }\n    }\n    targetSyncButton.setOnCheckedChangeListener { buttonView, isChecked ->\n      val language = adapter.getItem(targetLangSelector.selectedItemPosition)\n      if (isChecked) {\n        viewModel.downloadLanguage(language!!)\n      } else {\n        viewModel.deleteLanguage(language!!)\n      }\n    }\n\n    // Translate input text as it is typed\n    srcTextView.addTextChangedListener(object : TextWatcher {\n      override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}\n      override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}\n      override fun afterTextChanged(s: Editable) {\n        setProgressText(targetTextView)\n        viewModel.sourceText.postValue(s.toString())\n      }\n    })\n    viewModel.translatedText.observe(\n      viewLifecycleOwner,\n      { resultOrError ->\n        if (resultOrError.error != null) {\n          srcTextView.setError(resultOrError.error!!.localizedMessage)\n        } else {\n          targetTextView.text = resultOrError.result\n        }\n      }\n    )\n\n    // Update sync toggle button states based on downloaded models list.\n    viewModel.availableModels.observe(\n      viewLifecycleOwner,\n      { translateRemoteModels ->\n        val output = context!!.getString(\n          R.string.downloaded_models_label,\n          translateRemoteModels\n        )\n        downloadedModelsTextView.text = output\n\n        sourceSyncButton.isChecked = !viewModel.requiresModelDownload(\n          adapter.getItem(sourceLangSelector.selectedItemPosition)!!,\n          translateRemoteModels)\n        targetSyncButton.isChecked = !viewModel.requiresModelDownload(\n          adapter.getItem(targetLangSelector.selectedItemPosition)!!,\n          translateRemoteModels)\n      }\n    )\n  }\n\n  private fun setProgressText(tv: TextView) {\n    tv.text = context!!.getString(R.string.translate_progress)\n  }\n\n  companion object {\n    fun newInstance(): TranslateFragment {\n      return TranslateFragment()\n    }\n  }\n}\n"
  },
  {
    "path": "android/translate/app/src/main/java/com/google/mlkit/samples/nl/translate/kotlin/TranslateViewModel.kt",
    "content": "/*\n * Copyright 2019 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.google.mlkit.samples.nl.translate.kotlin\n\nimport android.app.Application\nimport android.util.LruCache\nimport androidx.lifecycle.AndroidViewModel\nimport androidx.lifecycle.MediatorLiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.Observer\nimport com.google.android.gms.tasks.OnCompleteListener\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.Tasks\nimport com.google.mlkit.common.model.DownloadConditions\nimport com.google.mlkit.common.model.RemoteModelManager\nimport com.google.mlkit.nl.translate.TranslateLanguage\nimport com.google.mlkit.nl.translate.TranslateRemoteModel\nimport com.google.mlkit.nl.translate.Translation\nimport com.google.mlkit.nl.translate.Translator\nimport com.google.mlkit.nl.translate.TranslatorOptions\nimport com.google.mlkit.samples.nl.translate.R\nimport java.util.Locale\n\n/**\n * Model class for tracking available models and performing live translations\n */\nclass TranslateViewModel(application: Application) : AndroidViewModel(application) {\n\n  companion object {\n    // This specifies the number of translators instance we want to keep in our LRU cache.\n    // Each instance of the translator is built with different options based on the source\n    // language and the target language, and since we want to be able to manage the number of\n    // translator instances to keep around, an LRU cache is an easy way to achieve this.\n    private const val NUM_TRANSLATORS = 3\n  }\n\n  private val modelManager: RemoteModelManager = RemoteModelManager.getInstance()\n  private val pendingDownloads: HashMap<String, Task<Void>> = hashMapOf()\n  private val translators =\n    object : LruCache<TranslatorOptions, Translator>(NUM_TRANSLATORS) {\n      override fun create(options: TranslatorOptions): Translator {\n        return Translation.getClient(options)\n      }\n      override fun entryRemoved(\n        evicted: Boolean,\n        key: TranslatorOptions,\n        oldValue: Translator,\n        newValue: Translator?,\n      ) {\n        oldValue.close()\n      }\n    }\n  val sourceLang = MutableLiveData<Language>()\n  val targetLang = MutableLiveData<Language>()\n  val sourceText = MutableLiveData<String>()\n  val translatedText = MediatorLiveData<ResultOrError>()\n  val availableModels = MutableLiveData<List<String>>()\n\n  // Gets a list of all available translation languages.\n  val availableLanguages: List<Language> = TranslateLanguage.getAllLanguages().map { Language(it) }\n\n  init {\n    // Create a translation result or error object.\n    val processTranslation =\n      OnCompleteListener<String> { task ->\n        if (task.isSuccessful) {\n          translatedText.value = ResultOrError(task.result, null)\n        } else {\n          translatedText.value = ResultOrError(null, task.exception)\n        }\n        // Update the list of downloaded models as more may have been\n        // automatically downloaded due to requested translation.\n        fetchDownloadedModels()\n      }\n    // Start translation if any of the following change: input text, source lang, target lang.\n    translatedText.addSource(sourceText) { translate().addOnCompleteListener(processTranslation) }\n    val languageObserver =\n      Observer<Language> { translate().addOnCompleteListener(processTranslation) }\n    translatedText.addSource(sourceLang, languageObserver)\n    translatedText.addSource(targetLang, languageObserver)\n\n    // Update the list of downloaded models.\n    fetchDownloadedModels()\n  }\n\n  private fun getModel(languageCode: String): TranslateRemoteModel {\n    return TranslateRemoteModel.Builder(languageCode).build()\n  }\n\n  // Updates the list of downloaded models available for local translation.\n  private fun fetchDownloadedModels() {\n    modelManager.getDownloadedModels(TranslateRemoteModel::class.java).addOnSuccessListener {\n      remoteModels ->\n      availableModels.value = remoteModels.sortedBy { it.language }.map { it.language }\n    }\n  }\n\n  // Starts downloading a remote model for local translation.\n  internal fun downloadLanguage(language: Language) {\n    val model = getModel(TranslateLanguage.fromLanguageTag(language.code)!!)\n    var downloadTask: Task<Void>?\n    if (pendingDownloads.containsKey(language.code)) {\n      downloadTask = pendingDownloads[language.code]\n      // found existing task. exiting\n      if (downloadTask != null && !downloadTask.isCanceled) {\n        return\n      }\n    }\n    downloadTask =\n      modelManager.download(model, DownloadConditions.Builder().build()).addOnCompleteListener {\n        pendingDownloads.remove(language.code)\n        fetchDownloadedModels()\n      }\n    pendingDownloads[language.code] = downloadTask\n  }\n\n  // Returns if a new model download task should be started.\n  fun requiresModelDownload(\n    lang: Language,\n    downloadedModels: List<String?>?,\n  ): Boolean {\n    return if (downloadedModels == null) {\n      true\n    } else !downloadedModels.contains(lang.code) && !pendingDownloads.containsKey(lang.code)\n  }\n\n  // Deletes a locally stored translation model.\n  internal fun deleteLanguage(language: Language) {\n    val model = getModel(TranslateLanguage.fromLanguageTag(language.code)!!)\n    modelManager.deleteDownloadedModel(model).addOnCompleteListener { fetchDownloadedModels() }\n    pendingDownloads.remove(language.code)\n  }\n\n  fun translate(): Task<String> {\n    val text = sourceText.value\n    val source = sourceLang.value\n    val target = targetLang.value\n    if (source == null || target == null || text == null || text.isEmpty()) {\n      return Tasks.forResult(\"\")\n    }\n    val sourceLangCode = TranslateLanguage.fromLanguageTag(source.code)!!\n    val targetLangCode = TranslateLanguage.fromLanguageTag(target.code)!!\n    val options =\n      TranslatorOptions.Builder()\n        .setSourceLanguage(sourceLangCode)\n        .setTargetLanguage(targetLangCode)\n        .build()\n    return translators[options].downloadModelIfNeeded().continueWithTask { task ->\n      if (task.isSuccessful) {\n        translators[options].translate(text)\n      } else {\n        Tasks.forException<String>(\n          task.exception\n            ?: Exception(getApplication<Application>().getString(R.string.unknown_error))\n        )\n      }\n    }\n  }\n\n  /** Holds the result of the translation or any error. */\n  inner class ResultOrError(var result: String?, var error: Exception?)\n\n  /**\n   * Holds the language code (i.e. \"en\") and the corresponding localized full language name (i.e.\n   * \"English\")\n   */\n  class Language(val code: String) : Comparable<Language> {\n\n    private val displayName: String\n      get() = Locale(code).displayName\n\n    override fun equals(other: Any?): Boolean {\n      if (other === this) {\n        return true\n      }\n\n      if (other !is Language) {\n        return false\n      }\n\n      val otherLang = other as Language?\n      return otherLang!!.code == code\n    }\n\n    override fun toString(): String {\n      return \"$code - $displayName\"\n    }\n\n    override fun compareTo(other: Language): Int {\n      return this.displayName.compareTo(other.displayName)\n    }\n\n    override fun hashCode(): Int {\n      return code.hashCode()\n    }\n  }\n\n  override fun onCleared() {\n    super.onCleared()\n    // Each new instance of a translator needs to be closed appropriately. Here we utilize the\n    // ViewModel's onCleared() to clear our LruCache and close each Translator instance when\n    // this ViewModel is no longer used and destroyed.\n    translators.evictAll()\n  }\n}\n"
  },
  {
    "path": "android/translate/app/src/main/res/drawable/ic_baseline_delete_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#ffffffff\"\n      android:pathData=\"M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z\" />\n</vector>\n"
  },
  {
    "path": "android/translate/app/src/main/res/drawable/ic_baseline_translate_32.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"32dp\"\n    android:height=\"32dp\"\n    android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#ffffffff\"\n      android:pathData=\"M12.87,15.07l-2.54,-2.51 0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53L17,6L17,4h-7L10,2L8,2v2L1,4v1.99h11.17C11.5,7.92 10.44,9.75 9,11.35 8.07,10.32 7.3,9.19 6.69,8h-2c0.73,1.63 1.73,3.17 2.98,4.56l-5.09,5.02L4,19l5,-5 3.11,3.11 0.76,-2.04zM18.5,10h-2L12,22h2l1.12,-3h4.75L21,22h2l-4.5,-12zM15.88,17l1.62,-4.33L19.12,17h-3.24z\" />\n</vector>\n"
  },
  {
    "path": "android/translate/app/src/main/res/drawable/ic_compare_arrows_black_24dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#000000\"\n      android:pathData=\"M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3zM14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4z\" />\n</vector>\n"
  },
  {
    "path": "android/translate/app/src/main/res/drawable/ic_file_download_white_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z\"/>\n</vector>\n"
  },
  {
    "path": "android/translate/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportWidth=\"172.43\"\n    android:viewportHeight=\"129.06\"\n    tools:ignore=\"NewApi\">\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#66ff99\"\n      android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n  <path\n      android:fillColor=\"#66ff99\"\n      android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n  <path\n      android:fillColor=\"#009933\"\n      android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n  <path\n      android:fillColor=\"#666633\"\n      android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/translate/app/src/main/res/layout/activity_translate_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.google.mlkit.samples.nl.translate.java.MainActivity\" />\n\n"
  },
  {
    "path": "android/translate/app/src/main/res/layout/translate_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/main\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/textInputLayout\"\n        style=\"@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:inputType=\"textMultiLine\"\n        app:layout_constraintBottom_toTopOf=\"@+id/sourceLangSelector\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/sourceText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"top\"\n            android:hint=\"@string/source_text_hint\" />\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <Spinner\n        android:id=\"@+id/sourceLangSelector\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:textAlignment=\"center\"\n        app:layout_constraintBottom_toTopOf=\"@id/buttonSyncSource\"\n        app:layout_constraintEnd_toStartOf=\"@id/buttonSwitchLang\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textInputLayout\" />\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/buttonSwitchLang\"\n        style=\"@style/IconOnlyButton\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        android:text=\"\"\n        app:icon=\"@drawable/ic_compare_arrows_black_24dp\"\n        app:layout_constraintEnd_toStartOf=\"@+id/targetLangSelector\"\n        app:layout_constraintStart_toEndOf=\"@+id/sourceLangSelector\"\n        app:layout_constraintTop_toTopOf=\"@id/sourceLangSelector\" />\n\n    <Spinner\n        android:id=\"@+id/targetLangSelector\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:textAlignment=\"center\"\n        app:layout_constraintBottom_toBottomOf=\"@id/sourceLangSelector\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toEndOf=\"@id/buttonSwitchLang\"\n        app:layout_constraintTop_toTopOf=\"@id/sourceLangSelector\" />\n\n    <ToggleButton\n        android:id=\"@+id/buttonSyncSource\"\n        style=\"@style/Widget.MaterialComponents.Button.TextButton\"\n        android:layout_width=\"126dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginEnd=\"16dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:textOff=\"@string/download_model\"\n        android:textOn=\"@string/delete_model\"\n        android:textSize=\"11sp\"\n        app:layout_constraintBottom_toTopOf=\"@id/downloadedModels\"\n        app:layout_constraintEnd_toEndOf=\"@+id/sourceLangSelector\"\n        app:layout_constraintStart_toStartOf=\"@id/sourceLangSelector\"\n        app:layout_constraintTop_toBottomOf=\"@id/sourceLangSelector\" />\n\n    <ToggleButton\n        android:id=\"@+id/buttonSyncTarget\"\n        style=\"@style/Widget.MaterialComponents.Button.TextButton\"\n        android:layout_width=\"127dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:textOff=\"@string/download_model\"\n        android:textOn=\"@string/delete_model\"\n        android:textSize=\"11sp\"\n        app:layout_constraintBottom_toBottomOf=\"@id/buttonSyncSource\"\n        app:layout_constraintEnd_toEndOf=\"@id/targetLangSelector\"\n        app:layout_constraintStart_toStartOf=\"@id/targetLangSelector\"\n        app:layout_constraintTop_toTopOf=\"@id/buttonSyncSource\" />\n\n    <TextView\n        android:id=\"@+id/downloadedModels\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:text=\"@string/downloaded_models_label\"\n        app:layout_constraintBottom_toTopOf=\"@id/targetText\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/buttonSyncSource\" />\n\n    <TextView\n        android:id=\"@+id/targetText\"\n        style=\"@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginStart=\"8dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginEnd=\"8dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:gravity=\"top\"\n        android:hint=\"@string/translated_text_hint\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/downloadedModels\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/translate/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2019 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<resources>\n  <color name=\"colorPrimary\">#008577</color>\n  <color name=\"colorPrimaryDark\">#00574B</color>\n  <color name=\"colorAccent\">#D81B60</color>\n</resources>"
  },
  {
    "path": "android/translate/app/src/main/res/values/dimens.xml",
    "content": "<resources>\n  <!-- Default screen margins, per the Android Design guidelines. -->\n  <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n  <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n  <dimen name=\"input_box_height\">200dp</dimen>\n</resources>\n"
  },
  {
    "path": "android/translate/app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <string name=\"app_name\">MLKit-Translate</string>\n  <string name=\"translated_text_hint\">Translated text</string>\n  <string name=\"downloaded_models_label\">Downloaded models: %1$s</string>\n  <string name=\"translate_progress\">Translating&#8230;</string>\n  <string name=\"delete_model\">Delete Model</string>\n  <string name=\"download_model\">Download Model</string>\n  <string name=\"unknown_error\">Unknown error occurred.</string>\n  <string name=\"source_text_hint\">Source text</string>\n</resources>\n"
  },
  {
    "path": "android/translate/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n  <!-- Base application theme. -->\n  <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.DarkActionBar\">\n    <!-- Customize your theme here. -->\n    <item name=\"colorPrimary\">@color/colorPrimary</item>\n    <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n    <item name=\"colorAccent\">@color/colorAccent</item>\n  </style>\n  <style name=\"IconOnlyButton\" parent=\"Widget.MaterialComponents.Button.OutlinedButton\">\n    <item name=\"iconPadding\">0dp</item>\n    <item name=\"iconGravity\">textStart</item>\n  </style>\n</resources>\n"
  },
  {
    "path": "android/translate/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.7.20'\n\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.4.2'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        google()\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "android/translate/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.5-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "android/translate/gradle.properties",
    "content": "android.useAndroidX=true\nandroid.enableJetifier=true\norg.gradle.jvmargs=-Xmx4g\n"
  },
  {
    "path": "android/translate/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/translate/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      http://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/translate/settings.gradle",
    "content": "rootProject.name = 'mlkit_translate_sample'\n\ninclude ':app'\ninclude ':internal:chooserx'\nproject(':internal:chooserx').projectDir = file('../internal/chooserx')\n"
  },
  {
    "path": "android/translate-showcase/README.md",
    "content": "# ML Kit Translate Showcase App with Material Design\n\nThe ML Kit Translate Showcase app demonstrates how to build an end-to-end user experience with [Google ML Kit APIs](https://developers.google.com/ml-kit/guides) and following the new [Material for ML design guidelines](https://material.io/design/machine-learning/).\n\nThe goal of this app is to showcase an ideal ML Kit driven end to end solution for various ML Kit Natural Language Processing APIs and use cases. The following use cases are covered:\n\n* **Real-time translation using on-device Text Recognition, Language ID, Translate APIs** - An end-to-end solution from text recognition to translate via the live camera.\n\n![live_translate](./demo.gif)\n\n\n## Steps to run the app\n\n1. Clone this repo locally\n5. Build and run it on a physical device (the simulator isn't recommended, as the app needs to use the camera on the device).\n\n## How to use the app\n\nThis app demonstrates live text translate using the camera:\n* Open the app and point the bounding box of the camera at any text of interest. The recognized text and it's detected language will show up on the upper part of the bottom sheet.\n* As you recognize text within the bounding box, you'll see the translated version of this text appear on the bottom in real-time using the ML Kit on-device Translate API.\n* You can also switch the language you’d like to translate to using the drop down menu located in the center of the bottom sheet.\n\n## License\n© Google, 2020. Licensed under an [Apache-2](./LICENSE) license.\n\n"
  },
  {
    "path": "android/translate-showcase/app/build.gradle",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\napply plugin: 'com.android.application'\n\napply plugin: 'kotlin-android'\n\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 31\n    defaultConfig {\n        applicationId \"com.google.mlkit.showcase.translate\"\n        minSdkVersion 21\n        targetSdkVersion 31\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = \"1.8\"\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'androidx.appcompat:appcompat:1.4.1'\n    implementation 'androidx.core:core-ktx:1.7.0'\n    implementation 'androidx.fragment:fragment-ktx:1.4.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.1.2'\n    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'\n    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'\n    testImplementation 'junit:junit:4.13.1'\n    androidTestImplementation 'androidx.test:runner:1.4.0'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'\n\n    // Add CameraX dependencies\n    implementation \"androidx.camera:camera-core:\"\n    implementation \"androidx.camera:camera-camera2:1.1.0-alpha12\"\n    implementation \"androidx.camera:camera-lifecycle:1.1.0-alpha12\"\n    implementation \"androidx.camera:camera-view:1.0.0-alpha32\"\n\n    // Add ML Kit dependencies\n    implementation 'com.google.android.gms:play-services-mlkit-text-recognition:18.0.1'\n    implementation 'com.google.mlkit:language-id:17.0.4'\n    implementation 'com.google.mlkit:translate:17.0.1'\n}\napply plugin: 'com.google.android.gms.strict-version-matcher-plugin'\n"
  },
  {
    "path": "android/translate-showcase/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.google.mlkit.showcase.translate\">\n\n  <uses-permission android:name=\"android.permission.CAMERA\" />\n  <uses-permission android:name=\"android.permission.INTERNET\" />\n  <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n\n  <application\n      android:allowBackup=\"true\"\n      android:icon=\"@drawable/logo_mlkit\"\n      android:label=\"@string/app_name\"\n      android:supportsRtl=\"true\"\n      android:theme=\"@style/AppTheme\">\n    <activity\n        android:name=\".MainActivity\"\n        android:exported=\"true\"\n        android:screenOrientation=\"portrait\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\" />\n        <category android:name=\"android.intent.category.LAUNCHER\" />\n      </intent-filter>\n    </activity>\n    <!-- Automatically download the text recognition model after app install. -->\n    <meta-data\n        android:name=\"com.google.mlkit.vision.DEPENDENCIES\"\n        android:value=\"ocr\" />\n  </application>\n\n</manifest>\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/MainActivity.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\npackage com.google.mlkit.showcase.translate\n\nimport androidx.appcompat.app.AppCompatActivity\nimport android.os.Bundle\nimport com.google.mlkit.showcase.translate.main.MainFragment\n\nclass MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.main_translateshowcase_activity)\n        if (savedInstanceState == null) {\n            supportFragmentManager.beginTransaction()\n                .replace(R.id.container, MainFragment.newInstance())\n                .commitNow()\n        }\n    }\n\n}\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/analyzer/TextAnalyzer.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\npackage com.google.mlkit.showcase.translate.analyzer\n\nimport android.content.Context\nimport android.graphics.Rect\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.camera.core.ImageAnalysis\nimport androidx.camera.core.ImageProxy\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.MutableLiveData\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.common.MlKitException\nimport com.google.mlkit.showcase.translate.util.ImageUtils\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.text.Text\nimport com.google.mlkit.vision.text.TextRecognition\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions\nimport java.util.concurrent.Executor\n\n/**\n * Analyzes the frames passed in from the camera and returns any detected text within the requested\n * crop region.\n */\nclass TextAnalyzer(\n    private val context: Context,\n    lifecycle: Lifecycle,\n    executor: Executor,\n    private val result: MutableLiveData<String>,\n    private val imageCropPercentages: MutableLiveData<Pair<Int, Int>>\n) : ImageAnalysis.Analyzer {\n    private val detector =\n        TextRecognition.getClient(TextRecognizerOptions.Builder().setExecutor(executor).build())\n\n    init {\n        lifecycle.addObserver(detector)\n    }\n\n    @androidx.camera.core.ExperimentalGetImage\n    override fun analyze(imageProxy: ImageProxy) {\n        val mediaImage = imageProxy.image ?: return\n\n        val rotationDegrees = imageProxy.imageInfo.rotationDegrees\n\n        // We requested a setTargetAspectRatio, but it's not guaranteed that's what the camera\n        // stack is able to support, so we calculate the actual ratio from the first frame to\n        // know how to appropriately crop the image we want to analyze.\n        val imageHeight = mediaImage.height\n        val imageWidth = mediaImage.width\n\n        val actualAspectRatio = imageWidth / imageHeight\n\n        val convertImageToBitmap = ImageUtils.convertYuv420888ImageToBitmap(mediaImage)\n        val cropRect = Rect(0, 0, imageWidth, imageHeight)\n\n        // If the image has a way wider aspect ratio than expected, crop less of the height so we\n        // don't end up cropping too much of the image. If the image has a way taller aspect ratio\n        // than expected, we don't have to make any changes to our cropping so we don't handle it\n        // here.\n        val currentCropPercentages = imageCropPercentages.value ?: return\n        if (actualAspectRatio > 3) {\n            val originalHeightCropPercentage = currentCropPercentages.first\n            val originalWidthCropPercentage = currentCropPercentages.second\n            imageCropPercentages.value =\n                Pair(originalHeightCropPercentage / 2, originalWidthCropPercentage)\n        }\n\n        // If the image is rotated by 90 (or 270) degrees, swap height and width when calculating\n        // the crop.\n        val cropPercentages = imageCropPercentages.value ?: return\n        val heightCropPercent = cropPercentages.first\n        val widthCropPercent = cropPercentages.second\n        val (widthCrop, heightCrop) = when (rotationDegrees) {\n            90, 270 -> Pair(heightCropPercent / 100f, widthCropPercent / 100f)\n            else -> Pair(widthCropPercent / 100f, heightCropPercent / 100f)\n        }\n\n        cropRect.inset(\n            (imageWidth * widthCrop / 2).toInt(),\n            (imageHeight * heightCrop / 2).toInt()\n        )\n        val croppedBitmap = ImageUtils.rotateAndCrop(convertImageToBitmap, rotationDegrees, cropRect)\n        recognizeTextOnDevice(InputImage.fromBitmap(croppedBitmap, 0)).addOnCompleteListener {\n            imageProxy.close()\n        }\n    }\n\n    private fun recognizeTextOnDevice(\n        image: InputImage\n    ): Task<Text> {\n        // Pass image to an ML Kit Vision API\n        return detector.process(image)\n            .addOnSuccessListener { visionText ->\n                // Task completed successfully\n                result.value = visionText.text\n            }\n            .addOnFailureListener { exception ->\n                // Task failed with an exception\n                Log.e(TAG, \"Text recognition error\", exception)\n                val message = getErrorMessage(exception)\n                message?.let {\n                    Toast.makeText(context, message, Toast.LENGTH_SHORT).show()\n                }\n            }\n    }\n\n    private fun getErrorMessage(exception: Exception): String? {\n        val mlKitException = exception as? MlKitException ?: return exception.message\n        return if (mlKitException.errorCode == MlKitException.UNAVAILABLE) {\n            \"Waiting for text recognition model to be downloaded\"\n        } else exception.message\n    }\n\n    companion object {\n        private const val TAG = \"TextAnalyzer\"\n    }\n}"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/main/MainFragment.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\npackage com.google.mlkit.showcase.translate.main\n\nimport android.Manifest\nimport android.content.pm.PackageManager\nimport android.graphics.*\nimport android.os.Bundle\nimport android.util.DisplayMetrics\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.SurfaceHolder\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.AdapterView\nimport android.widget.ArrayAdapter\nimport android.widget.Toast\nimport androidx.camera.core.*\nimport androidx.camera.core.Camera\nimport androidx.camera.lifecycle.ProcessCameraProvider\nimport androidx.camera.view.PreviewView\nimport androidx.constraintlayout.widget.ConstraintLayout\nimport androidx.core.content.ContextCompat\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.viewModels\nimport androidx.lifecycle.Observer\nimport com.google.mlkit.showcase.translate.R\nimport com.google.mlkit.showcase.translate.analyzer.TextAnalyzer\nimport com.google.mlkit.showcase.translate.util.Language\nimport com.google.mlkit.showcase.translate.util.ScopedExecutor\nimport kotlinx.android.synthetic.main.main_fragment.*\nimport java.util.concurrent.ExecutionException\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport kotlin.math.abs\nimport kotlin.math.ln\nimport kotlin.math.max\nimport kotlin.math.min\n\nclass MainFragment : Fragment() {\n\n    companion object {\n        fun newInstance() = MainFragment()\n\n        // We only need to analyze the part of the image that has text, so we set crop percentages\n        // to avoid analyze the entire image from the live camera feed.\n        const val DESIRED_WIDTH_CROP_PERCENT = 8\n        const val DESIRED_HEIGHT_CROP_PERCENT = 74\n\n        // This is an arbitrary number we are using to keep tab of the permission\n        // request. Where an app has multiple context for requesting permission,\n        // this can help differentiate the different contexts\n        private const val REQUEST_CODE_PERMISSIONS = 10\n\n        // This is an array of all the permission specified in the manifest\n        private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)\n        private const val RATIO_4_3_VALUE = 4.0 / 3.0\n        private const val RATIO_16_9_VALUE = 16.0 / 9.0\n        private const val TAG = \"MainFragment\"\n    }\n\n    private var displayId: Int = -1\n    private val viewModel: MainViewModel by viewModels()\n    private var camera: Camera? = null\n    private var imageAnalyzer: ImageAnalysis? = null\n    private lateinit var container: ConstraintLayout\n    private lateinit var viewFinder: PreviewView\n\n    /** Blocking camera and inference operations are performed using this executor. */\n    private lateinit var cameraExecutor: ExecutorService\n\n    /** UI callbacks are run on this executor. */\n    private lateinit var scopedExecutor: ScopedExecutor\n\n    override fun onCreateView(\n        inflater: LayoutInflater, container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View {\n        return inflater.inflate(R.layout.main_fragment, container, false)\n    }\n\n    override fun onDestroyView() {\n        super.onDestroyView()\n\n        // Shut down the scoped executor. The camera executor will automatically shut down its\n        // background threads after 60s of idling.\n        scopedExecutor.shutdown()\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        container = view as ConstraintLayout\n        viewFinder = container.findViewById(R.id.viewfinder)\n\n        // Initialize our background executor\n        cameraExecutor = Executors.newCachedThreadPool()\n        scopedExecutor = ScopedExecutor(cameraExecutor)\n\n        viewModel.executor = cameraExecutor\n\n        // Request camera permissions\n        if (allPermissionsGranted()) {\n            // Wait for the views to be properly laid out\n            viewFinder.post {\n                // Keep track of the display in which this view is attached\n                displayId = viewFinder.display.displayId\n\n                // Set up the camera and its use cases\n                setUpCamera()\n            }\n        } else {\n            requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)\n        }\n\n        // Get available language list and set up the target language spinner\n        // with default selections.\n        val adapter = ArrayAdapter(\n            requireContext(),\n            android.R.layout.simple_spinner_dropdown_item, viewModel.availableLanguages\n        )\n\n        targetLangSelector.adapter = adapter\n        targetLangSelector.setSelection(adapter.getPosition(Language(\"en\")))\n        targetLangSelector.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {\n            override fun onItemSelected(\n                parent: AdapterView<*>,\n                view: View?,\n                position: Int,\n                id: Long\n            ) {\n                viewModel.targetLang.value = adapter.getItem(position)\n            }\n\n            override fun onNothingSelected(parent: AdapterView<*>) {}\n        }\n\n        viewModel.sourceLang.observe(viewLifecycleOwner, Observer { srcLang.text = it.displayName })\n        viewModel.translatedText.observe(viewLifecycleOwner, Observer { resultOrError ->\n            resultOrError?.let {\n                if (it.error != null) {\n                    translatedText.error = resultOrError.error?.localizedMessage\n                } else {\n                    translatedText.text = resultOrError.result\n                }\n            }\n        })\n        viewModel.modelDownloading.observe(viewLifecycleOwner, Observer { isDownloading ->\n            progressBar.visibility = if (isDownloading) {\n                View.VISIBLE\n            } else {\n                View.INVISIBLE\n            }\n            progressText.visibility = progressBar.visibility\n        })\n\n        overlay.apply {\n            setZOrderOnTop(true)\n            holder.setFormat(PixelFormat.TRANSPARENT)\n            holder.addCallback(object : SurfaceHolder.Callback {\n                override fun surfaceChanged(\n                    holder: SurfaceHolder,\n                    format: Int,\n                    width: Int,\n                    height: Int\n                ) {\n                }\n\n                override fun surfaceDestroyed(holder: SurfaceHolder) {}\n\n                override fun surfaceCreated(holder: SurfaceHolder) {\n                    holder?.let {\n                        drawOverlay(\n                            it,\n                            DESIRED_HEIGHT_CROP_PERCENT,\n                            DESIRED_WIDTH_CROP_PERCENT\n                        )\n                    }\n                }\n            })\n        }\n    }\n\n\n    /** Initialize CameraX, and prepare to bind the camera use cases  */\n    private fun setUpCamera() {\n        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())\n        cameraProviderFuture.addListener(Runnable {\n            val cameraProvider = try {\n                cameraProviderFuture.get()\n            } catch (e: ExecutionException) {\n                throw IllegalStateException(\"Camera initialization failed.\", e.cause!!)\n            }\n            // Build and bind the camera use cases\n            bindCameraUseCases(cameraProvider)\n        }, ContextCompat.getMainExecutor(requireContext()))\n    }\n\n    private fun bindCameraUseCases(cameraProvider: ProcessCameraProvider) {\n        // Get screen metrics used to setup camera for full screen resolution\n        val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }\n        Log.d(TAG, \"Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}\")\n\n        val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)\n        Log.d(TAG, \"Preview aspect ratio: $screenAspectRatio\")\n\n        val rotation = viewFinder.display.rotation\n\n        val preview = Preview.Builder()\n            .setTargetAspectRatio(screenAspectRatio)\n            .setTargetRotation(rotation)\n            .build()\n\n        // Build the image analysis use case and instantiate our analyzer\n        imageAnalyzer = ImageAnalysis.Builder()\n            // We request aspect ratio but no resolution\n            .setTargetAspectRatio(screenAspectRatio)\n            .setTargetRotation(rotation)\n            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)\n            .build()\n            .also {\n                it.setAnalyzer(\n                    scopedExecutor, TextAnalyzer(\n                        requireContext(),\n                        lifecycle,\n                        cameraExecutor,\n                        viewModel.sourceText,\n                        viewModel.imageCropPercentages\n                    )\n                )\n            }\n        viewModel.sourceText.observe(viewLifecycleOwner, Observer { srcText.text = it })\n        viewModel.imageCropPercentages.observe(viewLifecycleOwner,\n            Observer { drawOverlay(overlay.holder, it.first, it.second) })\n\n        // Select back camera since text detection does not work with front camera\n        val cameraSelector =\n            CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()\n\n        try {\n            // Unbind use cases before rebinding\n            cameraProvider.unbindAll()\n\n            // Bind use cases to camera\n            camera = cameraProvider.bindToLifecycle(\n                this, cameraSelector, preview, imageAnalyzer\n            )\n            preview.setSurfaceProvider(viewFinder.surfaceProvider)\n        } catch (exc: IllegalStateException) {\n            Log.e(TAG, \"Use case binding failed. This must be running on main thread.\", exc)\n        }\n    }\n\n    private fun drawOverlay(\n        holder: SurfaceHolder,\n        heightCropPercent: Int,\n        widthCropPercent: Int\n    ) {\n        val canvas = holder.lockCanvas()\n        val bgPaint = Paint().apply {\n            alpha = 140\n        }\n        canvas.drawPaint(bgPaint)\n        val rectPaint = Paint()\n        rectPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)\n        rectPaint.style = Paint.Style.FILL\n        rectPaint.color = Color.WHITE\n        val outlinePaint = Paint()\n        outlinePaint.style = Paint.Style.STROKE\n        outlinePaint.color = Color.WHITE\n        outlinePaint.strokeWidth = 4f\n        val surfaceWidth = holder.surfaceFrame.width()\n        val surfaceHeight = holder.surfaceFrame.height()\n\n        val cornerRadius = 25f\n        // Set rect centered in frame\n        val rectTop = surfaceHeight * heightCropPercent / 2 / 100f\n        val rectLeft = surfaceWidth * widthCropPercent / 2 / 100f\n        val rectRight = surfaceWidth * (1 - widthCropPercent / 2 / 100f)\n        val rectBottom = surfaceHeight * (1 - heightCropPercent / 2 / 100f)\n        val rect = RectF(rectLeft, rectTop, rectRight, rectBottom)\n        canvas.drawRoundRect(\n            rect, cornerRadius, cornerRadius, rectPaint\n        )\n        canvas.drawRoundRect(\n            rect, cornerRadius, cornerRadius, outlinePaint\n        )\n        val textPaint = Paint()\n        textPaint.color = Color.WHITE\n        textPaint.textSize = 50F\n\n        val overlayText = getString(R.string.overlay_help)\n        val textBounds = Rect()\n        textPaint.getTextBounds(overlayText, 0, overlayText.length, textBounds)\n        val textX = (surfaceWidth - textBounds.width()) / 2f\n        val textY = rectBottom + textBounds.height() + 15f // put text below rect and 15f padding\n        canvas.drawText(getString(R.string.overlay_help), textX, textY, textPaint)\n        holder.unlockCanvasAndPost(canvas)\n    }\n\n    /**\n     *  [androidx.camera.core.ImageAnalysisConfig] requires enum value of\n     *  [androidx.camera.core.AspectRatio]. Currently it has values of 4:3 & 16:9.\n     *\n     *  Detecting the most suitable ratio for dimensions provided in @params by comparing absolute\n     *  of preview ratio to one of the provided values.\n     *\n     *  @param width - preview width\n     *  @param height - preview height\n     *  @return suitable aspect ratio\n     */\n    private fun aspectRatio(width: Int, height: Int): Int {\n        val previewRatio = ln(max(width, height).toDouble() / min(width, height))\n        if (abs(previewRatio - ln(RATIO_4_3_VALUE))\n            <= abs(previewRatio - ln(RATIO_16_9_VALUE))\n        ) {\n            return AspectRatio.RATIO_4_3\n        }\n        return AspectRatio.RATIO_16_9\n    }\n\n    /**\n     * Process result from permission request dialog box, has the request\n     * been granted? If yes, start Camera. Otherwise display a toast\n     */\n    override fun onRequestPermissionsResult(\n        requestCode: Int, permissions: Array<String>, grantResults: IntArray\n    ) {\n        if (requestCode == REQUEST_CODE_PERMISSIONS) {\n            if (allPermissionsGranted()) {\n                viewFinder.post { setUpCamera() }\n            } else {\n                Toast.makeText(\n                    context,\n                    \"Permissions not granted by the user.\",\n                    Toast.LENGTH_SHORT\n                ).show()\n            }\n        }\n    }\n\n    /**\n     * Check if all permission specified in the manifest have been granted\n     */\n    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {\n        ContextCompat.checkSelfPermission(\n            requireContext(), it\n        ) == PackageManager.PERMISSION_GRANTED\n    }\n}\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/main/MainViewModel.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\npackage com.google.mlkit.showcase.translate.main\n\nimport android.app.Application\nimport android.os.Handler\nimport android.util.LruCache\nimport androidx.lifecycle.AndroidViewModel\nimport androidx.lifecycle.MediatorLiveData\nimport androidx.lifecycle.MutableLiveData\nimport com.google.android.gms.tasks.OnCompleteListener\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.Tasks\nimport com.google.mlkit.nl.languageid.LanguageIdentification\nimport com.google.mlkit.nl.languageid.LanguageIdentificationOptions\nimport com.google.mlkit.nl.translate.TranslateLanguage\nimport com.google.mlkit.nl.translate.Translation\nimport com.google.mlkit.nl.translate.Translator\nimport com.google.mlkit.nl.translate.TranslatorOptions\nimport com.google.mlkit.showcase.translate.main.MainFragment.Companion.DESIRED_HEIGHT_CROP_PERCENT\nimport com.google.mlkit.showcase.translate.main.MainFragment.Companion.DESIRED_WIDTH_CROP_PERCENT\nimport com.google.mlkit.showcase.translate.util.Language\nimport com.google.mlkit.showcase.translate.util.ResultOrError\nimport com.google.mlkit.showcase.translate.util.SmoothedMutableLiveData\nimport java.util.concurrent.Executor\n\nclass MainViewModel(application: Application) : AndroidViewModel(application) {\n    override fun onCleared() {\n        languageIdentification.close()\n        translators.evictAll()\n    }\n\n    lateinit var executor: Executor\n    private val languageIdentification by lazy {\n        LanguageIdentification.getClient(\n            LanguageIdentificationOptions.Builder().setExecutor(executor).build()\n        )\n    }\n\n    val targetLang = MutableLiveData<Language>()\n    val sourceText = SmoothedMutableLiveData<String>(SMOOTHING_DURATION)\n\n    // We set desired crop percentages to avoid having the analyze the whole image from the live\n    // camera feed. However, we are not guaranteed what aspect ratio we will get from the camera, so\n    // we use the first frame we get back from the camera to update these crop percentages based on\n    // the actual aspect ratio of images.\n    val imageCropPercentages = MutableLiveData<Pair<Int, Int>>()\n        .apply { value = Pair(DESIRED_HEIGHT_CROP_PERCENT, DESIRED_WIDTH_CROP_PERCENT) }\n    val translatedText = MediatorLiveData<ResultOrError>()\n    private val translating = MutableLiveData<Boolean>()\n    val modelDownloading = SmoothedMutableLiveData<Boolean>(SMOOTHING_DURATION)\n\n    private var modelDownloadTask: Task<Void> = Tasks.forCanceled()\n\n    private val translators =\n        object : LruCache<TranslatorOptions, Translator>(NUM_TRANSLATORS) {\n            override fun create(options: TranslatorOptions): Translator {\n                return Translation.getClient(options)\n            }\n\n            override fun entryRemoved(\n                evicted: Boolean,\n                key: TranslatorOptions,\n                oldValue: Translator,\n                newValue: Translator?\n            ) {\n                oldValue.close()\n            }\n        }\n\n    val sourceLang = MediatorLiveData<Language>()\n\n    private fun translate(): Task<String> {\n        if (modelDownloading.value != false || translating.value != false) {\n            return Tasks.forCanceled()\n        }\n        val text = sourceText.value ?: return Tasks.forResult(\"\")\n        val source = sourceLang.value ?: return Tasks.forResult(\"\")\n        val target = targetLang.value ?: return Tasks.forResult(\"\")\n        val sourceLangCode =\n            TranslateLanguage.fromLanguageTag(source.code) ?: return Tasks.forCanceled()\n        val targetLangCode =\n            TranslateLanguage.fromLanguageTag(target.code) ?: return Tasks.forCanceled()\n        val options = TranslatorOptions.Builder()\n            .setSourceLanguage(sourceLangCode)\n            .setTargetLanguage(targetLangCode)\n            .setExecutor(executor)\n            .build()\n        val translator = translators[options]\n        modelDownloading.setValue(true)\n\n        // Register watchdog to unblock long running downloads\n        Handler().postDelayed({ modelDownloading.setValue(false) }, 15000)\n        modelDownloadTask = translator.downloadModelIfNeeded().addOnCompleteListener {\n            modelDownloading.setValue(false)\n        }\n        translating.value = true\n        return modelDownloadTask.onSuccessTask {\n            translator.translate(text)\n        }.addOnCompleteListener {\n            translating.value = false\n        }\n    }\n\n    // Gets a list of all available translation languages.\n    val availableLanguages: List<Language> = TranslateLanguage.getAllLanguages()\n        .map { Language(it) }\n\n    init {\n        modelDownloading.setValue(false)\n        translating.value = false\n\n        sourceLang.addSource(sourceText) { text ->\n            languageIdentification.identifyLanguage(text)\n                .addOnSuccessListener {\n                    if (it != \"und\")\n                        sourceLang.value = Language(it)\n                }\n        }\n\n        // Create a translation result or error object.\n        val processTranslation =\n            OnCompleteListener<String> { task ->\n                if (task.isSuccessful) {\n                    translatedText.value = ResultOrError(task.result, null)\n                } else {\n                    if (task.isCanceled) {\n                        // Tasks are cancelled for reasons such as gating; ignore.\n                        return@OnCompleteListener\n                    }\n                    translatedText.value = ResultOrError(null, task.exception)\n                }\n            }\n        // Start translation if any of the following change: detected text, source lang, target lang.\n        translatedText.addSource(sourceText) { translate().addOnCompleteListener(processTranslation) }\n        translatedText.addSource(sourceLang) { translate().addOnCompleteListener(processTranslation) }\n        translatedText.addSource(targetLang) { translate().addOnCompleteListener(processTranslation) }\n    }\n\n    companion object {\n        // Amount of time (in milliseconds) to wait for detected text to settle\n        private const val SMOOTHING_DURATION = 50L\n\n        private const val NUM_TRANSLATORS = 1\n    }\n}\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/util/ImageUtils.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\npackage com.google.mlkit.showcase.translate.util\n\nimport android.graphics.Bitmap\nimport android.graphics.ImageFormat\nimport android.graphics.Matrix\nimport android.graphics.Rect\nimport android.media.Image\nimport androidx.annotation.ColorInt\n\n/**\n * Utility class for manipulating images.\n */\nobject ImageUtils {\n    private val CHANNEL_RANGE = 0 until (1 shl 18)\n\n    fun convertYuv420888ImageToBitmap(image: Image): Bitmap {\n        require(image.format == ImageFormat.YUV_420_888) {\n            \"Unsupported image format $(image.format)\"\n        }\n\n        val planes = image.planes\n\n        // Because of the variable row stride it's not possible to know in\n        // advance the actual necessary dimensions of the yuv planes.\n        val yuvBytes = planes.map { plane ->\n            val buffer = plane.buffer\n            val yuvBytes = ByteArray(buffer.capacity())\n            buffer[yuvBytes]\n            buffer.rewind()  // Be kind…\n            yuvBytes\n        }\n\n        val yRowStride = planes[0].rowStride\n        val uvRowStride = planes[1].rowStride\n        val uvPixelStride = planes[1].pixelStride\n        val width = image.width\n        val height = image.height\n        @ColorInt val argb8888 = IntArray(width * height)\n        var i = 0\n        for (y in 0 until height) {\n            val pY = yRowStride * y\n            val uvRowStart = uvRowStride * (y shr 1)\n            for (x in 0 until width) {\n                val uvOffset = (x shr 1) * uvPixelStride\n                argb8888[i++] =\n                    yuvToRgb(\n                        yuvBytes[0][pY + x].toIntUnsigned(),\n                        yuvBytes[1][uvRowStart + uvOffset].toIntUnsigned(),\n                        yuvBytes[2][uvRowStart + uvOffset].toIntUnsigned()\n                    )\n            }\n        }\n        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)\n        bitmap.setPixels(argb8888, 0, width, 0, 0, width, height)\n        return bitmap\n    }\n\n    fun rotateAndCrop(\n        bitmap: Bitmap,\n        imageRotationDegrees: Int,\n        cropRect: Rect\n    ): Bitmap {\n        val matrix = Matrix()\n        matrix.preRotate(imageRotationDegrees.toFloat())\n        return Bitmap.createBitmap(\n            bitmap,\n            cropRect.left,\n            cropRect.top,\n            cropRect.width(),\n            cropRect.height(),\n            matrix,\n            true\n        )\n    }\n\n    @ColorInt\n    private fun yuvToRgb(nY: Int, nU: Int, nV: Int): Int {\n        var nY = nY\n        var nU = nU\n        var nV = nV\n        nY -= 16\n        nU -= 128\n        nV -= 128\n        nY = nY.coerceAtLeast(0)\n\n        // This is the floating point equivalent. We do the conversion in integer\n        // because some Android devices do not have floating point in hardware.\n        // nR = (int)(1.164 * nY + 2.018 * nU);\n        // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);\n        // nB = (int)(1.164 * nY + 1.596 * nV);\n        var nR = 1192 * nY + 1634 * nV\n        var nG = 1192 * nY - 833 * nV - 400 * nU\n        var nB = 1192 * nY + 2066 * nU\n\n        // Clamp the values before normalizing them to 8 bits.\n        nR = nR.coerceIn(CHANNEL_RANGE) shr 10 and 0xff\n        nG = nG.coerceIn(CHANNEL_RANGE) shr 10 and 0xff\n        nB = nB.coerceIn(CHANNEL_RANGE) shr 10 and 0xff\n        return -0x1000000 or (nR shl 16) or (nG shl 8) or nB\n    }\n}\n\nprivate fun Byte.toIntUnsigned(): Int {\n    return toInt() and 0xFF\n}\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/util/Language.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\npackage com.google.mlkit.showcase.translate.util\n\nimport java.util.*\n\n/**\n * Holds the language code (i.e. \"en\") and the corresponding localized full language name\n * (i.e. \"English\")\n */\nclass Language(val code: String) : Comparable<Language> {\n\n    val displayName: String\n        get() = Locale(code).displayName\n\n    override fun equals(other: Any?): Boolean {\n        if (other === this) {\n            return true\n        }\n\n        if (other !is Language) {\n            return false\n        }\n\n        val otherLang = other as Language?\n        return otherLang!!.code == code\n    }\n\n    override fun toString(): String {\n        return displayName\n    }\n\n    override fun compareTo(other: Language): Int {\n        return this.displayName.compareTo(other.displayName)\n    }\n\n    override fun hashCode(): Int {\n        return code.hashCode()\n    }\n}\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/util/ResultOrError.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\npackage com.google.mlkit.showcase.translate.util\n\n/**\n * Holds a result or some operation or the exception.\n */\nclass ResultOrError(var result: String?, var error: Exception?)\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/util/ScopedExecutor.kt",
    "content": "package com.google.mlkit.showcase.translate.util\n\nimport java.util.concurrent.Executor\nimport java.util.concurrent.atomic.AtomicBoolean\n\nclass ScopedExecutor(private val executor: Executor) : Executor {\n\n    private val isShutdown = AtomicBoolean()\n\n    fun shutdown() {\n        isShutdown.set(true)\n    }\n\n    override fun execute(command: Runnable) {\n        executor.execute {\n            if (!isShutdown.get()) command.run()\n        }\n    }\n}"
  },
  {
    "path": "android/translate-showcase/app/src/main/java/com/google/mlkit/showcase/translate/util/SmoothedMutableLiveData.kt",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\npackage com.google.mlkit.showcase.translate.util\n\nimport android.os.Handler\nimport androidx.lifecycle.MutableLiveData\n\n/**\n * A {@link MutableLiveData} that only emits change events when the underlying data has been stable\n * for the configured amount of time.\n *\n * @param duration time delay to wait in milliseconds\n */\nclass SmoothedMutableLiveData<T>(private val duration: Long) : MutableLiveData<T>() {\n    private var pendingValue: T? = null\n    private val runnable = Runnable {\n        super.setValue(pendingValue)\n    }\n\n    override fun setValue(value: T) {\n        if (value != pendingValue) {\n            pendingValue = value\n            Handler().removeCallbacks(runnable)\n            Handler().postDelayed(runnable, duration)\n        }\n    }\n}"
  },
  {
    "path": "android/translate-showcase/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:ignore=\"NewApi\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportWidth=\"172.43\"\n    android:viewportHeight=\"129.06\">\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#abccfc\"\n        android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n    <path\n        android:fillColor=\"#abccfc\"\n        android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/res/layout/main_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2020 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  ~\n  -->\n\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/main\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.google.mlkit.showcase.translate.main.MainFragment\">\n\n    <androidx.camera.view.PreviewView\n        android:id=\"@+id/viewfinder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"@id/middle\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n    <SurfaceView\n        android:id=\"@+id/overlay\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        app:layout_constraintStart_toStartOf=\"@id/viewfinder\"\n        app:layout_constraintEnd_toEndOf=\"@id/viewfinder\"\n        app:layout_constraintBottom_toBottomOf=\"@id/viewfinder\"\n        app:layout_constraintTop_toTopOf=\"@id/viewfinder\" />\n\n    <androidx.constraintlayout.widget.Guideline\n        android:id=\"@+id/middle\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        app:layout_constraintGuide_percent=\".5\" />\n\n    <TextView\n        android:id=\"@+id/srcLang\"\n        style=\"@style/SrcLangText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"20dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginEnd=\"20dp\"\n        android:layout_marginBottom=\"4dp\"\n        app:layout_constraintBottom_toTopOf=\"@+id/srcTextScrollView\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/middle\"\n        tools:text=\"source lang\" />\n\n    <ScrollView\n        android:id=\"@+id/srcTextScrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:fillViewport=\"true\"\n        android:scrollbars=\"vertical\"\n        app:layout_constraintBottom_toTopOf=\"@+id/divider\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/srcLang\">\n\n        <TextView\n            android:id=\"@+id/srcText\"\n            style=\"@style/SrcText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_marginEnd=\"20dp\"\n            tools:text=\"source text\" />\n    </ScrollView>\n\n    <View\n        android:id=\"@+id/divider\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginStart=\"20dp\"\n        android:layout_marginEnd=\"20dp\"\n        android:background=\"?android:attr/listDivider\"\n        app:layout_constraintBottom_toTopOf=\"@+id/targetLangSelector\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/srcTextScrollView\" />\n\n    <Spinner\n        android:id=\"@+id/targetLangSelector\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"20dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/divider\" />\n\n    <ScrollView\n        android:id=\"@+id/translatedTextScrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:fillViewport=\"true\"\n        android:scrollbars=\"vertical\"\n        app:layout_constraintBottom_toTopOf=\"@+id/divider2\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/targetLangSelector\">\n\n        <TextView\n            android:id=\"@+id/translatedText\"\n            style=\"@style/TranslatedText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_marginEnd=\"20dp\"\n            android:layout_marginBottom=\"4dp\"\n            tools:text=\"translated text\" />\n    </ScrollView>\n\n    <View\n        android:id=\"@+id/divider2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginStart=\"20dp\"\n        android:layout_marginTop=\"4dp\"\n        android:layout_marginEnd=\"20dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:background=\"?android:attr/listDivider\"\n        app:layout_constraintBottom_toTopOf=\"@id/imageView\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/translatedTextScrollView\" />\n\n    <ImageView\n        android:id=\"@+id/imageView\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"18dp\"\n        android:layout_marginStart=\"4dp\"\n        android:layout_marginTop=\"4dp\"\n        android:layout_marginEnd=\"4dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:contentDescription=\"@string/content_description_google_translate_attribution\"\n        android:scaleType=\"fitCenter\"\n        android:src=\"@drawable/greyscale_regular_3x\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/divider2\" />\n\n    <ProgressBar\n        android:id=\"@+id/progressBar\"\n        style=\"?android:attr/progressBarStyle\"\n        android:layout_width=\"30dp\"\n        android:layout_height=\"30dp\"\n        android:visibility=\"invisible\"\n        app:layout_constraintStart_toEndOf=\"@+id/targetLangSelector\"\n        app:layout_constraintTop_toTopOf=\"@id/targetLangSelector\"\n        app:layout_constraintBottom_toBottomOf=\"@id/targetLangSelector\" />\n\n    <TextView\n        android:id=\"@+id/progressText\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:text=\"@string/downloading_model_files\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toEndOf=\"@+id/progressBar\"\n        app:layout_constraintBottom_toBottomOf=\"@id/progressBar\"\n        android:gravity=\"center_vertical\"\n        app:layout_constraintTop_toTopOf=\"@id/progressBar\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/res/layout/main_translateshowcase_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2020 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  ~\n  -->\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.google.mlkit.showcase.translate.MainActivity\" />\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright 2020 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  ~\n  -->\n\n<resources>\n    <color name=\"colorPrimary\">#008577</color>\n    <color name=\"colorPrimaryDark\">#00574B</color>\n    <color name=\"colorAccent\">#D81B60</color>\n</resources>\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/res/values/strings.xml",
    "content": "<!--\n  ~ Copyright 2020 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  ~\n  -->\n\n<resources>\n    <string name=\"app_name\">ML Kit Translate Showcase</string>\n    <string name=\"content_description_google_translate_attribution\">Powered by Google Translate</string>\n    <string name=\"overlay_help\">Center text in box</string>\n    <string name=\"downloading_model_files\">Downloading model files…</string>\n</resources>\n"
  },
  {
    "path": "android/translate-showcase/app/src/main/res/values/styles.xml",
    "content": "<!--\n  ~ Copyright 2020 Google Inc. All Rights Reserved.\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~ http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  ~\n  -->\n\n<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n    <style name=\"BaseText\">\n        <item name=\"android:fontFamily\">@font/pt_sans</item>\n    </style>\n\n    <style name=\"SrcLangText\" parent=\"BaseText\">\n        <item name=\"android:textSize\">16sp</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:textAllCaps\">true</item>\n        <item name=\"android:textColor\">@android:color/darker_gray</item>\n    </style>\n\n    <style name=\"TranslatedLangText\" parent=\"SrcLangText\">\n        <item name=\"android:textColor\">@android:color/black</item>\n    </style>\n\n    <style name=\"SrcText\" parent=\"BaseText\">\n        <item name=\"android:textSize\">28sp</item>\n        <item name=\"android:textColor\">@android:color/darker_gray</item>\n    </style>\n\n    <style name=\"TranslatedText\" parent=\"BaseText\">\n        <item name=\"android:textSize\">38sp</item>\n        <item name=\"android:textColor\">@android:color/black</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "android/translate-showcase/build.gradle",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\n// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.5.31'\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.0.4'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n        classpath 'com.google.android.gms:strict-version-matcher-plugin:1.2.2'\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n        mavenLocal()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/translate-showcase/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Sun May 17 19:28:24 BST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.0.2-all.zip\n"
  },
  {
    "path": "android/translate-showcase/gradle.properties",
    "content": "#\n# Copyright 2020 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n#\n\n# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\n"
  },
  {
    "path": "android/translate-showcase/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/translate-showcase/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/translate-showcase/settings.gradle",
    "content": "/*\n * Copyright 2020 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\ninclude ':app'\nrootProject.name='ML Kit Translate Showcase'\n"
  },
  {
    "path": "android/vision-quickstart/LICENSE",
    "content": "   Copyright 2020 Google LLC\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS"
  },
  {
    "path": "android/vision-quickstart/README.md",
    "content": "# ML Kit Vision Quickstart Sample App\n\n## Introduction\n\nThis ML Kit Quickstart app demonstrates how to use and integrate various vision based ML Kit features into your app.\n\n## Feature List\n\nFeatures that are included in this Quickstart app:\n* [Object Detection](https://developers.google.com/ml-kit/vision/object-detection/android) - Detect, track, and classify objects in real time and static images.\n* [Face Detection](https://developers.google.com/ml-kit/vision/face-detection/android) - Detect faces in real time and static images.\n* [Face Mesh Detection](https://developers.google.com/ml-kit/vision/face-mesh-detection/android) - Detect face mesh in real time and static images.\n* [Text Recognition](https://developers.google.com/ml-kit/vision/text-recognition/android) - Recognize text in real time and static images.\n* [Barcode Scanning](https://developers.google.com/ml-kit/vision/barcode-scanning/android)  - Scan barcodes in real time and static images.\n* [Image Labeling](https://developers.google.com/ml-kit/vision/image-labeling/android) - Label images in real time and static images.\n* [Custom Image Labeling - Birds](https://developers.google.com/ml-kit/vision/image-labeling/custom-models/android) - Label images of birds with a custom TensorFlow Lite model.\n* [Pose Detection](https://developers.google.com/ml-kit/vision/pose-detection/android) - Detect the position of the human body in real time.\n* [Selfie Segmentation](https://developers.google.com/ml-kit/vision/selfie-segmentation/android) - Segment people from the background in real time.\n* [Subject Segmentation](https://developers.google.com/ml-kit/vision/subject-segmentation/android) - Segment multiple subjects from the background in static images.\n\n<img src=\"../screenshots/quickstart-picker.png\" width=\"220\"/> <img src=\"../screenshots/quickstart-image-labeling.png\" width=\"220\"/> <img src=\"../screenshots/quickstart-object-detection.png\" width=\"220\"/> <img src=\"../screenshots/quickstart-pose-detection.png\" width=\"220\"/>\n\n## Getting Started\n\n* Run the sample code on your Android device or emulator\n* Try extending the code to add new features and functionality\n\n## How to use the app\n\nThis app supports three usage scenarios: Live Camera, Static Image, and CameraX enabled live camera.\n\n### Live Camera scenario\nIt uses the camera preview as input and contains these API workflows: Object detection & tracking, Face Detection, Face Mesh Detection, Text Recognition, Barcode Scanning, Image Labeling, and Pose Detection. There's also a settings page that allows you to configure several options:\n* Camera\n    * Preview size - Specify the preview size of rear/front camera manually (Default size is chosen appropriately based on screen size)\n    * Enable live viewport - Toggle between blocking camera preview by API processing and result rendering or not\n* Object detection / Custom Object Detection\n    * Enable multiple objects -- Enable multiple objects to be detected at once\n    * Enable classification -- Enable classification for each detected object\n* Face Detection\n    * Landmark mode -- Toggle between showing no or all facial landmarks\n    * Contour mode -- Toggle between showing no or all contours\n    * Classification mode -- Toggle between showing no or all classifications (smiling, eyes open/closed)\n    * Performance mode -- Toggle between two operating modes (Fast or Accurate)\n    * Face tracking -- Enable or disable face tracking\n    * Minimum face size -- Choose the proportion of the head width to the image width\n* Face Mesh Detection\n    * Use Case -- Selects from `Bounding Box only` and `Face Mesh`\n* Pose Detection\n    * Performance mode -- Allows you to switch between \"Fast\" and \"Accurate\" operation mode\n    * Show in-frame likelihood -- Displays InFrameLikelihood score for each landmark\n    * Visualize z value -- Uses different colors to indicate z difference (red: smaller z, blue: larger z)\n    * Rescale z value for visualization -- Maps the smallest z value to the most red and the largest z value to the most blue. This makes z difference more obvious\n    * Run classification -- Classify squat and pushup poses. Count reps in streaming mode.\n* Selfie Segmentation\n    * Enable raw size mask -- Asks the segmenter to return the raw size mask which matches the model output size.\n\n### Static Image scenario\nThe static image scenario is identical to the live camera scenario, but instead relies on images fed into the app through the gallery.\n\n### CameraX Live Preview scenario\nThe CameraX live preview scenario is very similar to the native live camera scenario, but instead relies on CameraX live preview. Note: CameraX is only supported on API level 21+.\n\n## Support\n\n* [Documentation](https://developers.google.com/ml-kit/guides)\n* [API Reference](https://developers.google.com/ml-kit/reference/android)\n* [Stack Overflow](https://stackoverflow.com/questions/tagged/google-mlkit)\n\n## License\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "android/vision-quickstart/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion 34\n\n    defaultConfig {\n        applicationId \"com.google.mlkit.vision.demo\"\n        minSdkVersion 21\n        multiDexEnabled true\n        targetSdkVersion 34\n\n        versionCode 11\n        versionName \"1.11\"\n        vectorDrawables.useSupportLibrary = true\n        setProperty(\"archivesBaseName\", \"vision-quickstart\")\n    }\n    buildTypes {\n        proguard {\n            debuggable false\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard.cfg'\n        }\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n        debug {\n            isDefault true\n            minifyEnabled false\n            proguardFiles 'proguard-rules.pro'\n        }\n        testBuildType \"debug\"\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    // Do NOT compress tflite model files (need to call out to developers!)\n    aaptOptions {\n        noCompress \"tflite\"\n    }\n}\n\nrepositories {\n    // Depending on AndroidX Snapshot Builds to get the latest CameraX libs.\n    maven { url 'https://androidx.dev/snapshots/builds/6787662/artifacts/repository/' }\n}\n\ndependencies {\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n    implementation 'androidx.multidex:multidex:2.0.1'\n\n    // Barcode model\n    implementation 'com.google.mlkit:barcode-scanning:17.3.0'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1'\n\n    // Object detection feature with bundled default classifier\n    implementation 'com.google.mlkit:object-detection:17.0.2'\n\n    // Object detection feature with custom classifier support\n    implementation 'com.google.mlkit:object-detection-custom:17.0.2'\n\n    // Face features\n    implementation 'com.google.mlkit:face-detection:16.1.7'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-face-detection:17.1.0'\n\n    // Text features\n    implementation 'com.google.mlkit:text-recognition:16.0.1'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-text-recognition:19.0.1'\n    implementation 'com.google.mlkit:text-recognition-chinese:16.0.1'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-text-recognition-chinese:16.0.1'\n    implementation 'com.google.mlkit:text-recognition-devanagari:16.0.1'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-text-recognition-devanagari:16.0.1'\n    implementation 'com.google.mlkit:text-recognition-japanese:16.0.1'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-text-recognition-japanese:16.0.1'\n    implementation 'com.google.mlkit:text-recognition-korean:16.0.1'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-text-recognition-korean:16.0.1'\n\n    // Image labeling\n    implementation 'com.google.mlkit:image-labeling:17.0.9'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-image-labeling:16.0.8'\n\n    // Image labeling custom\n    implementation 'com.google.mlkit:image-labeling-custom:17.0.3'\n    // Or comment the dependency above and uncomment the dependency below to\n    // use unbundled model that depends on Google Play Services\n    // implementation 'com.google.android.gms:play-services-mlkit-image-labeling-custom:16.0.0-beta5'\n\n    // Pose detection with default models\n    implementation 'com.google.mlkit:pose-detection:18.0.0-beta5'\n    // Pose detection with accurate models\n    implementation 'com.google.mlkit:pose-detection-accurate:18.0.0-beta5'\n\n    // Selfie segmentation\n    implementation 'com.google.mlkit:segmentation-selfie:16.0.0-beta6'\n\n    implementation 'com.google.mlkit:camera:16.0.0-beta3'\n\n    // Face Mesh Detection\n    implementation 'com.google.mlkit:face-mesh-detection:16.0.0-beta3'\n\n    // Subject Segmentation\n    implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1'\n\n    // -------------------------------------------------------\n\n    implementation 'com.google.code.gson:gson:2.8.6'\n    implementation 'com.google.guava:guava:27.1-android'\n\n    // For how to setup gradle dependencies in Android X, see:\n    // https://developer.android.com/training/testing/set-up-project#gradle-dependencies\n    // Core library\n    androidTestImplementation 'androidx.test:core:1.4.0'\n\n    // AndroidJUnitRunner and JUnit Rules\n    androidTestImplementation 'androidx.test:runner:1.4.0'\n    androidTestImplementation 'androidx.test:rules:1.4.0'\n\n    // Assertions\n    androidTestImplementation 'androidx.test.ext:junit:1.1.3'\n\n    // ViewModel and LiveData\n    implementation \"androidx.lifecycle:lifecycle-livedata:2.3.1\"\n    implementation \"androidx.lifecycle:lifecycle-viewmodel:2.3.1\"\n\n    implementation 'androidx.appcompat:appcompat:1.2.0'\n    implementation 'androidx.annotation:annotation:1.2.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'\n\n    // CameraX\n    implementation \"androidx.camera:camera-camera2:1.0.0-SNAPSHOT\"\n    implementation \"androidx.camera:camera-lifecycle:1.0.0-SNAPSHOT\"\n    implementation \"androidx.camera:camera-view:1.0.0-SNAPSHOT\"\n\n    // On Device Machine Learnings\n    implementation \"com.google.android.odml:image:1.0.0-beta1\"\n}\n\nconfigurations {\n    // Resolves dependency conflict caused by some dependencies use\n    // com.google.guava:guava and com.google.guava:listenablefuture together.\n    all*.exclude group: 'com.google.guava', module: 'listenablefuture'\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.google.mlkit.vision.demo\"\n    android:installLocation=\"auto\">\n    <!-- CameraX libraries require minSdkVersion 21, while this quickstart app\n    supports low to 19. Needs to use overrideLibrary to make the merger tool\n    ignore this conflict and import the libraries while keeping the app's lower\n    minSdkVersion value. In code, will check SDK version, before calling CameraX\n    APIs. -->\n    <uses-sdk\n        tools:overrideLibrary=\"\n          androidx.camera.camera2, androidx.camera.core,\n          androidx.camera.view, androidx.camera.lifecycle,\n          com.google.mlkit.vision.segmentation.subject\" />\n\n    <uses-feature android:name=\"android.hardware.camera\"/>\n\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.CAMERA\"/>\n\n    <application\n        android:name=\"androidx.multidex.MultiDexApplication\"\n        android:icon=\"@drawable/logo_mlkit\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/Theme.AppCompat\">\n\n        <meta-data\n            android:name=\"com.google.android.gms.version\"\n            android:value=\"@integer/google_play_services_version\"/>\n\n        <!-- Optional: Add it to automatically download ML model to device after\n          your app is installed.-->\n        <meta-data\n            android:name=\"com.google.mlkit.vision.DEPENDENCIES\"\n            android:value=\"barcode,face,ocr,ocr_chinese,ocr_devanagari,ocr_japanese,ocr_korean,ica,custom_ica,subject_segment\"/>\n\n        <activity\n            android:name=\".EntryChoiceActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/AppTheme\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\".java.ChooserActivity\"\n            android:exported=\"false\">\n        </activity>\n\n        <activity\n            android:name=\".java.LivePreviewActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n\n        <activity\n            android:name=\".java.CameraXLivePreviewActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n\n        <activity\n            android:name=\".java.CameraXSourceDemoActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n\n        <activity\n            android:name=\".java.StillImageActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n\n        <activity\n            android:name=\".kotlin.ChooserActivity\"\n            android:exported=\"false\">\n        </activity>\n\n        <activity\n            android:name=\".kotlin.LivePreviewActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n\n        <activity\n            android:name=\".kotlin.CameraXLivePreviewActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n\n        <activity\n            android:name=\".kotlin.CameraXSourceDemoActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n\n        <activity\n            android:name=\".kotlin.StillImageActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/AppTheme\">\n        </activity>\n\n        <activity\n            android:name=\".preference.SettingsActivity\"\n            android:exported=\"false\"/>\n\n    </application>\n    <queries>\n        <intent>\n            <action android:name=\"android.media.action.IMAGE_CAPTURE\" />\n        </intent>\n    </queries>\n\n</manifest>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/assets/automl/dict.txt",
    "content": "daisy\ndandelion\nroses\nsunflowers\ntulips\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/assets/automl/manifest.json",
    "content": "{\n  \"modelType\": \"IMAGE_LABELING\",\n  \"modelFile\": \"model.tflite\",\n  \"labelsFile\": \"dict.txt\"\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/assets/pose/fitness_pose_samples.csv",
    "content": "Screenshot_2021-02-11_at_12.43.07.png,pushups_up,1251.0012,384.75177,-1716.2709,1273.62,335.6524,-1687.6895,1289.1946,333.0695,-1687.8185,1305.1869,330.30487,-1687.6696,1224.0494,337.55386,-1683.0747,1207.5674,336.34988,-1683.0284,1191.0675,335.42764,-1682.8302,1327.9669,323.61716,-1387.2709,1164.6804,330.69382,-1358.8682,1278.6653,411.4735,-1596.0863,1224.2347,412.6137,-1587.069,1455.528,464.08652,-1138.7732,1037.5433,483.5423,-1115.6373,1612.7382,710.3087,-1251.8538,910.18976,739.30524,-1241.1416,1755.0282,991.45496,-1415.0264,775.6637,1006.5177,-1341.4398,1820.6271,1031.5334,-1491.4453,708.1981,1043.5697,-1394.7319,1788.2871,1038.5012,-1577.3204,740.4979,1046.609,-1488.5742,1745.6206,1035.9231,-1454.9657,783.1702,1041.2338,-1388.9114,1336.4043,799.71106,-7.4530435,1159.9393,802.6842,7.7585444,1311.6213,930.3494,863.83093,1182.4958,950.9533,888.5624,1277.7498,982.67847,1771.1549,1199.3987,983.8659,1808.5101,1267.0542,972.4627,1853.5869,1199.9396,968.99005,1896.0004,1278.4191,1057.8293,1583.9661,1210.4792,1060.416,1639.104\nScreenshot_2021-02-11_at_15.07.26.png,pushups_up,1098.9271,576.2824,-762.4204,1087.8611,549.4343,-816.07367,1094.0004,543.0081,-816.1491,1100.1069,536.4472,-816.327,1074.7643,556.1063,-749.5783,1071.6691,555.3278,-749.6008,1068.85,554.9337,-749.9649,1136.0227,496.65314,-923.8884,1091.2797,522.05676,-619.2933,1145.7218,559.49695,-788.1112,1133.8611,570.698,-697.80115,1381.4792,473.89667,-918.35974,1187.6628,487.63922,-399.286,1544.0657,719.66754,-895.4482,1236.6957,680.5054,-124.2675,1530.57,953.3952,-923.5161,1212.3969,894.8489,-165.0735,1532.7814,1006.6211,-1059.962,1173.9199,926.21497,-217.26468,1483.2753,989.19617,-1058.8033,1172.5128,942.00494,-312.351,1480.5895,971.12506,-933.805,1205.4075,932.07794,-208.9004,1742.3428,554.5395,-188.25949,1643.0712,569.3914,189.07172,1896.1217,642.0162,380.3359,1798.5203,652.5381,738.24805,2044.3694,672.0972,1006.8384,1941.2762,690.89056,1359.9421,2083.6396,656.61646,1058.9032,1979.5259,678.15967,1420.2972,2022.2213,773.026,928.3505,1931.4044,779.48413,1351.5216\nframe__E4JICzRQz1o__0012308.jpg,pushups_up,1241.7229,718.01385,137.62424,1251.704,697.2393,159.6271,1249.6932,693.4431,159.73944,1247.8171,689.86945,159.46976,1253.3268,699.6883,98.76,1253.2173,697.17816,98.78986,1253.0315,694.7735,98.70223,1230.1422,669.2982,254.4538,1238.5756,675.5661,-20.963575,1219.4009,715.6338,179.10297,1221.907,718.04565,98.911385,1102.1088,678.4934,428.9323,1154.6082,703.6722,-170.71446,1111.1611,826.5623,502.46222,1146.0586,851.2305,-252.32294,1135.7562,935.419,436.7794,1156.4379,994.15576,-266.25946,1175.2216,935.8177,478.2634,1197.639,1012.6971,-330.33838,1174.3862,949.0168,415.782,1199.1069,996.2394,-268.47296,1162.1207,954.90546,410.30463,1182.5687,995.4415,-242.7492,856.8169,697.43695,191.58943,875.30743,707.34436,-191.04874,661.776,816.9781,193.53271,669.4051,826.3236,-183.09341,469.73657,908.83093,270.54916,450.63013,927.15015,-130.53868,428.70026,915.6626,270.3628,403.99036,929.9552,-140.34084,477.61523,985.9966,154.54384,464.86215,1018.94,-292.02786\r\nframe__4zBnM_uozXM__0010540.jpg,pushups_up,289.5952,404.92422,-246.61234,265.03235,369.79248,-290.4404,266.88235,360.13873,-290.47543,268.5912,350.07425,-290.95706,262.40228,383.24567,-229.07101,262.34225,383.30835,-229.07455,262.59875,383.69968,-228.89888,297.67438,307.2837,-308.38745,285.63498,350.66287,-34.512375,331.63898,383.8876,-237.04222,328.2526,402.39886,-157.5888,492.1221,339.6821,-421.6161,521.3125,327.6213,303.61877,520.2169,648.4555,-492.0016,557.4331,601.0435,356.7752,500.59955,916.7754,-505.94318,552.9979,845.01227,195.29913,441.6232,948.0762,-615.2863,497.76828,858.578,203.35191,427.763,930.1046,-538.6236,497.1035,865.2389,108.287415,451.54614,918.8821,-482.74023,521.57825,864.6546,151.95038,1017.2738,385.23444,-233.37718,1005.6697,388.93073,233.36322,1347.7319,645.3849,-166.92297,1330.8297,619.8962,228.20352,1687.1592,786.8857,-106.847336,1680.9297,760.55554,330.4695,1773.1525,771.66455,-117.00832,1759.5332,754.8477,330.3595,1628.715,941.31024,-340.81125,1669.7885,926.9267,178.60692\r\nframe__VQKqjHtY8jA__0008583.jpg,pushups_up,1210.3065,594.73303,79.793785,1235.2892,578.0766,88.03166,1234.8342,574.1509,88.25018,1234.5682,570.4159,88.21795,1236.2174,579.48444,27.638441,1237.2148,575.38354,27.592993,1238.131,571.43915,27.323896,1225.7238,539.57184,158.72334,1229.9027,540.70996,-102.53172,1185.4751,581.3817,119.1528,1187.8018,580.8338,42.758873,1070.4565,502.7797,342.63876,1123.8888,538.9835,-250.3364,1019.6261,680.77954,424.12827,1097.9165,729.5013,-347.43512,1010.6292,825.3992,310.54733,1099.7546,912.1109,-293.1823,1038.5884,829.86975,321.40353,1133.6965,928.95435,-344.97617,1045.3608,842.22296,242.97652,1135.9037,915.6801,-288.32025,1034.838,846.07935,275.67267,1120.4689,909.943,-269.28186,744.14777,566.71484,171.49554,752.2864,585.8223,-170.9714,495.12326,699.2147,193.59457,496.6579,718.3127,-122.715065,245.59537,751.78357,305.3821,222.57506,755.9617,-39.932343,197.50374,740.3351,309.54764,169.6585,740.7035,-49.772125,238.60748,842.49915,209.09412,228.39883,863.7497,-192.1911\r\nScreenshot_2021-02-11_at_13.06.10.png,pushups_up,1367.1667,416.55225,-1936.1298,1394.7695,342.73422,-1921.2842,1416.7656,339.0486,-1921.5289,1439.3239,335.18182,-1921.5228,1328.7164,344.78418,-1917.9794,1304.7267,342.31766,-1918.1387,1280.7933,340.19565,-1918.0085,1466.9312,323.05017,-1600.357,1242.938,329.80927,-1586.8878,1407.363,443.69214,-1801.0021,1326.5531,445.42303,-1796.6716,1611.4049,477.85703,-1275.5917,1090.3113,501.65317,-1273.1238,1758.339,828.2396,-1366.0763,942.1921,847.3107,-1406.1226,1913.1932,1177.3766,-1588.8081,773.2278,1168.2847,-1599.7666,1983.9305,1232.4519,-1686.5817,686.7701,1211.0406,-1669.1115,1947.0636,1239.2158,-1765.1934,709.7965,1216.9042,-1773.8555,1897.4364,1224.6165,-1633.4037,764.54333,1206.9203,-1658.8203,1446.249,792.1886,29.993492,1225.7096,798.89233,-28.779037,1446.3374,984.9459,847.7625,1204.1018,986.3562,810.7144,1395.7848,1087.2004,1693.6763,1182.8365,1102.0084,1733.7233,1367.2874,1073.9264,1773.458,1180.7911,1093.5526,1821.1682,1433.8257,1224.5051,1540.3788,1179.513,1228.6138,1574.1444\nframe__PAG4Q_gXmpg__0018088.jpg,pushups_up,1259.1696,763.86847,89.206726,1272.9102,745.1841,112.67859,1272.1553,740.9394,112.925,1271.4989,736.78436,112.87882,1273.0253,748.3505,46.70641,1272.7456,746.01953,46.71307,1272.4498,743.75525,46.5327,1260.5475,711.492,222.07076,1262.5562,722.1312,-76.34596,1240.7637,755.91376,140.04631,1241.2186,759.3456,53.44471,1146.8793,677.0607,414.73456,1187.8263,743.27716,-233.45383,1113.7565,801.505,497.69635,1155.7739,889.7973,-349.03738,1130.8777,900.6492,321.83856,1168.1104,1007.46234,-306.4686,1158.9977,902.4525,345.79764,1198.9199,1021.3957,-370.72943,1163.4009,913.98145,270.52994,1198.6677,1005.5813,-306.42245,1154.0996,919.8916,287.8756,1184.9244,1000.42285,-279.0884,903.36536,752.31165,198.14021,913.1226,787.11926,-197.75215,754.6481,853.61383,258.01495,744.9766,861.2182,-139.02872,555.20807,871.61066,365.5044,535.4632,901.1726,-55.808914,515.2168,858.0402,372.5147,492.26944,889.2877,-56.030125,554.0522,936.1522,312.9383,538.3515,967.586,-156.0695\r\nframe__6rh6pVGTqRU__0013371.jpg,pushups_up,464.95108,663.9835,-102.85829,443.33847,644.93976,-160.07025,443.54376,642.0576,-160.02127,443.8188,638.80634,-160.58704,443.60306,641.6044,-103.0884,444.15567,636.6268,-103.064514,445.06393,631.7677,-102.6096,457.85364,610.76605,-257.11658,458.51233,603.0254,10.922813,489.8275,657.6413,-127.088486,490.03726,654.26794,-50.20222,574.2174,636.9874,-376.14334,628.6282,588.08246,263.53748,589.92175,838.09955,-426.98572,650.82935,758.6232,347.3356,597.6218,1020.4291,-383.09592,649.6339,895.3764,170.73773,541.87463,1032.4279,-455.26917,602.17773,876.8676,178.50298,540.5927,1008.85645,-370.66946,595.50586,892.7864,92.76913,562.8502,1007.5328,-350.27917,611.2105,906.7849,132.28778,918.734,669.30676,-185.08414,908.0617,648.4788,185.29684,1163.5641,811.01904,-179.49944,883.5595,758.50867,404.78232,1405.5724,903.5936,-124.856544,1045.0944,833.391,636.02325,1460.2959,908.62463,-127.91333,1080.4424,835.3074,651.3967,1366.7441,973.8489,-276.76456,1054.016,888.2045,621.5303\r\nframe__topJ0ianBlQ__0008994.jpg,pushups_up,1336.0172,769.80493,-19.5128,1351.8081,756.2779,2.0053391,1352.0059,753.31024,2.1488016,1352.3081,750.5547,2.1273515,1350.2971,755.90466,-61.51667,1350.1404,752.08246,-61.533207,1349.8904,748.3904,-61.573883,1347.8954,726.16583,111.1865,1345.1902,723.7768,-173.46501,1322.4076,760.2762,29.426014,1321.5765,758.9035,-53.074375,1248.1991,692.20776,316.38644,1278.8217,719.2821,-310.55054,1207.3708,805.8077,377.95187,1256.6978,833.00854,-406.63043,1207.1078,898.91614,191.21614,1254.4537,955.3333,-413.2485,1241.4086,893.51605,212.67691,1287.2903,963.1322,-484.03833,1246.784,909.888,130.09988,1291.282,951.8711,-416.4837,1236.0361,916.78546,151.29193,1279.4778,950.3853,-386.65872,1061.622,723.29614,187.72545,1064.9803,744.6416,-187.26952,918.75726,808.52234,219.17026,911.7872,825.6765,-163.4177,763.1162,851.37244,322.62143,735.6291,880.15356,-83.03089,728.3172,851.5841,328.98285,694.9928,878.1968,-90.90696,776.3402,923.48315,242.69122,756.8386,957.4989,-236.277\r\nframe__itlms4_050o__0012129.jpg,pushups_up,276.29895,399.2901,-0.6539844,262.60614,390.3001,-32.47749,262.32233,388.27148,-32.54988,261.9877,385.9894,-32.677532,262.69397,389.6878,7.6968913,262.61487,387.45566,7.7057366,262.7428,385.23865,7.775421,265.18518,371.3463,-103.7716,266.29095,370.2698,82.53974,288.93158,394.71524,-17.685274,288.93924,394.0289,36.292004,324.87076,378.51758,-192.7967,360.58185,353.79602,245.27817,350.00095,497.05008,-222.5621,399.73984,454.30887,298.58105,356.4361,602.7099,-154.5784,404.51718,537.4307,179.64944,328.2602,615.6203,-192.73456,379.62622,533.55585,192.57683,324.96518,603.99994,-146.3372,372.44147,545.07227,145.60779,336.6053,599.3701,-134.37383,380.15018,550.6015,158.27461,545.7458,393.67227,-137.37265,557.66504,378.00998,137.37326,685.2756,485.55145,-111.618835,675.98206,469.62653,243.97348,833.3264,553.6079,-73.82055,805.4143,515.11035,402.29944,867.9312,551.5234,-75.32933,834.74866,511.91458,414.6719,816.49414,615.54913,-174.56375,805.8739,567.9511,355.78888\r\nScreenshot_2021-02-11_at_12.53.02.png,pushups_up,1063.1144,477.1623,-1193.1283,1081.5219,436.327,-1211.6455,1094.1903,431.97977,-1211.8003,1107.2648,427.4987,-1211.9443,1040.0991,438.21707,-1207.3699,1026.8331,435.32858,-1207.3674,1013.6604,432.86295,-1207.3451,1132.946,387.57733,-1063.9584,995.3494,393.09415,-1038.48,1087.5957,469.97162,-1114.6329,1048.502,472.1567,-1107.9573,1252.7136,401.59354,-809.1426,910.46295,414.7719,-790.6253,1328.3856,612.12885,-728.82684,852.5713,632.4972,-774.8171,1404.454,852.6298,-763.9575,788.79834,856.8904,-796.3179,1449.4498,884.16595,-800.0977,749.7777,884.06775,-829.1809,1428.1764,892.75256,-853.8235,772.332,896.1262,-877.5242,1397.2504,887.27905,-786.32294,803.08484,890.20184,-820.1092,1164.1631,493.31146,7.68702,1012.5405,499.79453,-8.237566,1148.2179,603.6718,597.13464,1038.1877,605.59235,592.77545,1127.4198,633.39844,1210.0106,1068.9012,641.7286,1231.7283,1122.3994,620.13824,1273.5737,1075.3035,626.21423,1296.9927,1117.6368,716.6216,1148.5266,1082.688,726.60944,1166.363\nScreenshot_2021-02-11_at_15.13.55.png,pushups_up,1088.2405,354.0208,-1472.3417,1107.8846,292.7349,-1474.3854,1125.9365,286.27316,-1474.6866,1144.0613,279.55225,-1474.9224,1063.1477,304.98517,-1417.6552,1049.5284,306.92435,-1417.5758,1035.7025,309.3992,-1417.5107,1198.3387,259.84888,-1317.3502,1052.3192,299.74493,-1067.1534,1147.2089,370.36285,-1405.0021,1094.5114,386.80817,-1332.9152,1446.8643,400.86368,-1236.3477,1079.3204,424.74008,-784.2808,1593.6318,752.8741,-1329.4071,1084.9069,726.52,-666.5621,1640.9456,1091.7627,-1409.5692,1059.7285,1039.8815,-702.48334,1679.6354,1159.1979,-1552.4955,1011.9049,1091.974,-714.47046,1624.6388,1162.6978,-1577.057,1028.6903,1100.1779,-822.80493,1602.8478,1140.92,-1425.3618,1073.3417,1087.6825,-749.53186,1614.0243,722.294,-167.50375,1440.9066,727.8789,169.23862,1743.621,827.4502,621.9804,1525.3988,830.09717,1002.3771,1828.0671,876.76746,1392.1904,1628.425,860.33276,1795.3561,1853.2197,871.8473,1462.0225,1661.3748,854.8757,1874.3038,1797.0885,967.01373,1288.2849,1585.7758,945.291,1779.1641\nframe__eJBEYNKJ2Mo__0011475.jpg,pushups_up,2515.9858,1381.9958,258.1463,2554.9558,1355.2545,299.2597,2555.4248,1347.192,299.3816,2556.0757,1339.5303,298.89648,2553.5364,1359.4613,168.4626,2554.7456,1353.6676,168.46764,2555.8484,1348.11,168.27946,2545.7334,1288.4993,484.85858,2548.7676,1300.7986,-101.4662,2483.5012,1360.2863,344.75198,2483.8784,1364.24,173.34282,2311.7632,1207.8978,854.69025,2389.1064,1302.1737,-385.46826,2242.0125,1498.8246,985.2434,2322.499,1586.4259,-545.11426,2255.5671,1717.9104,703.5237,2326.668,1860.6696,-503.1559,2327.8843,1730.2916,766.1591,2405.0225,1902.2361,-625.2498,2327.9963,1757.3143,625.3689,2411.2373,1869.7722,-490.95166,2304.9834,1765.401,640.9782,2379.162,1863.97,-450.29507,1809.631,1208.0211,385.22656,1828.1938,1248.6827,-384.17725,1399.529,1429.481,411.68015,1421.9556,1464.6836,-306.91928,993.7185,1592.5276,588.3452,963.1817,1648.9792,-134.20975,908.96814,1596.5278,588.3723,869.07117,1645.0024,-145.56926,1005.9397,1754.2205,335.76657,981.79755,1838.6866,-446.30142\r\nframe__48tN82L4nD0__0001821.jpg,pushups_up,2419.001,1521.3947,197.76236,2451.5415,1496.0463,238.10042,2451.6624,1488.8328,238.17766,2451.9255,1481.8304,237.90756,2450.2834,1499.6882,122.85478,2451.0144,1494.5459,122.864395,2451.668,1489.6365,122.72219,2439.3206,1439.8236,397.8424,2441.599,1449.8582,-118.98399,2389.156,1504.4438,272.5424,2389.418,1507.1871,121.31324,2218.5696,1375.534,736.58405,2295.1074,1458.8522,-375.35797,2132.2476,1632.7997,834.0138,2220.9072,1693.2205,-518.29877,2133.97,1819.728,537.1905,2205.9697,1939.933,-455.283,2206.9377,1816.8159,585.36786,2279.9954,1968.7618,-558.165,2212.0618,1847.7063,453.2848,2282.4517,1937.921,-428.17352,2189.7478,1860.0505,475.66443,2254.436,1933.9224,-401.6377,1783.2994,1403.9854,333.19876,1803.3696,1447.9064,-332.51703,1452.4465,1591.8569,451.5992,1461.9277,1600.5015,-212.66942,1113.0986,1700.1423,682.99316,1074.9,1730.9729,23.639706,1046.6512,1699.4989,694.45465,1000.9584,1729.0016,17.358824,1118.8246,1834.523,507.2317,1085.4312,1882.9934,-244.7333\r\nframe__bleOTMDa3_4__0009809.jpg,pushups_up,1428.2522,743.1719,113.01568,1437.8362,726.5844,135.3643,1435.697,723.08734,135.4846,1433.6831,719.8103,135.32114,1440.4465,728.926,75.67144,1440.7974,726.7622,75.653755,1441.061,724.6788,75.57514,1417.8385,701.0419,224.23462,1429.0228,707.47876,-45.998516,1407.6287,738.80615,151.75693,1411.3545,741.12305,72.92379,1308.9963,707.4041,380.78146,1351.9062,718.77313,-184.54283,1337.2589,844.80994,451.35645,1359.9194,845.8971,-279.7615,1357.4594,940.45514,317.52362,1390.1957,955.5002,-267.53906,1386.5166,944.4581,337.9306,1428.8282,967.5488,-328.74936,1385.2615,949.02515,276.07245,1429.0709,953.3218,-270.72824,1376.2878,951.1747,288.31534,1414.2117,954.41394,-246.73965,1090.4067,703.3572,184.88849,1106.2399,705.3284,-184.36111,941.73114,812.3094,207.00589,949.5099,805.84375,-152.92087,794.3257,898.07904,306.23276,778.7145,901.28613,-69.29542,761.1863,902.968,307.2421,742.57965,904.7448,-73.05799,806.56995,963.52246,200.1218,793.1409,973.07477,-209.41414\r\nframe__hglfthV89Zk__0001579.jpg,pushups_up,1298.1904,513.12775,-950.4193,1313.9342,484.35715,-940.19543,1317.2292,484.88968,-939.96436,1320.8538,486.01715,-939.9863,1297.4888,475.7325,-979.2925,1289.4302,468.95996,-979.5864,1281.1791,462.3357,-979.81555,1299.2006,468.74234,-758.94464,1248.6542,435.4494,-933.10815,1275.5613,524.6898,-865.7032,1259.328,512.2584,-916.34845,1262.9022,503.91995,-496.5774,1065.9342,482.96054,-870.1654,1295.3938,687.8579,-282.74365,985.35596,708.2613,-936.25836,1304.1173,867.982,-349.05908,1013.1996,906.6002,-1005.4889,1337.271,894.1952,-413.39868,1022.3716,941.68774,-1135.0161,1322.6112,896.3855,-498.02423,1058.9146,924.9695,-1133.8779,1292.0356,889.9384,-385.7191,1055.9963,917.1511,-1016.3347,960.9938,585.615,140.37389,870.766,561.87933,-140.12512,806.52167,672.324,591.26044,747.715,634.22253,382.9337,660.6418,667.72034,1200.9126,621.2121,677.95825,950.76355,631.3079,650.1302,1257.3776,591.41003,666.58167,1000.2727,637.1966,742.1089,1169.457,611.4654,766.6369,875.6612\r\nframe___7i9ao_ajKw__0010609.jpg,pushups_up,1496.0054,609.1245,55.528927,1519.8192,592.87805,69.46528,1518.8466,588.866,69.67461,1518.0693,585.0822,69.51524,1521.4307,592.79755,-1.6429552,1522.9429,587.88446,-1.666755,1524.3247,583.1155,-1.797988,1506.9062,552.9895,160.1825,1515.6775,548.97815,-158.78418,1468.7904,595.5666,100.42188,1472.6885,593.6527,7.5511365,1342.744,535.4856,369.13226,1397.4019,535.62726,-314.96692,1302.7448,715.779,491.2076,1394.8721,750.0507,-422.90393,1313.7065,856.5426,372.87656,1427.7983,936.3036,-415.00055,1350.0988,860.7513,394.3592,1472.6992,958.0703,-492.81372,1355.1251,877.8584,309.84583,1473.7756,938.2024,-436.75848,1342.2191,881.21576,335.51007,1455.8207,934.9836,-393.6198,1004.4475,570.6577,208.7994,1007.29315,561.07855,-208.10866,753.1175,717.8996,255.74847,739.109,691.6403,-164.87341,512.1189,807.908,408.07053,451.0865,797.3155,-43.530907,463.83368,801.28436,412.07306,397.1838,793.2222,-55.8445,497.7407,918.2755,263.83105,439.16583,916.3312,-253.02733\r\nframe__phPxIeAloOk__0004026.jpg,pushups_up,467.54675,593.79456,-204.04309,456.25443,568.75726,-245.24751,458.3492,564.08484,-245.23793,460.2792,559.12585,-245.37405,455.06223,572.5253,-178.43747,456.3081,570.9317,-178.44498,457.89,569.4593,-178.47136,486.94833,534.0118,-299.47034,482.00848,548.2871,0.7912063,498.96097,588.48334,-214.59517,497.3463,594.0699,-127.492676,630.42645,567.45905,-434.4526,652.2285,548.41656,273.5645,628.53735,795.9314,-542.25415,676.9654,751.63043,291.19885,634.48724,984.67505,-564.69336,668.2732,919.14417,110.146576,589.20575,1011.14014,-678.25635,617.76904,923.4566,110.64719,586.07874,992.4455,-600.0796,617.6793,933.42816,16.424774,604.1676,983.20374,-541.4933,637.47723,936.1634,64.911255,1021.07153,557.25494,-227.3927,1009.91235,554.4241,227.67746,1281.3785,729.9604,-131.34047,1265.1448,722.93585,225.6239,1542.0537,839.5587,-22.482111,1520.0989,832.51575,378.3544,1599.0555,826.9703,-20.660837,1571.9838,828.47424,386.33096,1519.8752,956.17633,-215.2329,1530.1549,940.7214,224.94049\r\nframe__hnCg8x3xi8M__0009235.jpg,pushups_up,679.99963,679.05676,15.00044,661.05066,663.57263,-28.644297,661.33905,660.59106,-28.765999,661.56,657.2373,-29.016888,660.1351,662.5564,32.1752,659.9652,658.4852,32.232487,660.0564,654.4836,32.329395,672.8758,630.8795,-130.85344,669.28644,629.1207,146.41086,703.0015,670.5834,-13.151141,702.24927,669.0802,66.96219,786.30804,625.23395,-295.81445,822.40985,612.43475,369.8961,821.75366,803.7638,-393.12695,862.6069,787.1485,415.18222,842.0828,967.4929,-355.68744,861.53156,939.5741,232.06775,807.83374,987.5498,-431.6287,823.34015,946.4465,240.29317,802.9664,973.88074,-366.16776,815.54834,954.9357,160.48752,816.4641,966.73334,-331.85953,828.7856,958.2974,191.75365,1113.7876,647.9035,-209.0296,1119.8219,643.0695,209.2399,1350.9658,760.1918,-146.56824,1347.5055,763.5475,215.55896,1601.7902,855.50323,-67.96436,1584.0642,845.55426,316.69562,1653.9954,849.0987,-69.95628,1635.0623,842.4201,319.89816,1589.3262,948.36035,-231.99594,1580.6461,936.7949,187.85086\r\nScreenshot_2021-02-11_at_12.11.49.png,pushups_up,1103.1969,748.6544,-1300.9362,1108.8228,713.9464,-1328.9448,1118.6791,707.97406,-1329.2096,1128.6655,701.82153,-1329.2478,1075.1488,724.4426,-1311.9625,1063.3937,725.2412,-1311.7125,1051.5237,726.3357,-1311.936,1136.9922,660.8051,-1201.4316,1022.40735,700.16504,-1115.5673,1120.3484,744.6246,-1226.5427,1091.7311,754.0554,-1201.5032,1251.1299,672.8422,-992.56854,961.9839,716.0927,-840.07214,1322.6516,885.1771,-971.64557,989.5073,894.58984,-640.0531,1273.2463,1087.5375,-1093.6213,1049.8804,1095.8108,-705.09106,1273.2018,1134.3125,-1207.1277,1036.0754,1134.0836,-749.6462,1241.3107,1119.2584,-1227.5721,1060.2648,1130.4263,-804.80884,1233.6812,1104.9552,-1107.2828,1079.5095,1115.2031,-726.37897,1260.526,872.63763,-85.985016,1127.4939,894.84534,86.500015,1305.9492,954.6649,573.74445,1189.1661,973.39984,779.4967,1327.6202,973.04095,1308.1265,1228.8342,975.2557,1571.833,1331.4774,967.6417,1376.0664,1243.6569,969.27826,1652.5226,1334.2103,1037.3433,1213.2499,1233.3511,1025.561,1507.9142\nframe__mqwXyeCnkMI__0006613.jpg,pushups_up,1065.5759,668.3544,171.78098,1079.8693,652.82166,191.4184,1078.5497,648.9944,191.57863,1077.366,645.2784,191.44382,1081.833,655.7086,130.66754,1082.518,653.3966,130.70668,1083.163,651.119,130.65288,1068.3049,620.40234,280.02435,1076.4739,628.9127,6.338744,1047.4016,658.5733,212.385,1050.5707,661.66016,132.78722,956.41516,592.2414,443.27994,1009.0732,629.0033,-146.31317,925.55176,723.94214,536.58905,992.9914,768.306,-253.18938,935.2166,828.1052,450.94476,1001.71545,893.8056,-230.06514,967.6533,829.86176,484.37982,1038.0455,908.6797,-281.0103,968.8441,841.95154,420.20004,1038.7643,892.8243,-220.59729,956.4142,846.14386,423.34158,1023.20483,890.0795,-204.05623,735.57874,615.2127,179.48555,751.70374,636.91345,-178.96068,589.2189,735.47894,239.15753,591.4599,767.6611,-200.20784,418.76648,800.18195,304.2512,385.70856,814.94763,-229.89095,379.2566,801.559,307.22922,339.34604,806.5385,-243.27802,433.41132,864.0832,242.63318,402.80795,896.88617,-344.9314\r\nScreenshot_2021-02-11_at_13.04.20.png,pushups_up,1366.4076,373.24258,-1801.4269,1392.1041,303.50537,-1780.496,1413.2234,299.9046,-1780.7528,1434.939,296.1314,-1780.6722,1328.1128,305.5733,-1783.9294,1304.5858,303.33334,-1784.0674,1281.0729,301.4212,-1783.8684,1458.2188,287.7329,-1467.0829,1241.6553,294.80133,-1472.8712,1404.0327,401.8713,-1671.7919,1325.2941,403.721,-1673.1191,1589.9891,453.90866,-1187.0049,1093.6466,482.85156,-1184.686,1731.6459,802.50507,-1301.9454,947.8469,846.46576,-1342.1283,1889.2699,1167.3795,-1495.3857,773.6293,1164.0172,-1492.0219,1962.045,1228.2917,-1587.4982,689.67224,1203.3336,-1541.7783,1923.5325,1234.7279,-1669.1038,707.6087,1207.247,-1644.0319,1875.6179,1217.4135,-1542.0829,759.7208,1197.0366,-1547.6313,1440.964,764.0963,20.554081,1230.9235,775.4928,-19.95484,1448.8488,963.18225,750.9082,1217.4757,980.625,772.0113,1404.0814,1071.1525,1569.8483,1195.252,1091.2706,1683.3518,1378.7772,1059.289,1646.9182,1193.7957,1085.4402,1771.346,1426.6631,1206.8456,1420.1223,1186.8263,1210.3412,1537.8088\nframe__r_W49tWhVys__0025911.jpg,pushups_up,517.3644,642.5125,-391.45563,507.56738,612.9703,-402.79083,512.0031,605.5533,-402.66754,516.39355,597.91974,-402.58945,497.97415,626.9695,-355.9269,495.26996,629.7787,-355.9586,492.73773,632.86566,-356.03607,541.381,577.19434,-344.25867,508.34088,620.44165,-138.33922,550.79315,632.82495,-364.10446,537.76324,652.53094,-304.21863,665.1318,643.51904,-467.17435,635.24506,647.8327,153.95218,684.77185,853.2056,-564.0,637.5676,827.06104,144.89702,661.8696,1024.4813,-598.55554,611.8577,981.33624,-61.278435,636.7138,1043.8813,-703.9627,578.2805,995.9824,-83.632614,622.0682,1035.0591,-657.14667,581.5926,995.19965,-167.55605,634.2875,1025.3256,-587.30035,597.5911,991.5648,-106.00316,966.5116,735.3157,-192.95654,945.5798,748.5436,192.96802,1177.1409,858.8023,-191.71268,1151.0172,856.50244,170.93936,1408.6937,939.4172,-127.991684,1382.0497,917.8455,293.8208,1467.2628,936.0157,-138.06181,1433.534,921.0042,294.62427,1364.674,1031.1881,-333.82074,1353.2053,996.81384,151.66476\r\nframe__ihCpHCvZ4Ok__0008474.jpg,pushups_up,512.4848,663.1821,-94.81791,488.01184,648.3613,-150.89165,487.60843,643.724,-150.83347,487.1627,638.6989,-151.04027,487.57022,648.7402,-78.64003,487.03976,644.86615,-78.521194,486.95004,641.0778,-78.49725,497.02045,600.7277,-275.15256,495.7315,605.9356,56.470745,538.6087,644.1625,-130.70038,538.4274,645.1803,-34.761707,629.4678,567.5585,-438.9236,639.4121,572.43726,286.3781,588.3916,777.4311,-619.25,617.6731,748.2319,374.97437,545.9107,948.28345,-626.6725,582.0546,880.6674,192.0297,492.47766,971.05896,-724.2917,532.4492,885.271,184.11542,490.71317,953.74146,-661.2091,529.5232,887.20886,105.367714,511.58597,947.7377,-607.7182,548.4,888.83856,149.10115,1009.6128,575.78613,-217.88464,1001.2761,589.09674,218.1583,1253.3224,715.1843,-164.09749,1233.0156,723.62384,292.91345,1504.7268,824.83264,-77.50981,1462.7485,783.89154,464.96445,1557.3005,822.57806,-77.46829,1507.635,777.24365,475.06784,1506.3574,927.3869,-241.04831,1490.462,867.8571,346.6548\r\nScreenshot_2021-02-11_at_11.36.25.png,pushups_up,1249.9421,683.82935,-1271.9507,1268.1799,651.5085,-1261.2915,1279.835,650.1358,-1261.3357,1291.6821,648.6835,-1261.1257,1232.6252,650.9935,-1262.5233,1220.785,649.03613,-1262.4456,1208.8715,647.2862,-1262.2439,1309.1545,644.127,-1061.4855,1190.8163,641.529,-1055.7416,1269.3655,701.1984,-1186.6533,1230.2131,699.8736,-1185.0713,1372.1672,736.1978,-835.1706,1128.5706,740.5315,-852.0832,1408.7941,927.0196,-820.22217,1112.3658,943.91864,-876.22705,1457.62,1106.8853,-884.0109,1090.9337,1128.4652,-936.35486,1485.3629,1131.138,-949.4171,1068.2195,1153.5441,-987.1041,1462.5288,1133.931,-986.809,1092.6633,1158.86,-1025.0171,1444.0612,1128.6387,-905.8949,1111.4806,1151.5494,-955.3012,1308.9578,876.92267,-10.276127,1211.634,875.77747,9.401738,1306.711,985.13104,562.1053,1233.7158,982.471,561.73676,1294.7424,1042.2946,1215.5417,1253.4856,1037.8531,1200.3954,1289.504,1037.4913,1277.2993,1262.5134,1036.6667,1264.4847,1288.3572,1105.11,1092.1589,1243.8414,1096.5548,1080.4205\nframe__ptsTT-pDWcA__0016622.jpg,pushups_up,1424.2599,524.62616,57.57229,1446.3381,504.19763,71.52858,1446.1587,499.93707,71.80775,1446.0974,495.87033,71.84844,1446.3075,506.5408,5.5218544,1447.0375,503.48157,5.542561,1447.6659,500.5623,4.99476,1437.9426,466.21994,161.3244,1439.6327,471.0611,-138.9314,1400.9258,512.63434,107.06372,1401.8998,514.2113,19.691544,1283.9521,448.3881,349.10532,1351.5372,489.7021,-262.63486,1246.3445,625.18866,493.27847,1354.4119,689.3905,-304.3169,1257.2189,744.41296,422.53214,1385.7047,861.14343,-199.3068,1288.3336,738.2537,444.08078,1427.546,881.3099,-243.26085,1300.2123,759.102,360.61414,1431.6742,869.6582,-179.64978,1287.8069,770.7544,393.19952,1410.9109,865.7895,-166.96187,950.5107,529.6914,192.9125,950.6005,550.6077,-192.39377,825.2093,694.56323,401.52716,723.84985,704.0733,-125.123764,619.3727,682.5116,713.78687,446.94168,764.4282,-77.65593,580.91693,655.00006,740.0022,397.39563,747.39606,-72.56216,585.18097,730.36505,754.2902,418.87424,826.3801,-132.69199\r\nScreenshot_2021-02-11_at_12.47.46.png,pushups_up,1195.907,610.4619,-1805.2611,1235.3099,523.5618,-1847.2804,1263.3209,516.9183,-1847.232,1291.7162,509.90976,-1846.9778,1154.2493,527.33594,-1829.1011,1126.0999,522.46014,-1829.0785,1098.2676,518.0297,-1829.2887,1344.1648,463.64838,-1614.5726,1063.0688,474.0466,-1536.6542,1246.6359,629.97974,-1680.355,1161.5718,632.0749,-1657.2399,1496.0817,528.28534,-1222.7993,958.59924,561.46704,-1145.1609,1584.4785,797.614,-952.4208,865.82715,812.7534,-933.19696,1599.6641,1153.1696,-1123.2086,841.2804,1139.623,-1175.2053,1647.6824,1221.5023,-1270.0658,784.6562,1202.922,-1335.4476,1575.59,1234.5419,-1331.7607,856.5014,1207.6698,-1425.8873,1537.2686,1210.0422,-1157.744,899.94653,1183.6586,-1233.3218,1352.2065,848.48346,-3.1212945,1124.6132,874.26276,4.0849104,1333.1278,880.7916,885.0031,1154.563,898.93964,910.3805,1329.6199,837.7707,1807.2644,1190.9415,856.1827,1954.2236,1315.8877,807.5739,1913.4645,1206.4458,822.3275,2068.5474,1329.6407,920.4456,1825.3785,1213.569,927.0009,1996.8319\nframe__hKw1Xjw0-So__0001566.jpg,pushups_up,1191.8674,768.0845,-799.3096,1201.1543,743.8181,-776.55786,1201.2894,741.8637,-776.4542,1201.5282,740.366,-776.4061,1193.6927,741.0749,-835.78894,1189.4177,736.4614,-836.06146,1185.0032,731.9887,-836.45654,1181.562,712.69617,-582.62445,1161.322,701.39325,-853.4246,1167.7096,763.2679,-717.2335,1162.29,761.05927,-795.327,1132.818,716.73114,-359.1993,1010.68945,709.52203,-827.281,1120.4713,839.9879,-184.26428,950.9183,893.6773,-902.1615,1122.608,966.662,-236.98888,976.35736,1045.5109,-993.6753,1154.1333,982.051,-283.7936,991.91296,1077.3988,-1117.7928,1149.6654,984.49066,-360.31165,1023.69324,1062.3528,-1104.8154,1127.923,978.3524,-270.79614,1017.01605,1054.6514,-998.5276,871.2181,710.16736,153.94263,803.2658,691.06616,-153.63118,751.4748,799.049,549.5309,701.853,767.5733,263.48898,651.0293,805.9378,1049.8972,594.98676,808.36664,731.00073,626.4618,791.5504,1096.6346,568.659,795.3678,770.5095,649.9111,884.41174,1005.58374,598.5677,892.3536,635.5079\r\nframe__CI3o5FYbtOo__0003320.jpg,pushups_up,449.5529,533.416,-20.78604,435.19748,509.66617,-66.19948,437.03503,506.26453,-66.450165,438.75693,502.52292,-66.85152,433.55627,509.26883,-4.5668697,434.2617,505.47852,-4.4712696,435.30063,501.74567,-4.0008464,460.35742,481.59534,-155.50058,454.1716,480.7035,127.508095,478.09073,533.82605,-41.289757,475.60245,533.3473,40.625587,577.97125,528.4763,-289.5906,625.72217,484.7344,391.05658,550.94196,730.8909,-397.95938,636.5832,671.717,474.31766,546.24756,901.75256,-359.98026,619.691,818.87286,289.72626,499.5955,920.87573,-442.5497,575.2438,815.6767,302.5619,499.69183,899.03815,-370.736,568.7227,828.1413,221.57193,518.783,893.6933,-335.00635,584.72,836.9508,251.33589,953.42236,549.15186,-220.97923,962.4123,527.80853,221.21509,1220.783,703.7775,-253.19746,1182.2365,686.58856,351.83066,1511.4849,815.78436,-254.52841,1432.6477,777.69495,565.3883,1578.1941,813.9631,-269.65564,1493.3607,774.7244,581.49207,1469.6947,930.4493,-472.76044,1406.6516,889.127,470.77908\r\nScreenshot_2021-02-11_at_11.35.26.png,pushups_up,1276.5773,704.3511,-1266.1062,1285.6688,674.4146,-1253.9801,1294.3884,672.6796,-1254.1688,1303.3322,670.8262,-1254.2671,1258.1306,675.693,-1255.0267,1248.0775,674.6557,-1254.7585,1237.973,673.76324,-1254.4694,1310.0944,663.74615,-1055.9827,1218.5494,668.0333,-1057.523,1289.5277,717.30743,-1180.895,1257.7334,717.84485,-1180.7197,1374.8047,752.12897,-889.63184,1149.9937,752.7529,-837.04926,1440.7805,935.12836,-940.63666,1124.0349,937.3518,-851.50934,1487.4781,1100.589,-1014.75433,1092.6699,1111.9435,-925.0816,1511.8789,1130.5692,-1100.7482,1069.4431,1145.9666,-984.462,1486.9738,1131.1523,-1130.8553,1092.4827,1144.421,-1033.8702,1471.6099,1123.3109,-1033.9952,1109.702,1136.1309,-949.6367,1308.9812,913.0141,-33.960163,1217.1771,913.95605,33.929016,1305.2332,1000.5934,622.3294,1234.9019,1004.8973,645.8112,1308.0435,1026.6204,1310.8325,1249.8737,1033.1868,1327.4161,1307.2059,1020.96454,1377.9012,1255.7977,1028.8002,1393.8901,1304.0758,1079.115,1211.0703,1244.3748,1083.9222,1229.6779\nframe__1Benc0pfoFE__0003086.jpg,pushups_up,610.671,758.0609,139.41068,594.8548,744.4192,96.08273,594.25305,741.135,95.95122,593.5603,737.6099,95.79448,596.7772,745.4892,156.23485,597.86456,742.51666,156.16844,599.1179,739.67664,156.08978,600.9818,718.0923,-16.319239,607.0207,722.7425,258.16394,625.62616,752.57477,104.27001,628.0407,753.2925,184.30766,671.5923,737.81616,-182.96666,720.90405,721.62067,411.1104,699.1885,900.62634,-283.44962,757.16986,876.92017,447.83057,714.99133,1036.9874,-317.21805,753.69666,1006.8559,328.5181,683.6498,1052.5995,-391.55862,721.0322,1011.1261,359.8731,680.0992,1036.8148,-324.7544,716.3815,1018.4574,292.6325,690.8546,1031.4845,-294.75894,724.36,1022.2753,298.06775,942.8774,772.84894,-195.26276,957.8766,770.014,195.42386,1161.6876,872.3797,-224.57898,1152.4635,881.537,157.30159,1392.0839,948.74524,-233.14688,1370.1571,948.0089,231.7806,1438.6013,945.07263,-245.97708,1416.5631,949.43884,230.67154,1377.9097,1022.8828,-419.33685,1362.1964,1022.6798,97.827034\r\nframe__zCwaivZALos__0006587.jpg,pushups_up,1261.4706,658.6275,35.32896,1281.5905,643.1001,46.75888,1281.6404,637.7607,47.023754,1281.6869,632.5485,47.137245,1278.7932,647.3588,-16.92499,1278.3285,645.1767,-17.045597,1277.7871,643.0952,-17.307493,1268.517,604.594,112.64807,1265.2904,619.0518,-177.08833,1238.8976,645.8849,73.59249,1237.9517,650.4146,-11.197186,1127.6381,558.5184,328.16113,1146.9397,629.1106,-298.5129,1122.6285,747.7509,385.77917,1101.3333,817.1275,-306.7322,1133.4954,884.5552,198.8678,1102.3782,984.83734,-206.41254,1189.6373,876.5035,201.94658,1162.4146,1008.9739,-255.28499,1185.6399,893.04504,116.5844,1169.3994,982.30457,-167.69234,1165.4036,906.57214,159.6872,1146.3369,976.725,-165.25577,797.3166,567.0805,184.08325,799.6173,610.45844,-183.9205,609.5683,713.3814,399.22192,588.2729,747.5341,-31.177654,408.74216,801.1272,594.95166,342.52664,842.5047,122.037994,357.99963,804.13367,612.3652,286.10837,842.27313,125.66291,432.6629,880.57794,572.0365,372.06354,929.68304,36.889515\r\nScreenshot_2021-02-11_at_12.59.19.png,pushups_up,1191.9241,509.65927,-1763.5211,1224.5084,429.73807,-1785.0336,1250.3931,425.15692,-1785.1907,1276.7832,420.362,-1784.865,1148.3094,430.21515,-1780.9534,1120.9867,425.762,-1781.0845,1093.8151,421.67984,-1781.2091,1315.4747,386.7348,-1541.5393,1053.6925,387.8133,-1510.6283,1236.0508,530.453,-1639.2557,1151.5896,530.59735,-1630.7125,1472.9633,508.0955,-1163.7266,922.0812,495.75253,-1149.3975,1521.2565,858.0304,-985.66235,847.2398,839.6849,-1007.61597,1521.9172,1191.9738,-1084.0068,835.5187,1186.4144,-1102.708,1553.4778,1255.8447,-1196.2751,793.64636,1251.8516,-1228.8999,1512.3468,1255.7908,-1260.4309,853.44446,1259.6584,-1289.8472,1477.9095,1229.7416,-1118.7758,892.98627,1229.9044,-1137.2686,1297.2749,753.54047,-17.70435,1055.4258,748.7002,17.968983,1280.5653,993.7944,637.5851,1082.6294,972.57983,709.44366,1229.045,1087.7288,1474.2898,1108.6594,1087.6293,1561.497,1215.0411,1078.3751,1559.9067,1124.8656,1084.8695,1647.1729,1202.7509,1225.9645,1371.478,1100.5208,1223.0559,1419.1497\nframe__7IyYtxdDqJw__0014488.jpg,pushups_up,493.40045,477.808,-923.2134,498.29663,436.8574,-973.9252,506.79572,430.43106,-973.79755,514.9694,423.8406,-973.32227,485.289,444.63364,-900.1742,483.64386,445.04828,-900.19244,482.24332,445.9502,-900.60144,561.0888,390.1317,-1014.31494,514.9222,421.044,-673.04266,537.86884,473.1471,-924.59625,524.60535,485.46793,-824.69836,761.81445,419.75732,-981.1692,596.08026,459.3654,-428.28345,784.4503,707.34143,-1009.87714,580.90125,666.7428,-323.05762,758.2688,970.97925,-1090.9303,538.8189,887.34406,-446.29205,742.1961,1024.547,-1261.9547,490.1069,910.1505,-526.1052,700.5871,999.1011,-1228.3387,495.0907,919.82306,-650.27484,706.8342,985.20325,-1092.3845,530.70557,911.75134,-505.86246,1084.6884,529.9349,-213.09079,982.00366,566.8872,213.4599,1290.7583,671.179,205.4015,1167.3984,693.25934,655.013,1505.754,763.8637,653.46735,1332.0729,785.78925,1158.6484,1555.5624,756.8396,687.20325,1378.895,778.95636,1208.5513,1484.177,886.63715,518.9267,1312.524,903.7391,1140.7935\r\nScreenshot_2021-02-11_at_15.22.11.png,pushups_up,813.7904,445.85406,-1313.8158,820.5872,378.4772,-1354.3177,836.9533,367.729,-1354.0658,853.20715,356.73758,-1354.7323,784.55774,394.9358,-1286.023,773.95105,396.96573,-1286.0856,763.82544,399.7827,-1286.4879,912.80756,297.5453,-1322.8495,788.4919,353.80994,-1025.7015,881.956,431.717,-1283.2031,842.035,455.7244,-1197.24,1276.0988,312.09445,-1172.1172,820.40436,369.16885,-757.8026,1576.5247,729.1689,-1157.2098,706.9121,720.5912,-475.24023,1679.3442,1133.159,-1256.0837,554.4808,1048.27,-548.86163,1734.522,1215.6556,-1423.9495,460.48303,1097.5021,-644.7045,1657.7573,1213.1346,-1466.0127,477.07242,1109.6923,-752.48315,1626.7332,1183.5305,-1288.8828,545.71216,1092.2059,-601.9032,1651.2407,468.95447,-171.7079,1428.7137,503.91666,172.30545,1854.9956,702.65674,492.17038,1559.483,700.2167,762.4154,2034.6793,778.6961,1190.4038,1805.9352,786.8852,1504.1062,2078.3484,752.528,1253.7059,1863.5251,762.43976,1577.6859,2018.1498,964.48206,1107.706,1818.1562,957.7229,1535.0543\nScreenshot_2021-02-11_at_11.15.17.png,pushups_up,799.3955,477.76877,-1380.469,808.06726,419.1582,-1438.169,824.05853,411.21878,-1437.7198,839.9432,402.9346,-1437.9011,765.0612,430.3387,-1392.0513,749.0766,430.91983,-1392.0829,733.4636,432.10217,-1392.4055,864.02234,349.16113,-1375.1161,716.6201,393.2702,-1201.5565,837.8139,468.85907,-1327.8024,789.26495,483.0567,-1276.3024,1051.1614,300.69452,-1122.1445,626.7171,436.91434,-1010.5088,1281.2517,528.18506,-1164.1311,491.512,644.1635,-929.6621,1291.4215,761.8791,-1277.0487,391.15494,862.4229,-1025.7814,1313.0576,816.38184,-1373.8896,323.7723,897.3436,-1133.3625,1252.8678,790.5629,-1392.8794,348.50504,896.92346,-1187.7467,1229.1287,777.99396,-1297.1497,395.03183,881.26086,-1059.8312,1184.4656,454.5351,-73.11425,1001.17365,524.6343,73.891815,1329.9086,675.538,409.15765,1086.4078,654.14136,482.45642,1199.718,697.03143,1331.6562,1101.8936,714.8313,1305.2411,1167.6753,672.717,1441.243,1096.3268,706.8666,1397.999,1185.5686,797.0935,1549.254,1125.596,788.7731,1466.3661\nframe__Mpu8MrUd3c8__0002101.jpg,pushups_up,601.68256,559.87256,-389.07556,583.21466,543.6152,-437.2434,585.4874,539.20135,-437.11017,587.7177,534.6504,-437.16287,577.743,545.71094,-380.19128,576.336,543.4565,-380.4532,575.3282,541.31396,-380.9514,609.5452,501.9438,-549.0095,590.2576,509.5434,-279.65244,636.08044,542.2363,-417.40115,631.39484,547.12146,-338.19077,795.3081,484.65494,-584.7464,700.20996,450.2444,-57.554993,862.1864,708.6408,-573.3757,718.6073,618.953,172.83212,845.95325,912.04944,-535.87024,704.75446,777.9546,103.61476,833.9659,964.2466,-638.04065,673.801,798.1547,71.134125,801.65356,943.98846,-619.1388,671.8877,809.6041,-0.80526394,806.685,923.66095,-534.72644,694.7415,805.29486,69.12396,1155.5016,459.53146,-167.47862,1094.4575,449.12994,167.85178,1334.2283,566.7203,202.68465,1279.2415,560.0762,520.01135,1500.9115,638.0524,642.77374,1445.1526,631.5311,984.5763,1541.1018,628.597,678.9743,1485.8291,620.8895,1028.0009,1486.8488,741.1199,570.93506,1445.383,737.68274,958.64557\r\nframe__JSn5DY10dbA__0007764.jpg,pushups_up,1271.9261,802.35455,-117.232506,1275.4153,784.8664,-92.8296,1272.3414,782.6907,-92.75526,1269.462,780.81616,-92.7521,1277.3977,784.3847,-156.7282,1276.4233,781.15375,-156.78174,1275.3627,778.0373,-156.77605,1246.8285,762.9073,57.498272,1255.8433,759.5031,-234.78343,1249.3564,800.81964,-54.76708,1252.2963,799.96765,-138.94916,1146.3356,779.9261,266.97546,1167.8192,769.71625,-379.5273,1158.4268,907.83435,300.24316,1154.6562,898.6398,-543.30475,1175.289,1017.0523,81.67538,1182.9175,1022.0689,-622.54285,1203.909,1020.88385,74.58285,1216.0723,1033.8827,-732.0478,1205.9531,1021.13824,-11.087527,1218.4167,1016.92523,-678.9111,1196.7388,1024.4226,37.38644,1205.8279,1014.30334,-608.3352,916.554,795.01917,202.66232,918.95105,790.4644,-201.87,764.53284,892.00507,168.89598,761.67413,890.0239,-245.87935,601.96027,964.5563,211.98112,566.90234,965.19946,-205.99149,565.05475,967.9021,206.61053,521.6123,964.3772,-221.0725,625.0674,1035.8818,46.778896,594.276,1044.0812,-417.96396\r\nScreenshot_2021-02-11_at_15.08.47.png,pushups_up,1111.9645,554.8996,-727.4416,1100.4426,524.54205,-785.1036,1106.3447,518.2322,-785.19403,1112.2168,511.739,-785.32074,1089.6477,529.7248,-715.7993,1087.8345,528.49274,-715.9238,1086.2921,527.651,-716.26917,1152.3278,471.44077,-899.0656,1114.6704,494.05807,-582.06415,1160.6783,539.769,-755.6818,1150.9192,550.11755,-661.887,1404.3273,463.2896,-888.61896,1221.0946,469.83902,-364.37674,1550.9003,724.2694,-862.85736,1264.4626,662.6283,-83.87123,1528.6956,957.2686,-886.45496,1236.4965,871.3639,-147.78946,1524.4115,1010.2851,-1019.3387,1196.4749,900.9795,-210.75291,1477.0392,989.8523,-1017.50946,1195.9951,913.7019,-310.47836,1477.8711,971.86865,-896.5906,1231.0941,903.823,-193.68091,1773.1262,546.2825,-184.81055,1677.0255,556.2522,185.4767,1908.3683,639.0908,426.1987,1826.8816,638.9019,761.4296,2036.9391,674.80896,1079.6713,1952.3822,682.6707,1408.878,2073.8584,660.0239,1137.4775,1988.7515,669.86365,1475.1149,2005.6094,779.90326,1029.2936,1936.8397,774.0591,1418.9882\nScreenshot_2021-02-11_at_15.23.51.png,pushups_up,872.4639,676.7138,-1041.009,869.8079,629.96814,-1084.0819,878.63293,621.1876,-1084.0435,887.30475,612.13727,-1084.1954,853.2973,642.7235,-1012.0646,849.21045,644.4486,-1011.9358,845.273,646.67633,-1012.22455,932.79333,567.3797,-1083.3624,873.73334,614.9365,-752.3793,924.80347,664.47516,-1022.92523,905.9072,682.7674,-927.28973,1197.7672,593.27094,-1062.6804,942.8054,663.63916,-528.3237,1355.7115,900.3756,-1148.9093,943.80786,881.9711,-415.3365,1383.0403,1143.6127,-1138.1244,907.0475,1075.2131,-583.10284,1391.0267,1190.0989,-1257.3184,871.3709,1109.9353,-653.1946,1344.5945,1178.6927,-1270.7343,873.94525,1102.8353,-740.49567,1338.0061,1165.0421,-1150.2944,908.3514,1092.5272,-625.6406,1537.2087,787.4026,-205.69748,1395.9233,839.1572,206.17865,1821.8527,892.2152,242.77359,1503.7385,908.51807,782.38794,2087.2864,910.26935,729.23553,1674.5822,921.6609,1518.329,2135.7031,884.8583,770.6506,1714.8207,906.8267,1590.8973,2127.6167,1032.3237,551.73474,1685.2881,1005.10657,1552.227\nframe__HlgmHxVXw7g__0022344.jpg,pushups_up,1471.574,704.049,139.99432,1474.842,681.60114,180.77515,1472.9045,679.3541,180.87006,1471.0887,677.13403,180.62643,1474.457,681.28644,104.90105,1472.3751,678.31055,105.089264,1470.3115,675.366,105.06923,1445.5667,663.30383,329.68298,1446.3464,662.4677,-3.9922254,1448.2073,710.58997,207.07619,1447.4406,709.30695,110.474915,1292.5925,667.07196,537.0687,1365.0742,728.47565,-196.86572,1188.5186,788.26904,650.79425,1261.2806,867.9365,-276.48526,1210.0806,911.9906,593.0722,1290.0015,997.46655,-253.78722,1234.6143,917.3576,628.6931,1322.5968,1018.82916,-316.92935,1249.9604,930.2241,561.9308,1326.4873,1000.7531,-259.32968,1245.1714,933.9799,562.6538,1311.4775,993.19586,-229.30879,1039.9596,780.7402,214.34862,1067.9202,820.61346,-213.77557,816.92804,852.9585,248.27042,793.3532,889.00006,-196.61302,579.7862,896.1243,377.13562,559.8019,922.7616,-112.01666,540.6113,890.328,383.9188,527.3848,912.9437,-112.72002,560.11725,957.64307,288.90353,534.26306,997.04083,-270.12952\r\nScreenshot_2021-02-11_at_15.27.36.png,pushups_up,1557.1339,469.32846,-1385.1056,1590.2704,428.13516,-1374.9598,1602.2079,425.6101,-1375.2878,1614.8179,423.66638,-1375.5922,1551.2368,418.17715,-1408.3094,1537.2948,410.43802,-1408.4911,1523.2,403.0273,-1408.4043,1624.8154,388.86722,-1162.8544,1499.9242,350.965,-1312.1528,1556.33,473.52136,-1290.2361,1518.6567,463.90384,-1331.8809,1663.5889,406.70865,-926.02936,1289.8604,323.62747,-1121.3152,1651.8323,617.9608,-762.5275,1106.1638,570.009,-1174.3291,1613.3524,892.9039,-903.085,1094.1582,882.1289,-1203.4442,1661.2916,954.7059,-988.4933,1073.1182,941.78485,-1321.3625,1613.4436,951.5211,-1074.7189,1134.8213,944.2856,-1327.8837,1571.696,933.32666,-940.85266,1149.9795,924.53613,-1216.0415,1347.6995,510.12708,88.22908,1178.0115,455.8162,-88.2752,1298.5105,543.1198,877.1987,1138.0447,494.2322,691.8103,1287.9786,521.1792,1677.7101,1152.8667,484.32025,1513.2986,1294.2192,496.10938,1764.1836,1163.6354,459.8604,1597.8903,1282.8309,578.2925,1707.4004,1157.123,569.7419,1532.4174\nframe__1fDHrKRqy34__0004813.jpg,pushups_up,585.77765,718.74884,-682.0537,574.9776,701.3697,-704.8123,576.92816,695.66003,-704.5171,578.7989,689.912,-704.5415,572.3406,712.0688,-657.319,572.1524,714.82666,-657.22455,572.1621,717.73236,-657.2762,594.0596,673.531,-694.47986,584.3231,707.5753,-468.31155,607.2787,708.8623,-669.02545,604.5974,723.8546,-602.34546,691.8792,694.59656,-723.5519,636.42346,680.2594,-170.08334,709.00055,833.9845,-813.2581,633.5104,781.7904,22.315348,699.8252,937.8063,-918.2784,618.4123,876.32367,-121.21389,692.5759,961.4456,-1054.066,603.8226,890.18494,-150.63795,674.78864,950.83813,-1040.798,603.4095,896.2216,-229.80373,679.53094,943.1877,-925.06226,614.5049,891.8782,-159.54297,889.2219,670.7644,-189.43912,856.5159,665.63135,189.36551,1004.27545,729.83026,112.96382,965.38226,726.041,535.0564,1128.2921,779.9772,455.7867,1080.4148,762.04675,952.45,1164.4749,774.30054,473.24423,1113.1963,759.9118,987.5282,1113.4869,860.1918,305.00238,1067.1901,838.08765,899.9978\r\nScreenshot_2021-02-11_at_11.02.53.png,pushups_up,1184.1503,469.13455,-1535.1661,1200.8446,438.0149,-1556.7231,1210.4789,434.10995,-1556.7759,1220.4884,430.10492,-1556.985,1170.7617,440.6917,-1551.8541,1160.6947,437.95694,-1551.6482,1150.67,435.61728,-1551.9723,1239.016,390.16367,-1350.4012,1134.9233,396.68524,-1328.9315,1197.7727,462.50037,-1430.1649,1172.1289,464.03055,-1423.8889,1326.1051,389.84244,-1027.2058,1063.0338,403.0276,-1019.06793,1379.3358,559.9493,-881.49023,1039.0155,569.0272,-829.00616,1405.1382,776.34283,-962.00336,1034.6877,760.75555,-898.48236,1435.9777,818.70154,-1029.6064,1014.88446,796.6733,-973.8174,1409.6178,832.54663,-1101.5894,1038.3738,801.5207,-1035.858,1385.0255,822.03784,-987.7478,1058.8224,791.01587,-924.92163,1274.211,583.22705,-6.333221,1146.9895,586.6796,6.43414,1335.8606,603.9707,820.64703,1160.9333,622.9772,895.4955,1314.4476,628.67255,1779.8557,1171.7042,632.98016,1876.3164,1304.5492,626.7319,1877.9421,1178.7062,632.10376,1978.2065,1319.3484,681.25165,1737.3125,1164.9103,682.3245,1859.0302\nScreenshot_2021-02-11_at_14.07.55.png,pushups_up,1751.2704,461.48538,-1612.4703,1765.4575,416.54715,-1612.1422,1777.4576,412.78574,-1612.169,1789.7441,408.75806,-1612.2089,1724.777,422.79425,-1599.7555,1711.5559,421.82632,-1599.5428,1698.126,421.25635,-1599.372,1807.7318,383.44766,-1383.3478,1673.3643,403.61374,-1327.6538,1774.3384,473.12848,-1510.3047,1735.1268,477.2428,-1493.7598,1939.9515,471.61856,-1182.8739,1602.2025,488.8181,-1009.3371,2029.4176,739.0029,-1286.2228,1538.0627,703.88635,-940.52026,2049.2585,1019.18414,-1375.857,1537.5621,963.01843,-954.3437,2072.4917,1068.538,-1481.3004,1508.2645,1000.6565,-998.6304,2021.2179,1071.7028,-1495.5122,1542.6483,999.34076,-1037.1483,2009.3252,1057.4836,-1384.089,1566.7272,994.5623,-971.0533,1908.4487,681.37646,-79.983475,1766.648,694.38116,79.59769,1912.8763,775.6317,722.9047,1787.8772,787.8375,879.404,1916.096,806.4008,1589.2521,1811.484,823.08936,1767.2174,1915.0277,797.2047,1672.217,1823.6276,814.93933,1855.621,1902.0156,871.1474,1398.4271,1805.5759,880.5396,1604.099\nScreenshot_2021-02-11_at_11.55.43.png,pushups_up,1349.8887,480.0151,-1721.3188,1378.6613,425.28894,-1730.6879,1396.1733,420.97577,-1730.9354,1414.2717,416.86703,-1730.9625,1326.4612,422.41602,-1735.1141,1309.8585,418.2449,-1735.1078,1292.9745,414.40833,-1734.9043,1452.1436,382.81995,-1492.2463,1277.0109,370.6062,-1499.743,1383.443,486.37595,-1607.071,1329.6676,487.11502,-1605.7777,1594.3031,486.59232,-1191.5001,1159.7072,413.9128,-1229.7848,1671.4598,802.7029,-1263.2699,1061.8964,725.4127,-1325.9485,1694.659,1102.1909,-1426.6118,982.4481,999.0972,-1409.557,1742.3525,1152.1051,-1560.0818,951.57263,1040.6826,-1536.1105,1691.562,1135.653,-1599.1818,1002.9779,1042.4143,-1547.1666,1658.3479,1122.415,-1459.5314,1024.0453,1030.3014,-1429.624,1396.0002,670.30286,15.238151,1214.8193,644.9361,-16.806517,1367.0427,803.5573,795.7293,1227.3042,785.72894,782.91156,1361.1619,831.11053,1731.9169,1269.122,814.00696,1720.2893,1356.8988,804.14044,1831.1498,1286.16,794.64294,1815.1744,1358.9447,945.90643,1641.6139,1263.813,925.94116,1628.4265\nScreenshot_2021-02-11_at_15.28.11.png,pushups_up,1545.4236,459.8435,-1504.402,1581.4882,422.25867,-1494.3853,1595.6562,419.61594,-1494.5789,1610.475,417.67523,-1494.6296,1538.4899,413.71237,-1524.465,1524.1593,407.29858,-1524.6483,1509.6317,401.17093,-1524.8206,1634.9689,387.18835,-1234.8551,1498.277,353.67532,-1379.1976,1557.3524,464.3119,-1387.4786,1515.6711,457.36722,-1426.2477,1699.1185,405.01144,-932.92773,1321.6263,331.44412,-1181.7098,1660.2817,633.1841,-743.3964,1136.7285,564.7,-1251.2927,1596.4274,914.7968,-858.651,1085.7231,879.59326,-1289.9949,1635.0312,973.0976,-961.1106,1052.3806,934.0004,-1450.4471,1589.6068,969.2911,-1048.796,1124.086,949.0317,-1449.912,1550.3232,954.1633,-897.2006,1138.952,932.0828,-1304.6965,1366.9149,526.65454,112.13732,1201.5973,482.5628,-112.034836,1273.6748,527.9724,1029.6547,1151.8727,516.85864,765.9177,1239.0303,497.46445,1932.682,1150.3524,486.382,1670.1792,1243.144,473.20242,2030.8085,1156.5198,459.0943,1760.2117,1225.9569,556.36816,1925.3892,1144.6353,565.5744,1651.3351\nScreenshot_2021-02-11_at_10.55.49.png,pushups_up,1163.299,473.57413,-1507.8435,1184.7338,455.1152,-1500.6864,1195.1511,453.70966,-1500.8901,1206.0078,452.49084,-1501.2102,1153.3369,451.44,-1521.07,1143.0697,447.3895,-1521.2107,1132.5966,443.69757,-1521.2109,1220.2333,433.73804,-1302.8635,1119.4252,411.61212,-1393.5,1174.6017,474.7069,-1414.5771,1143.4961,466.9199,-1439.7969,1277.0957,439.95837,-1067.6775,1010.73883,408.13934,-1127.9917,1320.0082,637.6172,-993.2597,931.63794,612.72797,-1099.3508,1344.5413,835.96985,-1046.7596,861.45123,823.586,-1172.5634,1377.9907,863.8332,-1131.5214,824.3,864.2476,-1287.0189,1357.891,870.52466,-1196.8573,869.6287,870.2614,-1323.6177,1333.8385,864.21344,-1072.6294,891.5503,856.6791,-1198.1921,1110.2849,497.83685,54.93456,990.2912,478.008,-54.889175,1099.0221,627.7292,685.8671,943.4225,624.5123,516.54834,1072.1478,694.80695,1523.9788,947.4242,715.25635,1291.039,1070.1257,691.9989,1609.4038,953.57104,712.09625,1360.9736,1063.1987,770.5939,1515.6965,931.5941,804.78577,1230.4559\nScreenshot_2021-02-11_at_14.12.18.png,pushups_up,1732.9026,511.71902,-1475.1042,1745.1005,471.72983,-1471.8474,1758.3331,469.47708,-1472.0637,1771.659,467.01028,-1472.2158,1704.9286,475.9173,-1458.3722,1690.9385,475.033,-1458.2992,1676.9777,474.63684,-1458.1494,1788.9034,452.6583,-1260.6537,1657.8501,466.82047,-1226.1163,1759.8525,526.32336,-1384.3512,1715.4288,529.4102,-1375.1503,1926.61,520.6117,-1094.0227,1599.7843,542.89935,-918.04065,2025.7343,782.8125,-1151.3137,1525.7914,743.72565,-829.2909,2066.5127,1055.8319,-1231.2512,1503.4272,981.0864,-832.8617,2100.6934,1106.3049,-1321.2736,1461.6769,1018.91907,-856.91895,2061.0474,1111.5281,-1352.8657,1477.5684,1025.7402,-907.7574,2039.9,1096.0061,-1249.375,1509.4697,1018.29767,-856.4148,1939.7657,674.72455,-70.586555,1800.8887,695.6794,71.64748,1942.2109,783.958,682.7319,1819.0945,788.1244,772.1311,1951.1249,815.94403,1415.8977,1834.6917,847.65735,1448.7733,1951.3699,809.72925,1484.7549,1843.6809,847.1675,1516.4402,1928.8591,877.4423,1333.8021,1803.7411,906.0309,1367.179\nframe__-0eYiItN2D8__0002432.jpg,pushups_up,1368.427,385.85776,-386.46304,1384.6873,368.45203,-369.71655,1385.4935,366.73755,-369.55197,1386.359,365.3737,-369.6179,1378.76,365.28668,-427.356,1375.922,360.3667,-427.35583,1372.9698,355.57767,-427.4781,1369.1613,338.12054,-242.50128,1353.1978,325.78214,-497.85764,1343.8032,379.23883,-325.9293,1338.4069,373.5898,-399.68976,1270.7006,301.099,-9.449234,1212.4326,324.97836,-559.3332,1213.3486,407.507,190.57275,1110.6876,465.14697,-575.32764,1223.202,534.3804,136.19551,1125.5787,621.8494,-547.85754,1249.8994,545.009,121.079506,1143.6548,651.7754,-627.6969,1255.2938,558.2061,45.479797,1168.193,639.1351,-600.92773,1236.9753,559.0078,104.079636,1158.5627,627.795,-536.9318,983.24457,347.1475,173.12817,947.53986,360.8959,-172.68939,839.87787,412.02005,558.52625,799.4032,423.74722,223.58447,691.4306,437.80646,975.2094,638.7877,457.61838,630.0898,651.40015,423.72964,1015.3927,598.64984,441.85056,663.61456,697.99304,527.3104,979.6993,641.8451,556.3949,580.2644\r\nScreenshot_2021-02-11_at_11.26.05.png,pushups_up,1392.7078,673.3237,-1573.7866,1402.865,640.2479,-1563.5015,1412.4216,636.35913,-1563.7488,1422.4415,632.681,-1563.5918,1372.9814,643.3445,-1577.2731,1361.939,642.1155,-1577.3225,1350.7902,641.11035,-1577.2329,1431.431,611.4775,-1317.372,1332.1449,619.8433,-1377.4219,1408.2189,674.36285,-1464.9143,1376.0591,677.83716,-1480.427,1504.5448,642.02576,-1052.1667,1242.1456,642.27264,-1103.022,1573.5719,784.17096,-991.5486,1186.5514,787.79535,-1120.1427,1571.3285,943.452,-1107.1462,1170.9111,942.14465,-1210.0189,1587.9191,972.1388,-1179.1631,1151.8531,975.36975,-1311.6492,1564.5808,966.15674,-1234.8928,1184.5663,974.4393,-1330.8748,1549.5681,959.7955,-1132.4192,1199.7748,959.31476,-1225.8539,1395.3931,741.96246,36.98089,1273.3201,734.30316,-36.94981,1384.2672,820.93195,813.3916,1278.1847,811.9837,695.414,1394.4746,856.4611,1598.1648,1282.6625,836.051,1431.1481,1390.7758,846.6891,1676.594,1286.2413,824.3108,1503.637,1415.4039,919.11115,1519.0328,1288.4475,906.39215,1338.982\nframe__0LlT7MSKJBc__0014590.jpg,pushups_up,544.21454,761.76666,-639.72516,532.244,744.56244,-692.1862,534.428,741.22876,-692.0179,536.4989,737.7022,-692.074,529.0227,743.37897,-624.1754,529.05096,740.5782,-624.0486,529.3239,738.01764,-624.2797,557.2806,709.262,-800.80554,546.7564,710.9692,-487.60077,571.81647,750.8556,-669.87714,568.8913,752.74585,-578.1652,693.02374,694.1228,-871.67224,620.8693,702.76935,-245.2904,719.0775,858.52356,-1010.0885,614.78357,853.08344,-140.69916,688.84467,1007.48444,-1121.1796,584.1235,967.2929,-278.33325,672.60236,1038.623,-1269.4072,556.73895,978.8491,-321.657,651.63367,1025.1898,-1246.4226,557.76227,985.9545,-415.23456,656.72675,1015.0218,-1124.5143,572.88586,982.1032,-326.5629,915.4337,680.96246,-197.4235,866.8729,694.6038,197.8206,1058.9197,781.6034,57.11546,1001.1653,806.4985,535.00323,1208.2554,874.7104,449.68442,1147.3696,869.85095,1005.046,1241.9215,880.15936,473.41678,1177.8634,874.3551,1044.9104,1205.6793,961.4608,278.6397,1155.3584,935.28436,920.90625\r\nframe__3tWgNMmnxi0__0006912.jpg,pushups_up,459.86957,490.78894,-498.70743,451.0486,449.981,-568.36505,457.09134,442.63284,-568.1325,462.97388,435.13565,-568.0921,441.554,457.802,-492.26898,440.35504,457.19412,-492.6087,439.69052,456.76053,-493.17145,505.756,390.1342,-703.27783,469.53265,418.26123,-358.10162,508.73016,475.95132,-533.71783,498.322,487.1974,-432.52988,737.9109,390.2193,-721.26025,595.70416,417.7428,-176.34921,781.3317,711.8471,-701.3954,574.60925,667.034,-34.80397,713.28076,989.25244,-699.90656,518.3441,906.1756,-99.859604,705.5935,1063.4568,-832.6843,478.25656,948.04114,-155.50275,659.0281,1037.407,-820.711,477.90018,951.5573,-246.14865,663.02783,1009.3464,-707.4923,509.95032,937.63025,-147.059,1231.5342,418.46426,-183.6351,1132.8667,449.8797,184.80045,1483.2405,605.79083,116.59874,1346.1871,616.976,462.71558,1723.4646,702.54144,489.77582,1569.1732,724.1274,901.56604,1783.8394,686.5794,519.0913,1626.4613,704.5181,939.3659,1710.7399,849.4712,371.9628,1579.392,873.06134,863.65344\r\nframe__ktjcOU_-x98__0017054.jpg,pushups_up,1661.5063,516.5174,-411.464,1675.5317,483.44766,-407.0034,1673.877,477.49966,-406.59775,1672.4279,471.9826,-406.49194,1669.6831,487.7929,-477.31354,1665.5359,483.91812,-477.52112,1661.2235,480.09967,-477.66507,1636.821,441.7151,-289.51212,1626.0139,451.2885,-602.4129,1621.4474,512.8703,-353.4908,1618.0658,517.4,-444.26797,1465.6339,450.9907,-20.799557,1423.9895,508.8204,-645.2086,1411.3833,658.68713,147.71593,1352.5573,742.4301,-597.84955,1396.332,854.23126,40.921783,1310.6484,970.46893,-576.7938,1452.6614,846.0811,-4.9275165,1347.1729,990.1021,-707.1046,1457.8065,867.9849,-109.61502,1369.845,975.72485,-671.27716,1429.858,881.70074,-7.6953516,1352.965,969.0566,-569.4837,1039.4335,510.9553,194.94504,1005.7868,534.13495,-193.95955,757.25574,636.4927,421.88406,724.1429,672.46326,103.543686,503.8332,725.7199,742.84503,444.8078,748.8341,415.21295,440.43066,721.11127,765.4217,377.74234,745.784,422.768,528.82556,844.4916,613.15857,487.13635,865.6757,210.33945\r\nframe__hjklQnYRz_8__0008015.jpg,pushups_up,1089.8076,722.98987,-101.03257,1097.3641,700.6832,-75.762726,1095.6692,698.5205,-75.4479,1094.1733,696.50336,-75.41162,1095.1193,699.3402,-136.29674,1092.1598,695.26056,-136.3327,1089.1453,691.2613,-136.32654,1071.2695,680.15424,75.29321,1064.1865,672.31335,-197.56943,1066.0157,726.75256,-38.575367,1063.6031,724.0084,-117.62316,954.56775,717.0097,294.10202,957.9547,715.53815,-339.869,953.74316,862.4085,323.52008,946.51056,872.3358,-465.62277,958.162,978.33264,122.224106,950.356,1031.8308,-525.14746,984.60547,972.7865,124.77632,973.4944,1036.7424,-624.96045,988.9006,973.01874,46.73781,977.7848,1028.4645,-571.0414,978.7122,980.23145,80.83259,968.8164,1028.1647,-508.5553,719.1949,807.40247,197.17303,715.2692,804.68616,-196.40819,544.12463,908.29266,178.02919,517.6853,913.49585,-265.03418,332.28156,927.5769,285.6265,311.19904,926.3231,-183.43604,293.03738,917.7037,287.87546,278.1159,918.5933,-198.44115,320.1606,1006.4962,157.36417,299.86655,1000.3304,-412.1335\r\nScreenshot_2021-02-11_at_15.32.32.png,pushups_up,990.23126,583.0025,-904.24335,987.4011,549.0717,-962.81,994.897,542.37463,-962.4488,1002.1492,535.60547,-962.2973,971.19366,555.7108,-888.6364,966.93536,554.53516,-888.679,963.232,553.6898,-889.25275,1033.0764,491.16174,-1028.5289,977.9527,515.53827,-684.36676,1031.755,566.6558,-910.11255,1015.3385,575.4084,-809.21387,1233.5464,457.73492,-978.24896,1039.1538,504.09457,-434.5065,1286.6715,763.0315,-983.93384,972.04974,723.527,-268.15393,1276.3949,1018.8602,-1039.127,916.3047,914.82324,-354.54367,1269.3401,1079.1987,-1199.3004,857.4382,929.9939,-421.08704,1218.8649,1050.3213,-1185.2474,866.80774,942.359,-520.40204,1218.5833,1033.1333,-1048.8617,901.4168,937.7575,-403.79095,1568.2131,451.34485,-205.74205,1466.954,492.80063,205.90588,1804.0143,631.14703,185.18564,1666.6296,655.3233,652.4478,2025.5507,751.5574,643.779,1868.4628,762.89734,1247.2125,2075.187,750.5604,682.5726,1915.3903,755.243,1303.75,2012.2563,880.26575,518.1325,1876.0254,890.156,1221.3892\nframe__X3k4r2s7srU__0017656.jpg,pushups_up,650.89,609.2118,-152.50917,636.4,590.22644,-199.622,637.1472,586.80396,-199.51541,637.79407,583.15173,-199.64322,636.3541,588.3539,-134.07703,637.294,584.5566,-133.91602,638.5994,580.91656,-133.77792,654.0097,556.6888,-291.01498,654.17413,554.3882,6.5125494,674.5909,602.4001,-176.09789,675.08386,601.1377,-89.7841,766.9844,569.3767,-411.49475,789.58685,549.08954,245.82353,757.35516,746.43774,-535.4974,786.658,708.3092,317.81186,747.88477,909.0135,-548.306,782.15204,830.7732,169.71375,699.7736,923.5748,-641.2332,740.3064,821.30365,177.39081,698.30383,906.51843,-572.3003,738.2075,833.818,98.83636,716.20264,903.76666,-524.40466,753.6488,842.7275,133.07614,1088.9434,553.23346,-201.86726,1088.8307,555.4105,201.9127,1306.9303,689.7491,-143.76907,1229.0984,721.2297,327.33167,1528.291,760.6105,-40.83518,1430.7606,754.6386,503.1053,1579.6914,755.03937,-45.039677,1470.0616,742.15894,511.92294,1501.029,860.707,-223.8091,1444.0331,835.32965,416.52676\r\nframe__hnCg8x3xi8M__0014997.jpg,pushups_up,688.8606,691.4587,8.918146,669.93604,676.4254,-38.172794,670.28284,673.6571,-38.284744,670.6154,670.4819,-38.69861,668.82806,674.1317,24.181555,668.765,669.2741,24.227247,668.9622,664.4567,24.415442,681.2145,641.6209,-154.41188,677.38354,635.4582,129.32878,710.9949,681.7324,-23.305895,710.44727,678.7048,58.57278,798.6025,628.0495,-304.99133,825.6551,614.3783,345.7524,829.6344,803.24786,-395.69403,856.9836,782.22943,391.02524,837.08057,973.9711,-339.0135,860.7938,928.6584,196.11078,801.2519,991.1046,-404.0007,824.7839,929.9456,202.95322,796.2435,977.1631,-339.2411,818.81335,938.47156,126.202225,809.95044,970.1835,-313.69513,831.606,943.9707,156.92651,1127.4504,676.7005,-202.65599,1130.603,668.2195,202.73436,1374.4414,783.36835,-130.6544,1365.2025,770.137,208.05139,1628.7828,868.17004,-34.644413,1608.9518,840.46094,293.22308,1680.3279,859.174,-36.6166,1662.6045,837.8712,295.63962,1612.5385,959.0738,-195.34665,1592.0822,927.67236,174.23174\r\nframe__hglfthV89Zk__0003443.jpg,pushups_up,1348.0765,445.37466,-887.2079,1366.4275,409.05145,-870.13416,1373.9312,409.91263,-869.96564,1381.745,411.3569,-869.93945,1340.0463,401.55463,-908.116,1328.0092,395.8022,-908.24695,1315.966,390.25427,-908.44495,1365.7616,406.99524,-672.27893,1281.1517,378.34235,-837.06024,1339.4664,471.0007,-798.11896,1307.2155,458.99103,-845.47833,1312.3828,476.5327,-370.61926,1126.6274,482.16455,-808.1796,1300.4305,641.7454,-104.37656,1019.5845,699.6217,-836.95276,1304.7899,804.3991,-76.12072,1007.7938,881.2599,-880.5577,1337.7203,826.89746,-108.74563,1005.40216,916.1183,-997.62726,1321.8195,839.66833,-185.41583,1038.2992,904.2274,-999.4638,1292.9647,836.00745,-107.86343,1037.8052,892.60474,-889.2478,950.43536,601.6487,134.82817,875.3976,595.5595,-133.83711,781.1356,682.4488,555.37976,713.2455,620.8516,345.00348,607.28326,660.3877,1109.6445,557.24725,636.12714,874.7801,580.13116,637.0596,1161.3748,527.08057,621.6807,922.71375,565.1308,729.4876,1106.3024,533.21173,720.71924,817.96027\r\nframe__CGBlXm4rzFU__0003676.jpg,pushups_up,293.13297,560.76666,18.720654,265.30872,540.1104,-32.27915,263.8135,534.7796,-32.116325,262.23605,529.0146,-32.13237,269.09872,541.31793,39.155136,270.4057,537.3981,38.947216,272.0067,533.54626,38.91934,273.25934,489.69852,-156.6141,285.16455,496.04776,174.44447,321.09644,542.9497,-13.831958,325.24268,545.7389,82.1455,413.04865,477.9839,-298.9681,487.23828,457.40002,393.43756,525.15356,647.0728,-419.95813,622.58923,584.5605,544.9798,505.46094,812.4155,-376.43933,621.2618,707.2776,472.876,460.67917,834.1506,-429.08923,587.16284,705.65326,501.65118,448.95154,818.77606,-364.50534,569.6194,722.03674,445.07114,467.2617,809.32745,-347.38153,578.44135,725.51276,445.8165,825.053,541.8083,-203.413,843.8742,523.0214,203.14993,1132.0012,651.4553,-234.22624,1138.214,631.61884,217.20114,1458.6678,667.6977,-154.92482,1443.6371,647.5814,346.58167,1504.5419,644.38324,-152.2982,1492.8611,625.9194,353.9865,1519.8036,757.8683,-290.03192,1503.8352,730.40393,254.3215\r\nScreenshot_2021-02-11_at_14.43.43.png,pushups_up,1660.2295,421.18054,-718.7333,1667.9524,378.51456,-701.0061,1667.0363,376.7728,-700.74347,1666.5358,375.58224,-700.8309,1659.7148,374.14627,-786.9393,1652.3843,366.90897,-787.30774,1644.9208,359.9179,-787.60895,1619.9056,342.4807,-501.83496,1591.7408,322.12613,-888.5372,1616.087,427.5595,-625.34344,1606.8523,418.5376,-737.27563,1496.5168,415.65018,-205.49261,1355.3236,382.21634,-911.5287,1448.4625,605.6625,125.08098,1213.8854,613.6968,-930.2074,1497.82,806.2935,99.968506,1224.1746,851.90015,-915.1698,1524.2678,839.6527,78.96465,1216.6116,896.0613,-1029.4272,1533.8727,852.2657,-27.68904,1255.4913,895.97925,-1028.7877,1505.4216,844.99756,54.40551,1258.1511,883.1601,-919.8412,1127.7712,629.10364,215.02687,1046.2405,596.68555,-213.98048,986.76733,727.12415,833.5612,837.45276,655.82947,270.42075,817.4039,730.25574,1583.8241,633.7894,666.92676,903.1159,769.1588,715.4798,1651.8252,586.4828,660.1426,957.6998,818.07086,811.7408,1596.5314,607.1038,729.0439,812.49005\nScreenshot_2021-02-11_at_13.15.01.png,pushups_up,1275.6674,544.7178,-1051.2643,1297.1771,524.05786,-1079.9517,1307.7863,522.5279,-1080.2217,1318.8236,521.31555,-1080.3158,1268.5215,522.50006,-1083.8297,1258.9458,519.35266,-1083.7761,1249.2731,516.5666,-1084.0149,1338.3911,509.89365,-999.62726,1241.743,497.44388,-1018.4505,1289.5746,551.10504,-998.6535,1259.3536,549.1469,-1002.373,1386.6034,529.2958,-774.8276,1170.8656,505.36115,-810.0945,1428.4862,603.09204,-357.50793,1102.2834,589.11755,-639.5619,1394.8516,706.3436,-174.97519,1129.9441,702.5365,-596.2664,1400.1713,728.1425,-155.50806,1121.4719,733.0151,-638.2662,1388.9174,733.78687,-189.15105,1144.6464,722.6962,-652.1052,1377.9283,726.6231,-180.82262,1156.6633,710.96893,-606.0476,1265.2228,609.9702,43.73045,1167.215,591.4625,-42.70853,1239.8334,687.4406,640.7163,1143.5665,663.4893,518.73596,1231.667,649.27954,1389.4058,1153.7434,638.7032,1228.8923,1236.1394,633.9639,1477.3319,1162.2292,621.30023,1312.4779,1213.024,662.4812,1555.7302,1146.8617,673.5931,1395.705\nScreenshot_2021-02-11_at_11.25.03.png,pushups_up,1237.5658,705.2076,-1079.9303,1248.1893,670.99243,-1083.5227,1257.493,668.4279,-1083.6882,1266.9717,665.72473,-1083.5857,1218.3955,673.64325,-1077.9253,1208.6825,672.4416,-1077.9615,1198.853,671.44586,-1077.9634,1281.416,646.98553,-925.2318,1183.4618,655.7975,-892.28015,1255.078,712.79425,-1006.8653,1225.8973,714.9076,-997.33856,1373.277,716.88934,-766.39136,1121.1577,727.921,-706.56146,1413.4973,930.41974,-832.97217,1103.646,928.64197,-747.3722,1442.0383,1123.1544,-907.7404,1064.2695,1119.8274,-781.3641,1465.2239,1152.4872,-983.00604,1030.7515,1147.9393,-816.3232,1438.2428,1153.406,-1010.01404,1047.9077,1148.1959,-866.81024,1420.3546,1145.3003,-924.51385,1071.436,1141.3905,-804.2253,1324.3207,913.7257,-33.092304,1216.7764,915.05963,32.857395,1317.8732,1003.5555,513.22723,1243.1372,1009.0239,583.6474,1294.3553,1055.766,1108.5658,1266.1034,1047.776,1200.1571,1288.5756,1054.4432,1163.4022,1271.9484,1044.8999,1260.4282,1290.2826,1110.9066,1004.28674,1267.2915,1098.92,1103.7117\nScreenshot_2021-02-11_at_12.21.29.png,pushups_up,1278.0375,652.32916,-1447.7806,1313.8958,625.3072,-1545.183,1331.3011,623.60925,-1545.1836,1349.4326,621.9163,-1544.7284,1260.5762,613.95245,-1536.9708,1244.4807,604.76086,-1536.8627,1228.1812,596.11865,-1537.1447,1400.6096,567.91644,-1508.6731,1211.4764,524.11884,-1477.3842,1305.255,639.9794,-1375.1295,1260.9558,630.6603,-1364.0605,1543.4805,526.62006,-1180.7573,1133.1693,446.55328,-1179.3202,1646.1989,691.4536,-929.64844,1029.1855,602.5005,-970.2292,1612.166,901.6305,-1123.4945,966.85077,821.7837,-1259.9014,1640.7859,941.7937,-1254.9512,917.89813,837.0601,-1407.1649,1604.8068,927.50006,-1296.8314,951.76965,846.6752,-1460.3661,1580.7787,917.2933,-1160.1301,985.11127,848.5985,-1301.8667,1399.1997,703.10785,-3.8569374,1213.0151,667.09973,5.691686,1358.0852,806.7344,879.9668,1226.7988,780.06635,865.87604,1352.8906,841.5906,1896.8187,1276.852,803.4171,1924.7471,1359.9222,824.5309,2005.795,1300.8901,787.94415,2038.938,1315.2903,911.942,1928.0032,1262.8884,867.883,1988.5918\nScreenshot_2021-02-11_at_15.25.24.png,pushups_up,907.60657,688.9887,-976.9948,909.50635,646.33484,-1031.3506,917.4322,640.13086,-1031.2404,925.18195,633.6342,-1031.2891,897.3637,650.81165,-957.09735,895.6581,649.021,-957.0332,894.1697,647.81116,-957.4577,976.49084,587.0776,-1085.907,931.434,608.63544,-745.58026,960.684,678.3318,-980.8652,947.76764,686.93756,-882.4373,1254.8976,610.3557,-1086.1733,1015.7445,636.31384,-547.5704,1383.4283,908.63385,-1178.312,971.6013,861.3487,-413.14337,1379.5469,1156.4604,-1220.6938,922.1967,1065.5273,-544.99744,1369.4006,1198.6418,-1364.2561,873.84326,1087.3538,-615.1773,1322.258,1179.4526,-1366.4854,881.1302,1083.923,-719.8852,1321.0535,1166.7953,-1234.8025,918.67316,1079.5598,-594.6574,1579.0527,763.3505,-211.3788,1448.3164,780.44977,211.6106,1860.5286,884.5188,239.95949,1547.5688,792.34045,815.24164,2115.568,894.6246,651.6794,1727.6993,736.151,1497.0808,2166.4385,860.64734,689.84106,1768.7506,711.6046,1569.3914,2137.5928,1017.5371,547.6903,1731.8175,803.4741,1613.1123\nframe__joNzM16CASk__0018757.jpg,pushups_up,641.1476,693.0686,-68.93869,634.1981,679.0886,-108.428474,634.9104,677.9833,-108.4111,635.63025,676.5057,-108.450424,635.6603,676.6416,-53.8166,636.9415,674.56494,-53.783577,638.4614,672.4561,-53.610382,648.4569,667.7592,-214.07706,652.2248,661.30676,45.13104,655.65344,697.70715,-98.23316,656.58746,695.9047,-23.597971,707.146,708.8316,-326.99103,745.7721,674.95557,255.83327,740.8297,821.0834,-328.8015,788.86206,762.86194,350.13058,719.9573,929.56476,-258.8989,772.15704,846.5745,196.62585,704.1888,942.7105,-301.3336,761.99524,847.2906,200.58072,698.19226,932.4144,-263.6277,751.175,851.7725,145.55821,705.93024,926.52655,-240.78876,753.4321,854.97406,169.30261,898.5019,789.87366,-191.05557,918.63007,761.7464,191.22325,1036.8584,865.7809,-187.47076,1033.3008,811.9758,468.7737,1193.9918,888.2517,-161.06505,1166.3069,825.68054,752.41125,1229.3948,877.3192,-165.04121,1197.5786,821.14905,780.3912,1188.3921,950.7158,-286.9073,1156.1836,877.4033,735.41614\r\nScreenshot_2021-02-11_at_12.46.00.png,pushups_up,1223.1971,741.76105,-1782.4928,1260.957,666.72485,-1810.9924,1286.0665,661.4515,-1811.1268,1311.5212,655.8572,-1811.1373,1186.8986,667.2399,-1798.866,1161.0704,661.4549,-1798.7758,1135.6831,656.1744,-1799.0123,1357.2809,605.57654,-1575.4178,1100.8943,604.8647,-1525.2997,1266.234,749.8369,-1660.252,1188.5237,748.5964,-1645.1538,1516.1234,624.1096,-1178.228,979.2267,647.79425,-1138.1156,1621.9554,854.78973,-813.9964,881.19446,871.44055,-885.39233,1609.1483,1160.9321,-920.6819,874.36566,1154.5293,-1051.9155,1642.4459,1223.2382,-1029.1584,828.99634,1208.7484,-1186.7249,1584.7256,1225.5864,-1095.7307,895.2452,1211.302,-1262.6748,1550.7014,1203.6381,-948.95917,934.70264,1188.7222,-1099.1642,1379.4419,847.9572,7.8790736,1141.7458,872.82367,-7.074434,1391.4213,879.07245,892.41296,1165.09,910.60345,904.94824,1367.131,843.64264,1804.2592,1192.7153,869.069,1916.4712,1351.1068,813.5498,1907.1476,1205.1854,830.7349,2025.0759,1369.2476,934.4961,1823.272,1216.072,958.7251,1947.2212\nframe__FNujCvj_NnA__0000963.jpg,pushups_up,807.43866,581.4777,-695.3669,808.1541,580.8088,-738.91614,813.8919,578.62463,-738.7376,819.7027,576.303,-738.97943,790.5875,579.2416,-698.0642,784.17725,576.51294,-697.8575,778.1522,573.8522,-698.07196,834.08044,551.4653,-836.1606,775.5594,546.72314,-642.322,831.15063,564.83234,-715.8622,815.6355,565.62335,-657.7637,963.7958,499.98947,-784.47723,760.7977,437.3915,-461.7111,1036.6064,682.8046,-788.03375,736.1196,572.4044,-221.74579,1012.70746,853.0451,-805.74646,715.09045,726.7175,-310.5336,1020.64453,892.17474,-887.1551,686.36786,751.50055,-360.37274,983.9669,872.4065,-895.4345,697.72156,758.9448,-433.68097,977.6161,858.8226,-812.56354,723.9094,753.1749,-341.0233,1113.6515,465.2271,-141.1014,1014.4258,443.15137,141.15022,1271.774,539.03546,382.14258,1023.4759,505.51178,728.1734,1399.4696,536.4407,947.183,1091.8129,529.63245,1393.9521,1412.3573,517.0704,1004.97766,1106.7979,519.5174,1460.1984,1425.0669,604.27,955.68976,1084.2885,580.83307,1450.7987\r\nframe__z5_CTDjMi_8__0029889.jpg,pushups_up,583.5273,741.8165,-33.847576,564.4927,727.72736,-87.49344,564.8069,724.7352,-87.49364,565.1099,721.4599,-87.784386,562.8261,725.64465,-16.357805,562.3114,721.34076,-16.324184,562.1553,717.0668,-16.196083,574.25037,694.0723,-210.41058,569.89166,690.3862,114.51445,604.5869,732.1912,-68.79316,602.9973,729.899,24.765882,673.2296,689.55945,-368.9094,691.00653,664.75824,347.9533,643.6383,845.8879,-541.08813,693.87665,800.941,382.23297,616.72473,978.4324,-549.0831,677.40186,902.75165,89.063156,570.6156,988.1001,-642.9587,638.2567,897.0977,77.836395,571.57874,972.2394,-569.2245,635.0042,903.36304,-9.906898,589.3149,970.7786,-525.0708,648.8091,911.4174,42.238327,958.2179,712.8755,-223.37349,953.7604,700.5717,223.43773,1149.3756,837.42615,-163.56145,1119.9819,810.45905,327.1225,1342.175,903.86035,-64.89046,1288.6702,866.2815,559.3072,1389.7423,897.78046,-66.490295,1329.7015,865.357,576.46423,1306.6119,992.238,-257.41913,1270.5587,946.5887,444.24734\r\nScreenshot_2021-02-11_at_11.33.38.png,pushups_up,1248.6067,703.4097,-1281.0345,1280.085,677.0273,-1299.7493,1300.0635,671.8767,-1300.7366,1320.3524,667.8001,-1301.4098,1225.8118,676.4451,-1317.7885,1207.8754,672.6684,-1317.738,1189.6787,669.09534,-1318.298,1356.5625,644.70374,-1208.3682,1183.8063,631.27997,-1286.9376,1275.8546,703.55743,-1225.706,1220.6208,705.18396,-1245.8486,1485.8943,625.41644,-1019.75854,1040.027,530.5658,-1123.5363,1600.9634,836.2186,-844.1381,826.9934,769.34344,-1142.1451,1596.6976,1080.3209,-994.8375,791.70245,1097.8358,-1171.3259,1656.7468,1137.3722,-1048.5796,754.8987,1170.9282,-1282.7815,1611.9088,1147.9802,-1117.6832,827.9159,1171.6393,-1290.5282,1561.1534,1133.3766,-1019.83624,852.9619,1147.473,-1184.709,1157.3635,681.89496,67.79785,970.7018,614.1779,-67.734955,1113.4824,739.03326,624.15515,954.6158,736.58844,632.62463,1058.2075,750.01556,1354.1906,957.0335,762.66675,1434.971,1045.2455,734.7425,1433.4147,957.8222,749.4655,1519.2515,1062.7056,807.8555,1444.0083,964.7675,846.32306,1568.6443\nScreenshot_2021-02-11_at_13.19.06.png,pushups_up,1295.5353,517.9503,-1727.785,1337.2524,446.44394,-1748.1578,1365.2852,443.7854,-1748.2316,1393.8008,440.89984,-1747.9912,1258.5477,442.74063,-1744.0455,1230.5565,437.02216,-1744.0521,1202.744,431.7586,-1744.2505,1439.2617,423.865,-1522.6321,1166.0422,409.83282,-1494.2863,1339.118,558.2198,-1613.7389,1253.2344,553.60077,-1603.6874,1555.7489,560.8612,-1136.3018,1069.5845,538.26654,-1103.6852,1630.1968,822.72595,-780.21906,997.9725,813.59607,-762.2011,1607.7596,1077.3542,-920.288,970.6674,1060.2933,-897.8849,1640.1235,1131.5636,-1081.1449,930.37915,1110.2134,-1024.909,1577.9779,1124.5538,-1136.7511,983.256,1108.9614,-1128.929,1549.5806,1101.1769,-957.049,1020.04614,1090.7365,-956.62384,1393.3147,731.9306,-0.54081273,1185.4073,728.8548,1.2975856,1364.491,767.9116,831.55225,1221.7441,792.71606,832.7379,1365.249,747.84644,1689.156,1251.2693,762.93726,1715.9929,1357.7783,728.887,1786.0569,1265.0294,739.1348,1818.4678,1354.4872,830.4936,1671.8207,1268.9415,844.7242,1710.6077\nframe__Mpu8MrUd3c8__0002591.jpg,pushups_up,462.28854,409.9266,-124.01825,437.3909,391.98367,-191.98138,438.1818,387.70465,-191.95137,438.84723,383.04425,-192.14091,433.96478,388.5928,-117.513855,432.56744,383.07285,-117.61984,431.58942,377.72888,-117.63035,453.4,343.55283,-362.22806,442.483,337.30927,-21.560076,495.9033,393.47195,-172.3851,492.31802,391.23172,-73.24143,613.89575,314.8329,-491.1062,625.97327,292.03586,248.60956,646.7059,537.81433,-540.9017,694.0345,460.60263,406.81296,644.76874,757.1143,-430.44418,670.0768,611.5396,273.09247,604.351,793.8967,-507.69855,618.68854,613.8839,282.85986,593.7591,780.3433,-451.97662,609.56866,635.6525,212.67447,609.41016,767.0571,-410.64597,631.0136,638.0935,240.74527,1037.6533,316.19107,-222.71811,1023.58624,312.73767,222.4776,1309.4612,479.29688,-53.363804,1260.935,466.9912,399.80157,1585.1942,563.00964,105.38805,1513.2578,552.8767,625.5118,1649.6187,552.70734,107.3667,1573.607,543.59406,643.5091,1556.9315,692.60284,-68.55843,1508.2915,678.2552,552.9381\r\nScreenshot_2021-02-11_at_14.12.56.png,pushups_up,1753.7324,518.8399,-1590.0352,1766.8799,469.149,-1604.7618,1780.5509,464.02966,-1604.8235,1794.4062,458.68225,-1604.7639,1722.9034,477.6522,-1587.1814,1708.337,477.3463,-1587.1002,1693.632,477.42398,-1586.9694,1818.6948,427.5169,-1411.4408,1671.4185,457.4595,-1324.4863,1783.2776,526.34424,-1496.7263,1740.7256,533.935,-1471.5334,1971.597,508.6157,-1172.7042,1606.2356,521.0929,-1015.85956,2069.6494,783.45026,-1276.467,1540.179,737.84076,-917.6132,2098.555,1058.8414,-1376.5431,1485.7906,997.1177,-918.2447,2125.23,1104.4789,-1474.4594,1434.7493,1032.0106,-947.0442,2078.2214,1105.6525,-1502.6747,1462.9484,1033.1045,-1003.08417,2057.5674,1090.4718,-1393.2673,1495.647,1029.1118,-941.0792,1917.7947,673.22705,-82.036255,1767.4878,679.2236,81.46762,1917.1975,767.0148,637.4593,1799.1815,754.00684,869.8997,1903.0365,812.4607,1456.5212,1835.1384,791.72125,1736.1301,1892.9598,808.06573,1536.2128,1853.6619,785.88983,1822.891,1894.7437,874.6567,1318.717,1818.3325,841.1479,1625.8422\nframe__ph1NjaXvOvg__0015764.jpg,pushups_up,452.19754,635.8486,-12.284355,438.4347,617.94763,-59.8589,438.7253,614.64484,-59.88184,438.88123,611.0188,-60.091454,439.33054,617.2662,2.8362074,440.48923,613.3887,2.8410325,441.9478,609.6009,2.9259794,451.5205,585.20825,-158.59454,455.05197,585.9569,127.85222,472.43353,629.5053,-38.707745,473.5108,628.33014,44.407192,548.6733,592.59406,-280.14786,594.2625,571.23804,332.46436,557.2008,760.4851,-379.2106,623.47363,716.7278,384.3644,573.7302,916.8196,-375.1864,637.23047,826.9091,227.04672,528.9492,932.77814,-448.0619,596.445,820.77106,244.14603,528.2417,918.0979,-375.3611,593.2881,830.1398,168.51274,545.1383,914.10443,-347.80945,606.9367,837.93427,192.66733,854.3874,588.9186,-188.04208,868.5721,580.30505,188.08272,1061.8804,702.2927,-147.97662,1070.0453,721.1236,217.47792,1291.7832,796.7172,-101.08928,1294.5405,793.35596,326.31464,1340.1018,792.4212,-103.24381,1340.3093,787.4694,331.90335,1272.094,882.78625,-239.07808,1300.1793,874.8821,223.26869\r\nScreenshot_2021-02-11_at_12.16.21.png,pushups_up,1247.2848,354.98837,-1758.8871,1269.7512,300.22104,-1785.7983,1286.7731,295.01974,-1785.6317,1304.2606,289.63922,-1785.4111,1216.9688,303.1043,-1779.266,1199.355,299.38763,-1779.2604,1181.8058,296.08838,-1779.4609,1334.537,240.85352,-1544.9333,1155.8694,250.05399,-1518.5732,1279.2946,349.90366,-1636.8177,1226.034,351.95456,-1630.2634,1476.8989,283.05917,-1137.7147,1047.4497,282.84286,-1188.9667,1528.0894,576.4983,-1052.5739,941.1709,533.8457,-1161.5873,1576.8225,860.3131,-1118.8776,867.59045,848.25323,-1276.1019,1613.6008,901.99646,-1175.3728,811.9197,898.89404,-1357.7397,1585.4006,905.94495,-1224.6398,864.41125,911.8728,-1402.7588,1554.7726,893.52997,-1140.8273,903.8082,894.3293,-1297.2102,1365.4446,439.10696,5.234884,1174.1292,440.40515,-6.2811923,1354.1987,636.7976,842.19244,1218.7517,636.76654,788.39453,1325.8967,760.2251,1707.0468,1260.1327,755.9067,1718.4572,1313.4714,761.54047,1793.0798,1268.4304,753.0394,1814.5156,1335.4128,887.32715,1569.5607,1282.732,887.91406,1595.611\nframe__QVNlEfFOWwg__0002390.jpg,pushups_up,1350.1616,555.11304,57.873493,1374.7344,538.928,71.18186,1374.8014,534.46344,71.46597,1375.0175,530.11646,71.47493,1372.6803,541.59375,13.3222065,1372.2633,537.8913,13.374833,1371.7662,534.31244,13.279692,1359.0242,504.5019,140.31053,1355.4045,510.40274,-108.61501,1320.0677,546.94775,97.804756,1319.2157,546.6245,24.979696,1165.7749,468.78723,337.963,1221.3544,548.3202,-253.51341,1098.7745,670.0034,437.89557,1178.8728,766.65204,-283.90463,1080.9229,814.0909,314.1462,1184.9,946.7092,-157.6654,1105.3397,809.13086,307.91748,1223.6713,963.9087,-200.13422,1112.5366,821.61725,233.50578,1224.483,948.765,-139.20555,1103.4056,831.92725,282.53177,1204.6279,941.9187,-129.31334,800.00525,613.08624,166.72829,818.2213,659.34344,-166.17581,525.70654,738.0055,287.525,517.7104,782.78955,-44.159126,255.80132,808.58185,465.7477,219.09296,831.9221,100.31571,204.39252,801.9251,478.25873,160.91943,828.00543,97.808784,248.41336,882.1801,396.91522,232.03566,908.7308,-34.338814\r\nScreenshot_2021-02-11_at_13.03.23.png,pushups_up,1327.7764,342.47824,-1862.784,1354.9979,279.32922,-1834.467,1375.9858,276.60706,-1834.6765,1397.5503,273.67996,-1834.6112,1294.3667,281.18814,-1832.6775,1272.2727,279.7203,-1832.8271,1250.2034,278.51816,-1832.612,1426.0592,274.93915,-1511.1545,1220.6024,281.3101,-1493.5549,1368.9664,374.58463,-1732.5015,1291.0128,376.16983,-1726.8202,1564.6597,456.02377,-1240.1748,1091.7769,472.03134,-1197.7946,1742.5562,798.468,-1386.5612,954.56934,833.9016,-1304.7048,1937.3685,1148.5573,-1511.7014,784.35645,1160.358,-1435.277,2018.528,1211.85,-1579.8796,699.7414,1211.2323,-1478.0259,1990.7529,1216.6543,-1676.0024,717.9598,1214.8816,-1593.3988,1940.8123,1199.5686,-1561.6393,769.95734,1201.4158,-1493.077,1423.6392,780.2233,12.002546,1218.6024,785.34454,-10.971061,1446.5695,973.2222,745.42737,1212.3455,1007.7021,803.43286,1404.5588,1090.13,1574.5691,1184.9344,1115.0271,1731.118,1384.1746,1083.8547,1650.125,1179.221,1113.364,1819.1929,1420.4126,1218.1691,1429.641,1181.8877,1226.2535,1594.8357\nScreenshot_2021-02-11_at_11.30.05.png,pushups_up,1374.22,653.4252,-1632.2295,1390.3375,624.68884,-1630.8949,1400.0671,623.6093,-1630.9854,1410.0883,622.4524,-1630.9427,1359.9084,621.57166,-1634.6205,1349.4371,617.6788,-1634.6788,1338.9165,614.108,-1634.6376,1423.0404,599.37,-1378.01,1320.1644,587.5044,-1399.4491,1386.6063,656.448,-1517.2582,1355.6831,651.36835,-1522.981,1497.131,627.71356,-1067.9418,1227.2039,613.2318,-1077.6296,1552.5764,774.1653,-952.9224,1181.9657,757.1705,-962.5356,1572.3243,933.4057,-1039.8151,1170.0747,939.04456,-1020.9019,1585.9562,964.4918,-1112.6666,1151.0986,973.9203,-1086.8102,1566.5686,965.1699,-1171.1744,1173.001,981.6395,-1134.4327,1552.1112,955.86127,-1065.3746,1189.63,969.9782,-1043.4781,1403.7562,713.2452,6.584626,1279.2222,706.96954,-6.148435,1384.0367,796.9873,767.72906,1281.842,792.6898,714.88696,1391.7642,824.87115,1611.9927,1278.0848,839.38025,1573.2141,1384.7908,816.1917,1694.6818,1282.7313,830.9718,1658.5312,1404.0177,896.4953,1496.0067,1284.3428,922.9527,1470.5084\nframe__VQKqjHtY8jA__0013907.jpg,pushups_up,1029.2653,435.61703,-1403.1892,1053.5092,386.31863,-1413.5104,1068.3986,383.52963,-1413.6545,1083.7969,380.79376,-1413.7544,1006.9773,379.73767,-1421.7233,991.68066,374.0878,-1421.7306,976.33954,368.82346,-1421.6918,1112.2341,342.89404,-1206.0614,956.7647,321.47632,-1222.9893,1054.1577,437.91113,-1301.5999,1008.46204,433.92163,-1305.0571,1241.5444,397.41287,-943.43335,849.27484,336.533,-959.084,1324.5214,636.47784,-1042.5695,757.6154,597.68634,-984.4111,1378.9425,876.11804,-1249.5337,692.07385,858.7866,-1068.062,1438.7915,922.20166,-1342.3018,655.7566,899.729,-1135.1274,1391.4772,913.9022,-1394.746,692.6252,913.3004,-1169.5535,1354.6003,901.03625,-1279.8405,722.88416,902.7245,-1084.6276,1097.526,544.1102,5.323091,922.85205,518.3358,-6.288386,1070.9481,627.52606,698.18475,902.5918,612.1026,685.5056,1062.2454,638.364,1453.4241,915.6355,613.68506,1432.0548,1059.2214,619.8038,1531.1891,928.99146,597.0839,1507.0045,1055.7512,717.82733,1361.7832,901.44653,694.56744,1341.4841\r\nScreenshot_2021-02-11_at_11.46.03.png,pushups_up,1449.5009,281.37375,-1812.4662,1468.1632,228.32584,-1818.783,1482.7786,225.41377,-1818.8643,1497.8757,222.28574,-1818.5795,1419.0914,227.84695,-1829.0679,1401.801,223.49704,-1829.0743,1384.3364,219.58383,-1829.1278,1512.822,193.63272,-1554.6555,1345.108,189.16109,-1597.5011,1468.3853,293.9797,-1688.5114,1417.2756,291.2321,-1700.694,1611.7869,262.6751,-1219.0201,1225.1611,293.8424,-1301.2874,1611.9216,539.3539,-1216.9426,1204.8037,576.9608,-1354.2239,1576.8694,790.59973,-1292.966,1266.9269,822.2238,-1481.4243,1589.4242,826.8833,-1389.1318,1256.8,862.7914,-1599.8525,1544.1733,829.4385,-1419.1082,1302.5521,852.08746,-1590.7556,1530.0393,815.66626,-1312.0605,1314.0457,833.73267,-1483.1498,1490.4811,431.76755,14.659311,1325.7637,444.78897,-16.278067,1483.0652,617.30005,724.1469,1336.7914,655.50275,706.8426,1453.8708,578.63367,1615.182,1322.4817,613.6068,1595.6067,1439.3354,543.03546,1712.6528,1333.5037,580.57837,1690.3802,1464.0873,676.4123,1570.2224,1313.5548,705.46985,1526.9478\nScreenshot_2021-02-11_at_12.41.19.png,pushups_up,1233.2399,418.5748,-1758.9073,1254.7535,371.70245,-1734.1621,1270.2726,369.2204,-1734.3116,1286.2212,366.57684,-1734.1895,1207.6608,373.93527,-1726.2555,1191.802,373.04666,-1726.3187,1175.9365,372.45764,-1726.2152,1311.4567,360.65765,-1440.4585,1154.872,368.9283,-1394.1006,1264.0792,441.9256,-1640.2141,1210.363,443.8898,-1626.1256,1445.9186,489.1916,-1171.6296,1049.0756,509.5686,-1131.4099,1608.3369,739.9329,-1258.0764,927.6684,776.31415,-1211.8567,1756.7948,1029.5154,-1385.2346,794.90393,1045.5282,-1307.1101,1822.6466,1074.691,-1452.1277,731.40735,1083.6818,-1343.0272,1792.9658,1082.9905,-1545.1038,754.5199,1088.2546,-1440.761,1750.2642,1075.7906,-1427.6077,797.80005,1080.4332,-1353.3547,1347.7109,789.16846,-14.277158,1178.776,793.53973,14.600689,1347.9644,927.59064,781.536,1216.0768,939.403,880.17914,1317.8887,993.5223,1678.0111,1231.5743,994.0553,1822.0597,1308.1497,985.91296,1759.5591,1230.7972,988.23694,1913.7672,1318.1805,1076.6188,1512.3816,1238.3081,1070.087,1678.3967\nScreenshot_2021-02-11_at_14.20.15.png,pushups_up,1280.6606,569.51306,-1299.9714,1280.8286,533.2881,-1272.4037,1285.2386,531.73334,-1272.2616,1290.0548,530.6591,-1272.1783,1258.9874,531.1668,-1319.5854,1247.8961,527.4386,-1319.7661,1236.7595,523.82336,-1319.8483,1264.4235,513.26697,-1009.64813,1192.6353,501.99863,-1207.5581,1267.506,582.44025,-1184.7668,1243.7378,576.5015,-1241.6445,1246.7681,560.9798,-726.33057,1026.6042,556.9261,-1094.5726,1341.1805,710.51575,-602.5078,911.89856,774.3153,-1163.1439,1369.7091,852.47437,-755.2989,925.2919,984.9493,-1180.8898,1393.7197,874.6269,-842.86774,915.58606,1031.2473,-1288.7938,1372.9934,877.0263,-908.1503,951.8368,1024.0988,-1311.5211,1347.8298,874.7703,-787.7641,958.627,1009.30774,-1193.4769,949.6764,693.60187,127.76257,848.404,670.747,-127.799164,857.14386,864.1649,625.0202,707.5095,802.61884,423.60242,719.0151,903.02966,1378.4774,566.5602,898.50635,1081.1373,686.7211,887.0234,1447.3914,533.9953,899.8801,1136.1179,714.9247,995.79565,1334.6104,556.8926,994.13025,943.37\nframe__hglfthV89Zk__0000647.jpg,pushups_up,1232.426,688.8533,-879.20337,1250.2648,658.81024,-868.19446,1253.828,656.91003,-868.1057,1257.6656,655.52094,-868.39496,1233.9597,654.24066,-916.1824,1226.6277,648.0202,-916.4753,1219.018,641.9128,-916.74115,1242.1456,625.0,-702.6013,1193.0118,604.2539,-915.75806,1211.4458,687.75867,-799.3272,1197.4081,680.8124,-861.8252,1218.6284,602.38226,-465.63943,1007.32214,620.9992,-836.7761,1245.8818,740.97046,-226.7884,861.984,784.8082,-891.78705,1249.1652,913.0914,-300.59222,822.10657,976.76105,-947.9915,1290.8917,931.79944,-372.56235,818.7441,1005.30066,-1073.229,1277.4747,948.0249,-455.91486,858.0351,996.4603,-1077.4987,1241.7893,946.32996,-337.49255,860.10266,989.407,-961.77747,894.19165,663.4487,162.11601,809.7999,665.04254,-161.88416,735.9913,710.9744,687.9479,701.293,690.0211,414.16064,599.2053,704.4754,1256.2244,584.4579,703.21893,963.4144,578.3561,686.8409,1312.6537,564.233,685.04706,1013.0729,570.1008,779.94214,1242.3228,565.8767,785.7608,917.6205\r\nScreenshot_2021-02-11_at_13.40.19.png,pushups_up,1198.2329,411.89005,-2047.4989,1233.467,347.39722,-2029.4977,1254.2113,344.67334,-2029.6124,1275.2528,341.8271,-2029.5092,1168.4135,344.94034,-2024.582,1147.2383,340.89093,-2024.4684,1125.8574,337.1208,-2024.0637,1305.5529,327.68927,-1694.6758,1091.6313,318.21283,-1656.4811,1229.6597,442.8316,-1905.2064,1159.58,439.56537,-1892.6228,1434.6355,511.82614,-1400.0441,935.1106,487.12863,-1358.1097,1508.7684,865.7918,-1526.691,875.7782,848.16565,-1433.7239,1536.0667,1206.2678,-1780.1001,833.3214,1171.905,-1650.8484,1580.934,1261.6432,-1967.92,792.31903,1223.2542,-1802.5089,1509.8229,1259.4124,-2004.8016,849.4465,1224.8007,-1851.4414,1479.1273,1245.5146,-1814.9553,880.4172,1211.5775,-1688.6091,1249.4598,839.0109,-34.30563,1041.9097,828.62805,34.21374,1177.0024,988.08636,1043.932,1016.54205,979.3005,1025.2402,1170.9235,1007.05914,2184.664,1033.5654,1021.043,2148.0203,1165.604,981.2406,2302.8628,1045.3055,997.9875,2261.8726,1151.9374,1104.112,2030.5043,1044.0382,1128.5771,1967.4609\nScreenshot_2021-02-11_at_14.03.41.png,pushups_up,1481.9894,399.8365,-1614.9655,1511.286,319.76324,-1622.4868,1535.507,316.08295,-1622.5475,1560.1146,312.1733,-1622.551,1442.9492,320.74802,-1614.9854,1417.6853,317.3956,-1615.077,1392.4657,314.34167,-1615.4005,1595.0328,292.6791,-1341.468,1357.969,295.93546,-1309.3757,1527.1882,425.64154,-1482.0641,1442.2809,426.25433,-1471.8872,1763.5122,447.55234,-1073.4574,1216.527,453.41614,-1053.1124,1870.5642,805.8853,-1070.8472,1141.946,808.27374,-1012.94885,1891.657,1165.7592,-1279.8728,1115.1947,1141.7095,-1236.452,1925.09,1254.9716,-1411.9182,1072.144,1217.9484,-1366.3461,1869.2998,1251.8413,-1468.7281,1115.3412,1224.6771,-1451.3508,1833.7926,1220.3809,-1311.7178,1162.9932,1196.247,-1282.5648,1619.5851,914.84625,18.346,1382.3562,925.4087,-16.789986,1623.8177,1071.6013,844.8683,1392.9579,1131.708,766.5655,1565.6434,1151.6874,1718.2899,1416.3652,1159.3812,1781.6631,1542.6006,1150.3157,1802.0812,1423.3489,1151.3413,1880.3376,1577.0933,1273.6725,1609.8818,1409.285,1261.6085,1700.7007\nframe__Bq778fD-G4U__0018377.jpg,pushups_up,573.15894,235.3881,-704.94543,582.99677,193.0812,-752.98804,592.5566,188.40953,-752.98706,601.92346,183.47108,-753.1114,569.42474,198.41753,-683.66223,569.0135,198.4581,-683.8704,568.84283,198.86916,-683.99634,657.8558,162.02614,-816.6507,611.28094,185.10493,-501.69937,625.3873,245.00053,-720.17444,610.1297,254.43869,-627.9715,910.70264,244.41864,-832.31104,744.4844,262.3621,-254.64644,1057.3335,566.1691,-790.0469,803.3186,503.5917,-28.134367,1047.3905,868.46875,-811.59534,778.34436,751.16693,-21.080032,1036.8345,926.26215,-959.24414,731.88495,779.95374,-49.339268,987.42505,911.21564,-946.5373,722.8338,794.5671,-149.74835,989.50696,893.38556,-820.44836,758.0248,791.02435,-64.0993,1312.8634,348.2648,-201.75739,1214.4497,363.22827,202.6335,1491.2998,516.30615,367.96896,1376.9567,518.8134,714.1774,1671.695,619.42664,941.2866,1548.7083,612.04376,1330.9994,1719.942,610.9491,989.99176,1596.9016,599.13446,1391.3162,1640.9706,751.7948,830.5584,1535.0027,739.38824,1284.4528\r\nframe__hjklQnYRz_8__0003005.jpg,pushups_up,1322.7295,630.3483,-864.616,1338.0664,600.8992,-867.39764,1340.1688,595.94183,-867.13,1342.3168,591.4779,-867.18976,1325.2205,602.95294,-935.9981,1319.9937,598.8,-936.3352,1314.6068,594.68256,-936.4686,1330.5171,546.1009,-724.7218,1295.902,546.72095,-1045.7922,1301.5485,610.0342,-791.9705,1293.6575,614.5585,-884.95526,1329.681,511.0168,-542.6514,1137.7174,525.1174,-947.7277,1341.345,679.71875,-390.6333,1088.8303,736.2499,-1021.22363,1341.0153,851.5305,-504.8716,1106.3978,916.97986,-1086.8896,1381.4731,875.3506,-569.50433,1120.7876,951.86566,-1229.1641,1369.349,880.7756,-662.4683,1161.8118,943.8745,-1207.471,1340.1968,871.9736,-547.1128,1156.3333,936.9665,-1092.3696,1054.7822,477.44244,143.86768,949.34155,464.19016,-144.13599,941.228,638.331,548.54,823.2153,623.5559,247.8782,821.4565,699.21826,1165.6588,678.12103,728.56256,751.72314,795.4573,697.97205,1224.9283,645.6873,733.9681,792.5645,830.24384,773.87787,1120.4387,697.9056,814.1634,615.16113\r\nScreenshot_2021-02-11_at_12.54.06.png,pushups_up,1118.8146,550.23047,-1655.8226,1132.9591,500.85254,-1680.4305,1147.6915,493.68317,-1680.3885,1162.7316,486.29248,-1680.3552,1082.5277,509.52997,-1677.3,1065.7971,507.8893,-1677.175,1049.1185,506.69916,-1677.1995,1186.9281,436.3177,-1466.6732,1016.73914,464.47165,-1431.2502,1143.9023,542.31085,-1545.6863,1100.3495,550.2744,-1535.9305,1306.824,458.52682,-1122.3671,944.10657,491.47476,-1087.5048,1326.5894,716.5598,-1085.0316,949.5427,728.73737,-1024.1615,1339.8658,969.3457,-1172.5941,956.2323,978.973,-1120.2103,1366.3773,998.7099,-1276.617,925.8697,1015.4456,-1188.1014,1324.6329,1004.74066,-1311.3287,967.56226,1016.3453,-1229.6704,1305.4502,996.86707,-1194.4203,993.2655,1004.29596,-1138.7798,1219.7393,544.86945,-33.01321,1065.9285,559.32367,31.119047,1203.1127,681.9118,722.0537,1096.9532,679.9451,755.29364,1187.6338,744.6465,1522.9058,1129.6133,742.26086,1578.6024,1177.8778,732.0384,1606.0718,1144.6182,729.6884,1666.3469,1177.6614,852.4916,1359.9121,1141.0222,844.87354,1422.9257\nScreenshot_2021-02-11_at_12.25.16.png,pushups_up,1221.0079,559.78894,-1843.0121,1247.4078,501.33188,-1843.5704,1265.063,497.11676,-1843.7379,1283.1849,492.7051,-1843.6696,1191.7859,503.63196,-1832.3047,1174.157,500.80966,-1832.3099,1156.3821,498.44907,-1832.3201,1315.8861,463.09796,-1572.64,1131.6974,468.90482,-1528.9774,1253.9678,573.2557,-1720.6082,1196.5952,575.13776,-1706.1132,1471.5116,565.4652,-1258.8317,1001.96405,589.1042,-1233.7106,1582.9062,859.6144,-1324.9169,875.499,890.8565,-1408.8201,1651.8427,1158.2186,-1531.3903,809.67017,1167.1406,-1643.3135,1698.0217,1205.8328,-1676.1741,761.82935,1208.4154,-1796.3558,1644.1624,1207.3627,-1719.5162,815.08453,1206.3397,-1846.4551,1612.7393,1197.207,-1562.8063,850.49915,1198.9011,-1681.0789,1328.8505,846.42505,-1.5349867,1131.4932,858.1806,0.7912155,1301.8593,999.0188,888.7754,1143.9508,1003.0092,806.5411,1281.0321,1035.6007,1861.529,1157.882,1037.773,1792.9515,1270.0618,1022.4026,1961.1941,1161.0604,1018.5436,1890.7101,1278.6616,1127.381,1734.823,1192.4523,1131.8351,1652.0931\nframe__GUC67V37m1U__0004690.jpg,pushups_up,679.77515,812.57385,-103.80953,665.07086,802.94104,-150.2319,665.4219,801.05347,-150.32695,665.7626,798.9891,-150.45755,663.7572,801.52716,-98.269066,663.3829,798.3307,-98.22441,663.19104,795.1952,-98.20612,673.9549,780.7261,-225.84122,669.3118,777.2773,10.625617,696.5314,805.732,-125.25766,695.38776,803.6863,-56.74499,757.7394,784.2134,-357.11444,764.7606,762.51996,212.684,757.0262,911.33405,-504.97937,773.4905,885.18085,208.99323,750.75354,1012.1072,-562.712,757.5166,985.6728,8.524696,723.28174,1022.70856,-653.8448,726.7532,989.823,-1.0598856,720.7178,1012.08685,-601.33,727.4108,992.24835,-74.06704,731.5691,1007.2002,-548.36865,737.9569,993.0475,-29.968513,997.83624,794.82544,-179.95686,990.18115,787.374,180.09442,1158.5914,887.9655,-168.79396,1148.2632,870.8634,193.07396,1335.3745,939.22894,-113.90644,1316.226,918.2265,300.66275,1378.3752,935.914,-125.523705,1356.3158,920.71643,304.16977,1303.8125,1015.94635,-315.1319,1296.8358,987.13495,173.19139\r\nframe__8p9Wv9Myu4E__0002069.jpg,pushups_up,1324.6125,564.3565,102.52132,1341.8013,547.39764,123.92001,1341.615,543.85693,124.01452,1341.5122,540.45636,123.82838,1340.8846,547.57635,58.919376,1340.861,543.8515,58.879974,1340.7845,540.235,58.731693,1330.2898,515.53925,210.40588,1330.9683,515.7545,-81.782974,1303.8412,556.60657,144.23848,1303.8065,556.28107,58.988583,1191.9392,494.00806,396.67584,1245.1747,526.62524,-213.92874,1137.822,633.37305,489.82388,1210.7944,677.052,-243.6883,1137.7119,749.2955,377.14725,1197.682,820.63403,-167.36766,1170.7828,750.4019,405.04727,1230.6771,840.29156,-209.07822,1175.0524,771.6981,333.00385,1232.3068,828.78827,-146.07913,1164.6832,777.0068,345.84464,1218.0021,825.35016,-139.21681,927.81506,520.4405,179.89658,944.6764,535.2723,-179.57166,737.5228,629.15735,270.46985,758.8228,637.52576,-78.11064,548.5707,711.3317,414.37344,543.6151,732.8179,81.55568,506.679,713.1246,423.45743,498.48325,733.5088,85.86683,558.4367,786.7522,327.70648,553.1187,813.95325,-29.883629\r\nScreenshot_2021-02-11_at_13.41.26.png,pushups_up,1498.3827,452.06137,-1729.7571,1529.3715,377.40494,-1753.6041,1550.0001,373.57986,-1753.7532,1571.0613,369.59433,-1753.6417,1468.0898,375.2692,-1741.9623,1447.7153,369.81238,-1742.0928,1427.2438,364.65475,-1742.2972,1610.4309,326.9921,-1483.4281,1402.6365,319.42984,-1423.4463,1537.1199,463.0925,-1595.6361,1472.3586,460.7104,-1577.6678,1797.2164,430.24545,-1171.2397,1267.3063,420.7219,-1145.2148,1879.9761,781.15015,-1205.4812,1193.1652,784.9773,-1185.7941,1884.9604,1145.1765,-1373.9644,1114.007,1140.7585,-1321.0048,1922.9617,1217.7994,-1489.948,1059.3147,1199.2256,-1412.683,1863.7277,1217.6781,-1547.5895,1090.4213,1213.2898,-1497.489,1828.1442,1196.1285,-1405.9927,1139.1147,1198.931,-1363.155,1647.4144,864.0704,-12.301123,1416.6217,861.52527,12.52939,1625.0841,1014.8101,835.74384,1426.9163,1035.2712,873.4059,1561.9436,1083.1993,1812.0005,1458.2688,1091.3579,1909.4369,1547.0524,1076.7639,1908.729,1467.0435,1082.4563,2012.3713,1543.3807,1189.8722,1695.1368,1464.3099,1197.203,1786.4423\nScreenshot_2021-02-11_at_15.31.03.png,pushups_up,1000.4328,577.67163,-870.403,1002.9896,542.6605,-933.40515,1011.15564,537.1269,-932.8947,1019.0484,531.5174,-932.6992,987.84955,546.4861,-855.7247,985.03546,544.37805,-855.8494,982.81287,542.5271,-856.4229,1056.3647,490.10843,-1018.57825,1005.2197,506.0838,-655.3108,1042.8862,567.82007,-885.3177,1028.0433,572.5273,-778.6952,1267.0017,472.88785,-966.2973,1065.8564,502.9616,-432.22275,1310.0077,778.6971,-964.6042,982.4579,728.8408,-266.83755,1280.2006,1011.08594,-1049.3046,912.03937,915.08484,-354.3449,1253.9115,1063.391,-1217.8131,839.1734,920.62524,-424.6471,1209.8695,1020.5997,-1201.5712,850.61786,933.54486,-530.94495,1215.1117,1008.5381,-1060.8359,890.0486,935.17334,-407.25818,1613.0033,459.35318,-199.8508,1503.9741,486.61142,200.4037,1822.7635,644.8189,216.14966,1671.9108,655.859,699.36957,2007.2732,763.7265,725.2233,1858.3269,747.29126,1347.526,2051.1174,763.03204,775.361,1905.9844,736.6998,1412.7369,1983.9613,876.3683,650.45197,1859.8016,863.368,1349.6465\nScreenshot_2021-02-11_at_15.17.06.png,pushups_up,1157.0092,397.24594,-1467.8978,1178.8796,337.5568,-1483.5406,1196.1685,331.47336,-1483.6693,1213.5288,325.14258,-1483.8499,1137.3337,347.2471,-1417.3794,1125.0228,348.03644,-1417.3024,1112.5282,349.36212,-1416.9005,1271.519,303.3878,-1372.2732,1135.5582,334.4907,-1085.4556,1215.9805,410.6112,-1416.551,1167.0095,424.61243,-1334.111,1513.0428,448.45508,-1259.853,1155.3605,446.57324,-800.9505,1626.8668,795.9455,-1348.948,1105.8425,738.4359,-688.878,1673.6498,1120.8134,-1431.6477,1037.6869,1049.2667,-742.25146,1712.3811,1183.7048,-1573.9069,977.47363,1098.1575,-764.8959,1662.9565,1180.4358,-1612.088,993.48505,1107.2458,-865.79877,1638.2969,1157.7849,-1456.7601,1036.5537,1095.8354,-789.53064,1639.0153,749.84064,-161.34496,1477.3412,740.2944,162.70953,1710.0604,892.39685,566.2521,1531.6027,868.52594,921.36993,1805.7529,904.1214,1387.4446,1653.5928,915.7371,1703.6813,1826.1283,890.7157,1466.1809,1686.6671,910.8875,1780.1124,1794.211,985.8836,1362.067,1621.4326,1001.7973,1713.8263\nframe__hjklQnYRz_8__0003255.jpg,pushups_up,1127.0626,753.4893,-85.945496,1141.2297,733.8308,-69.43015,1139.547,730.0782,-69.22808,1137.9987,726.573,-69.21079,1141.9917,735.2295,-135.64807,1141.673,731.91235,-135.70863,1141.3008,728.71893,-135.7596,1122.728,701.86273,50.943962,1128.1941,705.30273,-250.30756,1105.1117,747.1807,-32.539413,1106.6462,748.49927,-119.77799,996.2154,696.82605,294.89493,1030.7975,718.38336,-390.37622,975.39343,832.35254,336.00363,1010.6959,868.71924,-490.23267,964.33826,953.42645,160.05699,984.6511,1019.7335,-511.92743,1001.39417,955.2283,173.8376,1017.7723,1032.725,-608.1577,1003.2223,966.5612,94.24264,1018.6274,1021.9988,-537.62775,992.47504,971.27856,120.36209,1006.67645,1019.15295,-486.9973,755.35974,700.2968,210.73367,765.009,710.8472,-209.91884,554.9922,813.10956,199.7246,564.0779,838.9116,-231.62198,370.01575,907.06116,283.4585,358.6893,929.6043,-154.02245,320.1972,913.98254,279.91904,304.19318,935.8684,-175.38124,405.41425,1009.1737,121.86117,406.74658,1035.0054,-409.57913\r\nScreenshot_2021-02-11_at_10.59.55.png,pushups_up,1245.0912,519.28564,-1745.0566,1266.9825,497.16107,-1772.5284,1276.2611,493.60147,-1772.6512,1286.0984,490.07538,-1772.7041,1240.2563,496.021,-1783.2874,1232.0819,491.45825,-1783.171,1223.7133,487.40854,-1783.2644,1307.412,446.06833,-1593.6248,1213.7661,438.38776,-1647.1294,1255.1365,504.36453,-1646.2068,1232.7759,502.1153,-1660.7401,1368.1238,426.9471,-1288.8937,1105.4225,408.68295,-1309.3243,1461.5151,616.26074,-1143.3313,1014.39655,603.3227,-1305.9364,1537.8732,812.80774,-1231.0076,923.0367,796.0359,-1409.9728,1573.2871,843.15515,-1329.5552,883.1084,827.6187,-1518.9143,1555.1501,856.1679,-1407.4801,914.0021,833.294,-1592.0508,1530.739,849.8202,-1269.4564,940.2875,824.39166,-1447.0688,1275.5321,501.85205,37.0575,1136.8661,486.45093,-38.08688,1328.4209,631.73816,996.9018,1104.4874,546.3102,924.63354,1358.9464,651.78467,2079.1511,1097.9529,619.2197,1892.2131,1355.194,632.0281,2181.717,1092.2246,619.48486,1985.4177,1351.2372,751.8219,1980.709,1075.32,709.3441,1867.0992\nScreenshot_2021-02-11_at_11.13.05.png,pushups_up,1588.5206,378.2305,-1734.0651,1636.6434,331.74802,-1746.1544,1656.2563,333.16388,-1746.1449,1676.4253,334.78882,-1746.1742,1582.2206,314.86603,-1756.364,1564.242,304.2641,-1756.0095,1546.0417,294.30374,-1755.4436,1708.738,312.57028,-1535.0035,1528.6313,249.33456,-1552.3647,1614.2108,394.54913,-1630.3776,1552.5126,372.95065,-1635.7397,1809.6433,399.5388,-1270.9612,1366.7484,245.56718,-1307.4424,1987.5342,620.7281,-1509.0618,1229.4823,466.473,-1291.7504,2081.1553,892.7931,-1755.5042,1191.955,728.6549,-1329.65,2144.5842,955.3365,-1821.6864,1168.6327,782.0538,-1410.231,2118.4597,960.2541,-1895.3682,1211.5973,795.20416,-1435.0881,2075.2576,943.7787,-1796.4333,1241.8556,777.002,-1341.2123,1519.9872,585.99506,26.081827,1318.5474,508.0571,-26.46409,1465.69,816.1589,599.2927,1196.0703,739.83636,633.97,1475.131,935.1224,1356.013,1304.3003,802.79987,1558.7651,1473.5455,932.3089,1423.8142,1332.7891,794.1689,1649.8845,1451.1492,1050.8822,1248.9867,1280.8796,925.66394,1587.1246\nframe__vd8W1qsL0t0__0000667.jpg,pushups_up,259.22562,491.49243,24.717768,230.6868,465.62875,-40.1271,231.22867,461.17105,-40.32202,231.69943,456.30243,-40.648106,229.42206,464.4153,28.777412,229.02243,458.53162,28.71778,229.01527,452.85782,29.047985,252.34795,417.96582,-169.80057,244.77533,415.8949,146.61041,294.15646,480.4099,-9.510837,292.20898,478.66077,82.12846,427.58762,430.43445,-342.76636,471.5464,404.85605,425.36197,404.50052,697.91626,-497.60016,518.74774,645.7888,540.8117,387.7134,950.1663,-520.1784,494.96188,856.194,424.52264,332.48868,986.7407,-617.3109,441.18994,873.30945,440.0419,332.99927,968.04395,-553.52545,428.82413,879.8778,360.16794,353.81543,954.6245,-504.6679,449.76877,881.12085,385.8308,964.9695,479.71942,-232.50667,951.745,480.27054,232.82947,1332.7256,673.8784,-209.96576,1289.751,673.76825,213.6471,1708.3617,828.36664,-178.07126,1654.1191,784.5394,305.11572,1787.3704,819.1748,-187.79082,1735.7428,772.06134,304.70126,1685.6736,975.6834,-379.38535,1647.1351,944.71094,160.69722\r\nScreenshot_2021-02-11_at_11.10.37.png,pushups_up,1255.4938,366.7819,-1654.9817,1286.8584,314.2301,-1675.7148,1302.989,308.93274,-1676.0361,1319.6674,303.57675,-1675.9961,1233.8508,314.98746,-1676.293,1216.766,309.69705,-1676.245,1199.7114,304.81302,-1676.6057,1350.3777,245.53511,-1451.8882,1170.6705,243.57344,-1463.51,1278.9651,357.32407,-1537.5918,1228.1814,356.48242,-1539.2115,1497.2085,255.98778,-1156.7654,993.03046,263.68747,-1148.8232,1519.0658,539.44147,-979.1754,928.8855,555.9426,-1007.56256,1432.4689,843.73413,-1023.73846,1045.6349,822.0104,-1115.8931,1439.8751,900.45703,-1083.581,1049.0378,874.64325,-1231.3623,1396.0217,900.0231,-1151.3563,1098.5658,866.6513,-1239.0719,1372.8928,877.5884,-1046.4867,1114.4133,839.5011,-1125.9915,1322.9326,533.93494,10.937647,1087.9045,535.5398,-11.019921,1295.1906,685.809,832.6758,1059.9413,670.30756,819.6848,1203.5494,645.50183,1857.0177,1045.2958,690.9021,1788.2252,1185.7919,614.23517,1970.6335,1045.1987,669.3373,1888.5857,1185.3129,730.9016,1907.6913,1058.4214,797.6367,1741.6134\nScreenshot_2021-02-11_at_11.36.58.png,pushups_up,1280.3535,675.41046,-1169.7114,1298.3612,643.7034,-1151.5127,1309.6344,642.8671,-1151.6024,1321.1378,641.96313,-1151.5016,1264.1072,642.5237,-1155.2006,1252.5607,640.5362,-1155.1399,1240.8997,638.7486,-1154.9904,1335.928,640.70874,-946.7103,1223.4424,636.41595,-960.71436,1299.0222,695.4269,-1085.5685,1259.9729,693.0321,-1089.899,1396.6874,745.77094,-750.9863,1158.489,752.3416,-779.8767,1431.4901,943.5576,-747.1639,1131.6885,958.2633,-820.7263,1481.0044,1109.5499,-805.6042,1091.0356,1149.6481,-874.63226,1509.2843,1131.2129,-857.44574,1061.0585,1176.7747,-912.25134,1491.4071,1132.5948,-885.3352,1082.9443,1180.3843,-956.8995,1472.2308,1129.1166,-823.31586,1104.51,1173.5522,-897.2364,1336.463,914.0648,-4.0741305,1238.9369,914.353,3.557156,1320.0774,1001.9212,611.23334,1264.655,1012.3366,564.26685,1321.6503,1036.0182,1229.114,1287.639,1046.827,1166.0808,1321.7596,1031.7896,1285.9022,1291.8885,1041.8728,1227.5992,1313.8154,1082.5066,1098.807,1284.2971,1098.2218,1049.4119\nframe__J486Fn4Rhms__0010768.jpg,pushups_up,1340.9156,768.3307,-20.864704,1354.1931,755.38574,9.025359,1353.5616,753.5824,9.141775,1353.0459,751.8886,9.084855,1353.0978,752.97107,-45.18301,1352.334,749.32697,-45.132088,1351.5687,745.84186,-45.263004,1340.1492,736.132,134.25827,1339.3868,729.36975,-104.850784,1322.0559,768.38336,32.51569,1321.253,764.1386,-37.002827,1210.6937,723.5842,374.7196,1246.1653,760.63446,-248.83295,1174.045,864.67456,404.2928,1201.8687,897.9309,-299.55414,1173.2773,974.015,209.49167,1206.7834,1032.9241,-299.11508,1205.6339,966.3369,222.01509,1242.2747,1041.9331,-367.52283,1210.1276,980.55383,142.54121,1244.8508,1028.4257,-313.43582,1200.5869,988.67834,170.43405,1231.8297,1026.3804,-278.18692,979.76416,779.3892,184.01277,989.8747,805.6764,-183.39565,796.6068,868.97687,225.3988,797.5533,889.6478,-115.58468,617.89014,934.3239,383.63242,598.62976,958.2944,33.88506,579.10333,941.4023,391.84143,556.6651,966.8547,25.92529,638.91425,1007.141,271.73337,626.24084,1031.3854,-156.61058\r\nframe__ygMpEPT_86c__0012214.jpg,pushups_up,1454.3892,624.3962,14.605648,1466.6722,600.61316,39.96223,1464.9838,597.04706,40.103817,1463.3799,593.82245,39.982826,1466.2775,600.76917,-28.897984,1465.4034,596.9503,-28.947483,1464.4365,593.1988,-29.279367,1442.1078,569.58734,180.4908,1445.4977,568.9394,-133.53973,1426.7128,621.8054,75.251465,1427.2393,622.745,-16.04651,1284.2534,584.22144,385.81485,1332.9343,596.8031,-258.78833,1264.3153,762.35077,481.3135,1328.908,800.0331,-328.99033,1282.4143,901.4153,376.48026,1353.4105,978.6792,-298.06778,1318.6251,909.8996,406.10864,1397.4397,1009.3485,-365.46844,1322.1487,919.2364,333.6672,1405.6632,994.038,-296.70883,1308.2408,923.59924,348.22107,1386.132,990.1596,-271.64865,957.3811,568.718,209.31802,961.6035,563.3962,-208.5503,785.9338,729.1936,317.06808,722.82855,736.96045,-220.94318,563.5042,814.78357,489.10657,471.24814,899.38715,-146.55121,517.14764,816.6912,497.64377,416.6083,908.8867,-151.08914,557.8067,887.68445,400.50284,490.84482,992.2838,-320.30173\r\nScreenshot_2021-02-11_at_14.21.06.png,pushups_up,1248.6761,552.2581,-1202.3972,1250.3601,515.04803,-1182.9009,1254.6517,512.7927,-1182.754,1259.3606,511.08508,-1182.7852,1227.9601,513.99927,-1223.7997,1216.8593,510.59525,-1223.9204,1205.7333,507.3054,-1224.0073,1232.6456,492.563,-957.77295,1160.6661,485.26825,-1131.2941,1231.0834,565.3328,-1099.6022,1208.8414,560.976,-1150.0161,1214.5984,530.4238,-692.4298,979.32,545.6987,-1002.98175,1324.0471,690.19745,-490.05533,896.7716,785.34863,-1026.0654,1378.5165,847.3804,-527.927,907.0058,996.56323,-1067.9087,1422.0128,868.8433,-597.7236,897.17645,1042.8845,-1178.2961,1396.8062,881.6601,-662.3532,940.45233,1031.9283,-1204.3802,1362.7737,879.59106,-556.1074,945.2291,1018.7181,-1084.7423,920.53015,647.97284,123.820465,798.9205,632.9395,-124.07278,850.7132,838.40466,571.19366,667.9445,790.5808,445.43488,730.687,896.2779,1254.2705,531.9261,900.0859,1093.5543,701.0873,885.05475,1318.9268,501.51904,902.71265,1149.0824,730.4798,996.5668,1227.2742,529.64307,1003.55005,981.63983\nScreenshot_2021-02-11_at_12.03.51.png,pushups_up,1200.322,443.15912,-1691.4021,1212.1495,387.54572,-1700.5219,1227.681,380.55148,-1700.7726,1243.4567,373.32013,-1700.7571,1164.7402,400.36133,-1675.1381,1149.1047,401.24036,-1675.1962,1133.487,402.68054,-1675.5662,1272.9712,337.0026,-1479.6597,1117.3235,380.324,-1373.7458,1239.3053,442.8228,-1588.17,1189.3062,456.56454,-1558.2892,1430.8038,397.8026,-1228.5769,1067.2823,450.665,-1059.0479,1523.8427,714.82355,-1295.163,978.9131,745.64594,-1157.0045,1566.6915,1021.5723,-1424.8635,874.09204,1038.8881,-1272.7369,1603.8872,1070.4938,-1552.6437,799.1606,1084.2946,-1334.6724,1563.4324,1072.0884,-1576.3842,824.5107,1088.8584,-1426.564,1537.5203,1054.367,-1445.4702,868.9766,1074.3898,-1323.4393,1402.8394,582.4861,-62.032555,1240.1321,603.177,62.15358,1442.2637,723.64996,650.55225,1285.4172,737.374,822.32825,1463.3057,792.2706,1449.6932,1311.6653,800.97754,1659.06,1462.8485,783.4997,1523.7301,1319.0214,797.28955,1743.2882,1468.7151,891.248,1307.2496,1303.5052,875.87683,1539.4325\nframe__zSJYAyoojdw__0002983.jpg,pushups_up,2797.2793,985.52057,-944.28516,2845.5474,925.2739,-941.97107,2843.2012,915.95325,-940.76624,2841.3167,907.35046,-940.9915,2835.0886,927.93866,-1092.4845,2828.8374,916.30646,-1093.257,2822.291,905.0599,-1093.5857,2781.5012,826.637,-686.9651,2759.0725,815.2404,-1396.4725,2718.944,960.70776,-819.74194,2714.5303,956.627,-1025.5295,2499.249,818.6957,-140.07265,2359.8892,818.45844,-1475.78,2537.8564,1315.3539,186.92197,2299.5608,1361.0148,-1493.1827,2550.8508,1676.6302,-29.299492,2291.164,1862.1433,-1505.91,2654.3496,1670.8936,-63.54053,2377.2378,1930.9775,-1725.4662,2649.7737,1691.7603,-277.10175,2432.7856,1883.8395,-1650.086,2588.6855,1703.6396,-129.13959,2398.9902,1873.0812,-1489.1997,1750.5646,881.5778,451.60403,1609.4935,850.70795,-450.4717,1708.7339,1293.3252,1252.6996,1071.0427,1259.4406,-278.6798,1454.2891,1324.853,2217.446,532.53516,1559.5007,-6.686852,1368.6653,1305.5055,2307.6682,417.75397,1575.2721,-27.888819,1525.482,1542.7207,2341.787,571.80884,1830.331,-493.234\r\nframe__F4VlpHLVqaQ__0006132.jpg,pushups_up,564.06323,545.841,-78.23381,548.7289,519.55176,-133.22122,550.6853,516.4741,-133.19133,552.5877,513.02924,-133.41772,547.08167,516.8801,-75.937645,547.7433,512.2109,-75.8664,548.8287,507.7066,-75.76788,575.5099,488.759,-240.4785,568.3641,482.14508,26.850983,594.00336,546.1829,-101.65448,591.63916,543.1537,-24.80386,703.0281,549.8027,-341.9218,747.3856,481.17407,274.40222,685.1724,785.7239,-395.72174,741.104,686.9061,364.18237,675.49475,983.54126,-336.5069,722.4393,838.46027,240.25778,617.563,1002.28375,-406.00122,669.0649,821.39545,250.73773,614.87146,974.2597,-330.9553,664.11475,838.7756,174.22617,638.8797,967.8662,-307.83487,684.9869,853.79736,204.6456,1124.263,597.3686,-186.9917,1134.888,553.43365,186.97716,1368.8901,731.33997,-2.3724601,1313.9805,691.75305,397.55154,1614.0498,809.18866,153.00975,1521.9656,753.32306,640.23444,1667.058,792.2338,163.14993,1572.8376,736.00604,661.68353,1599.5249,903.8368,46.248978,1518.1595,859.5904,599.61945\r\nframe__71_FhXo2x0M__0022780.jpg,pushups_up,494.79996,423.37308,-419.2918,478.88312,394.08432,-414.88782,482.57837,384.90082,-414.90942,486.22546,375.4189,-414.7347,471.32327,413.9447,-384.9123,468.9592,419.75912,-384.73398,466.8913,425.79538,-384.6698,513.7565,357.99045,-289.692,486.98907,421.50183,-152.29187,530.6456,411.73547,-363.2306,519.3869,440.9117,-323.86554,642.2877,448.70663,-432.44028,652.2409,416.9195,248.45071,622.5599,701.0275,-468.33932,656.3137,618.93896,240.54442,608.42377,904.10126,-404.78125,632.36804,799.41345,3.9426873,562.53864,927.53265,-499.69077,583.8677,811.66925,-21.00805,555.6682,911.4402,-438.37756,583.5125,818.567,-113.2741,576.7278,899.14435,-386.42694,604.4457,818.42847,-43.709225,1040.9163,509.83643,-207.03023,1035.5856,501.21085,206.44809,1313.8563,642.7387,-144.80644,1293.9125,640.2189,255.9252,1601.6196,746.0466,-60.357708,1555.6924,728.85846,372.28983,1673.4393,735.95776,-62.235,1617.9231,724.0992,373.72076,1567.1118,849.592,-202.64246,1545.8595,834.5497,257.92517\r\nframe__YHKStY2-e9M__0000500.jpg,pushups_up,520.0674,684.07916,-13.806772,499.92874,667.8923,-62.282158,499.6875,664.8778,-62.23144,499.43607,661.51373,-62.396248,499.95792,666.1705,-1.9577967,500.20856,660.8757,-1.9469093,500.6991,655.75195,-1.6721098,509.5994,628.8436,-173.3418,508.58105,623.6683,103.62113,541.66095,671.79956,-45.443607,542.51434,668.53955,34.467453,627.1259,612.47296,-311.59882,652.94214,609.75586,316.40872,637.32434,794.30695,-426.55127,673.7414,781.0762,374.73746,636.6905,977.07983,-420.6892,650.76965,926.776,206.28833,595.9,992.46246,-493.98587,604.63745,929.2505,219.26143,595.5161,982.9638,-432.63904,600.3555,935.7823,148.6811,608.983,977.31616,-401.83566,616.2234,938.85956,170.77391,970.13007,682.3295,-199.0076,966.3192,687.62695,198.75958,1234.6595,821.83466,-170.47308,1201.065,797.9338,190.86778,1502.8645,881.7172,-140.64137,1464.0443,847.0733,259.06805,1561.3486,866.0304,-150.67877,1521.2002,838.33624,260.63693,1470.7999,981.9419,-324.51514,1443.3821,951.26843,149.62198\r\nframe__SOyAVe-cUzA__0004090.jpg,pushups_up,1426.6252,392.64517,-384.40457,1459.3113,386.44525,-354.52856,1459.4319,390.7756,-354.14346,1459.784,395.22354,-354.12738,1457.0828,366.85623,-400.0771,1456.4978,355.05066,-400.13824,1455.7515,343.42157,-400.45908,1442.0323,371.97177,-134.11111,1437.9563,305.17746,-333.21606,1393.8748,393.0638,-290.82455,1392.155,364.26672,-348.70096,1272.3474,305.08444,156.76291,1278.0311,335.89584,-432.12137,1224.2026,510.68552,200.52562,1242.7334,575.9244,-495.4791,1207.681,691.7138,62.3356,1235.1134,810.6275,-473.32666,1251.9331,694.4235,42.486664,1273.3116,835.13385,-558.0954,1256.4375,712.6881,-42.794563,1290.2577,821.4408,-518.64435,1231.3236,718.91656,20.989933,1267.8108,811.0292,-458.16705,835.23065,363.5824,177.03217,813.2801,393.23038,-176.46043,569.70654,469.72678,341.1974,533.35315,516.21814,-24.713722,328.57385,518.2434,525.1324,253.4392,582.6775,89.26778,276.47266,506.17432,535.3587,188.81888,572.6691,75.45039,320.78763,635.8635,418.89932,276.59763,705.1242,-136.24103\r\nframe__joNzM16CASk__0017639.jpg,pushups_up,643.0955,733.947,172.52795,631.4188,722.4273,135.77477,631.52094,721.3357,135.76677,631.4676,719.9577,135.72743,632.93646,719.23834,184.53517,633.95294,716.3033,184.42873,635.1718,713.2887,184.38644,639.9879,707.4269,11.398478,644.93646,698.9777,237.83122,657.60345,734.53827,134.33691,658.6686,731.60376,200.45795,692.99744,722.8385,-116.82591,743.2752,674.0531,372.11667,727.907,819.32495,-110.62017,792.8983,754.5865,490.60815,736.52167,924.8889,-21.043463,792.3707,845.5597,479.26038,718.3392,944.8961,-57.186684,773.2578,847.5505,520.9563,711.92004,935.81616,-4.9995484,766.93195,862.29645,472.0782,719.6701,926.9144,2.4661703,772.34106,867.5051,460.36963,888.7303,700.1132,-160.77718,908.6993,668.8365,161.15677,1020.656,779.899,-118.34052,1023.8174,769.6307,290.66412,1178.3865,848.9898,-38.944546,1164.0519,825.68646,448.82504,1212.7805,845.29584,-36.767353,1197.0555,821.8384,462.90778,1169.3849,918.37555,-125.75672,1164.5629,886.9496,419.98557\r\nframe__JSn5DY10dbA__0019114.jpg,pushups_up,828.58026,597.1633,-1074.2433,830.2776,573.3381,-1105.478,836.2682,569.7063,-1105.3225,842.0681,566.0081,-1105.0132,815.07416,577.4191,-1062.4714,809.7345,577.14026,-1062.2915,804.9684,577.052,-1062.27,857.7927,537.1133,-1054.367,806.93,554.21643,-866.243,851.15607,589.8591,-1039.5055,835.3716,594.8647,-985.28595,953.8315,512.4053,-907.6433,797.7811,564.9828,-587.85504,1044.2688,737.869,-928.555,792.00323,747.1789,-535.93365,1067.6709,950.21533,-944.0883,759.1572,923.0861,-590.2857,1081.1356,993.9024,-1035.4724,721.45337,952.84607,-622.7375,1051.4657,988.88477,-1035.9171,729.50104,963.9476,-690.07495,1047.0142,971.69586,-948.3437,753.0746,953.6868,-616.19196,1071.8754,523.97736,-108.993706,986.26855,550.6074,109.81935,1018.88257,686.41187,-428.07358,939.2527,721.8514,121.138145,1058.054,852.1744,-52.226482,934.95264,855.5119,663.09546,1073.0735,867.58636,-13.909655,943.1247,869.46484,711.77246,1024.0732,918.4146,-175.42003,912.5161,913.04645,635.3307\r\nframe__X_ZJpZgRecI__0009935.jpg,pushups_up,1075.4888,522.4373,-1067.9977,1096.7778,505.81094,-1067.9004,1105.4617,504.2444,-1068.0374,1114.2622,503.1879,-1068.3485,1071.8446,500.0573,-1102.6338,1063.6656,495.24683,-1102.6022,1055.1721,490.56396,-1102.7092,1122.1875,479.6422,-924.5306,1046.2284,456.1166,-1082.2175,1072.6805,517.63684,-997.3988,1049.4487,512.8076,-1042.4236,1144.3914,454.60324,-730.03845,922.17365,429.879,-968.9977,1157.2567,650.3968,-588.31555,855.4455,666.14087,-1017.2818,1175.1493,837.00305,-712.0772,875.4621,864.5608,-1070.1097,1218.9554,873.659,-790.7625,876.9643,906.775,-1182.5157,1200.9282,872.5246,-852.6822,916.8716,891.7185,-1185.9998,1167.5173,859.67706,-741.2123,919.28876,880.96515,-1084.5289,870.366,472.69443,116.76355,771.81024,452.63925,-117.06135,766.53687,526.869,734.7309,679.8795,536.19037,561.2793,684.3873,520.99695,1409.2432,618.6417,550.761,1217.5936,667.31775,504.07047,1480.2992,607.79846,536.0467,1284.9281,675.1707,578.6461,1450.2775,610.77405,620.90204,1242.9445\r\nframe__RTF4ADblouI__0008234.jpg,pushups_up,2963.9478,923.25183,-833.59576,2988.641,836.67004,-825.9702,2985.6084,830.69324,-825.5953,2983.2769,825.76544,-826.49005,2974.536,834.8767,-950.5885,2961.8503,823.31586,-951.21265,2948.6929,811.8253,-951.24615,2890.5972,765.191,-582.9446,2844.7764,742.6832,-1124.5345,2868.2505,935.7911,-718.7973,2854.8906,928.18054,-874.83295,2574.4065,941.7785,-235.38736,2317.7925,834.2317,-1200.766,2537.0251,1432.7402,61.63018,2158.8599,1451.763,-1184.7786,2701.7524,1868.9194,-235.61313,2481.0405,1886.2949,-1286.0454,2816.521,1901.328,-356.80307,2602.3516,1965.5112,-1548.056,2821.1619,1919.832,-544.80505,2676.9717,1882.6462,-1537.8973,2743.3652,1913.241,-333.92892,2628.4712,1870.7473,-1308.1017,1542.6813,1241.9756,330.60052,1391.9208,1148.6049,-328.36063,1017.1361,1478.4426,836.946,851.2584,1405.8694,333.895,499.9793,1501.6085,1612.5092,339.75427,1531.4639,977.5525,393.1644,1438.247,1679.6968,229.72583,1483.3392,1022.82715,425.87186,1727.3077,1469.3754,312.12787,1810.221,714.0966\r\nframe__dxA21IeBB8o__0004722.jpg,pushups_up,2434.5273,1543.9329,254.69,2473.9202,1527.3489,293.8691,2474.461,1519.6884,293.99405,2475.1333,1512.359,293.64807,2475.4634,1531.613,173.0653,2478.7454,1526.6355,173.05608,2481.9329,1521.8807,172.87662,2480.2188,1466.4357,468.86835,2492.3464,1479.2521,-77.33089,2413.4329,1517.9446,336.71637,2417.8828,1523.1384,177.17235,2301.2197,1367.9166,825.5482,2380.671,1455.5278,-357.8635,2257.9592,1642.6182,912.7725,2332.3188,1708.4557,-590.5166,2270.9893,1833.1178,523.6854,2337.7568,1954.7628,-549.73834,2344.688,1837.6215,578.4366,2415.9292,1981.5366,-666.3173,2344.9985,1858.232,424.23132,2418.233,1946.3079,-519.1662,2322.2512,1867.3185,453.08374,2388.5554,1944.6781,-489.5292,1879.0293,1382.016,360.8382,1899.163,1423.9497,-360.06564,1553.3651,1613.7831,396.06476,1582.9058,1620.9285,-271.49902,1199.7332,1712.9513,604.21484,1176.8605,1746.3289,-43.457115,1134.2484,1708.0186,613.7565,1099.7294,1740.3972,-47.009384,1200.6292,1840.9342,403.0886,1188.1252,1897.7688,-308.26422\r\nScreenshot_2021-02-11_at_15.31.44.png,pushups_up,945.4541,565.0522,-1041.8944,945.37103,528.2163,-1102.8761,953.85376,522.1207,-1102.4111,962.07776,515.9822,-1102.2576,930.2772,533.09143,-1027.0221,927.63184,531.3205,-1027.1853,925.47345,529.80914,-1028.0541,998.81384,476.32227,-1154.7972,947.9679,496.19107,-800.98303,989.4786,555.9755,-1044.2281,973.8343,563.3663,-940.5296,1206.3844,468.39774,-1065.6252,1014.3635,514.3717,-528.39435,1247.121,768.9342,-1046.7588,963.9085,724.86176,-343.78073,1258.2295,1017.2509,-1096.7548,914.9871,913.1084,-393.02826,1252.3948,1074.7076,-1252.2413,859.074,924.177,-448.60413,1205.1362,1037.0072,-1231.7272,869.657,941.18616,-553.8733,1206.3622,1023.20605,-1104.9331,905.9701,939.6701,-440.81458,1545.2692,462.9493,-209.0825,1445.6575,507.314,209.6686,1773.9487,634.8413,208.01741,1641.7723,647.5728,676.0056,1989.9275,735.7182,678.346,1827.3871,739.37305,1286.7875,2040.7957,734.26447,715.5215,1874.2006,738.2448,1344.0798,1968.9968,853.6794,549.02594,1827.342,844.6032,1260.292\nScreenshot_2021-02-11_at_13.19.30.png,pushups_up,1269.3591,482.08133,-1912.9368,1298.1803,402.7955,-1918.256,1324.9202,396.32544,-1918.631,1351.9958,389.6937,-1918.6803,1218.9525,408.40735,-1917.8033,1190.1125,406.42087,-1917.9017,1161.5476,404.79694,-1918.0321,1389.4283,363.5561,-1638.5122,1119.8842,383.63452,-1620.9214,1315.7,511.5932,-1781.906,1229.4845,519.09296,-1776.063,1534.7596,492.85144,-1233.4857,1039.5524,483.81592,-1176.4905,1633.6138,765.69916,-927.684,988.71375,737.2039,-829.2286,1594.205,1062.434,-1103.4019,950.7912,1026.3676,-965.7748,1627.1014,1119.8463,-1265.1377,902.2171,1075.4736,-1066.9479,1564.4915,1118.2146,-1321.3657,949.82477,1086.6843,-1163.0447,1534.5691,1092.8767,-1139.3772,993.4338,1066.8279,-1019.2354,1391.5527,623.11176,-22.013264,1168.8666,614.5713,22.50708,1386.603,670.2649,850.7799,1211.3124,669.01154,912.6505,1407.8003,635.80505,1780.1333,1246.1444,631.2461,1831.8177,1403.706,607.0294,1886.5642,1261.5215,602.343,1941.5046,1395.4999,721.62994,1767.4647,1252.0857,713.02075,1828.0524\nframe__BqV0WSuHoYM__0001054.jpg,pushups_up,1423.1228,1466.6782,-194.98143,1389.6293,1441.9186,-307.91354,1390.0271,1437.1405,-308.22424,1390.3093,1431.8915,-308.34497,1387.4229,1436.815,-188.13557,1387.2317,1428.8501,-188.00237,1387.5612,1421.0874,-187.59029,1405.8778,1380.8291,-499.11353,1402.2283,1370.3936,49.515896,1459.4991,1446.9535,-250.06015,1457.726,1440.1516,-92.036766,1579.8525,1375.3512,-738.5051,1613.308,1336.627,506.81854,1602.2048,1678.2063,-965.65454,1638.9933,1607.7166,569.54877,1593.0505,1931.7388,-1071.1743,1643.4475,1820.0226,221.86555,1513.8132,1952.8798,-1241.8921,1570.8494,1814.7583,240.94815,1509.4486,1924.7087,-1103.3287,1566.9078,1830.561,73.90587,1540.3489,1919.6763,-1023.2543,1590.8102,1841.9059,141.57231,2043.1785,1403.0043,-396.12936,2034.0933,1374.6724,395.9821,2382.2207,1685.2843,-438.57492,2330.7476,1621.062,519.58386,2739.2627,1861.9686,-363.52237,2638.7664,1747.413,822.36444,2830.4578,1872.0016,-397.98642,2719.1365,1749.8159,843.2739,2669.0374,2036.5271,-796.3628,2610.6133,1923.8649,601.9225\r\nScreenshot_2021-02-11_at_13.13.01.png,pushups_up,1244.0762,591.36127,-1405.7441,1263.5234,566.3238,-1411.5975,1277.6504,565.5761,-1411.6627,1292.1768,565.1837,-1412.0402,1225.5812,562.39233,-1428.4233,1212.9791,558.84705,-1428.1926,1199.9985,555.778,-1428.23,1317.0164,553.32306,-1224.357,1191.7157,532.60706,-1296.6567,1270.0541,602.0289,-1310.683,1227.9324,595.7928,-1331.7589,1397.0522,584.9245,-934.6493,1138.1311,532.437,-1199.7444,1418.806,802.5338,-988.89526,1096.9032,800.5409,-1364.1918,1416.1234,999.89453,-1237.3148,1164.2356,1009.4982,-1480.8007,1441.4537,1055.9221,-1330.2664,1162.394,1061.7717,-1601.4999,1412.252,1036.0496,-1420.8527,1209.8131,1050.1217,-1607.7318,1392.3113,1016.32874,-1276.4524,1215.7275,1035.7251,-1488.3889,1197.6782,651.8539,104.77093,1070.087,623.86096,-105.28647,1220.3853,830.5836,-32.90641,1001.79584,842.49963,-255.52922,1202.9307,749.05084,544.54486,1105.932,730.2725,480.52692,1208.1804,723.0855,615.57324,1134.4646,696.9341,564.8891,1194.0676,792.8989,769.68097,1101.9034,771.0504,811.1249\nframe___qNmbXRZtfY__0009066.jpg,pushups_up,1226.7477,770.8562,-195.33679,1239.7275,750.00244,-176.74979,1237.9183,746.60876,-176.52345,1236.3406,743.38873,-176.31981,1239.6605,750.5963,-238.3972,1238.5187,746.9093,-238.47887,1237.3069,743.4052,-238.6302,1219.3971,717.72107,-42.307274,1220.5394,717.21893,-321.35788,1203.8667,763.6949,-138.68716,1204.5806,763.8976,-219.15894,1114.8,734.73334,195.85736,1116.5103,730.12024,-457.3351,1133.1455,885.52234,214.21451,1142.7695,886.1694,-602.67865,1129.4952,1005.1973,-4.3674483,1161.9924,1044.7194,-696.98596,1163.6177,998.4875,-13.314992,1196.486,1049.6035,-813.0948,1164.3125,1000.46674,-102.5461,1198.5814,1038.8859,-745.95465,1152.5981,1006.91925,-51.206886,1186.4996,1037.6636,-676.55505,886.86707,805.2279,185.36017,877.20135,803.89996,-184.5068,695.0589,897.9549,180.66089,689.1195,921.066,-237.43149,520.7964,983.363,269.2167,483.48358,1001.0548,-156.83235,481.09726,994.8986,265.9965,435.94037,1010.3004,-181.63646,545.9586,1050.5345,86.28545,526.1253,1084.9685,-435.12115\r\nframe__9d0VKo-LnL8__0005803.jpg,pushups_up,653.84296,745.8264,-567.53455,645.9004,729.3606,-601.44867,648.9927,725.9171,-601.2012,652.0589,722.34766,-601.15375,640.8532,731.646,-547.29913,640.5827,730.0544,-547.2059,640.4349,728.53827,-547.3168,671.18353,703.16534,-658.98047,656.42944,712.8232,-403.2365,680.61847,740.7653,-584.9989,676.68616,743.4639,-509.30353,788.5988,700.87836,-672.1353,712.24286,689.36176,-148.4208,835.22284,853.7035,-728.582,726.65436,798.00195,82.38585,849.8225,989.00574,-799.22534,726.99896,906.47516,-24.278625,836.0619,1015.613,-925.87885,693.5874,920.49146,-68.14524,813.6105,1004.66284,-899.25653,699.7342,920.68005,-146.24532,822.1043,998.05096,-797.989,722.9711,915.6204,-59.95915,991.96173,713.66614,-186.08893,942.7492,712.65753,186.19995,1119.2869,754.26917,289.21313,1066.5466,742.877,606.41614,1227.3884,769.446,773.68945,1151.9493,767.1585,1105.8933,1254.2605,756.0199,815.59314,1175.4012,755.493,1156.4757,1224.408,845.5135,709.6849,1156.9474,832.85675,1107.0315\r\nframe__ihCpHCvZ4Ok__0020171.jpg,pushups_up,1031.0641,557.3601,-1081.2725,1045.741,539.8215,-1093.9801,1055.4756,540.00696,-1093.6925,1065.0854,540.08514,-1093.7426,1021.95306,534.31287,-1093.9697,1014.3607,530.8195,-1093.5857,1006.9108,527.01,-1093.3866,1086.6908,522.04663,-956.4937,999.6792,503.30066,-958.9,1047.5695,555.51117,-1009.6566,1021.22656,549.3179,-1009.29553,1178.1554,531.73804,-721.995,925.5503,505.26562,-712.9287,1228.579,651.0445,-650.20575,841.1065,634.81305,-684.80975,1209.5392,825.6287,-763.0615,828.875,789.4148,-831.11975,1217.3014,866.0836,-837.4458,802.603,824.6912,-910.12,1188.4595,865.7151,-843.65607,834.15283,828.96875,-936.22327,1178.146,847.75696,-769.7129,853.05365,817.2667,-847.96515,1124.3866,449.9562,-17.037798,1004.3194,429.65405,17.18662,1149.7256,465.30362,481.66925,1032.5734,421.1398,480.94946,1122.3519,418.9299,1050.1465,1064.0164,388.89594,1037.6597,1117.7864,406.84525,1114.0824,1074.1355,379.18112,1100.9452,1124.5836,445.21817,1096.2296,1066.733,416.07214,1084.4254\r\nScreenshot_2021-02-11_at_13.38.33.png,pushups_up,1188.7256,428.56964,-2019.3025,1223.8496,362.23428,-2011.0372,1244.4642,358.86618,-2011.0359,1265.3907,355.27997,-2010.8397,1158.5804,360.5441,-2004.104,1137.7366,356.22504,-2003.9893,1116.6761,352.20862,-2003.6305,1298.2097,332.94336,-1693.2015,1083.6407,325.97687,-1647.1561,1220.319,455.1478,-1881.1592,1152.9602,452.65094,-1865.8491,1436.2476,507.36218,-1391.6393,924.25287,478.10147,-1344.285,1504.0154,871.94446,-1526.3334,861.1109,841.77405,-1434.1095,1540.0128,1210.5829,-1767.3489,829.3312,1165.4436,-1653.309,1587.6517,1261.7238,-1959.9688,789.828,1214.3762,-1816.3383,1514.611,1256.9208,-1991.2944,853.63403,1211.8566,-1855.44,1485.3679,1246.1174,-1800.3107,882.84705,1199.7568,-1686.2863,1247.7482,828.92145,-36.15766,1035.7961,817.7216,35.343513,1172.5519,978.73254,1020.9977,1012.7711,957.71326,1028.6357,1164.6821,999.1304,2148.8643,1027.465,1003.2612,2172.9312,1155.6958,972.41766,2268.6094,1041.6237,980.65015,2288.9438,1147.1595,1100.205,1979.7354,1035.293,1108.1685,1996.3483\nframe__SdnNJKUOXsQ__0008959.jpg,pushups_up,1288.5203,760.4076,127.163445,1303.2896,744.97156,148.34634,1302.5243,740.9773,148.4907,1301.8489,737.22217,148.31728,1304.2666,748.0684,85.60894,1305.023,745.84265,85.49065,1305.6992,743.6448,85.29725,1293.3019,713.15967,245.4907,1300.1138,722.9325,-39.742584,1271.2385,751.51227,170.57144,1273.062,755.06494,87.42696,1182.1628,694.7978,410.92502,1226.2653,726.11774,-167.53609,1168.0579,820.52734,515.3092,1208.7302,851.0696,-255.88698,1186.0425,925.36383,428.153,1218.647,967.9137,-233.44002,1215.8553,934.70593,457.38654,1253.8213,990.04126,-289.58563,1215.9974,948.0315,400.96606,1256.0494,975.76324,-231.0603,1205.5663,949.4722,404.21002,1240.6995,973.5689,-212.27188,944.08093,679.3725,190.5135,959.1922,688.8274,-189.79706,773.9555,786.6352,205.70422,784.2669,798.8323,-183.88326,598.5456,862.9097,265.6153,582.88916,897.8472,-143.62811,559.32434,864.12537,261.53665,539.40857,895.51276,-149.3616,605.8033,930.7094,150.03464,592.5611,979.51245,-280.8796\r\nframe__TwOuh73cGGQ__0010712.jpg,pushups_up,1224.3726,778.6079,-561.1026,1241.2732,766.1024,-565.9321,1242.7402,762.0225,-565.7132,1244.3192,758.2788,-565.6872,1234.6318,768.96954,-629.29297,1232.915,766.1206,-629.4183,1231.0012,763.4165,-629.46674,1240.3657,725.58575,-465.10623,1224.7977,728.6111,-767.5089,1210.8754,759.32904,-507.8504,1207.9187,762.35535,-594.5188,1221.6742,674.7702,-261.3373,1127.5255,705.15125,-764.1021,1237.2339,801.0295,-122.068016,1119.565,842.0606,-866.64557,1244.6986,913.03784,-254.0109,1132.1244,957.16754,-965.60693,1270.481,917.8309,-303.33572,1151.3375,977.5008,-1084.5597,1271.3599,922.53503,-388.82687,1170.8453,964.3071,-1062.7595,1253.2623,923.8205,-292.8203,1164.2318,961.80914,-967.2655,1001.29407,680.3273,178.5062,943.6342,692.7735,-178.04521,966.3002,781.52734,631.14526,834.03394,790.6864,46.931747,904.64655,814.7974,1172.8312,683.2706,843.5534,339.10498,883.43225,814.7756,1222.3645,650.29724,841.32404,353.331,931.47437,873.8396,1169.9061,691.0809,910.16425,185.0378\r\nframe__J4sTsUuJzcw__0003415.jpg,pushups_up,380.408,437.7688,2.052853,375.547,428.0318,-23.339138,376.01883,426.71756,-23.33461,376.44373,425.2306,-23.473206,376.21902,427.61533,17.818226,377.24136,426.021,17.866682,378.40637,424.45966,17.946775,385.78192,415.70593,-79.763916,387.38785,415.40436,105.348724,390.7826,437.85916,-14.169926,391.7171,437.10934,39.31463,430.48325,428.72003,-178.57698,459.7309,421.00613,239.26927,425.94427,509.63242,-250.49547,465.89246,501.6235,243.20221,424.62033,597.36676,-245.77573,458.71606,575.8062,98.67867,407.57004,603.87964,-292.6185,442.6004,574.6783,97.44234,408.40637,599.11536,-252.95753,439.2453,578.59985,48.092976,415.95508,597.08734,-230.98192,444.773,581.63403,73.47537,590.03296,446.63165,-133.48157,597.30505,438.62198,133.64104,707.6386,513.0373,-101.49704,706.435,503.8257,132.56386,831.0037,555.47314,-57.72549,821.8317,547.3746,194.89127,855.88306,549.91486,-58.971157,843.2547,546.9771,196.75706,822.37146,603.0767,-157.59782,821.94147,589.79,114.21235\r\nScreenshot_2021-02-11_at_11.34.26.png,pushups_up,1205.0557,726.02844,-1345.3392,1236.9749,709.56226,-1374.7874,1257.514,707.38806,-1375.6871,1278.0867,706.236,-1376.3956,1182.5781,700.35974,-1395.0736,1165.371,694.6526,-1395.0109,1147.7567,689.17303,-1395.4763,1320.3219,691.2418,-1286.3053,1149.8177,651.31116,-1372.275,1234.942,729.5496,-1283.1045,1180.0385,724.6368,-1305.6716,1455.2078,670.0524,-1121.6821,1041.5549,555.03534,-1210.327,1574.1655,865.5003,-1080.074,850.76013,791.3201,-1213.6229,1600.877,1065.1144,-1385.6399,825.0071,1083.5846,-1255.5098,1660.8605,1118.3396,-1457.07,793.80536,1151.4197,-1366.9393,1617.8547,1123.4551,-1518.1122,860.6796,1149.0604,-1383.0577,1567.8357,1110.8475,-1410.3354,881.7348,1126.1035,-1272.7577,1134.2238,692.4561,59.47396,964.5349,629.53925,-59.70744,1130.9415,758.10364,703.68097,971.2056,770.1205,737.89197,1102.8285,776.5539,1490.5776,1021.79034,816.8708,1631.3744,1099.6737,763.8027,1577.8676,1034.6154,807.75,1728.495,1100.7191,822.90186,1550.3087,1026.427,889.2795,1770.8054\nframe__eOWJsw_ARB0__0010643.jpg,pushups_up,567.9257,662.9683,93.3879,559.3651,646.17883,54.58774,560.00116,644.2364,54.61092,560.5427,641.9716,54.4303,560.8873,644.99817,116.15886,562.47906,642.33124,116.22045,564.32965,639.5672,116.4815,574.32495,628.53674,-48.066216,578.6435,625.11224,237.68248,585.24146,665.6185,64.45632,586.37164,663.8435,146.7966,642.0202,665.92554,-213.69907,693.2351,632.7605,437.64914,651.6944,803.3713,-295.1535,722.2193,748.96747,506.78714,653.16925,917.20435,-249.09131,711.3815,840.0742,331.7523,628.55493,929.6641,-303.8386,688.86395,835.9833,347.9404,628.2214,916.80585,-246.70183,681.65967,847.2015,282.9855,639.4074,910.9481,-224.80936,687.6487,853.9868,299.8461,910.7405,701.1373,-207.01988,925.084,677.2613,207.34543,1101.4503,785.6809,-253.3558,1093.6752,770.47327,297.09204,1308.8585,871.9225,-291.22342,1280.0195,830.12115,449.74933,1346.9957,867.4631,-301.91718,1316.4009,828.88354,461.4501,1311.9554,950.6034,-438.04996,1290.9302,892.882,378.8727\r\nframe__1Benc0pfoFE__0010609.jpg,pushups_up,596.02637,676.7662,34.41253,598.8619,660.23926,1.1807396,601.00366,659.85754,1.13742,602.96515,659.1389,1.0012696,599.67395,657.1954,60.477005,602.2697,654.7647,60.461975,605.0432,652.43445,60.427853,624.7498,657.0269,-78.14984,626.0598,649.3705,183.68977,611.70465,689.8838,10.627858,612.037,686.8561,86.48516,693.36066,723.37976,-240.96523,743.4508,705.21387,380.3226,705.3121,883.3276,-289.13312,759.1063,862.5176,392.3451,696.16223,1037.4379,-272.98535,753.12646,994.70123,255.35829,661.92236,1049.4949,-346.26987,723.12415,987.20087,269.34525,661.1911,1037.6208,-278.08667,719.35767,997.6736,192.2678,674.6673,1033.9623,-247.7019,728.6213,1006.31226,218.94092,964.439,781.8608,-194.56488,985.4668,766.7015,194.75421,1188.0414,867.75977,-161.69191,1185.4692,865.2769,170.04475,1404.5691,937.31903,-109.82065,1398.3981,926.6943,243.82082,1442.3472,932.7777,-111.726906,1436.8116,924.7874,245.13556,1406.204,998.0736,-269.3515,1406.2372,985.43164,108.399185\r\nframe__pBo_DjHqVws__0003267.jpg,pushups_up,1616.2045,391.7891,-132.62051,1627.4688,373.60867,-114.54897,1624.9813,371.88132,-114.098015,1622.6768,370.3754,-114.069695,1626.2156,371.42838,-173.67482,1623.9666,367.17657,-173.57854,1621.5494,363.0609,-173.84503,1590.0394,359.98346,30.34324,1590.4325,350.01852,-238.08702,1580.6923,400.86832,-66.77535,1580.5225,395.55682,-144.90228,1395.7225,376.0761,325.54456,1445.991,421.87808,-381.0899,1378.0938,565.7692,418.31848,1444.0117,639.42847,-425.00143,1386.1929,722.2543,280.50226,1469.3213,849.172,-389.0206,1428.9121,713.72894,291.953,1520.7598,866.9503,-469.56668,1432.4482,733.4395,193.64178,1525.3445,851.5514,-409.9557,1415.1508,746.66656,238.16623,1500.4309,847.358,-365.50735,1005.68036,433.85522,224.42642,1020.93616,460.5859,-223.78339,733.26495,560.73193,367.9984,726.02734,590.5049,-118.80049,464.34952,626.00934,536.96094,423.86307,678.61145,-12.695987,401.7615,619.525,545.584,358.2656,677.0619,-24.347107,479.11697,739.83844,444.76105,446.79303,795.70386,-206.75024\r\nframe__wBy8-ilMe4c__0001531.jpg,pushups_up,912.05524,477.31567,-1511.469,930.3446,458.1931,-1496.9558,941.21063,457.05066,-1496.9436,951.84015,455.92725,-1497.5035,902.1412,454.72943,-1500.3339,893.54584,453.67194,-1500.1119,885.479,452.17557,-1500.5151,980.0668,433.35892,-1237.4282,885.68207,431.00897,-1253.1808,935.7665,475.96732,-1401.4204,906.3365,477.43335,-1404.7427,1073.0681,428.28085,-912.71796,821.6595,404.4669,-895.05756,1167.5195,619.7538,-852.62427,745.425,600.62616,-841.5398,1231.9667,786.4513,-1012.9812,726.20264,791.4003,-1013.86346,1264.4545,817.549,-1128.1791,700.73584,827.5876,-1103.2465,1224.9305,809.1572,-1164.0776,730.06104,831.72046,-1136.4059,1204.6716,800.9161,-1039.9506,739.93884,818.2728,-1029.275,1059.5334,368.41025,-40.21713,951.5248,360.4243,39.617847,1053.3405,483.3092,584.76587,917.2121,495.92612,472.04446,1042.4861,535.4595,1456.9622,949.6257,537.6921,1292.2826,1044.9652,523.5207,1549.5237,962.2878,519.8498,1379.0847,1040.3729,630.8365,1494.0077,930.6256,616.0356,1304.1787\r\nframe___qNmbXRZtfY__0008876.jpg,pushups_up,1219.1099,576.8888,-815.17706,1237.982,573.4884,-823.6308,1245.0543,572.5133,-823.6601,1252.4205,571.82074,-823.8239,1217.9508,564.10956,-858.2062,1213.2881,558.1693,-858.2435,1208.3816,552.3727,-857.90985,1267.6998,542.1766,-762.5151,1212.3973,508.9392,-916.2216,1215.4801,560.8488,-777.6152,1201.4957,554.3519,-823.3269,1297.2623,466.78906,-615.18463,1079.7179,441.7259,-800.411,1349.1292,673.26605,-512.4231,1052.3739,683.8586,-805.1378,1364.1697,900.417,-579.9433,1081.3497,898.0015,-871.9148,1414.2783,945.4534,-642.80383,1085.9976,943.67596,-968.99963,1392.4595,954.3038,-720.16455,1128.2217,933.52704,-968.9986,1359.3177,941.31995,-614.8098,1132.4185,919.2646,-881.81696,973.8469,492.37277,87.99949,853.6524,453.57278,-88.66198,814.42285,669.36774,193.72685,608.8764,676.1819,9.179303,656.17377,843.9303,501.85764,384.02756,853.41046,186.209,629.07385,864.6075,520.6645,358.73456,861.8045,193.38472,644.9717,918.5509,396.5219,335.87344,972.15546,60.548817\r\nframe__NiggcxGYM2A__0001516.jpg,pushups_up,304.84445,580.6622,-67.42691,287.0785,553.8552,-124.970184,288.318,551.0017,-124.84098,289.53937,547.79596,-124.97867,287.62207,551.4761,-68.357086,289.2307,546.8291,-68.45802,291.16104,542.3485,-68.4507,312.48242,524.3343,-237.34781,313.54752,518.47754,27.411318,335.05313,581.1941,-88.89696,335.1202,579.9858,-12.474424,444.4677,599.5229,-324.9097,506.47104,522.16003,289.57065,480.9517,817.6697,-346.8062,560.8241,705.59045,396.27158,488.43762,993.3019,-261.1588,557.01404,849.49695,219.92923,440.8548,1008.42676,-324.0127,511.0753,838.29175,224.00554,437.75684,984.3622,-262.0572,504.25415,854.148,150.95898,459.5417,976.84393,-237.31273,521.06964,864.453,185.36945,845.1873,707.2332,-194.94066,866.40814,650.5431,194.2901,1139.6641,798.3402,-56.238274,1143.1803,739.1565,330.83258,1445.7236,877.1942,75.767975,1421.7366,790.9019,501.46887,1504.839,867.59937,78.1263,1482.0962,784.8498,518.54254,1427.8958,967.23883,-57.13427,1401.4872,881.4142,456.85202\r\nframe__3g_yYPbjSV0__0007317.jpg,pushups_up,307.43658,434.0435,-108.59096,297.04147,404.97156,-165.19986,300.12268,401.72467,-165.28963,303.01144,398.0639,-165.62022,294.88977,403.75214,-104.95648,296.24542,399.66528,-104.907295,297.95465,395.7604,-104.57051,336.6013,373.4724,-268.85654,327.2469,371.95865,7.894711,344.37405,435.52423,-132.65543,341.6875,434.89078,-52.20535,508.8246,425.65176,-353.03964,544.67523,392.80124,251.26439,542.8541,670.4718,-360.37125,598.73224,605.2189,308.6561,578.55096,905.1489,-322.94794,589.0584,795.88324,210.56206,536.44446,933.43463,-403.27,534.0271,792.3356,220.77194,526.9383,914.27374,-336.53308,529.05634,808.9898,139.99745,544.6439,904.4889,-301.02417,552.44836,814.8362,175.78503,983.65656,456.9411,-189.38165,984.08606,442.18658,189.77332,1279.2773,646.6017,-85.95629,1282.2977,625.4009,240.2748,1580.6433,778.5616,33.302242,1596.1252,746.34656,328.58313,1651.927,774.5035,33.97052,1669.1826,741.5268,332.67743,1526.59,890.5749,-114.65946,1574.2622,867.9412,228.84267\r\nScreenshot_2021-02-11_at_12.18.00.png,pushups_up,1246.4746,367.80438,-1764.7166,1269.0834,307.4689,-1789.441,1286.8506,302.1651,-1789.3828,1305.1173,296.6499,-1789.0842,1214.222,310.91666,-1781.1362,1195.6577,307.20746,-1781.1075,1177.1394,303.95496,-1781.3281,1335.5459,249.31339,-1536.9624,1148.632,259.30536,-1505.1265,1280.0906,365.1659,-1639.1168,1222.5404,367.87933,-1630.5986,1486.0524,294.66583,-1131.6764,1033.3168,317.8656,-1146.7578,1547.9966,568.79224,-958.9533,876.5316,550.5913,-1116.5922,1587.3273,868.3133,-998.29114,841.0579,853.62524,-1232.1731,1617.4071,916.3944,-1046.3807,797.78894,903.48505,-1321.4957,1589.3647,923.1964,-1106.4698,856.77216,911.18365,-1343.5344,1561.2318,908.69293,-1021.32117,890.4324,893.4812,-1247.2876,1383.4303,508.44727,1.424569,1186.2527,531.5286,-2.4112856,1359.428,674.91956,854.0335,1239.06,726.28284,766.8331,1341.2528,777.4537,1725.4082,1283.6669,823.0811,1688.6439,1329.6692,777.38855,1811.163,1295.4716,813.71094,1781.195,1352.9603,894.45764,1581.4678,1307.3403,955.0496,1531.7664\nframe__Mpu8MrUd3c8__0002502.jpg,pushups_up,532.7308,397.60565,-123.39407,509.63763,380.68027,-188.7125,510.5225,376.4816,-188.62987,511.30804,371.92368,-188.78061,505.9643,377.70175,-115.25177,504.62064,372.25888,-115.460304,503.67886,367.03842,-115.70942,524.1071,333.94818,-348.1946,512.6975,328.5129,-13.085897,563.24603,381.8255,-167.41943,559.9443,379.5883,-69.83099,678.5436,309.79022,-474.47327,678.5955,290.99374,252.33876,702.2554,527.7173,-542.26276,722.0469,467.2682,393.53244,689.39355,744.8444,-472.66687,704.8995,621.86896,234.36812,641.0114,774.19946,-557.5567,651.78937,619.618,237.6977,630.64557,757.99084,-496.0263,644.1073,638.0224,160.40575,648.73676,748.45844,-451.07632,666.9147,643.61664,198.08171,1074.9767,341.27307,-222.44278,1059.8044,338.60544,222.03732,1332.5892,505.44263,-16.528015,1288.3218,493.37616,398.59,1583.2043,570.7768,189.06644,1527.9829,566.85266,653.3203,1644.0568,555.92535,196.43889,1585.0332,555.6894,674.2354,1547.7605,688.0131,23.741648,1518.7327,688.1288,574.2994\r\nframe__HRxXKX8zzs8__0020028.jpg,pushups_up,1260.6089,677.3465,125.90425,1279.8496,658.876,148.54875,1279.3385,654.2552,148.62819,1278.918,649.88336,148.39613,1280.1863,661.2852,77.88481,1280.8704,657.99396,77.881546,1281.4414,654.791,77.7993,1269.6188,620.4547,246.85269,1274.3088,626.8623,-71.690994,1240.6829,665.722,170.27722,1242.0167,668.0484,77.83102,1143.5754,598.6412,420.0292,1184.99,630.7,-218.32204,1146.7618,749.2976,516.35254,1184.8375,791.34406,-328.788,1175.3308,871.0134,392.7245,1202.799,937.1561,-299.47107,1216.4607,879.1854,417.68375,1244.3015,959.8203,-361.01135,1215.3167,894.5968,350.49887,1246.7306,941.27844,-297.64133,1201.798,897.0808,360.57468,1230.5063,939.08704,-275.40112,870.97833,606.8244,199.14835,881.6707,615.2322,-198.61148,666.70984,736.52576,226.68033,677.4676,743.13727,-167.6008,466.38855,818.43695,356.83188,454.97253,851.72046,-48.371136,425.95734,817.8059,358.382,408.2579,853.0432,-52.78015,465.51105,896.55804,210.88318,464.66165,943.1834,-228.422\r\nframe__ilh-78AaSjQ__0001073.jpg,pushups_up,1554.8486,386.9659,-254.0322,1565.1844,364.1157,-235.58272,1564.1215,360.84738,-235.43204,1563.1024,357.9229,-235.47542,1561.9293,365.41885,-306.65475,1559.254,361.99042,-306.74554,1556.4554,358.6718,-306.91122,1537.501,336.89838,-102.49903,1530.9331,338.08112,-421.5535,1525.9207,386.19482,-192.84016,1523.0901,386.32547,-285.00665,1406.2404,350.25305,153.49025,1401.299,361.22345,-544.5087,1348.5095,475.0772,333.9364,1315.7448,503.86118,-581.8436,1367.5095,601.48444,234.26888,1328.4519,655.52136,-553.902,1392.0508,614.90076,226.0722,1347.8132,683.7676,-645.7512,1402.9586,627.6623,147.47029,1367.7372,675.4346,-612.675,1388.9294,626.9901,198.52748,1355.2648,666.1563,-542.50946,1109.7218,384.33643,215.59007,1095.1821,388.65714,-214.73122,993.30273,510.32965,591.94214,957.837,521.08936,86.937164,829.7621,538.5343,1024.1752,775.3662,533.03076,508.62076,789.17883,522.5971,1065.0739,738.0936,510.4108,551.1698,829.4054,621.5177,1040.9849,760.4833,613.80505,500.88586\r\nframe__tz5OMDdUtNk__0014914.jpg,pushups_up,879.3991,600.1649,-222.41995,864.9916,590.01697,-260.6885,865.8399,588.34546,-260.65225,866.60297,586.4299,-260.82108,862.9589,587.5148,-206.5889,862.55743,584.82983,-206.57495,862.40247,582.1193,-206.49481,876.54254,572.6495,-341.6117,870.97485,564.81464,-89.242355,898.8693,597.309,-240.95773,896.67175,596.4067,-167.2308,960.5679,590.39276,-406.78455,959.779,524.36395,173.24316,991.279,722.7971,-435.75766,986.5636,631.28723,362.59195,987.4531,825.45337,-384.4251,969.298,718.9854,250.26607,967.13904,847.7831,-457.7922,943.43207,721.7509,263.77988,958.3772,837.1394,-414.24524,941.4256,735.6498,199.4044,969.25073,827.50665,-368.56534,953.9795,738.5656,223.27881,1202.4546,550.1934,-192.35124,1192.6157,514.10016,192.12056,1345.4718,639.1372,-12.899159,1314.4912,614.41614,480.81,1516.7622,710.632,176.55983,1454.8779,678.6358,788.8312,1558.2468,704.84576,184.07535,1491.7587,677.5651,817.9011,1498.656,802.57275,46.082672,1441.5717,760.5641,757.28894\r\nframe__F4ewRlyAJBo__0000723.jpg,pushups_up,1073.3706,1353.6285,-267.62625,1036.4674,1325.6501,-367.1872,1037.4045,1317.3549,-367.3192,1038.1709,1308.485,-367.55093,1031.5752,1328.9326,-221.89922,1030.3191,1322.8071,-221.68852,1029.597,1316.7607,-221.18907,1054.1775,1254.6504,-523.00433,1043.2521,1268.8015,140.7315,1115.7001,1329.4004,-308.96054,1111.2717,1333.0354,-117.38573,1246.1012,1263.5732,-793.9748,1294.2223,1205.1086,701.093,1298.0171,1583.8003,-920.4276,1355.929,1497.0049,746.10583,1310.4851,1902.9319,-940.7852,1342.5646,1756.2488,176.03897,1208.5267,1917.9016,-1117.139,1244.2614,1726.9199,176.79916,1204.6504,1882.585,-947.6454,1237.8335,1757.9385,-15.3707905,1238.297,1877.8839,-876.50104,1267.196,1782.4211,81.13636,1788.578,1315.3335,-460.99173,1803.5315,1279.3579,460.01416,2178.8281,1634.207,-493.0061,2159.3953,1583.605,557.88513,2604.3887,1738.1841,-388.31607,2570.5154,1677.945,950.1548,2702.7544,1729.862,-411.00766,2665.9126,1665.0085,971.5137,2543.8152,1915.0208,-884.2384,2553.7185,1868.161,628.86206\r\nframe__W2tcQrYuDc4__0004734.jpg,pushups_up,1385.4073,547.72626,-53.292767,1397.0636,521.12164,-39.92258,1394.4495,517.1896,-39.67002,1392.0729,513.4695,-39.652977,1397.801,523.84827,-101.66325,1396.2936,520.1364,-101.69334,1394.6641,516.50604,-101.79836,1362.935,489.4061,70.14301,1366.2273,493.74225,-196.47536,1351.9719,546.9989,-1.8922796,1353.6685,546.89526,-78.80227,1200.4059,514.88556,278.02625,1229.426,545.6832,-327.6192,1222.8271,717.0428,348.4309,1243.5521,766.95844,-406.19528,1266.204,892.98694,228.01862,1303.5911,967.31604,-368.58014,1307.0618,892.4814,212.76204,1348.9463,984.7971,-443.28802,1313.3165,906.21497,138.54184,1357.5815,970.3595,-395.67984,1296.9601,913.8981,191.4577,1337.2758,966.9885,-353.08313,843.3458,647.99634,186.71695,840.4957,660.72156,-186.19722,590.6916,789.0512,201.09793,559.8166,809.01263,-153.90988,316.83987,836.01245,355.28503,260.49487,824.5022,-32.336037,274.72144,818.62445,364.08734,214.13898,802.90674,-34.357536,268.6989,916.7442,259.56516,229.04034,920.1308,-186.9074\r\nScreenshot_2021-02-11_at_15.24.51.png,pushups_up,888.42114,611.8825,-1002.4421,892.7598,567.61755,-1042.549,902.4973,561.45764,-1042.615,912.102,555.00256,-1042.8523,874.54645,575.0298,-975.33356,870.586,574.4941,-975.2505,866.7498,574.53314,-975.45337,962.1899,519.0463,-1051.037,898.6881,547.89404,-744.1595,942.55896,610.2431,-990.60535,922.2934,621.0327,-902.30536,1228.6396,574.8836,-1077.47,982.87885,607.6797,-501.11816,1363.2,880.3264,-1171.3457,965.03265,845.3021,-347.4426,1363.6548,1135.0818,-1177.6682,920.96216,1063.0822,-466.58658,1360.6074,1179.5249,-1310.2968,877.35583,1099.6505,-545.2305,1312.4012,1161.9012,-1324.1154,877.96106,1095.1769,-638.17993,1309.7004,1145.8385,-1193.1467,912.04846,1091.2128,-515.233,1560.7354,768.96204,-196.27362,1415.0654,796.87,196.71959,1840.9567,880.7862,260.6721,1443.2936,864.59534,793.6929,2106.8416,891.6064,681.32245,1587.7358,899.1264,1472.9176,2160.5886,866.11664,718.10345,1631.6943,890.9517,1539.4502,2121.7942,1002.27856,518.0089,1551.5513,980.8379,1506.8411\nScreenshot_2021-02-11_at_14.44.45.png,pushups_up,1664.9957,425.4786,-816.93634,1670.0238,384.18448,-797.3385,1668.642,382.34265,-797.06274,1667.7228,381.1442,-797.1598,1662.2189,380.69232,-882.8223,1654.8317,373.75977,-883.1821,1647.2954,367.1162,-883.4068,1619.0043,349.33075,-583.18225,1593.7062,332.44873,-966.97186,1620.4711,432.27844,-716.69666,1612.1904,424.03488,-827.7421,1494.6306,406.971,-266.742,1360.7195,399.65616,-978.45514,1451.5774,593.7006,65.56595,1214.2386,627.7944,-1004.6536,1505.702,797.4867,47.13143,1226.9097,855.565,-1001.38696,1533.0022,829.9279,29.628216,1221.9904,897.7047,-1118.9329,1539.3527,845.77814,-79.073975,1258.0443,894.40466,-1119.9923,1511.0253,840.08344,2.6507957,1259.3082,882.30304,-1007.4061,1126.2523,604.9997,223.7686,1048.1167,589.3088,-222.45157,990.32806,710.8283,852.6034,861.83704,638.8525,331.72418,821.6906,723.3071,1623.6632,668.94775,674.25085,1007.07904,772.4428,706.66425,1696.4188,618.3643,666.82196,1066.616,828.6321,815.28046,1644.6519,664.6118,760.2083,921.6629\nframe__J5FZeUV6l0E__0005683.jpg,pushups_up,331.82632,424.33817,-171.49763,318.1757,412.47406,-214.78732,318.36435,409.37076,-214.78723,318.4679,406.08017,-214.71281,317.96716,413.28992,-158.06796,318.3205,411.3878,-158.01492,318.88107,409.56067,-157.88846,326.24606,384.5755,-272.74603,326.70953,389.15192,-15.402582,347.60767,414.57266,-186.60341,347.88388,415.88998,-112.290665,396.64465,387.14627,-379.67432,413.8054,367.83337,197.27028,396.58594,502.0899,-472.5086,427.6983,473.3954,221.95459,395.18085,612.93384,-527.04205,425.40253,568.52203,67.444016,362.60526,617.16986,-601.81165,394.5015,560.8425,69.54982,363.14575,607.2986,-545.9335,392.98315,572.2227,0.30658293,375.3865,605.7256,-507.97748,402.82013,579.71704,33.14573,599.5385,398.24255,-176.73927,599.9702,383.55487,176.46548,738.3652,499.31403,-186.09764,721.6583,476.66516,251.58464,885.5323,529.5794,-160.72409,856.8484,502.41153,390.6504,919.5945,525.6306,-174.6942,888.1997,498.53476,398.1994,872.6316,593.46246,-347.1837,856.5152,565.27246,286.24832\r\nScreenshot_2021-02-11_at_12.41.44.png,pushups_up,1255.8717,390.20557,-1734.4371,1277.7499,344.76215,-1703.8131,1293.3406,342.792,-1704.0236,1309.4121,340.67285,-1703.89,1230.129,346.1389,-1699.5776,1213.9191,345.2388,-1699.6093,1197.7183,344.59323,-1699.4868,1332.2152,339.3999,-1407.1881,1173.9696,345.0937,-1376.0411,1284.9525,418.4931,-1617.1339,1230.48,419.3916,-1607.5405,1461.2117,488.91873,-1142.8749,1056.5702,502.9995,-1139.7655,1616.9706,754.44806,-1246.6913,930.00824,778.139,-1245.8809,1765.7483,1043.1798,-1387.1368,796.44464,1053.5078,-1337.2686,1833.3092,1088.178,-1456.1099,730.96857,1094.1646,-1378.6737,1802.2125,1094.8645,-1543.419,762.26056,1098.9739,-1475.2417,1756.9515,1088.4552,-1426.579,807.0975,1089.7498,-1381.799,1353.3298,793.19775,-5.3065567,1180.8043,793.028,5.664697,1339.5139,927.92944,820.7419,1206.3578,937.36816,885.65576,1305.3422,987.85657,1712.407,1215.3066,990.11597,1823.7227,1294.623,977.62756,1792.418,1212.5101,980.55444,1914.6113,1307.1799,1070.521,1533.4816,1223.7771,1074.139,1676.735\nScreenshot_2021-02-11_at_12.46.52.png,pushups_up,1258.5154,623.7242,-1805.4436,1295.4222,540.0329,-1837.6084,1321.7456,534.3922,-1837.7305,1348.4674,528.46497,-1837.6963,1217.3245,539.789,-1825.6177,1189.9772,533.4021,-1825.6816,1162.9866,527.4781,-1825.8416,1394.0146,473.89474,-1602.2869,1124.291,472.04434,-1548.3602,1304.3605,631.8645,-1682.1421,1221.4402,630.291,-1665.9348,1569.3525,517.4311,-1193.0765,989.7956,527.24493,-1169.6205,1674.6388,808.21533,-925.30725,908.8953,807.4311,-944.32074,1648.2083,1170.7776,-1029.3462,893.1015,1137.6024,-1075.5576,1679.8064,1239.4166,-1125.1453,842.4983,1192.6431,-1182.2314,1614.1992,1240.9681,-1189.1846,905.87775,1202.8027,-1242.2617,1580.4707,1213.6769,-1056.1276,951.9838,1179.4337,-1112.8846,1411.9122,731.9818,5.4686046,1160.1223,746.02155,-5.4562473,1417.4501,806.52875,887.8701,1194.2671,818.41925,864.1632,1378.7965,809.54987,1772.8654,1221.4941,812.8295,1846.5903,1357.5624,778.2342,1875.0607,1234.276,778.6081,1952.1005,1381.5676,920.1144,1765.156,1239.1377,917.7242,1841.665\nframe__nhy9aJ-veTw__0005078.jpg,pushups_up,928.1313,331.75116,-1458.5854,954.79724,269.86835,-1485.912,973.9418,265.56543,-1485.9568,993.5015,260.9593,-1486.101,893.8042,270.6868,-1478.6543,873.9158,266.40344,-1478.7356,854.0762,262.46826,-1478.8495,1025.6826,218.9241,-1305.4377,822.5992,221.82156,-1270.4858,960.27856,339.69403,-1363.0748,901.27985,339.10413,-1353.2346,1157.819,294.92432,-1012.23083,708.76245,294.35876,-1000.54456,1190.1516,623.0541,-1037.0408,672.463,611.91113,-998.299,1210.4106,940.78217,-1154.0302,618.883,934.17053,-1049.0507,1252.1342,986.8431,-1262.8121,563.421,978.1482,-1134.8468,1197.8832,992.00397,-1289.3507,612.6807,988.9409,-1191.8041,1167.8972,977.20605,-1174.4685,654.01337,976.85913,-1078.0542,1012.04724,442.49124,-13.099252,819.8915,446.53696,11.604469,1010.86255,577.5903,661.0211,838.76,580.5673,681.41254,992.84875,627.8852,1386.6962,872.9345,623.5044,1480.6332,979.8983,612.1675,1466.7891,885.2495,606.1441,1567.9143,990.5722,732.7222,1275.9784,885.9761,715.63214,1384.9808\r\nframe__fH_1skamnFk__0003137.jpg,pushups_up,1103.6067,685.2798,-1003.8637,1112.1279,669.4603,-987.63464,1114.3636,669.3839,-987.52466,1116.8052,669.72675,-987.50635,1100.1444,663.7447,-1030.5996,1095.1332,659.20276,-1030.2832,1090.0178,654.7892,-1029.4706,1103.8528,651.5975,-794.0884,1071.4183,627.6349,-989.4435,1089.7261,685.4658,-917.19867,1081.4185,677.67834,-971.67755,1100.1587,652.0939,-575.3361,963.96893,641.7952,-911.64386,1107.4579,797.11975,-489.51724,935.8984,810.00824,-989.41486,1117.9701,931.2006,-572.4368,930.30505,964.35815,-1036.7162,1144.6624,949.50366,-629.8816,927.91034,991.24854,-1144.4747,1137.9874,951.771,-704.5151,958.9476,990.8852,-1143.2926,1113.9417,948.0804,-605.04205,958.32263,984.5366,-1046.6346,917.2697,668.75287,120.15278,838.9037,653.76373,-121.63486,855.7478,801.1649,405.14407,794.92633,807.2195,204.53128,773.9249,843.87683,1019.9961,715.0003,846.593,760.5854,755.44415,841.8985,1082.2438,698.76276,842.67346,809.7405,766.2194,897.3642,988.4759,714.3512,905.0898,682.523\r\nScreenshot_2021-02-11_at_11.22.09.png,pushups_up,1266.5886,707.55304,-1194.1724,1279.2742,675.7728,-1189.768,1288.697,674.2704,-1189.9608,1298.2673,672.6186,-1189.975,1248.0952,676.3234,-1190.8096,1237.6958,674.4978,-1190.8099,1227.1613,672.90485,-1190.8014,1308.4011,660.179,-1002.36456,1206.3062,661.4675,-1004.06256,1280.0576,720.32184,-1111.2684,1249.1151,719.28625,-1112.1594,1384.3145,738.2536,-830.1024,1132.5544,744.4302,-802.6757,1431.4224,944.1944,-913.70404,1121.1444,938.1434,-854.1267,1457.586,1125.999,-989.6718,1093.4985,1122.2311,-909.59985,1479.8894,1154.4924,-1061.2606,1063.8435,1150.8041,-952.3637,1450.2542,1154.7604,-1083.4355,1081.1053,1146.1283,-993.63324,1435.4958,1148.2281,-1004.9109,1100.0864,1140.8866,-929.02594,1325.7655,907.61237,-26.19633,1218.7719,909.6062,25.797142,1320.2981,994.8361,563.1823,1238.1996,998.21234,581.1533,1303.7289,1041.9875,1184.884,1252.3646,1037.1327,1213.3201,1298.1642,1039.6422,1243.5558,1258.3192,1033.9291,1275.2863,1300.3323,1092.4851,1061.3844,1248.5748,1084.2853,1094.454\nframe__z5_CTDjMi_8__0002481.jpg,pushups_up,596.4211,684.5786,-114.990105,583.317,667.6761,-158.1093,584.4828,665.03516,-158.13365,585.61456,662.1596,-158.33951,581.5392,666.65643,-96.88294,581.5884,663.24634,-96.806755,581.96857,659.94763,-96.76467,601.65594,641.7961,-234.98549,595.74146,640.3164,44.961998,620.048,680.8825,-135.60184,618.0485,679.6215,-55.046394,709.146,666.2019,-385.5793,723.18945,648.63025,279.51913,679.1613,830.93207,-556.4655,714.739,809.31696,268.20856,666.02374,971.2844,-592.8338,698.7723,932.22144,13.607674,624.60925,983.87317,-700.4686,660.20807,930.1343,-3.8170977,626.2911,969.0445,-628.75397,659.9146,935.54706,-92.30028,642.4203,965.9942,-572.6921,673.7426,940.2238,-34.159332,995.0121,701.2176,-211.45966,986.5431,694.6366,211.72876,1180.1208,835.24854,-160.85158,1150.1852,813.93365,301.16205,1378.2942,915.81726,-51.616276,1320.3179,877.2715,518.2632,1426.6375,913.20624,-51.728844,1358.3662,878.77454,534.43506,1341.3357,1003.15497,-237.18436,1308.6364,950.475,405.25696\r\nframe__mqwXyeCnkMI__0002496.jpg,pushups_up,1190.6838,611.40564,118.66082,1199.0924,595.4539,145.38371,1197.9257,592.2562,145.53781,1196.882,589.15125,145.37007,1198.7784,597.7995,87.828064,1197.855,596.0627,87.98769,1196.9292,594.3854,87.95401,1182.5024,573.49384,247.86424,1183.6157,581.08203,-8.605927,1173.0154,609.87994,165.51096,1173.2352,612.4155,90.978745,1063.5363,573.1369,425.8146,1115.0974,609.98724,-183.34146,1020.0436,707.84766,452.39105,1081.8174,753.0047,-263.18924,1017.1875,820.2723,292.96533,1082.792,885.92126,-208.51091,1038.0067,821.3107,307.5053,1106.5845,902.24884,-263.11444,1044.1903,833.37506,239.4075,1108.9921,895.2617,-207.91643,1038.281,837.05914,261.60803,1096.3417,890.05414,-185.12935,852.2531,663.6814,183.1368,869.94086,689.62115,-182.58357,707.9162,756.16644,241.84047,698.01953,789.92615,-144.58165,524.224,796.6135,343.35403,497.41687,828.5214,-92.1312,486.50183,792.4926,350.7669,458.76733,817.9363,-95.91617,530.4144,857.68915,294.47827,506.0219,907.3057,-208.33943\r\nframe__3HwW3mEM5Ws__0004896.jpg,pushups_up,324.57935,566.87305,64.48328,303.59436,549.13196,10.995123,303.2173,545.53284,10.965363,302.71243,541.55304,10.817685,303.8636,546.99976,73.4307,303.83664,541.96643,73.400764,304.14362,537.0211,73.44589,311.08475,510.88235,-108.89584,312.40265,508.33228,176.00415,345.76398,557.7936,32.147564,345.72052,554.98285,114.96211,409.26385,507.10205,-249.6151,474.63843,486.13116,405.85828,410.6331,704.2236,-336.4005,526.1034,669.4298,503.70233,404.5111,901.0122,-318.9516,513.5354,821.37354,395.61136,350.55936,927.92444,-386.5635,461.85806,822.2336,436.62573,348.10306,913.5372,-309.2556,450.73697,839.17535,362.20483,369.95663,904.4286,-288.39664,468.4292,845.0645,364.36035,769.214,501.51932,-198.05566,784.7812,495.4145,198.15561,1023.49744,670.7279,-124.951385,1021.79877,680.64996,219.67477,1278.0508,797.0039,-54.350998,1274.1732,780.89276,311.41342,1328.0796,791.09247,-53.13442,1321.2681,772.85834,314.78845,1275.7294,901.4273,-176.33136,1303.7443,876.2326,211.13933\r\nScreenshot_2021-02-11_at_12.17.00.png,pushups_up,1254.4436,377.0226,-1742.3643,1276.8853,315.2031,-1771.3104,1294.6967,310.16034,-1771.2479,1313.0133,304.87527,-1771.1316,1222.9955,318.09143,-1762.6965,1203.9338,314.21216,-1762.6805,1184.9812,310.8508,-1763.0625,1340.2266,258.4238,-1537.8486,1154.3789,266.7479,-1511.5316,1285.4733,374.442,-1622.2561,1225.9316,376.2753,-1615.3135,1477.699,300.91376,-1158.7501,1025.5898,319.07422,-1168.0757,1542.0052,569.70715,-1025.4175,884.28827,552.8476,-1175.4872,1602.9519,860.50354,-1105.3218,859.2268,848.9536,-1388.0991,1638.8964,913.1974,-1170.84,816.4564,905.75867,-1503.7905,1616.6083,917.7331,-1229.4384,875.38196,912.0021,-1540.2112,1583.4484,900.0961,-1130.2623,909.90204,889.46313,-1412.0441,1357.9994,533.439,10.345426,1166.0626,553.92224,-10.5806675,1368.2505,683.30457,878.4672,1223.2389,729.42926,769.8357,1343.8314,781.5357,1699.4924,1274.5978,820.9391,1685.6798,1328.3182,776.8945,1783.3146,1279.9192,809.88385,1780.3864,1366.6189,917.01166,1615.3998,1309.812,960.8321,1606.8373\nframe__vvxPOsJ9GWg__0001722.jpg,pushups_up,1469.0494,693.1316,-60.937035,1476.0427,674.3607,-37.417053,1473.4904,671.949,-37.155563,1471.0378,669.6958,-37.17679,1476.4069,674.8387,-105.143684,1474.7942,672.1856,-105.121475,1473.1265,669.5987,-105.15983,1447.5233,659.1973,94.41333,1452.0747,658.9674,-210.62926,1445.173,699.1674,-2.7849607,1446.1467,698.8364,-91.0204,1310.2993,686.04755,353.84488,1350.0112,709.01587,-357.55835,1266.2063,827.0654,392.09793,1299.3367,870.68604,-406.55878,1243.8391,949.4163,198.78244,1293.7635,1018.8305,-386.8254,1269.1294,946.564,208.21281,1328.229,1029.9531,-470.99442,1271.811,956.5675,121.773605,1331.0535,1017.19275,-408.06097,1263.9243,963.0733,156.64188,1315.2052,1015.6009,-363.93018,1053.0408,753.53784,221.03505,1069.189,767.85144,-220.56384,873.9932,847.63495,325.79504,872.9252,850.6772,-114.67973,675.7586,899.8316,507.1281,661.7837,913.3898,56.631035,628.1951,898.322,520.02686,615.2752,913.85675,55.565525,699.50635,982.0487,420.0313,684.99994,989.30054,-109.23339\r\nScreenshot_2021-02-11_at_11.32.49.png,pushups_up,1507.0477,689.36346,-2195.4792,1519.311,648.75134,-2197.6277,1529.5278,642.93494,-2197.093,1540.1249,637.44196,-2196.145,1481.8595,653.07385,-2234.515,1465.9868,650.0098,-2233.376,1449.0835,646.59406,-2232.8801,1520.6378,601.12,-1933.6117,1390.2987,604.0664,-2085.7605,1487.9932,686.0556,-2066.8965,1457.7119,693.6512,-2108.0002,1512.8262,599.346,-1423.2252,1130.3665,599.80566,-1693.6355,1596.844,783.0309,-859.8226,921.998,767.81995,-1495.6041,1603.0757,1082.4102,-734.3478,951.44556,1019.67834,-1409.1167,1661.5278,1129.4011,-836.826,931.4948,1084.3347,-1537.0144,1640.0024,1168.3953,-941.9194,1003.05743,1076.3715,-1559.5394,1583.3679,1157.5172,-822.95233,1025.1625,1040.6332,-1413.4551,1174.6786,776.8219,116.98332,998.85425,774.9498,-112.78807,1201.566,864.82574,1509.7941,1003.95935,905.97797,1220.7008,1184.0511,945.9271,2846.9387,1047.9967,934.8739,2642.9482,1175.1516,926.1246,2934.3948,1055.9086,903.7386,2806.442,1201.4081,1033.155,2903.0706,1062.4684,995.11383,2882.401\nframe__VQKqjHtY8jA__0009766.jpg,pushups_up,1251.1969,417.94278,-688.9006,1276.2706,404.38412,-657.97894,1282.1404,411.92447,-657.7644,1288.1252,419.74194,-657.7476,1257.7902,382.28635,-685.3078,1250.1244,372.4031,-685.25323,1242.2793,362.86182,-685.2858,1274.19,428.21753,-435.82666,1215.2147,354.34448,-553.8003,1236.6013,449.74826,-597.3846,1212.487,418.22168,-632.0076,1169.5024,475.69736,-78.52541,1087.761,439.25397,-645.75366,1187.9218,654.108,104.23924,1018.56024,638.3023,-657.95715,1224.3237,783.2826,-22.864092,1047.687,823.2732,-666.1246,1246.2754,802.5986,-59.60281,1055.0807,862.0713,-763.1874,1246.4688,803.05316,-140.0288,1083.1624,853.7995,-754.38074,1225.7944,801.88696,-61.06918,1073.301,839.26605,-662.9263,800.8938,547.19214,175.86292,764.50323,537.15173,-175.21939,657.8573,630.6605,568.2071,574.88007,656.1598,63.716568,492.7826,619.54895,1049.7394,399.4537,686.0851,443.93143,460.43726,602.3332,1094.5568,364.46988,664.3398,481.72565,462.69272,691.49475,1081.6061,365.9808,779.6121,403.41486\r\nScreenshot_2021-02-11_at_13.39.19.png,pushups_up,1188.3634,430.95312,-2072.3313,1223.6334,365.20215,-2061.7131,1244.5724,362.07718,-2061.6772,1265.8038,358.76044,-2061.5425,1158.2719,363.2263,-2054.7986,1137.1627,358.90866,-2054.737,1115.8713,354.8999,-2054.3608,1298.5256,339.60324,-1729.753,1082.4375,331.28177,-1687.1119,1220.9028,458.6055,-1928.6333,1151.7343,455.6302,-1914.425,1433.5642,505.44934,-1426.5104,928.9759,484.08325,-1383.7528,1516.9489,852.5704,-1557.016,864.6619,830.092,-1475.1904,1544.0758,1202.0887,-1815.8236,842.19586,1159.4553,-1703.0525,1588.6245,1262.5658,-2017.184,803.01154,1215.9487,-1875.9938,1510.2429,1259.2902,-2047.888,872.8959,1215.5415,-1916.6842,1481.7773,1244.5964,-1849.6449,900.24475,1200.0858,-1738.2848,1252.1616,827.61945,-29.084957,1042.4697,819.69354,28.391964,1185.089,984.28894,1009.27496,1030.5121,963.0713,980.7635,1182.8689,1007.3175,2147.6582,1048.2191,1011.28253,2101.9172,1173.9943,982.08154,2268.806,1059.5115,991.8496,2215.497,1175.0984,1108.599,1995.7968,1063.5265,1112.061,1916.2128\nframe__QVNlEfFOWwg__0005300.jpg,pushups_up,1374.466,575.54944,-27.605,1396.8297,551.64087,-15.622548,1397.0425,545.9352,-15.440519,1397.4309,540.3904,-15.445529,1393.0582,557.28723,-77.50418,1391.5045,554.2163,-77.69684,1389.8647,551.2093,-78.07097,1377.6731,508.13913,67.97881,1367.8225,522.8008,-195.69711,1342.381,565.1957,16.687044,1339.4672,568.6974,-60.409534,1187.331,481.2958,246.42242,1218.4541,568.23737,-316.12393,1138.4923,692.1689,369.64328,1184.7942,817.6474,-342.87085,1154.6007,842.36017,272.5778,1234.2798,999.0619,-219.15904,1183.901,849.79596,260.5012,1273.9875,1027.4805,-283.80222,1191.2898,860.9192,192.36845,1279.7443,1007.53156,-239.58376,1178.0925,867.7548,243.18626,1258.2478,996.4562,-201.41922,795.2839,646.22375,158.48138,792.7469,688.4859,-158.05511,548.2798,797.8168,253.8035,521.4997,821.715,-32.97011,268.1399,848.8143,446.4842,231.04797,868.2643,139.23602,219.80284,833.44684,461.039,178.47891,854.6632,148.38834,239.13283,915.8206,399.4265,221.49399,934.082,61.748737\r\nScreenshot_2021-02-11_at_15.18.04.png,pushups_up,992.054,365.72525,-1257.7977,1012.4968,308.19543,-1272.5846,1029.9008,301.1702,-1272.6641,1047.1454,293.80386,-1272.8018,972.24164,323.1985,-1220.8644,960.1944,326.23935,-1221.0107,948.29565,330.02643,-1221.2659,1101.2361,269.17886,-1160.1049,966.07916,319.77008,-933.71783,1052.3511,377.37628,-1205.061,1005.68317,396.14066,-1139.48,1364.3751,358.93555,-1101.8842,1008.4088,442.34232,-668.148,1509.9254,740.1801,-1117.1238,992.79443,745.82886,-491.01733,1482.4008,1070.2516,-1196.1837,901.10516,1034.1074,-572.1709,1488.4073,1136.4504,-1353.0253,835.929,1079.1868,-629.34546,1420.8698,1127.3298,-1369.7395,832.10895,1084.0885,-739.0605,1414.7382,1107.2621,-1217.7053,885.12946,1072.3257,-620.1025,1701.3304,606.71594,-182.55618,1536.8608,658.2355,183.25963,1868.7026,763.58124,514.82294,1697.6189,771.055,878.2986,2041.7069,840.8354,1189.1418,1864.2114,838.3259,1619.1337,2091.533,830.5115,1244.5935,1916.0892,829.98236,1692.1838,2017.2759,978.8816,1052.9557,1836.4722,964.23364,1598.9413\nScreenshot_2021-02-11_at_11.23.27.png,pushups_up,1249.3171,707.1014,-1120.0156,1263.4115,671.39374,-1124.8439,1273.8253,669.391,-1124.9425,1284.4688,667.2245,-1124.8663,1229.94,672.10034,-1124.1777,1218.7811,670.14075,-1124.142,1207.5637,668.3672,-1124.1132,1297.4667,651.43964,-960.48975,1187.7784,653.6509,-950.9953,1265.2717,718.3642,-1043.1102,1231.5051,717.991,-1040.8672,1370.0834,725.69543,-769.01465,1115.9546,733.3842,-757.6031,1397.7146,933.5125,-815.18066,1097.3914,935.9234,-805.8145,1430.4742,1128.1245,-883.6242,1063.6577,1133.6768,-840.314,1456.6661,1156.8004,-954.9411,1029.768,1162.0852,-882.3228,1429.7577,1159.9258,-982.8483,1053.9856,1164.6818,-922.1632,1410.8516,1152.7864,-900.71454,1076.1307,1157.1398,-858.3223,1308.1089,901.76935,-18.646011,1202.9421,904.2122,18.212124,1295.3184,992.5769,540.40826,1232.3191,993.5934,586.143,1279.2418,1036.4031,1134.4927,1259.3846,1034.4371,1205.9836,1271.3173,1029.1855,1193.0833,1263.7454,1027.1975,1268.3958,1282.3245,1099.6458,1034.0812,1270.5525,1094.6564,1112.8977\nframe__X2koA7Kz61s__0015629.jpg,pushups_up,671.77795,473.57358,-866.46765,675.7036,450.55783,-923.8525,684.17615,447.3817,-923.7566,692.5107,444.00247,-923.694,656.48047,450.67697,-874.1926,650.88696,448.5993,-874.1634,645.7441,446.94553,-874.4864,721.0424,414.34045,-1003.00195,656.0193,419.8784,-770.5813,708.54016,468.31525,-878.60724,689.486,470.04163,-809.7984,890.0953,396.24213,-947.6079,668.8226,417.03873,-591.0715,941.5928,674.69403,-963.60693,648.2185,634.079,-461.77014,917.9512,909.3866,-1018.90173,636.8927,848.78613,-545.9442,921.3829,963.877,-1152.1208,600.11743,881.94135,-617.6761,872.2031,942.7401,-1153.8121,610.7058,886.27997,-715.86395,868.2247,925.568,-1032.5748,642.35126,873.9017,-588.79016,1129.9525,432.82913,-153.84128,1024.7797,455.52823,153.92351,1253.3485,564.3158,347.29312,1164.2034,556.27136,689.60205,1371.6462,662.80884,871.3887,1272.7637,638.12213,1303.2888,1400.0035,661.8529,919.8019,1301.7434,634.8019,1367.6006,1366.7538,758.00854,835.12964,1282.3344,721.01404,1317.5804\r\nframe__48tN82L4nD0__0011073.jpg,pushups_up,1222.7291,1525.5421,20.383596,1192.3901,1504.1256,-62.00377,1191.934,1498.5391,-61.977554,1191.3585,1492.4812,-62.40539,1192.1239,1502.2733,57.854378,1192.157,1495.4161,57.846756,1192.6387,1488.6266,58.02749,1205.877,1444.104,-240.77843,1206.1887,1443.5754,299.89948,1256.2997,1505.3258,-34.2046,1256.5975,1501.9692,122.434746,1369.3691,1426.8574,-531.1322,1412.4037,1400.1222,654.993,1364.0548,1718.7444,-849.85046,1419.4117,1646.3602,745.6438,1338.2174,1952.8456,-945.05347,1391.2,1835.257,373.87125,1260.6752,1975.8455,-1117.5496,1320.9519,1839.6503,377.3762,1260.2383,1948.8761,-997.03204,1317.7141,1842.8135,242.77525,1289.8007,1944.6918,-907.8126,1340.9999,1850.0593,303.19678,1822.1838,1370.4686,-359.62762,1829.3606,1378.6154,360.43372,2171.0835,1583.0697,-400.1428,2147.9336,1620.8152,279.4756,2534.3105,1771.078,-402.9518,2474.6956,1756.8878,470.38034,2608.0732,1777.1775,-416.21436,2543.6353,1765.7374,474.9074,2526.5134,1920.737,-722.90186,2479.0962,1882.5192,193.82002\r\nScreenshot_2021-02-11_at_15.26.31.png,pushups_up,1676.3392,618.11884,-1243.3224,1696.5135,588.2365,-1235.9082,1707.8898,582.2802,-1236.2604,1719.7214,577.28644,-1236.7388,1660.08,589.024,-1278.9049,1646.3411,585.33167,-1279.0354,1632.4961,581.68726,-1279.1167,1715.5486,542.131,-1098.9539,1601.1088,540.0383,-1289.9622,1667.2797,610.9708,-1177.4541,1631.3906,612.1897,-1231.388,1731.7719,491.5386,-875.52106,1383.758,490.5964,-1149.7761,1737.2394,678.24976,-584.73724,1174.3094,688.33093,-1176.9128,1699.7401,925.8538,-694.5855,1168.3141,926.5942,-1215.1755,1744.4806,979.1782,-768.0615,1154.9707,974.2493,-1345.5262,1707.6467,994.9404,-861.8971,1211.1425,966.9112,-1366.2258,1660.2673,981.4619,-734.57446,1220.2512,950.12396,-1238.5457,1383.3439,542.5942,137.26952,1236.7516,533.5125,-136.63258,1283.2391,555.3324,898.02997,1190.6759,552.22437,689.8717,1212.9626,544.48425,1671.8889,1137.6116,540.80286,1481.4186,1205.5538,522.15796,1752.5786,1129.5747,518.1439,1561.5385,1209.8925,607.65173,1694.5099,1145.9802,628.7287,1503.032\nScreenshot_2021-02-11_at_11.28.32.png,pushups_up,1383.5371,670.23865,-1567.8668,1392.0691,640.2091,-1560.7865,1400.5063,637.4834,-1561.011,1409.371,634.8755,-1560.822,1365.47,641.6108,-1570.6738,1355.5839,639.955,-1570.698,1345.5574,638.5553,-1570.6282,1417.1206,616.9183,-1322.5854,1327.2118,618.705,-1362.39,1396.3811,673.5715,-1461.3649,1367.7687,674.555,-1470.7148,1493.9142,654.34564,-1061.0729,1237.7205,648.46014,-1075.6644,1568.8041,796.94,-985.7958,1173.0411,782.377,-1074.9192,1586.7295,949.1543,-1111.7151,1165.4846,941.9011,-1173.935,1607.5769,976.571,-1202.5826,1149.8922,978.3877,-1279.4222,1582.0581,972.16895,-1262.7133,1186.9004,977.72144,-1307.8921,1565.5746,965.4224,-1140.8989,1199.1053,961.7909,-1193.5901,1398.3043,743.6375,18.190699,1278.3551,739.4492,-18.408932,1392.4098,818.21027,799.5032,1280.1088,815.153,719.14557,1404.9907,847.58905,1632.5989,1285.3794,835.09143,1529.6224,1400.172,836.4469,1716.2101,1292.7307,825.94324,1608.5367,1420.293,916.48047,1551.3226,1273.7069,900.2472,1445.8752\nframe__QGDq8m2MaB8__0016049.jpg,pushups_up,1360.8584,485.49484,-64.93317,1377.2535,468.6438,-45.70851,1376.0312,466.61017,-45.317127,1374.957,464.7557,-45.18831,1375.0267,466.91278,-96.08777,1373.2178,463.32587,-96.06211,1371.2344,459.84497,-96.381035,1346.4347,444.8268,67.55001,1342.4597,438.1559,-158.8156,1325.6992,484.28412,-11.781135,1323.9951,480.4362,-77.44423,1179.4244,407.05438,265.90936,1191.1823,494.75626,-282.6131,1192.1027,580.4515,365.53455,1188.8702,740.705,-324.77377,1190.0964,748.0601,320.08902,1222.6859,933.3924,-250.38863,1225.8481,757.0985,330.09268,1264.6908,968.8161,-301.91772,1221.4656,768.28925,247.91965,1277.2423,951.3966,-250.16069,1202.3887,773.08813,286.61472,1252.8783,935.1145,-226.0539,764.948,478.01062,163.04968,755.1234,531.3415,-162.77292,562.2908,617.5497,429.41888,503.16998,700.10535,-28.97885,356.41376,679.6011,700.0906,238.72176,825.8635,-14.655652,305.70694,674.3923,725.7798,174.09502,827.8992,-19.546728,364.9239,760.65784,714.06854,265.06604,921.2836,-110.842896\r\nframe__1BZM2Vre5oc__0006695.jpg,pushups_up,666.16235,831.9253,-515.81256,659.99146,819.93524,-560.0555,662.1563,818.2497,-559.8066,664.3345,816.48,-559.8019,657.48364,818.5729,-505.0767,658.29065,815.6627,-504.92163,659.21814,812.84796,-505.0326,681.48663,797.5593,-646.6035,674.54156,796.08203,-389.85214,689.00574,828.3073,-540.0944,689.0187,825.9391,-463.91974,797.12006,779.06494,-667.8012,727.9938,767.94745,-158.05399,856.387,885.5071,-773.9497,757.69385,839.1437,78.76448,850.59845,1006.92804,-877.88446,745.6982,926.501,-6.5865717,840.1831,1026.7251,-1003.03424,716.92883,938.64075,-57.636604,819.54364,1023.06354,-979.1509,722.6887,936.5577,-128.42883,826.24994,1017.79095,-877.2082,743.6582,932.986,-40.159523,984.5391,809.6752,-177.44438,943.6667,804.2214,177.50244,1097.8921,833.3448,314.49,1076.1898,824.6622,581.9679,1209.5973,834.4664,787.199,1171.1497,831.7262,1051.1041,1236.849,820.7488,829.4866,1193.0559,819.354,1100.732,1203.8906,900.7603,747.1789,1177.9054,888.40955,1064.2507\r\nframe__ohPA6wqX24o__0002544.jpg,pushups_up,1173.986,384.6187,-398.10538,1178.8855,366.52814,-394.26547,1177.2836,363.57104,-393.89352,1175.8162,360.9466,-393.68155,1175.4236,370.17877,-438.18982,1172.2186,369.1223,-438.36377,1168.9274,368.0728,-438.70633,1150.0095,346.66608,-292.66153,1141.897,354.9196,-492.96454,1148.8422,385.13815,-347.84747,1147.391,387.37186,-405.05435,1064.1584,338.25687,-81.38346,1019.95734,402.1375,-507.5594,1067.7782,454.85876,21.047396,988.00653,539.88824,-493.6484,1092.4897,564.8381,-120.65053,1004.8937,657.7559,-503.53455,1134.2869,549.6624,-165.84125,1038.5923,663.5761,-592.8543,1133.636,560.50836,-248.73325,1053.4087,641.40045,-562.7907,1113.5408,573.6851,-161.94185,1040.1002,640.22186,-496.6201,841.05066,391.0754,140.42015,813.42035,431.7203,-140.36562,751.90936,450.31442,491.7652,678.00397,478.9177,193.7185,653.29614,467.0807,869.252,526.8053,497.8032,501.83344,623.1074,465.46857,907.9827,488.67944,498.0385,523.32666,685.21875,519.54504,871.92053,561.3232,548.27997,422.15424\r\nScreenshot_2021-02-11_at_11.57.12.png,pushups_up,1307.9597,484.50455,-936.5761,1309.359,481.48996,-961.56226,1308.837,483.02658,-961.24805,1308.1152,484.477,-961.4497,1312.0057,481.0502,-963.4734,1312.4578,482.2078,-963.2427,1313.1832,483.00806,-963.2284,1303.7628,495.01736,-869.5847,1312.9033,495.6556,-881.498,1306.1718,494.9628,-881.9601,1306.1342,492.54486,-884.334,1308.1759,532.8554,-640.8624,1287.486,551.312,-652.0102,1336.6549,561.23346,-466.9257,1264.3097,637.5348,-463.06818,1343.6901,596.50665,-453.85446,1281.7913,716.0052,-413.74326,1340.873,608.3634,-480.9354,1280.9039,736.9092,-445.60498,1332.7267,604.20575,-512.7988,1281.3657,736.3054,-459.97296,1335.2012,597.47406,-469.12143,1285.2515,727.9405,-421.20682,1356.39,483.93652,-10.324271,1347.9269,491.47455,10.547037,1337.7576,491.38608,326.15543,1320.2701,519.8971,362.60016,1324.3364,565.0224,916.5568,1308.5967,550.2511,912.05084,1318.7635,581.2348,978.1097,1307.6412,554.9347,966.9542,1336.1039,587.5414,919.2644,1315.5618,567.18304,889.0178\nframe__ieyzL5OaPZk__0007943.jpg,pushups_up,1200.55,755.31775,-7.1106076,1218.9171,745.01794,7.4767385,1220.1434,741.6488,7.6320066,1221.3894,738.4458,7.561747,1216.0704,745.61163,-49.57424,1216.102,742.78516,-49.506798,1216.073,740.0303,-49.48813,1220.5298,715.407,86.624176,1214.8353,718.14655,-173.38956,1188.0295,744.57886,30.845894,1185.8999,745.66284,-44.317158,1129.6455,669.66425,272.77478,1137.9281,713.63354,-282.08792,1113.6348,795.4082,326.125,1105.0198,849.7529,-345.60217,1108.1752,891.7774,162.64343,1095.9656,970.8172,-322.70255,1143.8024,894.39935,172.68718,1130.5454,989.9644,-380.90463,1140.9507,903.9815,109.47817,1136.3641,974.8781,-319.22415,1128.3418,909.7811,132.51788,1123.2014,969.6982,-296.37518,889.0029,670.2844,177.70648,889.4624,697.10834,-177.45358,726.44415,758.4509,288.7329,727.95807,802.5442,-116.80397,567.34827,824.81964,438.86594,542.3077,850.5206,13.511986,525.01074,826.0657,448.99124,497.42548,843.94495,9.797582,585.5938,908.03204,371.31543,558.6817,938.6154,-116.13919\r\nframe__4ZUNCOjTIh4__0000840.jpg,pushups_up,828.10834,506.73364,-1046.8082,827.0355,482.7849,-1078.9995,833.30365,478.5799,-1078.8822,839.54926,474.24136,-1078.9384,811.7876,487.0062,-1034.2489,807.22125,486.17746,-1034.1003,802.92896,485.76074,-1034.2753,862.0733,443.39304,-1062.9637,811.3742,460.081,-857.69336,858.2499,495.2393,-1024.095,843.0367,502.03244,-963.52374,1021.307,423.66788,-976.2815,831.5492,441.78583,-608.2004,1143.5475,612.961,-992.75653,832.67554,576.995,-355.09866,1157.864,805.44495,-1053.7598,801.8433,718.51074,-335.27115,1162.5131,844.40753,-1171.823,757.93146,728.4057,-372.03613,1122.6028,838.17725,-1168.9507,762.75195,743.9405,-433.774,1117.2401,825.8441,-1059.864,792.48914,741.9209,-360.74765,1180.6284,458.42587,-130.48674,1096.0902,471.33298,130.72682,1287.4009,512.4664,498.82083,1187.2178,524.58136,699.8535,1369.9413,504.43683,1133.9407,1269.1965,521.99133,1368.2883,1384.4285,484.1707,1199.033,1283.41,508.11935,1438.2296,1381.3212,574.31854,1121.1035,1291.9973,572.0083,1390.9656\r\nScreenshot_2021-02-11_at_11.56.20.png,pushups_up,1346.7673,526.71716,-1810.1459,1377.0728,477.43323,-1821.9625,1394.0688,472.76645,-1822.1907,1411.7292,468.12936,-1821.8618,1321.474,473.3706,-1827.5067,1305.326,468.18185,-1827.4944,1288.9222,463.5128,-1827.3312,1452.7156,418.82324,-1570.7994,1268.8356,404.22583,-1582.5536,1375.3613,523.56525,-1689.1921,1326.2341,523.51,-1689.4117,1603.6311,473.6994,-1237.3171,1130.0612,441.01828,-1283.0988,1681.6088,790.037,-1324.6498,1038.2584,783.3046,-1436.397,1729.5349,1115.9204,-1497.75,963.8714,1097.7155,-1507.2821,1792.1521,1160.3484,-1633.7136,921.8301,1133.7174,-1641.7701,1731.0035,1154.5698,-1682.1024,988.5097,1146.3453,-1664.1588,1690.9967,1146.7059,-1532.6698,1014.7326,1138.9241,-1528.9639,1435.0153,661.63995,15.617921,1228.3506,655.16473,-18.057121,1417.4535,802.0246,878.89404,1233.7599,828.0773,814.89557,1411.9352,821.48096,1867.7472,1272.3414,830.8767,1783.4175,1402.8865,794.19403,1969.903,1292.3207,804.4826,1879.6476,1420.6549,924.24664,1749.8634,1266.1024,932.27374,1654.7404\nframe__pBo_DjHqVws__0004386.jpg,pushups_up,1516.4995,445.47974,-31.948597,1532.316,431.1789,-17.73797,1529.501,426.86255,-17.43514,1526.8121,422.80414,-17.245203,1534.1918,435.44952,-79.596306,1534.1876,434.00647,-79.52612,1533.9915,432.65207,-80.135025,1498.3629,405.818,94.54685,1508.7009,415.47192,-196.61284,1480.4116,439.2491,22.967413,1484.4614,441.88144,-61.03936,1316.7731,395.65387,308.963,1370.9243,446.2235,-350.56134,1348.7526,596.5178,415.64124,1418.8547,671.2605,-434.7261,1376.9152,728.6838,274.65582,1486.9531,851.14105,-378.38983,1432.7866,713.39417,277.41153,1554.1755,870.03906,-436.00723,1435.3289,729.8698,173.01389,1559.3235,839.7167,-365.42688,1412.9377,748.7737,230.40952,1530.486,835.8693,-346.5013,935.67456,448.96045,206.74335,927.2872,480.77982,-206.29826,825.046,615.86194,513.7741,670.36633,671.85126,-139.35362,615.726,616.1317,900.4699,376.20242,804.94867,-166.42213,573.84784,591.1448,937.2899,316.34702,803.9417,-167.84218,577.4418,660.6378,986.5654,375.3411,886.38696,-255.9345\r\nframe__g9QFlwHD_oQ__0009581.jpg,pushups_up,1299.1573,783.0959,-1167.7103,1303.9137,761.06274,-1150.2396,1311.0011,759.5564,-1150.397,1318.1799,758.4306,-1150.7831,1281.4015,760.8935,-1170.4081,1272.3857,758.85406,-1170.2112,1263.2534,756.971,-1170.2177,1316.6564,747.1111,-945.73096,1244.442,743.5296,-1036.3735,1304.204,791.1005,-1078.6068,1281.4169,789.72345,-1104.789,1341.1007,768.2306,-719.6121,1195.9983,742.6816,-839.36725,1383.9847,892.1271,-674.7233,1139.1064,882.84894,-848.18774,1412.7714,1025.9266,-762.0916,1128.257,1029.9235,-914.6853,1446.9224,1053.5244,-793.3714,1118.9613,1059.9373,-993.73376,1427.4058,1066.4625,-845.95013,1145.3566,1054.7819,-1003.286,1403.5431,1057.8622,-783.02136,1153.7047,1049.9292,-926.5944,1221.4706,768.6089,65.27789,1156.6042,749.918,-65.22251,1188.3582,811.53357,455.55518,1125.2333,840.5498,358.62012,1142.11,832.4953,1066.1206,1099.4326,856.2917,1040.062,1138.6747,828.4983,1132.0608,1104.2006,852.30646,1108.6232,1135.8365,874.76666,1078.1089,1083.8523,896.2163,1060.0594\r\nScreenshot_2021-02-11_at_12.29.46.png,pushups_up,1310.311,433.75122,-1844.8363,1326.3644,385.98495,-1844.6276,1342.7698,383.489,-1844.665,1359.3271,380.62186,-1844.534,1276.3893,389.44208,-1844.0726,1257.62,387.6588,-1844.2079,1238.9976,386.4876,-1844.3645,1370.5187,361.60406,-1556.6239,1201.63,374.79315,-1582.8225,1335.3969,452.84814,-1716.0149,1279.3822,453.1754,-1724.2772,1464.1102,428.57275,-1257.2777,1107.876,487.97128,-1209.8582,1546.5667,726.9189,-1269.7651,1057.4899,755.75574,-1220.1255,1586.7416,1020.8029,-1413.7444,1023.5714,1041.3373,-1398.6572,1619.252,1078.0143,-1536.1975,971.28723,1097.9615,-1511.3192,1577.2792,1087.9574,-1570.7228,1005.3338,1088.3619,-1585.5013,1555.0035,1072.7955,-1435.738,1042.6517,1068.3331,-1437.17,1438.1262,629.99414,-23.25607,1281.3055,663.4737,24.274458,1459.4318,790.8225,779.92426,1281.2205,794.5584,800.72424,1465.6365,832.0808,1659.8463,1304.5668,865.2869,1740.9377,1458.0338,831.39014,1748.0947,1318.0574,860.1449,1835.1915,1499.229,908.294,1608.8535,1309.7952,960.0338,1695.9944\nframe__0UjHJ6g8YV8__0000923.jpg,pushups_up,1620.6971,686.3647,3.5824568,1645.825,668.5228,14.92208,1645.5372,664.1338,15.061047,1645.4656,659.8998,15.036756,1644.9171,668.4369,-49.09287,1645.2928,663.1222,-49.339207,1645.5829,657.94055,-49.7737,1635.6183,623.86255,97.93585,1636.1855,620.2678,-185.55922,1595.1753,670.5763,45.61715,1596.4872,668.76227,-36.95129,1482.6274,607.94836,276.63388,1511.1528,606.28015,-296.64703,1455.2946,814.65906,340.96524,1489.9194,824.1255,-325.1692,1486.2095,974.85504,232.271,1518.5684,1017.1522,-300.66116,1532.9054,974.76416,236.39957,1560.7476,1034.1743,-377.0469,1537.8147,995.56665,163.34454,1567.5591,1021.7773,-330.11606,1520.9219,999.96173,196.47328,1551.4939,1020.24207,-283.23346,1138.5378,692.86993,177.5369,1132.6265,686.74554,-176.90439,885.81055,815.7994,240.91135,877.6616,817.97626,-90.569214,659.0333,898.9291,408.32446,617.0705,911.4953,46.272835,609.8969,896.5245,413.16193,560.0189,905.8412,35.761154,665.16614,987.42615,252.09337,642.29535,1021.2323,-163.96423\r\nframe__ihCpHCvZ4Ok__0019905.jpg,pushups_up,913.0045,405.18658,-406.581,893.47797,379.31805,-405.90878,895.99,369.25482,-406.01437,898.47156,358.96344,-405.92975,887.43835,400.38947,-368.4578,885.2966,406.6929,-368.3358,883.39,413.11197,-368.05713,917.1818,334.7997,-301.74707,896.6528,404.91028,-131.61649,943.9184,387.3091,-360.09454,934.9377,417.23593,-310.89447,1025.6963,391.87094,-439.12524,1029.927,378.47974,239.30846,1036.5459,582.4489,-510.93396,1050.0576,536.57886,296.97668,1008.7657,748.8878,-487.5468,1019.11444,669.4113,72.05926,974.49713,765.2736,-576.2481,980.4998,677.5452,48.120945,965.5261,756.31494,-533.6796,973.86774,682.9713,-29.51507,982.70166,747.4257,-474.9094,991.8052,685.4204,29.295248,1359.8192,460.5337,-207.01186,1348.8711,451.99994,206.52357,1584.3326,551.96967,-334.86337,1546.4299,546.97565,328.2596,1821.1993,629.601,-382.1288,1751.9724,587.2408,516.73334,1879.8445,626.1602,-401.3153,1805.6886,578.79486,526.3699,1794.5398,725.38043,-567.7591,1728.4742,689.4779,429.75195\r\nframe__A61dLcsS9Ck__0001099.jpg,pushups_up,442.0249,462.05237,24.393644,438.40518,434.85678,-21.20024,440.6745,431.8207,-21.145836,442.7967,428.36694,-21.222717,439.20953,434.4332,45.969112,441.8707,431.7545,45.894615,444.74213,429.20636,45.892277,470.73358,412.99802,-126.688156,471.58228,415.49823,179.26466,466.78796,469.4144,-2.875457,466.63226,470.60913,85.2712,561.8415,492.5862,-278.50784,629.6233,464.17514,409.7043,578.5149,674.1728,-315.6335,660.2796,636.13983,461.90036,578.21265,862.64996,-281.03638,655.8532,782.891,373.49152,542.66785,875.16815,-342.4494,624.9102,769.9908,408.4746,538.7286,859.9554,-273.10968,615.2102,785.83887,338.0289,554.10876,854.58124,-252.41,623.57166,797.2788,342.9388,881.0531,600.83484,-217.95613,903.4671,567.38226,217.79533,1156.219,692.2929,-190.30742,1138.5665,652.6431,234.67879,1410.427,740.24554,-152.4261,1387.2135,693.30255,355.63873,1455.8629,722.9117,-155.93137,1433.838,683.4479,364.33737,1416.0068,820.41113,-310.9594,1400.1578,771.7377,271.78497\r\nframe__RI-9wv8fK1A__0006813.jpg,pushups_up,513.6398,441.94998,-29.543625,494.6065,421.68152,-74.9683,495.12457,417.69797,-74.9411,495.55325,413.32666,-75.100746,494.07376,421.4703,-14.738589,494.15097,417.20032,-14.677212,494.50446,413.1863,-14.443561,513.2603,382.57828,-166.7852,508.75146,383.41504,107.97736,541.6163,432.1949,-53.29116,540.88885,432.4997,26.3693,642.2528,396.103,-318.3099,678.39056,391.77722,350.97943,622.0303,618.2201,-454.27216,694.927,595.4025,442.4234,600.3708,836.33887,-478.4633,682.1742,778.8109,324.10443,558.7294,859.9656,-556.772,645.2346,791.71045,338.83337,557.06494,848.2994,-499.30835,636.167,795.5204,264.8833,573.4344,838.5275,-459.1056,650.1243,798.86536,288.79178,1021.18207,475.135,-197.92038,1022.5581,481.9113,197.97,1306.6489,623.53467,-166.27963,1294.7034,612.69037,185.72998,1592.2609,690.048,-122.10713,1593.6072,660.42737,254.02176,1649.938,675.8336,-129.72902,1647.9272,647.8375,252.46393,1590.3828,791.1133,-303.71912,1617.7012,759.2594,113.84024\r\nframe__8bD7D4JsmCo__0005758.jpg,pushups_up,1386.7266,547.6262,-871.9637,1406.2524,511.15393,-868.41815,1410.298,505.16455,-868.31934,1414.4948,499.6643,-868.6038,1387.2816,512.3106,-936.7231,1379.4318,506.9469,-936.97156,1371.4254,501.61746,-936.9858,1400.516,444.6225,-735.99664,1344.7246,444.6779,-1043.853,1360.2957,524.2854,-805.7267,1346.2314,528.63403,-895.6914,1382.5729,388.40747,-577.9509,1139.2827,413.03455,-952.77216,1413.7649,613.21094,-330.82843,1087.605,696.19806,-957.41223,1419.7135,835.4675,-404.39215,1115.9427,936.50726,-974.58,1479.4695,863.75415,-488.8159,1137.7328,981.7575,-1107.9246,1461.0448,871.30347,-579.04254,1190.7709,967.7461,-1099.9905,1417.8842,859.5949,-443.9536,1182.209,956.49225,-982.543,1017.42084,363.79553,160.21217,898.6404,345.42157,-160.79785,825.8187,509.35632,571.7794,743.768,477.0201,361.0652,683.20264,562.7319,1123.2295,602.1793,540.5108,880.9334,650.98914,552.52185,1177.027,567.9,525.8757,925.22656,686.75226,659.5462,1090.5975,630.5389,649.1456,807.2025\r\nframe__ihCpHCvZ4Ok__0007943.jpg,pushups_up,669.3549,499.74103,-1059.7595,657.0763,476.18857,-1137.143,661.5787,470.08887,-1137.0142,665.8144,463.86746,-1136.8469,646.9307,480.937,-1057.8341,644.1013,479.19946,-1057.7056,641.7316,477.8059,-1058.0393,685.90356,425.25055,-1274.8855,651.37994,445.91858,-895.5,704.86505,484.63748,-1087.3849,695.2644,488.8451,-976.5501,852.1447,401.35474,-1249.7524,693.38336,415.01663,-563.3154,859.7257,658.162,-1341.257,670.3205,599.2188,-326.3856,840.8125,855.1269,-1468.2009,656.23627,748.6846,-509.75882,835.8177,903.0396,-1673.8822,624.4523,764.90643,-609.2144,791.8721,876.25604,-1660.2924,629.58295,776.30255,-743.4456,792.66815,863.8683,-1482.5142,653.0993,771.5267,-577.6553,1100.928,413.82166,-249.68402,1006.73114,431.72293,249.85611,1283.1356,498.1922,160.19226,1112.6902,511.20554,1020.283,1478.7925,562.4865,654.9656,1260.6493,559.67615,1860.6947,1524.5487,556.112,687.7853,1304.9937,552.65393,1941.0825,1471.5774,666.297,465.91867,1248.3495,652.5871,1860.1482\r\nScreenshot_2021-02-11_at_13.20.48.png,pushups_up,1271.5206,390.7905,-1826.8873,1302.185,324.88583,-1813.2792,1327.3783,319.2863,-1813.8501,1352.9491,313.56598,-1813.8651,1230.6129,332.23038,-1801.188,1205.0953,332.72635,-1801.228,1179.9266,333.5058,-1801.4471,1396.2455,312.2831,-1561.9131,1153.9495,336.67578,-1488.9232,1322.8102,428.50732,-1720.2128,1239.9893,438.51556,-1697.4495,1542.0276,496.06137,-1215.5787,1087.6315,481.89606,-1136.9492,1639.8188,772.4037,-977.09595,1021.72815,745.1834,-894.9836,1603.0822,1031.6956,-1137.5145,973.42053,1006.47375,-1039.903,1633.9077,1083.4836,-1299.0791,926.0268,1056.0474,-1155.4286,1570.5969,1075.6102,-1354.478,981.502,1067.2272,-1240.5115,1544.751,1050.6736,-1173.6255,1023.5069,1044.3733,-1089.6223,1401.9319,634.7088,-22.690828,1208.534,617.0848,23.019342,1376.6592,663.64545,803.41504,1225.0953,655.2548,844.25085,1397.139,612.3755,1682.1713,1254.0017,609.1448,1693.1971,1399.7783,585.4362,1779.3267,1269.3046,581.7923,1790.9615,1379.721,670.89343,1669.894,1248.8386,671.64185,1690.9026\nframe__RTF4ADblouI__0001772.jpg,pushups_up,2679.1685,640.7026,-1044.5676,2698.4868,550.3577,-1032.6761,2695.3542,545.02234,-1032.3344,2693.21,540.6229,-1033.2585,2684.0227,549.60626,-1171.2726,2669.6714,538.69507,-1171.895,2655.1145,527.9917,-1172.2172,2590.0051,486.0314,-794.85425,2538.4492,461.96567,-1389.8999,2578.6208,659.4576,-928.28467,2563.328,650.10675,-1100.1685,2284.3403,631.0179,-376.81076,1983.2925,612.94464,-1486.7861,2118.7627,1105.6226,-28.332108,1677.8867,1227.3452,-1454.06,2104.905,1615.8716,-108.127525,1705.4893,1772.2898,-1350.2917,2159.3857,1682.7601,-182.8276,1716.1249,1872.5059,-1577.363,2160.8,1706.4851,-349.39743,1800.3307,1847.1814,-1582.3767,2097.9773,1690.3177,-187.58362,1784.9434,1813.4935,-1372.0883,1445.7543,1052.002,375.3727,1257.7089,1004.8771,-372.72958,1001.45197,1381.6213,854.7315,762.08374,1311.2013,265.66245,490.65863,1486.9005,1593.6195,241.82156,1475.0958,945.08276,367.73654,1446.8644,1654.1985,111.16882,1446.2745,976.74554,506.89563,1751.3789,1468.3263,306.94495,1782.378,641.25104\r\nScreenshot_2021-02-11_at_11.41.34.png,pushups_up,1214.3771,327.0954,-1314.81,1233.8667,274.0653,-1325.9108,1250.3058,269.677,-1326.2142,1267.0819,265.0643,-1326.2297,1178.8069,276.4314,-1325.9438,1160.0094,273.4518,-1325.9539,1141.1986,270.8126,-1325.8334,1288.5339,228.05087,-1153.0098,1101.8788,237.4192,-1148.0713,1240.4777,334.85434,-1228.7621,1184.8905,337.0535,-1226.3928,1403.866,276.5232,-906.4752,1005.0321,298.5687,-934.38477,1485.4423,512.66425,-940.7787,971.5229,556.5713,-888.0038,1479.8805,785.3208,-1040.1101,996.03766,824.5848,-985.1207,1511.5458,828.823,-1128.6469,962.33496,868.79645,-1080.6592,1454.2546,832.3959,-1148.3754,1015.73566,864.7819,-1089.7648,1432.6144,818.57574,-1056.9904,1041.1255,847.3058,-997.7758,1300.6332,445.83945,-12.680403,1125.3258,455.888,12.666351,1317.6646,539.7255,631.6988,1107.1147,551.36237,663.1191,1324.9899,555.29504,1276.0217,1101.5763,548.96655,1361.7095,1319.4968,536.35315,1345.3971,1110.7549,528.5946,1439.0872,1331.1067,638.904,1213.8132,1094.6052,622.1498,1319.8356\nScreenshot_2021-02-11_at_15.15.26.png,pushups_up,1026.1758,438.06616,-1402.1438,1039.4219,374.35257,-1426.0837,1055.8351,365.85718,-1426.2911,1072.2839,357.14575,-1426.6211,1000.22876,389.71872,-1353.9426,988.71747,392.04895,-1353.843,977.04254,394.97714,-1353.685,1128.4822,323.92032,-1334.3348,1000.1149,373.71402,-1012.28253,1087.25,442.8691,-1353.9795,1042.0918,462.7772,-1260.7992,1408.132,426.08307,-1234.4231,1042.1488,475.55902,-745.60803,1586.8262,755.2126,-1318.933,1059.5741,756.30054,-586.1387,1624.9542,1082.027,-1389.458,1039.5952,1056.5186,-668.3838,1658.4259,1147.3885,-1538.4105,993.9218,1106.8854,-696.34375,1600.7568,1147.5317,-1559.0671,1005.281,1116.4683,-800.9138,1580.1891,1124.8387,-1405.4745,1050.4043,1102.5526,-718.6394,1605.2826,746.5995,-174.84215,1434.8047,760.03564,176.49037,1718.1523,849.78894,618.4699,1542.3716,848.24316,1031.0087,1813.9404,896.28644,1409.7852,1668.4996,883.25745,1806.4124,1839.9348,888.806,1481.9729,1702.1361,878.5362,1883.9103,1782.8131,990.25085,1294.7701,1634.3474,967.65924,1776.9878\nframe__ilh-78AaSjQ__0003415.jpg,pushups_up,461.27313,278.00085,-22.598677,453.15958,258.59497,-67.9787,454.67114,256.41666,-68.12091,456.03387,253.93945,-68.125824,453.81876,255.9561,-6.932374,455.50427,252.89197,-6.918286,457.45837,249.9397,-6.976458,479.35306,237.27338,-191.42087,480.01575,233.52823,86.9062,486.63425,280.7854,-58.021175,487.0859,279.74252,22.898672,583.72705,272.9341,-322.27258,615.3222,257.18484,295.47363,581.96814,445.96255,-345.83255,628.94653,421.4307,374.25388,578.1071,616.7297,-251.59682,616.22235,564.85736,263.87784,551.31134,642.9174,-309.32135,589.04254,567.499,281.38324,545.30457,626.1219,-260.29526,581.47876,580.62866,213.41412,557.53455,615.41345,-231.40132,592.70386,583.72705,234.8362,891.721,316.79422,-204.71153,898.60614,302.94733,204.80995,1084.7571,432.10968,-149.23907,1076.4202,413.25272,300.89993,1298.7205,508.44492,-64.27153,1274.9672,481.60406,468.97516,1347.419,500.48065,-69.49836,1324.1641,475.7455,480.47717,1270.1135,603.3628,-214.15714,1250.0336,580.89294,403.29776\r\nframe__gUXOyOrFQcw__0016351.jpg,pushups_up,1567.3379,460.19678,31.921892,1588.163,437.2664,41.837345,1585.6661,430.6886,42.078926,1583.4108,424.38,42.38609,1588.7941,442.62897,-28.584942,1588.961,439.36176,-29.034561,1589.0,436.1232,-29.517279,1554.8374,391.56595,133.5387,1564.9065,404.8748,-171.3629,1528.7233,449.06577,79.213905,1532.3098,453.44275,-10.751505,1337.5107,374.87164,362.13068,1393.0376,431.66153,-305.5124,1319.6498,646.8057,387.51074,1372.84,699.8364,-320.44937,1331.8969,832.72266,325.71967,1394.2595,904.2555,-278.8436,1389.3629,844.42554,348.6691,1454.3617,934.39886,-357.6449,1386.683,857.9257,280.57938,1455.98,916.85974,-297.20474,1367.3497,862.26013,294.1903,1427.5142,909.5422,-254.16446,889.59595,371.67834,195.98601,897.42444,398.83194,-195.3802,569.31287,552.4364,324.5844,571.21893,645.6276,-114.51634,311.7464,747.22925,485.24167,239.44205,855.77936,-12.451416,251.68997,764.7727,488.46014,161.67743,880.18536,-21.09681,330.97595,851.2425,330.4806,290.64142,956.3183,-205.00146\r\nScreenshot_2021-02-11_at_14.42.43.png,pushups_up,1689.2028,500.34232,-790.31445,1693.1562,455.28967,-773.3426,1690.6332,450.58456,-773.10986,1688.5712,446.7007,-773.2283,1686.9703,457.56497,-862.74207,1680.2083,452.16122,-863.1903,1673.2716,447.02106,-863.4106,1638.1147,406.95123,-569.20233,1619.3323,408.2392,-967.04474,1641.9932,499.14404,-691.59607,1637.3605,498.49054,-806.0284,1510.1279,443.38815,-271.45132,1360.2786,445.28445,-948.7062,1435.2803,603.5844,120.5238,1149.0199,618.1725,-977.58185,1490.4138,800.55853,136.88275,1215.9727,861.38934,-1002.6901,1525.587,824.3143,132.4081,1230.3638,909.9058,-1117.9081,1531.1151,852.0395,24.053127,1270.3765,897.64014,-1104.869,1500.3374,849.04565,93.01219,1265.6241,883.32495,-1004.7382,1127.1543,620.6135,227.90483,1042.1216,610.9462,-226.64703,957.67267,715.99475,864.1484,884.7315,681.46075,415.21808,799.796,732.43445,1672.445,718.4055,735.9421,1206.0739,755.232,710.8899,1751.6904,672.3173,724.8707,1279.4257,811.888,829.42395,1663.4149,733.5331,837.4314,1143.0679\nScreenshot_2021-02-11_at_13.51.08.png,pushups_up,1460.8226,385.99896,-1667.4686,1490.0452,308.98505,-1682.8013,1512.4951,305.23856,-1683.0491,1535.3163,301.33188,-1683.0018,1426.304,309.60706,-1670.1151,1403.7599,305.89972,-1670.2529,1381.2142,302.53384,-1670.4487,1573.9086,275.73553,-1417.3801,1355.2516,277.07544,-1354.2572,1505.9574,406.67783,-1539.7883,1430.3778,407.33255,-1520.6785,1760.2119,412.70227,-1139.7416,1228.6831,434.44858,-1103.1718,1847.8005,779.67896,-1155.7131,1175.0487,816.4592,-1135.9717,1883.1376,1156.5596,-1363.8486,1126.189,1149.9321,-1368.4872,1923.9828,1240.9362,-1487.7872,1078.3325,1214.9067,-1491.7126,1870.4214,1239.1011,-1553.6235,1112.0424,1222.7488,-1581.467,1830.689,1210.527,-1398.8037,1163.4749,1198.9496,-1418.8081,1643.4128,895.5739,7.9290285,1410.656,907.45776,-6.5037284,1651.4752,1060.5712,814.0921,1418.5272,1104.8843,820.52496,1588.254,1149.4241,1713.3004,1445.1486,1160.2366,1803.4922,1568.9604,1144.9991,1800.543,1452.3746,1152.607,1899.3712,1586.253,1270.0863,1613.9548,1443.5206,1268.8696,1700.9495\nScreenshot_2021-02-11_at_15.09.18.png,pushups_up,1110.1182,648.2409,-789.14075,1097.3671,624.79724,-850.76025,1103.0782,618.6915,-850.7375,1108.7063,612.4939,-850.9268,1085.0892,629.33746,-779.0623,1082.2576,627.52435,-779.0055,1079.7035,626.1041,-779.38116,1139.8995,568.17017,-979.398,1099.2731,588.2619,-649.4666,1153.8019,628.62054,-820.2092,1143.9176,637.03296,-722.88464,1398.7208,513.0244,-964.20703,1178.1576,536.08673,-412.74985,1565.7925,738.5271,-952.8944,1225.9634,708.097,-68.35131,1528.185,967.3709,-971.75037,1210.9094,905.448,-120.66684,1524.9275,1016.5213,-1113.6273,1175.9797,934.1984,-167.54843,1470.5686,997.46625,-1109.8252,1175.4901,947.0561,-272.01157,1466.5461,980.3306,-981.9081,1207.7073,937.6175,-165.97339,1744.7477,579.72034,-210.61192,1634.872,601.1307,210.98611,1912.327,663.7256,381.68076,1804.875,679.4656,773.27686,2070.1897,695.24603,998.6866,1952.7484,709.2189,1393.1042,2108.8083,676.9163,1049.7264,1992.5294,693.86597,1455.1691,2057.0955,805.391,919.45135,1945.5437,806.96246,1392.1906\nframe__RI-9wv8fK1A__0004274.jpg,pushups_up,903.01874,374.8977,-1572.227,907.2248,319.98352,-1588.1343,922.22485,312.52853,-1588.2339,937.3252,304.76013,-1588.3099,857.8389,334.65833,-1585.7771,838.93176,335.8523,-1585.8634,820.1943,337.5288,-1586.0415,943.12134,261.18503,-1339.1544,776.0771,313.24802,-1358.8071,926.3613,372.14456,-1450.085,874.3948,384.8063,-1456.717,1070.7977,251.77328,-1051.5583,673.04443,380.45364,-1013.48535,1235.2917,467.44162,-944.8918,595.8302,606.81866,-857.21063,1320.5914,736.6838,-983.6691,620.3877,844.9283,-884.00525,1357.1741,783.5406,-1037.6686,593.7378,889.2247,-952.9498,1332.0531,790.8007,-1077.5768,623.3945,887.2289,-1003.31726,1306.5316,782.81775,-1003.17755,655.0733,869.19525,-912.36237,1084.9121,462.37262,-35.04725,909.5577,537.39465,36.126392,1109.5742,610.8528,725.96594,964.3412,662.17554,772.6257,1110.3849,661.22095,1501.9937,977.38,712.87823,1637.3212,1104.2805,655.8688,1578.6093,984.1078,703.71796,1722.7482,1133.2723,746.5845,1399.8204,997.88416,791.62103,1533.7139\r\nframe__-0eYiItN2D8__0002754.jpg,pushups_up,1085.474,387.0704,-1169.262,1099.4309,367.32343,-1175.4094,1108.1895,362.3797,-1175.8116,1117.1725,357.92697,-1176.0989,1071.6893,370.11475,-1208.8638,1062.4493,367.7678,-1208.96,1052.9463,365.67477,-1209.0693,1126.1852,330.67444,-1057.2959,1040.3911,331.2544,-1202.3362,1089.3197,377.4377,-1103.9027,1065.2595,380.0876,-1146.0487,1188.3215,289.19818,-908.5077,922.1583,303.61804,-1011.7075,1304.0901,439.58524,-809.7705,803.3581,460.36694,-1028.0771,1368.8923,599.36774,-868.6088,704.982,635.7551,-1085.1116,1424.9934,622.4502,-921.54254,663.9145,664.11554,-1165.5123,1397.3221,641.7292,-968.7603,700.7473,671.7341,-1191.3937,1361.6533,641.5645,-885.8137,724.05005,663.9182,-1104.7083,1017.64984,342.7747,79.628075,908.769,329.18768,-79.88236,994.4047,422.36823,702.0041,873.2041,379.46664,624.991,977.7079,472.84073,1414.1918,865.7374,408.599,1360.332,973.81384,472.3486,1491.1417,869.5345,406.86398,1433.2375,981.87024,521.8482,1422.0273,859.08655,465.40707,1363.1188\r\nframe__e-GKf6MJ7mc__0006439.jpg,pushups_up,675.8659,568.97424,60.03515,654.94604,561.17004,14.80311,654.09247,558.0101,14.68171,653.1391,554.49097,14.484485,654.57166,560.89056,68.36455,653.7674,557.3224,68.3115,653.3106,553.7623,68.26009,654.00745,528.80835,-107.4121,654.7063,530.3345,142.32362,692.18365,556.7051,26.6717,692.24634,556.2051,99.34618,743.4002,503.72137,-237.2129,778.40015,488.4947,341.00122,746.7508,682.2005,-282.729,816.7414,648.55286,423.4026,771.209,848.5764,-209.37175,831.9796,773.15674,286.40482,732.4655,875.97217,-264.09567,793.1058,775.2035,315.6409,729.5055,857.9392,-195.44696,786.545,786.83295,242.91824,744.99457,848.16187,-181.39899,800.7294,791.8701,255.79225,1084.1226,515.3316,-176.92374,1090.0745,508.89856,176.53827,1299.6622,648.6929,-80.88601,1293.3817,649.98193,250.76935,1518.1035,734.9461,26.744411,1496.633,734.06213,403.8755,1564.3352,728.2477,29.912277,1539.0084,731.21954,415.0195,1503.5453,819.54755,-92.38369,1503.6353,815.6638,325.62292\r\nframe__J5FZeUV6l0E__0009217.jpg,pushups_up,297.4732,412.8698,-162.36362,284.40222,401.51102,-201.9179,284.62613,398.6556,-201.88806,284.7881,395.6165,-201.84297,284.13394,401.7327,-152.96094,284.31418,399.64267,-152.9249,284.69095,397.6804,-152.85002,294.20682,375.6969,-256.5016,293.47238,378.44257,-33.09781,314.49683,404.34958,-176.60764,314.4697,405.3444,-111.88403,369.88968,380.23108,-356.534,385.766,366.14343,159.69931,365.7852,502.2945,-469.1785,397.8678,475.6969,185.51788,361.91064,605.3475,-508.51904,394.61655,565.99713,57.87609,335.33362,611.9978,-583.02386,368.32465,565.3365,58.9561,334.53522,606.106,-539.57404,366.257,572.09924,2.0449634,345.62964,603.6985,-495.98706,375.41223,576.0478,28.620604,576.48236,389.24316,-155.8642,576.1942,384.08908,155.90224,715.38586,476.4661,-140.28322,704.69446,465.4338,236.84915,864.68933,534.96466,-95.92639,838.73956,505.45242,361.36337,898.89124,536.99054,-104.37125,867.6437,507.28293,369.31323,851.9436,597.9116,-259.34045,839.6911,556.3492,266.41022\r\nframe__CjlLMXJoWsI__0021096.jpg,pushups_up,712.01215,727.08014,-49.9718,700.6572,707.4136,-90.9081,701.7245,704.2261,-90.92125,702.6771,700.75507,-91.0412,700.0076,706.8176,-31.634903,700.7079,703.59766,-31.580845,701.63513,700.48206,-31.538593,718.66235,679.60236,-184.19124,716.6277,679.8959,87.009315,734.04553,723.48236,-76.78037,732.8493,724.0338,1.5503416,804.6466,711.2066,-310.58334,843.7219,681.47095,289.03314,811.9043,873.5439,-363.53735,852.6832,827.07074,318.11713,808.11163,1016.00415,-326.24994,844.49994,939.4563,165.66626,771.2186,1028.7401,-394.2823,810.5348,931.0628,186.07446,765.32684,1013.8715,-332.29327,806.51263,944.5222,118.07779,779.5527,1009.2813,-301.66647,816.54474,952.917,133.79796,1061.5065,745.54614,-190.41003,1073.4006,728.9519,190.08894,1251.6295,857.56696,-196.98575,1219.1481,850.493,247.5509,1458.404,922.7129,-178.96996,1417.3644,889.1691,347.19656,1501.8943,916.2044,-188.46866,1460.0298,882.5947,350.00415,1442.6909,1006.0937,-351.828,1413.3629,965.83685,254.88359\r\nframe__YArvGEk8c6c__0012408.jpg,pushups_up,463.69113,409.66772,-494.75693,464.5404,365.98294,-532.73724,472.7627,358.8996,-532.47986,480.74225,351.5613,-532.3414,450.0487,377.22916,-473.21313,446.65826,378.93317,-473.32764,443.61368,381.02084,-473.8241,523.80743,325.71198,-545.0775,470.75357,362.93082,-276.4337,509.63367,408.94617,-486.3839,491.3248,425.66605,-407.64044,705.1536,385.3765,-586.7766,617.7123,427.06494,-40.02365,718.1946,668.83,-604.15564,621.35004,635.06,3.0209937,683.01996,945.29034,-630.08844,542.7919,837.01056,-143.23232,679.5502,1008.65155,-751.3768,503.2925,870.9974,-187.303,641.49365,1000.03174,-723.49567,499.0429,869.5217,-281.2757,648.4518,977.8699,-630.0195,528.44464,856.5538,-190.33282,1174.2188,495.52545,-193.53914,1115.1617,531.3881,194.04431,1468.1024,633.5024,25.509626,1401.6676,621.6022,362.9256,1785.7301,705.6629,299.85406,1678.0675,679.99133,597.0003,1855.2966,687.6591,311.4828,1741.4342,665.8707,615.27344,1782.612,840.2626,110.83342,1672.9604,811.93085,508.1643\r\nScreenshot_2021-02-11_at_11.45.28.png,pushups_up,1202.5593,302.99475,-1957.9592,1228.9697,248.65218,-1974.9388,1247.1746,245.65941,-1975.0535,1265.8926,242.52136,-1974.9181,1172.431,247.05986,-1969.0854,1153.0348,242.33371,-1969.1886,1133.763,238.1606,-1969.436,1294.6235,207.6006,-1708.2413,1102.4966,201.1013,-1687.2181,1232.8783,309.3855,-1828.3839,1173.1174,306.09164,-1822.3121,1418.2437,264.14117,-1305.8018,993.13715,264.73624,-1315.1,1455.5406,541.27045,-1197.6357,970.4226,539.1043,-1197.0957,1483.7684,821.1703,-1241.5662,964.2693,817.6002,-1249.2411,1518.1265,862.1169,-1311.365,933.13824,858.73676,-1329.0537,1483.3337,873.0802,-1369.7545,976.7858,863.55194,-1353.4495,1454.135,857.74506,-1268.0886,1005.63824,844.1612,-1262.3599,1290.3965,351.55823,2.1551464,1107.068,352.97214,-2.8781195,1297.7307,471.27682,968.6026,1106.094,458.40643,922.47876,1290.313,479.09183,1948.2576,1101.6791,423.5471,1947.7363,1279.8456,453.5189,2053.961,1109.1582,394.2061,2059.6025,1296.3193,583.18677,1903.4005,1095.9498,504.63403,1948.0829\nframe__1Benc0pfoFE__0003791.jpg,pushups_up,394.53076,382.82498,-661.5845,407.97443,351.9097,-692.06683,415.3274,348.46417,-692.0247,422.45093,344.62973,-691.8842,398.07376,358.7116,-624.90356,397.70816,360.73364,-625.0644,397.4683,363.0562,-625.34033,463.10693,341.03702,-702.17554,428.74637,364.30344,-394.91513,427.0209,397.01196,-657.8139,415.41614,407.44095,-568.51184,609.5348,455.27457,-767.2396,545.5718,465.35764,-122.33501,676.92676,716.25946,-770.3727,601.89734,681.1621,-90.883156,686.06323,960.821,-766.1966,616.9202,903.05585,-158.31973,667.0732,991.62604,-897.88354,587.6555,916.401,-177.96577,642.4139,979.22626,-854.2243,586.90576,927.4524,-273.10986,649.4428,969.9534,-759.3819,604.59985,924.33215,-203.5252,939.68787,604.3032,-220.18352,898.9751,609.84,220.42969,1189.9735,699.5374,153.23048,1106.8622,730.93274,511.5683,1433.178,779.2567,545.89996,1337.0391,792.7088,924.94916,1482.4519,764.6675,575.9303,1388.6669,779.4981,961.42584,1441.5875,876.9672,367.73016,1340.1208,891.19006,822.83844\r\nframe__NTng60w9N7w__0012083.jpg,pushups_up,596.085,692.507,78.76812,578.0991,681.4034,34.012558,577.5277,678.9524,34.001705,576.9153,676.17017,33.824917,578.18964,678.932,90.18445,577.9164,674.9476,90.08744,577.90936,670.9682,90.10256,579.3284,652.6835,-83.28227,580.57245,647.1381,175.22871,610.0164,684.4395,46.848522,610.3103,681.55756,121.86254,649.88184,641.6695,-211.78645,694.0882,618.4922,365.87283,663.1676,772.4292,-275.80173,730.6119,741.488,436.27203,671.13635,908.88617,-205.7367,734.806,841.22076,291.4121,638.211,922.81964,-251.67426,705.15015,835.322,317.91074,637.5031,911.76086,-186.27994,694.2211,849.05707,256.52643,649.61255,905.5262,-178.61423,702.7631,858.03314,263.37424,915.7352,673.5617,-175.02818,928.98627,655.4141,174.7448,1095.5066,765.31384,-102.30747,1095.2795,743.9525,235.53362,1282.7239,838.32025,-9.043734,1273.2749,792.25494,353.91675,1320.5186,831.86664,-5.2164865,1311.0103,786.4939,363.08582,1274.911,908.5309,-110.72957,1276.887,859.14764,290.02344\r\nframe__zSJYAyoojdw__0003259.jpg,pushups_up,2799.0012,593.3338,-854.9823,2765.1746,540.5486,-800.9075,2764.153,539.75854,-800.59625,2763.9785,539.4516,-800.3142,2743.161,549.09467,-908.2789,2725.422,551.5186,-908.47546,2707.4302,554.0047,-907.919,2696.6304,581.62683,-477.39114,2616.938,591.8294,-931.53906,2766.074,667.09937,-716.32605,2738.4583,672.60724,-853.06274,2544.6714,879.0962,-110.53226,2427.7761,961.2733,-1005.604,2477.0308,1301.6871,112.06806,2286.6143,1423.5782,-957.7348,2515.876,1749.6912,-31.916698,2309.0012,1918.1289,-982.4673,2570.3066,1804.5521,-140.99326,2301.827,2008.2677,-1205.1372,2568.082,1816.3612,-273.42026,2366.284,1998.127,-1219.5876,2522.846,1819.4019,-104.819145,2355.35,1970.191,-1008.3112,1909.382,1480.214,305.06192,1872.866,1489.9541,-302.7105,1440.4336,1557.8806,918.1458,1380.1051,1613.0533,361.06808,935.1611,1562.4667,1622.2363,869.4833,1676.1324,1200.296,836.9665,1528.3722,1696.8718,772.1955,1661.8658,1280.8724,866.1388,1657.44,1598.0542,854.64856,1825.6395,1030.315\r\nScreenshot_2021-02-11_at_12.26.08.png,pushups_up,1224.4525,537.27576,-1690.9592,1246.2999,484.8362,-1686.4965,1262.0587,482.24667,-1686.6704,1278.3433,479.4827,-1686.5128,1195.5327,483.63904,-1684.1177,1178.806,480.0731,-1684.1206,1161.9407,476.90958,-1684.0667,1300.2921,456.14774,-1428.0834,1132.7963,451.53424,-1420.1193,1250.3856,553.51794,-1575.2957,1196.8594,551.27576,-1571.07,1436.5829,565.1402,-1150.2312,994.5177,571.9997,-1146.2114,1531.482,864.2481,-1186.5308,907.4463,888.9987,-1261.895,1583.8972,1163.3673,-1330.5674,863.7563,1174.4459,-1393.442,1626.7446,1212.3547,-1467.6068,825.38983,1220.1534,-1519.0878,1566.2291,1213.6279,-1500.207,877.7405,1217.8678,-1557.0598,1537.3973,1200.5505,-1357.4803,907.56525,1206.099,-1421.4746,1301.8811,808.7027,5.3070016,1111.2976,824.31195,-6.3702836,1283.7783,956.52924,797.27185,1132.5648,997.32135,717.2857,1273.3953,988.2623,1678.5088,1158.4664,1025.4858,1613.1387,1260.6184,971.2648,1769.8975,1165.3143,1004.3994,1702.0045,1287.0226,1085.6273,1575.4929,1178.1832,1122.8359,1486.3556\nframe__RTF4ADblouI__0005003.jpg,pushups_up,2767.95,1027.498,-2147.7244,2840.869,1005.2299,-2143.7007,2859.6794,1005.9709,-2144.3438,2878.6238,1008.76276,-2145.2397,2788.5762,969.7292,-2222.2034,2773.4065,947.6992,-2223.4229,2757.6072,925.78687,-2224.1987,2902.4863,933.8235,-1885.1554,2754.4065,814.6876,-2234.2915,2748.0913,999.9952,-2011.7157,2704.2378,966.9477,-2111.5962,2990.0203,769.17444,-1405.4453,2314.2942,634.7781,-2068.4565,3084.133,1108.5499,-968.04395,1771.1698,1110.7361,-2093.325,3093.906,1486.4291,-1137.5145,1318.823,1636.9694,-2101.3867,3228.0635,1570.9705,-1263.3472,1182.5403,1722.3641,-2382.2803,3154.5933,1605.159,-1410.2437,1294.3821,1786.3273,-2398.5808,3056.9268,1575.9993,-1195.909,1354.715,1749.7793,-2136.282,2357.718,815.49365,250.75253,2057.5059,738.2915,-251.692,2089.7715,873.39374,1484.0288,1841.4937,884.96185,1125.9861,1900.2635,872.05133,2976.099,1658.5688,938.30896,2572.0608,1868.475,841.7371,3135.0874,1631.1982,897.84,2704.018,1876.2258,1021.7858,2973.6443,1623.145,1165.031,2494.7485\r\nframe__8bD7D4JsmCo__0012451.jpg,pushups_up,1073.825,552.1247,172.1694,1095.1982,535.23206,188.25418,1096.3024,531.7971,188.32846,1097.6201,528.5566,188.16165,1092.5668,535.4716,128.21931,1092.3761,531.0373,128.14142,1092.1398,526.7229,127.90528,1092.3613,496.61185,259.44922,1084.9097,494.39572,0.9050046,1054.8096,538.99805,208.45412,1052.8002,537.7368,132.29886,949.52277,459.44464,384.41467,1002.51276,488.96487,-145.53455,885.7848,614.61127,479.11035,964.98834,681.8249,-214.56232,910.1197,718.51666,421.47995,1001.6017,830.6649,-177.82243,932.1021,727.27747,442.74872,1026.9402,857.24695,-226.05913,945.5258,737.247,386.04465,1035.544,845.6464,-187.61815,937.1448,737.29205,398.1454,1021.3099,836.2674,-161.11331,671.2452,536.95,156.32793,683.7331,557.0241,-155.95699,403.9798,650.6012,116.82747,421.75806,706.4804,-147.98485,164.9223,728.7627,180.83122,154.4403,791.9671,-151.86041,118.44017,725.09607,183.34735,97.82976,783.2415,-163.37047,164.19238,809.1421,82.86884,167.82681,899.44543,-298.5329\r\nframe__6xKrGNq6Hd8__0010405.jpg,squats_up,958.3683,201.09503,-614.75323,969.0335,184.90814,-577.2034,976.44415,185.159,-577.37885,983.9845,185.19836,-577.4267,948.90344,184.97032,-573.32056,941.5387,184.83595,-573.13196,934.07587,184.82497,-573.25275,993.4466,200.22873,-375.50714,925.93976,198.85812,-350.47943,973.221,223.26239,-542.3465,942.8081,222.99141,-534.0177,1051.9305,322.40982,-232.80324,877.064,328.69858,-256.52155,1161.9435,413.2284,-203.29097,780.0929,416.90393,-242.28601,1092.524,500.29208,-359.35776,862.23883,521.33234,-399.85324,1077.133,523.72015,-430.44052,885.10254,543.39374,-476.31522,1059.601,514.4496,-447.97232,893.9229,522.48566,-489.36246,1063.4651,509.3721,-369.979,885.6437,516.7245,-410.10287,1027.2474,598.40936,-1.3140808,924.819,603.7973,2.0341852,1050.9004,805.50397,37.436455,906.7091,810.9186,70.96009,1082.221,971.8831,380.29968,888.01624,969.1528,447.09964,1086.3636,989.107,403.07657,888.7488,987.7139,471.57272,1060.8168,1044.1372,160.03275,883.14905,1038.6113,240.64053\r\nScreenshot_2021-02-11 at 15.22.54.png,squats_up,154.01031,146.82536,-47.71822,159.1379,141.08539,-29.77001,161.96527,141.48412,-29.720182,164.8848,141.84653,-29.725393,150.33951,140.48044,-32.530792,147.40869,140.23146,-32.574444,144.45862,140.07544,-32.682537,168.66629,148.24966,64.59873,139.71658,145.7013,51.979115,158.67741,157.40126,-13.324592,148.07228,156.31204,-17.096659,188.97295,195.14587,56.73351,114.31599,188.9692,26.356028,208.5767,186.88959,-141.92413,112.7084,186.85352,-146.53069,150.8713,179.30542,-313.08887,176.78336,179.98753,-256.00565,136.19197,182.16379,-355.52014,193.54794,183.35269,-290.84186,132.44458,180.76439,-342.40625,195.68027,180.56189,-285.61343,138.33432,181.90022,-315.2788,188.87317,181.60434,-256.48978,175.8793,324.70697,4.774404,124.72955,323.96182,-4.9129987,188.37868,432.13873,-16.98369,113.51266,431.2215,-45.129677,204.02664,532.4027,56.472775,109.76952,534.86365,40.21579,200.85544,546.076,56.33606,114.99171,548.31946,41.207565,213.66103,561.2346,-63.520847,94.381165,568.48944,-77.74985\nframe__p2Dg4UYYOSE__0006182.jpg,squats_up,976.67224,232.66812,-820.98035,985.7063,214.93864,-785.5197,993.01746,214.30344,-785.3998,1000.5139,213.5403,-785.2591,963.3767,216.53249,-789.76044,955.53973,216.88654,-789.5902,947.6958,217.37349,-789.4864,1010.2104,223.58377,-551.9154,938.18713,228.18074,-557.4978,991.6712,251.7534,-732.547,963.96643,253.46512,-734.6847,1063.8011,340.72726,-338.48666,892.15656,333.2878,-365.13474,1079.1089,471.25656,-236.91113,873.60345,461.89972,-221.52954,1088.5186,594.1404,-421.17075,861.12897,586.5355,-341.32117,1097.9634,624.58856,-465.67764,854.4152,617.8584,-360.17276,1095.3635,629.6715,-538.242,854.32135,624.8914,-442.33627,1086.0719,619.42365,-455.1131,867.09906,614.19025,-375.32346,1027.4324,562.68823,15.047344,926.588,559.93384,-15.045651,1014.03296,767.4731,16.55508,940.5062,760.3615,6.4921083,998.52057,912.9246,386.9992,942.5806,919.6738,337.61896,991.82056,928.1459,408.1064,945.54816,941.41473,356.25024,994.4512,982.37164,162.70053,943.21277,983.0106,92.830185\r\nframe__c-5WsFKlKDk__0002122.jpg,squats_up,1100.9136,306.97632,-403.52115,1104.9884,297.66653,-350.4086,1110.0822,298.16907,-350.20914,1115.4624,298.64383,-350.29068,1087.971,298.64362,-382.19696,1081.0797,299.46118,-382.02094,1074.3556,300.65836,-382.1695,1119.4028,316.3484,-116.40334,1064.4658,318.90677,-274.01065,1112.9153,328.7979,-320.6337,1090.077,329.94366,-365.20206,1149.0192,401.55707,42.89992,1039.3309,398.82172,-354.89328,1190.5626,289.8499,118.99307,1058.0447,298.9353,-582.7808,1218.4617,173.74016,-6.2427316,1069.5219,151.75604,-732.0106,1228.4232,151.24022,-50.163742,1069.0729,117.49414,-825.1439,1217.3926,143.6966,-64.29182,1069.7725,114.29693,-812.05585,1212.8257,150.33336,-26.617691,1072.0319,125.48515,-737.4684,1115.5327,633.82043,148.6447,1051.2671,629.0503,-148.2424,1097.5936,814.286,249.74353,1038.1212,818.4185,-186.54091,1095.3431,966.6977,496.16376,1015.051,982.985,-5.6892815,1083.3646,998.39813,510.09137,998.45996,1008.1672,1.0918119,1163.5918,1001.17694,351.66653,1056.0974,1041.6881,-217.10349\r\nScreenshot_2021-02-11 at 14.45.40.png,squats_up,475.67188,89.63707,-287.58224,481.60745,81.06653,-262.96625,486.33105,81.373634,-263.00098,491.11835,81.58516,-263.0508,466.94626,81.04758,-267.84232,461.62833,81.22392,-267.863,456.3154,81.46803,-267.889,495.3977,92.18634,-123.36563,447.7065,92.20287,-147.47357,483.8771,106.0487,-237.33351,465.13965,105.91492,-244.26851,532.14764,170.7454,-48.360004,408.82153,171.47012,-61.15244,588.247,236.17636,-166.24445,373.72137,252.52972,-157.28032,575.6941,160.49147,-405.69003,376.15976,189.81834,-390.88245,577.1798,138.52403,-459.5827,380.10657,174.40173,-435.81378,568.8951,131.61096,-450.89084,378.30466,158.81792,-443.3302,563.8518,140.40434,-410.86206,382.28436,165.91614,-397.90125,509.83914,338.4631,3.8270388,435.27112,339.10083,-3.6954877,540.3315,473.9619,-49.63011,418.77963,473.18542,-33.304535,542.04395,604.39124,101.86375,412.05856,596.71606,101.9476,532.34924,623.71515,108.227295,419.91428,616.6112,106.67337,565.99084,645.12524,-34.387955,384.99573,634.90173,-38.656048\nframe__lFy8a46jkcA__0001650.jpg,squats_up,908.973,328.8612,-436.25986,919.11835,314.4967,-405.69733,925.0238,314.80923,-405.47375,930.99445,315.04883,-405.427,901.44745,313.4404,-411.1906,895.2653,312.6353,-411.05957,889.058,311.999,-411.10852,937.3301,320.9823,-204.6343,879.37726,316.2885,-225.21123,917.75604,343.98813,-360.27496,896.8185,342.17587,-366.16916,968.9766,387.4766,-117.97761,839.742,391.27725,-138.86542,984.6018,466.86322,-422.17413,850.9712,483.30746,-406.71176,934.2115,386.67242,-780.63837,887.72394,405.20065,-712.5238,925.34155,367.00784,-860.3385,896.30096,386.15436,-785.41315,923.7834,357.3202,-838.7176,892.3316,377.1098,-769.24286,921.264,365.84204,-780.4662,895.11426,384.48535,-711.89154,955.47174,595.36505,8.65459,873.438,599.5942,-8.633232,991.6796,734.26764,56.417736,836.9151,733.968,83.01022,1022.74316,846.5162,411.69797,802.49176,845.957,457.7455,1017.1757,863.8935,436.7366,805.8366,861.5855,482.90738,1050.5836,895.6663,240.27757,786.2685,902.9677,286.82706\r\nScreenshot_2021-02-11 at 15.27.49.png,squats_up,668.76245,131.77808,-104.645836,675.43256,120.356544,-86.148834,680.1871,120.15545,-86.10829,685.01013,119.883514,-86.191696,661.73395,121.08045,-87.19057,656.93335,121.26111,-87.166405,652.14734,121.49079,-87.28531,691.4559,126.30826,33.873917,646.9842,128.22084,30.216087,678.4015,144.32437,-60.39314,660.7388,145.13747,-61.46973,722.3959,196.21788,101.21868,620.84106,193.63701,104.00235,762.1603,266.7838,-34.829414,600.14264,265.03415,-19.349579,776.31836,202.001,-314.3509,580.56274,205.37779,-303.61624,784.1764,187.2385,-365.58917,574.02026,193.16327,-354.46542,780.5435,175.01701,-368.07663,576.42163,177.61238,-361.4506,773.69006,180.70279,-322.41058,582.85706,183.32549,-312.896,705.67554,357.1845,-0.55120426,642.1796,357.11823,0.8339456,729.1729,488.59332,-49.808273,631.9158,492.4835,-48.733253,739.8892,625.4208,32.648735,619.53046,626.4078,17.435894,734.1465,643.83606,32.00084,622.05194,644.7655,14.01204,754.369,662.5656,-107.305725,612.338,663.005,-126.92399\nScreenshot_2021-02-11 at 14.42.09.png,squats_up,412.1951,99.79649,-246.96162,420.97256,88.54078,-225.17587,425.67633,88.80622,-225.04106,430.47217,89.018486,-225.05362,407.48334,87.79067,-223.73235,402.97897,87.29808,-223.65239,398.43317,86.91302,-223.64813,437.89972,95.71098,-90.114204,394.5856,92.42345,-81.36672,421.04236,112.90912,-198.02748,404.18427,111.71266,-195.57487,469.90268,164.49258,-30.700806,361.86386,164.40984,0.049124815,471.68808,236.33224,-204.84677,356.3501,247.16576,-141.38258,463.79855,172.30688,-474.65768,356.27417,171.87457,-397.55664,466.49734,152.97348,-535.3837,358.01703,150.06792,-448.76584,465.76492,145.90314,-525.63684,352.71365,140.03212,-447.52182,460.2848,150.80647,-478.02936,357.16846,146.58249,-402.58054,452.02002,331.78168,-2.6973453,387.6363,331.21957,2.6946473,461.5212,466.9572,-9.819952,391.2488,460.95825,9.811691,465.63312,568.3799,226.58575,389.55795,562.135,238.72722,459.89188,576.62726,243.18672,391.80426,570.52057,253.67798,472.06967,621.20483,94.78552,394.02823,616.91406,104.075836\nframe__YArvGEk8c6c__0007130.jpg,squats_up,943.8887,216.08116,-283.10828,952.70465,201.43019,-247.31297,958.689,202.0097,-247.23541,964.8894,202.55713,-247.35983,934.0227,199.90518,-258.94128,927.3404,199.0142,-258.83887,920.70184,198.30783,-259.1886,968.56647,210.89192,-61.966503,908.3194,206.00888,-123.826515,951.4176,236.54881,-214.18208,929.71625,234.48773,-230.89128,1004.81586,307.04352,-64.40076,855.02185,284.9793,-274.61868,1075.8699,278.1012,-460.03995,899.2922,233.05437,-743.7364,1139.169,178.70497,-834.60046,966.7304,132.92606,-996.73517,1166.185,150.56949,-935.4648,984.34845,114.48503,-1106.5885,1155.8235,144.50487,-943.7442,982.7569,106.613914,-1101.7782,1140.8813,157.4955,-859.3609,979.86774,119.73748,-1008.82025,977.25037,573.8312,45.086987,870.3259,577.8307,-44.60707,1015.962,764.66943,-12.385511,838.44824,777.4637,-149.7595,1014.2793,969.39606,129.51447,777.96814,973.4986,1.1627048,997.152,1003.04553,130.22646,770.3041,1001.6462,0.6883916,1043.055,1016.0904,-74.43166,780.25635,1027.7671,-223.55925\r\nScreenshot_2021-02-11_at_16.02.03.png,squats_up,644.85974,65.018845,-277.26364,652.58545,58.10047,-254.9699,656.9237,58.45941,-254.99559,661.42706,58.71381,-255.02719,638.827,58.06779,-255.08386,634.45166,58.17223,-254.97543,630.09796,58.35131,-254.94293,668.1771,68.47909,-125.69992,624.8166,67.564415,-120.07752,653.3818,80.115105,-228.59866,636.87646,79.70609,-227.28009,703.1006,149.57707,-34.017365,588.75616,146.7447,-29.306746,722.1899,225.107,31.82031,567.9026,222.82858,33.28358,725.59094,299.2116,-126.65005,563.5314,305.602,-109.27363,730.2247,324.77567,-174.76709,556.95856,333.44763,-148.24135,720.5816,323.66583,-217.88098,569.136,334.43744,-196.83652,715.83405,314.52267,-147.47353,576.22595,323.80023,-131.14282,679.4219,309.74707,-1.532888,609.982,311.49472,1.602496,695.51263,446.10068,-39.86439,600.22015,453.31522,-31.748407,706.01184,575.9796,107.64865,593.044,584.0729,114.54083,701.55536,592.9595,112.67357,598.8956,601.72833,119.86634,714.1403,618.1628,-38.07953,577.8936,626.1787,-34.905273\nframe__h85Dzknz8G4__0000914.jpg,squats_up,917.0605,158.87154,-438.3595,922.11505,144.39804,-397.07922,927.7766,144.17244,-397.0066,933.69855,143.79787,-396.97095,903.0669,144.54967,-418.34525,895.8937,144.24931,-418.0831,888.71204,144.08226,-418.18784,933.1391,151.92032,-150.82066,872.6739,152.64536,-260.43564,925.298,176.47946,-345.43744,901.2982,176.61255,-377.0737,955.8141,261.21072,86.33131,821.5971,244.6043,-250.48279,1018.85126,358.9498,204.46799,810.0499,361.4903,-380.06464,1086.8795,449.01184,-23.099422,818.7481,474.88104,-654.12683,1109.886,475.03726,-57.619167,811.8378,510.24924,-747.8821,1105.4352,478.38055,-130.8655,828.03784,506.64493,-772.1819,1093.5175,471.4439,-59.449043,831.5924,494.7793,-670.7496,910.83154,487.97372,127.708755,829.3629,485.53564,-126.991714,933.23065,663.8183,190.91353,822.41144,680.6113,-175.8981,929.99713,825.4462,476.95868,772.7609,839.906,94.74533,915.25354,855.6763,490.87842,756.0137,859.285,107.257774,982.16766,869.753,295.7305,804.0799,906.6664,-124.876\r\nframe__4aUK4cm2hiQ__0000500.jpg,squats_up,881.1698,137.86966,-339.99982,887.90826,121.190216,-296.72037,893.8834,120.37056,-295.99557,900.064,119.51475,-296.6247,868.7272,123.55396,-303.13403,862.2496,124.03107,-303.49585,855.7034,124.739876,-303.74475,909.6523,126.21089,-65.777725,846.62604,133.5469,-96.1064,893.95734,155.17305,-258.77545,871.4186,157.84029,-264.9133,956.94794,218.32025,18.511322,803.2821,224.89015,67.68931,1054.1329,154.87502,-34.92522,716.96643,171.4583,146.13177,937.8108,144.85837,99.85217,818.2702,137.19383,439.94434,914.2948,137.84776,81.767265,840.6693,125.84245,444.28265,908.95184,155.9343,131.95851,846.315,139.10455,462.33347,916.304,163.59555,116.151764,838.5768,148.1032,446.557,920.2534,468.1895,1.4218619,822.4259,465.40677,-1.4877988,945.16077,651.58264,65.09796,808.0569,648.8344,80.186615,949.0501,812.6416,385.40387,792.18036,822.4044,361.92194,934.25366,839.121,409.61548,794.45435,844.6719,380.03973,993.6836,857.59955,199.15205,779.34766,883.7173,149.22171\r\nScreenshot_2021-02-11_at_15.52.50.png,squats_up,1334.5039,177.42934,-779.6972,1347.4307,160.57774,-753.6452,1355.9331,160.46492,-753.50085,1364.81,160.11897,-753.3712,1320.5024,162.93285,-759.1796,1311.4908,163.96318,-759.0485,1302.5627,165.17088,-758.9013,1378.492,178.53268,-514.2914,1291.1064,183.81926,-535.203,1352.3091,206.9327,-684.74994,1320.2942,208.86491,-690.7033,1466.1562,340.51974,-296.13043,1215.0084,342.1685,-363.1287,1524.1853,513.40936,-169.67078,1176.8346,509.87637,-254.55373,1542.7053,686.5717,-403.1344,1170.0375,693.5018,-444.1926,1559.455,740.0678,-473.85706,1155.8523,748.5413,-487.4256,1536.7242,745.66284,-558.90295,1175.2335,755.9739,-594.86993,1521.0408,728.04694,-440.4542,1194.512,736.3381,-486.89426,1420.7758,678.5365,34.14522,1271.5437,689.5806,-34.37456,1472.3529,957.7354,23.716473,1250.7238,977.0533,-106.0401,1495.0454,1231.9442,235.11438,1202.4418,1235.8713,138.17387,1478.6493,1277.7384,239.90474,1212.9867,1272.3264,145.24588,1558.4194,1306.0613,-19.88067,1147.313,1325.3053,-131.90063\nframe__YArvGEk8c6c__0008619.jpg,squats_up,1299.3861,154.1893,-462.9437,1311.1273,138.15817,-428.05417,1318.3596,138.28279,-427.85718,1325.7437,138.37,-427.83966,1290.5435,138.07867,-426.92334,1283.4148,137.79536,-426.94727,1276.2651,137.73322,-427.05685,1336.9382,151.0441,-218.9914,1269.2004,149.41711,-208.19028,1313.8339,175.2133,-386.20825,1287.2661,174.70377,-382.70532,1384.0912,248.22987,-137.30994,1221.4099,250.36392,-129.37898,1499.0889,248.51334,-402.49878,1114.1747,240.91408,-417.95767,1408.6593,170.85294,-619.1312,1216.3121,168.52852,-642.59143,1393.8141,144.61897,-680.3647,1238.8767,142.6628,-708.7576,1380.6298,149.54385,-646.8384,1247.3555,150.0953,-673.58777,1384.5017,165.15489,-618.2996,1241.9276,165.16263,-640.9,1349.1171,526.90564,-28.305313,1245.5714,531.07086,28.145195,1388.0773,733.50555,-64.895134,1203.6349,730.0799,13.282141,1422.2109,924.2631,134.23366,1182.2739,916.91895,240.81436,1420.0682,950.9301,141.3087,1197.0818,944.3095,249.20145,1429.4108,983.2552,-83.89596,1131.8597,980.06354,36.54965\r\nScreenshot_2021-02-11 at 15.57.16.png,squats_up,194.33533,95.115,-139.46698,201.12326,85.76089,-131.57877,205.13904,86.11518,-131.49895,209.26665,86.420586,-131.5089,190.14897,84.85153,-134.15143,185.99956,84.28515,-134.11594,181.85037,83.81357,-134.14693,214.50583,92.78072,-58.37423,176.52774,89.03116,-68.25149,200.9471,106.99976,-110.91913,186.26604,105.59073,-113.483765,235.87141,144.3932,-39.35693,146.3779,137.16196,-50.931866,245.90184,174.80167,-152.5639,129.78447,171.72368,-201.88972,263.25632,141.45496,-293.6414,132.67128,138.55609,-359.01227,271.6227,133.42842,-323.16028,129.86621,130.5243,-384.43338,269.56348,130.68834,-325.45224,132.17662,126.64709,-385.99524,263.41888,134.65831,-298.88803,136.66608,131.35226,-362.85132,208.26462,296.7835,6.224432,155.46295,291.88342,-6.1727695,211.7787,400.45102,15.512404,139.45702,388.70993,-9.832383,221.59709,481.83588,90.87519,123.40402,470.1637,85.19868,215.18951,490.95163,92.940056,126.66017,479.24945,88.50853,239.03236,520.9156,-0.52730477,107.25926,510.71802,0.7036074\nScreenshot_2021-02-11 at 14.57.04.png,squats_up,461.05005,132.37152,-471.5653,466.9417,119.956924,-456.4943,471.0537,119.63671,-456.4828,475.3261,119.21577,-456.42984,453.44925,120.208626,-460.02686,448.7154,119.89426,-459.9219,444.00815,119.64156,-459.82816,478.58633,120.95674,-312.04004,435.5805,120.81363,-321.32977,467.09103,141.89706,-414.24496,451.75113,141.87169,-417.3137,507.5,183.40637,-195.65321,399.88342,183.17023,-190.39594,515.8607,269.24304,-167.8175,390.54974,266.3937,-142.42448,522.40155,346.84738,-294.00552,377.77823,340.62424,-253.03645,530.0025,368.46066,-322.11334,369.75153,361.85364,-279.0448,523.4834,370.18842,-366.18652,372.95685,364.77798,-328.49948,517.3912,362.97324,-313.2271,381.90356,357.79895,-274.80383,487.00174,336.69824,0.058933806,419.66898,338.67245,-0.13861991,514.91956,467.15598,-15.696458,401.32724,466.72394,-14.0071945,536.2796,585.42865,120.609116,378.32956,580.9338,127.10325,533.6003,601.2797,125.26755,380.65717,597.6037,132.30963,544.3729,625.4732,-43.921513,365.09015,619.6504,-34.98259\nframe__Spc5yl47h1Y__0002785.jpg,squats_up,1803.5739,437.0606,-385.75287,1816.5436,404.2695,-478.0082,1821.7448,402.10953,-478.1136,1827.3119,399.64423,-478.07306,1817.7716,405.73468,-355.32083,1822.5074,404.90576,-355.28992,1827.3616,404.34454,-354.88202,1870.6123,405.84433,-678.5713,1871.6049,410.7104,-86.48349,1830.7039,466.87662,-448.03137,1829.8488,469.0339,-277.3329,1973.1921,571.8318,-987.4355,1956.7225,611.6536,370.06583,1971.2609,809.20416,-1212.302,1991.9197,881.8707,507.4704,1804.2917,975.0792,-1382.403,1891.3264,1054.5065,300.17725,1771.3384,1020.1188,-1560.7706,1880.0638,1097.8774,375.47214,1753.1696,1007.3467,-1530.9299,1844.4198,1095.3914,225.92123,1772.6659,994.97205,-1377.4346,1849.6758,1080.4551,234.01395,2063.4182,1056.1401,-412.6218,2049.277,1058.094,413.28824,1980.5669,1436.6636,-377.96695,2066.5178,1441.3254,585.97174,2026.0044,1806.9467,-217.20317,2141.6062,1784.8063,875.5196,2069.1543,1876.0422,-232.53928,2182.7522,1857.1118,889.8106,1846.5903,1885.2013,-578.03784,1986.6078,1849.6764,706.57733\r\nScreenshot_2021-02-11 at 14.48.06.png,squats_up,423.79584,80.28895,-485.53784,429.5485,68.106964,-477.0964,433.687,68.04223,-477.01385,437.94476,67.89111,-476.98004,416.14642,67.63263,-482.26746,411.3891,67.06735,-482.24484,406.67355,66.57605,-482.11334,440.56503,70.6598,-349.9517,397.2674,68.49342,-370.7657,429.49234,90.84012,-431.92426,413.7526,89.84795,-438.1965,468.84198,133.58919,-201.83585,357.55466,127.52423,-237.17355,482.4037,213.70074,-117.701294,344.46436,206.88792,-130.44054,489.794,289.8397,-196.88766,333.85693,281.83914,-190.2398,495.57834,309.85938,-214.59758,326.31088,302.1192,-194.34805,492.33383,314.01514,-257.4609,328.2597,305.99338,-246.10239,485.62875,307.6152,-215.92319,336.92285,299.63434,-209.1726,441.3833,275.45386,14.821119,377.66013,275.80533,-14.975363,450.70172,397.48105,15.623305,363.13412,399.14346,-35.892925,456.23767,504.94974,156.40837,355.65723,506.45413,102.38683,450.09085,520.69727,161.81845,361.8755,522.95715,107.23013,473.91455,540.7015,29.322485,332.45502,542.8986,-34.162727\nframe__9d0VKo-LnL8__0002267.jpg,squats_up,960.2073,320.232,-530.0867,968.18915,308.48474,-495.7379,973.8824,309.87082,-495.819,979.5924,311.13654,-495.7513,950.18317,305.5469,-510.22098,942.989,304.34213,-510.11295,935.8413,303.30823,-510.2441,980.04126,321.1741,-289.6916,920.0706,312.02112,-356.29575,967.3374,340.71072,-450.3996,943.30426,336.55093,-469.9546,1027.9247,410.48895,-144.05539,862.46173,417.41495,-209.37315,1094.2402,486.0189,-9.988191,796.96747,504.7192,-181.30048,1056.572,542.8941,-142.78943,870.02466,568.0261,-341.87766,1043.0741,564.1083,-198.43085,891.07654,592.0055,-394.41757,1030.9688,555.59796,-215.66481,905.04645,576.2048,-417.55637,1032.6758,547.9108,-152.53148,898.5741,568.9991,-351.63165,1024.2268,626.3254,-10.613157,936.787,641.419,11.442811,1008.0707,797.9636,-167.5257,940.6743,809.5576,67.46973,1018.09937,935.654,148.06493,941.1315,927.00397,578.0582,1019.53296,953.55597,171.4703,950.94476,939.2661,619.40765,1012.62396,1000.2167,-28.911097,922.7568,996.3312,440.43002\r\nframe__Ns1leUPXc8Q__0003034.jpg,squats_up,642.39923,313.9721,-388.94107,647.64716,306.02042,-370.92682,650.8828,305.89737,-370.8708,654.2044,305.76868,-370.84094,637.9248,306.91068,-371.09177,634.60565,307.0801,-370.93082,631.3472,307.41763,-370.99567,658.8529,311.0541,-253.44862,627.766,312.85983,-258.72922,648.95056,322.46,-345.64883,636.70447,323.04224,-346.7723,679.55023,347.02176,-214.91133,610.5221,352.82788,-245.16748,697.5807,283.49252,-276.3893,595.4028,298.83618,-370.42905,670.9692,218.21397,-317.69205,603.6067,231.58414,-457.21072,664.64233,203.90477,-364.8636,607.5206,215.91812,-511.47266,656.9732,201.83751,-353.36563,611.3861,213.09464,-505.73444,658.8848,207.33328,-321.3693,612.43036,218.15024,-462.91986,675.3223,476.89346,12.592091,627.8782,477.24493,-12.435242,676.7228,583.0704,34.55344,612.4963,578.08514,-42.668728,678.0224,671.5389,169.78418,581.87396,669.15875,94.45471,672.72284,681.33875,176.21222,577.75854,677.3056,99.57856,684.0679,703.3426,47.1908,590.7776,705.6873,-40.40206\r\nScreenshot_2021-02-11 at 15.51.54.png,squats_up,218.40929,74.722694,-253.85568,226.13826,66.106834,-228.95052,230.45302,66.094505,-228.75525,234.92365,66.09593,-228.6891,214.49126,67.0412,-224.7892,210.65048,67.307045,-224.82005,206.76028,67.76634,-224.8966,244.75237,76.42981,-109.04176,206.40778,77.74875,-86.64702,229.6562,88.65063,-213.59937,214.0446,89.1102,-206.60368,280.11432,142.86945,-109.81025,185.34409,149.32324,-68.28436,336.66757,64.854164,-387.7933,133.2721,75.21483,-225.85825,262.61728,75.62033,-558.3228,200.23499,69.00695,-282.03058,244.80072,77.38569,-600.126,216.86115,63.529278,-307.574,242.18007,90.79429,-574.12195,216.9428,75.067184,-281.33337,248.38892,94.12316,-557.4922,213.3529,79.22073,-277.51837,265.84576,335.26974,-3.16608,205.26332,333.81088,3.2158313,267.80222,484.74435,-18.842424,199.01222,475.6114,24.502293,268.22925,623.38025,88.6677,201.43834,602.6227,197.44798,260.97272,642.7316,90.57285,215.03894,620.9061,205.58801,289.09512,665.90765,-60.04013,158.05974,647.30054,65.37231\nframe__8f_6sVIsh38__0004167.jpg,squats_up,936.7132,351.34213,-250.96606,945.6286,339.39154,-209.19261,951.129,339.225,-209.07588,956.79395,338.975,-208.99028,928.8275,340.47784,-204.22905,923.30945,340.78952,-204.10226,917.70325,341.22977,-204.16374,965.92596,349.62164,8.934924,911.948,351.85223,31.792574,948.51324,368.63025,-173.5727,927.8137,369.71896,-166.86662,1006.7373,440.8599,70.06251,876.7258,442.69644,112.25593,1058.3103,514.6144,-269.76617,825.1976,511.68198,-224.8666,975.5301,463.83667,-551.3309,907.9721,463.77103,-552.4653,954.761,449.48892,-618.3493,928.9672,449.74594,-633.2819,950.0893,443.83502,-576.8619,933.34845,446.1273,-592.03253,955.0274,450.6335,-539.52783,928.4274,453.7742,-544.0918,982.13965,662.15826,-5.1864843,895.88824,661.13934,5.5687084,1006.446,823.415,-4.3584895,867.9974,821.11554,-32.881165,1034.4138,967.71277,347.57126,841.76025,968.91315,300.83307,1030.9941,986.2497,367.27682,843.6697,987.32043,316.71265,1053.0532,1016.1888,92.12019,833.1592,1024.0881,43.310535\r\nScreenshot_2021-02-11 at 15.29.36.png,squats_up,401.8861,116.277756,-236.53545,407.33838,107.17775,-208.85854,411.9799,107.27316,-208.7619,416.7412,107.33063,-208.77939,393.19733,107.81679,-217.51314,387.93552,108.14849,-217.50975,382.6502,108.59754,-217.65292,420.97955,118.40105,-71.381325,373.6206,119.93528,-111.06579,410.28708,132.24138,-186.92845,391.8367,132.86847,-198.1484,449.06628,189.13576,-57.570583,338.0323,185.32649,-81.11941,487.3062,203.29395,-253.98796,274.12366,181.91537,-303.29,504.04877,160.59314,-475.12445,348.12482,160.20332,-507.51022,515.8978,150.92712,-520.9059,368.608,160.78233,-546.92737,507.67627,147.9746,-521.2912,374.5167,153.8634,-539.38116,500.49646,153.91725,-483.4158,367.8949,158.28552,-508.78973,429.554,382.74966,15.631592,358.25912,383.571,-15.789599,454.33734,515.8778,18.529314,338.34427,508.3609,-19.809385,468.9112,631.5042,160.13652,329.93185,624.6973,130.68643,458.01492,649.76825,165.70955,337.4056,640.394,136.1703,508.32986,673.55927,36.41391,307.8609,671.6745,3.7597427\nframe___0CAcnhL5Sw__0012549.jpg,squats_up,1093.5117,134.51302,-457.5437,1087.3619,115.665886,-422.05933,1090.74,115.30147,-421.9512,1094.528,114.82678,-421.86652,1073.251,116.70625,-466.06042,1065.3396,116.71835,-465.96774,1057.5027,116.89747,-466.16464,1078.668,124.19296,-220.74814,1030.2789,128.04443,-418.63345,1094.1757,155.40872,-380.9957,1073.1562,156.51819,-438.6312,1091.8837,259.8246,27.41631,956.216,251.22092,-449.41544,1113.8455,397.1623,194.49031,907.51587,408.56818,-463.32184,1184.3186,498.67902,15.746144,973.6181,532.952,-533.0544,1207.3099,529.5909,6.554579,981.08026,576.51044,-584.8383,1215.7404,529.90216,-76.98494,1011.042,564.70386,-600.92535,1197.7449,522.82355,-22.244717,1011.4317,549.44556,-533.23413,1048.8279,534.3933,154.49113,969.822,538.19995,-153.75674,1035.165,741.2271,345.8371,948.4739,765.3328,-92.349525,1012.4388,921.9539,587.31177,912.1253,964.02344,107.7634,991.8883,953.5135,599.0387,885.3313,990.68567,115.97997,1083.1168,983.2258,470.63205,981.09155,1045.1154,-73.105606\r\nScreenshot_2021-02-11 at 14.29.43.png,squats_up,468.8944,154.82074,-272.30774,475.28226,142.04016,-252.96286,479.86038,141.6173,-252.92526,484.52563,141.11914,-252.92126,461.5065,142.75397,-252.59204,456.70624,142.65341,-252.61534,451.91592,142.63203,-252.64252,490.6287,144.13953,-118.967804,446.61874,146.02425,-114.92797,477.9998,165.36818,-222.53587,461.1867,166.17015,-221.2827,525.4715,203.45494,-22.623049,416.6593,204.66168,-26.36424,579.3418,268.82785,-135.78915,374.4156,268.2154,-153.84393,595.33966,205.24423,-341.28268,358.3976,207.48624,-398.13657,605.38995,182.70515,-385.1532,348.15466,187.93033,-451.0902,599.69073,175.33722,-381.53745,353.10434,179.46979,-446.88257,593.23444,184.34358,-348.94714,360.76483,187.29474,-404.81982,509.3903,370.68347,-4.9156966,441.22247,373.13898,5.0451956,560.7713,475.1099,-156.06807,399.28308,490.163,-45.240074,587.0817,593.4256,2.062182,373.00604,599.9025,107.22657,582.0354,613.9983,8.958203,380.56934,619.2237,110.909836,613.2046,621.30536,-157.09528,338.93243,629.4301,-42.672333\nScreenshot_2021-02-11 at 15.43.12.png,squats_up,638.9924,91.367455,-366.51865,641.33014,81.149635,-347.7967,644.4559,81.96199,-347.75073,647.7663,82.66197,-347.66138,628.93304,78.430374,-363.82846,623.761,77.07568,-363.8397,618.5953,75.755745,-363.9649,640.527,87.021385,-198.64488,600.4774,78.31387,-273.83936,637.84686,105.385475,-306.48312,623.13824,101.61717,-328.21616,661.3984,166.3397,-91.18623,537.84216,149.39336,-177.49297,672.6045,267.3414,-19.350513,519.84406,247.25186,-148.94235,680.53174,355.16397,-103.26754,511.51913,343.75244,-233.9755,686.3344,377.59875,-120.40181,503.9729,371.5549,-257.44888,687.33044,382.34583,-162.8109,509.74493,374.97696,-302.01266,681.12506,374.94592,-122.236404,517.33923,364.9335,-251.76176,644.1057,343.3899,31.405937,564.9253,348.46185,-31.19825,670.3611,487.13077,34.045273,535.1734,502.69373,-73.286194,685.00323,630.05914,167.89525,511.0693,650.18945,28.808897,677.79584,650.5439,172.74084,512.8936,669.401,28.104338,708.94104,675.4938,32.458153,500.1973,697.8115,-142.83102\nframe__Spc5yl47h1Y__0004417.jpg,squats_up,1859.3289,501.86633,-188.22952,1869.3385,466.36865,-265.96475,1874.4218,463.00833,-266.1415,1879.9022,459.35934,-266.2171,1868.7646,468.38083,-151.20404,1871.8625,466.82397,-151.2586,1874.9714,465.51257,-150.89433,1919.87,450.9508,-431.5148,1913.6155,456.36734,117.41753,1886.6079,519.3366,-242.07281,1882.8933,521.87286,-83.85789,2045.1036,555.2233,-703.48254,1963.8674,620.5423,507.62714,2174.952,734.2622,-1057.9059,2028.0848,830.54596,702.46423,1999.5397,873.3484,-1156.7386,1941.7317,951.6424,400.42828,1962.2626,917.9551,-1247.5839,1928.3049,985.86633,410.91534,1940.4032,886.8766,-1246.69,1892.3704,974.52527,300.16638,1963.4374,875.61523,-1146.9175,1901.1338,961.5687,342.09116,2065.0806,1059.2456,-391.21774,2003.4801,1064.4073,392.05548,2062.636,1454.1241,-547.515,1993.6022,1410.622,634.5442,2115.0642,1835.5806,-670.04816,2037.7695,1740.1101,926.7252,2161.2253,1901.5239,-711.03986,2080.588,1813.1501,938.24915,1954.1638,1926.3298,-1088.1252,1862.0347,1806.8967,742.72906\r\nframe__--pHGLXZTBk__0005913.jpg,squats_up,1349.5565,203.91776,-91.43233,1344.7863,184.8973,-68.332985,1343.3972,183.0625,-68.31502,1342.2144,181.14603,-68.41031,1341.8684,186.50952,-128.08302,1337.5186,184.98308,-128.04626,1333.2316,183.54405,-128.06058,1315.8971,173.46516,45.41478,1305.794,176.82582,-223.58595,1333.4895,210.93042,-43.709976,1328.502,211.21237,-122.27159,1257.9807,246.59622,204.13074,1237.3484,231.71295,-339.7214,1233.5781,380.496,291.76782,1227.1245,354.35788,-405.62683,1235.7488,488.31454,226.84155,1247.4988,485.7636,-413.06738,1239.0767,514.63525,241.70615,1239.6929,520.66046,-462.7346,1244.5138,518.58685,189.85869,1260.7074,524.71893,-452.8124,1241.1265,509.88828,205.01483,1261.143,514.22766,-404.8884,1208.7809,470.9179,176.33926,1189.9116,474.909,-175.64151,1193.2974,678.75464,253.6102,1202.5442,688.2446,-148.99356,1192.2069,866.9799,394.0492,1187.6212,899.65393,-64.072266,1173.9694,894.2545,401.92395,1159.911,926.6252,-64.928154,1259.742,923.4202,320.24936,1266.735,970.0574,-199.40666\r\nScreenshot_2021-02-11 at 15.53.25.png,squats_up,169.69263,130.94608,-108.511536,173.52744,123.90562,-96.90688,176.76443,124.15276,-96.91725,180.11092,124.328224,-96.95052,164.29933,123.71435,-99.92633,160.54387,123.67312,-99.90645,156.79427,123.69561,-99.907845,182.09851,131.2145,-39.857418,150.38731,130.1781,-49.26976,174.75743,141.72424,-87.22363,161.5828,141.414,-89.94692,201.72981,183.89539,-37.818394,126.1607,186.13577,-31.014244,214.00609,242.88986,-33.35877,120.996925,248.3787,-30.388464,215.42503,297.27814,-71.01708,130.56155,306.16595,-64.92734,219.75569,313.96536,-83.18673,129.12474,325.31476,-80.03591,211.36482,314.6544,-97.43854,139.9311,323.69043,-92.80573,207.20949,308.83865,-76.53878,143.55145,317.0896,-70.74947,189.84604,307.16208,-13.434126,148.41432,309.7177,13.633958,194.52994,384.20773,-8.291798,152.54514,386.66672,25.645248,196.64105,458.64572,39.304226,162.50243,456.24756,104.40397,197.56819,468.3452,40.80372,169.95314,467.30234,107.733894,193.32382,489.32016,-11.123352,144.15656,484.65845,54.91746\nframe__cvhQkEjB--o__0002938.jpg,squats_up,814.1031,309.15073,-235.20667,823.6155,292.03378,-261.77182,827.9125,290.64728,-261.887,832.4208,289.10248,-261.98132,818.2536,294.7764,-211.8512,817.87634,295.3338,-211.77264,817.449,296.02615,-211.63165,854.92444,292.289,-294.01224,835.7999,299.3731,-51.10431,830.4105,321.75845,-244.13576,821.74524,325.02817,-173.52866,905.3491,374.75156,-383.93723,843.2918,389.66388,150.11858,871.8828,487.98227,-446.90732,814.9341,491.78604,235.15231,781.146,544.85254,-519.6725,751.39777,540.63983,104.574165,764.59454,565.2375,-585.39465,737.4257,556.58594,123.26405,753.4006,554.8497,-585.43646,727.09595,549.5668,58.73992,759.90424,548.5,-521.1286,735.13446,545.48193,73.82794,892.2257,608.12305,-172.43192,852.99915,603.6095,172.68022,897.84985,788.0066,-207.7563,862.26154,751.8793,339.0263,932.7875,966.241,-214.91072,889.04834,906.8284,519.7403,953.7617,996.48267,-230.12267,905.694,940.24866,532.04333,863.1287,1011.3136,-413.0734,817.08484,934.35406,444.05722\r\nScreenshot_2021-02-11 at 15.37.13.png,squats_up,539.97955,61.191574,-385.84067,546.1388,53.702435,-361.34293,550.6905,54.35461,-361.2724,555.41785,54.879185,-361.25473,531.3342,53.182495,-368.74805,526.05566,53.165234,-368.76242,520.78613,53.2464,-368.8433,558.5912,67.692276,-219.99858,511.05414,65.69337,-255.0984,547.69446,80.50731,-333.11493,528.87177,79.40644,-343.2499,599.287,164.77121,-113.76027,467.86636,165.20253,-168.23277,628.0412,257.3235,-27.11293,437.0733,258.4968,-115.689476,642.37616,339.66888,-115.7158,416.48788,341.62473,-220.4332,650.90436,364.20532,-142.04033,405.32126,367.0139,-248.64737,646.74054,368.76746,-185.25372,414.39304,368.62247,-299.34488,638.86633,361.61816,-136.24101,423.8703,360.01114,-242.5801,581.73706,348.99814,23.193707,503.55557,356.9037,-22.99656,600.2688,480.82852,13.74992,489.50333,496.8088,-23.24571,618.22076,615.3559,174.64821,477.09146,624.0644,147.28146,611.9454,638.7589,180.63455,481.92297,641.862,153.00577,648.9244,652.3788,39.94763,463.30005,671.1583,-1.5402623\nScreenshot_2021-02-11 at 15.24.55.png,squats_up,524.83624,94.22079,-445.07336,532.18744,82.00193,-425.02856,537.1524,81.31564,-425.03662,542.2855,80.51323,-425.03394,516.5029,83.79424,-422.40622,511.39774,84.138466,-422.303,506.30774,84.57015,-422.223,551.61365,84.67463,-265.59064,501.13156,89.31308,-249.7694,536.15674,105.61983,-383.74576,517.89154,107.33802,-379.42838,600.93646,159.39304,-155.9566,471.09033,165.5593,-112.372154,631.805,253.31271,-111.1888,463.09387,255.15532,-43.586456,653.94745,341.6585,-245.13321,441.91934,338.31598,-207.95401,666.84973,366.06912,-278.23947,433.0476,363.36087,-240.60532,658.40125,369.88324,-325.4625,434.37036,362.54712,-301.62686,649.24786,361.708,-266.4613,443.32114,353.85675,-236.12134,576.4812,344.52884,-5.8308992,494.32062,347.33072,6.104559,628.0211,484.2011,-19.148397,452.24744,479.08557,-22.963032,670.2652,613.8788,177.3918,407.5402,604.2404,164.72551,667.2106,635.0752,186.98582,413.5927,624.76697,173.37155,697.35876,653.9362,-0.34960616,367.62918,647.24164,-7.4960203\nScreenshot_2021-02-11 at 15.09.48.png,squats_up,606.60004,145.48691,-123.94384,612.2696,137.98567,-100.40261,616.28357,137.95847,-100.33223,620.38806,137.83295,-100.45074,599.7466,138.98886,-103.71352,595.3682,139.50821,-103.63975,590.99005,140.09424,-103.65276,626.39667,146.46695,18.586884,585.3564,149.19638,3.3681767,614.94617,158.90422,-81.54539,599.7961,160.06726,-86.0935,659.7294,214.18448,34.59123,556.30194,213.57283,24.60966,666.1648,268.34915,-134.33006,563.9993,270.41202,-145.98889,626.00446,212.4558,-281.22296,597.31415,215.32439,-329.5442,620.71124,198.05696,-319.00925,604.975,201.89209,-368.6126,619.7709,195.88315,-301.57162,601.51843,194.52654,-362.01224,618.8047,200.83907,-278.6232,602.7224,200.12436,-329.57507,639.6156,371.1388,8.279728,573.078,373.8117,-8.301436,674.1724,488.1248,-16.3792,549.776,491.14554,-22.741726,695.57623,600.0846,104.203316,526.6877,598.21136,136.34229,688.4162,618.4558,109.22913,530.96027,615.5954,144.28827,725.5533,627.44104,-11.87538,502.01993,627.6062,20.544716\nScreenshot_2021-02-11_at_15.37.57.png,squats_up,1330.5192,120.81905,-415.8341,1344.8413,98.71483,-364.13177,1354.539,98.52315,-363.9965,1364.4294,98.180695,-364.1418,1315.038,99.742065,-371.83484,1304.8029,99.96432,-371.7708,1294.5858,100.39092,-371.82336,1377.9744,114.02361,-72.45423,1281.4802,116.29365,-108.2144,1349.5657,148.75874,-308.49072,1313.2264,149.95667,-319.1715,1444.4,265.9073,58.99415,1215.1523,256.96298,23.951422,1510.6359,400.61737,-296.83246,1150.0116,396.91772,-300.4184,1409.9679,247.36519,-744.475,1245.7959,241.82742,-678.072,1393.5331,206.49406,-844.6868,1271.2576,201.67816,-755.67865,1382.8193,192.86531,-782.3877,1270.6223,184.88487,-726.6992,1379.4983,209.44557,-729.35547,1270.4232,204.44774,-668.7491,1393.3047,608.1055,27.101868,1250.8191,602.94696,-27.03342,1444.6102,873.34625,20.255928,1211.038,867.7122,-29.796198,1457.4199,1091.9712,452.4881,1174.3014,1089.3588,346.07635,1434.1774,1128.2292,480.20978,1177.6278,1119.3367,365.30447,1535.0442,1162.7484,189.12654,1159.2225,1174.2397,41.919132\nframe__RC2rq5Djv48__0001517.jpg,squats_up,733.57495,269.4648,-91.42483,745.51605,255.81502,-102.56469,749.9261,255.16765,-102.47287,754.6031,254.46315,-102.51363,738.37524,257.20795,-60.645798,737.33,257.26617,-60.60653,736.2094,257.49698,-60.434475,774.0139,258.85468,-91.22955,750.9084,260.32318,122.10663,746.13617,281.66324,-86.151054,736.714,282.6275,-24.90556,809.1619,323.29504,-235.23537,728.3114,346.82922,300.4839,772.94086,365.2086,-604.3912,664.67615,437.1496,390.67828,719.02594,347.93738,-879.6951,589.869,486.5713,293.20572,711.7816,344.58853,-939.8035,569.148,500.32703,332.91858,714.5173,340.49805,-941.0012,557.32404,497.10236,257.56995,716.632,344.05014,-885.9635,567.1456,495.19678,258.93372,743.3482,553.6229,-178.46014,698.0222,550.6096,178.24553,718.39276,732.7481,-284.92224,687.94836,723.79865,218.83275,713.31366,919.0931,-354.5465,687.26184,887.54407,280.54636,728.2056,950.8902,-374.00046,699.0136,920.76495,276.56482,648.4529,959.35675,-560.26074,619.1954,915.7032,151.15668\r\nScreenshot_2021-02-11_at_16.12.08.png,squats_up,1421.4865,232.51508,-1075.4042,1431.6259,205.87764,-1044.5603,1440.4435,204.57262,-1044.5251,1449.5137,203.02217,-1044.2904,1404.2067,208.5572,-1050.6334,1394.2603,208.80902,-1050.3787,1384.3577,209.24059,-1049.9739,1460.2006,207.73288,-761.6352,1369.3373,215.20702,-772.5272,1438.5471,252.89067,-962.34094,1405.6449,255.19753,-965.4185,1543.1036,332.42072,-511.9208,1301.0859,345.44757,-493.23788,1586.0074,499.74826,-374.0991,1272.2292,520.0932,-373.42047,1582.8376,654.43164,-603.26447,1274.396,679.9588,-593.76666,1591.278,698.863,-694.5007,1267.8738,729.6216,-655.6348,1568.9175,700.6166,-767.1003,1287.1027,730.95306,-749.65643,1557.3419,684.0095,-635.9518,1301.4302,709.3474,-633.1315,1503.1244,653.95514,-7.670668,1361.6232,658.04553,7.060646,1540.3763,916.24976,9.395795,1311.3228,896.4236,62.03809,1581.6006,1123.5052,368.19415,1276.5347,1090.8297,506.79156,1573.7053,1151.1112,389.97763,1290.6628,1117.4248,536.2948,1617.5769,1217.3213,101.83715,1232.7124,1192.9097,250.13564\nScreenshot_2021-02-11 at 15.28.40.png,squats_up,636.27246,82.346924,-206.0594,642.1728,71.79272,-181.51453,646.67303,71.85738,-181.41705,651.2484,71.81769,-181.4248,628.09296,71.79252,-185.92801,622.97864,71.77069,-185.85805,617.8693,71.79653,-185.88667,654.45435,79.340195,-32.311478,609.39557,79.11018,-54.556656,643.76044,95.62996,-151.95331,625.7885,95.60094,-158.48221,680.03314,151.92822,53.549377,573.7839,148.23141,43.64509,714.18787,227.57094,-50.573345,547.2192,229.50426,-55.075798,740.5162,168.88652,-311.31305,521.1573,167.96237,-335.97284,753.3155,151.1914,-364.82056,512.6865,150.71867,-394.08722,751.01495,142.8689,-369.58585,512.1043,136.88173,-400.6437,742.4142,148.8934,-321.08722,519.6422,143.46947,-345.21887,657.74457,309.10962,13.37734,593.25214,307.9699,-13.075798,678.58154,440.51346,-0.8264833,581.58484,440.5257,-34.419502,677.7561,558.7309,173.14513,566.56305,560.30676,128.77715,668.8143,574.7365,181.95088,568.48175,576.3836,134.84789,697.4071,597.38324,42.550274,560.01917,598.8616,-19.810957\nScreenshot_2021-02-11_at_16.27.03.png,squats_up,1271.6829,145.22086,-606.3698,1287.1234,123.99428,-565.0811,1296.2107,123.40386,-564.85156,1305.5134,122.76621,-564.9532,1262.4557,126.44982,-554.8817,1254.3484,126.986435,-554.9322,1246.1023,127.88802,-555.0614,1324.099,139.12616,-317.70178,1243.5161,143.8753,-262.22852,1293.3044,170.18219,-518.01935,1261.2528,172.34854,-500.46518,1389.1533,260.8199,-205.58008,1196.0878,277.53522,-169.21118,1549.1172,169.67151,-457.30286,1039.7458,216.91168,-493.34958,1396.8038,145.08936,-529.62976,1192.5609,163.6621,-718.79364,1358.7004,135.01233,-560.51544,1240.958,149.90964,-792.38617,1349.0474,147.10486,-525.5979,1243.3126,151.58514,-747.43097,1363.6306,161.62454,-524.09766,1228.1482,167.70688,-714.60754,1351.7872,633.95996,-45.56285,1222.487,640.3838,45.143963,1400.4266,921.40985,-109.26532,1173.2709,900.24756,35.206734,1447.4872,1184.7994,130.08331,1152.5056,1154.088,309.92444,1450.3423,1215.2178,140.75316,1170.4543,1187.8539,320.29428,1443.131,1281.3308,-152.78996,1091.7637,1250.9537,45.620274\nframe__dHp2JCXHWSs__0007399.jpg,squats_up,897.29504,395.28467,-277.86197,909.1817,383.07098,-294.62823,913.1628,382.77344,-294.72595,917.38245,382.33994,-294.7651,903.7377,384.056,-251.12209,902.95795,384.1125,-250.98209,902.0864,384.28638,-250.8559,936.2259,387.69092,-290.81625,917.271,388.6318,-75.75141,909.3276,407.5204,-272.37146,901.0065,408.04117,-210.5435,976.2999,459.39905,-330.8594,900.4971,461.27515,110.176506,987.76715,555.41956,-385.9855,877.9146,541.91986,228.3379,940.5402,635.3239,-458.91156,851.2444,611.4586,43.59089,936.8712,659.7827,-515.3007,845.4197,636.22095,17.22591,921.347,655.0849,-528.39636,844.6796,635.9326,-47.15146,922.98206,646.85504,-461.71542,854.04553,629.0792,11.570088,937.5356,656.2813,-140.41022,893.93365,656.26135,140.62068,951.6523,801.1136,-171.56445,881.45557,783.71027,353.71008,973.4679,935.8005,-92.108055,891.34033,891.19403,634.57623,986.762,957.66986,-92.94784,906.1834,915.04156,658.38715,931.6098,981.63324,-256.0061,831.8842,921.1517,565.39905\r\nScreenshot_2021-02-11 at 14.53.41.png,squats_up,482.17914,114.7106,-436.48608,488.49622,105.033424,-421.94852,493.08316,105.27209,-421.9243,497.81616,105.397255,-421.81406,474.89474,104.85972,-424.70575,469.93527,104.75668,-424.6325,464.97934,104.73489,-424.53506,502.57617,113.55722,-302.22427,457.20544,112.136566,-310.6705,489.8332,128.91869,-389.05972,472.5484,128.32054,-391.43878,538.5021,185.76143,-199.82062,416.37708,186.88005,-225.93779,572.1844,272.75885,-156.64983,397.86676,277.83148,-201.60306,581.7491,356.76416,-264.60367,386.50403,361.38495,-278.1439,587.9127,381.3841,-295.56503,380.299,384.83896,-294.15823,577.83124,382.114,-330.8845,383.34628,389.4345,-343.14185,570.6341,373.9209,-280.98483,393.762,381.85776,-298.32104,519.1784,354.2484,10.103685,446.48468,359.73093,-9.998616,539.86096,486.11023,12.370708,439.87564,497.3427,-26.274967,556.0815,612.2364,139.28441,428.37036,616.9814,107.68498,550.6563,630.98425,144.05244,433.3642,634.3288,112.38028,579.01117,653.005,12.189593,411.4994,658.6949,-27.559969\nScreenshot_2021-02-11 at 14.30.22.png,squats_up,472.23123,161.65189,-500.0348,481.09338,147.49803,-483.17178,486.23923,147.55696,-483.10434,491.44717,147.51562,-483.10114,466.62924,146.48485,-483.00397,461.70013,145.64696,-482.97852,456.76855,144.89456,-482.98047,498.84683,149.18634,-332.88086,452.16113,145.7805,-331.2421,481.15024,172.3568,-441.25357,463.45752,171.01962,-440.3073,529.64374,202.08234,-199.65186,417.13452,197.36632,-211.08167,579.6285,266.86823,-312.0288,374.53546,258.57477,-334.33173,598.2966,203.4941,-518.50476,354.40878,199.01309,-576.80536,609.37213,180.44835,-560.1916,344.39084,180.33583,-623.19055,603.5961,172.2657,-553.517,348.40216,170.45967,-622.4766,596.6289,180.38223,-524.34186,355.49515,177.35669,-582.9664,512.3136,363.08612,1.474868,443.48132,364.56012,-1.2838728,566.1829,462.53464,-162.02518,405.25027,481.38574,-61.682144,589.54193,588.05475,-42.955242,373.55856,595.94745,45.716248,584.10455,609.49475,-41.233723,377.7627,617.3456,43.93215,610.2522,615.56213,-213.74028,345.43854,620.1341,-118.853386\nScreenshot_2021-02-11 at 15.33.01.png,squats_up,632.84033,129.84302,-139.61911,637.408,117.55936,-122.232185,641.58215,117.05692,-122.20978,645.8911,116.45578,-122.18252,623.7152,118.60642,-126.28471,618.97833,118.68199,-126.229225,614.2177,118.802765,-126.27779,650.2998,118.51257,8.112447,606.1049,121.63805,-8.291975,640.686,140.25314,-88.546074,624.6054,141.27425,-93.60707,688.348,184.15965,93.3601,571.47906,183.43979,50.607906,707.75696,260.32654,88.52595,556.27386,260.72855,27.634943,694.2988,321.82352,-141.15756,573.0396,322.8415,-154.55252,695.0125,347.26132,-206.48584,574.39813,346.19894,-203.60303,682.5288,342.2752,-233.68773,583.59796,341.3946,-235.8888,679.7039,331.86142,-158.78151,585.96594,332.9497,-169.8959,672.5215,348.12897,13.517707,600.6328,349.93338,-13.139687,692.32947,484.72028,-46.33834,587.2613,490.54315,-74.14965,705.33386,618.1779,75.97266,568.93665,624.7757,57.216736,701.4223,633.1125,77.66996,568.18225,642.43536,59.40124,704.03424,664.98914,-71.858116,570.72314,667.1915,-96.34243\nframe__-nXY1rQt1bI__0022161.jpg,squats_up,972.0069,302.33383,-165.89911,980.2352,290.29163,-127.33555,985.81537,289.9626,-127.02898,991.54956,289.50827,-127.0955,963.62585,292.39682,-122.30721,957.85535,293.00198,-122.27504,952.0194,293.824,-122.61296,1000.68054,300.92676,50.92485,946.2501,305.9109,77.82161,984.9867,317.75272,-103.534,962.1223,320.03296,-95.41644,1039.0922,376.79135,157.49791,913.9386,384.16165,195.69481,1150.2388,354.6199,130.78635,811.62445,365.8973,238.742,1083.1163,268.45682,166.03116,863.3196,275.83374,328.31476,1067.3165,242.4254,143.51257,877.6164,252.0754,317.97797,1058.4325,249.12155,178.12764,889.799,255.71022,342.49054,1059.9762,263.20285,174.99944,887.29114,268.36743,335.0602,1010.70593,581.9102,-19.011688,934.9261,584.18097,19.489006,1001.51483,758.9576,-37.666904,950.1739,756.0141,17.081146,1012.60205,913.4432,193.27065,957.4605,914.1006,227.41705,1009.23785,930.66144,204.11884,961.9731,933.0593,235.76077,1018.96545,969.28046,-16.28284,954.3201,969.02954,29.105995\r\nScreenshot_2021-02-11_at_15.53.55.png,squats_up,1371.1882,124.81257,-541.12213,1383.9209,105.11682,-494.15048,1393.8479,105.419975,-493.94034,1404.1489,105.49541,-493.76663,1354.0968,106.0501,-503.3845,1343.1378,106.62913,-503.19104,1332.2068,107.39833,-503.0021,1414.9849,126.58408,-243.50705,1314.8932,128.55737,-257.4919,1389.6421,157.6369,-447.57956,1350.5396,158.18939,-451.9548,1499.4479,295.86432,-122.95889,1230.2828,298.1446,-121.11312,1582.4165,449.5931,-147.088,1184.4357,468.30667,-41.508396,1623.442,596.0973,-594.74475,1175.1398,648.10504,-280.48065,1645.7335,654.14734,-713.6629,1158.7677,705.33856,-337.1474,1610.1724,647.93665,-793.49274,1186.696,715.29114,-440.73642,1593.7972,629.4513,-635.7854,1209.4958,694.4155,-325.00986,1452.6715,658.7148,-12.83528,1297.7749,666.2744,12.882511,1484.1783,949.1299,-58.544464,1266.9542,956.5719,31.083967,1526.3274,1211.6729,205.55244,1254.1401,1193.9166,405.3079,1520.5753,1243.8744,218.1427,1275.9988,1226.411,429.01886,1548.9923,1321.4556,-53.901733,1178.9745,1299.8479,163.37071\nframe__TBXy4D2k-II__0005697.jpg,squats_up,789.3036,318.87735,27.331648,798.7473,304.0939,-14.051007,800.6803,303.7982,-13.746513,802.8529,303.41476,-14.061689,801.1348,304.3774,46.525944,804.6944,304.20404,46.524437,808.1992,304.3005,46.44626,825.11676,311.78653,-118.058044,833.09314,310.7863,164.62482,798.7089,337.32986,-8.805821,801.3386,337.36603,72.001335,864.9614,397.1509,-206.10135,851.71893,389.91406,308.7753,883.6977,325.05838,-586.18427,852.2689,371.35107,649.0516,884.51447,301.991,-751.6418,865.8843,313.2824,871.70593,893.6793,290.81143,-780.8007,874.1497,297.98752,908.2172,898.3537,305.4775,-771.8969,870.88495,300.59024,922.7925,897.2644,310.05933,-756.3994,866.625,307.69693,879.1901,844.60925,636.1364,-182.20076,838.18866,634.67474,182.05156,846.072,831.2973,-260.20096,844.42865,811.95984,222.71582,856.4481,1026.7776,-344.4582,886.49365,963.10516,393.99216,878.9802,1056.4364,-356.68735,909.94104,990.42883,402.87714,795.14606,1078.9185,-489.9525,822.0297,999.479,308.33334\r\nScreenshot_2021-02-11 at 15.05.31.png,squats_up,549.67224,88.36423,-386.25247,557.41656,77.445435,-363.26077,562.65656,77.450066,-363.15903,568.0974,77.27739,-363.02444,540.8735,78.4273,-368.3118,535.1899,78.8111,-368.20102,529.53033,79.2737,-368.1684,575.98804,86.40707,-211.43616,521.8481,88.716675,-227.1731,560.49274,104.70788,-328.8996,540.3732,105.518135,-333.82443,627.97327,168.00513,-132.45181,484.62073,181.24858,-138.50156,666.7943,254.20552,-137.57803,465.08923,276.9868,-132.70917,698.0145,347.718,-345.7405,446.19775,378.4121,-247.40205,717.2716,379.03143,-404.74133,432.59573,407.87317,-280.83273,697.3945,381.8598,-448.65527,443.87848,413.53955,-338.06046,687.1738,372.1254,-368.1635,456.08862,403.1051,-273.03018,628.6286,371.2994,5.2939897,535.77094,383.17175,-5.235547,706.53674,509.49384,-11.245826,471.42877,525.2157,-23.22997,783.10767,641.97064,115.34435,414.24957,652.6373,144.33383,782.5628,668.8269,119.766594,418.23883,673.42303,151.72377,831.0079,671.4181,-39.9863,376.55106,693.84106,-8.055057\nframe__M_heu5pg2IQ__0008580.jpg,squats_up,936.50775,108.20161,9.733694,947.9347,92.638596,-30.01133,950.8487,92.627716,-29.921232,953.94135,92.49488,-29.957563,947.3976,90.82002,32.350914,949.57245,89.378456,32.228214,951.8047,88.02231,32.229027,975.9558,96.46145,-130.48428,972.4924,89.24537,149.60757,947.6329,124.59474,-19.379343,945.4546,121.96752,61.17207,1012.58203,173.9405,-275.01114,999.0881,189.07513,332.8287,1036.3441,277.4952,-332.71387,1018.5639,298.996,409.21082,984.4553,375.00742,-222.36986,994.41077,384.6677,264.4038,978.755,402.15695,-264.88773,987.84406,403.73056,257.72177,963.9293,397.62494,-252.06685,982.64166,398.35107,216.06741,973.00586,389.0786,-212.60594,982.47174,391.32736,238.94504,995.61584,450.45328,-184.91467,982.7119,447.50815,185.13806,1014.81274,670.8205,-159.43526,993.12286,660.52203,165.34587,1044.7112,890.12396,-124.70684,1025.2904,860.6263,273.9651,1066.512,924.4005,-131.59538,1047.4094,897.32263,276.78424,971.2087,938.6264,-282.01086,952.5123,897.13666,186.12616\r\nframe__4nbkEcxHNhQ__0010565.jpg,squats_up,902.2848,258.97388,-187.79555,916.8079,241.08365,-176.22557,923.2056,240.54906,-176.01147,929.8793,239.93259,-175.95071,901.52057,243.57661,-133.65039,897.1887,243.94647,-133.5104,892.9278,244.62146,-133.63898,948.5039,246.53868,-98.22259,902.68024,251.44061,96.070145,918.3295,274.556,-160.54466,899.96375,276.35126,-104.23188,995.8154,313.68518,-156.1623,878.8263,319.62903,233.83083,1022.2959,201.6889,-369.78296,842.7852,218.64389,310.7472,1052.9095,75.03998,-413.04605,819.6129,102.15666,198.78572,1066.3193,41.909603,-468.84344,813.91675,76.17722,177.55246,1063.0814,38.61306,-448.93542,826.6238,64.8383,155.29137,1054.321,50.64225,-411.8948,834.4299,72.99337,180.41948,970.9234,592.8356,-145.62762,900.4467,597.8282,146.07434,985.60626,794.99976,-141.59273,901.9653,791.59406,223.17455,1023.5211,982.39075,-1.8117324,911.93176,963.8283,416.37976,1036.4517,1008.6863,-5.203425,926.324,996.4377,426.63876,983.92523,1043.9725,-255.51822,850.09766,1005.37946,252.82405\r\nScreenshot_2021-02-11 at 14.20.51.png,squats_up,560.5143,138.55446,-528.8017,569.74347,118.90691,-519.55615,576.7197,118.56571,-519.4958,583.9803,118.08727,-519.3362,548.7191,119.39365,-521.4022,540.9878,119.08985,-521.3153,533.2715,118.877106,-521.2531,591.1918,123.7331,-362.17798,520.83624,123.91114,-365.1271,572.37714,155.88983,-462.33228,546.39484,155.85345,-463.0603,648.67694,225.05603,-218.40805,462.65857,229.54704,-221.48715,687.07874,366.16644,-123.478615,448.67828,375.67416,-162.5572,718.64825,496.07364,-237.88754,430.36993,508.13547,-265.53146,735.3034,533.8731,-273.01675,418.18082,544.8165,-276.6038,721.5787,535.3834,-331.18054,421.7962,550.6104,-354.12418,707.034,522.6242,-261.60086,439.00568,538.3841,-296.90973,621.743,490.64523,2.021262,509.59708,497.7822,-1.988058,642.04535,718.17267,-37.038334,501.68118,722.43085,-52.635975,666.23224,935.3754,91.36387,469.25113,923.0959,114.94953,659.89905,964.91736,92.48582,470.7864,948.43896,120.7271,679.92847,1003.5184,-123.28962,452.93048,993.70215,-81.543816\nframe__TJwLjTQivFM__0024752.jpg,squats_up,898.7372,271.55807,-389.38,910.07947,271.88705,-399.65964,914.8146,273.97876,-398.8258,919.83185,275.62955,-399.63068,901.3277,269.08316,-358.86276,900.5795,268.79706,-359.15958,900.5517,268.76706,-359.94177,934.53253,292.39877,-338.73898,909.49084,282.27682,-116.977615,902.5112,299.49982,-370.48853,895.55145,295.78964,-309.8675,934.4324,389.16965,-358.4525,872.5665,370.51587,129.02,927.1509,355.89005,-419.72052,764.05597,359.1113,496.24445,939.99225,271.81595,-101.88674,850.15924,290.02408,653.1089,959.4856,249.67484,-16.527859,875.6185,257.20544,698.1419,970.43494,262.24878,-44.87364,892.38745,273.4276,730.4111,963.39624,269.77872,-101.47526,882.56,288.83078,659.3866,900.7604,604.4918,-166.59816,830.8745,599.7643,167.03792,901.4376,795.6388,-80.19985,796.72723,769.5485,409.17477,911.7143,961.85785,-81.18232,791.5518,908.3133,631.19727,923.6446,994.9814,-82.8371,802.5687,943.1713,655.27637,864.7169,1022.12775,-254.06564,709.9647,943.62823,602.6475\r\nScreenshot_2021-02-11 at 15.48.59.png,squats_up,609.6518,107.70486,-186.00307,616.1086,96.87851,-167.50615,620.11694,96.21624,-167.3686,624.2998,95.56089,-167.3536,605.9593,98.80085,-160.13336,602.893,99.2883,-160.1661,599.7772,99.91505,-160.2612,635.5107,102.26325,-54.889977,601.9083,107.42825,-23.21315,621.21356,119.81464,-145.48582,608.2393,121.832726,-135.68286,675.3527,163.48747,-64.21294,582.9474,171.4775,-35.745407,737.1811,132.74622,-352.32877,517.3945,165.2205,-327.94107,673.1657,146.47523,-536.8072,597.5995,151.74167,-565.5707,660.6178,153.87581,-579.2447,618.3691,153.37555,-618.701,651.76544,157.97287,-561.93726,623.8998,149.16202,-598.6083,658.5464,161.65668,-536.06116,616.78076,153.73927,-566.20404,670.1587,344.80286,7.6808314,603.69226,345.23294,-7.80172,696.63983,500.9649,-6.166543,590.7699,501.13577,-22.682264,723.9861,648.33325,83.111,574.59436,650.9401,75.50938,716.35425,670.447,81.536285,577.77484,670.1945,74.89882,749.3292,685.4473,-96.89361,564.922,697.3911,-96.229095\nframe__rSNN-Arbxuo__0011153.jpg,squats_up,1292.0116,225.44409,-402.1879,1295.2728,204.23662,-378.40234,1295.3821,203.82071,-378.3701,1295.8766,203.3661,-378.20123,1290.3058,202.55315,-437.5595,1285.7368,199.65668,-437.5839,1281.384,196.93106,-437.6366,1274.2416,197.80705,-229.89415,1256.279,189.12672,-497.57996,1275.3872,237.27362,-339.34134,1267.4368,233.31949,-417.78168,1229.8304,270.63205,29.855364,1147.6097,266.70123,-596.80365,1212.2925,398.4919,243.39758,1087.0016,427.73718,-641.9426,1239.6084,503.40103,210.45201,1119.3374,578.0377,-686.21936,1251.0311,537.096,235.58861,1111.0713,620.4919,-762.5723,1255.627,538.27344,160.26828,1144.2306,623.38306,-755.9431,1245.4417,528.73914,181.09871,1146.5623,608.2702,-682.7867,1144.2511,516.0501,191.91309,1085.322,526.29065,-191.1807,1180.0618,712.08594,334.17648,1119.3452,735.2365,-142.74722,1156.7568,882.33124,568.9436,1120.8589,930.399,7.515747,1134.2166,907.8872,584.6459,1092.0381,955.27704,16.39927,1216.655,947.9294,530.44275,1204.1091,1005.96436,-102.47158\r\nScreenshot_2021-02-11_at_16.29.58.png,squats_up,1389.4878,323.27942,-763.5938,1401.5339,309.9569,-722.3872,1409.2125,310.13892,-722.4366,1417.1697,310.12485,-722.35516,1377.3008,310.8922,-721.6875,1369.2891,311.49048,-721.4357,1361.2517,312.22736,-721.29724,1428.8677,326.9333,-470.20764,1351.5311,329.0817,-455.45636,1405.1428,349.4815,-670.43945,1375.7065,350.0963,-666.2682,1497.1892,472.23105,-310.89246,1290.0377,468.5086,-261.4365,1540.6213,614.4287,-270.73892,1259.8668,609.8333,-177.31982,1561.2855,740.47455,-584.86163,1226.5027,739.45276,-415.30066,1577.3464,779.83374,-674.2545,1211.829,777.9789,-470.21344,1555.914,780.3237,-752.5053,1217.3662,783.8159,-569.412,1545.1138,766.11194,-622.6677,1233.1667,770.73956,-460.91757,1456.5371,751.7682,-6.3608117,1327.7499,750.4454,6.3804097,1498.531,982.0031,-26.473928,1282.8456,980.86835,-38.455643,1535.9352,1188.7157,294.5351,1236.6617,1186.4872,274.79007,1531.807,1216.6473,307.65744,1246.0503,1216.6154,288.68484,1550.7444,1264.2279,-2.9455302,1189.3579,1261.2504,-11.320748\nframe__Z7m4mv8arb4__0013975.jpg,squats_up,911.5151,194.77826,-137.11441,920.26276,175.24318,-186.0481,922.64923,174.29767,-185.95543,925.27167,173.24504,-185.8801,922.6925,175.26143,-122.422455,925.65765,174.53207,-122.47006,928.6787,173.89784,-122.46676,948.1405,174.58122,-305.50195,952.8872,174.66208,-14.399994,923.21826,209.46078,-171.78264,923.88116,209.47678,-87.48979,976.378,265.5316,-425.0529,997.32263,265.64752,206.895,940.7275,420.3263,-436.49265,979.3634,405.27887,279.3423,885.8976,553.66113,-332.41125,941.02374,527.7498,180.21521,881.18823,585.36914,-385.9502,935.7614,558.4949,200.21654,869.45825,586.8228,-367.02972,926.8797,554.33105,144.7364,875.7998,575.825,-322.08347,923.79816,543.9217,154.3973,972.60614,526.2863,-195.76593,984.56476,518.20435,196.1254,944.8201,721.96454,-51.78939,971.31824,713.0078,283.3965,961.6223,915.19183,121.23887,972.5965,891.8092,464.52042,987.1011,947.81244,127.965706,992.57684,926.35364,476.8303,877.4002,956.15,0.26589745,893.379,927.9294,399.69177\r\nframe__PVh70znekVE__0000500.jpg,squats_up,965.43066,212.08884,-450.26962,973.93445,202.01054,-418.48865,979.7206,201.7384,-418.47806,985.75146,201.32068,-418.33215,954.4764,203.72633,-418.6091,948.3893,204.4449,-418.43582,942.3374,205.28816,-418.53946,995.6946,211.73434,-227.78079,935.0247,216.81244,-220.43796,978.27954,231.04129,-379.67322,956.7748,232.72037,-377.99576,1060.4451,322.90463,-88.61462,887.76544,330.6627,-105.80305,1096.6301,444.44302,-40.040565,869.16,466.42822,-79.1366,1116.5747,561.5834,-278.68646,853.20685,584.2873,-263.0858,1129.9406,595.0794,-336.6448,841.9264,614.4999,-300.68002,1118.6394,600.0999,-406.7508,848.80725,622.41766,-378.776,1108.0771,589.6159,-310.81763,864.4642,612.33307,-297.15247,1033.7028,562.7371,-2.0269299,930.9718,565.54364,2.0673604,1021.6113,772.6165,-43.52439,940.17395,774.01,-43.174957,1008.37415,957.8913,191.96478,947.42114,950.41095,195.23611,1000.38367,980.8496,199.05179,956.21857,973.0982,202.77797,1007.65686,1021.29333,-38.229954,937.9125,1011.71606,-42.218834\r\nScreenshot_2021-02-11 at 15.17.44.png,squats_up,639.8248,132.66298,-121.71849,648.5553,125.61765,-99.32753,652.9497,126.1762,-99.362686,657.5276,126.658875,-99.4676,636.1786,125.00606,-91.44639,632.18085,124.87238,-91.37055,628.1278,124.83714,-91.24798,665.82404,135.98465,11.302848,626.10345,132.44514,57.034546,648.9986,146.61362,-83.45994,633.03906,145.58353,-71.193,691.0486,195.32672,-43.366497,590.7151,204.44203,158.15953,696.31537,238.30402,-304.33868,523.3558,249.45724,141.51453,646.941,185.28357,-547.8754,442.08252,272.01312,50.090496,634.8835,177.03976,-602.233,417.90134,278.03024,67.93623,638.24664,166.71185,-597.5999,410.476,273.9167,17.76264,640.0043,172.1854,-552.0235,419.8529,275.2938,26.711597,662.3764,367.3587,-48.652287,596.2086,370.20038,48.635258,685.03046,505.65338,-106.9266,573.91364,501.68463,31.19632,710.04517,640.34216,-26.442595,559.4151,633.8099,131.95085,708.67096,661.33514,-29.919348,562.65094,656.9351,131.04373,710.126,672.0963,-195.78864,536.7022,659.0273,-18.478367\nScreenshot_2021-02-11_at_15.45.37.png,squats_up,1238.4789,206.33078,-630.6196,1250.4044,182.58998,-585.47003,1258.9122,181.62378,-585.5038,1267.6362,180.48842,-585.4694,1223.508,185.0046,-590.814,1214.3737,185.61295,-590.5697,1205.1501,186.29399,-590.66644,1278.933,189.575,-282.82944,1191.5002,195.66753,-300.94153,1255.2391,229.42708,-514.9558,1223.4846,232.01137,-520.33563,1351.2388,328.10657,-45.064415,1123.215,334.04248,-71.582115,1400.83,513.35675,-134.60501,1052.0968,512.90375,-185.96211,1301.7821,510.4594,-673.30646,1202.0441,516.83386,-609.53125,1264.9932,525.2191,-799.01776,1252.6395,530.11835,-717.486,1264.1337,490.3738,-818.7051,1254.1146,496.2897,-720.4015,1272.9974,486.15527,-689.78015,1240.7695,491.5045,-615.168,1316.3525,669.9278,20.215828,1178.0076,679.0908,-20.07488,1346.7822,936.4567,-19.574013,1132.317,955.2661,-72.04104,1369.2134,1183.7567,333.00098,1089.8496,1201.2673,295.80484,1358.535,1219.297,349.88113,1094.8322,1235.9137,310.88016,1403.4453,1261.2693,32.58983,1060.4017,1284.9963,-19.912209\nScreenshot_2021-02-11_at_15.50.29.png,squats_up,1268.7812,142.5281,-664.05756,1283.2397,121.72784,-620.20667,1293.5858,121.856384,-620.1164,1304.2333,121.735344,-619.94507,1253.534,123.14186,-628.52826,1242.479,123.876305,-628.3972,1231.3987,124.848915,-628.5462,1319.5907,144.37454,-351.63647,1218.2561,147.3939,-384.15002,1290.0762,175.05203,-563.4188,1249.4724,176.33798,-573.1663,1400.5857,318.64972,-192.87048,1141.5406,308.64703,-253.30779,1426.1174,512.2339,-97.55647,1105.3292,488.8516,-234.09541,1411.3743,681.2784,-330.36624,1113.9153,670.564,-446.7079,1417.4974,740.7408,-401.32394,1105.2605,732.4149,-509.28482,1395.6608,741.3241,-477.13412,1128.2192,737.3927,-595.72876,1383.5533,718.06305,-363.64862,1145.078,714.25476,-482.85815,1344.6305,691.7357,26.834007,1192.0099,689.95966,-26.04528,1396.134,955.68445,59.222748,1156.4546,955.3662,-6.9970245,1399.3743,1183.1343,380.48975,1146.2899,1181.6091,393.8461,1378.353,1220.8529,398.62823,1168.4963,1216.397,416.79785,1464.7903,1273.9523,172.68817,1076.4962,1286.191,153.37279\nframe__YrIqX5FkctA__0014617.jpg,squats_up,530.52954,274.0701,-116.47337,545.3587,262.69296,-158.42499,547.7696,263.10883,-158.459,550.32306,263.36038,-158.37872,545.8707,262.46576,-99.57214,548.46875,262.6868,-99.55562,551.0652,262.96127,-99.49786,567.70337,274.1845,-254.35092,567.6855,272.68378,17.232758,534.7502,291.93924,-147.12744,534.84454,291.12042,-68.43646,574.6954,363.14105,-376.0521,578.4812,380.62265,221.21756,554.14264,497.12396,-424.06848,566.82227,500.7043,295.54022,520.14923,621.93335,-427.3151,535.7855,604.07996,251.19664,518.9854,645.0328,-491.13583,534.1649,624.32294,292.39798,515.0969,650.3166,-480.68332,526.40436,628.2028,227.35469,517.03705,644.7285,-425.18857,526.5278,620.30664,223.70598,628.6872,597.54956,-191.23619,626.54034,599.1092,191.88937,602.1471,782.5424,-143.30191,609.73193,774.4707,230.5551,611.24567,975.611,-53.45316,618.1551,953.347,324.67676,630.475,1008.99994,-61.26548,635.6391,987.24414,325.10526,529.7218,1004.1334,-231.3612,543.5412,980.4613,227.57323\r\nframe___y-DOueHrR0__0004482.jpg,squats_up,959.58594,150.5278,-300.3836,971.0859,134.52612,-262.359,978.276,134.64961,-262.19937,985.7183,134.6096,-262.19498,948.52405,134.3228,-262.03522,940.99493,134.07199,-261.7152,933.413,133.92767,-261.67487,996.1402,144.82912,-23.348492,923.548,143.17566,-20.021763,973.4342,170.58412,-212.79784,945.9208,169.95303,-212.434,1043.0609,259.01218,117.64788,867.89606,253.05255,141.97647,1060.6024,376.49203,40.909008,836.831,380.6556,54.584167,1104.7479,441.28918,-433.53333,790.9424,438.82867,-427.53497,1127.2896,471.03394,-530.06335,774.3921,460.70465,-521.38586,1117.782,463.42172,-595.7588,776.9696,449.83298,-579.7004,1105.0514,453.4596,-470.13528,791.31213,443.57828,-461.70673,1003.5932,527.60345,10.792376,891.15247,528.47864,-10.148696,1034.9521,744.423,-33.453583,857.6719,749.5136,-79.466965,1071.3032,929.3902,274.14432,818.9161,934.71295,258.25534,1062.4708,956.42725,289.24115,823.56964,961.7711,273.53445,1105.3644,986.73456,43.761833,793.92487,992.9288,16.129032\r\nScreenshot_2021-02-11 at 14.32.45.png,squats_up,392.4915,136.80922,-99.54932,400.51312,126.18695,-82.35754,404.8499,126.244896,-82.279564,409.2795,126.21885,-82.32317,387.9468,125.81769,-80.4691,383.85498,125.4198,-80.37647,379.73108,125.09078,-80.42384,417.83017,130.70549,44.419327,376.72897,128.6821,54.286926,401.72403,147.26726,-51.649673,386.26178,146.52942,-49.52528,449.24918,188.70808,131.2674,347.9603,184.33807,130.03432,469.34515,255.78941,49.909058,325.15726,257.7369,28.586855,457.11996,250.94188,-216.96132,333.7671,250.09146,-258.33746,455.85324,255.95992,-274.96048,333.7958,251.95901,-322.39432,451.55582,245.22961,-283.89606,340.7033,241.21605,-330.8634,450.23547,243.91919,-227.15329,344.62524,240.66794,-267.78064,430.06424,345.49655,6.241889,366.67218,344.7132,-5.8480506,438.70135,473.56104,-31.273205,353.7963,473.4192,-39.03309,444.2216,587.25916,117.90049,341.64972,582.24695,131.61008,437.36407,602.2495,125.45241,344.47134,595.2844,139.4989,461.35226,627.5401,-10.97683,333.37506,625.43024,-2.004119\nScreenshot_2021-02-11 at 15.51.09.png,squats_up,220.29651,86.132935,-338.5979,226.79025,76.46399,-316.49402,232.017,75.67749,-316.56354,237.40004,74.79243,-316.57675,212.54976,79.15115,-311.0196,207.63142,80.183174,-310.88354,202.68654,81.29594,-310.93808,249.26309,83.50512,-195.74576,201.22408,91.72461,-164.93463,234.50458,100.00266,-295.3098,215.62086,103.12071,-286.48544,299.5515,170.73984,-117.7485,173.66571,172.56853,-78.231735,308.6104,271.1676,-71.415276,163.60518,267.19318,-57.537834,308.7772,360.51257,-190.19444,169.76004,307.31754,-218.41429,315.17084,388.10458,-226.10312,172.9741,323.82208,-259.52924,306.70096,389.8473,-268.94946,177.47519,314.398,-292.3649,298.62097,379.61963,-208.00728,181.26688,307.19412,-234.97162,265.26178,354.61227,-14.47491,191.29794,352.11813,14.953921,259.5075,486.4121,-4.471446,181.41513,485.2662,47.31168,250.58594,605.10583,171.38771,184.55739,602.57715,256.86572,243.53973,621.1567,179.5733,199.61685,621.3632,267.97986,261.22916,654.94965,31.640669,140.87358,651.6234,125.800735\nScreenshot_2021-02-11 at 15.41.32.png,squats_up,491.65674,75.96865,-168.63313,496.0779,66.40294,-143.25177,500.3411,66.165504,-143.18085,504.71832,65.83664,-143.20424,482.03702,67.806915,-150.07417,476.88925,68.35994,-150.01082,471.75262,69.01842,-150.05052,508.32358,74.78941,-9.43943,462.0049,79.02685,-39.33309,499.4014,91.20343,-119.08232,482.4727,92.72641,-128.07118,548.8353,152.92609,32.374718,422.1183,152.17224,-6.4902377,583.7612,220.40628,-119.84592,390.7608,213.04645,-193.411,520.0537,184.57607,-285.4333,469.64008,166.39607,-367.47406,504.87216,178.88336,-320.7505,488.2292,157.63817,-406.10715,500.27713,170.29984,-301.96875,492.08066,150.8168,-387.93253,503.39087,174.2182,-280.49716,488.64258,157.4158,-361.18454,527.313,338.6275,9.282237,448.36572,341.11816,-9.288436,548.1199,477.41635,-9.958214,433.23038,478.47134,-43.61182,556.4229,597.0455,161.91968,431.6944,601.7335,120.10919,548.4032,614.8028,170.9593,441.31357,619.7009,127.640915,577.86066,637.8073,31.972832,401.5613,647.05963,-21.545557\nScreenshot_2021-02-11 at 15.21.33.png,squats_up,296.428,121.55462,-302.904,303.70694,113.694214,-280.6306,307.70477,114.386826,-280.59406,311.752,114.99336,-280.63467,291.61737,112.22057,-283.19247,287.46848,111.70048,-283.1212,283.2902,111.24874,-283.114,315.1695,122.89161,-139.25815,276.27722,117.50226,-149.00606,301.9349,134.70729,-251.21739,286.65005,132.6062,-253.9395,334.63303,185.54184,-53.96341,242.27551,180.77983,-58.09806,369.43585,251.79364,-190.63304,220.63574,247.31065,-179.45975,387.76385,205.34232,-466.44238,203.36559,202.56302,-445.36612,396.52478,193.07367,-523.43677,195.09789,189.76747,-502.01892,393.2489,182.75378,-529.49805,195.723,179.92801,-508.3025,386.47516,188.43498,-477.47748,201.59874,185.1565,-455.3673,313.0597,331.16003,5.6276536,254.26256,329.60916,-5.4749923,350.28464,435.5604,-10.694324,222.12573,434.1654,1.6673566,358.71008,536.9332,162.47168,194.3621,533.1233,177.14644,349.77304,553.96765,171.79007,198.49945,550.68567,185.34703,386.1086,563.8918,46.382782,166.25955,559.1859,53.046017\nScreenshot_2021-02-11 at 14.39.47.png,squats_up,442.58136,97.83734,-440.5874,449.29227,83.70549,-427.03897,454.17862,83.73803,-427.00534,459.22443,83.6437,-426.9073,434.08603,82.83912,-433.55045,428.46082,82.019775,-433.50174,422.83243,81.27496,-433.4612,462.2947,85.39687,-283.6614,411.81003,81.70077,-310.02594,448.7575,109.14937,-381.44278,430.74185,107.6844,-388.89188,495.1557,146.74988,-180.61934,367.0772,149.01236,-201.85466,511.7959,238.25227,-141.6225,360.36343,248.59868,-174.50171,522.5811,328.68353,-235.72958,350.765,341.87866,-268.44357,532.54395,354.4153,-260.05148,343.32477,368.9081,-290.3225,523.0519,358.08646,-300.6157,346.991,371.98907,-339.04984,514.24414,350.0738,-253.30957,357.36435,363.68442,-289.27213,474.26962,335.6434,12.13739,395.61362,342.08868,-12.08056,511.65176,468.559,30.080912,369.72858,480.9299,-8.862521,535.3765,590.13214,197.52545,347.7126,601.37036,151.19926,529.12396,609.1199,207.06729,352.28818,620.3545,158.80315,560.70966,632.7339,71.03795,326.44125,643.4432,9.038909\nScreenshot_2021-02-11 at 14.45.02.png,squats_up,417.2589,130.31303,-80.51927,419.54132,124.20606,-55.973434,421.93692,124.507866,-55.94291,424.43484,124.78534,-55.997036,410.98688,123.551674,-64.18461,407.7134,123.20206,-64.21827,404.4215,122.94236,-64.39679,423.6887,129.65245,56.19311,395.88962,127.44534,14.092505,419.40427,140.70818,-41.0309,409.42422,139.77658,-52.935143,443.13455,179.43127,10.575033,366.51157,173.39137,-12.191023,476.15604,158.10213,-216.01811,381.76334,162.65771,-193.5627,418.7987,145.06958,-333.28473,417.57303,152.12889,-268.06952,407.0425,142.63004,-378.08783,426.22644,151.64595,-304.8212,399.72882,144.86598,-355.84143,426.35913,149.51048,-301.54272,403.6185,148.3327,-332.5985,422.98856,151.57541,-269.99094,426.96732,311.71155,13.270195,373.52734,309.7536,-13.21313,437.2286,407.26462,18.163187,355.48828,406.84222,-31.030596,440.6065,502.8968,119.720856,338.7853,499.97675,64.160576,433.79523,518.46796,120.36301,340.09842,514.78253,64.61788,455.5898,527.91174,-7.8423524,327.82318,526.304,-64.93521\nScreenshot_2021-02-11 at 14.51.09.png,squats_up,184.98854,43.480816,-144.43222,190.30424,36.17766,-124.30406,194.599,36.081802,-124.421455,199.01233,35.85912,-124.43884,177.7999,37.14461,-125.00496,173.39832,37.642014,-124.975395,168.95013,38.19836,-125.13229,205.2808,44.723637,-28.807571,163.62842,47.484676,-33.08991,194.09407,57.234154,-109.72433,177.26302,58.481216,-110.41003,240.92758,116.69567,18.266855,130.85315,117.15736,18.167831,281.7564,187.39597,49.581768,70.47204,181.12822,20.513052,249.12646,230.39812,-34.17102,118.598854,226.8468,-68.00608,242.10576,249.26125,-66.35802,134.08606,244.04817,-97.03533,230.15858,239.1194,-82.19138,141.81924,228.34653,-111.87441,231.22754,233.45468,-39.98029,137.15909,224.53348,-72.56708,217.09251,282.8545,5.4524274,148.81729,281.2373,-5.2384486,245.80061,409.72177,0.77115667,122.9161,405.91022,-1.5010039,261.52716,531.2111,105.05022,97.54456,521.02264,105.22341,254.15729,550.608,107.42165,101.34023,540.73236,107.99489,282.55746,561.29535,-9.95944,72.25322,549.185,-5.717537\nframe__YArvGEk8c6c__0006724.jpg,squats_up,1293.3628,165.7264,-562.02515,1303.2291,153.50212,-533.34,1309.9448,153.74403,-533.3949,1316.9495,153.78082,-533.3762,1281.7758,153.49936,-532.24896,1274.6469,153.48497,-532.156,1267.4988,153.59737,-532.0795,1325.3616,164.76086,-340.7406,1257.159,164.19594,-322.0474,1305.6279,186.4376,-488.23517,1280.0355,186.17249,-482.5935,1382.1602,279.0338,-231.69745,1199.6084,275.2614,-146.66425,1439.5747,406.2164,-209.16301,1140.6176,395.32098,-77.4153,1502.5494,515.79645,-363.17252,1071.4722,497.22293,-241.58994,1529.6802,541.94446,-403.99515,1043.7811,525.0403,-263.25595,1519.901,543.7129,-473.869,1044.45,526.85675,-350.5086,1504.7045,537.8068,-395.1612,1061.8899,522.5438,-281.8979,1338.8242,545.82306,-24.146246,1227.3582,547.6054,24.213514,1388.6732,741.6091,-53.411404,1190.566,741.8904,19.543806,1400.1603,913.96515,217.23438,1164.7507,916.56335,270.87546,1390.8103,940.3928,229.83197,1174.2941,946.71,281.6979,1421.4989,975.4852,8.266388,1125.4211,969.1963,53.893764\r\nframe__1R1w-YcubSk__0010399.jpg,squats_up,1036.662,379.10272,-856.16626,1043.8921,356.80722,-838.6693,1049.8599,356.2287,-838.59937,1056.0265,355.73322,-838.54584,1026.9973,355.8173,-838.9708,1020.71466,354.2731,-838.9805,1014.3379,353.02682,-839.01056,1061.2725,353.7518,-626.7286,1004.1235,349.1258,-622.7741,1046.4203,388.79645,-771.9636,1024.9722,387.13367,-768.73816,1107.351,421.25034,-526.22266,949.4073,406.2827,-555.04,1233.001,377.2681,-903.12427,861.13074,336.68906,-940.1788,1134.5931,355.7371,-1281.1963,953.4582,332.28998,-1236.7455,1107.822,348.61838,-1386.5408,975.27246,325.81332,-1349.0696,1093.585,354.36475,-1360.5647,988.8157,332.81366,-1290.3116,1100.353,366.6164,-1285.4713,983.6529,341.12897,-1230.8988,1030.7429,658.0843,-1.459516,944.52203,652.0351,1.885467,998.55756,828.4703,208.20273,940.307,818.99384,216.68056,992.8065,958.8986,675.57104,934.67535,958.2428,657.459,989.686,969.15265,712.30475,935.92145,973.23645,688.39435,973.8867,1025.8582,505.04266,933.6646,1022.1776,451.94598\r\nScreenshot_2021-02-11 at 15.50.45.png,squats_up,610.04346,131.87068,-56.048775,617.2746,121.23781,-35.482384,621.1928,121.30172,-35.36436,625.1989,121.2855,-35.428967,604.53064,121.06007,-37.7505,600.3835,120.797295,-37.744152,596.18695,120.62289,-37.725838,629.7959,126.3572,98.134964,589.6888,125.116554,93.56944,616.64606,143.5651,-6.266964,602.0456,143.0938,-8.034885,652.115,188.396,165.36191,560.4943,184.59729,141.32487,687.3028,237.1414,-38.30165,547.2485,245.94438,-63.31492,637.12134,189.5545,-243.95258,607.0597,183.40256,-230.20287,628.794,176.44835,-289.02448,622.1157,165.01715,-262.67792,625.39435,173.78343,-259.79172,620.1836,163.75455,-237.09512,625.9726,179.1019,-236.96962,617.5522,171.93086,-220.16496,637.727,342.30875,-2.5979474,573.1931,340.59396,2.3999565,673.5124,478.6257,-58.656548,534.93616,468.36368,-37.38979,706.7274,592.63885,101.60493,500.95673,585.69666,118.6284,704.54865,608.0633,109.36786,503.40518,602.51556,124.251465,723.4494,624.6878,-54.68721,479.6702,621.72015,-32.42833\nframe__4qz94HJYjdk__0011023.jpg,squats_up,919.50085,247.82446,-407.80225,928.4759,231.92465,-374.2379,934.44995,231.6615,-374.06244,940.5741,231.29617,-373.90613,910.5822,232.58769,-371.155,904.21985,232.45763,-370.9694,897.7963,232.4368,-371.00137,947.0591,239.2341,-167.56038,887.50885,239.6337,-149.09865,929.9218,263.18304,-330.9753,906.8069,263.45303,-325.9216,986.4229,321.70505,-55.042477,843.0143,331.74344,-30.404316,1054.1887,416.4172,-230.19205,773.1932,424.69162,-248.01616,946.3655,437.153,-508.23193,888.36505,418.1836,-547.7209,914.02563,452.5403,-560.43884,923.77716,422.0351,-619.95776,906.7652,434.01517,-545.96674,928.2512,409.01337,-585.8259,918.4899,432.7423,-500.3213,918.827,411.03433,-539.4407,970.4799,557.3908,-11.503317,881.25995,562.1871,11.745984,978.70935,755.8338,-43.552322,886.7438,749.4833,13.621625,982.6423,903.8351,293.00818,896.4762,903.1711,356.51135,979.1272,916.4388,315.75803,903.3458,918.8748,377.3449,979.8137,980.5943,85.67137,893.9855,979.5995,142.4018\r\nScreenshot_2021-02-11 at 14.33.13.png,squats_up,339.06946,103.60443,-108.5235,346.26312,94.87475,-87.78472,350.43158,95.072876,-87.74643,354.68503,95.17997,-87.77895,333.77533,94.69775,-87.35543,329.59943,94.649956,-87.29007,325.39008,94.64091,-87.40877,360.91843,102.55265,37.883934,320.54056,101.20832,41.795197,347.30463,115.82675,-63.002758,331.71762,115.38936,-62.48535,387.8509,168.40602,122.911804,290.82147,162.91888,128.35963,413.03586,248.57303,45.182365,270.8498,242.30666,39.28928,401.18854,219.67456,-219.62419,282.56778,210.71097,-215.74274,396.7829,217.44237,-275.00375,285.68152,203.77977,-269.13818,396.65262,203.03662,-278.20303,287.6499,192.38712,-273.57468,395.22174,204.10129,-225.46135,291.43832,194.49557,-221.88187,365.49396,311.2884,5.4400516,304.98984,308.79495,-5.1376004,369.86057,440.20535,-21.7969,290.06244,437.57578,-37.991047,377.11438,551.1498,127.88075,276.39883,550.15643,112.82771,372.19724,564.9764,134.93652,279.5601,563.3604,118.21805,390.36572,588.7452,-5.535115,266.91556,591.7418,-25.702137\nScreenshot_2021-02-11 at 14.47.25.png,squats_up,387.34378,97.8003,-407.21313,392.65485,86.22941,-392.28766,397.19528,85.878105,-392.30936,401.88034,85.42477,-392.27017,378.3282,87.04218,-397.48804,373.1849,87.15346,-397.44852,368.05774,87.315636,-397.40738,405.98993,90.417076,-263.1253,359.38538,92.568924,-283.3592,395.32224,110.21462,-354.8897,378.08087,110.99746,-360.9142,442.399,164.46881,-168.45807,320.40054,164.08727,-187.29022,463.51477,259.0952,-130.77916,304.68326,253.45314,-147.58588,473.75937,345.15518,-227.96527,300.4114,344.17438,-233.51212,481.26608,369.3737,-259.82486,294.29355,372.10736,-263.44025,472.69376,370.2627,-297.46054,303.3877,373.9764,-307.10336,465.618,362.271,-245.789,310.97165,363.547,-252.77664,417.93774,347.5216,6.1210866,343.5415,349.5647,-6.0186486,442.73743,488.19766,-2.469615,320.7648,489.6118,-40.63723,458.48657,621.4233,119.23758,306.1225,620.05493,81.747795,454.28278,642.3414,121.76507,313.8232,641.2733,83.69676,474.83762,660.1283,-29.520445,277.7796,658.62933,-70.39369\nframe__Jv6AyrhXJ4M__0020901.jpg,squats_up,932.7735,317.41278,-82.77693,941.28064,307.59338,-45.3875,946.3527,308.06302,-45.28393,951.5597,308.4189,-45.44648,925.3152,306.87415,-50.492817,919.9605,306.57678,-50.412884,914.5572,306.3985,-50.599274,958.47174,318.98413,146.54407,906.5849,315.89127,129.57831,942.087,333.8169,-14.607391,922.30115,332.7391,-20.163609,993.17737,401.26767,196.5796,870.0295,387.17325,158.67949,1030.4348,461.82144,-97.26992,857.9275,433.44177,-174.29497,1002.5541,393.747,-440.92493,891.52905,352.18607,-511.4394,1003.3738,378.34863,-513.0338,899.3082,330.5344,-580.08496,996.18396,370.24457,-491.9428,897.1831,325.42993,-567.87933,992.5392,376.5156,-441.9549,899.0322,335.62772,-513.402,973.07086,596.9193,0.44744408,892.07916,595.2764,-0.5712116,997.64777,773.4565,-49.5844,881.2676,771.847,-7.2246194,1005.3559,925.2528,183.7918,880.32776,928.20605,219.51466,996.33923,944.35547,196.54599,892.5298,951.9878,230.28317,1030.6194,979.7999,6.918894,843.31024,976.75146,40.91839\r\nScreenshot_2021-02-11_at_16.24.02.png,squats_up,1293.7236,181.811,-403.3702,1307.6447,158.77817,-359.02524,1316.3112,157.90508,-358.86462,1325.2435,157.05127,-358.97754,1281.9629,161.60918,-352.63083,1273.797,162.22125,-352.3864,1265.5713,163.0168,-352.6145,1342.6515,169.29091,-105.58852,1259.3722,175.33913,-80.80203,1313.4861,205.96385,-311.4313,1282.7736,208.5793,-303.18,1413.9114,293.6908,-235.07596,1209.5933,303.39865,-130.45996,1422.3967,304.1656,-947.33905,1163.0093,304.525,-839.896,1366.1709,245.76613,-1513.54,1235.0133,249.18234,-1474.7225,1349.7712,238.83742,-1663.4717,1256.1946,239.48065,-1634.4966,1343.9913,225.78381,-1647.948,1266.1617,228.408,-1617.5427,1348.2917,234.97507,-1528.3484,1261.7996,238.35324,-1493.4254,1371.7495,667.4977,-19.910387,1231.9552,673.03125,19.959967,1413.2413,938.5143,-94.587715,1180.5326,943.5096,-101.7741,1480.1267,1192.5265,117.66242,1131.021,1197.1344,160.3766,1485.8564,1223.4125,118.42992,1138.192,1230.1403,165.3223,1465.2402,1271.0122,-214.55826,1100.3715,1277.0662,-148.87375\nScreenshot_2021-02-11 at 14.41.26.png,squats_up,384.11432,76.17954,-348.52338,390.5565,63.458233,-326.7964,395.37067,62.761627,-326.96942,400.30542,61.94059,-327.01257,376.895,65.40065,-324.39865,371.94803,65.8885,-324.30444,366.97598,66.46055,-324.29108,407.09262,69.35751,-192.97166,361.84122,74.16631,-184.55054,394.24338,88.74303,-298.4113,375.24762,90.95634,-295.65054,449.63535,149.27408,-86.53561,329.548,156.78297,-104.277054,504.8115,236.46542,-43.805782,259.78333,224.5432,-92.225464,472.29166,304.86667,-166.122,305.32678,303.3227,-206.98111,464.34564,326.90295,-208.57545,316.14804,321.78894,-255.91266,451.9475,318.9136,-232.71411,326.9106,309.07693,-268.99622,452.68002,310.88605,-176.87126,322.90393,302.66895,-215.18181,423.72983,335.8961,13.844424,356.25174,337.75677,-13.458505,412.95984,481.38556,22.289179,366.5761,482.74283,-22.431747,410.18884,614.50256,176.52667,372.4215,612.16626,154.5083,404.4172,632.1057,183.57414,374.27518,629.36005,162.27144,414.6098,654.386,18.29831,375.29498,653.9777,-2.7964902\nframe__awBQVJ39sKM__0011979.jpg,squats_up,1784.8591,463.45358,-355.91925,1802.4874,424.264,-308.51633,1813.89,421.97928,-308.4529,1825.6461,419.5483,-308.57782,1766.9879,426.98718,-301.26978,1755.7706,426.10785,-300.65176,1744.4155,425.45273,-300.52112,1848.6382,416.38977,91.24576,1736.8566,423.7323,132.56548,1811.9155,483.58908,-199.00824,1771.1372,486.0852,-188.81163,1936.2914,573.76874,370.7965,1673.5948,555.29285,451.6381,2007.2163,752.3897,240.41064,1610.2572,739.3905,251.52872,1922.3259,820.12805,-457.24182,1647.8054,788.28516,-650.4852,1902.9166,853.877,-620.3413,1650.0564,814.5542,-858.91327,1886.1843,819.456,-683.2955,1674.1985,785.7928,-894.63556,1893.0535,804.80396,-497.23453,1677.8485,776.2566,-685.1922,1863.3972,1023.79913,-24.427832,1691.9087,1005.53375,24.837286,1935.3801,1392.888,-222.2022,1629.7186,1360.625,-71.43614,1969.6556,1713.7979,311.4986,1582.2463,1674.1603,456.93634,1956.492,1750.468,339.00208,1591.6001,1715.3372,480.5952,1992.9913,1837.5046,-106.809654,1553.0269,1800.3745,38.75552\r\nScreenshot_2021-02-11 at 15.42.09.png,squats_up,600.5279,120.779785,-408.48666,605.82153,112.588066,-392.29642,609.55927,112.57918,-392.28067,613.42505,112.47919,-392.1954,594.4108,112.93583,-393.1011,590.3963,113.01202,-393.01648,586.3941,113.152855,-392.984,617.83276,118.765976,-268.27985,580.7119,119.030785,-267.7754,607.3648,131.57446,-360.38727,593.171,131.63516,-360.46292,647.1225,181.24591,-160.68826,552.8688,181.54593,-159.94812,663.61804,256.5955,-94.44716,546.6328,257.52524,-115.10953,672.53156,325.6916,-186.0422,533.5402,325.39655,-207.08112,679.49854,345.98935,-209.65402,526.3587,345.4556,-220.69815,672.55225,348.1227,-251.19023,527.79126,348.20102,-272.17258,666.8381,340.8617,-203.32199,536.3482,341.95496,-228.43068,631.86487,313.82806,4.7371798,573.7519,315.19156,-4.6908264,641.97675,433.97275,-10.505835,566.0621,435.04504,-36.9898,658.4551,544.6535,114.146736,556.20935,543.19305,90.99623,657.1579,559.468,117.861916,561.15106,558.9343,95.574684,662.5908,580.04504,-30.914808,537.9754,577.24744,-49.6853\nframe__JuDMyY-ybQQ__0004862.jpg,squats_up,992.4183,260.3138,-237.20444,1002.8548,242.69513,-212.77669,1009.5227,242.16379,-212.53152,1016.3727,241.60538,-212.57265,983.98956,244.15958,-206.71812,977.65686,244.30078,-206.50613,971.2628,244.5984,-206.54564,1029.4391,250.08662,-30.722105,967.23944,253.06633,2.4113402,1007.88586,277.3981,-169.73515,983.4994,278.59192,-160.2896,1080.0183,341.3741,-23.691847,928.39935,346.6261,108.968414,1095.4459,401.38892,-417.9748,901.9339,431.36627,-206.03937,1089.3279,379.82474,-926.8025,898.65247,385.43793,-748.83124,1095.0938,387.00818,-1024.8204,894.5428,382.1071,-857.0266,1083.6299,375.9025,-1038.3043,903.6215,363.99112,-869.8442,1082.1869,374.3106,-945.65894,908.0846,367.33978,-769.4442,1036.7568,593.30133,-39.578255,942.6503,592.77295,39.749935,1038.5363,787.3204,-131.86697,932.17664,790.6846,-7.9870625,1049.7911,964.0874,65.676994,926.53546,965.84937,216.12558,1048.0529,982.559,71.33472,932.6289,986.1282,222.45341,1041.6099,1039.0894,-147.20836,914.02295,1040.5826,12.248875\r\nframe__Sjh9S2OhDyw__0001554.jpg,squats_up,951.2037,220.55995,-395.4399,960.77673,207.33255,-359.23178,966.5765,206.7921,-359.20236,972.5112,206.14632,-359.19556,942.9846,209.5021,-355.3643,937.4771,210.24318,-355.11884,931.88983,211.11517,-355.22437,985.8171,214.7655,-140.42838,928.8583,220.34813,-114.0991,966.3176,237.28775,-315.2829,945.36365,239.33537,-308.54626,1046.3501,319.16095,26.73799,886.67114,318.98825,47.397556,1061.373,446.117,-52.88407,865.8264,444.51715,-54.604042,993.365,435.1504,-475.99683,932.29834,434.40515,-455.91736,971.606,443.48624,-578.70746,952.7361,437.27728,-556.39233,971.4379,419.37213,-601.0848,956.0297,418.25214,-565.8363,976.0952,413.50644,-493.74545,952.8266,414.63806,-466.99576,1008.73236,535.8121,-16.773989,910.5324,535.7002,17.09069,1027.328,724.21124,-66.31214,890.2541,722.2918,33.3497,1047.4469,883.3563,241.27327,868.12384,879.0416,407.43964,1042.3275,907.1659,257.52557,875.8122,902.973,428.63464,1064.5798,935.01135,21.534826,843.1976,936.75464,194.37802\r\nframe__JSn5DY10dbA__0004586.jpg,squats_up,965.0474,299.5146,-77.016235,973.28235,284.2029,-38.49106,979.4172,283.80582,-38.303505,985.70996,283.364,-38.407413,953.93774,285.80493,-40.693752,947.2197,286.12518,-40.770813,940.411,286.59164,-40.78831,993.6558,292.0936,163.04002,930.64685,295.76147,150.82684,977.42914,317.36877,-6.3587494,953.64136,318.62778,-9.621375,1038.813,372.43195,85.868164,894.02014,382.24142,115.93231,1048.8162,346.1788,-363.8133,879.3173,416.44315,-342.95447,1025.1162,314.09366,-680.5133,874.1322,337.80194,-762.38855,1026.66,300.79004,-771.4013,866.0018,315.60074,-861.43823,1022.451,306.0213,-758.25543,874.2431,309.06046,-858.2072,1019.81024,312.34286,-693.0913,882.1157,316.5233,-775.4693,1023.10583,605.9229,2.6019309,925.0746,604.0436,-2.474856,1053.5027,807.5109,-130.17706,900.1844,805.7237,-116.410614,1076.7982,991.05927,19.490374,869.1334,989.56177,36.31053,1070.973,1016.87726,17.431467,876.19965,1015.0775,33.578922,1094.2579,1044.534,-219.95395,841.851,1048.248,-200.21222\r\nframe__-nXY1rQt1bI__0012387.jpg,squats_up,959.64166,319.00204,-136.76303,970.8045,305.4576,-162.11073,973.5289,305.0609,-162.23595,976.37054,304.5451,-162.47076,968.722,305.65118,-109.717735,969.8202,305.28534,-109.61255,970.9092,305.00015,-109.61272,996.32654,308.6142,-182.00958,989.6822,307.4886,60.41014,970.56573,331.74847,-140.49156,967.0513,331.36032,-70.76248,1044.6432,376.1042,-221.60587,997.56146,395.36426,264.09552,1117.9117,453.00085,-321.67874,1022.95374,493.7608,140.38814,1006.9672,453.17368,-301.03818,968.199,461.50702,-313.1454,981.00793,460.62106,-328.32892,951.5566,455.42548,-380.28632,975.63446,439.85974,-326.22723,946.8187,439.59827,-393.00635,990.824,437.64355,-292.68668,953.0999,439.7968,-334.9353,1046.0717,588.0433,-178.10126,1016.74725,588.1939,178.19806,1022.3377,755.043,-268.31448,1020.58344,736.8428,232.64249,1061.8868,915.95715,-252.59834,1064.1039,891.5614,349.46353,1087.1207,938.43756,-261.5424,1087.3518,917.6928,349.14935,999.2498,962.9853,-419.25134,999.40027,934.11066,228.6545\r\nScreenshot_2021-02-11 at 15.48.23.png,squats_up,611.74133,146.2087,-85.31605,618.3008,136.53516,-58.92212,622.3622,136.40617,-58.86085,626.5455,136.1941,-58.951378,605.8658,137.48758,-60.630417,601.6019,137.74353,-60.562984,597.2802,138.0694,-60.689255,632.7107,143.45108,80.55551,591.7702,145.16278,72.919846,619.97437,159.11136,-34.02458,604.7864,159.84984,-36.785763,663.19147,210.35127,82.52438,561.97266,215.07938,128.38414,669.7947,275.9893,-99.30659,546.212,285.54953,-51.282322,601.0305,261.14786,-279.91272,606.5465,265.9902,-286.79517,582.5559,265.45068,-329.01324,623.1085,266.645,-341.09708,582.5875,253.93883,-316.9521,623.679,253.32738,-337.8988,588.6293,253.96925,-279.57724,619.4573,254.15866,-290.58737,645.11273,392.83823,-1.6704949,578.0323,395.10275,1.8888505,656.7601,536.5433,-22.779333,567.41016,536.65247,-8.031703,677.0953,667.2189,123.38288,561.1563,664.54504,165.81093,673.9701,687.2205,127.41719,567.74994,683.44165,171.8173,693.26495,702.29706,-35.6048,539.5007,703.43896,17.410246\nframe__j64BBgBGNIU__0016954.jpg,squats_up,1033.7894,294.03595,-138.32964,1034.1986,273.45978,-117.02864,1038.321,272.26038,-116.8279,1042.7244,270.86478,-116.8058,1018.30444,274.90182,-145.71782,1011.1968,274.43082,-145.40125,1004.2113,274.24466,-145.70297,1036.6123,271.70752,64.80961,985.57446,277.93698,-69.79339,1039.5905,308.95407,-66.57839,1019.24976,310.6347,-106.897415,1048.7694,363.55194,305.56033,944.50616,350.91003,-123.88394,1131.6384,365.4856,753.45984,857.6698,324.5974,-405.03223,1191.8005,360.46097,1097.4727,752.5725,276.37747,-727.7384,1209.5533,355.0827,1162.5753,708.85815,261.19623,-766.5719,1213.0911,360.26212,1161.8046,707.84314,246.5921,-828.9214,1208.1422,366.93863,1102.9279,727.51056,257.44165,-758.90784,1016.50726,612.5353,151.5169,958.1235,608.3969,-151.77527,1017.67505,803.51776,169.9599,947.0488,816.76135,-216.63907,989.5064,984.6234,286.791,915.4601,1009.55316,-249.41672,969.06213,1015.27606,286.82996,891.9134,1039.6709,-261.70422,1051.6841,1042.7522,183.7734,959.34985,1076.7542,-417.16965\r\nframe__BZBICKiw9Eo__0009203.jpg,squats_up,1780.8401,342.66086,16.408186,1796.8427,292.1447,85.11657,1810.8484,288.62982,85.63673,1825.3783,284.90576,85.3299,1753.0808,299.54565,94.250046,1738.1637,300.05646,94.23605,1723.0581,301.36035,93.377625,1848.5917,281.66998,465.18167,1710.2582,301.43726,509.52228,1814.535,368.02036,151.18724,1763.778,375.84964,165.49297,1964.3688,433.51834,625.9604,1641.2347,457.6322,704.2281,2062.3286,133.9123,976.49664,1570.2134,131.15236,792.2462,1885.1898,188.38113,1885.0809,1724.7719,158.71057,1266.4926,1828.6584,191.23807,1940.631,1762.402,157.45987,1257.1117,1842.581,230.96414,2001.1345,1759.5309,199.3743,1312.1377,1859.9272,229.81772,1908.0356,1750.5707,205.74994,1283.6235,1903.7585,1051.4094,-98.097176,1677.2283,1066.9244,98.56276,1942.3572,1483.7327,-228.91972,1634.232,1476.4265,95.77059,1995.7542,1895.0737,189.4145,1583.7792,1869.1709,605.87366,2007.1372,1944.1619,210.00896,1605.8081,1929.359,629.5325,1934.198,2065.216,-298.16257,1497.8843,2019.7026,175.0937\r\nScreenshot_2021-02-11 at 14.34.36.png,squats_up,171.68321,78.46935,-350.09515,180.89479,65.65468,-330.41904,186.77737,65.67169,-330.23526,192.72177,65.57799,-330.46997,164.4808,66.36621,-329.99518,158.73529,66.61723,-330.1198,152.93413,67.07549,-330.21313,202.51134,75.67578,-213.24664,148.26408,77.105194,-198.40974,184.31876,95.108246,-304.82224,162.59634,95.77563,-300.49255,240.9752,162.59314,-94.45273,117.08414,161.66669,-106.9632,252.46184,243.2195,145.4487,115.3801,249.79749,110.38718,236.06038,311.17148,415.64078,126.79726,324.61542,327.1908,234.94795,334.46252,470.3195,126.840096,347.07394,389.0743,229.52156,335.8608,453.976,128.06267,345.22336,356.8203,225.19098,328.28375,416.5927,133.32831,337.57483,324.11612,215.0371,351.22208,-1.3722589,141.93954,353.4406,1.2906588,215.8469,491.39398,-10.359309,154.91083,494.03455,53.539856,213.75397,606.9717,198.52544,168.82335,607.8377,293.50693,208.47542,621.7795,210.37042,176.04543,623.2398,308.91397,217.92914,659.62897,79.5648,156.76926,658.99304,181.77544\nframe__GYKaOqNtTEo__0008434.jpg,squats_up,790.79065,226.81305,-26.875908,801.1037,209.17671,-68.11279,803.9887,208.32544,-68.08962,807.0611,207.3356,-68.17396,801.506,208.05298,-2.4557822,804.6289,206.41463,-2.5836222,807.75024,204.85,-2.4464004,829.12354,208.86163,-181.73206,829.3356,205.05664,117.31567,802.2868,242.97813,-63.291893,802.1654,240.96536,22.60693,875.72076,293.5674,-353.5531,871.1071,309.4131,318.4413,914.6427,416.5606,-473.09622,931.9206,405.63272,426.20914,952.5275,571.6192,-488.29532,994.16327,530.67505,338.02704,972.44257,607.3578,-557.63416,1012.31506,564.9232,357.07465,961.85266,623.8621,-548.87305,1015.2938,566.6448,302.96722,954.9549,613.72253,-482.01947,1007.4651,553.1365,311.8858,917.36176,551.65625,-202.1557,907.3461,562.7504,202.47562,895.6612,756.2923,-183.80411,890.747,743.5627,248.19188,910.50507,963.9331,-68.27282,914.4436,927.4765,411.459,931.3521,1001.03687,-71.614784,936.5416,964.39276,415.57184,824.8343,1005.41766,-247.64325,830.50867,960.2751,310.7385\r\nframe__QfAY5JsB7qY__0000874.jpg,squats_up,838.8374,276.8119,0.07734024,847.9375,264.51025,-29.430153,850.1743,265.05347,-29.431526,852.59314,265.63068,-29.67861,847.974,263.36572,27.500282,850.3331,262.8266,27.559774,852.7526,262.54736,27.49912,868.23364,273.87103,-110.224686,869.7389,268.669,138.19255,845.33154,293.56915,-23.377293,845.488,291.82684,48.65949,885.55,332.4144,-248.80777,891.4974,349.14435,310.9659,857.0811,222.42722,-392.05984,897.6682,248.67963,381.32816,904.34247,141.51329,-298.7493,907.375,171.9298,159.25383,918.38403,115.081314,-338.34088,914.2406,150.2708,129.60126,924.35394,122.31137,-327.02756,920.55774,148.80093,102.74641,920.2948,134.92593,-292.0041,918.80536,156.57516,136.86298,894.89124,569.7146,-189.1116,896.23315,581.7536,189.03088,893.9069,755.1588,-168.62952,906.63306,774.6526,152.84792,919.10583,949.3923,-115.37872,928.5283,951.71875,214.10345,938.93854,979.93414,-119.957565,942.39557,979.978,211.44267,859.6524,981.12964,-271.0932,873.10736,971.84357,105.67817\r\nScreenshot_2021-02-11 at 14.43.05.png,squats_up,392.2246,100.5297,-405.8432,399.5279,90.06879,-389.69067,404.0514,90.02556,-389.70663,408.71725,89.88176,-389.6358,386.90228,90.41865,-385.12305,382.4825,90.41504,-385.03314,378.05722,90.47668,-384.89905,415.984,96.25965,-274.6334,374.282,96.54704,-244.12216,401.3507,112.519264,-362.05667,384.74097,112.60395,-353.42804,443.71765,162.94798,-205.84854,347.84277,163.51259,-148.15729,448.81827,246.40932,-185.75679,353.31058,245.54999,-111.77742,431.87488,318.06284,-267.91074,376.32126,318.64404,-201.56245,433.09732,341.82944,-306.0401,378.133,347.0593,-234.87717,419.70544,340.50052,-328.8514,390.84036,342.6035,-266.93436,416.9115,331.2754,-277.63483,392.29718,331.9071,-216.28862,427.28687,311.70163,-20.951883,364.34946,314.42212,20.85782,469.8106,428.53168,-44.2908,330.31247,435.09125,46.83943,500.92786,538.1317,110.84081,299.11508,538.51025,221.67,498.37363,552.6329,120.58833,303.65866,554.7698,231.97589,516.08215,582.91376,-22.168812,273.67056,581.0577,90.98388\nScreenshot_2021-02-11_at_16.18.58.png,squats_up,1218.7722,121.249985,-627.42816,1232.2188,99.862274,-592.2872,1241.7694,99.12304,-592.15295,1251.7318,98.14573,-592.0277,1202.5577,103.21706,-590.4239,1192.4009,104.43384,-590.21564,1182.222,105.867165,-590.00964,1267.1182,114.255875,-361.88217,1170.4846,123.4887,-336.59305,1239.4254,151.55315,-541.0453,1203.4581,154.83983,-533.78125,1358.0321,297.2823,-225.80182,1097.3494,300.30383,-191.35223,1367.5985,492.97537,-171.45235,1074.7964,491.22803,-132.92735,1362.9803,682.27966,-443.82474,1083.5638,679.5254,-366.95636,1375.7832,745.16486,-529.9251,1071.5043,740.9226,-435.34433,1347.2164,748.2691,-612.4142,1099.7592,747.18555,-522.379,1332.88,723.5871,-479.6164,1119.7681,723.81964,-406.69717,1302.7717,675.9301,-8.032907,1148.6643,678.63007,7.9560485,1321.7506,970.8291,5.4787984,1124.0118,966.5135,0.85746723,1360.7795,1227.0302,277.27768,1099.4089,1212.6356,331.24078,1353.9916,1260.7075,289.487,1108.9047,1245.08,348.5142,1380.763,1327.1968,-0.5720378,1072.7767,1315.0588,51.841312\nScreenshot_2021-02-11 at 14.52.48.png,squats_up,230.53487,84.17316,-211.32104,235.1964,74.656784,-202.09409,238.14537,74.6388,-202.01706,241.175,74.5945,-201.96506,226.2934,73.88119,-205.38309,223.11302,73.11062,-205.34499,219.89914,72.4367,-205.40524,244.85814,74.09076,-117.451164,214.45897,70.63472,-126.5276,234.7775,90.75208,-176.33069,224.81776,89.50032,-178.66931,270.0091,100.760574,-95.70949,184.4709,97.84812,-99.747215,288.1639,114.098114,-259.996,142.42201,103.735115,-275.84964,256.2238,93.57791,-426.35547,193.94281,92.2061,-418.05325,245.94037,92.3324,-464.33008,206.9728,91.77965,-451.72226,245.00548,86.83433,-458.3697,212.86678,88.22847,-439.62527,246.22336,91.4524,-428.5607,209.33533,92.19813,-416.88788,245.01591,237.87161,-2.157003,193.34187,236.89227,1.9226131,252.95181,325.51108,10.368917,176.66402,319.8043,46.650074,253.06549,396.47952,148.4637,166.86821,384.52948,213.32898,247.27826,405.92355,156.8969,173.46979,395.95728,224.3846,261.85104,428.8111,66.51,141.19853,412.6982,139.47334\nframe__8ghtQpeWov8__0001813.jpg,squats_up,992.152,150.27681,-307.5583,988.834,134.39772,-271.3407,991.519,134.59431,-271.19177,994.55255,134.68228,-271.29315,976.3955,132.82654,-307.21606,970.2674,131.82407,-307.08246,964.14685,130.92104,-307.12854,978.92444,139.22064,-75.34905,938.61926,137.04008,-237.14238,987.68243,170.14355,-231.46611,971.9663,168.20753,-278.63535,987.4242,254.14748,100.08038,860.15125,236.39973,-242.70596,1034.5525,356.5762,103.22185,852.0094,364.73886,-385.62747,1105.6171,408.91916,-270.10034,954.2079,400.74268,-606.2238,1127.1073,433.18582,-337.0063,977.5873,422.91885,-682.9812,1122.111,421.11618,-397.36737,989.99176,405.2189,-694.18207,1110.9166,414.4246,-306.435,981.51227,399.11505,-610.9274,957.8265,505.39413,118.11851,879.088,510.0138,-117.80343,966.5145,695.88727,146.69757,883.33636,716.2557,-133.58191,953.1861,862.74915,397.94156,866.8106,899.32196,33.76099,933.8917,888.8913,411.19696,846.4824,923.14124,38.501793,1006.15686,923.7753,254.04453,928.39,971.5631,-162.6447\r\nScreenshot_2021-02-11 at 15.45.23.png,squats_up,584.1631,185.89996,-370.31967,589.8939,175.7013,-353.63275,594.12067,175.56169,-353.6342,598.4747,175.31415,-353.5486,577.1709,176.24898,-354.8936,572.59875,176.29413,-354.8384,568.02893,176.42084,-354.854,603.39856,181.1384,-234.94139,561.76764,182.08148,-234.9946,591.91144,197.56662,-324.13666,576.0105,197.9684,-324.03177,636.61035,246.56856,-144.9364,529.0863,252.20241,-148.91142,661.3239,326.27,-102.61177,514.61,337.38184,-115.515625,678.8123,400.5551,-190.19206,503.9528,413.89218,-203.78545,686.9036,420.83255,-213.62396,497.5583,435.7305,-225.86426,681.0395,421.9914,-251.92285,502.7042,438.85056,-270.49136,674.60815,415.61804,-207.21039,512.27277,431.99124,-223.75128,619.14606,405.43668,-1.2751523,556.51465,410.59753,1.3621011,629.6656,521.8149,-11.489052,556.61487,528.50446,-13.909094,639.43225,628.2054,124.00347,559.2803,634.0515,130.77281,636.3995,643.40454,128.36923,565.3713,650.19604,135.89603,646.6395,663.48096,-11.033057,547.4978,667.76324,-4.116207\nScreenshot_2021-02-11 at 15.47.06.png,squats_up,590.76276,71.50635,-154.35172,599.80566,60.354996,-128.43233,605.25,60.420895,-128.43811,610.80475,60.36576,-128.49852,584.1557,60.818405,-130.1813,578.7679,61.042774,-130.0619,573.3548,61.345467,-130.10611,620.53375,70.03366,17.415136,568.18945,70.53303,16.575193,602.3975,87.5014,-101.07969,582.7267,87.868256,-101.924065,660.59674,154.04872,116.47949,528.26935,148.42844,98.129105,689.41754,252.05484,31.83693,497.16742,247.72017,-18.075268,649.2853,215.63802,-260.51105,531.63257,212.25262,-307.5008,635.07983,215.85811,-320.62384,545.19574,209.97871,-367.77103,632.8622,195.95743,-324.76907,547.9642,189.09998,-375.04166,633.60364,197.78342,-265.21588,549.74396,192.08879,-312.93146,634.1722,347.74313,8.969222,548.4797,349.4596,-8.657678,670.7532,501.87253,-28.375273,517.8445,503.39148,-3.6382165,691.1182,633.73303,172.48979,490.3922,627.31903,238.16139,682.1175,655.904,184.94595,496.75177,647.5269,252.19315,729.08234,672.4907,47.554756,459.8354,668.7107,105.11823\nframe__AGYM9Quh9J0__0002099.jpg,squats_up,972.58264,157.19785,-437.5313,980.4571,141.93445,-402.61105,985.8932,142.20853,-402.57135,991.48065,142.40782,-402.44684,963.17334,140.75662,-409.00433,956.8014,139.98305,-408.78488,950.35626,139.30333,-408.9472,993.22565,149.12573,-182.12016,936.0502,144.22636,-207.98018,979.40015,172.95613,-353.86194,957.3644,171.01239,-361.50232,1028.8845,240.42381,-30.844881,876.48706,238.2331,-44.577663,1066.1813,358.3282,-112.048935,835.8948,360.241,-174.9431,1019.9374,360.98596,-524.093,914.94946,366.30573,-542.08344,997.9629,372.63614,-623.13324,940.8102,375.4039,-634.6764,995.62146,348.86755,-637.41327,945.7173,355.51538,-634.3256,999.2188,346.75812,-535.5165,941.3861,351.75934,-547.0757,1001.75684,467.3345,6.626087,914.0741,469.3848,-6.1654606,984.2756,648.533,45.854134,921.1455,657.56335,19.762125,978.4957,778.21906,457.6746,924.5811,789.55914,446.22467,973.0914,792.2988,486.28967,928.422,803.3794,474.70447,977.96576,839.5242,275.22885,924.73865,855.7,257.21603\r\nframe__j64BBgBGNIU__0009475.jpg,squats_up,1021.88544,332.98987,-83.06554,1014.65295,316.9207,-61.53963,1014.80096,316.30725,-61.537342,1015.24976,315.54282,-61.44036,1008.1765,317.57074,-103.85116,1003.54443,317.19043,-103.783226,999.0104,316.87573,-103.86995,998.37866,317.11588,69.50872,977.06305,320.17026,-124.12408,1015.5041,347.03568,-31.381306,1008.0741,347.69232,-88.20729,1013.1194,418.0018,207.3029,906.4341,401.2462,-196.40866,1022.6374,538.4061,276.51892,889.6969,529.0707,-282.62234,1034.5106,648.68994,99.67798,882.35583,649.3266,-405.90982,1042.0406,681.1244,79.04295,870.18054,680.7622,-445.91937,1040.5546,683.1888,19.706963,880.3907,686.48285,-475.7768,1031.597,671.47186,71.128815,891.0538,675.4746,-415.95667,997.0485,628.46783,132.91011,927.0717,629.334,-132.12532,990.2689,826.4672,72.79793,913.8246,830.13556,-232.16394,977.6096,1005.8194,100.49769,886.8666,1018.76764,-230.36508,960.2276,1036.9271,92.94889,871.2427,1047.5862,-241.92238,1035.0962,1052.3884,-44.82202,927.9661,1073.278,-423.8949\r\nframe__MG69sFM1UIw__0000987.jpg,squats_up,1111.3011,258.89212,-425.49835,1112.5355,247.9395,-375.4349,1117.0504,247.8963,-375.4352,1121.756,247.69823,-375.42963,1096.5354,248.41415,-406.89777,1089.8804,248.57303,-406.62854,1083.2882,248.88127,-406.63397,1118.0529,259.4357,-141.95763,1067.6957,261.9754,-281.96976,1118.2571,277.64478,-341.96692,1096.9513,278.547,-383.47482,1133.7446,374.57507,111.45476,1023.6456,363.19165,-323.60107,1140.4282,489.82944,254.77464,1004.45276,481.5047,-346.12207,1170.7446,588.82135,37.123436,1006.4969,612.25354,-478.02545,1180.947,616.9349,9.08352,995.53046,648.16705,-543.635,1187.4866,617.4795,-66.77491,1017.05554,649.268,-572.7669,1179.0134,608.43884,-1.2257965,1021.5321,635.5882,-489.48978,1120.1053,589.7061,145.37686,1056.9393,594.54285,-144.57932,1130.9695,772.18036,165.42091,1072.5354,785.9865,-152.3549,1116.0225,934.8727,407.20657,1065.1063,946.6329,64.59587,1098.847,964.15216,418.84402,1047.6719,972.804,73.29173,1181.6252,979.65326,275.69797,1115.895,1002.03125,-132.16374\r\nScreenshot_2021-02-11 at 15.18.12.png,squats_up,619.9421,103.04678,52.7716,630.3715,94.28204,75.45261,634.7201,94.75839,75.53001,639.23975,95.128525,75.566956,617.5572,93.37632,81.61259,613.91986,92.71853,81.55829,610.1951,92.25824,81.2574,651.0572,100.90302,186.22397,610.8868,95.211975,208.87514,630.4113,115.95221,88.59514,615.7137,114.21038,95.190674,684.94977,152.49068,181.33566,589.42194,160.7512,251.01376,680.27954,73.75641,199.07741,556.23346,73.85376,271.0534,656.73773,92.99652,389.52612,607.5677,91.87905,451.02957,651.96954,94.08199,386.11444,618.03156,93.43474,451.51938,655.8692,105.89677,392.96,617.2843,107.16833,466.66226,655.5662,106.1291,389.6091,614.35315,108.13304,455.57123,675.08374,337.65158,-10.856357,605.08295,345.2721,11.088243,688.84625,487.30878,-43.558865,593.5557,486.33478,-42.140453,717.14636,629.96454,28.77889,574.6469,621.5274,78.00299,720.3483,651.8361,30.00209,581.9929,642.0493,80.48833,720.216,667.53906,-115.42429,550.2246,659.9188,-60.429737\nScreenshot_2021-02-11 at 15.04.20.png,squats_up,576.2453,95.92411,-302.7105,581.5376,87.02875,-282.5783,585.55066,86.724594,-282.57028,589.6882,86.33795,-282.6011,569.10504,88.375595,-284.9044,564.80066,88.8402,-284.84207,560.4952,89.38749,-284.85892,595.6445,93.921936,-158.96486,555.5996,97.50854,-163.70015,585.2264,108.27113,-256.13766,569.6866,109.64188,-257.84863,631.62006,165.45119,-76.74924,524.1876,166.80588,-91.44891,645.6294,240.66122,-59.353756,502.86703,240.06021,-42.584896,636.0687,298.9391,-248.8621,499.83328,309.29318,-145.6091,635.68134,321.45184,-298.66415,495.0596,331.96008,-175.47992,628.4794,316.3019,-330.80573,503.09183,332.0676,-219.72107,626.76263,307.8544,-267.81433,509.51108,323.37054,-165.27281,609.26855,315.22882,7.5341372,544.5381,317.11957,-7.365492,626.27026,436.53406,-13.4683895,532.96265,443.44852,-26.14881,643.54266,560.53986,91.44387,515.6818,561.315,92.318016,638.23486,580.4036,92.339294,519.0718,578.8864,95.01369,667.09985,594.37787,-57.273365,500.4018,599.0871,-56.568943\nframe__YArvGEk8c6c__0005236.jpg,squats_up,949.8621,203.30939,-128.91959,958.1606,192.36029,-96.14546,964.1659,193.62892,-96.09232,970.4613,194.69847,-96.05602,938.3819,189.69337,-112.19955,930.93243,188.8087,-112.16773,923.4249,188.03522,-112.476974,970.9116,207.78113,82.408775,906.8872,198.83186,-1.8729837,957.12427,226.7452,-63.498825,932.2014,223.23776,-87.824234,1003.6144,330.22058,199.69562,839.752,303.1051,-20.356565,1026.0061,453.88498,281.44635,804.2133,422.46414,-78.61867,1045.9231,578.99915,116.594574,807.66656,557.58936,-215.13046,1056.5266,619.0646,90.024414,798.7079,599.9608,-265.42957,1048.1365,622.58545,36.37525,815.1968,602.75354,-300.48315,1038.7362,607.68585,90.70744,824.6687,588.95685,-229.82312,973.02795,581.52527,90.30908,869.68274,577.1393,-89.58884,997.44806,786.94904,106.80742,838.7066,785.7984,-175.74817,998.263,980.52893,253.34184,783.7692,970.64276,-33.20922,983.88416,1015.383,254.55011,774.1809,996.3273,-34.186996,1048.6869,1028.9296,98.41538,787.7688,1032.9524,-225.52417\r\nframe__awBQVJ39sKM__0014404.jpg,squats_up,1375.187,511.16064,39.959335,1388.6593,478.1018,-38.422123,1392.5647,476.33264,-38.26802,1396.8777,474.3728,-38.271694,1391.9924,477.82892,85.356964,1397.6431,475.91525,85.06596,1403.4343,474.13367,84.68399,1439.7509,471.4979,-271.99677,1446.3754,470.36346,280.66525,1397.8306,534.79767,-30.282085,1400.2417,534.48413,130.1381,1523.8754,616.0374,-543.7932,1544.0475,635.4454,633.9268,1542.4901,869.6304,-468.11624,1579.9791,842.27313,769.28125,1451.1765,1018.2907,108.17304,1512.0118,978.94257,355.8652,1441.1559,1045.9243,102.08148,1499.8708,1009.23376,322.39185,1430.8588,1037.8042,113.46585,1491.5488,993.6215,244.53386,1443.7885,1022.8967,130.17966,1491.3857,979.3971,305.6182,1567.6499,1095.0288,-377.97644,1572.3187,1092.2397,377.78082,1535.6205,1488.3625,-195.51569,1538.2267,1468.5612,413.6622,1545.6161,1861.0654,121.264275,1546.3037,1821.81,698.90857,1591.5039,1914.8284,139.05252,1589.5875,1882.4158,710.7799,1394.7974,1950.6415,-64.761185,1399.2527,1906.3163,556.44226\r\nScreenshot_2021-02-11 at 14.51.31.png,squats_up,461.6983,101.60082,-447.56088,467.92194,92.31334,-425.931,472.56522,92.51397,-425.91827,477.33835,92.60431,-425.7974,453.56345,92.21715,-432.0586,448.3373,92.21464,-432.08228,443.12134,92.26591,-432.14426,481.10492,101.835205,-289.5569,434.59125,101.19241,-314.2092,469.40405,116.386765,-395.96042,451.16214,116.05261,-403.1344,508.9846,176.60771,-179.8098,400.02118,172.7305,-215.46074,523.7196,260.93146,-128.56421,389.4788,256.52448,-183.77965,534.56903,335.67633,-204.04465,370.925,331.7099,-259.5765,542.37396,355.79083,-223.70619,362.20087,353.34106,-277.46967,538.4215,357.73975,-264.33316,363.46887,354.6267,-322.67844,532.23285,351.95737,-223.23445,371.56213,347.5497,-278.99683,488.99924,320.48685,18.77582,420.74503,322.44434,-18.763876,520.3129,439.08334,28.938951,396.19846,448.818,-20.548704,537.5004,550.77716,168.2996,373.49115,559.44165,113.52924,529.1994,571.5865,173.21867,379.29965,579.31525,118.24282,571.8664,582.405,43.941853,343.11713,591.57245,-21.743326\nframe__dxA21IeBB8o__0005778.jpg,squats_up,1812.8892,428.46738,-1254.5891,1830.3763,396.0521,-1194.8054,1843.131,395.24188,-1194.7874,1856.4359,394.11432,-1194.7034,1786.6503,397.5265,-1200.8344,1771.9224,397.2818,-1200.382,1757.286,397.24826,-1200.05,1868.1656,406.13907,-730.5766,1730.0898,409.0,-746.50726,1833.1411,462.32495,-1074.702,1783.6803,463.25262,-1080.2164,1966.1724,611.1256,-359.11133,1625.1216,617.15234,-306.07697,2038.2369,845.14276,-191.38585,1587.6045,856.03143,-100.41592,2111.8914,1066.9944,-635.7165,1504.9762,1075.5442,-532.7576,2148.4329,1121.0789,-731.5855,1471.3169,1133.0203,-611.5766,2138.319,1131.9453,-881.1272,1474.4924,1141.1344,-790.59155,2114.854,1118.823,-702.5514,1503.8232,1124.356,-610.06665,1898.7682,1072.4122,9.046142,1687.3418,1076.4231,-8.871579,1987.5858,1480.7295,-13.904834,1622.2406,1472.0983,-52.40789,2031.8134,1821.3354,625.1248,1547.8081,1824.0312,440.2198,2011.22,1869.79,658.97595,1556.1896,1877.6628,462.6857,2083.4358,1941.9637,151.0816,1497.6777,1942.4081,-65.64114\r\nframe__7Pcqgk2hB9g__0007118.jpg,squats_up,967.3378,158.7681,-632.2921,978.68176,143.67863,-606.05475,985.3673,143.55775,-606.04675,992.37555,143.25713,-605.9697,957.06464,144.16315,-603.89325,950.0924,144.10904,-603.7464,943.1581,144.15906,-603.5744,1002.4665,151.66422,-399.85626,934.52313,151.84764,-377.76697,980.23267,178.04977,-553.5104,955.51886,178.0558,-547.51355,1058.4515,272.66626,-239.14922,874.7239,265.46762,-203.22557,1088.1951,419.49103,-177.60257,834.2301,401.53674,-125.53745,1120.2476,553.4005,-347.32425,793.8491,530.7862,-296.45905,1138.8456,586.55743,-391.15567,774.7444,565.1312,-323.12485,1127.8691,591.3349,-461.94803,781.0405,573.91296,-412.7638,1115.2318,580.9505,-377.63983,799.7694,564.41956,-334.89935,1013.6285,525.3968,-1.3875762,896.95404,526.25793,1.220539,1050.3757,750.0949,-54.8068,861.9577,746.2821,-38.993904,1083.4464,958.59143,165.16876,822.90393,944.62866,196.18991,1079.5404,985.19116,173.11786,825.5285,971.17487,206.65288,1093.5988,1029.3723,-94.9405,807.6338,1013.1646,-54.475334\r\nScreenshot_2021-02-11 at 14.40.35.png,squats_up,375.79242,106.01822,-351.97318,383.8461,95.60693,-330.39584,388.55878,95.51295,-330.4889,393.4208,95.2827,-330.44226,369.62817,96.302284,-327.8428,364.82666,96.51928,-327.75256,359.99194,96.79107,-327.68445,401.1643,103.3039,-194.8405,354.78345,104.544495,-184.6356,385.5249,120.354965,-301.65976,367.34323,120.89976,-298.55142,440.79984,183.39136,-107.13151,320.6651,187.82967,-75.84028,490.07953,270.0104,-60.936848,266.49033,273.59384,-76.13751,471.1328,355.0718,-169.37627,296.5164,346.33932,-216.71295,469.50916,381.16565,-213.4049,306.56958,371.38235,-259.55844,454.28488,376.77493,-238.29196,317.11462,360.17575,-280.53104,452.49713,367.50198,-180.71721,315.00638,351.39682,-227.44821,421.7243,369.56985,-3.570702,343.99982,370.44797,3.6246088,472.21988,505.68323,-0.5475845,280.06302,498.931,-25.11926,520.823,629.32623,163.63518,224.46507,620.06775,131.22664,518.12286,650.325,171.8034,228.0025,639.7399,137.87978,552.8506,663.54156,18.142647,185.4152,657.18085,-16.781796\nScreenshot_2021-02-11 at 15.22.09.png,squats_up,673.94025,167.7666,-282.3399,680.7293,162.22913,-262.47922,684.2585,162.72032,-262.5368,687.877,163.11224,-262.53925,669.9444,161.85535,-262.77557,666.3888,161.75807,-262.6445,662.80164,161.74448,-262.62997,693.24695,172.00084,-151.91562,658.79663,170.08261,-150.93854,680.70776,180.9895,-241.61891,667.2502,180.04858,-241.31018,721.5011,235.85315,-92.42645,631.39685,236.87457,-80.60779,739.7459,302.53574,-65.97245,618.9464,300.8586,-51.61465,744.6112,370.36084,-146.46866,615.97974,364.53265,-149.64233,751.1249,389.8953,-172.17242,610.399,385.27356,-179.82768,742.0584,394.2732,-202.06175,618.028,388.05087,-214.60182,737.46094,387.00677,-159.91344,623.2516,381.37677,-166.89714,709.5114,370.3793,-5.281388,651.8915,373.07492,5.3450108,730.63043,466.6358,-59.71388,620.8911,458.36682,-173.02931,746.45056,556.413,78.10698,612.2669,562.0641,-86.98872,745.02496,567.4611,83.37107,618.3256,575.6681,-85.95094,750.4404,592.58264,-54.212914,593.8079,597.7059,-232.07927\nframe__wYUHrvWLy7U__0001152.jpg,squats_up,925.76117,171.29945,-207.52054,936.8232,149.68314,-165.577,943.86426,148.73755,-165.35919,951.1863,147.74329,-165.32935,914.8671,152.03539,-167.47728,907.332,152.27727,-167.44676,899.7305,152.79121,-167.91982,961.1912,154.75084,62.54116,891.4147,159.97371,46.202415,940.3869,188.84935,-126.615616,913.47144,191.30698,-130.43343,1008.5288,250.69048,177.18597,848.61896,265.17676,151.53743,1117.9987,173.54437,97.23298,742.6038,164.56998,135.50847,1006.40576,142.37709,184.86142,860.6897,134.73975,394.15073,979.5052,124.856,167.25784,889.4211,120.257095,407.74356,978.65344,142.94775,218.69945,888.1144,140.293,451.9137,986.05273,155.70967,197.66898,881.1501,149.95317,410.2519,990.9809,526.2778,26.358238,884.37915,534.6809,-26.287014,1016.49207,752.853,9.81461,857.2895,751.6367,-78.4521,1040.262,948.0183,222.44122,833.6416,959.9896,119.43835,1033.0491,976.66833,231.3974,840.7517,990.282,124.757065,1069.2593,1001.8057,-4.481504,806.3142,1022.9768,-119.48127\r\nScreenshot_2021-02-11 at 15.54.35.png,squats_up,573.5909,67.9353,-101.16839,579.6176,58.277206,-75.442535,583.64496,58.09266,-75.388885,587.78064,57.861156,-75.49956,566.98254,59.01574,-77.53918,562.819,59.104,-77.48938,558.6389,59.29292,-77.66625,594.2902,63.50516,62.774563,553.60614,65.0587,51.46016,581.8391,79.22339,-51.277237,566.76733,79.94262,-54.106438,624.79614,120.01605,55.41215,526.37225,121.12711,65.04931,647.8564,129.45987,-200.50769,497.31482,138.20001,-178.68416,632.75665,78.04396,-437.15082,510.20563,78.734085,-435.00705,636.11346,63.5181,-494.31186,511.7968,64.04847,-492.10074,630.3913,62.080097,-482.2491,516.71106,59.12342,-490.39096,626.72705,69.01749,-442.48767,519.5196,66.42284,-441.56448,612.5848,294.29028,3.5662427,548.78174,292.9637,-3.5692353,636.2442,427.90714,-16.20774,531.5776,419.76465,-20.27374,636.5853,546.4716,134.25012,519.5905,541.14526,114.960365,624.55,565.63074,140.14427,527.5975,561.8757,118.49141,671.37915,577.2164,7.6448674,488.45084,572.0483,-17.79812\nScreenshot_2021-02-11_at_15.46.47.png,squats_up,1227.8442,211.31662,-547.9929,1240.4176,183.86612,-511.5757,1249.5319,182.18686,-511.63678,1258.8624,180.33273,-511.66165,1212.8138,187.46709,-510.4208,1203.5807,188.17218,-510.25146,1194.2665,188.94643,-510.36597,1275.0162,184.8181,-234.92853,1185.005,194.55464,-224.6724,1248.795,231.311,-439.98395,1216.2211,235.26831,-437.34204,1358.1179,316.90793,-2.309168,1120.4379,322.6773,-2.6223266,1405.8195,512.40564,-66.64175,1058.331,509.9472,-67.57615,1304.0829,520.1763,-543.44434,1203.4111,517.7229,-455.55646,1268.8855,535.60675,-663.4865,1254.2452,533.38306,-557.9851,1266.3389,501.69556,-682.89984,1254.6499,496.82166,-568.3421,1274.26,496.3578,-559.9466,1241.3494,491.00723,-463.38467,1309.2625,658.8065,6.713346,1165.467,663.9744,-6.502088,1334.588,943.13416,-44.743748,1122.9396,953.958,-70.37175,1369.2195,1194.3899,272.8717,1087.8956,1209.4231,258.2177,1361.0372,1230.3379,286.32913,1094.7944,1244.701,270.36356,1399.3754,1274.3713,-30.505548,1060.7108,1298.2457,-47.418255\nScreenshot_2021-02-11 at 15.00.25.png,squats_up,661.92523,57.32289,-109.19583,669.3595,48.177094,-75.680504,674.18634,48.798462,-75.54466,679.1312,49.315765,-75.57888,653.3186,47.26655,-81.01749,647.71765,47.015343,-81.06285,642.10956,46.835938,-81.05486,683.44244,59.274612,83.97329,632.3101,56.127655,55.54592,669.50446,74.95162,-53.784687,650.71436,73.72676,-62.250927,717.3541,144.9515,70.70028,589.9245,143.86697,74.90796,719.0983,198.19875,-191.05125,606.13727,220.60074,-132.28917,682.57526,118.75184,-344.58194,641.2718,136.68704,-296.68143,683.9094,90.9374,-402.1321,649.418,109.87372,-341.6123,683.67706,97.00569,-359.9549,638.17126,104.43666,-326.52356,678.3594,104.953476,-336.57263,640.54193,113.040085,-294.64474,698.2043,328.41623,8.832575,614.8144,331.65714,-8.776985,737.42053,478.51935,-25.074614,598.58734,485.45926,-44.425922,760.9835,618.4669,152.41194,571.61584,613.99927,157.74097,755.9294,634.38794,161.82413,569.20105,628.0762,169.89746,773.72797,667.3967,-12.276888,573.2277,663.4436,-8.970245\nScreenshot_2021-02-11 at 14.37.55.png,squats_up,473.64676,77.29074,-308.25467,480.84384,67.44899,-286.91455,485.76767,67.27013,-286.95157,490.8867,67.008934,-286.9838,466.1454,68.58509,-285.5842,461.1414,69.08849,-285.52014,456.11115,69.659256,-285.42322,498.02103,76.33583,-167.62292,451.115,79.144394,-155.24022,484.00858,92.17095,-264.41415,465.37195,93.37142,-261.18896,529.7392,160.99936,-118.748825,416.39166,160.9008,-92.306526,519.8881,255.17447,-99.53098,414.11664,251.18513,-70.45228,501.65982,334.2755,-213.42041,426.79932,331.50616,-176.55637,502.77975,364.4101,-254.5267,425.58054,363.09073,-217.71056,487.99283,360.56628,-285.41217,438.17966,359.24863,-248.11511,485.0521,348.35703,-227.0199,441.76028,347.4228,-192.08537,502.00723,334.66257,-3.509929,426.5543,335.7604,3.7215314,544.4782,468.9431,-29.613869,392.7288,469.7603,-16.293034,571.9362,594.0811,130.19473,364.40878,590.3877,136.13838,568.65454,612.47565,138.96251,367.99112,609.585,142.59215,590.5289,637.0447,-11.269768,346.5263,632.0326,-14.034135\nframe__0-pvF5qUTos__0001642.jpg,squats_up,1054.848,146.60025,-381.38354,1070.6638,131.17165,-427.5913,1075.3109,130.81787,-427.59656,1080.0769,130.30247,-427.4447,1067.9554,132.2946,-375.04623,1069.7357,132.93408,-375.065,1071.3328,133.62448,-374.92877,1105.9379,141.89899,-484.9217,1093.3071,145.32617,-233.12965,1068.0725,166.2829,-395.75955,1063.2604,167.77614,-323.22604,1132.5531,254.20256,-546.01196,1084.2494,247.14212,-17.159893,1140.3875,403.5881,-556.89453,1090.4858,397.30322,52.52829,1113.7557,527.19403,-634.6928,1082.5076,516.32074,69.701065,1121.8713,559.9171,-724.08856,1086.2153,548.193,105.47107,1092.1079,558.73785,-730.8999,1076.8102,550.5024,51.061058,1088.7867,548.04596,-642.0551,1079.8984,541.2432,49.172234,1105.1965,508.0121,-170.79506,1076.3864,498.47174,171.1319,1110.0009,684.31537,-38.156204,1096.0215,679.1401,399.2668,1121.3743,863.4982,104.25493,1124.6493,825.9708,628.8381,1137.005,894.5021,103.784294,1138.3442,857.6841,650.13495,1044.1577,903.6793,-37.744816,1055.3872,852.029,611.6151\r\nframe__pE3P6Luw6DI__0003909.jpg,squats_up,973.5273,133.11182,-433.56027,981.3944,116.27801,-401.5339,986.9814,115.055435,-401.41827,992.7919,113.88758,-401.42172,964.9636,119.225235,-388.495,959.88556,119.77285,-388.17282,954.7868,120.47729,-388.4358,1005.95435,118.44291,-231.69511,952.7384,125.64103,-168.83969,987.5053,146.48058,-374.1137,968.4614,149.57344,-354.86377,1050.8452,197.14458,-358.5059,921.81464,192.04083,-148.48993,995.94293,190.07083,-796.94556,844.84094,162.5961,-608.07416,922.15784,133.43956,-1061.1398,868.9041,133.2145,-1098.1138,896.8749,120.68038,-1145.0021,870.74335,125.95723,-1216.4381,908.63715,111.88027,-1130.5094,885.6106,121.48611,-1200.895,917.45575,121.09707,-1061.7942,885.38873,127.58896,-1113.58,1005.62555,438.83127,-42.595955,912.08325,430.99146,42.355106,1022.68353,612.9722,-25.256138,880.6278,606.50323,32.659267,1054.7045,758.4542,248.27689,844.7267,762.4613,295.69028,1055.5347,773.93115,263.5757,846.1142,780.45795,306.8502,1043.8428,817.0195,29.525513,842.97876,825.5875,71.74478\r\nScreenshot_2021-02-11_at_15.52.18.png,squats_up,1326.4923,176.66832,-814.8191,1339.4497,158.88152,-786.2545,1348.2194,158.95059,-786.16003,1357.3403,158.78755,-786.0402,1311.5751,160.70734,-794.587,1301.997,161.53104,-794.4569,1292.4998,162.51833,-794.3153,1369.0416,177.81589,-535.7054,1278.0592,181.5153,-570.09454,1343.3551,206.97409,-715.68494,1309.6823,208.30144,-725.4333,1452.7825,339.70468,-313.70035,1198.5818,343.50287,-393.81357,1513.3837,512.43115,-188.04375,1162.2639,514.2035,-285.78046,1535.9048,680.5092,-420.8879,1162.5243,697.80096,-481.0095,1551.8234,731.60046,-491.5094,1150.999,754.69226,-533.7171,1532.1011,735.55914,-575.1233,1172.0581,758.63965,-636.259,1516.9174,718.5821,-458.61908,1189.0688,737.10956,-522.08997,1416.6403,678.2701,37.969364,1265.6665,693.4313,-37.994823,1472.4337,952.5122,30.794502,1243.4772,979.2897,-101.01719,1490.1333,1225.0792,261.67535,1188.8464,1235.1847,150.27788,1472.255,1269.2488,268.55975,1195.1669,1270.1583,157.54935,1551.5132,1301.5106,9.515903,1147.294,1324.7352,-127.25847\nScreenshot_2021-02-11 at 14.26.03.png,squats_up,598.4763,62.27053,-334.27884,606.65985,49.600895,-313.4077,612.1309,49.33447,-313.5164,617.70386,48.969707,-313.62823,591.29865,50.95322,-312.08893,585.9028,51.498726,-312.02838,580.4504,52.1071,-312.12418,626.7809,58.390293,-177.83296,575.34705,61.462864,-165.93094,610.2059,78.421265,-282.70322,590.3353,79.83956,-279.42798,669.37354,149.53123,-91.68993,540.13556,149.2393,-49.54231,701.5191,262.03937,-128.32962,512.0701,251.8044,-104.72429,632.5501,246.7795,-323.7516,577.7785,243.19157,-330.6426,607.811,250.78358,-374.91934,601.3936,248.86555,-385.37842,606.4036,228.47505,-376.51306,603.3491,226.87639,-389.936,612.3394,228.53407,-326.5354,598.00793,226.58585,-335.9323,641.77356,349.52145,-17.299479,562.1514,353.3912,17.51474,679.36346,498.54437,-35.3387,538.6035,502.00223,44.057438,706.3026,645.0326,127.244514,515.555,633.19147,243.48575,706.1363,665.37744,134.33667,518.8514,652.2083,253.04254,713.5822,693.54144,-22.569605,500.04248,680.8049,101.367165\nframe__-nXY1rQt1bI__0003405.jpg,squats_up,928.24896,305.52402,-914.8174,940.1572,293.2431,-871.3927,946.07764,293.08563,-871.3161,952.20087,292.86285,-871.09235,922.64343,295.94012,-869.7868,916.6815,296.76077,-869.6229,910.9001,297.9088,-869.8813,965.18176,305.824,-626.0683,910.70184,310.98694,-624.02875,942.9151,321.71387,-827.29724,920.91974,323.91782,-825.6724,1002.87256,369.60858,-528.86554,881.4253,374.06143,-556.04034,1021.4422,245.7933,-602.8477,856.5267,250.56334,-643.53876,1010.07947,128.11769,-735.2094,854.1578,139.66302,-743.7926,1009.4941,110.55872,-825.94183,860.615,117.07279,-829.8649,989.5957,97.44739,-835.09436,867.7898,104.661415,-834.9368,988.2907,101.95141,-752.6314,868.42316,111.45219,-757.9784,979.1542,588.2784,-3.3798366,898.12274,592.81537,3.7703183,995.76575,763.1029,107.31871,897.4695,773.56824,116.681526,1008.59015,913.3671,460.53696,884.0968,922.63513,470.71814,998.9196,930.9558,479.00757,887.5182,938.9272,492.76913,1029.4551,979.6246,199.53574,888.4419,988.2959,213.86052\r\nScreenshot_2021-02-11 at 14.57.43.png,squats_up,500.3585,128.10275,-399.18872,507.44403,119.011185,-384.4641,511.28296,119.09255,-384.45206,515.2791,119.049805,-384.36755,494.9861,119.03987,-386.77835,490.85614,118.8825,-386.69595,486.77164,118.77583,-386.62228,519.8949,124.29877,-260.27164,480.73273,123.1379,-267.4585,506.53375,139.89705,-351.21674,492.39545,139.39874,-353.56238,548.1458,187.42195,-165.95738,446.64233,193.79631,-164.53256,564.1907,265.52234,-142.49748,434.59833,274.70102,-142.50945,579.44055,342.53513,-250.91168,415.15372,345.2354,-247.22055,590.27783,363.22864,-277.8779,404.83264,364.51678,-270.8324,582.3605,367.34247,-317.7512,410.26398,367.0162,-317.05542,575.19977,361.3269,-268.33807,419.94385,360.57413,-267.53702,533.0745,336.08218,4.566739,467.13806,340.4652,-4.702118,573.6237,461.83978,2.0018828,427.36826,462.56766,-27.82883,607.3846,577.7792,107.65328,395.71475,578.2046,67.97869,604.4983,597.2286,110.01998,403.20056,597.5891,69.369675,632.1944,609.1722,-27.94436,358.40704,611.25616,-70.8392\nframe__akB8RpULI7U__0007437.jpg,squats_up,997.1356,130.64384,-467.88748,1005.59796,113.8413,-431.99982,1012.49945,113.33211,-432.03253,1019.58344,112.71706,-431.9552,985.2789,115.24389,-434.82584,978.0742,115.670975,-434.77283,970.77655,116.14772,-435.1844,1028.2279,123.06428,-216.78252,961.07965,126.87777,-223.42876,1011.1449,150.20839,-387.80234,984.39984,151.84416,-389.3943,1071.0742,240.69247,-49.302628,906.3842,236.27051,-91.85874,1095.0981,363.2281,-132.47813,847.51526,364.85852,-191.00157,1087.2373,377.2908,-608.7971,901.9256,385.89575,-563.63245,1082.8069,391.95947,-718.9642,920.98804,404.9041,-666.7528,1076.9651,368.4235,-752.25964,932.96844,380.2482,-684.2722,1074.3745,364.0466,-633.6453,931.53595,373.88177,-577.3482,1018.91864,511.08014,18.567928,918.08075,507.0941,-18.154953,1027.97,712.1725,45.687737,893.8021,708.1666,14.822438,1039.2151,894.866,337.99472,871.2699,884.1685,344.5431,1030.2849,917.1478,349.99423,871.81366,902.5424,359.03436,1060.8435,960.91187,91.22209,875.58716,958.8053,103.01715\r\nframe__jPO_jp4Sb00__0009448.jpg,squats_up,928.6191,124.28666,223.25641,921.04926,104.56779,148.78879,913.07764,104.621506,149.2456,905.4294,104.60062,149.40067,944.14026,104.648636,162.81152,952.38104,104.028885,162.61147,960.55286,103.51467,163.08852,900.8703,117.320145,-100.015526,976.39343,114.89821,-37.569435,919.77045,142.66966,146.27098,942.8439,141.0494,162.13135,839.23645,232.14803,-278.62854,1046.6794,229.64449,-130.5125,791.4373,391.09286,-388.83685,1111.5803,387.26315,-264.7327,809.7041,536.4745,-425.23587,1098.7683,538.50775,-328.92426,817.7199,582.41724,-444.74344,1098.6597,587.0555,-335.30502,825.7905,576.68835,-444.4196,1088.5721,578.7044,-347.82565,824.5073,558.9258,-421.91827,1081.9464,560.2026,-330.04434,885.08594,542.30896,-32.09637,999.40485,536.1128,32.92549,853.2125,762.09784,106.59651,1033.1385,762.2773,264.5978,831.63336,996.582,135.60185,1063.5223,1000.9368,346.29532,843.3517,1039.3693,132.70227,1065.9524,1045.6182,350.24246,787.61487,1006.7026,116.63209,1063.4628,1024.7278,345.6038\r\nScreenshot_2021-02-11 at 14.51.54.png,squats_up,479.59018,94.46867,-289.0909,486.34848,85.73904,-270.3953,490.53183,86.31409,-270.2844,494.80106,86.79646,-270.35022,473.10086,84.85278,-274.9211,468.55334,84.48183,-274.9818,463.98132,84.215836,-275.09085,498.2277,94.19715,-155.36707,456.24152,90.72305,-168.01962,486.11615,108.908394,-244.20189,469.87527,107.38603,-247.81866,526.87744,165.95316,-59.468586,421.77444,167.11597,-92.43445,540.1514,250.17018,67.216324,410.10446,252.72562,47.634167,543.0595,326.4598,145.79012,411.83163,330.3595,161.88484,547.288,349.26187,160.29814,406.76248,352.85352,195.82953,544.28033,350.75342,136.63931,412.0721,351.3029,165.67006,539.0181,343.12567,137.4084,417.9316,342.83246,156.0856,518.6479,331.2987,7.170067,451.7407,338.09827,-7.0593233,537.7857,456.3433,0.8356864,444.06152,467.39914,4.5493546,549.0718,576.7277,148.58163,427.66727,587.6505,158.07051,545.8106,593.5342,153.55019,429.4599,604.2339,164.56514,551.55096,615.2098,28.166712,416.26355,625.17365,35.630493\nframe__-VS6jgTTYAQ__0001855.jpg,squats_up,860.2868,245.47462,119.29636,866.89716,225.93735,115.65805,871.9074,223.83253,115.70569,877.1639,221.59486,115.43798,854.5163,229.33138,161.3677,852.0322,229.22278,161.42996,849.58136,229.43878,161.31798,897.77576,211.01807,149.67368,861.05695,218.80347,347.84796,878.37775,251.66068,134.42589,867.0991,254.90028,191.45886,974.0634,256.42273,77.376335,860.526,284.8904,474.39398,938.6099,241.41113,-11.555533,776.2732,256.76938,604.9856,903.2438,167.46437,256.0251,824.19727,177.60959,738.35297,899.91925,135.80096,251.9598,839.41974,154.72157,736.1935,905.1795,146.32202,274.7397,844.5336,153.20552,748.5073,900.4764,160.94342,267.87683,841.63763,163.46661,738.7636,963.51526,527.9291,-139.00708,890.8748,542.414,138.68027,963.7704,749.3862,-198.06067,876.66187,751.731,74.30903,973.7605,955.84155,-148.42775,867.4359,944.1925,245.26483,989.4659,986.1937,-150.4263,889.60724,980.64874,250.56284,914.4386,1013.5883,-325.56863,777.2228,991.5321,100.98805\r\nScreenshot_2021-02-11 at 15.21.02.png,squats_up,601.10144,84.84806,-138.93065,610.3102,75.29588,-113.25892,615.00934,75.65014,-113.15214,619.82025,75.92263,-113.17432,595.9718,74.93882,-114.254135,591.43604,74.819374,-114.24459,586.87994,74.77218,-114.36836,627.9626,84.06744,24.765257,582.3614,82.06696,17.959408,610.2851,99.80868,-89.046326,593.48456,99.223,-91.00469,664.58484,161.89241,48.395813,548.9913,162.3397,42.04125,662.0502,225.51656,-137.74944,563.4882,238.19164,-162.45848,619.2428,151.01654,-284.66284,601.4574,152.86661,-332.71088,613.97925,129.81982,-338.33655,613.1264,128.34769,-378.29697,613.6807,125.82064,-307.24405,602.4305,121.09657,-364.71857,611.31213,131.18365,-277.73166,603.1021,129.87454,-331.01706,649.18274,339.3402,2.9776568,576.0999,341.88065,-2.7994313,668.2021,478.00983,-28.554129,564.9512,480.4999,-20.918884,679.43164,603.2761,166.02393,551.4368,601.01526,188.44536,676.0318,617.60516,177.65044,552.21277,614.9458,200.98831,682.7515,645.76025,15.508164,549.38794,644.39325,37.16461\nScreenshot_2021-02-11 at 15.56.43.png,squats_up,622.36176,79.40271,-215.08482,630.5956,67.50447,-199.57973,635.94104,66.77858,-199.52365,641.4982,65.96939,-199.60313,615.4552,69.728455,-190.31686,610.7037,70.43735,-190.20302,605.9252,71.2603,-190.10419,654.5207,72.93949,-88.21003,606.15375,79.26591,-38.82098,636.9817,93.145325,-172.49907,618.42505,95.68919,-158.435,710.9179,155.29953,-24.529366,577.5087,159.69873,50.4952,754.8764,238.91112,-36.740295,562.811,246.68454,124.17714,737.9873,307.78702,-230.35974,553.3631,317.294,-38.481678,739.09076,337.193,-281.64758,548.91956,344.03247,-70.96967,720.4634,329.80133,-312.86475,552.331,342.69156,-121.671616,717.8503,319.65723,-244.46266,560.84784,333.478,-61.5387,679.505,354.9055,-7.3991866,597.5883,354.8833,7.708777,695.3324,506.73386,-46.540432,581.76794,508.79437,-11.556119,704.31177,640.19073,136.17657,562.7882,637.44543,164.70604,696.6418,658.92584,145.55833,566.9204,655.94885,172.14009,723.7198,689.1967,-23.345098,552.34686,686.8926,2.270194\nframe__4qz94HJYjdk__0003933.jpg,squats_up,932.7152,234.39551,-398.70267,940.7271,222.0949,-355.2641,945.9325,221.87953,-355.00613,951.2614,221.64084,-354.86255,924.35376,223.22456,-352.0366,918.9125,223.40436,-351.83444,913.398,223.74168,-351.82684,957.675,231.8213,-131.85257,904.3346,233.63243,-112.63195,942.69025,250.15306,-318.96002,922.1951,250.86191,-313.54523,999.6666,312.86295,-89.68506,867.6218,324.53748,-27.580633,1087.3685,367.21426,-489.07596,791.6882,362.724,-418.13852,970.8532,355.27127,-835.27905,906.633,338.18872,-779.63586,938.53925,357.30658,-908.99054,936.94904,332.63538,-872.032,933.8574,345.198,-871.6608,942.5758,330.1664,-824.2915,946.7853,351.70428,-822.4763,934.3897,337.16727,-771.10626,990.4349,539.58905,-26.647003,909.07336,544.6475,26.883154,990.2435,740.04095,-19.43177,923.0489,734.4738,67.57446,998.94574,894.1377,352.89893,929.9871,893.90533,415.30328,998.3529,908.46515,376.37277,934.6161,910.84314,435.06018,987.498,959.88043,133.00467,933.1775,960.715,184.43332\r\nScreenshot_2021-02-11 at 15.51.30.png,squats_up,218.81664,106.872444,-298.01315,226.39526,94.54889,-279.23218,231.5766,94.594986,-279.3155,236.85332,94.548965,-279.26855,212.03455,94.4931,-281.73337,206.53293,94.31189,-281.6325,200.9726,94.21881,-281.68723,243.3831,102.05829,-149.92975,192.87627,100.939415,-157.22632,227.96329,121.133354,-247.77538,208.49892,120.6357,-250.02307,275.55396,172.74362,-60.775917,152.19868,171.16336,-57.177094,303.62943,265.4178,-94.55021,116.120995,260.0081,-73.84641,243.21011,268.38492,-303.16666,179.22142,277.2616,-235.49207,220.5727,280.5207,-347.84177,201.20753,291.7152,-271.89987,218.44125,259.19632,-358.31638,206.15875,272.3492,-285.59894,222.63498,256.48718,-309.0938,202.22952,267.90433,-240.54597,243.85638,361.2364,-1.3006594,174.04312,361.6264,1.5863603,247.4404,496.17017,17.95235,167.88919,493.91125,32.38799,243.2207,612.8663,170.84627,173.18886,610.3747,205.99211,232.76033,630.715,178.25127,186.0812,628.689,214.80115,272.03564,660.5185,60.49372,133.12358,660.4888,90.25386\nScreenshot_2021-02-11 at 14.50.12.png,squats_up,402.01556,103.187065,-319.49142,407.86328,93.89532,-294.58975,412.22525,94.07272,-294.6366,416.69968,94.17838,-294.64566,393.8338,93.684364,-303.22275,388.7887,93.59058,-303.2028,383.72098,93.564896,-303.32947,419.56058,102.35781,-152.6907,374.57037,101.38654,-188.89224,408.84946,117.45341,-265.0712,391.42032,117.003365,-276.13818,446.28995,178.2635,-89.59528,338.20227,177.90205,-119.54844,428.16867,251.18817,-83.031075,333.89142,270.09018,-97.22747,392.10684,287.22888,-195.94202,341.08554,355.3647,-160.43398,383.9993,301.9207,-237.9394,336.4319,382.0433,-186.45328,382.80905,297.68964,-261.62915,345.00787,381.7499,-221.91815,384.1911,292.13498,-212.1885,349.70932,370.70468,-175.60141,430.17615,343.43527,14.683135,362.0303,344.07953,-14.503572,455.98077,464.5257,18.412733,341.52057,465.91855,-38.25217,461.40485,572.27515,186.56915,340.11642,578.2396,120.58119,451.21082,590.9269,193.67018,348.70667,595.5119,126.38844,493.15375,611.57166,62.992588,315.11414,620.43115,-17.526249\nScreenshot_2021-02-11 at 14.37.38.png,squats_up,388.54376,91.177956,-367.86603,394.7766,81.13645,-350.4652,399.4136,80.79434,-350.46173,404.2088,80.347015,-350.4266,381.02158,82.64126,-351.3947,376.20724,83.206024,-351.35803,371.37683,83.859314,-351.3181,411.0176,88.51506,-232.7425,366.54446,92.561104,-232.11304,398.44778,105.02895,-322.94257,381.1362,106.692856,-322.95105,444.01938,166.17807,-165.72693,336.66165,168.7671,-156.44995,441.02094,254.75339,-140.5964,335.04498,251.84602,-133.38634,425.74048,331.8699,-237.95859,348.8217,329.8533,-232.4884,428.12424,359.9334,-273.79388,346.8535,359.81137,-271.7624,414.5266,358.3556,-305.94785,360.37024,357.09918,-303.28848,410.65558,347.65686,-252.24745,364.41336,346.19913,-247.61256,421.3398,334.58386,1.6225278,351.934,336.81876,-1.5653898,465.24658,456.4159,-17.785069,319.01447,458.3942,1.0135067,487.87863,575.6611,118.75495,295.92862,570.11646,146.47136,481.18002,596.63434,125.21963,303.1086,590.2839,152.26274,520.0187,611.2593,-10.781247,267.15164,607.0459,11.755249\nScreenshot_2021-02-11 at 15.12.09.png,squats_up,655.8414,223.02516,-66.538635,659.72754,213.70076,-37.768974,663.5594,213.11429,-37.722664,667.56274,212.49867,-37.747787,647.35266,215.7775,-39.65941,643.10596,216.36148,-39.554333,638.8937,217.1196,-39.68983,672.3966,216.70215,87.85597,633.66187,223.22299,80.20484,664.5737,232.34573,-22.644228,649.7036,234.73216,-24.74309,698.4091,262.86328,99.48192,617.4852,263.90097,109.30073,721.4711,186.67564,57.980804,608.73944,191.33849,72.151726,701.91614,127.63509,44.81089,616.81683,123.217064,81.77684,697.552,113.423904,1.0782579,620.511,106.78209,53.23802,691.5034,110.912,20.026882,624.26794,104.27543,55.949673,691.87885,114.6725,42.638123,624.85376,109.2429,77.92278,689.13226,421.4391,-13.427634,631.0337,419.9367,13.800246,706.1101,544.29565,-43.676888,615.99646,542.7202,-2.8166103,723.98376,649.368,117.84058,614.03656,655.7337,140.50427,721.26044,664.7559,124.324295,621.8659,670.204,144.3008,740.78534,684.4376,-29.561901,597.9572,697.96747,-9.270151\nframe__-nXY1rQt1bI__0017935.jpg,squats_up,955.88696,301.0306,-392.994,965.2479,287.39682,-364.63373,970.80725,287.1957,-364.51202,976.4749,286.89145,-364.46802,948.4228,288.16827,-363.10083,943.1263,288.28085,-362.86536,937.78204,288.469,-362.91037,986.9752,294.32806,-158.27026,933.834,295.81494,-155.27664,968.4113,316.03488,-314.5817,948.29724,316.63657,-314.12198,1029.3923,384.71826,8.93922,897.1262,388.65924,-6.1832323,1034.4049,486.29172,-51.472717,872.58734,500.89746,-97.57393,1053.6309,491.48502,-507.14978,906.1533,492.31918,-502.8698,1062.4521,498.3495,-618.56116,919.22144,494.03934,-608.8268,1060.302,485.33432,-656.5134,921.1938,476.44794,-631.0332,1053.9926,480.40753,-537.34326,920.42957,473.1759,-522.32104,1009.90656,600.36536,6.702328,929.51605,602.2184,-6.2611938,1032.598,768.79004,-42.15229,912.1613,779.63617,-63.675236,1051.5344,932.88745,185.32536,892.525,935.0912,215.09244,1046.669,953.63477,193.72858,894.2286,951.68097,227.63622,1065.3915,987.28845,-43.931496,887.9426,997.4446,-8.476582\r\nScreenshot_2021-02-11_at_16.07.36.png,squats_up,1638.8329,142.49628,-686.5466,1649.6136,127.68663,-646.4605,1657.918,128.39948,-646.50494,1666.6003,128.90878,-646.46454,1623.6477,127.72403,-656.3829,1614.0898,128.13873,-656.3111,1604.5604,128.67976,-656.2712,1672.6946,150.86081,-409.12048,1587.3872,149.42609,-455.48856,1652.3073,174.3369,-597.41394,1618.7777,173.94841,-610.21704,1739.7917,312.29266,-227.83763,1506.8018,314.54932,-329.8779,1826.4094,483.00568,-112.442726,1453.5508,492.0249,-314.69382,1844.959,644.5978,-336.0191,1466.6906,653.44275,-485.81696,1857.2563,695.7669,-408.13892,1460.7185,704.45874,-549.4676,1829.7128,693.98865,-474.94705,1484.3406,703.9622,-611.8272,1816.453,676.85486,-367.9622,1495.337,684.8832,-513.8196,1698.8308,644.57605,43.455017,1560.2383,649.96924,-43.432014,1741.3768,900.097,70.01635,1535.8394,916.45776,-62.899887,1752.8162,1148.3706,284.96152,1501.5105,1150.8198,195.6532,1731.5381,1188.0707,291.19955,1505.2391,1182.5585,201.84113,1827.9059,1224.2673,45.219795,1491.5758,1235.1495,-75.78646\nScreenshot_2021-02-11_at_16.11.24.png,squats_up,1438.8673,218.37814,-1010.26025,1449.5026,193.29066,-976.0924,1458.2953,191.99178,-975.9892,1467.3995,190.45712,-975.7555,1422.6638,196.62318,-978.604,1412.9646,197.31818,-978.37115,1403.2805,198.24724,-978.06305,1479.794,198.94089,-707.8921,1391.1628,208.31624,-698.42096,1457.2732,240.2962,-906.8612,1424.0886,243.4742,-904.04095,1562.7064,336.6732,-496.27814,1328.0731,345.88614,-449.58737,1592.456,508.8162,-397.82236,1301.626,518.8198,-342.52988,1600.2222,671.5382,-617.0469,1286.879,683.56604,-526.8935,1613.413,716.0319,-688.9017,1274.6962,730.7292,-561.8147,1594.4797,721.74316,-769.7983,1287.3118,741.34705,-666.9238,1580.2762,705.7231,-650.8536,1308.1566,723.6734,-570.3236,1516.976,664.3112,-13.513897,1379.7938,664.7214,13.013292,1542.7894,922.07166,44.369473,1338.9493,903.8574,99.73153,1576.1256,1115.7472,430.52057,1309.2821,1098.4128,530.8254,1567.3744,1142.652,454.87848,1322.979,1125.0623,560.09515,1614.3751,1204.7544,175.73326,1265.1987,1197.4727,278.4946\nframe__GauW8uJtvFs__0022189.jpg,squats_up,1013.14465,173.54553,-882.358,1025.8253,149.55287,-873.68866,1034.1034,148.1235,-873.8775,1042.5999,146.48009,-873.81824,1004.34656,153.15451,-854.5049,997.0658,154.13237,-854.2886,989.7324,155.2579,-853.9729,1061.3717,153.33833,-731.0994,990.13446,163.63216,-623.60815,1034.0414,192.19675,-824.1765,1005.9698,196.01378,-792.60156,1138.4353,276.97116,-626.85126,945.1586,276.90097,-389.8977,1158.7911,443.71973,-621.5673,915.1603,424.48755,-308.8002,1075.9694,540.2647,-780.7043,929.91315,542.53204,-506.04544,1055.9032,574.67914,-879.0478,934.73987,585.5846,-570.53986,1033.715,563.2109,-897.221,947.116,572.38556,-626.7973,1035.4381,547.7102,-790.7013,952.51886,552.7022,-532.7839,1081.7253,535.48193,-82.68294,978.49786,532.3324,82.61787,1128.2823,747.0431,-69.74788,930.8062,731.60474,303.8212,1149.2048,924.5457,174.39952,881.65533,879.6485,716.7749,1152.2222,949.5831,187.19238,889.47595,911.5558,748.764,1134.1714,995.4148,-19.62334,819.41,933.24097,586.1995\r\nframe__yWky9j7mG2Y__0006408.jpg,squats_up,1003.4835,138.17027,-366.48007,995.34186,119.194496,-352.1285,996.0393,118.615074,-352.01614,997.0666,118.0642,-352.0163,986.93964,122.797485,-402.69904,981.0292,123.795105,-402.6848,975.2567,124.87473,-402.5439,981.4911,132.44324,-223.25296,955.9091,140.7591,-450.19077,1002.90436,162.12338,-310.00217,990.93463,165.3214,-376.05365,951.54346,254.18086,56.895237,946.2257,268.73367,-560.5082,935.3835,416.4717,139.28647,945.59503,427.2303,-559.2439,962.1754,569.34985,85.036514,972.1319,593.484,-567.0955,969.18225,600.7808,106.75024,963.35254,631.6455,-661.0762,976.2807,607.93146,37.939953,989.98956,640.1003,-644.37085,970.38403,600.99554,56.77897,986.61005,630.2309,-561.9813,883.2425,499.78595,195.86758,874.6836,515.17,-194.68501,941.95197,705.6314,319.94937,929.9975,725.836,-190.69606,930.4296,895.52484,521.4308,901.3276,951.4038,-129.3221,902.98956,933.1463,532.3596,867.40424,995.37415,-138.94943,1031.4888,939.987,449.90076,1005.50574,997.2927,-298.94006\r\nframe__hkfSvagHBdk__0004512.jpg,squats_up,683.4652,173.42848,-348.52234,687.9979,163.83632,-324.83475,691.7901,163.57513,-324.8268,695.6836,163.21288,-324.79663,675.7202,164.88919,-327.08008,671.3758,165.18939,-326.97858,667.0179,165.56174,-326.9315,699.0957,170.07639,-181.47214,659.8309,172.76443,-189.41429,690.56165,185.22845,-294.86108,674.84143,186.32332,-297.08102,729.8066,239.81107,-65.05113,624.4863,239.07855,-96.09275,775.8944,296.01385,-6.0628743,564.69196,292.079,-51.23463,750.5964,352.65994,-148.86539,607.5251,354.61215,-166.87796,745.4633,370.8323,-198.78088,617.18494,370.91483,-210.54582,736.10547,367.6708,-223.47948,627.5089,363.13522,-227.15735,736.38275,361.209,-163.50752,623.57855,356.61206,-175.9833,704.69916,389.77957,8.836884,642.1454,391.10757,-8.690289,718.10535,513.76605,-9.375374,633.8752,516.62537,-9.501027,738.02344,631.0564,145.90756,623.8296,625.29,193.60054,735.4249,646.1204,152.81027,625.9185,638.77234,204.93509,743.9662,668.6796,-18.232616,616.9101,665.49817,38.716057\r\nframe__YP1pmz6XYLc__0004927.jpg,squats_up,1018.9924,187.73013,261.70642,1009.7928,175.175,204.89629,1004.39746,175.19647,205.10452,999.19464,175.22557,204.9466,1023.96277,175.21768,206.22261,1029.2277,175.00139,206.42262,1034.2703,175.07047,206.29745,991.91296,183.66081,47.228985,1038.3645,182.48697,48.394604,1012.3136,200.36095,218.3405,1027.2643,200.3901,219.97206,940.0495,259.12604,35.613773,1100.7192,256.56262,54.0746,886.83356,322.64218,383.97925,1159.9705,322.02222,402.07428,941.12604,284.06955,880.83484,1102.6324,274.0567,904.4986,950.2161,272.47137,955.7025,1094.5934,261.40607,981.06433,962.51654,270.36157,942.01135,1080.6306,256.05164,980.1259,965.4762,277.21063,885.80164,1078.8436,262.99747,916.3934,994.8842,520.9613,-17.02817,1076.9916,516.9271,16.745749,974.4843,692.05023,66.87189,1097.8003,693.31775,82.851845,972.74634,878.053,-44.51475,1116.1473,876.00256,-8.194035,984.4376,911.36255,-54.667416,1116.304,908.93646,-19.699106,939.75397,902.1777,-41.359974,1128.8237,905.1751,-15.218615\r\nframe__f9hh9pzZA4s__0003193.jpg,squats_up,860.9393,214.50995,-143.4893,873.43225,195.41782,-189.1886,877.4672,193.85358,-189.03854,881.66724,192.12323,-188.83643,871.88275,197.02182,-131.03218,874.44275,196.76237,-131.14484,876.91797,196.53555,-131.1977,909.4193,194.59088,-266.36493,902.0203,199.13493,2.8891718,876.5856,230.64265,-165.68248,874.3216,231.98799,-88.07936,949.7045,286.43338,-377.2491,926.21063,305.8398,210.046,946.9725,433.18713,-429.17557,927.8064,450.027,258.07706,900.8498,559.6935,-468.36795,897.229,564.3499,233.09319,904.8194,596.58594,-545.7435,891.97546,595.66614,264.71274,878.54535,599.0329,-546.3856,884.6568,597.5452,216.07668,880.88165,587.23517,-470.00333,886.30084,586.7246,211.79073,950.27997,544.6312,-183.21965,929.73126,543.6571,183.2589,932.5096,762.69574,-168.77899,934.0098,743.8151,246.65804,967.55835,980.70605,-133.14938,954.9788,933.947,388.23294,990.4129,1018.52057,-143.77548,973.5142,971.43787,394.62695,874.63995,1030.4517,-328.66354,876.71234,976.5518,299.66583\r\nframe__FsqhUFcjL8k__0002257.jpg,squats_up,981.32983,237.35551,-283.466,985.60785,216.03845,-247.17696,992.56647,214.88141,-247.06114,999.7041,213.62552,-247.05768,965.97394,217.90125,-273.08798,957.9707,218.11719,-272.98535,950.0388,218.53142,-273.13397,1001.3593,219.5796,-34.008343,936.6942,226.9049,-150.05064,993.4704,253.9884,-202.47812,966.6718,256.8604,-235.48024,1012.8401,319.87207,188.49968,906.68054,321.33725,-215.34106,1028.7705,452.6447,22.64496,917.9142,471.98505,-202.92656,1046.3416,381.28415,-358.42816,1009.55383,391.70087,-45.627247,1058.1061,360.91086,-425.4615,1042.5406,378.7398,-58.267292,1057.5706,346.40967,-414.54013,1029.8021,352.045,-54.763645,1047.0112,351.06183,-367.39078,1018.1098,357.69833,-34.22961,968.5835,570.73535,156.33368,916.11694,574.88513,-156.24335,945.4692,759.60547,262.81528,927.321,778.011,-98.91634,920.081,905.6849,543.27496,918.05597,959.6669,20.492435,900.1518,931.3352,566.09033,890.4183,988.7067,28.37106,983.01544,958.5767,468.37344,992.90796,1024.2976,-131.2373\r\nframe__b-WgQRAneho__0007618.jpg,squats_up,1180.435,206.23582,-97.49822,1167.248,194.03517,-56.703133,1166.3274,194.37213,-56.79385,1165.8242,194.56422,-57.238525,1163.6158,194.55157,-114.734886,1159.7977,194.87473,-114.44493,1156.0197,195.58517,-114.664825,1153.3135,204.26009,111.79112,1137.6176,206.9072,-149.67747,1180.956,224.34856,-31.12695,1174.0135,226.26697,-104.75164,1155.0173,310.67743,316.44333,1154.9485,289.7068,-310.5796,1257.0332,242.59094,426.23596,1271.4124,238.99168,-386.6445,1188.6271,125.19193,453.31485,1192.3265,122.94725,-184.95372,1182.4781,91.12502,456.8772,1178.085,90.381836,-218.8684,1164.5653,96.66841,471.05624,1161.288,100.821884,-242.60585,1163.83,108.69751,453.8591,1164.5043,119.35266,-189.34924,1181.0958,558.346,202.53748,1175.4279,551.6366,-202.66316,1162.6575,775.18036,237.18922,1161.9303,768.6564,-174.68057,1150.6235,960.8937,394.65808,1135.8396,964.6626,-75.741974,1138.4021,996.63257,407.44208,1115.1334,998.4936,-73.40273,1217.33,989.67914,326.82764,1202.492,1008.6967,-221.26143\r\nScreenshot_2021-02-11 at 15.15.05.png,squats_up,640.88934,73.08431,-517.36224,647.25024,62.940342,-495.63113,652.3101,63.101624,-495.5946,657.54205,63.147095,-495.46127,631.98083,63.11855,-499.71646,626.46844,63.22794,-499.71957,620.9723,63.416798,-499.73352,662.02747,73.21632,-345.66406,612.5079,73.192604,-357.52133,649.66315,89.12257,-459.3824,630.3008,89.028496,-462.80838,698.3003,161.20604,-219.17856,570.70984,159.49599,-248.82843,729.4502,268.76154,-169.31438,550.4293,270.267,-213.52466,758.8622,360.0536,-249.71138,531.3025,358.5782,-280.49118,771.93567,381.05148,-263.63138,522.7539,381.3229,-287.59164,768.681,384.226,-312.36856,522.3971,386.00394,-341.90717,758.73035,378.21423,-271.0613,534.2876,379.34033,-302.62717,676.1061,338.62152,9.377479,600.0921,342.2656,-9.357546,686.9965,489.94208,13.673644,599.08563,497.32205,-7.405561,693.8143,635.85004,159.58432,598.5827,638.26825,155.89587,686.63635,658.32684,163.165,605.4917,659.27216,160.75946,718.17065,676.8587,-5.534762,582.58374,680.0056,-10.116637\nScreenshot_2021-02-11_at_15.39.02.png,squats_up,1331.9949,133.0197,-459.31183,1346.1621,109.67498,-412.67026,1355.1869,109.44828,-412.5874,1364.3752,109.06584,-412.68915,1317.7144,110.023705,-418.76318,1308.0681,109.73239,-418.7263,1298.4259,109.60849,-418.63046,1376.8373,120.06678,-112.57198,1285.2811,119.98783,-138.84517,1349.0691,158.09334,-346.51392,1315.44,158.1793,-354.71274,1446.0127,263.48022,61.695953,1217.1808,256.05984,46.54712,1523.4452,417.72122,-265.2005,1144.0225,427.12338,-243.93173,1413.8751,289.28613,-738.12646,1242.5637,289.84833,-654.66394,1389.8438,255.37512,-839.4252,1273.521,253.23497,-736.29474,1381.6348,236.90495,-780.5148,1270.4165,229.82916,-701.4949,1381.6306,251.52657,-722.0435,1268.3762,247.96056,-641.7318,1400.9783,593.51746,12.80746,1259.1337,587.7875,-12.730397,1446.5856,867.1532,-29.28726,1216.8054,859.2807,-24.271158,1460.5396,1095.8672,409.8084,1187.5476,1096.8125,367.2861,1440.4952,1131.5927,436.96527,1194.595,1128.9332,387.32068,1528.173,1170.5121,120.12929,1160.8958,1184.6697,48.415447\nframe__8ghtQpeWov8__0007795.jpg,squats_up,1093.241,150.25873,-375.1606,1097.2854,135.53372,-339.61417,1101.8652,136.76746,-339.6441,1106.6664,137.83073,-339.69647,1080.5977,131.09378,-369.75003,1073.2979,128.82869,-369.48447,1066.0234,126.716965,-369.59708,1096.4075,143.7024,-123.86348,1042.1777,129.43306,-269.94824,1092.5906,169.33444,-292.59125,1070.5775,163.53061,-334.80237,1107.6388,255.79633,98.42964,956.9131,220.59724,-250.87306,1125.0723,374.8643,294.3404,875.04504,325.17642,-247.54,1118.9492,482.82553,88.729744,928.7633,440.48743,-344.8608,1116.2644,519.7153,44.449062,937.45184,465.71152,-391.99066,1108.0837,513.23175,-14.8600645,957.0323,451.08432,-410.52362,1101.8915,498.50043,61.455616,954.19824,442.68378,-347.25058,1057.9075,506.7158,137.82634,973.3031,502.873,-137.16364,1053.8336,703.1968,237.0539,983.80884,716.79816,-192.59476,1052.985,873.4153,490.65332,976.72003,900.21,-88.03059,1037.6443,904.56067,503.4946,957.7859,927.4736,-89.81384,1108.5482,922.445,360.2781,1034.1621,964.4459,-296.47083\r\nScreenshot_2021-02-11_at_16.19.56.png,squats_up,1332.7739,309.48862,-769.2862,1341.6779,289.73712,-739.65216,1349.0273,289.05118,-739.61414,1356.6375,288.17984,-739.46704,1317.4681,291.59192,-744.75934,1309.0197,291.9618,-744.6205,1300.6145,292.47076,-744.56696,1363.5854,297.47943,-489.04022,1286.3132,302.4686,-505.95847,1345.7327,329.9771,-671.3128,1317.087,331.7896,-676.62354,1426.2687,421.53143,-267.23727,1227.6888,426.3058,-290.10513,1460.6989,564.9875,-174.78113,1207.8702,570.55115,-208.23503,1490.367,688.91223,-395.81644,1179.5775,695.8131,-427.15198,1508.2557,722.23517,-450.14868,1164.588,731.11176,-473.3962,1501.1445,727.62885,-531.42694,1166.9615,737.57837,-573.9469,1488.9496,717.5858,-432.99448,1183.9236,726.1542,-471.34747,1395.0051,699.11926,23.644493,1275.2646,705.4917,-23.653372,1429.7167,923.12744,-11.663833,1254.4442,928.7688,-82.37445,1437.1671,1129.7135,270.39514,1220.9725,1126.7334,191.99396,1424.7625,1161.9656,281.9873,1228.5028,1159.6031,203.12074,1462.5414,1193.4187,10.596424,1180.2804,1185.8284,-78.951805\nScreenshot_2021-02-11 at 15.32.48.png,squats_up,646.2803,160.88213,-380.87585,650.9721,146.89825,-373.93884,655.10895,146.20723,-373.88156,659.392,145.4063,-373.80008,637.3694,148.04564,-376.39554,632.6469,147.96457,-376.30624,627.9649,147.9475,-376.23782,663.71936,144.56183,-248.69595,619.9161,147.43909,-255.22218,653.5298,169.19911,-327.23077,638.5848,170.11577,-329.57184,703.88666,203.87444,-132.55429,580.5075,201.42865,-130.58882,723.7427,286.9898,-63.835598,564.56525,278.94928,-45.52579,709.71484,357.50458,-221.2902,574.15216,359.86768,-156.1147,709.5446,381.71857,-273.81873,571.73334,384.0103,-184.17136,696.1842,379.05804,-306.07877,580.5449,385.7064,-237.03922,692.59937,369.84015,-235.8779,587.4593,376.37338,-176.67815,677.5801,370.24615,5.5654416,604.29126,370.2879,-5.6425195,694.8968,508.55954,-32.44063,588.40686,511.0187,-45.387363,704.94946,635.3447,98.44787,569.68176,634.3318,89.59731,700.9556,651.1085,102.47576,572.0038,651.0782,93.59198,704.5395,681.2695,-55.07482,562.5197,679.32056,-65.179665\nframe__iqBidNs7j3s__0010076.jpg,squats_up,628.6189,196.17113,-275.2783,632.70215,185.2474,-247.76416,636.6212,184.54126,-247.74484,640.6415,183.8553,-247.84593,620.44385,187.20778,-250.62392,616.4106,187.76006,-250.56053,612.3638,188.41568,-250.68977,647.01746,189.1664,-101.74572,607.5535,194.65355,-107.31582,637.6954,206.09189,-222.22513,623.11145,208.3285,-223.22816,673.8806,243.89293,-145.84741,588.2776,244.30492,-173.68456,679.483,240.25139,-504.0075,574.0176,243.38098,-553.41785,691.1712,221.276,-871.8207,567.1534,215.14868,-926.48486,701.7346,215.36426,-964.9939,560.76917,207.08952,-1026.3307,690.9894,212.72414,-971.43616,572.4901,199.68796,-1032.8398,687.2987,217.18118,-891.8527,575.6612,205.16202,-944.7419,657.8836,396.78473,5.796919,594.6172,397.10312,-6.1537523,686.527,514.57135,-66.31597,571.6285,517.3182,-47.06243,705.59607,634.59436,34.237877,545.71814,631.4546,85.59051,698.8592,651.24445,35.653385,549.26135,648.10297,88.64394,726.739,671.28174,-126.55773,521.7888,667.38293,-77.08441\r\nScreenshot_2021-02-11 at 15.36.07.png,squats_up,602.3843,73.87801,-404.65775,610.36224,60.074253,-382.31784,615.5006,59.69043,-382.3155,620.7275,59.20271,-382.31677,595.67535,61.31772,-381.67123,590.57666,61.597977,-381.57632,585.42554,61.956425,-381.5803,629.7804,65.861084,-229.75478,580.7869,68.49523,-221.24852,613.70197,87.67977,-347.2935,594.8809,88.76378,-344.67535,670.60004,145.92967,-119.98242,545.74786,149.90077,-83.810486,697.4343,252.66768,-201.10005,512.57666,257.36642,-160.7196,660.62964,232.07454,-536.2799,543.09436,235.63007,-484.30716,645.8751,235.16196,-612.53894,555.95294,235.93369,-557.9269,645.81604,212.5217,-626.6124,559.03503,213.92456,-572.7155,647.7552,212.10109,-548.2537,560.0503,213.4538,-496.29645,636.59845,338.8349,-11.037858,561.59155,340.03992,11.354104,695.12335,465.2554,-3.6914625,499.17636,468.15094,17.590462,754.86237,573.44696,214.83301,455.57568,583.62585,229.43979,755.6522,593.6937,227.61325,464.05228,605.00995,241.0194,787.2877,605.5739,88.43239,401.36954,620.428,97.41582\nScreenshot_2021-02-11 at 15.19.35.png,squats_up,215.71567,72.01287,-42.43458,219.71281,66.87011,-29.694265,222.89546,67.17696,-29.661037,226.15585,67.426094,-29.66746,209.84735,66.79871,-33.311386,206.26167,66.89011,-33.36405,202.69977,67.052284,-33.415943,229.07088,75.35051,35.63042,196.4703,74.96181,20.236122,220.94664,83.988716,-18.293348,208.68839,83.77119,-22.658634,249.87666,119.83187,37.485336,174.90746,122.03847,11.224472,260.96344,119.97579,-61.502563,170.71733,125.762794,-91.99136,216.59798,94.210884,-149.0128,213.86096,100.51593,-151.7122,207.39865,92.322044,-171.01569,223.30399,97.463326,-162.91254,202.29333,90.93776,-162.30132,224.4873,96.013435,-160.55399,204.98793,93.40007,-149.85783,221.13553,98.958145,-151.36601,244.78543,242.15909,6.166282,193.21843,245.16962,-6.308751,268.0876,343.00797,-36.53636,175.04933,346.21274,-51.722675,280.33243,450.66608,-30.866758,159.03053,453.16446,-31.221518,273.19592,468.26233,-36.149174,163.30884,470.88004,-35.221527,302.24722,472.55908,-123.18291,136.84708,476.34546,-120.018814\nframe__KBPjMze4FpM__0002619.jpg,squats_up,952.4311,270.22177,-379.96817,961.6473,258.44016,-336.7495,968.16516,257.87302,-336.67255,974.9081,257.2309,-336.76715,942.9556,261.14157,-335.49008,936.99744,262.30344,-335.28482,931.00574,263.6152,-335.49646,988.9958,271.64932,-124.54236,928.4612,279.1817,-113.23825,969.32764,290.02576,-304.9898,945.6388,293.17996,-301.78833,1055.3933,377.14368,-147.13823,888.10126,377.39026,-110.76689,1091.2128,421.46738,-573.01886,827.36804,364.0552,-587.1749,1087.6066,400.2511,-1085.5826,779.3787,339.85974,-1177.8534,1095.2297,407.3142,-1210.5934,757.2243,342.08328,-1321.639,1080.171,396.00116,-1219.4874,775.3926,333.50134,-1331.8499,1075.5107,397.4441,-1107.1051,784.8492,337.94992,-1207.3837,1027.9338,635.8654,-10.228478,917.07684,642.0367,10.184051,1053.4073,838.416,-52.609356,896.1036,837.6086,51.37601,1087.9236,1009.69324,210.91968,876.39197,995.1954,430.5746,1085.7062,1035.7776,220.22174,889.7875,1020.952,454.86444,1091.7439,1067.852,-40.984318,827.08136,1051.1791,220.3539\r\nScreenshot_2021-02-11_at_15.38.34.png,squats_up,1327.7368,133.99324,-530.38104,1342.1576,111.670815,-479.582,1351.5393,111.45688,-479.46634,1361.0767,111.082306,-479.5573,1313.2026,112.53694,-485.33148,1303.341,112.55536,-485.28683,1293.4811,112.77695,-485.16678,1374.7845,124.85641,-175.72752,1280.9227,126.14403,-199.09341,1346.177,160.65178,-417.5394,1311.554,161.27002,-424.76175,1442.7899,272.37616,-7.0567403,1213.1244,264.2341,-40.727814,1514.1383,424.31558,-385.68738,1139.173,426.16476,-371.0433,1405.8008,278.02487,-889.3287,1245.9093,280.35464,-786.59644,1382.5394,239.85503,-993.69165,1278.0975,243.10236,-872.72656,1374.9537,221.4191,-933.92694,1276.4811,220.54454,-836.658,1374.1113,238.13245,-874.3005,1274.2118,239.86809,-774.75903,1384.6913,607.0991,21.57958,1243.6603,601.7817,-21.559752,1432.6508,877.8295,-12.93905,1207.4004,871.69745,-21.310385,1450.0872,1107.6487,420.80664,1179.6152,1102.3782,389.79437,1428.7571,1143.953,447.9327,1185.2848,1132.7659,412.2596,1524.7927,1186.0349,132.32965,1159.0425,1194.0887,74.355896\nScreenshot_2021-02-11 at 15.03.22.png,squats_up,514.84283,175.87193,-463.10022,522.40686,166.58487,-444.25186,526.57764,166.69347,-444.27176,530.8797,166.71687,-444.23325,509.60312,166.53107,-446.46777,505.46313,166.4117,-446.34634,501.33752,166.36104,-446.23477,536.9301,172.94435,-299.77316,496.7852,171.67166,-301.6218,522.5421,187.30899,-406.58722,507.46323,186.90462,-407.50153,564.09955,232.6497,-168.15848,467.09537,239.45918,-186.33331,588.2869,307.67795,-156.86894,453.56342,322.84256,-145.63571,611.454,372.03964,-332.36624,434.03958,397.57507,-246.97215,622.93915,390.14056,-368.45474,424.34323,417.77292,-266.49756,618.1258,390.22083,-415.97617,426.00565,422.72815,-324.90662,611.6849,385.0018,-356.33286,435.88184,416.22232,-272.18338,551.19836,380.94418,7.4588046,488.6197,385.55264,-7.5414343,582.79785,507.17615,-34.592155,468.50436,510.9783,-45.259327,597.70355,628.30927,100.35985,445.7532,626.6151,95.373184,593.10394,647.7344,103.04554,449.99484,644.69666,99.12337,619.96783,661.3502,-57.671017,423.1633,661.62933,-61.1232\nframe__bggX6ocjojk__0001696.jpg,squats_up,1853.7036,418.6427,-1305.8743,1870.4215,388.2837,-1255.7115,1882.2634,387.39322,-1255.6306,1894.6693,386.16922,-1255.3833,1830.2749,390.57678,-1262.7173,1816.9373,390.7854,-1262.297,1803.7029,391.21408,-1262.115,1908.0132,397.89108,-820.30457,1781.5117,402.88528,-845.3389,1874.4982,451.7768,-1134.8732,1829.737,453.479,-1143.5323,2008.7507,602.2643,-415.83044,1675.3453,613.1738,-458.4255,2074.1726,832.17804,-224.65804,1626.0511,853.49615,-360.75787,2138.3376,1057.7767,-644.22705,1543.4971,1084.0422,-749.21204,2173.965,1116.9792,-739.5998,1504.1196,1142.7703,-830.60693,2159.9873,1130.3282,-892.97906,1513.3285,1155.9374,-1003.7389,2136.095,1116.0267,-711.4768,1545.6838,1138.5247,-825.2562,1931.0293,1056.3583,28.206945,1721.5358,1063.1666,-28.187258,2017.4403,1457.7317,1.4960386,1663.0743,1464.4924,-88.13266,2050.3218,1812.8829,528.5374,1597.7587,1815.6559,387.65143,2029.3425,1866.0908,552.77136,1606.1415,1868.2087,407.32257,2099.6892,1924.9861,87.27882,1557.9412,1929.7661,-88.271416\r\nScreenshot_2021-02-11 at 15.30.11.png,squats_up,167.32036,45.161263,-411.9525,175.50746,38.135868,-391.3314,180.00696,38.454933,-391.42526,184.65767,38.65731,-391.4706,161.69815,38.349915,-390.5969,157.31236,38.56954,-390.5078,152.94823,38.851803,-390.40277,191.92946,49.54122,-254.54808,148.82211,49.216175,-244.27434,176.67786,61.203583,-359.3709,160.19162,60.93875,-356.77164,232.66173,131.6443,-159.99152,113.84655,136.53226,-119.231636,267.77188,225.01291,-116.398865,102.50484,231.41061,-51.20644,298.3013,302.02798,-231.20479,89.75648,318.41354,-178.13962,311.6124,324.15808,-268.00192,82.684296,346.0964,-199.6068,305.80133,325.44608,-314.28256,84.946365,348.89264,-264.2824,297.34534,318.2677,-252.59349,93.76955,338.5707,-206.46323,220.58096,303.2013,-12.3677025,143.77335,307.2334,12.4088545,262.04346,458.79044,-75.83883,110.38163,449.4146,-32.97069,290.45428,610.5131,38.441216,94.30723,591.2301,112.89958,288.10416,634.0879,38.366352,107.86169,615.3338,115.9675,312.98566,649.65375,-144.49393,46.583275,630.6469,-49.25478\nScreenshot_2021-02-11_at_15.49.43.png,squats_up,1221.885,145.997,-560.5711,1235.817,124.23681,-518.2409,1245.869,123.82752,-518.26086,1256.2594,123.20038,-518.27576,1206.135,126.45361,-523.2741,1195.6271,127.27667,-523.1215,1185.0997,128.30736,-523.0972,1272.3613,141.84724,-267.03253,1173.4783,147.74092,-281.42032,1243.7743,175.89256,-465.99194,1204.7212,178.14305,-470.4672,1360.9279,314.8157,-122.860954,1097.7261,307.7097,-157.37184,1393.5663,501.90433,-39.22746,1062.5084,487.48187,-108.37388,1390.3761,664.9787,-338.1002,1062.2385,669.3266,-355.90503,1399.0187,723.8096,-433.7505,1050.6912,731.1991,-427.33142,1372.3981,720.3051,-509.90292,1075.8693,733.3115,-512.8163,1359.819,696.8899,-374.1952,1091.9388,710.07556,-393.03317,1303.1465,692.0038,23.522024,1149.1736,690.24115,-22.79672,1366.1389,953.69965,19.178017,1117.4333,954.9445,-49.89672,1360.1132,1170.8936,395.22964,1113.4235,1174.878,376.84964,1336.8752,1201.5361,419.54532,1133.2476,1206.2225,403.18176,1421.4028,1270.6353,201.50403,1057.9393,1279.948,148.86147\nframe__kKOqiUh_F2g__0020819.jpg,squats_up,598.4167,176.85677,-276.3936,605.2283,167.89905,-258.7815,609.0451,168.0174,-258.79535,612.9742,168.06573,-258.82568,593.30365,167.44089,-258.446,589.38367,167.09459,-258.3648,585.4481,166.79993,-258.41013,618.85565,172.2278,-123.899536,580.33777,169.58871,-119.675766,605.66907,186.87775,-224.2572,591.4858,185.96844,-223.58153,650.114,230.80264,-22.540255,546.5514,226.60464,-14.0927105,663.2214,308.89804,-27.287762,531.29553,307.97974,-24.4503,626.954,350.7445,-255.66238,562.8561,345.4359,-230.68092,616.89124,368.9749,-313.23923,570.18066,360.9404,-286.6985,610.4872,359.43103,-338.30627,577.1789,352.72113,-307.26794,612.4864,351.33432,-269.83038,577.5981,345.06113,-242.80333,625.15375,373.6015,-0.87077665,563.70624,371.82297,0.9063935,633.6474,503.68323,-31.479942,561.0003,501.5057,-21.68004,628.31,621.3856,107.43494,563.3321,616.45135,131.29927,619.1379,638.06396,114.48918,570.76715,633.2915,137.62782,648.97314,662.2486,-15.369615,547.0139,657.7533,-0.2803112\r\nScreenshot_2021-02-11 at 15.25.29.png,squats_up,584.22845,110.61077,-320.82504,589.3993,101.91312,-302.62326,593.1578,101.79189,-302.65112,597.0516,101.59102,-302.6465,577.7406,102.53664,-303.97437,573.66425,102.6605,-303.83478,569.5729,102.87585,-303.84125,602.34796,107.66582,-184.80125,564.4614,109.17646,-181.85912,592.0101,122.47212,-275.7727,577.7269,122.93116,-275.2293,638.9346,178.74213,-92.65026,532.69714,180.31204,-104.236336,651.28174,259.48856,-39.539043,520.8459,265.92316,-57.263134,652.7934,329.88095,-173.08301,512.0326,344.3547,-135.03972,655.44165,351.13046,-209.85489,505.5211,366.3809,-148.75116,652.3761,350.41742,-247.65312,508.49063,369.96973,-201.08018,647.4096,342.0697,-191.78835,517.6011,362.04416,-156.8246,619.2265,330.9629,-4.361935,555.22876,332.5785,4.5874434,622.3818,448.57565,-14.773048,548.3951,455.73468,7.0602436,630.30634,559.6559,117.61582,531.5764,566.51483,150.4294,626.1249,573.68256,121.75259,532.15326,579.16724,156.64215,638.5691,600.92706,-19.271305,527.73224,611.30695,15.476081\nframe__Y6T7XweU9G4__0001450.jpg,squats_up,966.49304,157.61366,-158.13493,976.10547,140.32915,-123.88843,982.9778,139.69868,-123.782845,989.9991,138.94005,-123.90232,954.5852,142.25432,-127.02229,947.33704,142.87032,-127.04881,940.0452,143.59229,-127.30368,1000.4545,147.91534,84.864456,931.5956,153.51741,70.34695,981.4358,177.44041,-81.73528,956.01245,179.89847,-86.25981,1055.7266,266.43167,195.2325,884.58563,262.82263,166.5558,1076.4303,390.39154,4.010176,884.9433,399.21,-32.82144,1004.5998,306.1519,-304.4195,943.9796,295.30124,-331.0411,990.1041,286.6877,-381.388,962.50256,267.6993,-404.35864,988.1343,271.2415,-359.38388,951.5616,250.79558,-391.46805,987.65967,275.48236,-302.61694,952.43854,260.90036,-329.877,1013.1941,530.12555,19.434744,902.83496,526.23303,-19.26966,1041.0485,738.6045,-12.121018,876.46533,732.1552,-22.165323,1048.0779,924.8184,265.05142,848.0855,916.57324,263.98236,1034.574,952.5818,279.37292,849.03595,941.43964,275.79874,1085.5646,976.33215,43.824203,845.35876,976.23175,27.44888\r\nframe__fRBFohrfRd0__0001189.jpg,squats_up,1214.9479,136.3194,-115.05188,1226.0511,118.53844,-163.42885,1228.9601,117.685394,-163.35127,1232.0719,116.711754,-163.33794,1227.375,118.87717,-104.47888,1230.6472,118.46978,-104.48301,1233.8546,118.12973,-104.404915,1256.1387,122.776596,-263.2308,1257.5385,123.01603,4.6555033,1226.5592,154.41095,-141.64755,1226.9753,154.84816,-64.70007,1293.8553,225.77283,-370.3949,1283.5304,235.881,231.69325,1287.3102,385.11945,-395.8532,1281.2465,384.0352,308.27255,1240.9714,526.6546,-367.49152,1255.6494,519.8719,256.6527,1243.1797,564.89276,-437.7271,1251.1919,553.6167,280.71506,1219.748,565.7381,-430.5616,1246.6785,553.2379,231.44917,1222.219,553.404,-364.0129,1245.3529,542.42065,233.94434,1301.8024,508.49893,-190.27263,1289.83,503.27237,190.66249,1302.3898,722.0003,-64.75954,1296.6003,715.80255,284.64835,1346.5325,940.6483,69.03314,1318.6979,908.4643,465.94507,1375.575,977.44995,68.96524,1342.1184,944.66797,476.46622,1259.3075,986.6136,-76.8041,1237.9528,949.5908,395.75812\r\nScreenshot_2021-02-11 at 15.40.32.png,squats_up,586.0413,107.10727,-497.58475,593.28436,90.61121,-488.79474,598.2751,89.71323,-488.74716,603.4284,88.66971,-488.5982,578.3715,92.26915,-488.7254,573.2216,92.30807,-488.67105,568.10345,92.44127,-488.6331,612.4875,88.782875,-359.12207,563.2602,92.94232,-350.09058,596.67737,117.70449,-444.2902,579.69305,119.1307,-441.83975,660.34174,154.94191,-250.26862,529.3751,165.70358,-228.74402,673.44727,253.9377,-234.73032,523.08386,267.19547,-202.95512,664.6621,347.13522,-355.81506,520.2937,359.76495,-308.00336,671.5384,375.83456,-396.71396,511.56964,386.30237,-340.12015,654.39294,377.894,-433.04648,524.4318,388.725,-386.00458,646.3026,367.98935,-371.56665,535.4758,378.35318,-327.73376,637.68646,343.5277,-8.974804,557.6107,347.50153,8.709784,692.65283,481.9893,-2.1941884,512.7782,482.7383,24.955854,720.03485,609.1455,134.77472,487.45935,605.90137,176.71033,712.2394,632.7719,141.30412,500.26666,628.962,183.1206,760.6663,647.63995,13.760406,438.28104,648.9752,53.02692\nframe__ZdrQyCZ0Qk0__0012268.jpg,squats_up,941.4751,144.7596,-575.0348,950.9692,127.86316,-536.96063,957.84143,127.89087,-536.9518,964.8778,127.734184,-536.83984,930.3701,127.73293,-538.1399,922.8689,127.29172,-537.9906,915.328,126.96416,-538.199,970.9047,138.18382,-304.36633,903.8585,136.805,-314.78894,953.8032,163.11108,-488.09033,925.4384,162.66492,-490.59363,1019.0888,249.10597,-132.3607,849.77716,241.87624,-180.81798,1109.0911,351.9744,-68.24241,771.0695,323.51193,-79.43862,1031.099,425.08383,-168.19685,848.5046,415.11124,-102.92587,1012.08856,441.6734,-215.10739,866.81665,431.38556,-141.51834,1002.0082,431.60617,-227.11636,872.3492,417.3729,-156.09288,1007.8094,426.51114,-175.7241,865.60095,410.88745,-108.793106,990.5975,504.7058,31.011616,889.2951,504.07278,-30.697819,994.6375,719.10095,63.44382,885.86523,720.8412,-8.353813,1004.75934,895.4823,379.91348,869.49426,893.11707,320.8183,996.43274,919.97394,399.13773,869.0227,914.84186,338.58,1021.5486,953.80347,134.43709,870.6402,958.23315,67.91904\r\nScreenshot_2021-02-11 at 15.33.39.png,squats_up,613.1296,131.96664,-406.5876,618.06696,120.77405,-387.91406,622.37994,120.56783,-388.0448,626.7673,120.24635,-388.0399,605.78217,121.31936,-386.98886,601.06366,121.27475,-386.87137,596.3387,121.29918,-386.86652,630.1873,126.83089,-265.307,589.34564,127.67062,-260.98715,620.6678,142.87314,-360.3582,602.8026,143.33513,-358.7216,659.5614,193.89088,-151.93776,556.95386,192.95625,-177.66594,714.30804,257.1819,-90.43264,488.03156,233.77872,-158.19363,669.7013,306.6764,-191.15317,529.8076,303.62976,-249.96835,657.2018,320.91528,-230.22449,537.81177,312.02557,-289.1311,648.98254,314.55328,-246.66422,545.10175,302.42853,-300.70004,651.3525,310.6714,-199.18456,541.2723,300.25214,-256.80173,628.85614,337.97144,7.4028764,571.9269,336.4524,-7.14179,619.376,464.14935,12.327333,583.5487,461.58905,-10.943867,613.6146,569.66833,178.2288,590.88416,564.0368,167.37991,608.80524,581.86395,189.12607,591.9355,577.86993,177.89719,609.4665,607.7646,44.305454,589.9427,600.73676,32.21367\nframe__yWky9j7mG2Y__0013525.jpg,squats_up,883.26697,159.09972,-26.67247,869.32404,140.2764,-5.330618,867.5355,139.08807,-5.0553236,865.98236,137.86267,-5.1403375,868.74207,142.96349,-57.985146,865.3138,143.55588,-57.953915,861.9424,144.38243,-58.09213,851.99365,147.86804,129.44429,846.2116,157.3578,-115.018616,882.45276,177.61913,23.0508,877.7067,181.10858,-47.552906,872.26587,268.62457,280.11697,841.22314,270.82266,-288.74243,950.11053,369.34558,95.492386,925.6611,422.99268,-201.31723,941.6745,271.68182,-260.64133,942.7781,293.89407,123.20811,945.2527,246.25415,-335.44025,948.0296,256.42203,126.03776,932.41974,238.51541,-297.69012,924.9425,243.62383,113.26638,927.8223,246.70154,-265.75443,921.6124,256.329,129.49998,876.39264,540.0805,199.02493,856.49835,532.55634,-198.61601,856.503,734.99243,389.90305,860.34094,750.84204,-122.488464,841.5186,898.96875,678.1945,830.407,950.6543,-64.38678,822.19104,934.58704,697.795,798.55634,986.04565,-62.20474,918.0677,937.2491,610.3148,911.3782,1020.3121,-228.66754\r\nScreenshot_2021-02-11 at 15.02.50.png,squats_up,827.38184,125.66934,-321.97678,833.4189,118.49973,-302.88788,837.50256,118.48792,-302.8919,841.7298,118.363144,-302.85098,820.648,119.41792,-303.17654,816.3813,119.86273,-303.09134,812.07446,120.39043,-303.08707,847.8324,127.77668,-182.77419,807.3254,129.99,-186.02104,836.1878,139.79149,-277.27664,820.65454,140.57993,-278.4577,884.08264,206.37631,-99.498116,773.8571,203.476,-119.669495,899.48615,292.4295,-55.605286,759.25494,286.43958,-108.91061,904.4464,371.7505,-171.11305,745.13416,365.81238,-228.75977,910.13007,397.9191,-201.58528,737.39014,390.5469,-260.7908,901.86945,399.9841,-241.11214,739.84143,393.99234,-307.54752,896.737,390.1092,-188.57202,748.5763,386.06058,-250.8642,857.03827,365.4306,23.25326,787.7801,365.4361,-22.896288,873.7599,494.4758,34.39575,777.7413,500.76413,-68.6928,893.43445,610.6727,172.48041,750.539,621.1368,63.541374,888.63605,629.2355,176.88754,751.3969,635.3729,66.46514,916.33923,646.7842,25.471659,739.7914,667.6415,-95.99969\nScreenshot_2021-02-11 at 15.09.09.png,squats_up,620.6722,162.00652,-156.3419,627.10626,153.19487,-132.61328,631.43,153.24026,-132.52455,635.825,153.19633,-132.57819,614.4203,153.7493,-136.10709,609.89905,153.98042,-136.02423,605.36926,154.2931,-136.0973,642.10376,161.57854,-9.792745,599.5992,162.59464,-26.903559,629.1799,174.93546,-111.624245,612.9077,175.44492,-116.70743,668.4603,226.41533,15.914485,569.41876,222.86041,8.627645,678.5215,282.37735,-126.01111,554.2132,277.62012,-138.87556,633.56757,228.17902,-248.81049,603.90015,233.06905,-318.39703,625.9617,215.26631,-280.3507,615.0194,223.98659,-358.34247,624.5272,210.48889,-265.0909,617.2966,215.0766,-352.0052,624.9946,215.77618,-246.32239,615.9203,220.4754,-318.45032,644.16394,384.56787,8.325209,582.26013,386.23236,-8.371984,674.10675,502.54358,4.700037,565.7325,503.5575,4.72879,698.0869,614.3446,117.74785,543.36206,608.3899,155.02644,690.67114,633.6076,121.97946,546.74023,626.08966,162.06125,730.1383,640.0516,-0.27327582,521.63074,635.2383,39.921314\nframe__iqBidNs7j3s__0009956.jpg,squats_up,628.11487,191.47946,-477.76843,633.8887,182.2577,-458.1149,637.8399,182.00945,-458.10077,641.96204,181.6445,-458.0089,620.8627,183.18465,-459.65717,616.45557,183.38898,-459.48807,612.0655,183.67017,-459.29013,646.7595,186.97041,-311.97507,605.5326,189.17259,-310.99484,635.2743,202.56311,-422.2152,620.3902,203.261,-422.1952,678.6489,252.24759,-184.91696,575.127,258.49335,-181.28004,698.5719,330.37094,-134.83107,563.6406,341.7744,-129.63638,722.70447,400.77396,-262.36508,547.27136,415.04587,-242.8636,736.63306,417.81104,-294.14648,537.6637,434.20987,-263.70642,731.18945,422.4893,-343.76862,540.5175,438.4513,-320.82562,723.0504,417.76038,-284.2787,549.92145,431.7985,-267.16214,660.80884,395.02612,4.9253674,594.51874,398.06326,-5.0877423,681.8649,525.4617,-11.846016,574.7356,521.5737,-23.87972,701.4212,635.0603,154.33287,543.92053,629.30493,151.05676,698.24536,649.05115,161.73169,544.72723,643.8203,160.88095,709.5123,677.57635,-10.8178425,530.76654,671.801,-6.468494\r\nScreenshot_2021-02-11 at 15.40.57.png,squats_up,330.95218,94.86194,-146.90547,336.8762,90.402985,-128.50845,340.05807,90.89337,-128.57285,343.35565,91.30925,-128.64479,326.99237,90.13504,-129.38896,323.84695,90.1959,-129.33131,320.6709,90.31104,-129.38434,348.50958,100.13637,-37.55532,317.25934,98.54423,-39.08728,337.66354,107.69887,-114.0269,325.09537,107.010254,-114.89458,374.68835,168.49088,10.117299,287.3326,164.23578,10.247939,385.66974,233.83623,23.373173,263.62256,228.09694,20.714865,364.71036,268.50424,-119.29768,293.7906,268.0492,-93.13935,359.7234,284.1416,-164.83217,299.17117,285.09512,-130.43907,353.47668,277.49823,-182.9704,310.84155,277.93665,-149.04333,354.47427,271.1383,-130.44856,310.0164,271.29736,-102.33637,356.74042,303.85086,-0.03958559,301.79095,303.73718,0.27492476,373.64157,414.72134,-27.312862,291.76364,420.20682,-27.880203,385.55063,522.1001,72.96731,284.35648,529.1372,64.49634,382.7623,535.04034,75.50594,288.42853,543.2116,66.2643,389.90634,558.8732,-31.667332,271.1185,565.3987,-47.430847\nframe__TBXy4D2k-II__0002838.jpg,squats_up,962.76855,306.82025,-109.61573,976.7981,293.7858,-148.15102,979.4895,294.24152,-148.16496,982.42035,294.5793,-148.16515,977.81525,291.9161,-88.67828,980.52966,290.94434,-88.605156,983.16284,290.13785,-88.55671,1004.9443,303.06924,-233.80597,1005.9753,295.44904,40.420315,970.3397,325.20303,-136.76039,970.16486,322.5165,-57.468952,1018.6042,386.20868,-379.00867,1011.0569,392.15186,249.39914,923.54626,447.73376,-442.55093,944.9461,465.63055,431.86984,832.4366,458.52075,-361.46277,865.68365,476.40878,454.0433,813.6354,460.64163,-403.59592,845.47485,477.3868,482.7772,815.0378,449.20444,-398.2489,841.4039,464.6501,440.55136,825.0483,450.01315,-359.03198,844.1282,464.9379,431.76587,988.98193,617.0851,-188.45738,979.18945,608.9798,188.65285,948.3848,791.39105,-198.12515,960.729,787.55994,205.62254,1001.38116,971.43994,-102.0979,991.9909,950.42163,312.06076,1029.1055,995.5947,-97.39941,1013.42377,975.94116,319.91895,938.2323,1029.9745,-211.15239,926.4584,995.7607,236.45941\r\nframe__ZwbX1A-LlTs__0013051.jpg,squats_up,1009.2167,121.36361,-235.3408,1004.61993,96.97927,-215.62054,1006.47296,96.607704,-215.35712,1008.5623,96.206215,-215.43994,995.2733,97.192154,-268.9092,988.86487,96.51366,-268.87454,982.4813,96.04261,-268.91455,987.79724,101.55584,-64.467705,953.74695,102.16821,-294.19336,1002.9149,140.21541,-171.00255,988.58527,140.40028,-236.73099,958.38824,199.68526,102.771645,906.58307,197.22064,-383.0666,1043.3096,276.54535,-18.594465,976.7615,298.49197,-486.9533,1106.2578,246.96962,-346.17175,1062.1594,240.14201,-373.61856,1126.3954,243.56651,-387.99454,1082.1323,225.8416,-404.81488,1118.4711,228.84087,-409.55615,1078.006,212.4911,-388.96957,1106.7659,234.69604,-365.4478,1070.0981,221.46596,-361.58667,893.6533,497.49075,162.41286,866.3714,503.3393,-162.29283,924.99896,678.4692,296.61743,914.0459,689.0137,-8.463591,925.7503,846.3304,510.88068,928.78784,875.92053,167.03748,901.574,878.9901,525.61365,897.91565,906.5711,175.58736,1018.5897,889.18616,450.18524,1032.619,932.714,53.441578\r\nScreenshot_2021-02-11_at_15.57.47.png,squats_up,1305.2798,103.4879,-510.55676,1319.6349,88.1379,-469.4966,1328.391,88.29112,-469.50586,1337.485,88.23856,-469.63034,1291.9437,89.929436,-471.81705,1283.1663,90.841,-471.59195,1274.4133,91.92584,-471.43192,1352.0607,107.35263,-225.56305,1264.8137,111.64161,-218.23471,1324.3292,133.89784,-418.06198,1291.1653,135.45055,-416.65958,1435.3556,276.23196,-70.24333,1199.1605,277.23712,-40.031353,1483.2941,430.79684,-47.06272,1157.335,430.38882,84.90797,1489.7917,557.3181,-504.9821,1148.8597,584.4776,-210.77136,1498.2739,608.0333,-625.908,1135.875,638.7389,-287.32248,1474.7885,597.7004,-704.47156,1161.3104,641.0929,-383.32996,1466.0336,579.41614,-545.72107,1176.7566,619.54626,-253.36842,1405.3434,605.7533,-8.207225,1266.2279,614.7085,8.136575,1460.6202,871.69604,-97.50817,1267.926,895.63727,-40.63987,1488.8875,1129.9465,196.64816,1271.6101,1148.3838,268.1851,1478.7635,1165.8383,206.90976,1287.3336,1183.3783,279.90823,1517.6238,1211.3357,-78.81784,1242.362,1231.7256,-17.669844\nframe__7FPCZ-YksQk__0001030.jpg,squats_up,590.19885,139.18509,-418.63083,598.2191,130.29729,-390.62863,603.51355,131.07925,-390.5681,608.9111,131.7736,-390.5844,583.0933,128.78877,-393.5043,577.73676,128.31282,-393.56784,572.3485,127.982376,-393.68625,615.2359,142.14294,-241.8364,565.98865,137.08218,-248.35074,599.39325,155.78731,-364.17474,579.7967,153.86807,-366.18466,645.2058,225.56236,-123.79012,528.00116,213.93855,-150.05357,642.9298,311.4359,31.327625,515.7213,299.71295,-18.155851,638.0923,384.37558,28.77478,522.4908,380.26227,-30.10378,641.07446,402.06424,29.913485,524.1054,402.18002,-34.0582,642.2378,405.59103,-12.247807,526.5365,398.6357,-77.392166,636.87524,400.41342,12.605404,531.07996,390.57587,-45.51218,623.51025,391.76056,9.264602,550.593,389.86862,-9.188789,615.28955,528.82965,-17.919239,553.12067,518.3804,44.710266,605.4682,589.9087,314.3347,565.8647,583.6787,401.9551,602.20447,593.08575,339.88757,569.27747,590.9412,430.6231,593.3333,635.9016,224.04951,570.1367,623.3262,309.85327\r\nframe__TBIcyRTTWFo__0001581.jpg,squats_up,755.6775,165.01476,-663.89545,763.71466,145.96376,-631.8772,770.7813,144.79677,-631.9058,778.00574,143.50594,-631.8993,741.8802,149.1762,-633.5179,734.3127,150.1677,-633.3329,726.7103,151.23152,-633.323,788.0022,151.61313,-401.0069,717.51447,161.0924,-408.46494,771.1134,183.88841,-575.2457,745.00507,187.73708,-577.63086,851.30597,268.76505,-210.97859,667.1373,275.69858,-226.16318,882.6782,414.92715,-228.46384,638.88605,419.72366,-293.11914,821.7684,444.0847,-619.64044,720.10394,451.6324,-678.43195,799.61316,462.3944,-720.71796,746.21625,470.42615,-791.8098,795.50525,438.78772,-750.8893,750.2253,446.48135,-808.79486,799.74084,431.34097,-639.5537,744.9866,437.79416,-693.5813,813.2881,541.0661,15.704804,699.9161,542.55835,-15.429566,858.7078,764.46265,-70.885155,679.80237,771.66205,-109.57584,865.81323,982.0338,195.0165,648.92786,972.44214,176.88098,853.4356,1012.6665,206.18517,647.8383,1000.83167,184.81792,888.1175,1050.1488,-55.396236,649.50287,1041.4335,-97.30773\r\nScreenshot_2021-02-11 at 14.44.17.png,squats_up,158.02707,196.00447,-215.30356,162.7299,189.62578,-200.76479,166.00792,189.62804,-200.78673,169.38689,189.55853,-200.74216,153.19241,189.90012,-201.57652,149.82352,189.99629,-201.51353,146.45834,190.13628,-201.50114,174.20325,195.10759,-114.94891,142.38156,195.58026,-114.77822,164.61716,205.1317,-183.06297,152.06511,205.23436,-183.00627,195.81589,246.12808,-61.171436,119.04866,243.27501,-63.465748,206.11191,304.53934,-46.270393,106.48311,300.3563,-45.284756,195.89838,352.9381,-156.59784,112.26053,348.527,-128.57068,196.41254,371.60202,-189.26689,110.583755,367.32886,-151.02405,185.08908,368.66995,-210.76332,120.63534,364.2955,-174.54614,182.28331,361.47562,-166.57733,123.73146,357.9047,-138.03091,174.87575,356.73105,0.29521903,129.80423,355.07632,-0.17782073,185.13158,445.85458,-8.881217,114.9918,444.5745,-9.103024,191.13318,528.2431,80.40967,104.30205,525.01953,90.75721,185.82169,538.39966,83.80078,109.7146,536.92474,94.1671,206.05547,560.8176,-7.986731,84.18203,555.8154,-3.4311707\nScreenshot_2021-02-11 at 14.32.06.png,squats_up,356.74796,122.11229,-324.1459,360.84125,116.685524,-306.6838,363.85464,116.81933,-306.6683,366.9774,116.872406,-306.56787,351.3905,116.89535,-308.72946,348.0778,117.08718,-308.67972,344.76917,117.33415,-308.70032,369.92294,123.7803,-203.86462,339.5116,123.99255,-209.44667,361.94016,132.17735,-286.32367,350.07117,132.30193,-287.87827,392.1432,176.37613,-126.31711,313.49115,178.67427,-148.92627,408.38696,231.72269,-91.32893,300.94,237.78786,-138.11557,413.2246,287.3436,-168.067,293.29764,289.66187,-204.13606,419.28,303.25845,-190.56007,288.6012,303.43033,-224.9747,410.78433,304.81836,-220.95705,291.59158,306.2282,-257.1506,406.75494,299.793,-181.7749,297.57526,302.3096,-219.44484,379.00385,282.7859,12.262015,330.43826,286.12683,-12.2767,394.61652,366.15298,-11.9979725,330.44406,371.58282,-37.075237,408.00998,447.14417,89.82367,319.277,448.84268,65.42145,406.5928,458.50986,92.826096,318.84363,459.78036,68.42189,413.26813,471.97952,-25.490898,319.6797,473.9289,-50.179153\nframe__9d0VKo-LnL8__0003004.jpg,squats_up,893.82446,316.55606,-436.81122,910.7879,303.15833,-433.14163,917.2746,303.59085,-433.18112,924.0379,303.86954,-433.28842,897.9612,302.22217,-389.33124,894.5202,301.63098,-389.03436,890.9856,301.20453,-388.87207,946.6791,314.6988,-341.56396,904.8763,308.78223,-136.78989,911.1791,334.7758,-401.25742,892.96893,332.7309,-342.77652,1007.7174,413.7989,-306.9519,888.61505,419.7404,89.59003,1053.2764,537.6577,-284.18488,893.6944,535.863,193.73907,1090.4218,658.2412,-391.78455,878.4666,634.021,-77.708725,1110.5979,687.0309,-442.7972,878.92206,663.5622,-127.725334,1101.4169,696.5834,-492.00336,871.5752,662.69226,-199.72495,1088.323,687.89557,-411.29086,880.1592,653.4494,-116.62313,992.86194,642.7322,-122.59673,922.6036,645.89685,122.994606,1014.31586,816.43225,-26.217066,917.8845,803.1444,294.35855,1049.7903,975.1228,307.915,924.0978,939.5906,657.2241,1065.7021,993.85046,330.90436,945.2807,962.3051,683.04755,1011.38074,1041.841,119.613014,858.608,994.13904,519.85223\r\nScreenshot_2021-02-11 at 15.55.30.png,squats_up,641.48126,76.81237,-255.42567,647.44446,64.49965,-229.22618,652.2818,64.186584,-229.08247,657.24133,63.85249,-229.14262,633.0631,65.33266,-235.48582,627.81836,65.41081,-235.47507,622.5647,65.60886,-235.71558,663.3659,71.23725,-77.809525,615.44214,73.06287,-107.616234,650.86316,90.402466,-200.24284,633.1679,91.34163,-208.10625,695.53394,141.23195,-108.45199,582.81824,139.05347,-137.61943,696.8546,172.07956,-432.85828,572.4497,170.52188,-460.92816,699.6798,137.95258,-765.1251,566.74304,130.17227,-774.995,707.56433,132.09595,-845.6729,561.4269,120.377655,-857.3634,702.3529,127.43026,-845.23035,564.38513,113.58407,-861.4338,696.8897,132.03308,-778.83386,570.5176,118.74261,-788.8635,675.6005,349.1218,21.52626,599.2206,350.03516,-21.628027,698.7904,497.99152,21.347792,573.82275,498.0723,-49.524277,722.17096,637.44885,125.17403,538.3093,627.73755,96.421814,710.51184,659.9918,126.56033,538.03986,645.56305,99.928246,761.1998,673.8276,-40.679382,527.7896,668.87494,-70.850235\nframe__iqBidNs7j3s__0002534.jpg,squats_up,638.3275,185.68167,-201.03041,643.5292,175.65732,-177.80786,647.70087,175.41653,-177.7182,652.03125,175.12154,-177.73163,630.5079,176.56357,-178.92319,625.7525,176.70282,-178.85126,621.04944,176.9525,-178.88695,655.74866,181.44876,-45.146976,613.9918,183.7326,-48.867943,646.394,196.64192,-152.6506,629.23517,197.45108,-153.87906,681.83606,236.7602,22.46191,583.5164,237.23164,31.176512,742.0143,250.10123,-5.054638,510.62762,239.34343,1.3636665,783.31604,193.67274,-134.44772,485.2539,173.59784,-141.7802,798.75977,179.66841,-174.2121,475.2759,158.4558,-182.5222,793.4746,172.23546,-188.6396,483.42255,148.23009,-195.98395,786.7329,178.01312,-150.39069,487.58713,153.98326,-155.76021,662.4485,391.46692,-0.6098381,602.69446,393.0604,0.9034898,683.8369,522.30347,-22.969187,585.08093,518.12946,-22.4105,700.1294,641.2762,106.10633,568.22644,632.3453,121.04763,693.89594,660.6037,110.31096,573.9958,650.02765,125.93784,724.78094,676.56445,-44.608074,548.0928,669.6476,-28.136139\r\nScreenshot_2021-02-11_at_15.51.02.png,squats_up,1255.4967,146.59172,-591.12946,1270.2863,123.73579,-550.0862,1280.6688,123.10871,-550.1213,1291.3647,122.237236,-550.15686,1240.216,126.4238,-553.82465,1229.5588,127.311455,-553.6154,1218.881,128.44493,-553.56494,1309.9044,139.50919,-302.97546,1208.652,146.88086,-306.655,1278.8975,176.04546,-497.13934,1239.4142,178.79523,-498.5132,1403.2677,307.91132,-166.60844,1134.153,310.71814,-166.9814,1440.4508,495.2536,-110.65041,1103.3069,496.60385,-110.33854,1431.1028,664.74786,-410.61484,1099.9224,674.9284,-362.852,1440.9036,726.87396,-506.98962,1088.7788,736.46594,-435.01196,1411.283,725.35596,-582.82684,1111.6853,737.5162,-526.3576,1397.8646,701.4394,-445.04282,1129.0056,714.3345,-402.60077,1341.5437,698.6588,9.480074,1186.3945,700.1866,-8.811609,1405.8678,958.09735,-3.6865869,1161.8743,965.0395,20.401968,1396.7968,1180.3834,376.96542,1160.1515,1177.4111,484.6613,1372.4457,1214.0686,402.52487,1183.7858,1211.8739,516.3662,1459.7926,1276.7872,200.19803,1088.6493,1278.0011,289.2225\nframe__1J8CRcoFekE__0013490.jpg,squats_up,939.8885,164.2961,-486.6116,946.7031,148.97383,-461.652,952.56024,148.09753,-461.54382,958.74445,147.08275,-461.3427,926.4121,151.67078,-464.01398,919.43604,152.61905,-463.96127,912.51807,153.66525,-464.03778,964.4101,155.30615,-288.09784,901.28955,162.71259,-289.52505,950.7002,182.44788,-420.76398,928.1066,185.55603,-421.2908,1025.4631,274.57993,-164.80547,845.5312,280.32895,-179.39001,1048.61,420.81027,-111.82688,826.11914,429.39795,-168.01607,1061.3136,547.82544,-259.07123,812.3945,556.38855,-288.39484,1072.2003,579.9069,-295.02057,805.05396,583.8923,-304.65106,1062.6375,583.994,-360.25394,806.6662,594.6692,-369.08136,1052.047,573.7118,-285.05872,823.1811,587.50635,-315.86417,991.23663,532.74475,5.70893,882.6153,537.7229,-5.927003,987.24744,760.16125,13.042952,879.851,765.29504,-21.064243,990.7565,960.26337,205.27705,865.20044,958.5213,157.90004,983.901,988.0934,210.80107,867.8766,986.13837,161.92526,998.1014,1016.5246,-7.2683687,863.5995,1012.05145,-67.89936\r\nScreenshot_2021-02-11_at_16.08.24.png,squats_up,1393.0715,121.06765,-848.37244,1401.8303,104.154884,-814.17303,1410.8752,103.894905,-814.1282,1420.3651,103.43168,-814.0026,1373.9655,106.96727,-820.5718,1363.6819,108.42668,-820.50574,1353.4377,110.05862,-820.51086,1427.9556,125.363945,-580.12244,1337.2242,133.24689,-605.9114,1410.172,151.9964,-759.33954,1374.6698,155.3331,-766.43915,1497.3636,291.6571,-360.3423,1271.4364,299.23978,-455.66754,1563.6083,465.8543,-222.19162,1238.4724,484.88132,-418.58893,1600.7917,628.24713,-414.78036,1215.0223,648.8854,-576.71075,1622.4817,677.8907,-463.9778,1197.9634,697.96246,-623.8567,1598.7317,680.33954,-549.19806,1213.1616,706.4769,-707.4227,1582.4137,665.17444,-450.99063,1232.8213,690.1921,-612.3991,1463.4382,617.51373,48.418427,1324.3103,625.4584,-48.67784,1513.2689,872.30817,80.67016,1311.3286,896.6898,-71.9927,1536.4856,1119.3215,312.42294,1278.0884,1127.1757,191.51247,1519.2025,1158.4979,319.88937,1278.6298,1157.2827,199.59062,1599.2817,1194.3312,47.439117,1282.4056,1211.3176,-96.36077\nScreenshot_2021-02-11 at 14.46.21.png,squats_up,412.03284,217.87784,-79.55411,419.6504,212.1738,-53.537632,423.5178,212.83238,-53.528355,427.50143,213.46396,-53.618416,408.4481,211.17232,-49.819042,404.95618,210.83617,-49.763176,401.4995,210.61345,-49.93112,433.97086,221.77576,57.23377,398.54935,217.61443,73.221436,418.97775,229.33606,-41.902622,405.14447,227.76805,-36.82285,448.75473,265.14536,24.011301,376.59763,260.64288,47.62511,460.39136,206.67162,-125.13727,349.3116,205.928,-126.58168,466.4223,140.22896,-236.83696,331.68515,148.79135,-296.31534,471.29834,124.18259,-289.8158,324.7508,133.65445,-355.2545,465.60596,121.85454,-282.44836,334.95413,132.2409,-357.14435,462.31076,127.9774,-244.53214,339.0834,138.34724,-308.59512,431.17096,393.43958,-14.053642,378.65295,392.48877,14.1444235,451.86066,503.43576,-48.79997,357.19495,504.52548,-26.071342,474.953,621.78467,1.7643492,335.55786,619.4433,28.780718,471.54434,639.98444,-0.9837358,341.8228,638.0642,26.334486,490.75827,645.6919,-151.98569,308.72934,642.14185,-112.95535\nframe__DxZEBqUjIDU__0001450.jpg,squats_up,738.4765,182.66376,-152.1926,746.7698,170.26324,-130.15671,751.7083,170.25266,-129.95905,756.7945,170.22522,-129.97348,732.4044,170.68666,-127.13518,727.4951,170.49942,-127.05677,722.6129,170.50331,-127.207375,764.3142,176.20836,-14.970295,716.57684,176.0146,-2.7632089,747.5482,195.2846,-110.150345,729.6545,195.0441,-106.464424,794.0051,228.90723,-32.743156,684.1366,228.82199,-25.057686,791.1565,173.56403,-291.74597,655.40094,178.58096,-267.98627,767.93494,85.18213,-431.2236,699.1427,89.278275,-431.6856,766.1937,62.964706,-476.16092,712.6767,68.66247,-482.02435,763.6895,63.19999,-454.29132,715.8081,65.97443,-457.1841,760.99805,71.65288,-429.59088,714.7112,75.14543,-430.06976,777.84796,397.48047,-13.853923,708.22577,401.30023,14.180716,777.9199,538.1177,-64.91588,718.9184,540.41113,-53.530373,783.4524,656.7778,79.25656,731.3302,665.0551,100.06667,782.98004,667.4427,86.38436,738.1043,679.6324,106.468094,769.55804,710.8294,-54.676342,728.20917,715.62115,-34.61452\r\nScreenshot_2021-02-11_at_16.03.02.png,squats_up,666.9298,56.462334,-269.95425,674.607,48.38746,-250.57063,678.83856,48.45802,-250.59998,683.2358,48.43635,-250.65994,661.31726,48.973827,-249.86934,657.17566,49.215183,-249.75586,653.0343,49.544853,-249.68527,691.07275,56.8851,-131.5282,649.3344,57.859566,-122.202835,676.3127,70.89359,-224.86732,660.50354,71.18713,-222.47548,731.2872,139.92264,-52.792496,614.5759,136.9708,-39.046455,753.46747,218.6928,-23.188324,592.8589,214.23946,16.878048,752.20917,291.16156,-210.48044,586.41125,295.50574,-122.952805,755.0902,318.07306,-264.99268,579.6451,322.9115,-161.40292,743.7528,314.90143,-303.13147,590.1786,324.6286,-210.5746,739.943,304.47165,-230.07951,597.9402,314.32083,-145.75656,703.8216,304.7745,-1.2281934,634.08563,305.3456,1.3619171,723.4149,437.09177,-41.777504,626.79156,444.16556,-23.622007,736.5289,566.9933,93.849724,618.4889,571.527,120.99711,731.4714,585.0733,97.67331,623.0357,589.0307,125.56777,749.9298,606.89777,-51.25709,608.60516,612.71344,-28.478828\nframe__iwFB8SvDJaw__0018318.jpg,squats_up,945.7147,286.70276,-542.65356,953.7501,274.90222,-496.0838,958.97675,276.19995,-496.0005,964.4166,277.3088,-495.85464,936.72845,271.31424,-511.3425,930.3548,269.89227,-511.1677,924.06165,268.72424,-511.10727,964.8473,286.3411,-249.92392,911.64404,276.04218,-328.1227,952.6298,304.88394,-454.26904,930.481,300.46777,-476.50552,1002.1843,371.16998,-83.05457,840.7348,359.3602,-241.37686,1103.6735,362.45862,48.685314,719.99316,360.58365,-302.94543,1201.2197,349.76108,-99.42699,600.13525,358.9548,-476.39465,1227.368,349.95032,-110.95443,569.2408,359.8656,-495.42892,1234.3666,340.98895,-184.42253,558.73596,350.20035,-557.4511,1224.0092,342.8376,-136.2329,570.1979,352.12228,-511.60617,968.6504,602.0953,81.586235,877.073,598.2991,-81.082886,978.18225,802.2669,84.376945,895.7142,791.9536,-112.27457,956.4946,942.00494,403.57056,907.1621,947.7037,193.74323,941.4874,962.2446,423.6568,908.3287,968.6998,209.55089,973.18774,1004.1969,213.5088,927.8912,1008.38293,-50.681416\r\nScreenshot_2021-02-11_at_16.25.19.png,squats_up,1299.1355,146.43057,-444.58554,1309.5774,119.745056,-402.83594,1317.917,117.315056,-402.75238,1326.5186,114.90418,-402.87094,1284.0242,125.482635,-395.06622,1275.9564,126.70937,-394.82855,1267.8639,128.11511,-395.12732,1344.7802,118.8043,-149.1596,1262.183,134.59003,-113.90917,1320.3411,165.49326,-350.86243,1292.161,171.94026,-339.53793,1435.5944,234.42464,-247.40932,1211.7391,258.30518,-126.61936,1439.2762,261.9079,-900.01306,1160.551,275.78058,-772.4374,1367.5663,178.45407,-1425.0652,1247.0771,213.38466,-1398.4382,1349.5963,159.54568,-1569.2758,1273.688,201.0157,-1551.3219,1349.02,146.95781,-1547.6173,1277.6309,185.3191,-1538.39,1351.8055,159.75871,-1435.4613,1272.6685,194.972,-1418.3281,1397.6249,641.1588,-27.474169,1246.7972,651.39215,27.326164,1433.4924,935.39136,-87.04778,1197.3693,934.4477,-77.85118,1503.9476,1203.6959,144.86475,1164.7234,1200.8096,204.18971,1504.4078,1239.7476,149.88992,1180.0007,1237.4343,212.1796,1509.5018,1280.3129,-190.10284,1114.7434,1284.1381,-97.99107\nScreenshot_2021-02-11 at 15.18.01.png,squats_up,608.5702,130.1036,-67.97145,621.8144,122.128174,-53.65556,626.25256,123.14473,-53.478714,630.809,124.07462,-53.48543,611.54535,119.93591,-33.030846,608.89197,118.94964,-33.00661,606.14087,118.06955,-33.028545,644.32477,132.81671,30.326756,612.40753,123.18494,121.68424,618.0447,145.74391,-39.63051,605.7854,142.28304,-13.237336,675.0268,198.82986,-3.9886916,576.5613,197.8207,163.25363,655.94476,247.1156,-240.36415,545.7792,263.96927,-63.60946,632.12836,166.3206,-380.02518,564.3332,184.71907,-321.5484,628.8572,145.99475,-416.75476,568.39075,161.72942,-371.9309,634.9748,142.18617,-397.77127,569.4339,154.24835,-350.21237,632.5824,148.77785,-374.32022,572.38885,163.11656,-320.75714,646.2682,366.17255,-41.116875,580.47577,368.3822,41.254147,664.7539,506.63828,-77.30603,557.8421,502.18274,-11.536853,686.1584,638.14386,55.56617,537.5744,629.4543,138.43956,690.35223,656.2017,60.810772,542.05444,649.05396,142.38803,682.59174,677.6077,-96.64851,518.2714,665.32416,-9.404755\nScreenshot_2021-02-11 at 14.25.16.png,squats_up,636.8376,68.15397,-437.20844,643.62836,55.113605,-418.36108,649.2533,54.50699,-418.3895,655.07214,53.76125,-418.35165,627.64764,57.58223,-417.97543,621.684,58.543053,-417.88712,615.7104,59.589676,-417.70703,663.8062,64.71599,-298.17828,609.6887,71.71856,-285.2578,649.71075,84.95427,-392.22638,627.9699,87.68302,-388.25046,711.15186,163.66083,-217.89189,573.75055,165.63348,-194.72829,734.5487,275.86755,-187.73125,557.1299,268.74118,-164.24815,727.2402,378.2669,-285.59747,563.5672,369.97556,-274.03342,732.3775,410.95264,-327.92236,558.1715,402.76337,-309.22467,714.4472,411.67603,-363.57513,573.342,404.59503,-352.339,707.17035,398.501,-301.31845,582.82996,391.29114,-293.6723,678.2581,359.9925,-6.565393,596.9158,362.77176,6.6107655,723.3844,507.52136,-11.977394,561.189,509.85507,10.504848,752.5972,640.0532,126.94207,536.5439,633.4254,186.55359,747.9378,659.71027,134.56845,545.7348,654.2904,196.80334,778.81305,691.7943,8.697675,493.6285,682.5753,66.337105\nScreenshot_2021-02-11_at_15.46.30.png,squats_up,1224.6838,194.95364,-715.9543,1236.5361,167.65298,-675.03296,1245.9515,166.14389,-675.0787,1255.5466,164.46739,-675.086,1208.3828,171.11053,-679.68536,1198.464,171.96164,-679.51495,1188.4777,172.90646,-679.62256,1269.7883,172.62904,-383.4529,1176.3761,182.29715,-395.4071,1245.0664,218.27972,-602.6657,1210.905,222.28554,-606.21326,1354.3373,322.05234,-145.89316,1111.2704,322.63452,-151.76857,1404.3708,528.5682,-258.3791,1043.346,516.2074,-306.7752,1292.0184,487.68182,-770.7181,1196.5449,483.6643,-760.1947,1248.9346,488.9554,-886.0354,1248.5125,484.27225,-868.09,1252.8303,448.89703,-892.1994,1247.8693,447.40244,-861.0647,1262.5658,449.4018,-780.506,1236.0009,449.06393,-762.16815,1306.4363,677.97723,0.35809904,1163.5634,682.8987,-0.26445025,1339.0702,947.683,-33.93213,1116.5686,961.3278,-2.8388276,1356.9023,1191.1067,336.10083,1075.6395,1199.2858,407.5178,1343.6807,1229.7715,355.63553,1082.5553,1234.5118,426.79196,1402.8739,1267.1617,60.527653,1039.132,1284.2047,120.859215\nScreenshot_2021-02-11 at 15.23.51.png,squats_up,630.32245,118.05471,-18.65296,636.41547,110.959335,10.45561,640.5779,111.3037,10.467117,644.8567,111.54126,10.45608,622.966,111.043884,5.509315,618.29236,111.2432,5.438544,613.58673,111.51644,5.2901955,649.1474,121.541145,149.51459,605.2629,121.42426,128.8734,637.5572,133.94518,30.967234,621.10004,133.75125,24.443691,681.1275,196.47151,195.03598,564.39233,196.04042,168.00316,737.2428,257.54532,77.01,520.8786,266.70468,45.516953,667.0479,229.46533,-104.38533,598.7782,248.8085,-119.94039,647.6488,230.8567,-149.65848,621.8822,252.0197,-160.2556,639.8384,219.12465,-135.25941,629.02655,237.2285,-153.46487,645.5509,220.42592,-102.3548,621.9907,238.71242,-118.06386,661.4517,361.92538,3.6457078,583.12964,363.75275,-3.2808325,690.2304,502.91754,-34.15219,563.50916,497.8654,-40.80559,714.75775,638.21423,103.64745,551.13684,632.29236,90.59382,712.073,657.9781,108.39304,556.1226,652.4328,93.583374,730.28314,672.5972,-43.537113,537.88055,669.7152,-63.70987\nframe__GUC67V37m1U__0001222.jpg,squats_up,984.0795,302.083,-207.33679,992.3545,282.3861,-176.19594,999.39996,281.47025,-175.93036,1006.59827,280.47787,-175.88907,971.1535,284.47144,-180.9892,963.635,284.88104,-180.89555,956.1054,285.41373,-181.10173,1015.7382,287.72235,34.392544,945.6725,293.26254,1.1038121,998.3517,317.6795,-126.61449,971.3252,320.10626,-136.76753,1057.6704,378.2998,49.341335,906.58386,383.69992,80.62787,1006.0398,464.64944,-194.54782,912.4467,482.23746,-142.02373,922.9711,482.10117,-429.85495,981.0632,504.30176,-415.70648,911.7688,496.05197,-516.6715,998.4927,518.0222,-491.153,901.7793,490.1381,-497.532,1002.56,504.94928,-497.00397,905.68164,484.07053,-433.34326,996.1941,499.32724,-424.41553,1024.3141,612.7596,14.846553,930.1057,612.0783,-14.320354,1008.9354,817.4154,2.4805667,939.6219,816.31384,-95.7037,997.9899,992.20996,279.30524,944.2772,992.71765,166.85542,989.18585,1015.4915,292.8123,947.63367,1013.81335,177.58362,1005.7442,1052.1095,58.73098,949.3346,1057.2726,-75.13436\r\nframe__2cxv842fE2I__0000500.jpg,squats_up,1022.37946,162.10864,-697.9541,1030.0509,145.01309,-666.56476,1036.5491,145.05551,-666.3409,1043.1187,144.91856,-666.42847,1008.8464,144.87192,-679.6265,1001.08203,144.42523,-679.55835,993.2764,144.20905,-679.58594,1046.3639,152.04012,-439.40555,978.24084,151.33768,-490.64694,1032.3538,180.09198,-607.6768,1006.0937,179.67542,-622.13043,1077.3053,245.73203,-231.2188,931.9917,236.00824,-242.39096,1097.7732,333.2246,49.17176,903.67224,329.20465,147.35338,1140.036,396.29697,196.22015,870.9237,409.05862,413.0859,1157.6733,412.7385,226.08752,855.0669,429.11542,487.3307,1155.4584,412.46313,171.13344,854.1213,428.42465,414.7218,1146.0188,410.2123,180.23773,865.1065,425.607,396.06027,1049.6371,471.52875,19.426016,954.0288,472.2755,-19.598623,1077.042,644.3063,30.858421,920.03455,643.19324,-17.537924,1092.3657,794.85236,347.65527,879.33655,796.29614,283.40674,1084.0557,819.2553,363.44623,876.84314,820.4241,296.49054,1112.8433,847.6099,154.40532,870.44855,846.902,70.22334\r\nframe__BZBICKiw9Eo__0011265.jpg,squats_up,1632.6703,336.85358,-784.17615,1667.4283,290.6203,-817.5766,1682.2826,286.8436,-817.80237,1697.4976,282.78305,-818.0196,1640.8722,295.32034,-695.87634,1635.1432,295.1014,-695.9372,1629.3619,295.19424,-695.2958,1754.6965,287.17773,-740.49817,1670.3687,296.85873,-173.40117,1680.0701,368.26837,-748.38824,1642.2303,372.84695,-585.94574,1866.8452,490.3458,-903.9803,1754.9907,522.26996,394.28976,2044.5502,715.0672,-1122.1307,1902.6842,751.13837,556.4271,2054.8743,960.7977,-1344.918,1939.3087,942.08307,232.8447,2084.5007,1024.4346,-1520.9985,1956.6975,1000.16565,197.21982,2028.4706,1035.6531,-1551.7769,1936.8885,994.15717,97.21336,2024.7148,1017.674,-1355.3015,1930.4506,975.2337,174.16957,1898.5266,1081.5881,-411.60474,1825.9353,1072.0267,412.62906,1874.0496,1528.5303,-455.44208,1807.1117,1473.8068,795.3421,1948.2628,1942.9524,-326.18033,1869.1606,1829.9734,1316.3391,2005.6112,2028.3483,-343.16708,1928.1382,1903.9802,1351.6846,1753.955,2031.4939,-739.83704,1666.8018,1927.2952,1154.5715\r\nframe__PYtcl2PbMyI__0011348.jpg,squats_up,1002.6102,254.85938,-53.719486,1015.2245,238.44905,-53.319077,1021.6342,237.23752,-53.27407,1028.1298,235.91043,-53.34915,1001.3839,240.9217,-14.937496,997.3962,241.17467,-15.038444,993.3655,241.57738,-15.196313,1046.2235,239.6485,13.889635,1003.10944,244.40067,187.9271,1020.2726,267.01733,-27.589466,1001.0407,269.0214,22.756605,1069.0403,295.4768,-136.7337,1034.6039,327.05746,396.4388,1028.9329,374.63928,-319.5822,1014.9844,406.9651,273.3016,948.29254,363.36612,-310.61307,945.3309,373.85565,-92.845985,933.4505,361.45605,-352.73627,922.7156,365.57498,-142.93912,934.4259,347.91605,-348.96747,916.5514,353.4102,-165.59206,944.72205,349.46353,-307.71127,924.16943,355.19324,-118.29265,1094.2926,519.7487,-175.62544,1067.3344,528.4103,175.04767,1062.8052,710.6089,-263.4865,1048.2788,706.8886,113.17619,1090.2648,898.4173,-338.97983,1066.4426,890.98376,154.0184,1114.567,934.31793,-358.09756,1088.295,928.51636,143.63324,1009.46423,930.0139,-543.8693,981.39954,920.61743,4.426267\r\nframe__UwW586G8GnU__0020695.jpg,squats_up,597.82336,176.86404,-85.06911,605.8048,166.05719,-94.59708,609.51105,165.23093,-94.60784,613.30505,164.34505,-94.67592,598.926,167.47765,-66.13303,597.3791,167.63968,-66.13762,595.78735,167.83835,-66.060036,626.7681,167.54588,-84.02299,605.1519,170.31451,44.813877,609.09106,185.22145,-77.813866,599.37067,186.7411,-40.881905,645.12,213.19116,-149.20865,623.8417,233.00609,171.52484,652.6337,281.34338,-212.02654,638.12933,300.97708,209.28902,630.9541,343.5207,-243.25594,627.0929,344.63403,129.74461,634.52765,360.2701,-275.94855,624.9823,358.16147,129.17221,623.957,359.33813,-279.58508,619.45197,356.29053,100.3956,625.8104,354.226,-244.81723,621.33246,351.55466,114.49406,660.2674,372.84247,-102.00702,642.9473,376.00436,102.156876,658.4972,499.15292,-119.92528,644.02167,498.18054,76.474815,672.0415,627.4032,-139.56313,658.0087,616.9619,87.18711,686.4648,648.5519,-148.86443,670.359,638.8062,83.15792,625.02295,656.3888,-242.82553,607.0472,641.2888,25.831535\r\nframe__z0u-9E2HmdA__0021044.jpg,squats_down,1392.6389,872.99274,-596.23206,1395.3839,841.1135,-648.2139,1402.5227,837.6209,-648.0437,1409.882,834.13654,-648.2261,1387.5087,841.1482,-552.12415,1387.8977,838.81604,-551.7023,1388.607,837.02,-551.68896,1457.6738,817.06854,-769.20215,1432.0681,820.43896,-331.56937,1437.0992,884.714,-634.7916,1426.9069,887.1351,-506.24335,1624.3151,915.2667,-932.30255,1520.4949,876.36487,-9.67111,1445.6388,1051.7185,-1129.0111,1385.1604,974.68616,452.4739,1249.6116,946.8349,-1035.8799,1263.0006,928.6651,637.7471,1193.584,916.8094,-1129.851,1236.5167,905.47833,684.8449,1219.9886,881.54425,-1128.2273,1239.2064,896.05164,631.0513,1242.6837,893.358,-1033.7507,1251.9818,910.8944,615.1415,1888.2332,1203.6652,-274.10178,1801.8881,1181.8481,274.8385,1723.2667,1357.228,-615.66815,1580.5072,1324.0195,639.9809,1749.008,1683.2042,-402.18073,1619.3108,1570.2302,1065.397,1782.5105,1753.7308,-399.18365,1655.895,1625.7258,1100.064,1613.7046,1760.8972,-643.3461,1483.9124,1639.045,1041.1631\r\nframe__GdxOW-GswaY__0001091.jpg,squats_down,1168.0619,546.609,-74.18532,1157.4982,530.05023,-50.1245,1153.5824,529.5572,-50.162407,1149.8281,529.07477,-49.903976,1158.4983,531.09845,-110.52635,1155.7485,530.5346,-110.37169,1152.837,530.1353,-110.48823,1121.8944,535.11786,52.048004,1125.0493,534.71594,-224.20212,1151.5593,566.1953,-35.5237,1153.1212,566.13855,-113.33799,1057.8776,621.5781,232.05061,1083.3129,634.6613,-371.86578,1164.8907,702.97156,352.02655,1199.3921,747.4661,-289.97736,1224.2716,647.2272,305.94534,1245.0461,651.0141,2.3634405,1243.5509,616.77167,334.8427,1265.453,617.4047,-35.662647,1239.5355,613.8682,314.09427,1242.522,599.42847,-47.571457,1231.2114,628.7009,295.77283,1230.263,616.77594,7.9590745,941.15125,806.62036,194.81866,946.01404,818.3137,-194.29985,1099.8417,755.37604,379.4982,1148.1335,759.0596,-262.14594,1001.9301,892.4003,520.8049,1007.06305,912.30237,-142.87206,967.69763,918.47546,537.17474,965.79114,936.71625,-131.77289,1060.0304,933.1774,599.5958,1048.288,962.9434,-101.40349\r\nframe__SdnNJKUOXsQ__0009920.jpg,squats_down,1271.5388,579.0627,-88.11853,1272.5691,561.819,-74.36977,1270.3644,560.7485,-74.35687,1268.25,559.7979,-74.28022,1272.6475,561.899,-126.19672,1270.2296,560.43256,-126.10266,1267.6804,559.1899,-126.18697,1244.5308,559.4625,44.201828,1243.7117,556.5501,-199.32095,1252.6095,593.4741,-43.94202,1251.6458,592.85223,-112.46369,1162.7343,622.34924,233.10338,1185.814,646.3883,-303.62012,1222.5558,731.9444,277.511,1249.8455,767.7288,-227.76181,1279.5542,672.5185,219.01723,1299.4487,668.7722,65.979935,1301.6808,644.4181,259.42593,1321.1421,638.7071,51.61869,1287.5536,641.25824,273.1966,1299.2596,628.6331,41.705837,1278.3387,655.22687,222.18999,1286.8696,643.2105,72.69864,954.68854,742.4604,177.87663,961.8729,760.37427,-177.29668,1118.5842,734.9052,452.7534,1179.3462,763.6287,-201.33917,1046.1516,876.457,652.0071,1071.6337,933.9223,-202.3867,1017.1367,905.7318,674.20154,1033.4243,967.24945,-206.49953,1111.8512,905.6547,723.44763,1143.6262,972.4708,-203.23158\r\nframe__H0_1sulrkr4__0004974.jpg,squats_down,909.7846,563.98016,-522.2532,918.99365,540.96185,-504.08008,926.92456,538.55884,-503.94354,934.9609,536.1916,-503.91614,900.43317,547.0911,-481.91757,893.9862,549.13293,-481.64548,887.77625,551.3969,-481.47885,955.45935,542.90735,-360.89603,894.8253,562.0177,-261.11588,932.0969,577.2599,-468.28418,904.7363,586.36725,-439.54684,976.3529,626.5865,-500.57315,934.1875,609.71185,30.520285,853.8733,671.4997,-617.12775,818.848,671.1775,17.735498,727.5941,649.5395,-567.9029,731.1341,639.9453,-184.30196,691.9994,642.2137,-647.22394,706.8534,622.6916,-205.70909,691.3517,627.7006,-606.9839,709.7741,616.85455,-246.35448,708.3157,632.64905,-557.17346,719.47095,626.68933,-209.62344,1111.7622,806.07764,-176.79395,1077.2009,777.44684,177.32358,914.13354,825.18567,-203.5704,912.31213,756.0099,336.31253,1004.989,945.5635,111.36931,991.7756,888.9687,560.23126,1043.6165,961.9882,142.47678,1026.1974,904.99097,577.6859,942.5023,982.3944,132.6147,936.15625,944.2183,588.9684\r\nScreenshot_2021-02-11 at 14.50.05.png,squats_down,379.0448,280.25995,-265.73706,384.37827,268.31192,-246.84511,388.7015,267.9618,-246.75737,393.07397,267.58105,-246.67613,371.43317,268.4912,-248.8305,366.71185,268.16888,-248.77432,361.97952,267.9727,-248.8159,397.24133,269.2459,-120.32651,354.30093,269.47916,-127.821045,385.48495,289.67548,-216.90875,370.46878,289.92758,-218.91801,418.7674,306.1129,-80.43823,327.15875,302.1602,-96.91045,459.28073,322.41763,-291.43417,293.8748,330.86154,-333.13342,438.56354,255.22383,-441.1024,339.0724,274.72333,-484.2508,439.78336,232.40175,-484.78378,348.5045,255.85748,-516.6464,432.8193,231.112,-448.39432,354.1424,254.05502,-482.20563,428.69315,241.88486,-434.0938,354.40866,264.11853,-473.60693,399.20123,420.0872,9.100037,342.37985,418.1624,-8.806217,458.64374,446.96033,-387.94193,308.56522,450.15903,-412.51263,434.9775,521.8132,-124.95,313.80502,524.85944,-156.70143,420.89532,533.476,-105.757225,321.80038,537.1974,-138.64354,460.88412,554.95825,-240.77054,300.68488,555.26416,-284.86887\nScreenshot_2021-02-11 at 14.45.33.png,squats_down,490.85468,256.64386,-199.85658,496.7931,247.31546,-178.75163,501.62677,247.27359,-178.7355,506.50278,247.15137,-178.82913,483.29425,248.56131,-180.7562,478.18915,249.13347,-180.67511,473.09308,249.86386,-180.66603,513.21515,257.18082,-76.67204,467.2919,260.77148,-82.83062,500.71588,272.44604,-164.95084,483.0802,273.62784,-166.4828,546.7092,318.44458,-45.71454,440.70508,325.96207,-47.51173,604.6376,380.28485,-173.26329,396.52338,387.9246,-164.66502,608.2679,314.36707,-308.60623,385.44446,319.8998,-312.48654,613.49585,293.81558,-338.03156,378.0554,301.8476,-335.49347,606.4191,282.84476,-322.8561,383.89694,291.15414,-325.15454,600.29285,294.6249,-308.3603,392.56305,300.60538,-311.80792,536.5301,458.99326,-0.86516744,475.5592,462.65463,1.1326483,599.93555,399.33453,-247.65138,405.63477,416.91678,-227.66426,570.34344,522.449,-135.00638,430.62552,526.9879,-122.79691,556.3255,542.0815,-125.14865,447.46,548.67206,-113.77427,587.8724,558.359,-213.77402,398.3442,560.2582,-191.85564\nframe___0CAcnhL5Sw__0015561.jpg,squats_down,1132.5985,607.4845,-623.79846,1129.3186,591.64636,-589.67993,1130.1295,591.52856,-589.60175,1131.2534,591.5219,-589.2263,1119.0901,591.564,-633.221,1113.0607,590.77075,-633.22845,1106.9028,590.0717,-633.1295,1107.9688,595.3392,-391.92703,1074.9086,590.65326,-592.12115,1117.2603,624.0012,-548.1352,1106.0472,622.76337,-605.7207,1080.2869,650.5406,-252.57408,956.4697,672.5146,-558.9029,1100.6373,779.37683,-441.6973,944.9617,847.5111,-567.05524,1140.9764,817.0601,-862.4929,1079.7267,843.95056,-549.05383,1168.4697,822.837,-944.02014,1115.7515,848.69745,-620.41925,1160.0017,806.73236,-929.3905,1125.4012,815.98035,-604.21906,1140.8906,810.1039,-871.2814,1110.5723,815.55597,-544.45984,951.1403,764.72,102.81899,858.11505,783.8925,-102.840576,1099.5692,763.58655,-17.296085,888.3669,852.83606,-740.06866,1056.3402,888.7666,232.78119,799.82086,1001.2991,-482.3544,1024.3771,905.836,254.93617,775.30475,1023.84216,-468.33978,1112.7117,958.36755,176.35623,837.22675,1082.7911,-694.97894\r\nScreenshot_2021-02-11_at_15.52.34.png,squats_down,1324.1783,564.13074,-284.70593,1338.3168,547.779,-227.29422,1348.0616,547.4344,-227.4071,1357.8589,546.8981,-227.5699,1310.1321,551.723,-221.4129,1300.6865,553.46423,-221.28418,1291.1925,555.477,-221.23119,1377.8806,567.71686,0.6434647,1284.4247,578.5723,26.146513,1347.5233,596.068,-210.86765,1313.2336,600.04486,-203.99815,1456.3508,716.5112,33.376755,1232.2623,728.9849,90.55216,1514.5835,902.6101,-230.69981,1191.4349,928.8232,-210.05205,1379.464,788.12286,-456.6674,1301.9674,796.82654,-579.8254,1341.2921,752.1694,-506.77106,1333.1797,762.30945,-632.4857,1344.9213,725.2481,-432.87244,1325.4664,729.43066,-578.19965,1347.8159,743.20825,-428.6562,1326.46,747.6219,-558.0861,1424.7341,1002.8579,-5.252061,1281.5624,1005.81915,5.7609577,1570.721,999.1766,-732.47437,1135.3895,1021.58655,-665.4549,1495.214,1231.3693,-231.18439,1198.9088,1247.6147,-248.15135,1458.2242,1273.3135,-189.85844,1236.081,1285.8816,-212.90115,1573.183,1295.3661,-408.1654,1127.263,1333.1626,-431.3052\nScreenshot_2021-02-11_at_15.46.08.png,squats_down,1247.0944,661.24585,-1393.8031,1259.6661,635.1298,-1350.1426,1269.6625,635.2258,-1349.9893,1279.5405,635.2133,-1349.7509,1231.1665,634.54254,-1354.9949,1220.743,633.83795,-1354.6053,1210.2955,633.3149,-1354.7046,1287.6383,640.221,-1041.9629,1192.954,638.57574,-1072.2786,1261.2379,683.96826,-1275.4884,1226.5397,682.0329,-1284.559,1347.3778,732.4201,-809.6766,1117.0973,748.25684,-831.8703,1403.2832,917.57227,-1242.1312,1096.9026,940.81226,-1281.1434,1302.0685,828.5984,-1768.7245,1198.7797,811.0505,-1793.3138,1265.5017,809.117,-1849.3738,1227.9285,773.17865,-1872.695,1275.6045,763.76056,-1781.5424,1218.9362,743.6036,-1794.4962,1277.0149,775.65173,-1740.9917,1220.6976,758.4985,-1761.4219,1310.9348,897.4014,-4.545271,1177.6719,907.7224,5.038305,1367.2041,968.354,-822.69806,1084.5942,997.4961,-771.95703,1374.8955,1195.2054,-421.29803,1100.7135,1198.457,-339.95236,1367.1213,1222.3794,-393.1681,1115.0355,1231.0436,-313.07748,1385.3131,1292.157,-697.92865,1072.3221,1271.2302,-609.6981\nScreenshot_2021-02-11 at 15.08.23.png,squats_down,601.4823,300.8926,-193.0024,607.72705,288.21274,-167.54953,612.7588,287.80054,-167.509,617.86865,287.34387,-167.64716,593.2513,289.55463,-168.91144,587.86053,289.84525,-168.75757,582.4832,290.29556,-168.7119,624.9706,294.45203,-38.120125,575.9531,298.35962,-43.537056,611.82837,313.94907,-148.23427,592.27203,315.3483,-149.81006,655.3757,350.57654,-27.946379,549.61414,354.17126,-25.678207,703.3117,385.4754,-283.23544,510.7867,377.11862,-288.77472,698.4253,339.58173,-528.2323,502.10144,330.2048,-550.93085,706.2885,325.6747,-575.2862,495.4603,320.98416,-594.8292,695.39435,323.58005,-551.5177,502.4127,316.31393,-582.81775,688.57275,332.04358,-526.0425,509.0589,323.57272,-552.42786,641.31604,501.9582,0.13275507,578.16376,503.29968,0.30848327,689.95734,499.4357,-399.05475,530.05865,497.6665,-357.56516,666.6382,610.9093,-230.8046,546.29016,607.779,-211.10484,655.7215,621.1216,-218.84712,557.10126,622.7097,-201.20555,674.4032,662.0191,-352.30072,536.3189,654.1689,-322.30728\nframe__0LlT7MSKJBc__0025382.jpg,squats_down,905.5431,513.29614,-987.7725,914.3335,491.75256,-952.0776,922.2196,491.12048,-952.1164,930.0442,490.3585,-951.96796,891.4789,493.48608,-950.4033,882.99896,493.78207,-950.2726,874.4381,494.27295,-950.2489,939.8132,497.8253,-715.6325,860.8796,502.5391,-704.07336,920.13586,531.437,-897.40607,890.13116,533.1743,-893.75507,991.0651,588.39124,-539.97327,815.45526,589.32495,-542.55,1024.0308,741.3166,-751.7199,771.84595,744.8281,-793.35693,925.204,723.0161,-1031.8741,898.0743,734.45264,-1067.4944,893.1207,722.3116,-1103.7876,931.8575,736.1123,-1136.0763,892.5107,698.9355,-1073.834,938.16705,715.5338,-1098.3131,897.1077,701.26495,-1023.0041,931.8856,717.0768,-1052.6774,953.7171,757.9393,-14.162571,862.39825,753.0714,14.556789,985.6748,781.0637,-768.8054,826.1596,789.8714,-706.86316,949.25903,916.64514,-250.79724,843.7774,913.60345,-201.12105,939.2946,932.4753,-213.48827,856.5927,930.0611,-163.12315,954.03784,977.91003,-494.37756,813.4325,976.0396,-418.20966\r\nScreenshot_2021-02-11 at 15.56.33.png,squats_down,598.7415,334.22324,-550.09326,606.78394,318.80124,-529.82355,612.5087,318.50815,-529.7727,618.2018,318.05255,-529.9449,590.276,319.7647,-525.3167,584.64343,319.7728,-525.2441,579.02795,319.95435,-525.49335,627.9871,320.43576,-369.02277,572.26276,323.40118,-360.28845,609.36584,347.24524,-487.45245,590.3242,347.68286,-484.58282,680.1117,379.34363,-234.82567,530.0962,383.7526,-227.7534,738.8294,477.35547,-368.51874,500.39267,466.0578,-355.28397,705.98846,469.04193,-689.1576,497.7375,472.19263,-726.9958,696.6392,467.6626,-769.7129,492.0448,477.2171,-820.1895,691.20197,447.44806,-763.0303,499.0614,459.55893,-825.6905,686.0449,452.4836,-694.7296,508.4492,459.95352,-739.8802,655.05176,504.36734,-2.65769,576.19556,507.45786,3.2754753,740.55273,498.8455,-493.482,490.00806,516.25366,-477.09003,713.4113,636.4712,-219.63928,498.6848,636.8342,-214.11705,697.4339,655.4657,-201.65625,511.1838,657.6725,-195.72739,737.30206,680.6503,-390.1228,475.43985,669.8058,-373.71652\nScreenshot_2021-02-11_at_15.47.33.png,squats_down,1248.6019,661.1905,-1274.5609,1258.7994,637.1896,-1222.1648,1267.8271,636.52527,-1222.093,1276.813,635.70844,-1221.9573,1231.0282,639.8414,-1229.3695,1221.1019,640.5338,-1228.9679,1211.1427,641.43665,-1229.0419,1283.0729,642.51337,-918.9008,1194.0719,649.8932,-945.936,1262.9546,684.3243,-1161.5758,1230.9644,686.2031,-1169.712,1348.0011,744.7678,-708.9705,1124.3103,766.07684,-746.3372,1420.0652,904.2651,-1160.5509,1088.9554,937.11224,-1212.6791,1293.9911,816.09186,-1678.26,1200.1138,819.2237,-1677.156,1254.1714,795.07654,-1764.3931,1221.9359,782.2395,-1752.9524,1258.4042,760.6626,-1684.4027,1223.8342,762.4065,-1667.281,1264.6779,774.9029,-1649.4014,1226.7605,778.7087,-1642.9613,1309.6544,919.0191,-0.21771443,1178.1002,932.1115,0.32837373,1397.595,975.60535,-862.57837,1094.1763,1006.3422,-826.3985,1371.9851,1193.396,-445.1643,1094.8098,1206.0641,-405.11966,1355.8363,1227.065,-419.71384,1108.7604,1241.7795,-383.7721,1401.4354,1272.235,-741.9892,1063.6581,1277.0682,-709.5707\nScreenshot_2021-02-11_at_16.08.04.png,squats_down,1655.086,441.33994,-1077.4698,1666.5308,422.52158,-1038.4739,1677.0007,422.3569,-1038.773,1687.6979,422.16022,-1038.7001,1635.4354,423.67697,-1033.824,1624.8887,424.57687,-1033.7969,1614.1595,425.65848,-1033.8132,1704.3436,442.196,-770.75085,1601.2201,445.21893,-743.046,1675.7327,472.87073,-979.5068,1639.0942,475.54105,-969.04266,1775.6543,582.80695,-567.7803,1540.334,565.8686,-639.082,1859.3156,734.38513,-1098.3131,1483.7117,728.6386,-1132.9503,1749.4214,604.163,-1652.5157,1597.573,601.5663,-1633.1562,1730.8646,566.93445,-1750.4645,1629.0199,558.4905,-1716.6055,1717.6898,553.0271,-1656.7877,1623.7993,539.1784,-1658.485,1714.2435,573.59076,-1626.9576,1622.6515,565.7442,-1619.7914,1657.1967,826.64496,29.428364,1517.992,814.3529,-28.520206,1822.7081,864.31305,-751.79425,1441.1655,843.955,-983.60236,1759.2461,1075.3511,-295.23227,1476.2892,1086.2292,-445.47513,1719.3619,1114.0352,-263.1834,1494.7843,1121.9615,-407.98306,1837.6619,1159.1678,-526.6806,1467.263,1172.7831,-733.88464\nScreenshot_2021-02-11 at 15.22.45.png,squats_down,153.40497,298.40964,-71.10616,157.73853,289.71252,-49.91151,161.2815,289.39822,-49.780277,164.8768,289.0071,-49.692863,146.6259,290.88354,-51.662163,142.64719,291.20013,-51.61157,138.65823,291.605,-51.625145,168.78528,294.23886,61.989273,131.63493,297.45004,57.0344,159.66216,308.1356,-30.627089,146.21487,309.3961,-31.966896,187.31258,335.7477,81.07638,114.1844,334.8186,48.601597,203.62779,365.7629,-104.119576,100.624825,360.49402,-186.19603,146.05135,361.88428,-219.57967,156.3698,336.92004,-322.757,133.90018,361.69797,-253.59457,167.40215,330.78152,-355.65656,126.466675,357.52518,-228.11653,173.39029,331.23407,-323.669,130.50037,361.14694,-214.20311,171.76231,336.9057,-312.86435,179.07642,430.81018,5.9375663,131.35016,431.7813,-5.7596455,234.21082,453.49884,-303.07693,86.74811,454.58865,-311.8192,207.56311,524.884,-60.315044,108.42746,526.7245,-52.187855,193.81674,536.1637,-41.710148,120.639786,539.7722,-30.815187,229.83305,560.6686,-154.82086,85.36002,562.0166,-141.58214\nScreenshot_2021-02-11 at 14.52.07.png,squats_down,513.3796,269.7723,-172.91301,517.6315,256.05063,-150.76723,522.1559,255.25151,-150.79951,526.70654,254.50024,-150.78522,503.70062,258.1497,-151.56874,498.9669,258.52786,-151.56178,494.20453,259.06122,-151.67267,532.22095,256.90454,-38.39567,486.39127,262.7707,-25.490658,522.44104,279.11243,-130.40532,505.17102,281.08078,-126.39082,559.1808,296.49518,-93.121544,463.25845,303.79364,-79.547905,580.3184,271.61887,-399.9513,441.57104,299.4925,-378.75943,593.7542,249.8815,-689.5866,422.62845,268.1417,-652.2726,602.6442,242.97205,-766.5175,414.3471,260.71985,-717.9645,589.8119,238.549,-769.3434,426.5655,248.8697,-733.4904,587.1528,245.54784,-705.42523,430.3717,255.76003,-670.6592,551.52875,434.05957,-5.64942,484.6867,434.74045,5.866481,589.9701,438.06897,-423.71274,444.9427,432.16757,-386.75958,572.2305,547.49713,-388.17084,448.91046,551.3273,-354.4179,566.8562,557.4201,-389.76355,452.86978,564.68036,-357.84067,569.04895,595.7639,-538.3858,444.83032,600.28284,-510.27856\nframe__8ghtQpeWov8__0007065.jpg,squats_down,1114.1753,599.0659,-325.0323,1120.4558,581.07306,-300.87656,1121.0574,581.19525,-300.85864,1121.8352,581.4395,-300.87485,1114.9307,578.28094,-348.39142,1110.9579,575.0856,-348.4201,1106.963,572.20233,-348.4895,1103.6262,575.0616,-152.00792,1085.5852,563.2513,-372.77386,1099.2871,608.60345,-267.0913,1092.416,604.51965,-328.648,1069.5433,603.2652,46.3011,1017.4955,606.91626,-454.708,1188.5352,634.1548,92.96989,1120.2333,687.17664,-601.7694,1275.189,640.05707,-95.22719,1255.4124,665.8289,-655.3165,1297.2449,645.66736,-108.417,1286.663,667.5876,-732.4752,1289.1382,632.24255,-155.41626,1291.576,645.2094,-706.19006,1277.2186,635.31006,-123.86096,1277.1047,647.72784,-647.4908,929.59753,749.2871,161.92181,881.6737,755.15607,-162.04861,1063.648,731.45074,332.8626,1016.2539,756.0021,-570.4864,1005.4534,865.5733,510.47922,964.61163,920.85114,-518.2354,977.50214,888.176,530.08813,936.89087,942.5167,-512.99426,1051.9775,905.89233,499.96423,1030.8724,983.407,-652.0945\r\nframe__jBY85tpUliY__0022348.jpg,squats_down,1000.5394,530.60986,10.133388,1009.2359,515.90314,-25.887436,1012.23016,516.2792,-25.708406,1015.38885,516.6245,-25.678762,1008.23413,512.68866,34.95655,1009.8262,510.7725,34.980824,1011.48755,508.98233,34.77438,1038.9468,522.52936,-124.2231,1034.979,512.3948,144.39056,1015.3176,548.1575,-25.63961,1012.10266,544.4349,51.75706,1100.2998,600.82495,-281.3387,1061.8727,596.0955,267.60022,1024.8938,719.1773,-264.68927,1036.5166,699.59985,50.09436,1004.9999,615.8464,-41.522884,1018.0983,629.822,-344.73337,994.501,591.37274,-41.74288,1002.8611,610.62067,-376.6477,1020.6411,591.5655,-61.213432,1014.45764,602.564,-347.91196,1029.3164,601.91125,-39.145634,1024.7328,610.49255,-344.66858,1185.7109,793.9514,-163.49889,1146.802,782.36957,164.1517,1025.8337,787.55615,-286.59235,987.24097,758.397,239.79497,1113.2783,928.3765,-109.766685,1093.7375,882.2976,205.37796,1152.0487,943.0571,-84.69401,1130.0883,895.81616,205.06053,1060.7875,989.747,-85.43549,1052.6277,940.627,213.9099\r\nframe__4zBnM_uozXM__0001262.jpg,squats_down,840.8986,206.8699,-192.44792,866.67,186.89203,-211.64674,874.1532,186.84413,-211.49423,881.74084,186.54898,-211.30199,857.7738,187.52519,-146.88356,857.98785,187.93532,-146.87206,858.3085,188.85901,-146.6956,922.8648,201.36919,-242.56161,890.4652,203.0845,40.475376,865.65735,236.38065,-207.53918,853.0137,237.254,-125.22462,972.5442,325.42313,-368.58813,915.8441,354.53485,176.44815,801.4396,445.0818,-482.82675,793.0442,473.85306,189.01425,614.64465,522.4231,-444.2086,641.5223,532.1866,130.86674,573.9919,533.9589,-507.79868,599.7275,530.6298,153.4935,570.6477,519.69586,-487.74078,590.24207,523.2528,107.86929,587.8041,520.3989,-438.0755,606.57605,531.3767,107.452286,1134.4026,609.8062,-151.39061,1064.21,615.2819,151.86574,1009.5495,575.753,-692.2734,849.87256,610.52094,70.89315,1072.8279,817.22327,-503.5362,946.83307,788.5366,302.5108,1100.8331,860.28973,-496.04874,992.47034,816.68695,323.1848,965.6173,878.8489,-702.5543,844.0283,853.46356,264.97156\r\nframe__yWky9j7mG2Y__0013256.jpg,squats_down,971.3902,546.87775,19.758244,961.8314,530.6922,39.4982,958.56445,531.1777,39.55802,955.5079,531.7633,39.838543,963.1627,529.0622,-14.587221,961.1506,527.66406,-14.581621,959.05566,526.52344,-14.785871,931.2681,541.5903,146.60211,936.2124,534.0659,-104.67293,957.54553,568.95935,51.45538,957.6008,565.57355,-18.586046,891.7641,657.7975,282.6661,893.9559,653.94714,-273.83038,937.00146,790.9996,134.5656,952.6945,798.7621,-123.819565,962.41724,685.0459,-249.30951,973.2875,681.22424,235.16573,972.6497,648.3116,-275.79474,980.67456,641.90826,240.30176,953.75366,636.63306,-240.0943,959.58856,628.671,229.04749,945.2053,648.9315,-247.71094,952.8823,648.18427,245.17215,762.81866,871.7478,189.82549,752.47687,866.9699,-189.3076,973.29987,802.0182,222.99933,985.46747,767.0479,-208.18513,872.4319,950.45105,199.0692,865.5142,971.6769,-125.61565,845.54956,972.4102,199.68776,826.961,1002.96875,-114.8688,920.5746,983.13464,219.79143,913.87726,1036.0814,-87.489784\r\nframe__TmsDaoMsHDk__0004413.jpg,squats_down,768.9279,359.2276,-351.6554,770.02264,348.34592,-324.95242,771.6655,348.9594,-324.98264,773.40173,349.63553,-325.07047,762.3829,347.01392,-354.5558,757.79443,346.05103,-354.5122,753.3125,345.3236,-354.54163,761.7444,355.0978,-185.7483,737.95215,349.9604,-323.1856,765.5481,372.96442,-299.7627,754.8375,370.55734,-338.29175,734.67444,403.9808,-1.6745483,709.30493,407.84613,-400.6922,823.94073,411.2882,38.358643,811.4697,438.53876,-491.88297,908.1674,396.50146,-98.10556,909.7162,418.017,-521.7931,929.6023,387.08176,-111.01628,932.95056,413.6625,-596.925,925.5448,382.53656,-156.08138,931.9768,401.56335,-578.3394,917.4253,388.6852,-125.02349,921.8674,405.20096,-518.87463,653.3739,540.4656,120.60574,629.078,554.3023,-120.45447,749.0827,546.3853,280.40955,753.72766,587.00494,-286.02298,689.8654,632.3987,432.7028,670.347,665.5666,-131.95273,668.7593,645.3306,445.63275,644.70105,671.7765,-115.82239,724.10516,654.6396,464.84735,696.17706,687.0005,-124.190765\r\nScreenshot_2021-02-11 at 15.41.25.png,squats_down,501.15585,244.38379,-377.73166,505.60184,234.13576,-348.28177,510.08774,233.92781,-348.16876,514.5654,233.59998,-348.19754,491.7399,235.37836,-347.79025,486.6645,235.7189,-347.56018,481.56433,236.21194,-347.61255,518.0639,238.7083,-197.97969,472.38745,242.43407,-196.63228,509.03674,256.89246,-323.40817,491.80142,257.80817,-323.277,554.3942,300.20056,-155.92816,434.41608,304.31094,-139.31894,588.3413,380.2718,-403.87976,413.8884,381.78973,-380.70047,528.66113,351.8618,-681.2374,472.5594,346.27878,-664.13446,512.12445,347.57617,-735.53827,485.78848,339.9898,-718.0356,510.7146,331.46448,-704.5059,489.79684,327.93277,-687.8681,513.23236,336.37314,-673.19214,489.20773,332.60284,-655.56146,535.1963,439.72498,-10.495137,463.59186,446.4394,10.8941555,589.3977,465.40045,-487.19836,414.81393,482.6587,-454.69974,567.4818,594.5466,-262.5658,434.30072,603.29865,-245.39835,557.6291,608.819,-249.77977,445.68896,620.9488,-232.77214,574.90985,648.2491,-435.99963,417.53787,647.8501,-409.0354\nframe__Qzd8oJyKQaI__0010512.jpg,squats_down,1094.2374,501.91064,-39.965782,1081.9769,486.76126,-20.962868,1078.9244,487.08203,-21.00233,1076.0039,487.44458,-21.100424,1081.5215,487.5629,-75.90349,1077.9042,487.79813,-75.8473,1074.2949,488.2365,-75.81557,1050.7501,499.52753,81.81227,1046.8689,499.25336,-170.14484,1081.949,524.2716,0.25939488,1081.3163,524.81757,-71.839455,1006.9196,613.6358,235.53583,1016.525,602.11346,-293.5395,1120.3136,680.90314,241.50595,1134.3146,696.0107,-246.37459,1172.659,594.7687,144.24194,1177.0426,597.9835,4.884103,1186.6119,558.5457,148.225,1195.1954,562.64435,-37.62065,1180.4497,552.3881,136.38225,1170.7931,551.6139,-37.66852,1175.31,568.4646,133.47531,1162.9282,568.9351,9.846618,905.2439,831.38617,174.98445,900.41797,830.09314,-174.28018,1056.7101,799.9371,391.2307,1069.0834,806.09247,-278.90195,991.2877,943.4735,519.9217,979.07855,988.1311,-260.97406,962.29626,965.3913,526.73865,944.86566,1012.61255,-258.23944,1036.3501,971.28107,549.67285,1027.6064,1026.4744,-271.4128\r\nframe__zbt1g9WX6bA__0016235.jpg,squats_down,1842.5702,1248.7737,-1789.3533,1863.1316,1199.6272,-1764.4834,1876.0095,1198.0524,-1763.647,1888.6521,1196.0378,-1763.8167,1825.8315,1199.3466,-1755.0764,1813.9631,1196.9515,-1754.7736,1802.0071,1194.9995,-1755.3804,1915.736,1181.2822,-1369.8738,1789.6466,1178.9984,-1342.435,1865.6586,1267.5842,-1624.6694,1828.2922,1266.7748,-1618.5734,2024.0929,1299.005,-909.5443,1696.4525,1277.2764,-898.32733,2055.3599,1552.7284,-1361.8024,1637.9974,1511.4644,-1350.219,1895.5594,1479.7115,-2145.9824,1773.0851,1484.3638,-2113.8423,1849.7626,1445.693,-2346.8071,1814.6964,1469.1567,-2294.0151,1852.8914,1401.3519,-2259.4304,1818.8728,1429.1846,-2225.6917,1850.2756,1413.9829,-2133.842,1819.2391,1438.3198,-2100.696,1932.357,1544.8632,2.3622065,1749.5298,1531.008,-0.77577025,2105.4219,1579.398,-1283.7897,1610.8986,1589.7533,-1236.8882,2099.7368,1891.6628,-601.63837,1592.5756,1892.5016,-601.46155,2077.27,1949.3596,-553.9591,1614.1704,1951.935,-566.72015,2158.729,1994.3552,-1018.4856,1530.4493,1984.3252,-1053.3572\r\nScreenshot_2021-02-11 at 15.48.09.png,squats_down,624.27527,403.58105,-277.0543,629.2763,395.30017,-253.57156,633.2934,395.4029,-253.58818,637.3639,395.41544,-253.58757,617.0528,395.40353,-257.07297,612.5671,395.41504,-256.9379,608.0665,395.53204,-256.91992,641.80475,401.46094,-128.92778,599.71155,401.38364,-144.1008,630.5617,415.01437,-231.12083,615.4874,414.82996,-235.5798,668.41327,443.2959,-108.00967,572.9466,441.2597,-140.07808,696.2183,486.65292,-331.47522,569.2205,482.13428,-376.8874,633.6216,489.10635,-486.88815,632.15485,470.57526,-538.0562,618.85815,494.49017,-518.5047,645.6546,471.2415,-574.2084,610.05365,487.30884,-492.36295,651.41907,464.57175,-549.4058,613.55994,489.60776,-479.44678,648.55945,468.75082,-529.5911,648.2463,543.68744,6.1409025,586.8566,543.1594,-5.830591,691.53235,556.61584,-354.85385,550.08154,551.992,-391.7371,674.63617,661.008,-200.56746,557.56683,658.08905,-215.58441,662.5328,679.2334,-192.49562,566.2023,677.25995,-204.93855,698.3844,694.87665,-321.04712,539.526,691.60077,-337.50717\nframe__bXyhN4CK0_8__0006178.jpg,squats_down,990.27594,370.8922,-747.82043,998.53625,343.70847,-712.4156,1008.7342,343.13632,-712.30304,1019.0657,342.41248,-712.402,967.90704,345.2218,-727.9385,955.2701,345.408,-727.8012,942.62195,345.81863,-727.42395,1019.39734,355.97705,-457.28235,915.7251,360.23138,-509.56827,1002.7454,398.68195,-651.1565,963.0385,400.37106,-664.8473,1064.3472,456.75745,-327.34888,849.45575,482.27917,-374.79694,1170.5876,550.1345,-614.34344,845.1011,648.4962,-621.8459,1273.7686,505.755,-1044.701,834.97974,511.3293,-1030.5952,1321.4512,490.9889,-1123.8551,821.70776,471.32483,-1115.3989,1306.5156,483.47964,-1152.2782,823.1419,441.44736,-1100.9932,1282.977,494.87387,-1074.5702,834.81824,457.1989,-1039.1812,1015.5921,744.85236,10.196785,880.35175,754.73914,-10.118269,1220.8246,820.70764,-469.2521,701.1951,873.9758,-364.34094,1148.4753,947.36786,92.60675,703.94946,951.8097,231.8034,1105.0006,962.12354,140.11748,727.54877,967.31067,283.7491,1215.6136,1061.2205,-12.647047,641.4751,1038.8987,132.90741\r\nframe__ohPA6wqX24o__0002899.jpg,squats_down,1108.9998,486.11484,-532.2491,1109.6182,469.59784,-512.4155,1111.251,468.61588,-512.3662,1113.1608,467.77844,-512.2274,1100.2457,471.19644,-553.64935,1095.2152,471.09924,-553.57715,1090.1896,471.16644,-553.7223,1098.9208,470.99753,-343.90424,1069.7329,475.32303,-530.6117,1102.9348,499.30624,-466.05762,1091.7067,501.42682,-517.43994,1066.1926,532.33386,-104.0911,1006.56683,541.5618,-555.2438,1056.9081,628.65076,-97.668236,999.3781,684.10724,-584.99664,1092.9807,581.8728,-322.9349,1084.5795,595.4673,-482.83643,1105.8105,568.35144,-353.72488,1114.759,576.2436,-501.5153,1102.6626,555.0794,-351.756,1100.8057,551.23865,-501.9235,1095.7765,560.4179,-328.78726,1092.642,560.4027,-475.28375,919.5298,662.76056,167.34627,877.84076,675.6361,-167.59216,1072.2743,693.2039,15.694948,1028.6074,742.2324,-344.19226,963.6281,841.65,131.08055,921.4596,871.9405,-223.03104,923.5814,861.76154,141.66135,877.6502,887.05365,-211.35309,1009.992,893.4213,89.901344,976.8363,920.4464,-273.49432\r\nScreenshot_2021-02-11 at 14.31.53.png,squats_down,453.13733,235.61917,-76.99778,457.30728,228.82895,-67.251785,460.1938,228.60936,-67.20818,463.10968,228.3469,-67.242096,449.24747,229.6674,-67.22755,446.43848,229.85077,-67.20269,443.61804,230.11786,-67.23365,468.1537,231.80481,1.1062067,440.59717,233.72986,1.5849648,458.61215,243.53723,-50.82246,449.15717,244.3745,-50.415997,489.8405,263.93378,20.370827,421.56076,266.96487,23.421638,501.5972,309.19806,-62.049854,416.11,317.5782,-57.78272,470.73172,305.00528,-169.70416,435.2927,308.30673,-176.17876,462.39487,309.10873,-191.34508,439.00455,310.807,-198.95847,459.5435,299.8072,-189.61368,443.56036,300.23737,-197.5875,460.92816,301.4959,-169.92076,444.53775,301.90533,-176.31746,477.93857,360.2591,2.96293,433.50192,359.3228,-2.9242108,528.20166,352.8271,-212.63042,396.68036,352.69977,-220.2818,503.17056,442.01416,-203.3919,422.98367,442.53772,-207.76318,490.14856,458.108,-204.47194,434.30304,459.07672,-208.22011,521.32874,461.32684,-279.07697,409.74445,464.4457,-276.7737\nframe__TwOuh73cGGQ__0017921.jpg,squats_down,1092.5504,564.59436,-256.75186,1102.1511,545.50214,-251.44612,1108.7836,545.26337,-251.35114,1115.4219,544.93414,-251.42029,1084.4851,545.3614,-253.06543,1077.821,544.6264,-253.08417,1071.1481,544.03656,-253.19354,1124.6255,546.81696,-162.7973,1063.0559,545.15857,-167.68289,1103.1605,578.3833,-219.53244,1081.6686,577.4757,-220.53893,1160.1377,598.1888,-79.683174,1020.8525,606.1649,-101.561134,1182.6,718.05615,-132.59613,1028.6659,742.97815,-174.91005,1121.6409,631.4607,-183.55576,1077.5767,636.7157,-267.04712,1101.5016,608.17786,-187.51643,1092.6691,607.10254,-275.09348,1110.8324,587.0406,-167.1507,1079.1724,586.19055,-251.3699,1111.4911,597.93066,-175.27484,1081.8856,597.89087,-256.45242,1129.8018,764.83716,2.632266,1051.178,765.0479,-2.7200825,1215.274,756.2506,-280.11868,948.3064,756.5281,-189.11296,1191.7325,899.2814,-162.14801,971.06824,885.328,-86.0927,1173.496,924.2593,-151.47404,993.3439,911.86194,-78.76493,1228.7399,941.72754,-245.4585,912.97455,926.7973,-141.48123\r\nframe__bXyhN4CK0_8__0006978.jpg,squats_down,989.343,365.8959,560.29224,972.385,349.84195,511.90704,961.0998,351.77405,512.2516,950.124,353.92252,512.09955,1000.81366,346.20197,500.22693,1010.9459,344.26596,500.32355,1020.90674,342.54114,500.31622,932.3676,374.83914,258.85336,1032.3163,358.2283,229.68018,972.1747,388.0431,469.86044,1001.9086,382.15353,460.27036,859.76215,517.19543,-54.48269,1093.9452,487.28546,57.749897,867.2225,666.9038,-550.8543,1072.6205,585.5484,-391.9955,930.5266,763.1941,-1061.6428,1024.0829,696.87646,-848.8563,943.0165,773.20544,-1134.8735,1003.51685,710.16736,-920.86646,952.5622,776.4444,-1142.6252,1004.67303,722.9782,-892.7481,955.45685,770.7863,-1084.7754,1010.06744,719.2762,-854.9464,935.52405,817.08026,-72.14664,1078.4695,823.8071,74.68574,784.47375,727.38367,446.23907,1176.3816,720.67413,613.04816,762.73914,973.9903,376.4722,1240.4364,974.6929,393.5676,772.6015,1014.59106,373.2089,1245.5143,1012.8508,379.18237,711.30286,1001.9441,465.66666,1246.774,1007.7183,562.82684\r\nframe__mGvzVjuY8SY__0006600.jpg,squats_down,767.5169,539.7567,-135.65251,773.4417,521.13776,-178.14027,776.1825,521.43884,-178.10031,779.21625,521.7086,-178.08908,772.86487,517.1537,-109.25431,775.0003,514.3804,-108.96877,777.37256,511.76196,-109.07788,805.7445,523.14465,-270.71146,805.4432,509.0255,42.53771,787.79724,558.0544,-170.66132,785.88873,552.7065,-81.18736,879.98083,613.87616,-437.90964,877.8759,609.5532,236.45332,817.83276,769.01575,-285.39615,836.3237,746.1549,52.810028,768.7013,664.2192,78.511086,783.2128,675.80817,-326.9189,736.27075,644.80725,64.567505,756.30255,657.9515,-362.46558,772.5507,628.12897,21.7108,772.87305,642.2283,-326.51254,793.4065,635.98126,74.67333,785.652,646.4765,-328.55096,1070.7783,782.72644,-221.66852,1045.7919,761.25433,222.13809,875.49835,759.4296,-435.5913,849.39996,754.0045,427.53778,972.9695,977.2159,-344.04184,959.50085,905.9111,536.1488,1020.2702,1011.3409,-335.5863,995.9618,923.5955,546.8353,895.7348,1032.8347,-355.25223,917.83905,978.6541,570.6621\r\nScreenshot_2021-02-11 at 14.43.14.png,squats_down,413.6328,216.95428,-585.766,421.30292,203.7379,-572.7184,425.92606,203.54205,-572.7323,430.56992,203.24251,-572.55994,408.38992,203.69063,-570.10895,403.96866,203.26212,-570.0896,399.5394,202.90953,-570.10736,439.26093,204.71587,-453.68893,395.71234,203.8632,-437.77835,422.56232,225.9776,-538.62823,406.54196,225.56264,-534.0704,470.15396,247.83838,-362.71777,367.83444,247.6376,-329.50357,464.68887,343.47946,-367.4318,377.23123,345.30878,-324.52728,450.01834,412.53674,-429.37067,389.90472,417.83282,-372.38965,454.87744,432.76584,-469.89886,385.42462,437.58582,-395.89258,442.1196,430.81256,-491.7742,392.9479,437.8479,-426.74304,437.58093,422.66534,-439.97864,398.7035,431.15256,-384.73486,447.8731,338.82904,-4.584144,388.48947,337.31403,4.533007,524.98346,375.14233,-340.1128,320.8262,372.85767,-336.86942,518.0436,461.48267,-72.82497,320.4454,461.49744,-55.57408,505.7497,474.76797,-50.80879,330.56387,476.86823,-32.33037,549.73895,503.9007,-162.01411,294.92935,500.39832,-148.25334\nframe__jaWXM1wCBxE__0001186.jpg,squats_down,1043.6482,459.39023,-918.77234,1055.2019,435.86258,-895.45514,1063.2412,435.64172,-895.542,1071.3844,435.2965,-895.57623,1031.78,435.06317,-899.74133,1023.19037,434.1708,-899.6097,1014.58386,433.3641,-899.58685,1080.0133,438.04294,-687.4573,1001.55066,434.8236,-712.13245,1055.647,477.2816,-835.23334,1027.6517,475.78336,-841.9164,1135.5479,517.8053,-476.61075,943.54144,523.53937,-501.53104,1166.6703,681.9066,-622.55817,918.946,693.8266,-663.42206,1093.7885,632.1407,-942.00696,1010.3906,629.3432,-973.2464,1067.8665,620.31775,-1012.63995,1048.5233,614.6598,-1036.9404,1070.9519,588.2838,-982.47504,1035.8535,577.50464,-1009.1543,1072.4634,591.30383,-935.45447,1031.915,583.98895,-962.46313,1098.9617,664.3688,5.082643,992.9853,666.9227,-4.8655295,1148.1078,797.94214,-597.41876,962.45074,798.93884,-504.6297,1127.8237,992.82733,-285.97162,955.51,975.33655,-208.4352,1112.6263,1019.1901,-266.159,962.4204,1002.7215,-191.88345,1144.3134,1059.7169,-511.4995,933.3868,1036.5151,-434.48038\r\nframe__QfAY5JsB7qY__0004997.jpg,squats_down,827.8745,544.50134,-481.11844,834.6437,529.1037,-491.19553,839.1206,528.3381,-491.09528,843.641,527.523,-491.18832,826.83374,530.23376,-445.35452,825.807,529.9055,-445.1677,824.8945,529.9109,-445.17578,862.6448,524.7773,-482.80402,838.4945,527.1705,-280.4576,845.0588,554.2123,-476.832,836.4902,554.3574,-417.48303,928.2577,567.85406,-549.2507,844.87524,585.08606,-204.22981,875.877,542.18365,-815.2931,758.64856,544.42145,-277.96704,799.7831,451.0301,-997.4953,667.6539,474.31055,-421.638,785.95044,423.3393,-1081.4995,648.75275,454.0892,-462.41846,789.4848,418.33917,-1065.7129,647.2007,450.92664,-495.32285,791.05756,426.32245,-1000.62823,652.9674,457.3546,-444.99005,1012.2385,737.73413,-108.59327,956.62195,741.42413,109.17361,960.04224,824.85944,-485.4392,868.47906,809.73895,-203.3689,976.0479,950.25116,-293.89014,913.011,927.6262,16.778923,987.9418,978.4318,-287.3252,942.5128,950.4544,31.529367,919.49396,977.1343,-498.72104,830.58765,971.5299,-104.7394\r\nScreenshot_2021-02-11_at_15.58.45.png,squats_down,1311.2657,486.85712,-391.41278,1328.5885,464.59473,-341.8008,1339.6895,464.7492,-341.70386,1350.8394,464.7458,-341.9129,1298.8057,465.7086,-335.98676,1287.984,466.1022,-335.7339,1277.16,466.83954,-335.45154,1369.9493,486.05905,-91.04324,1269.6171,488.85635,-56.379204,1335.0225,517.4302,-306.50043,1293.6454,518.1983,-295.97495,1424.7849,618.00287,-89.061356,1224.8024,630.0059,-10.143835,1392.3008,777.4915,-584.91974,1250.2422,784.38965,-398.85223,1406.4741,640.3852,-1012.69366,1248.2333,640.3884,-748.0418,1429.4275,599.84735,-1085.0991,1239.6345,605.56335,-789.26306,1437.7144,605.75397,-1048.912,1222.6995,588.67883,-745.35095,1420.8372,617.7124,-1007.77527,1232.2635,601.7114,-733.5063,1392.541,931.46,-7.416791,1275.2573,933.18085,8.276925,1433.2916,868.4438,-874.2557,1172.0374,888.0492,-789.56195,1415.6292,1072.4432,-323.32178,1202.2721,1086.8002,-319.75363,1401.1812,1095.1041,-274.9936,1225.2368,1108.4043,-279.7825,1442.3225,1170.0607,-522.85364,1161.2008,1183.457,-521.46075\nframe__jPO_jp4Sb00__0027689.jpg,squats_down,854.85724,467.8695,-214.59149,866.9403,445.65677,-191.6688,875.1097,444.82135,-191.64786,883.3098,443.8492,-191.62555,846.3203,447.43207,-175.96431,839.1871,447.31696,-176.03749,831.9338,447.45193,-176.01662,900.74884,448.99292,-42.94878,830.4717,452.78412,40.336746,873.3042,485.18625,-159.58566,846.7563,486.7178,-136.1122,960.6601,528.01074,43.429432,793.4189,532.5747,100.18698,996.08057,645.07983,-170.46114,727.03564,652.5033,-196.18436,899.9622,534.72437,-244.51158,807.5465,516.7565,-408.21143,881.75214,499.5668,-276.78616,820.3957,476.97604,-449.55206,877.8218,491.3146,-204.83015,828.89746,466.19922,-378.36194,877.8526,507.05826,-217.74239,834.7016,485.47665,-383.94495,930.8922,730.0178,-24.741228,830.3826,727.8161,25.178083,1000.6939,729.0288,-699.7173,730.07245,714.896,-610.50037,958.72876,864.6268,-272.40625,783.3949,857.4257,-251.41763,945.1587,876.76465,-235.96436,808.5622,873.4479,-220.30986,960.5818,945.8714,-467.78802,753.93445,936.1236,-425.01093\r\nframe__miPKBTdcCIY__0004615.jpg,squats_down,950.7256,520.30286,-329.04395,953.7736,500.33,-307.4592,955.1888,499.24463,-307.3928,956.773,498.18506,-307.45306,945.1149,501.54877,-350.14224,940.5851,500.8578,-350.01498,935.95013,500.34857,-350.0916,945.82666,499.74155,-164.7455,918.27045,500.81808,-350.29486,946.0523,534.2376,-271.05768,935.856,536.04193,-321.5982,917.13763,547.0414,76.7807,862.0102,580.42664,-429.98355,1009.7594,601.3036,223.77827,891.7136,696.6219,-482.29993,1005.7799,559.34863,194.14331,948.78705,568.4566,-321.3089,1010.0617,551.9366,194.31323,979.00256,541.89246,-335.55737,990.0792,543.7148,188.79782,956.40857,518.11694,-351.8969,984.4464,555.21924,187.75276,942.91797,531.0064,-320.0301,759.8293,730.95984,187.87958,730.79565,749.6824,-187.94278,921.9984,699.199,256.42126,918.3546,717.4311,-285.8407,848.40356,854.1138,362.1913,815.7965,865.17035,-183.46725,811.81915,880.07666,372.96127,768.9418,885.7797,-172.81215,911.8554,902.86115,358.761,888.70264,917.0441,-193.846\r\nScreenshot_2021-02-11_at_16.08.47.png,squats_down,1724.9965,379.9945,-1093.0465,1732.5193,360.5672,-1043.9113,1741.1598,360.81845,-1044.1481,1749.8657,361.03024,-1043.9668,1704.5812,360.43942,-1058.223,1694.2495,360.62933,-1058.0547,1683.7141,361.1202,-1057.7952,1755.8607,377.6913,-728.4744,1662.4418,376.63535,-789.26935,1737.27,409.87576,-978.8168,1705.0264,410.6694,-994.3002,1816.4841,511.31134,-513.7256,1588.4037,500.49048,-633.04315,1908.6816,675.04956,-1021.43787,1549.953,681.2221,-1041.7178,1815.6975,538.6462,-1587.857,1667.4712,534.9215,-1317.7993,1798.9177,498.0466,-1689.889,1700.1217,482.86557,-1381.5946,1787.3323,479.59622,-1584.4454,1689.1368,463.58044,-1325.1432,1783.4623,499.7563,-1557.309,1691.3319,488.0785,-1298.6428,1713.5706,747.50775,45.16657,1577.4437,741.1995,-44.540546,1860.5306,813.95074,-689.8626,1508.7535,792.15454,-1133.978,1807.0055,1016.5664,-245.3226,1530.6272,1041.4556,-577.58374,1770.3417,1057.3702,-215.54115,1542.1042,1079.9918,-540.9818,1897.6538,1093.2146,-476.62302,1515.479,1121.4316,-909.8044\nframe__8ghtQpeWov8__0013922.jpg,squats_down,1158.8892,572.87823,-122.235115,1167.372,558.91046,-99.728714,1166.0607,555.7301,-99.727585,1164.8931,552.7236,-99.6708,1165.5194,563.67285,-153.2725,1163.2195,563.0624,-153.20198,1160.8091,562.79974,-153.26218,1144.804,550.12885,-9.083175,1140.503,561.79297,-257.3049,1139.7065,579.77026,-87.04987,1137.8301,583.9346,-157.33919,1074.606,564.3167,167.88835,1057.3665,606.46387,-417.53705,1208.3384,576.34784,276.54266,1161.0267,661.58234,-692.9588,1289.9343,547.1121,145.17728,1283.196,622.9178,-768.2962,1305.4735,532.0347,152.67377,1323.2246,614.4229,-847.45056,1305.0581,525.2318,83.956924,1308.0634,590.26624,-820.70764,1299.1066,539.25354,113.98917,1293.6866,594.2685,-760.3099,866.2212,729.01544,202.39432,851.624,758.3746,-202.04306,1078.5286,719.4229,361.69833,1081.7821,762.4579,-269.9044,961.85956,856.4736,691.00116,974.71484,914.1584,17.952316,930.2166,871.2321,725.0413,941.1721,932.09753,45.501106,982.2664,906.78204,793.9116,1011.4588,964.5929,62.581673\r\nScreenshot_2021-02-11 at 15.41.06.png,squats_down,373.70682,248.9057,-266.52054,378.90527,241.64755,-246.3396,382.66336,241.67445,-246.36345,386.50748,241.62744,-246.35207,367.8516,242.15016,-245.56453,363.99014,242.43465,-245.43123,360.1014,242.80116,-245.44046,392.71036,249.52763,-135.07803,355.18414,250.80542,-133.593,381.52258,260.78568,-226.19815,366.8491,261.15973,-225.56789,418.33688,305.26047,-86.85582,332.08047,300.34906,-83.65503,428.99368,362.05542,-157.65152,305.60596,352.29645,-164.18396,412.04803,388.67892,-349.1962,340.0248,382.22495,-350.31503,410.51608,400.77988,-398.8857,348.5068,398.52267,-397.33633,402.78238,392.76688,-406.90137,358.47882,387.82425,-403.8358,401.85052,388.85263,-357.47958,357.1777,383.83554,-355.48358,400.95584,413.95438,0.43306512,348.7867,411.74005,-0.18693057,435.63773,449.78397,-298.90182,307.96036,440.94327,-334.9341,424.06497,531.74457,-62.20473,314.69635,524.19183,-85.4974,416.36087,542.3736,-44.665085,324.5519,535.9486,-65.8223,434.8122,569.7874,-157.79276,291.31354,560.03564,-180.9462\nframe__dCNS-QVXa6k__0022882.jpg,squats_down,1062.3062,385.67206,155.8595,1053.8481,367.16556,166.492,1050.1206,366.02505,166.68127,1046.587,365.06143,166.61667,1056.3123,370.1233,108.493645,1054.6975,370.65463,108.78315,1052.8455,371.3401,108.82379,1027.6184,375.57233,242.06683,1036.6776,381.55252,-28.530022,1051.303,406.11765,189.65024,1054.4749,409.5164,112.55179,963.8379,471.195,448.84335,1026.9922,474.91818,-196.53716,1091.2766,543.6611,568.85693,1155.3201,548.4517,-133.74316,1181.4098,514.98267,463.1337,1213.5956,516.0735,265.69122,1207.8616,490.48846,472.40033,1236.6055,490.38556,240.97775,1201.9749,484.50073,421.72128,1227.968,484.02097,277.46588,1194.0131,495.82672,440.5439,1219.3008,494.4786,287.34894,780.8424,658.521,220.97195,817.4846,667.35394,-221.02615,941.9776,733.2757,600.99475,1026.926,775.5174,-183.04492,881.3534,903.59906,893.5817,968.7584,971.8642,-117.57597,855.2072,936.25903,924.35913,934.14685,1004.1353,-107.7777,922.56335,923.6051,1003.87506,1042.6344,1008.77515,-81.717995\r\nframe__dCNS-QVXa6k__0011204.jpg,squats_down,1124.0336,302.49496,108.68337,1113.0438,285.53418,115.656494,1107.973,285.41058,115.69397,1103.0833,285.38965,115.75951,1118.4744,286.55713,50.935013,1116.4794,286.61087,51.146416,1114.318,286.88025,51.00209,1075.8579,298.39703,203.56342,1090.5616,297.9363,-101.33919,1107.7988,325.357,144.69943,1113.486,326.80496,57.025723,1002.1852,399.08237,427.75745,1062.2544,413.5613,-265.12823,1102.365,509.7697,636.6071,1174.8164,522.89575,-121.14073,1152.2963,441.29144,786.52136,1169.7917,432.88248,320.1809,1176.8348,412.23965,824.3711,1176.5708,399.9946,288.58395,1158.7115,409.76996,819.1322,1164.6932,400.8157,281.5561,1146.4857,422.2631,786.46045,1157.2275,419.29004,326.06866,811.34753,597.81683,227.69136,842.0999,615.5526,-227.44675,997.4154,664.37573,619.533,1067.0476,733.1374,-229.8458,913.7407,856.06104,851.3019,966.5418,916.8826,-152.11728,878.8626,891.4702,883.5786,926.2631,951.66925,-145.79279,991.184,897.09955,989.836,1064.4578,958.1191,-110.39269\r\nScreenshot_2021-02-11 at 15.24.49.png,squats_down,558.33215,330.0757,-491.0152,565.52747,315.01227,-485.34036,569.9653,313.58765,-485.34418,574.5371,312.0815,-485.46436,552.4009,317.70367,-477.83954,548.26825,317.9178,-477.5919,544.0681,318.28955,-477.53796,583.9127,305.87506,-385.06516,543.1779,313.63742,-344.83786,568.3184,335.54172,-446.49716,555.7554,338.27585,-435.00278,628.3156,345.10367,-339.4851,511.55716,341.96024,-289.8909,624.92163,406.84,-604.60156,472.29898,408.16724,-553.52405,573.64734,337.24335,-751.6866,532.30084,333.17062,-727.5572,567.9777,315.17786,-789.97614,538.4195,305.696,-754.31146,566.222,307.05954,-747.64746,547.8038,303.04056,-702.7627,566.0013,317.51373,-736.4553,550.5864,317.4385,-709.0652,604.33405,492.11182,-12.062526,527.7508,491.96155,11.977373,716.32495,485.75803,-357.1276,436.6627,488.07843,-281.6908,707.982,606.49615,-171.22115,440.24942,611.3217,-88.93191,691.5793,632.18555,-158.86603,454.85995,638.7245,-77.22438,748.64087,648.5559,-280.5047,399.4791,652.78357,-182.01924\nframe__abrchWe7pnE__0003420.jpg,squats_down,2039.0706,1149.3215,-1656.897,2060.9294,1107.4391,-1613.1696,2074.213,1106.0863,-1613.1326,2087.7073,1104.5748,-1613.0842,2021.883,1107.7151,-1617.1279,2008.7693,1106.4503,-1617.3644,1995.5491,1105.3608,-1618.2015,2110.3225,1104.3773,-1219.325,1980.3505,1102.7922,-1235.4218,2061.4797,1175.7848,-1498.8423,2019.7515,1177.248,-1499.8479,2210.2861,1240.4369,-806.67377,1884.1218,1241.8701,-896.4811,2244.1301,1506.5226,-1103.6875,1856.2041,1537.6646,-1245.7714,2126.1934,1455.7174,-1785.4071,2009.5814,1465.2451,-1839.5485,2106.4841,1436.5957,-1972.4158,2052.6187,1439.2705,-2012.8464,2097.6675,1398.0797,-1915.1558,2051.0938,1390.0494,-1966.5852,2086.457,1408.6241,-1783.9723,2055.1738,1405.091,-1843.4263,2096.6414,1531.3693,18.7094,1922.1272,1528.6158,-17.69089,2315.572,1551.5856,-1208.3925,1799.1494,1527.0225,-1282.7921,2257.0408,1850.2894,-466.35724,1767.7861,1859.2589,-594.1508,2216.9114,1906.852,-416.2,1790.3441,1917.5349,-552.79767,2339.6653,1953.1154,-864.1173,1698.2579,1971.269,-1014.5547\r\nframe__UxstRqRaIPs__0006369.jpg,squats_down,926.73975,434.34155,-821.0042,933.9177,412.52957,-793.6493,941.29065,411.50507,-793.5882,948.66815,410.38226,-793.46375,912.0241,414.74936,-797.18774,903.9631,415.184,-797.0451,895.905,415.71017,-796.91364,955.01245,415.11795,-575.53094,883.69464,422.84183,-590.8898,939.30774,450.56213,-737.5085,912.5657,453.03754,-741.5092,1002.62445,497.33426,-414.2403,839.63794,512.5242,-419.47333,1030.7358,622.84,-707.223,837.2557,631.8241,-726.2855,1011.27515,536.35944,-1141.4568,840.3124,544.1178,-1148.0737,1007.67566,507.73972,-1230.5692,839.3541,516.8982,-1225.6732,1011.02637,487.49615,-1198.4988,831.3995,500.47766,-1198.633,1005.24,498.0508,-1138.4049,839.7015,509.51773,-1145.8988,975.3484,664.8948,1.3246369,875.34534,669.18695,-1.1197236,1058.2473,795.29364,-408.94727,803.3474,806.05035,-447.395,1055.6815,940.8697,-22.110542,801.39905,941.4801,-54.69352,1042.4559,958.73755,7.2954807,812.6306,961.19214,-26.138126,1074.3301,1013.82996,-198.31822,765.91504,1005.4407,-243.84195\r\nScreenshot_2021-02-11_at_15.38.15.png,squats_down,1333.2468,572.86365,-414.39624,1345.8037,553.14343,-354.2503,1355.0571,553.40497,-354.41702,1364.4413,553.4911,-354.40134,1319.436,553.2397,-360.10342,1309.7067,553.0491,-359.9618,1299.9841,553.1069,-359.84888,1375.6669,567.84753,-85.99523,1286.4275,566.62537,-110.72759,1348.6965,600.0213,-321.9796,1315.0433,599.3205,-328.86047,1437.1405,682.1424,-10.065819,1214.9274,680.02106,-73.56875,1508.8928,831.153,-520.2379,1136.8195,823.6657,-620.2308,1406.6656,698.6738,-903.5124,1248.0271,698.9645,-1062.6373,1383.5748,661.3655,-960.5898,1277.6984,669.3525,-1114.4644,1378.5664,642.66815,-853.4823,1283.1271,644.9049,-1032.5707,1375.1855,662.7016,-863.6757,1283.151,665.16595,-1027.2053,1388.3746,913.4355,24.67968,1252.4049,920.32513,-23.806454,1491.981,871.9769,-839.43555,1192.732,877.6571,-1002.0943,1457.3549,1091.1167,-422.33038,1194.27,1103.2965,-606.2126,1432.936,1125.653,-394.32916,1206.2821,1137.4264,-580.27515,1499.5978,1173.7778,-697.8918,1183.9039,1181.8906,-914.2788\nframe__Qzd8oJyKQaI__0010691.jpg,squats_down,1081.7716,411.73505,-62.8589,1068.1973,395.70386,-48.419243,1064.4221,395.37247,-48.453743,1060.7867,395.09125,-48.520782,1070.0979,398.7277,-109.514145,1067.3398,399.7015,-109.449295,1064.586,400.82507,-109.634575,1036.0013,406.73346,50.59025,1040.9895,412.46664,-228.54938,1069.9304,432.62338,-20.190609,1072.6547,435.59665,-100.59387,997.6963,523.3411,225.03627,1022.7462,511.5959,-347.02444,1112.2959,608.6307,267.04166,1138.2163,610.529,-316.58554,1196.3793,550.905,137.76462,1206.0432,540.01227,-106.58336,1219.1144,521.1378,138.33649,1229.5985,508.70325,-162.36366,1215.6473,510.32242,108.7585,1212.2704,496.5635,-146.87439,1207.698,521.497,119.0051,1203.0809,511.7318,-97.396935,903.3001,739.75275,181.66971,907.73956,740.78174,-181.2869,1031.3892,815.064,439.69748,1055.9587,822.5699,-208.95892,995.3769,967.44745,693.0725,971.4675,989.7496,-110.58521,964.2968,998.36816,717.0832,935.90955,1011.2601,-102.35993,1070.1859,1006.04877,750.03064,1029.7999,1046.2737,-111.082695\r\nframe__bggX6ocjojk__0001456.jpg,squats_down,1862.1237,1054.8574,-1063.085,1876.9562,1009.2049,-1035.6781,1888.5024,1007.34906,-1034.981,1900.1411,1005.1864,-1034.5922,1840.8188,1011.0064,-1034.4655,1828.6946,1009.72864,-1034.1023,1816.4639,1008.7739,-1034.5493,1918.3912,991.80096,-584.5506,1799.406,996.53613,-608.58435,1882.452,1071.6661,-877.5341,1844.2916,1072.671,-883.6529,1996.8823,1085.7104,-258.173,1704.4729,1074.1831,-243.68237,1998.3309,1238.9808,-870.5019,1657.696,1224.9885,-796.71625,1921.5282,1296.1517,-1891.7701,1764.3868,1297.0006,-1775.631,1911.1858,1318.5314,-2144.7485,1796.6921,1325.198,-2004.7749,1874.7518,1297.3015,-2140.6882,1822.6074,1295.922,-2003.5055,1872.353,1295.3279,-1921.9691,1819.3727,1293.7399,-1798.7053,1921.5475,1417.2306,25.495234,1738.0181,1407.3152,-23.669762,2104.1917,1523.7888,-1024.6682,1585.3105,1533.098,-1069.243,2055.0522,1828.169,-447.07358,1599.2601,1835.6674,-474.85083,2017.4419,1887.7008,-415.11502,1634.4119,1900.8652,-445.94983,2130.5176,1922.4939,-851.6194,1516.356,1929.0492,-922.01953\r\nframe__ekowbKbBNSM__0007375.jpg,squats_down,1240.1278,546.5549,-450.77924,1248.1792,519.23364,-441.22885,1248.046,516.5628,-441.0697,1248.0824,513.9945,-440.91882,1244.9843,522.3588,-495.94006,1241.8062,520.22296,-495.96204,1238.5918,518.61755,-495.94785,1226.6373,499.90033,-322.74463,1213.2511,505.78726,-576.0333,1221.4756,550.4918,-401.13196,1216.7595,551.6923,-472.62,1182.6583,527.53864,-141.09671,1135.9224,540.63416,-662.2069,1383.8369,560.8508,-184.87791,1300.8859,607.4931,-852.7715,1556.5782,551.48724,-356.0047,1499.7153,575.001,-876.89825,1604.8264,547.2843,-385.9519,1550.6774,575.1305,-955.7886,1597.4791,537.0221,-451.55185,1544.9835,542.2381,-928.3783,1579.6655,545.97565,-396.9043,1526.8125,543.36566,-870.2026,1000.76135,754.11206,176.62823,961.02124,768.83734,-176.8117,1203.9597,676.5353,232.89392,1183.0215,689.5481,-389.2274,1110.4385,854.6912,451.84644,1083.2761,894.1604,-120.24024,1084.4036,881.09686,471.89313,1050.6956,917.94684,-89.874596,1124.1068,892.13367,501.98703,1106.3091,949.56256,-72.988914\r\nframe__ku3vgejAZ0g__0001229.jpg,squats_down,920.6912,391.36667,-1042.6,933.0794,371.98767,-1004.7029,941.2908,371.67746,-1004.66125,949.4274,371.28992,-1004.6547,910.3624,373.4651,-1004.05035,902.5504,373.92426,-1003.7244,894.70197,374.5442,-1003.5703,963.18,380.4159,-756.6412,887.2119,384.82642,-763.9478,937.2394,411.70593,-949.0478,908.5643,412.93082,-950.6886,1022.04663,480.2771,-583.3929,836.78357,474.5952,-600.6567,1071.1108,624.7741,-878.86676,760.035,602.891,-927.9022,984.52686,585.32965,-1291.687,853.6916,564.6693,-1321.8772,953.1338,580.9633,-1362.4603,882.6908,557.46234,-1394.9548,956.6477,544.987,-1325.0272,888.14185,536.2085,-1347.5599,960.58124,548.1354,-1277.6344,885.4353,542.58344,-1303.4305,993.2167,641.53925,5.8037877,883.4517,642.0689,-5.564067,1083.0254,733.26575,-537.60895,813.87933,757.0088,-545.9337,1039.3186,851.52936,20.115835,863.0438,854.49677,34.938354,1021.4788,870.9275,65.44301,884.4549,871.4229,79.42079,1066.8207,913.85297,-135.2384,829.8866,917.76764,-132.49336\r\nScreenshot_2021-02-11 at 15.47.00.png,squats_down,566.1186,306.4851,-263.09808,573.81335,294.0929,-239.47986,579.51917,294.03354,-239.43365,585.2522,293.86124,-239.3624,557.8767,294.71732,-240.48302,552.0461,294.87234,-240.45079,546.20825,295.1284,-240.42737,593.3649,301.6566,-109.59619,539.05774,303.09412,-113.88126,576.7269,321.7445,-216.45613,556.51556,322.13913,-217.42169,628.8582,368.72028,-41.321705,507.02628,365.91608,-38.162884,659.0643,474.38895,-227.2925,480.01913,469.09528,-213.88234,621.04065,394.6044,-443.83072,523.9897,399.4968,-423.2327,609.34393,372.12848,-479.98376,538.77216,383.2802,-446.23093,614.2679,353.31818,-440.7431,534.8558,363.3377,-418.57724,610.92993,363.38165,-430.73196,537.38,372.38623,-411.3389,605.8633,496.87915,-1.8482736,532.15686,494.2699,2.1942658,688.5107,497.09747,-396.31323,463.93027,489.61465,-372.11932,661.8017,627.1635,-216.69159,472.85068,618.00037,-214.42123,645.4667,648.3508,-204.43643,487.68573,641.65436,-203.26071,689.9302,670.4263,-341.80008,431.4882,657.6861,-334.48434\nScreenshot_2021-02-11 at 15.50.40.png,squats_down,603.3988,334.02942,-408.76328,611.9552,322.2346,-392.951,616.7934,322.54144,-392.98135,621.6295,322.75003,-392.8683,598.29016,321.48584,-392.97708,593.6535,320.97934,-392.873,588.99927,320.53827,-392.92026,628.2979,325.8518,-277.00598,583.62085,322.67657,-276.92508,611.0406,345.15002,-363.46573,595.12695,343.7725,-363.5384,654.50745,376.3706,-191.49724,549.97845,369.3088,-196.4372,653.6626,464.5478,-325.44382,550.56104,456.3664,-360.4223,621.0034,401.53754,-464.1282,596.1641,397.93268,-514.00476,614.059,381.5232,-499.88095,604.3597,377.35086,-548.6003,620.0578,369.07837,-467.34058,600.15375,369.07947,-521.19635,618.687,375.70248,-453.3942,602.52356,377.00272,-506.04044,628.0847,480.59015,2.9801574,566.80695,480.11594,-2.7814283,700.7682,487.72406,-317.6922,505.46497,484.23532,-334.19437,690.01483,597.073,-116.69089,496.3886,592.9916,-133.0319,677.7683,616.715,-103.38546,504.4566,612.8723,-120.64528,720.0428,632.91046,-224.59718,463.76315,625.5765,-243.3457\nScreenshot_2021-02-11 at 15.42.03.png,squats_down,613.4107,236.37299,-113.381836,617.06757,227.94786,-94.381035,620.0997,227.53767,-94.26427,623.2339,227.11737,-94.38439,607.8794,229.38365,-98.50233,604.58295,229.80649,-98.53186,601.2864,230.32271,-98.61152,627.2069,232.40454,11.614473,597.46423,236.54375,-3.636671,620.07,245.8238,-73.67252,608.2557,247.26694,-78.24238,649.47076,274.08466,-7.6024036,578.0917,274.6106,-4.6443954,678.3591,280.39664,-250.55331,548.105,278.5901,-256.06302,697.5752,275.54095,-513.62335,522.58954,276.24063,-560.9817,711.3323,279.4889,-566.6219,506.69583,281.86008,-610.9567,697.6946,277.09235,-573.35345,520.91815,276.14597,-623.8655,694.064,279.17172,-527.2266,525.9442,278.7097,-575.19745,640.0343,383.3612,6.7431517,590.1298,383.63715,-6.561203,679.98157,441.85098,-277.29544,558.57715,446.48633,-246.85657,668.4627,538.2867,-209.4831,568.8481,541.0119,-178.46104,658.3061,554.0189,-211.068,578.4952,555.6273,-177.9756,690.1952,570.9788,-329.1589,549.719,573.8198,-289.59515\nframe__iPCJs2jh4Hk__0001781.jpg,squats_down,834.2707,571.01843,-220.85187,840.8306,562.55164,-175.13797,845.9302,563.3633,-175.12662,851.13885,564.0258,-175.09712,824.86365,561.44104,-181.60551,819.0648,561.1823,-181.47081,813.2787,561.0709,-181.39905,854.3106,575.6344,20.869928,802.21844,571.57434,-5.594599,840.6978,589.7883,-155.80455,820.7806,588.07556,-163.5281,888.1768,661.35583,80.10368,752.40265,654.2358,22.40483,920.975,759.02075,-240.5692,744.67114,760.62177,-309.86557,887.9946,682.80035,-560.991,800.8294,670.7777,-627.0753,886.0647,660.3441,-617.17773,813.3012,642.15204,-680.0335,880.4798,648.89716,-565.5132,811.71985,629.26227,-642.0361,874.71277,659.97205,-546.2384,814.2655,643.38965,-614.9335,852.43097,815.16724,27.114874,764.95844,814.51324,-26.37856,934.5735,801.6348,-560.1269,731.6016,806.51184,-664.55786,912.49994,971.33154,-525.79315,708.2755,983.1519,-616.5096,893.0035,1001.75635,-532.21454,709.11316,1012.41626,-620.72986,950.2053,1013.6625,-741.6117,705.89185,1028.5851,-846.5378\r\nframe__mGvzVjuY8SY__0013411.jpg,squats_down,871.5465,587.22345,-408.6195,881.48395,561.829,-414.4165,888.7398,559.27997,-414.4008,895.9199,556.66455,-414.48718,866.2476,565.69025,-375.55475,861.39,565.8338,-375.24112,856.6428,566.1581,-375.08328,920.98755,548.80457,-344.30133,870.1593,560.5341,-179.01614,894.8414,594.00574,-377.67654,874.1804,598.33154,-329.74695,1006.1473,603.09674,-358.95938,877.64777,612.7321,-35.559814,960.73047,775.5856,-503.42337,824.1016,747.3347,-287.82733,863.2356,663.4655,-505.94055,824.679,655.45776,-646.40204,831.461,632.871,-536.90717,819.33875,634.91284,-694.4365,859.6501,612.21906,-523.335,832.6361,615.7669,-648.6594,870.4669,621.2493,-495.70248,842.97437,624.9734,-634.17676,1078.1248,766.18024,-109.75948,1007.8924,767.59753,110.87966,971.1566,798.11633,-552.4287,869.64575,791.9023,-313.81226,1014.9265,977.19244,-386.15167,946.24774,964.8797,-268.22397,1043.4036,1001.16785,-374.61295,980.74976,989.2277,-268.37836,959.25824,1056.6536,-558.9494,891.67993,1035.6028,-399.87177\r\nframe__Av83LHehBK0__0002759.jpg,squats_down,827.50806,396.81534,609.3937,805.6683,385.78394,582.5341,801.7469,384.15665,582.55786,797.7512,382.1235,582.70667,817.81445,385.7475,623.96094,822.68536,383.2804,624.0507,827.8266,380.95953,623.7438,801.7472,372.03696,458.59103,842.3093,372.0223,662.1357,839.20135,396.80566,563.8249,853.57495,396.53314,623.9293,843.07935,404.76392,208.23946,971.4013,386.12558,681.0412,852.6096,586.74567,35.17136,1025.9985,546.04846,761.90015,796.00616,725.74615,17.479702,987.5855,696.3574,782.19916,777.17114,752.36694,-5.5697446,982.93604,716.71497,818.2576,774.81757,742.37146,33.76233,959.9098,723.25665,797.8673,785.252,730.0222,32.025345,954.62335,721.95996,772.2856,1149.0496,539.47,-150.7224,1223.7803,532.7337,151.39484,915.91516,568.28564,71.52286,1008.3578,598.34,572.97455,1024.7728,752.00635,-68.52215,1149.7224,672.39667,594.05316,1075.9243,783.32074,-80.56791,1194.9308,669.887,592.93134,966.4537,793.778,-58.645725,1139.459,702.12415,578.1632\r\nframe__zJBLDJMJiDE__0000500.jpg,squats_down,1040.0221,530.91315,-609.619,1048.5801,511.5095,-572.6954,1057.1162,510.57144,-572.6983,1065.6035,509.49866,-572.96545,1025.7865,516.5904,-571.04926,1017.14746,518.8648,-570.68933,1008.4261,521.37164,-570.74,1077.7838,526.2694,-388.11502,1001.8478,542.1846,-383.7753,1060.0605,555.93256,-545.1475,1028.0609,561.5063,-544.18475,1150.5425,647.0766,-399.38226,973.8195,647.1437,-272.72784,1163.8058,829.87445,-635.334,911.4993,797.57574,-531.0657,1032.9052,734.1917,-925.57166,872.0919,739.5448,-973.04974,990.7475,726.3516,-997.1952,859.2816,733.43567,-1041.1453,999.74854,682.63275,-988.68066,864.291,706.15125,-1032.3187,1015.42426,691.018,-927.24365,879.86884,711.9437,-978.41895,1156.2345,869.24713,-56.050213,1059.1642,862.8064,56.56035,1127.5813,790.95435,-637.3083,914.78876,770.0488,-353.15143,1161.5565,954.4574,-249.56937,976.7747,949.4814,-80.37158,1175.06,977.90906,-219.20653,1016.37573,984.8098,-59.946068,1140.6995,1025.373,-378.1081,884.4645,1021.28595,-174.04166\r\nframe__mGvzVjuY8SY__0004756.jpg,squats_down,919.3215,546.92584,-874.28424,932.1142,527.2427,-836.82135,940.48456,527.0397,-836.8068,948.8562,526.72955,-836.69946,909.013,527.6881,-834.6846,900.9926,527.67474,-834.6354,892.9351,527.7603,-834.70514,962.93665,536.8429,-626.0562,885.2837,537.5072,-615.07996,935.3462,568.3383,-797.35986,906.80536,568.70404,-793.0599,1019.80945,638.5684,-453.90167,840.0032,636.3841,-452.4168,1040.3304,796.3711,-682.23724,812.0507,788.3173,-698.91077,961.03455,721.69196,-1040.1901,873.0901,713.8941,-1066.8595,936.8262,699.52454,-1125.8173,893.3131,692.1222,-1146.5981,941.7849,669.0548,-1074.444,890.1151,665.0703,-1104.7084,941.49274,678.3062,-1026.4442,893.5224,675.5429,-1056.398,983.0718,779.5096,-4.6071844,887.00366,774.9674,5.2555203,1013.1325,838.60986,-720.8583,845.98096,838.263,-677.0373,1000.85565,985.6346,-248.50087,843.7481,978.49316,-195.39532,993.3916,1008.0646,-215.9015,853.01074,1000.24506,-165.55634,1010.41797,1046.932,-486.876,824.3073,1041.6349,-433.61575\r\nframe__e2xTVq6wtsM__0035202.jpg,squats_down,758.9573,229.54742,-9.064943,780.22626,218.88663,-54.224365,783.016,220.85175,-54.155075,785.9459,222.67728,-54.234474,782.9187,215.65923,14.778604,787.0757,215.74144,14.909944,791.4941,216.09091,14.872334,815.1182,240.05493,-170.44833,819.59686,233.54305,138.11931,766.112,257.27982,-51.915623,768.74927,252.93857,37.505287,828.2489,358.7608,-344.4583,849.97876,361.47784,355.48044,687.09436,459.18683,-242.39133,718.7519,439.68628,390.24435,633.69275,323.03165,49.813435,643.29504,334.29065,315.09857,605.92566,286.2254,-0.82249117,620.12366,296.7572,321.33173,638.4027,275.5006,-22.851183,631.1674,288.51874,314.1765,654.0334,293.11172,47.482018,640.1264,302.38358,300.3993,974.51166,594.7769,-222.0977,978.59814,580.002,223.4254,782.4786,730.3029,-246.89761,797.2672,711.3919,336.764,787.18506,949.159,-225.69785,794.4843,903.97107,424.2367,809.2393,996.2752,-223.90265,818.9798,942.71747,432.11273,674.8597,963.76874,-260.9372,689.5254,937.8916,407.4636\r\nScreenshot_2021-02-11 at 14.53.36.png,squats_down,404.31018,334.8083,-97.35719,411.06058,321.09497,-78.366745,416.76083,320.53494,-78.18457,422.54535,319.97238,-78.334496,394.53876,322.2182,-84.05322,388.39566,322.06146,-84.04667,382.23462,322.02994,-84.03998,430.2513,323.2244,32.05031,373.35638,325.3838,19.599869,414.41974,346.96875,-53.275494,394.53766,347.75397,-57.325485,445.9866,363.37894,30.513683,362.07947,360.80704,32.729023,476.4915,374.38867,-115.37024,339.3788,372.26984,-123.64945,480.6656,324.2568,-256.30188,322.39688,328.47934,-303.7594,489.81808,307.03882,-305.11765,307.99118,313.623,-351.77466,477.8958,299.8212,-297.6307,326.20886,304.2033,-351.88745,472.61392,308.7296,-266.08774,332.47058,313.51535,-314.54202,434.5155,481.7909,-0.62943566,374.0379,483.711,0.8108199,502.50232,483.7206,-312.0346,310.64023,497.5064,-256.99072,473.68243,586.1043,-181.93349,343.1899,597.1959,-145.53429,458.01175,603.39307,-172.58624,357.93903,611.2329,-140.18506,503.64392,626.73676,-272.14102,323.07043,640.1724,-252.96684\nframe__ZwbX1A-LlTs__0009913.jpg,squats_down,1121.2802,595.90784,-652.24725,1124.6793,583.88446,-628.9531,1130.2233,583.9719,-628.99347,1135.7693,584.1016,-628.8914,1109.1334,584.8716,-641.46716,1102.86,585.277,-641.2767,1096.4202,585.87634,-641.1813,1138.3384,593.98145,-453.20868,1082.0895,595.19257,-496.00995,1131.214,611.063,-583.0165,1110.0612,611.3979,-594.5584,1151.7426,649.5088,-294.5162,1049.4476,656.13416,-464.2272,1217.3147,709.206,-507.85504,1067.8555,769.37964,-697.1068,1207.3398,694.49536,-850.06494,1156.4551,728.6786,-849.4054,1208.1985,688.1238,-921.5797,1178.5736,715.8394,-901.6159,1196.6685,680.5832,-909.40137,1175.292,707.3073,-881.3454,1191.774,684.6338,-856.88385,1170.5447,713.86707,-842.19794,1089.284,755.5622,47.737133,1026.3726,755.6833,-46.9354,1141.1254,830.50214,-443.1514,1055.0117,816.7208,-600.3325,1117.8439,927.41724,-157.34178,1064.0973,921.9112,-356.24112,1105.0874,943.99976,-137.50923,1063.1467,933.4348,-334.12268,1138.2518,963.5728,-298.416,1080.7086,961.0154,-497.75842\r\nframe__6Gim-ntffUY__0005315.jpg,squats_down,973.7898,495.3674,-681.9969,984.7704,483.25836,-641.49524,991.1338,484.48535,-641.4179,997.5991,485.6202,-641.33655,966.4784,480.32898,-639.1353,960.1879,479.203,-639.0017,953.8397,478.22308,-639.12994,1006.1998,497.0354,-425.5479,945.65717,487.25586,-416.75256,983.4558,516.31244,-604.1914,960.4081,512.0884,-601.06494,1048.375,590.1677,-314.27136,893.28503,581.3011,-313.89285,1048.662,707.1164,-604.97046,876.81006,707.0508,-582.6828,989.87915,654.79834,-993.11957,953.26086,656.7693,-950.91296,977.8202,642.0414,-1078.5739,974.9681,643.88257,-1032.8302,975.09155,620.6938,-1039.4152,972.9389,625.0668,-1000.73193,974.36475,626.1428,-984.9,971.8434,631.5014,-942.80774,1019.3747,765.66815,7.42118,934.1101,764.8312,-6.490435,1006.1673,772.63184,-614.0952,940.1294,757.56573,-654.02356,994.0831,933.5648,-283.4639,953.9706,929.0366,-303.63504,991.15436,961.1037,-261.44946,956.30835,958.9756,-280.6202,975.8909,982.709,-506.52106,956.0041,977.17645,-516.8837\r\nframe__eAW98p-wPQ4__0007163.jpg,squats_down,1162.6891,634.1248,-67.40378,1165.8396,619.76196,-100.99216,1167.9366,619.933,-100.99742,1170.1858,619.9521,-100.97974,1166.9318,615.40875,-44.34295,1169.2815,612.964,-44.28753,1172.0774,610.57526,-44.347126,1192.6066,618.7214,-203.4036,1194.832,608.09546,54.94365,1176.9839,645.98114,-103.45944,1176.7612,642.2849,-28.67352,1242.477,676.7567,-346.07135,1248.6503,647.80273,222.60449,1162.835,760.1679,-449.12213,1168.3491,749.5021,301.27402,1036.2444,792.7469,-365.88553,1056.9967,781.1108,193.7504,1003.5523,797.849,-442.176,1026.457,774.41864,216.5273,999.1523,786.86,-399.0462,1018.1365,778.1845,145.52628,1014.82477,785.62146,-353.0686,1029.457,786.0783,160.44629,1424.2006,813.2257,-182.0564,1415.0802,787.1233,182.90596,1227.9154,766.7845,-225.59784,1210.4614,742.6509,310.02847,1348.6481,906.168,60.287167,1316.5316,883.6874,519.80914,1378.8794,913.9948,90.335014,1346.6746,894.58844,537.50305,1326.5328,951.8074,135.30402,1295.6519,932.8042,591.073\r\nframe__Gq6gXBCMP2A__0009671.jpg,squats_down,1067.2435,255.86479,144.17087,1058.8806,235.52687,150.11421,1054.5778,233.62811,150.12038,1050.3687,231.84464,150.09743,1063.5543,239.83017,86.918884,1062.5231,240.38182,87.186646,1061.2007,241.10855,87.23626,1026.3235,238.41084,204.10535,1040.9865,248.50044,-90.25357,1051.6024,274.18207,171.34277,1056.2618,278.78827,88.586006,937.8611,319.855,454.11096,1011.92035,352.47256,-249.66597,1001.66235,426.5377,734.73566,1081.8502,470.70135,-75.791534,1061.3696,367.81152,928.03467,1093.8922,383.5184,435.02322,1086.38,342.57584,989.6741,1104.31,352.634,440.2547,1075.1896,337.34564,979.544,1096.4023,344.9943,441.5006,1063.4685,348.43027,927.8911,1086.2266,357.34082,450.0534,748.0507,513.4562,231.1407,790.7178,537.11536,-231.4889,903.1123,576.4043,686.09955,1017.96466,631.5614,-177.42355,825.2062,756.61316,886.44495,916.4392,812.8399,-181.10945,788.05304,789.6797,912.4489,867.7575,847.9861,-176.64235,891.9026,795.8598,1055.0609,1006.8218,856.3647,-96.724754\r\nframe__zJBLDJMJiDE__0017590.jpg,squats_down,970.2963,539.0757,-193.63617,984.7546,528.18445,-231.37105,986.952,528.7679,-231.24423,989.323,529.3134,-231.06079,986.2206,528.5727,-171.57681,988.8551,529.4967,-171.56822,991.7584,530.746,-171.71391,1012.2057,541.5968,-325.7068,1013.6532,544.36475,-57.448826,978.3845,556.9362,-227.22319,979.0515,557.86743,-148.90877,1033.6595,629.0674,-447.8076,1020.7821,626.40497,69.65502,910.9571,682.4591,-574.4141,912.803,681.4389,63.65791,776.1087,661.32367,-585.0967,794.6454,661.1412,-104.72594,741.00183,650.8154,-686.07745,769.4693,637.3777,-110.3917,743.9568,636.80817,-643.7474,765.72,636.0711,-190.24652,756.4861,643.57477,-577.7828,775.60223,646.90784,-146.01697,1109.8516,841.8794,-175.76416,1098.3315,817.2573,176.73901,972.82764,735.01917,-202.75883,974.89014,691.82465,289.23203,1032.0994,890.60956,84.106384,1023.8309,850.01355,492.60892,1062.0012,909.6422,114.4634,1049.574,870.5351,511.46567,983.3817,915.33057,153.76956,975.8943,883.0009,576.68884\r\nframe__rSNN-Arbxuo__0010743.jpg,squats_down,926.58606,705.06915,-457.4839,933.26404,685.81775,-483.3152,938.43463,684.77814,-483.52295,943.5744,683.6572,-483.5994,917.2887,685.627,-474.91254,911.17096,683.7579,-474.60648,905.1978,682.11127,-474.53873,946.7575,667.33203,-445.49844,891.7964,667.78955,-410.50058,932.63574,708.3254,-428.83228,915.7936,706.24005,-418.85193,1005.1028,670.17017,-319.63773,846.62317,688.0509,-265.44012,1046.8126,799.3751,-207.97292,847.37756,784.2165,-126.17739,951.03406,831.67456,-203.73117,901.28577,822.64685,-51.635647,928.3258,852.689,-220.6161,904.4966,834.78296,-45.90085,919.7947,819.2728,-227.29541,910.5768,826.0968,-46.824684,927.5027,809.74524,-203.3159,912.6833,822.17505,-45.477295,1024.1538,766.2039,-39.052326,938.05286,774.432,39.8123,1041.6218,801.4246,-314.0014,880.6035,773.76166,-243.03305,997.4176,864.1664,-208.37398,893.24756,822.1155,-216.50012,991.8228,860.6733,-194.48203,898.36346,831.6991,-214.82903,978.7475,906.3964,-232.04555,887.8955,828.6738,-271.82712\r\nScreenshot_2021-02-11_at_15.50.46.png,squats_down,1248.4628,508.9318,-250.21933,1261.43,492.64886,-198.19614,1270.4044,492.21704,-197.91995,1279.4882,491.63177,-198.18593,1235.2656,496.55444,-203.84317,1226.2432,498.21762,-203.6226,1217.22,500.1793,-203.73602,1294.6486,511.16666,60.8992,1207.6647,522.1154,34.34997,1268.4878,535.27655,-159.88867,1234.5217,539.3976,-167.5831,1353.8665,606.98535,55.68098,1164.412,631.5218,38.602375,1424.2427,656.07306,-456.05164,1105.1771,666.25616,-530.9927,1465.593,629.7817,-1050.0112,1072.5015,603.28723,-1173.2689,1499.4818,629.26514,-1154.8173,1049.1366,601.45013,-1280.6866,1475.5796,628.6131,-1155.7571,1065.3129,588.85693,-1273.8882,1459.814,635.36633,-1069.1615,1079.1437,596.73206,-1187.5483,1352.0062,884.0363,16.753674,1225.6846,895.1419,-16.429352,1478.8569,979.5877,-543.85846,1105.8262,1007.7839,-517.50903,1413.4725,1185.6151,-161.25545,1132.1086,1183.5795,-131.34273,1381.5579,1216.0847,-136.25801,1166.8433,1210.1162,-106.40258,1472.4752,1263.8707,-350.48306,1050.0078,1271.8488,-313.83704\nScreenshot_2021-02-11 at 15.18.07.png,squats_down,593.79095,333.01578,-117.39637,602.9976,319.5487,-105.30195,607.6181,318.63507,-105.3303,612.3212,317.65454,-105.395615,591.3371,321.95044,-89.75206,588.0298,322.23425,-89.783,584.68713,322.81482,-90.00544,628.76514,319.00037,-13.724324,590.6604,324.2397,54.78145,608.012,342.6752,-85.08741,594.6794,344.90262,-65.58274,677.47864,358.39673,29.265995,583.0229,372.00653,127.55604,686.2244,297.04733,80.280014,528.429,307.51758,173.1948,641.6148,312.99292,326.52795,591.91656,304.37192,323.86893,632.0038,314.3246,347.32126,605.15076,300.36633,328.68774,632.69653,323.92502,364.25366,609.3387,312.01004,353.37714,637.59576,326.64282,334.81122,605.3923,317.40234,333.01718,683.23285,540.09644,-24.683222,616.82056,539.7286,25.048426,715.4001,505.41772,-383.56284,505.79385,496.55362,-240.88094,721.6186,635.4239,-431.82736,562.1477,620.96765,-302.5268,720.2657,659.9931,-435.3489,590.7174,642.01904,-310.5884,734.66315,660.6568,-564.5107,518.87506,659.6657,-409.81134\nScreenshot_2021-02-11 at 15.17.39.png,squats_down,591.77496,335.9224,-160.3104,602.38306,327.13397,-148.30853,606.9275,327.39984,-148.3131,611.57697,327.5305,-148.27151,591.5436,327.09763,-129.77307,588.2684,327.01407,-129.80754,584.9492,327.10507,-129.90567,626.32416,334.90497,-80.29852,590.1667,333.09183,2.3588996,603.5688,349.77786,-139.53253,590.0996,349.28052,-116.024734,665.4317,391.29727,-114.65094,562.1096,388.30505,35.176006,661.56635,462.43585,-317.0785,478.74817,417.86377,-24.0582,611.7177,401.48697,-481.2492,395.04648,414.7311,-108.87838,597.33405,387.11447,-514.70447,367.28525,410.14664,-110.3222,605.1826,374.17172,-500.0399,367.6698,402.5177,-121.537315,606.7411,382.9912,-479.04874,378.54987,408.13907,-119.22673,649.2746,548.11224,-35.44351,586.7313,546.2741,35.83101,678.00134,513.0337,-391.83694,492.75385,512.6662,-235.27312,696.6442,642.46783,-377.6425,526.6442,634.6435,-212.35356,694.79803,666.1537,-376.6194,548.2049,657.26715,-213.22058,709.0525,673.11066,-501.53635,486.68936,664.63574,-321.9995\nScreenshot_2021-02-11_at_16.18.31.png,squats_down,1226.7666,586.3389,-1177.8224,1237.6896,558.557,-1124.9115,1247.6166,557.38,-1124.6649,1257.617,556.0382,-1124.7374,1207.1821,561.88446,-1130.8564,1196.7242,562.83215,-1130.9728,1186.2684,563.9545,-1131.4845,1269.4414,569.47675,-829.43854,1170.3506,580.22064,-865.4308,1244.467,614.3391,-1070.1213,1209.6228,617.84705,-1077.7476,1344.4465,693.03766,-578.8549,1097.8431,723.5392,-591.5666,1375.8768,870.8073,-751.96893,1078.9362,915.9934,-806.6038,1370.0365,878.4285,-1304.2655,1082.0394,878.7636,-1376.7676,1376.8839,877.33673,-1448.5431,1083.4762,868.917,-1537.0249,1367.1987,846.8941,-1448.842,1085.0044,825.94745,-1518.6317,1352.036,853.2986,-1322.9955,1098.0736,832.94977,-1391.7483,1288.4994,866.94415,-4.595236,1156.5197,878.2557,5.3595214,1359.8577,998.61725,-877.9507,1072.0756,1023.53534,-896.7737,1350.6572,1187.8315,-227.22058,1097.4817,1203.4175,-239.44653,1337.6223,1213.5598,-182.05426,1121.064,1227.776,-197.12018,1367.7823,1282.9556,-492.4873,1064.5035,1297.4592,-516.69385\nScreenshot_2021-02-11_at_16.24.22.png,squats_down,1318.5513,650.9453,-212.75755,1331.1315,628.9082,-163.32642,1340.9235,628.8282,-163.1694,1350.8271,628.6883,-163.23839,1302.279,630.5843,-159.71849,1291.9915,630.86926,-159.24762,1281.7181,631.5216,-159.09435,1363.8694,643.524,82.88756,1265.7595,646.8433,107.58953,1336.013,679.74536,-128.09584,1300.0737,680.87225,-120.4909,1423.0833,760.4643,-49.591915,1209.2767,757.6969,-4.763331,1453.1925,781.92993,-783.6766,1200.2567,783.0647,-692.13135,1350.1652,771.2864,-1224.932,1295.5975,740.06213,-1109.0342,1320.2719,772.3409,-1332.4357,1319.3962,733.5133,-1200.9263,1305.8395,760.26263,-1284.2202,1332.0834,723.3997,-1158.9846,1312.9779,772.5664,-1220.1263,1328.1863,735.9935,-1103.8859,1381.8002,1088.8203,-8.117475,1246.1796,1083.1198,9.234045,1494.0446,959.9056,-761.1861,1143.7552,939.5854,-730.42487,1485.2095,1218.6348,-705.5425,1137.9174,1197.7666,-627.0012,1470.2634,1262.178,-709.8704,1159.4905,1253.9899,-628.5486,1504.2241,1293.6005,-981.7772,1072.3821,1263.2092,-858.90674\nframe__fiWGWUl30I4__0026890.jpg,squats_down,691.7014,240.44354,-375.8676,699.75183,226.363,-348.84088,705.64124,226.28102,-348.72495,711.6085,226.06494,-348.73715,682.5561,226.74086,-348.52197,676.4133,226.66537,-348.266,670.2892,226.71661,-348.33926,719.6151,233.05698,-182.18874,661.0535,233.86136,-184.19487,701.97156,255.00667,-313.4039,680.3956,254.92781,-313.91937,758.6581,301.6427,-84.83269,624.1236,305.07947,-84.373535,784.3719,379.7081,-182.03674,603.41077,384.77798,-187.52728,789.44946,416.58875,-519.71,601.6903,418.90866,-524.6892,794.5869,431.1841,-609.0415,601.3725,432.63696,-606.6179,781.95123,418.7761,-624.09937,607.4967,417.54404,-630.1101,775.8972,414.66504,-536.929,613.33685,414.24374,-543.91187,740.2536,443.4607,5.931091,665.1366,450.99915,-5.006208,790.10077,487.9103,-477.464,635.611,488.2402,-483.5814,778.7224,624.4098,-263.7753,615.2863,615.8006,-253.11058,766.8341,641.30963,-250.0903,616.7192,631.9669,-236.0741,785.79956,684.88367,-425.47937,610.4389,672.114,-391.66965\r\nframe__i1iVWZSPPe8__0005654.jpg,squats_down,939.5853,647.96576,-705.02527,949.93317,625.6877,-695.58154,957.51697,625.6207,-695.5696,965.2979,625.6027,-695.55975,928.37305,624.12067,-700.1775,920.0497,622.81494,-700.0351,911.6244,621.52435,-700.1747,971.1884,628.67865,-569.6821,896.6637,619.8585,-580.30194,949.88617,664.312,-652.4257,923.3726,662.3094,-654.0809,1010.6845,687.622,-434.93842,843.8276,678.70355,-434.16464,1051.753,812.9574,-606.88965,824.59515,810.8088,-439.47223,984.5788,752.3994,-848.2334,916.356,748.41846,-474.642,970.6944,734.3865,-898.24854,946.6659,733.79987,-502.2539,974.0995,710.852,-863.8517,947.07086,698.7679,-490.291,972.7271,722.70575,-837.4192,944.47125,706.44214,-472.9712,928.87665,765.5179,-1.502245,836.2647,766.3113,1.4494027,1018.12616,796.73944,-172.89445,784.90924,801.7623,-293.66833,1017.835,868.55664,67.75225,790.45984,900.9705,-20.98267,997.7131,883.9167,85.606964,793.7099,919.02856,3.0218391,1066.0444,916.2385,-14.629485,779.38983,952.53534,-111.59582\r\nframe__FLGeX3l1_AI__0001511.jpg,squats_down,765.2284,483.132,-159.47182,773.43616,467.5232,-197.16107,776.665,468.05774,-197.24774,779.916,468.62115,-196.99722,771.2438,464.52634,-138.69235,772.49725,462.59137,-138.53183,773.98865,460.68167,-138.63913,805.1372,473.308,-268.4754,799.5979,461.6424,-3.80357,785.4315,500.7654,-187.8302,780.13135,497.19504,-111.52367,883.4193,563.50964,-411.86893,864.846,551.6706,207.67685,859.94354,738.0512,-262.8614,871.6015,685.2965,75.687546,799.04675,647.55914,100.069954,817.96454,630.73926,-326.0575,771.1992,630.2986,97.593636,792.3475,618.0395,-363.07648,796.7568,608.39984,63.14343,800.88763,603.49426,-341.8889,814.1105,612.83185,99.63188,812.3586,607.5738,-331.64304,1065.3287,714.10626,-210.87164,1032.0464,698.96155,211.29625,884.24347,704.00494,-445.44153,842.2776,695.8932,366.02753,951.65485,933.1085,-537.97577,933.6597,878.28314,386.2815,1001.1643,971.6176,-552.64026,968.13446,899.62244,385.76108,855.4915,987.2296,-634.7651,888.05914,953.5677,368.86435\r\nframe__MythPbjCmZU__0008025.jpg,squats_down,971.055,511.39264,-699.8966,977.0287,493.06332,-676.1578,982.81726,493.30734,-676.1379,988.79596,493.55798,-675.9329,958.7756,491.10217,-699.2958,951.20276,489.54822,-699.1568,943.5576,488.18744,-699.01917,984.2736,493.3834,-466.18417,921.664,486.03262,-567.00885,973.57306,524.2715,-613.4796,950.8619,521.4196,-640.97894,987.5753,526.8923,-271.17163,861.5409,545.1194,-547.4057,1051.6176,598.80963,-512.3879,921.7231,676.11426,-758.4794,1071.83,604.75696,-942.9292,1024.6349,638.1759,-882.4169,1090.4435,610.3015,-1023.7238,1049.9684,631.7193,-951.7958,1070.6821,599.9185,-1026.0372,1052.4128,610.3722,-929.43567,1058.1919,603.504,-955.29834,1044.8872,617.9919,-873.5539,898.5682,671.735,80.72949,822.3416,682.4853,-80.46769,985.36194,702.8855,-389.15717,853.42993,723.9299,-684.5693,929.5331,842.25336,-54.625164,808.9022,872.8742,-323.80417,902.2139,868.17645,-31.4234,791.1958,893.00336,-298.35355,976.4747,894.1184,-187.14409,836.67523,935.15533,-496.48984\r\nframe__gHdFxGA4g9o__0007955.jpg,squats_down,260.6161,452.40198,-80.52894,262.0494,440.958,-107.58342,263.2407,440.7516,-107.537735,264.57748,440.4979,-107.552216,262.9328,439.54047,-75.203735,264.71524,438.45963,-75.22771,266.69946,437.47968,-75.205666,279.32312,439.11432,-179.55124,281.69965,435.81232,-35.412815,271.2482,460.14288,-104.42229,271.9245,458.94443,-62.65432,310.58362,489.92465,-241.74492,343.8675,469.10312,65.87844,299.41022,588.5667,-272.21967,350.06384,545.705,87.950066,260.52142,647.8258,-243.93451,319.55594,584.01654,39.902695,250.52951,659.89514,-286.66,311.33105,583.9268,48.742996,246.71266,656.3035,-263.59763,307.79575,587.6084,18.408806,253.35863,652.4673,-237.93951,311.19434,589.4849,25.390305,402.88336,608.31866,-96.63504,418.94342,589.85876,96.94153,308.53598,538.911,-71.199486,340.8509,538.5814,168.93454,316.35654,644.35693,101.077194,362.7266,632.65704,272.7192,328.90094,663.57605,119.24135,373.84973,648.2656,284.09235,272.79025,647.5062,131.79112,329.3487,645.25385,318.93643\r\nframe__zEbmezjb5_E__0004484.jpg,squats_down,314.94528,404.56268,-100.61166,307.82452,391.81818,-129.34671,309.15735,389.79947,-129.38449,310.69235,387.6137,-129.31216,306.91403,391.5525,-75.67987,307.66336,389.38345,-75.58464,308.88937,387.1866,-75.62148,327.30444,374.24258,-197.29185,324.2772,375.2867,49.357292,333.00797,404.94528,-123.42256,331.86935,405.51886,-51.3935,394.72742,410.09985,-294.3188,389.12643,370.30536,231.52626,336.03427,515.1456,-444.41837,333.95392,454.87405,376.85544,224.9134,538.4153,-383.79825,251.09459,473.8659,284.9699,194.91833,544.419,-440.27127,229.78717,466.91495,303.59372,192.05075,526.7757,-402.88763,227.9585,466.70453,250.35591,203.50955,526.2658,-370.32355,235.4142,472.70947,259.4714,562.83496,503.79523,-176.92325,554.84875,483.27438,177.34831,422.39935,468.48267,-319.71753,407.9441,458.41565,396.16757,455.80167,622.71686,-66.36056,459.80774,573.47614,728.975,473.17596,646.8943,-37.32469,477.36295,596.16437,757.2886,399.17633,650.1483,-64.88478,418.81537,586.14307,759.01196\r\nframe__E4JICzRQz1o__0017185.jpg,squats_down,1242.8953,560.92096,-276.09583,1247.7246,545.8421,-232.46007,1249.3263,547.1255,-232.20235,1251.1134,548.5271,-231.726,1237.5029,539.93,-282.54114,1232.0327,536.1776,-282.3817,1226.4833,532.6828,-282.58313,1232.3387,548.9117,-13.326255,1203.9489,531.0162,-245.37134,1233.4359,579.06274,-199.93407,1219.5547,570.3981,-263.4794,1166.8284,628.6249,218.61923,1168.3003,635.56824,-355.50674,1216.1217,768.2196,129.96423,1245.209,777.52295,-205.10985,1250.8899,748.93994,-203.39014,1249.6212,751.64197,200.96367,1262.1809,739.22186,-214.47256,1246.48,744.1388,219.72253,1246.1179,729.6787,-197.29129,1231.3804,741.896,216.08537,1238.9846,733.6553,-206.84282,1226.5676,746.12244,216.86813,1031.098,837.8949,197.70323,1021.6904,845.4067,-197.6318,1209.5533,822.3423,298.70032,1244.7324,818.2723,-212.28905,1102.0879,938.9549,346.73135,1088.6848,952.46674,-109.81341,1076.3766,960.4894,350.3843,1050.1726,972.021,-104.92147,1142.1133,986.1492,387.01376,1108.5288,1021.16833,-69.53444\r\nframe__dxA21IeBB8o__0006042.jpg,squats_down,1816.1401,870.56805,-1368.2301,1837.1206,834.1015,-1311.6401,1850.7352,833.4942,-1311.7393,1864.4675,832.59235,-1311.8198,1796.8612,834.79596,-1307.4111,1783.0784,834.43353,-1307.1432,1769.2101,834.26337,-1307.1952,1883.4543,842.6396,-916.33734,1752.3489,844.2417,-901.1848,1840.1038,904.30597,-1216.489,1792.9077,904.50507,-1211.205,1975.009,1026.111,-591.8574,1655.605,1005.02704,-580.93317,2008.5652,1312.4736,-951.161,1612.7976,1274.1129,-1008.7798,1870.3395,1163.6746,-1580.6199,1756.7091,1156.3198,-1702.6726,1823.4878,1119.5128,-1734.8546,1801.5001,1121.0952,-1839.2384,1838.2794,1064.2222,-1658.3743,1789.4028,1082.466,-1779.8743,1842.6123,1079.5325,-1560.3844,1790.2726,1098.0013,-1685.6033,1902.3115,1365.1262,-0.5703969,1708.4004,1352.6035,1.3023654,2101.0305,1535.7532,-1059.1355,1536.5571,1515.4446,-973.0779,2080.602,1819.5223,-257.99744,1518.1611,1809.5874,-209.3121,2046.7886,1867.24,-198.03314,1547.3707,1869.4484,-157.02782,2150.4302,1926.2675,-634.0663,1413.2634,1898.0425,-602.45056\r\nScreenshot_2021-02-11 at 15.54.28.png,squats_down,594.6696,267.58597,-83.24939,600.2588,258.93875,-59.71149,604.682,258.49243,-59.59498,609.14923,258.0079,-59.509003,587.3618,261.2574,-61.27162,582.9468,262.12646,-61.252537,578.5481,263.12427,-61.441067,617.4671,266.31537,66.01221,574.2399,273.06143,60.5326,604.98175,280.13666,-38.50266,588.7334,282.6323,-40.05449,642.77075,310.93515,86.57768,554.92004,316.4135,70.947266,687.51056,307.70294,-85.32222,507.9797,316.21326,-182.3952,663.6285,302.915,-279.60806,531.5091,294.80786,-424.8327,661.65283,302.93286,-328.5139,531.2896,293.69492,-472.4736,650.6028,302.08514,-322.6141,544.9194,291.05722,-461.9991,651.4632,307.47757,-285.1455,546.9112,296.662,-427.47873,631.96924,442.6159,4.4087267,571.731,442.7265,-4.0594897,710.3822,431.5183,-293.40262,490.22687,442.5856,-278.0609,662.13916,542.3466,-186.82317,533.0541,533.39355,-157.29155,642.97375,560.55994,-181.77669,555.0784,550.38586,-151.78044,684.9876,581.80304,-284.90564,502.0312,571.9429,-248.84377\nScreenshot_2021-02-11 at 15.33.07.png,squats_down,635.6119,401.39227,-574.15405,640.1657,387.4677,-560.542,644.4277,386.91003,-560.588,648.75543,386.3111,-560.47205,627.23035,387.55038,-566.7256,622.3073,387.04788,-566.6601,617.3766,386.56693,-566.57715,651.36316,384.963,-447.8183,607.7151,384.85825,-467.35208,641.6142,408.88843,-528.92676,626.1508,409.0518,-534.4153,678.6625,420.51862,-348.93484,574.5566,418.91443,-345.8068,694.95276,504.11523,-508.6218,559.53326,508.10394,-470.4429,651.793,451.3279,-682.0197,602.6715,448.63144,-607.8904,639.4994,433.25223,-711.8845,617.9576,429.66956,-630.09235,643.8917,422.10242,-678.77277,611.2982,414.7036,-609.25806,644.08685,430.22293,-670.33246,612.1123,422.31323,-601.45404,646.268,479.975,6.695673,590.58875,479.68533,-6.853481,689.01385,535.0158,-269.21954,577.5902,542.2688,-254.93762,693.73285,625.7636,-137.69257,572.192,633.39215,-99.17005,687.84906,642.38745,-130.21556,574.1827,647.24054,-91.47898,712.8435,657.94073,-229.85243,565.3794,671.00885,-211.8264\nScreenshot_2021-02-11_at_16.03.20.png,squats_down,431.42355,171.14507,-147.9283,436.04916,163.75145,-129.91019,439.58334,163.80847,-129.91661,443.14648,163.80914,-129.94936,426.46173,163.91768,-130.37465,422.83234,163.96272,-130.31602,419.208,164.11723,-130.3026,447.88443,169.92358,-48.078938,415.014,170.4618,-48.70554,438.2521,180.69145,-119.94952,424.939,180.82956,-119.90857,466.8892,215.11151,-31.723629,396.40317,215.86644,-54.71734,459.18466,277.1425,-144.06973,420.34644,275.8095,-98.08421,455.8762,223.58482,-235.027,454.14,222.31917,-72.04496,458.29453,206.68279,-254.29253,464.09375,210.14812,-76.7239,464.86905,205.53362,-237.41525,457.31235,203.0488,-61.492954,460.64,210.85304,-230.9771,456.58124,208.09923,-64.07362,454.96497,315.18994,2.5330894,413.79086,317.84912,-2.248651,474.21957,303.46216,-230.81345,384.5699,309.14276,-254.79886,468.23288,363.6381,-50.74041,395.70596,369.9179,-69.05485,465.85104,369.62482,-33.72403,403.2667,376.7699,-51.30457,473.7895,398.29086,-101.76441,379.0397,403.57013,-120.54024\nScreenshot_2021-02-11 at 14.29.32.png,squats_down,501.26114,321.06604,-291.2112,505.905,309.25443,-273.14105,510.28775,308.68707,-273.11258,514.75885,308.05124,-273.20578,493.8463,310.4615,-275.64917,489.22696,310.6595,-275.5745,484.63705,310.98895,-275.49365,520.5431,311.9024,-160.77348,479.663,315.7458,-169.87404,510.63864,330.9157,-249.13475,494.2215,332.30023,-251.59502,556.6478,357.51556,-91.33532,450.91675,365.77985,-99.079155,620.5439,401.7664,-222.18991,407.51355,415.39508,-240.16855,629.5003,363.14856,-409.94513,388.52133,362.58987,-422.25583,634.5078,350.02136,-440.91406,378.19897,344.88736,-453.8452,625.7629,342.65472,-422.1738,383.9684,338.85843,-435.64148,620.9544,350.79254,-407.10406,391.70154,347.562,-419.07666,550.8508,463.95035,6.8205075,490.7139,470.82822,-6.5374293,610.80096,490.8208,-283.9204,473.78003,473.23947,-281.81033,612.8738,585.7529,-241.75346,502.63205,515.3196,-185.92503,605.7256,600.7492,-240.76175,506.63004,522.3509,-180.32932,634.9473,609.6394,-360.01974,520.56146,524.39905,-272.9413\nScreenshot_2021-02-11 at 15.55.40.png,squats_down,656.25226,315.04218,-174.1422,669.3417,306.19714,-149.44336,676.0119,307.31055,-149.32214,682.6809,308.3356,-149.28148,651.7173,304.54614,-148.28778,645.5014,303.9284,-148.1734,639.2309,303.52057,-148.21317,694.00354,322.2135,-30.126137,633.4581,315.56464,-25.268456,668.09796,336.4641,-134.53827,645.1846,333.59006,-132.83325,715.9689,389.54117,-61.631252,604.759,394.10788,-11.283574,733.3621,455.16248,-298.68567,592.25714,461.44662,-235.42015,722.0458,415.246,-516.2334,580.4832,409.5389,-469.7153,724.43176,404.23477,-557.9205,569.1036,396.09323,-511.15524,721.21954,397.9354,-545.92993,573.20825,388.76578,-498.36475,715.665,405.55637,-518.2392,583.30475,395.02057,-471.07318,707.3528,547.03644,-4.6728787,638.0438,549.4675,4.8307056,788.0351,506.54083,-262.94763,550.45734,511.16318,-215.90253,750.50555,644.2541,-157.2918,572.1429,634.6046,-167.11775,731.2089,666.8079,-150.95705,588.8573,655.814,-166.85562,777.9494,674.8229,-257.26807,543.3739,669.4474,-262.2415\nframe__ku3vgejAZ0g__0010351.jpg,squats_down,1089.1763,536.872,-268.141,1080.819,520.58514,-219.33293,1082.7814,520.5341,-219.29965,1085.0695,520.47516,-219.34973,1069.2155,519.7435,-267.82208,1062.3063,518.7721,-267.77545,1055.421,518.07306,-267.96524,1065.0157,521.32306,-4.3183866,1025.4167,518.8583,-227.43492,1083.003,552.5854,-190.31644,1069.4648,552.39777,-253.91971,1063.004,603.24274,117.063805,962.9995,582.7078,-360.25955,1100.6001,679.3981,-76.52804,1026.0325,698.3313,-551.6274,1158.8086,659.1676,-424.56787,1136.405,653.316,-497.6107,1185.2947,655.23987,-463.9632,1164.414,644.1695,-546.68616,1175.5668,642.03534,-481.8151,1158.7162,626.609,-525.6171,1161.2743,647.01636,-444.6357,1145.4335,634.3524,-485.61115,948.6219,798.1707,143.38304,878.8669,789.33673,-142.36061,1087.707,745.66223,97.96406,965.4576,730.87213,-492.76434,991.551,862.258,239.30423,903.4224,893.3708,-287.05954,951.8606,882.296,251.27509,869.8579,916.3763,-268.42154,1054.814,917.6792,148.46362,953.6061,951.63074,-441.89398\r\nframe__4zBnM_uozXM__0006346.jpg,squats_down,912.0396,468.82996,-83.099495,915.71967,445.34442,-113.75527,919.7457,443.74802,-113.61939,924.03937,442.01196,-113.52703,911.41,443.33823,-54.016537,911.93494,440.04288,-54.03214,912.8896,437.11948,-54.32088,953.76215,428.0739,-189.44096,936.3451,421.94235,74.54492,936.8128,476.84213,-111.30873,931.1723,474.09906,-34.792736,1034.0497,471.42297,-331.06772,982.375,480.50772,199.76115,879.3588,567.4179,-501.94495,829.72644,577.16766,172.44873,694.84204,588.14703,-466.2247,680.76715,600.43115,-15.541933,650.81464,593.58075,-544.4817,640.72003,591.40564,-27.266193,644.8103,577.2099,-516.82886,637.9703,584.14703,-99.46672,663.6092,579.5873,-461.08057,655.4302,593.5936,-55.773396,1173.9391,750.3837,-166.0862,1135.2749,747.0622,166.46594,977.0137,558.91565,-396.977,931.8652,567.47974,272.33902,1003.9556,803.097,-196.76366,972.7002,778.5916,448.2902,1035.5801,842.40234,-175.55019,1008.0144,812.1081,459.68826,912.4461,848.23236,-218.52985,885.438,829.53375,484.79672\r\nframe__JSn5DY10dbA__0005040.jpg,squats_down,1003.0693,195.41663,-595.91327,1024.8713,175.0781,-564.87445,1036.2773,174.30069,-564.65424,1047.7714,173.39812,-564.7045,998.15137,179.61417,-530.03076,990.32904,181.16417,-529.74115,982.57654,183.2105,-529.7938,1082.8706,193.42206,-406.0095,994.7484,205.55016,-250.76419,1035.6758,229.29578,-541.4552,1001.82324,233.06003,-496.283,1172.4286,310.9668,-470.04187,975.486,362.01035,-198.3269,1109.0105,392.5028,-735.7692,835.8464,471.59503,-613.75934,984.59186,271.62897,-820.5203,887.09607,274.15033,-919.2685,952.4229,248.68799,-879.7028,887.8576,224.64899,-977.11224,966.3313,236.44563,-863.2378,912.58905,204.83385,-895.2587,981.1241,253.27512,-816.3001,921.0345,226.23143,-900.5902,1227.5356,614.2086,-63.865765,1101.6987,637.5921,64.02299,1250.819,597.89417,-783.64355,928.1278,646.94525,-421.77957,1288.7449,880.31995,-483.4913,1003.85974,876.32983,-240.85883,1282.8618,938.53796,-467.2115,1054.2368,919.1541,-232.66489,1310.1295,937.5218,-740.23926,890.6353,965.3988,-408.35794\r\nScreenshot_2021-02-11 at 15.53.32.png,squats_down,181.2457,319.96588,-119.30942,183.36227,312.97287,-107.57338,186.52573,312.7294,-107.48516,189.73625,312.4551,-107.47218,174.0048,313.5022,-114.21376,170.00108,313.5872,-114.12447,166.01028,313.75803,-114.11259,190.55022,316.29126,-32.30489,157.25916,318.62802,-62.78676,185.48125,328.81433,-90.07932,173.41986,329.20242,-98.77729,198.2487,345.3012,-9.753522,142.18037,345.16678,-47.403885,211.80191,374.0356,-42.85668,139.98814,367.6527,-138.29042,221.07617,403.08725,-149.5297,150.94855,395.42844,-279.97092,229.60426,416.16953,-177.776,149.93056,410.7356,-310.0184,217.45377,415.04794,-191.77258,160.5702,405.11246,-320.3274,213.61511,411.89066,-157.70764,162.32954,402.5785,-286.16672,194.50314,419.238,3.8338125,162.70741,420.54214,-3.447775,206.16185,392.17746,-172.36807,134.69238,392.16672,-156.808,204.92252,432.52057,-69.99356,149.50302,435.61386,-62.45088,201.05957,441.53842,-61.3153,158.08177,445.7479,-55.139854,208.61479,445.59332,-117.12904,140.79276,451.38138,-98.608894\nScreenshot_2021-02-11 at 15.29.23.png,squats_down,568.52216,306.21332,-158.68083,573.96857,297.16806,-133.57054,578.576,297.3675,-133.54427,583.23834,297.50925,-133.4997,560.3096,297.63022,-138.42299,555.1917,297.873,-138.32652,550.06793,298.254,-138.31891,587.96436,307.1808,-13.549839,542.2495,308.0763,-38.74737,577.03033,320.7157,-116.57769,558.59973,321.0889,-123.70214,608.88275,368.7121,23.078564,514.2842,361.54074,6.5425596,653.71826,391.08487,-33.44489,446.21674,360.91693,-58.32265,676.07574,335.9748,-42.824318,512.50836,345.2018,-78.77546,687.85974,315.43094,-56.528717,528.1664,342.65848,-85.275826,682.58215,312.22638,-37.214577,537.54474,340.77435,-69.01622,675.3741,321.79956,-41.837044,532.20807,345.99576,-73.200386,589.05304,508.70914,11.853202,527.96893,508.61505,-11.61281,680.80835,507.5417,-225.06992,465.8734,511.9342,-294.40573,633.36346,612.0962,-101.71079,479.18256,620.32776,-186.32872,613.38855,626.3001,-91.64533,489.8865,636.0479,-177.1175,664.63055,653.76465,-170.4594,458.70157,657.7,-274.7396\nframe__8ghtQpeWov8__0004585.jpg,squats_down,957.49884,474.1373,-763.42163,967.35767,450.20145,-741.15985,975.34045,448.90244,-741.0927,983.3765,447.38416,-740.9919,944.51654,452.5616,-738.83044,936.2819,452.58997,-738.6686,928.07166,452.79953,-738.52765,995.9403,447.35764,-539.072,918.7821,454.3529,-522.68317,973.1092,488.31073,-682.63214,945.93835,490.8539,-677.616,1052.1462,521.5969,-351.56424,871.5408,513.33704,-329.71045,1135.6521,639.57245,-484.71194,782.13196,600.33167,-292.01437,1059.8157,641.02435,-792.82056,781.244,670.89923,-469.24127,1039.2308,641.5075,-872.1592,777.4826,693.76025,-507.79736,1028.1367,623.1558,-857.65,793.4562,684.35394,-536.1176,1030.8497,625.7903,-791.93524,801.83545,677.35944,-478.98474,1017.9682,695.3985,-1.9494627,914.15643,698.5377,2.430919,1146.6963,732.4262,-479.5763,796.22284,751.29144,-457.51254,1119.3346,868.29694,-40.74559,814.8216,887.85455,-42.86966,1096.8389,891.6491,-4.7464614,836.3593,911.1852,-9.867107,1171.8799,919.1696,-170.00424,768.5288,944.7508,-194.46701\r\nScreenshot_2021-02-11 at 15.17.52.png,squats_down,593.501,337.67084,-39.052227,605.4996,327.2368,-29.775951,610.7842,327.7456,-29.687258,616.1807,328.1647,-29.73648,593.9798,326.55618,-6.8276405,590.6403,326.1344,-6.871863,587.19336,325.86102,-6.931928,631.7453,337.24527,21.212894,593.4091,333.26743,128.62259,605.57153,353.7512,-23.771343,590.73413,352.42477,7.1302805,673.1561,403.5548,-3.1526268,564.77966,401.97592,156.85031,661.2074,477.0978,-196.11053,525.4172,474.50876,-0.5467376,623.7662,390.98523,-324.31015,545.5833,397.1084,-159.864,616.2233,370.4779,-344.53754,547.84796,373.81708,-178.00615,620.9046,366.33267,-315.93115,550.83704,367.3702,-143.81049,619.0413,376.29788,-311.8992,556.4424,378.0648,-149.80357,650.44727,564.00946,-31.478777,580.8139,565.33307,31.770758,689.0734,523.1714,-393.39133,504.10754,522.5191,-244.15051,695.3634,653.2589,-318.12405,529.10547,640.94763,-196.04546,691.75995,673.7228,-310.27786,546.8283,662.5809,-193.18199,704.4898,701.4321,-435.46832,491.2835,679.32666,-296.64227\nScreenshot_2021-02-11 at 15.23.45.png,squats_down,599.9967,322.7697,-234.96815,606.7789,313.03992,-206.14264,611.7288,313.02325,-206.19728,616.77014,312.94266,-206.15338,592.60315,313.75638,-203.64116,587.683,313.87244,-203.57133,582.7716,314.18027,-203.52443,625.36383,321.1088,-78.26213,577.2867,322.26843,-63.430286,609.87946,337.0592,-191.50983,592.5666,337.49677,-186.84932,664.6362,380.22275,-94.3344,545.4984,378.72006,-83.7646,732.5181,373.4138,-392.87582,471.72513,382.05106,-348.14352,643.2541,346.6418,-525.3892,565.75574,349.80313,-446.5408,621.37897,338.3651,-549.6626,587.8645,339.10245,-461.72568,617.36444,342.162,-497.0093,598.77686,339.83893,-410.8474,622.7943,352.67023,-508.90253,592.7388,350.0921,-427.94077,635.21136,540.43616,1.2943888,560.03143,539.7365,-0.8949692,709.9108,503.6313,-382.20343,491.91425,501.1584,-361.40735,697.45233,636.9934,-304.94388,515.1391,630.3372,-270.4223,683.89636,661.75104,-300.22662,530.67114,654.4954,-264.38635,726.20435,669.21466,-445.58353,488.97314,658.8001,-403.55032\nScreenshot_2021-02-11 at 15.51.16.png,squats_down,215.11275,387.6314,-198.1269,221.72058,374.35614,-184.0018,226.92978,374.087,-183.91766,232.25996,373.76486,-183.95045,207.0521,374.89078,-185.51303,201.3179,374.8511,-185.43567,195.54521,374.95355,-185.52386,238.88774,380.27054,-82.07879,186.94667,381.5534,-90.204605,225.07452,400.54916,-159.47769,204.8261,400.7766,-161.71426,261.65173,425.63373,-53.1573,160.73169,419.7415,-43.055893,294.76196,471.74927,-166.80397,95.69197,434.57715,-163.34213,294.18118,500.6081,-373.04037,48.81151,427.17697,-336.99026,302.45023,519.55853,-422.0547,27.428955,431.5065,-371.6272,283.69296,510.18402,-431.73706,40.58457,421.70773,-384.72614,278.73383,506.49615,-383.9192,48.42332,424.89008,-348.82068,237.72704,554.6378,-0.69511986,186.149,552.94006,1.0255028,276.1855,516.4556,-293.60464,145.8542,514.00226,-263.35876,250.69267,603.6086,-107.17166,178.6729,595.95984,-58.74429,237.70341,619.4541,-93.86878,195.52782,611.7192,-42.421005,273.42523,641.01587,-191.02647,148.11002,636.67993,-120.22644\nframe__4zBnM_uozXM__0005710.jpg,squats_down,983.2969,188.75082,-482.7785,992.5643,172.61496,-404.93387,1002.92474,174.6429,-404.66995,1013.4731,176.51094,-405.01782,959.5239,171.07663,-435.67825,946.33563,171.47491,-435.42914,933.15063,172.35843,-435.28424,1013.10974,211.05356,-86.82578,900.9824,206.38278,-216.99568,994.4283,236.97214,-373.924,951.9268,234.4249,-410.91025,1059.4642,382.16388,-116.14926,806.82886,361.99643,-378.50958,1174.6085,424.22247,-736.2966,809.3042,429.59985,-927.23517,1244.8003,432.8661,-1360.7511,1005.08057,401.12195,-1169.0558,1292.8832,451.01855,-1493.1561,1043.1919,412.11786,-1235.8177,1252.0751,441.95346,-1490.5258,1069.0,399.11502,-1204.4187,1225.2311,448.7007,-1384.321,1054.6924,409.88562,-1156.0641,986.18225,760.8079,49.900448,828.2257,750.21436,-49.958294,1221.5364,631.51184,-529.43085,690.08887,609.90826,-775.0792,1053.8141,895.93024,-197.41191,774.0629,892.00385,-321.20197,982.6012,947.8567,-174.9347,818.1572,952.67786,-286.75775,1166.7777,985.42804,-381.8975,685.451,972.3387,-512.4726\r\nScreenshot_2021-02-11 at 15.57.08.png,squats_down,182.97452,286.71176,-185.22168,188.06578,276.85788,-180.02528,191.90968,276.93118,-179.98288,195.80594,276.95016,-179.96976,177.35971,276.40585,-182.21822,173.19885,275.98288,-182.20175,169.03058,275.62744,-182.21902,199.00647,279.84265,-109.727,162.09453,277.80475,-117.640854,188.10115,295.8418,-156.40141,174.69278,295.0182,-158.29004,214.3812,308.26526,-62.253216,138.345,310.4176,-69.24025,228.51003,349.2151,-126.98737,134.4225,364.72415,-134.74289,236.20189,328.35486,-274.86526,133.80502,336.47308,-268.61172,241.48196,325.54343,-303.3597,131.2242,331.98135,-293.62842,238.85423,316.4815,-309.52924,131.50919,319.6082,-292.80377,234.28427,318.5532,-281.58408,134.80544,322.2257,-271.3417,195.80298,397.7948,1.0934308,148.5667,398.20682,-0.97439134,244.53282,413.38623,-191.453,106.54336,410.48285,-182.25899,220.8233,476.34012,-53.67571,119.960945,476.0184,-42.57923,208.75421,483.52396,-43.549118,129.90451,485.14587,-32.485695,234.09038,513.3103,-117.69791,104.91976,511.20148,-102.05955\nScreenshot_2021-02-11_at_16.12.36.png,squats_down,1462.7247,699.9712,-891.76166,1473.1001,668.5049,-884.29755,1480.6908,665.8377,-884.44977,1488.4908,663.036,-884.647,1448.0316,670.23914,-897.3804,1438.5238,668.4885,-897.2328,1428.9045,666.9407,-897.0172,1492.4724,643.5815,-685.64984,1408.4637,646.7397,-737.0836,1469.2502,703.9257,-804.3362,1443.6002,706.261,-817.8314,1549.6378,679.00507,-492.0584,1319.7731,687.62787,-512.6302,1623.4222,836.2869,-758.0481,1262.5922,876.5435,-734.056,1516.7179,784.3182,-1109.8088,1386.207,788.17535,-1005.67993,1492.7866,768.566,-1176.5472,1433.5868,770.05817,-1051.9642,1484.6946,751.5803,-1112.3026,1419.952,723.5809,-1007.03723,1484.6223,760.43524,-1089.4442,1415.3193,732.3492,-990.04584,1456.1393,866.6968,0.74213195,1333.0891,870.2441,-1.0492775,1624.1124,916.42773,-602.12524,1219.0709,901.3498,-610.739,1592.0822,1124.9576,-265.4228,1250.8026,1107.8263,-241.07968,1562.0057,1161.5548,-240.8137,1271.9653,1143.8282,-210.98813,1664.4576,1202.4718,-455.86105,1197.2764,1178.3339,-423.82895\nframe__jFWW75URYbM__0001376.jpg,squats_down,1021.0029,531.22144,-967.5817,1030.5072,509.8142,-937.8234,1037.3494,509.06458,-937.86847,1044.2352,508.22125,-937.7742,1010.93756,510.83508,-937.05884,1004.08014,510.6894,-936.95734,997.1575,510.6193,-936.88007,1054.3762,510.67636,-721.6717,989.63995,513.925,-717.7918,1033.3777,546.22955,-885.8834,1010.2413,547.45953,-883.29694,1106.2355,588.40234,-538.8164,943.9029,585.7689,-549.3508,1142.6473,715.74347,-848.77246,891.5184,702.0886,-862.0684,1127.5007,650.45624,-1223.4082,923.4306,623.2921,-1238.6831,1129.1754,621.3326,-1304.169,931.90436,594.1448,-1317.2373,1129.1611,603.52686,-1252.6453,932.4737,577.23914,-1265.4701,1119.7775,614.8939,-1210.1958,940.05115,591.6735,-1224.2861,1075.721,726.01263,1.0623958,981.2503,720.9779,-0.5014061,1169.8666,771.1002,-618.9506,908.1292,759.0266,-642.9466,1143.578,890.8534,-114.640884,900.3897,893.82745,-157.40369,1128.6763,910.15454,-75.52841,910.8176,919.19244,-123.018654,1167.766,945.87427,-304.25446,864.2399,943.2741,-372.44653\r\nframe__XJcoOdKlYqk__0022306.jpg,squats_down,1659.3796,956.8546,-351.14212,1676.7346,925.67456,-442.76697,1680.0947,926.11597,-442.854,1683.8602,926.4472,-442.93964,1682.9874,919.69495,-318.36597,1690.7856,916.41705,-318.10095,1699.0857,913.6328,-317.93903,1736.3877,927.0802,-628.34204,1757.075,909.9212,-61.561905,1689.0898,989.19824,-419.45673,1696.5502,982.0935,-254.56444,1847.5553,1091.0729,-816.8452,1878.0665,1096.2693,365.45102,1669.1342,1355.9225,-639.04083,1767.166,1305.2366,307.0449,1532.5408,1179.3501,-142.9137,1576.9858,1163.1996,-36.78929,1474.2104,1132.7311,-222.56197,1515.846,1108.192,-43.879612,1526.0369,1105.6051,-260.10883,1527.8987,1094.8285,-19.251915,1559.3102,1128.5934,-143.23254,1556.9103,1111.1506,-48.8448,2177.8364,1433.8042,-396.94693,2154.9194,1403.2499,397.9059,1880.758,1468.9893,-1059.1218,1869.3,1439.0741,1155.8744,2002.9808,1900.8746,-1085.9364,1936.0419,1762.9719,1678.2122,2067.8958,1985.4985,-1094.0911,1988.9053,1828.7461,1734.5747,1804.1887,1963.6445,-1258.8074,1758.0217,1842.2529,1765.8468\r\nframe__8soywvU3l0w__0021627.jpg,squats_down,965.2605,665.5643,-587.8748,972.6101,649.8622,-567.34607,978.7721,649.5626,-567.3762,985.0491,649.17834,-567.4626,955.3118,650.75073,-565.5137,948.9194,650.83246,-565.41473,942.451,651.04376,-565.3384,994.1208,657.0952,-426.30322,934.39514,658.18286,-416.654,977.64246,681.12897,-534.62726,954.7337,681.80676,-531.06573,1033.7384,725.55035,-325.82022,901.7915,725.53625,-334.83847,1079.0729,828.74713,-458.2196,858.1751,836.24396,-439.66107,978.07056,830.9537,-591.54736,946.74945,849.0601,-585.67255,953.1269,835.8589,-631.5623,969.9454,857.72186,-634.86115,948.99176,819.1405,-609.12994,975.6863,836.8312,-614.2369,956.4781,819.6742,-584.6992,970.9075,834.6104,-580.0798,991.1838,852.7862,7.2751703,919.7475,850.027,-7.1756806,1107.787,843.42035,-405.71115,868.56433,829.48944,-492.04364,1066.9666,944.63824,-64.346436,866.0554,927.0116,-120.053375,1046.7539,959.5151,-36.049717,875.61084,942.654,-87.89264,1109.486,998.4556,-166.00146,832.5806,971.1435,-232.61682\r\nframe__UwW586G8GnU__0022398.jpg,squats_down,644.0616,362.5655,-457.41284,649.3552,352.9372,-437.90634,653.2446,352.88834,-437.86383,657.1891,352.78064,-437.84552,638.19666,353.15094,-438.48343,634.1758,353.10858,-438.28458,630.13904,353.14523,-438.2246,662.28827,357.01825,-300.91504,624.0882,357.64984,-306.7423,650.7321,372.17728,-404.84827,636.23254,372.16544,-406.4159,682.9762,397.72296,-214.5765,599.0714,401.6361,-217.9118,699.38635,444.20264,-386.31134,585.1313,453.5862,-366.7024,675.98444,457.6959,-670.4095,618.9143,465.14117,-613.17926,673.09265,466.44064,-736.0056,626.9128,472.44263,-672.1375,663.8584,458.72614,-725.95856,634.4189,464.12683,-670.7032,662.8226,457.35684,-672.9107,633.9617,462.58804,-616.76953,667.6544,490.12515,2.0670397,618.6228,492.8327,-1.5724444,702.1711,504.70334,-375.44986,595.1192,508.6787,-386.5927,713.9259,607.8436,-214.33209,578.9396,609.5449,-209.72644,709.47076,622.82477,-207.0058,579.4269,623.0471,-199.96414,723.69214,644.53467,-364.01523,576.0386,648.03314,-350.34573\r\nframe__4zBnM_uozXM__0007108.jpg,squats_down,905.32605,253.62476,-32.01108,920.1732,227.24161,-67.2358,925.2216,226.36691,-67.10982,930.52783,225.34685,-67.16246,918.3915,226.22377,-2.97544,920.9509,224.62532,-2.9297318,923.8739,223.47595,-2.8605123,970.67377,231.05426,-154.694,959.6606,228.19281,136.12057,929.98035,278.6484,-62.86543,925.1412,277.52917,21.00462,1037.538,343.00677,-312.54266,1011.7264,369.92688,306.0261,829.52765,437.28235,-428.9226,828.2601,470.84607,379.13843,616.99084,422.0319,-350.5639,633.8168,442.12436,256.1401,563.27954,412.7181,-420.2802,587.36255,412.39444,267.59543,560.94226,393.15097,-390.48254,577.7273,405.82928,190.59297,581.94336,405.0972,-341.81595,596.56085,423.67465,216.1954,1231.5131,719.21405,-203.30824,1194.2687,706.29553,204.22096,957.1795,569.1819,-294.519,922.1333,558.97784,269.0517,1111.8757,850.7274,9.534981,1035.8513,821.5391,474.72314,1174.8118,880.40515,38.852943,1094.0414,850.7153,490.8913,1039.15,935.3257,103.93984,946.8771,922.9581,582.9259\r\nframe__0Wad9V2m4JI__0012916.jpg,squats_down,696.022,351.67413,-152.19284,703.872,341.68295,-121.83387,709.34607,341.96555,-121.84796,714.9139,342.1427,-121.92626,688.84436,341.65005,-122.752754,683.2732,341.66757,-122.67116,677.67664,341.77628,-122.7472,723.85834,351.5444,14.182044,671.24207,350.5136,12.199427,706.80176,366.46347,-106.09566,686.5276,366.066,-106.77321,754.7865,412.974,28.273632,637.1842,411.92233,9.634175,749.4288,500.46732,-104.63891,649.87616,502.68768,-123.74162,717.1833,495.4404,-289.5716,691.1599,491.25375,-277.17087,711.4951,502.60306,-332.35858,702.4633,492.25388,-313.50674,708.0401,488.74698,-326.8468,698.66064,477.074,-313.8519,705.9222,486.57568,-291.3787,698.397,477.66803,-278.77588,719.93665,565.5901,16.023472,646.81226,567.8685,-15.423757,788.8456,532.5856,-298.1436,616.8281,533.3341,-390.69952,758.62866,642.91925,-182.04001,625.0129,641.109,-222.2768,742.02527,657.8689,-172.0566,632.3696,661.71844,-205.58081,775.83105,693.88135,-293.99326,601.96094,677.19196,-310.49146\r\nframe__mGvzVjuY8SY__0003053.jpg,squats_down,879.3353,444.00262,-513.6883,901.8752,419.73615,-509.8059,911.6291,419.62756,-509.74463,921.39777,419.37302,-509.6632,881.0497,419.15646,-465.68796,875.06586,418.16867,-465.39813,868.98535,417.48654,-465.17633,951.967,426.48038,-417.47278,883.617,422.5289,-219.11661,903.3679,467.83432,-478.43402,877.46594,465.0803,-420.131,1024.9235,525.6636,-376.3382,844.6256,520.135,-90.44048,1000.57983,678.407,-534.47156,749.3496,689.6903,-454.089,902.9732,539.1032,-588.2616,824.5098,550.9432,-846.5089,866.96515,512.7049,-602.07495,840.0467,511.49738,-883.62134,894.1496,488.85565,-581.7256,853.9755,487.19907,-783.70135,906.3282,501.4242,-569.4365,859.3142,507.3542,-812.396,1035.6711,738.1228,-77.13254,922.9179,733.3996,77.30481,1097.5315,776.8904,-828.69055,760.34644,749.136,-315.0829,1112.9025,973.27905,-490.40012,826.77386,908.0335,74.29909,1101.0436,1017.9094,-471.05902,860.7559,941.97235,104.69145,1148.2815,1029.3638,-744.8762,748.7403,976.0657,-55.691986\r\nScreenshot_2021-02-11 at 15.33.34.png,squats_down,604.47754,307.79523,-216.9947,609.3876,298.78906,-200.78896,613.6377,298.78204,-200.74529,617.9854,298.73688,-200.73564,596.9059,299.03506,-201.97636,592.2999,299.13617,-201.98338,587.7176,299.36346,-202.01259,623.3381,306.39377,-116.89502,581.7033,307.3443,-120.90357,612.908,321.61096,-186.75066,596.3614,321.97897,-187.8167,653.7494,370.17026,-69.07383,553.30804,361.86084,-64.13696,714.70795,408.95795,-56.7944,494.8834,376.73062,-4.1698256,662.6647,440.7588,-75.96846,538.7967,424.62363,-17.575256,649.0233,451.6879,-84.218895,549.3523,444.32898,-26.616327,642.14954,441.64987,-79.86229,561.2973,437.09955,-26.630646,647.54254,440.46796,-70.52509,558.613,433.05725,-14.114649,637.8407,480.78687,7.467873,580.7775,482.77325,-7.346258,648.7981,488.05362,-282.2621,569.9854,527.93646,-109.09021,623.9461,552.30536,-110.6881,595.80066,563.0697,191.34294,619.8935,555.9374,-93.06652,599.2159,564.9263,222.4754,613.4817,580.5394,-172.38576,607.64954,588.8242,186.15672\nframe__zLBFQ_mFl2E__0019168.jpg,squats_down,964.83673,523.86334,-454.24588,967.9177,512.3346,-413.85263,972.78314,512.2176,-413.91257,977.7555,511.981,-413.9927,951.1339,513.2959,-427.40665,944.6676,513.7682,-427.30875,938.24664,514.3759,-427.15256,979.5313,521.1196,-215.66513,923.8244,524.47723,-281.99924,972.1123,541.5863,-383.83835,951.84717,542.4137,-402.6285,1020.83813,608.70325,-111.70371,869.3502,609.26764,-209.66425,1081.1545,720.90704,-290.42667,845.6234,749.97797,-406.86752,1011.8475,674.83417,-586.5181,948.0578,693.99817,-623.69836,996.0877,663.60077,-643.6986,982.4885,683.6012,-659.631,987.3463,649.2588,-598.65314,973.87665,657.14075,-634.8256,985.82886,655.29736,-573.9815,967.3874,664.388,-608.8487,965.90643,762.4103,38.445736,872.08716,760.27704,-38.302284,1071.2526,784.77844,-462.41254,806.95795,784.70667,-599.155,1010.1501,914.5988,-46.59911,806.89954,935.47705,-218.93909,981.6106,936.4317,-10.7217865,813.609,958.6272,-187.85916,1064.9298,962.1073,-145.82701,788.94885,985.8918,-394.07916\r\nScreenshot_2021-02-11 at 14.46.15.png,squats_down,334.32703,278.6572,-128.33849,340.43652,272.9961,-101.47014,344.85104,273.2391,-101.508316,349.37155,273.42154,-101.81305,328.15625,274.2118,-98.51917,323.7297,275.0198,-98.500916,319.2947,276.03705,-98.48177,358.01938,287.21176,5.7500916,314.6376,289.92654,19.08954,343.95465,294.06094,-93.79203,327.90036,295.42764,-89.73528,377.00418,338.48322,-46.164375,301.68228,331.88144,-47.053406,393.82855,301.47253,-313.90247,270.28772,298.64188,-314.64774,394.99915,237.41182,-424.9291,257.82327,243.53542,-506.02576,405.37808,219.6017,-455.4966,246.48448,230.4614,-554.69934,394.87656,220.95396,-442.41385,261.51764,230.11432,-541.66614,388.36523,232.43045,-429.3881,265.96262,241.20728,-510.50357,356.14398,479.72702,7.1259565,303.19788,473.79202,-6.838352,423.93643,408.25714,-268.2532,251.5976,401.93716,-294.28622,410.18097,515.61426,-154.76234,257.1475,494.46082,-140.92014,394.59122,538.8324,-146.69144,271.46817,518.67426,-129.84749,446.93094,538.6065,-226.40712,214.25859,510.77402,-211.06119\nScreenshot_2021-02-11 at 15.09.38.png,squats_down,612.2003,385.37714,-383.70877,621.2381,370.1042,-381.76245,626.1585,369.72852,-381.69067,631.11005,369.26837,-381.6259,607.8472,369.68964,-379.12808,603.4685,368.7837,-379.15353,599.08716,367.95517,-379.43295,641.2692,365.3168,-278.60168,596.1218,363.18054,-269.8046,620.66724,392.1188,-338.04318,606.49243,391.51328,-334.58945,672.27625,397.89352,-135.96365,567.694,393.80365,-160.58441,672.35254,475.8174,-232.58049,555.86096,473.17023,-266.00464,656.7432,454.01782,-513.4822,579.23944,459.44504,-539.03687,654.09436,448.16785,-577.8428,587.1475,459.29382,-606.19836,654.2212,430.3933,-576.8066,589.9778,439.97534,-603.7105,649.1969,434.4988,-521.88885,593.8386,442.98093,-546.9986,648.71954,507.6225,-2.6589754,587.6071,507.78848,2.9463346,728.003,511.21225,-273.38464,502.95825,504.6212,-285.79407,706.9604,617.5698,-138.58131,518.8166,620.13965,-177.08568,690.45874,639.7697,-131.03528,533.7766,641.0838,-170.07124,739.7871,645.77734,-246.96672,488.80768,652.6194,-274.23062\nframe__FsqhUFcjL8k__0002647.jpg,squats_down,1077.7301,460.07605,-223.17865,1066.0951,446.10858,-184.252,1064.0258,446.29108,-184.18896,1062.2849,446.6482,-183.91133,1063.0453,446.4753,-246.6471,1059.1885,446.3679,-246.46783,1055.194,446.42865,-246.52118,1038.7701,455.82504,-11.690988,1030.6561,454.01495,-290.47095,1067.9928,478.61606,-161.30643,1065.1306,479.18436,-238.23163,999.45636,542.96625,156.44244,990.2953,548.4634,-432.23245,1086.5513,628.30115,41.647343,1090.6947,652.9925,-408.2801,1131.3364,564.7048,-287.6926,1104.396,534.32587,-115.82199,1153.8473,542.5713,-296.27975,1120.3287,502.2785,-135.75575,1129.4761,529.74335,-297.10034,1088.0079,493.98932,-143.26341,1121.054,539.35675,-298.90826,1076.6149,507.28467,-108.341194,849.6115,710.1186,196.67657,824.13153,731.05615,-196.24237,1026.6545,750.2646,395.49567,1003.5758,818.06836,-259.42093,921.8899,859.3141,490.63608,942.0559,973.77295,-182.18956,896.1671,874.99255,501.29517,914.01733,1002.0251,-181.37636,968.29047,888.28955,512.2587,1017.9524,1006.5876,-246.1292\r\nframe__nfRdTJY_xgM__0001239.jpg,squats_down,996.46045,480.4045,-263.90887,1007.02094,471.14993,-299.91278,1009.0061,472.18494,-299.64523,1011.043,473.25046,-299.73044,1008.7953,469.7515,-244.89369,1011.08777,470.00668,-244.73148,1013.48395,470.5584,-244.49217,1027.5885,487.7889,-377.96265,1032.6042,483.77582,-123.462494,1002.5109,499.53653,-287.17743,1002.7707,498.71527,-212.88164,1025.5364,567.00476,-477.2751,1061.4114,543.97015,88.85268,919.3526,563.98456,-601.4096,967.73517,538.4408,261.95425,810.3191,541.6422,-599.59265,879.8411,520.7209,212.86768,785.62396,536.26,-689.36694,866.86066,509.78705,233.70644,786.9762,528.2908,-659.2436,858.85565,509.4165,175.00858,797.15686,533.70966,-593.8646,860.0623,518.44824,187.15839,1102.257,753.5469,-185.59248,1113.1475,728.0438,186.16698,954.3084,747.37134,-145.46829,984.1839,726.1354,399.7641,1025.1576,869.5492,183.07053,1003.2469,852.86957,644.1548,1051.6017,893.3637,214.22995,1021.9131,878.08234,667.99084,978.06116,882.9989,221.2731,943.2515,870.40765,691.35864\r\nframe___0CAcnhL5Sw__0015916.jpg,squats_down,857.5268,406.26248,-799.60974,873.67053,373.35986,-770.70734,886.07947,373.24942,-770.62897,898.55536,372.8419,-770.49414,840.53156,372.907,-772.2453,827.7066,371.66342,-772.051,814.83057,370.70013,-772.2081,913.20844,383.066,-537.3646,795.47955,379.20212,-547.41614,878.70105,432.58148,-705.80164,834.03503,430.9419,-708.3075,989.9439,491.4839,-340.15527,706.39764,487.9013,-379.08334,1109.6045,688.4175,-426.36063,617.7806,696.3331,-350.09665,913.4706,727.22205,-438.59158,784.76245,745.0238,-326.33966,870.43066,754.2215,-483.03198,825.8873,771.5679,-360.7411,847.32465,716.9319,-425.2927,843.1594,740.43787,-344.9859,865.0753,713.2627,-412.59912,835.4203,729.02405,-316.24457,921.0635,739.10913,18.590223,771.3465,746.92706,-18.319262,1173.2496,655.9075,-504.54968,545.93384,658.04205,-582.7176,1100.6711,913.37146,-185.32117,624.66833,926.3854,-236.2157,1054.662,956.5855,-157.36371,668.1704,968.5469,-205.5092,1216.528,1011.2834,-355.3655,537.91705,1025.7998,-413.53342\r\nframe__TwOuh73cGGQ__0002302.jpg,squats_down,965.16724,481.63928,-233.99007,958.9374,472.1732,-189.74345,959.2682,472.31735,-189.84889,959.8867,472.54633,-189.74042,951.6018,471.22076,-231.68085,948.0204,470.9362,-231.61226,944.4613,470.73828,-231.40674,946.8341,478.41562,2.6725276,925.32477,475.15222,-183.43768,962.3103,495.06396,-168.09848,955.6497,494.4562,-219.98123,958.54236,552.40985,76.45076,879.2078,534.00977,-264.55243,1033.057,605.51935,-112.54492,945.2375,612.63055,-430.8214,1027.3824,538.76117,-350.8426,995.4517,528.57916,-325.5147,1029.3239,522.02094,-376.43475,1010.0362,504.07712,-336.7582,1010.2937,514.69006,-328.81784,988.8535,501.1702,-336.72913,1009.0741,521.8515,-337.79956,984.54333,511.23627,-318.1407,862.1262,695.20215,109.564186,799.81366,691.05255,-109.360825,983.50287,729.6706,-142.73036,846.5285,745.61084,-650.0755,928.703,840.7487,140.41777,803.5553,865.4923,-355.55615,904.3236,861.4385,165.87582,789.868,878.1315,-335.3975,987.4151,884.73834,52.425358,822.22076,916.94684,-528.05853\r\nframe__YArvGEk8c6c__0002123.jpg,squats_down,1250.3633,554.93976,-724.51013,1265.1691,532.1065,-732.5111,1272.6324,532.0576,-732.4841,1280.3608,531.74524,-732.147,1240.8701,529.9033,-736.75586,1233.3674,527.87244,-736.65,1225.9772,526.2031,-736.7068,1293.128,522.83514,-537.2519,1214.2201,513.5898,-547.19006,1259.3086,565.25696,-632.67206,1237.6685,563.3386,-635.15094,1352.9335,556.99115,-179.1875,1167.6368,544.5123,-214.29712,1428.742,603.28,184.39474,1097.4104,580.01056,213.19955,1429.3296,685.7693,343.45972,1090.9911,674.73517,481.84598,1438.1648,705.932,343.43063,1075.4999,694.1122,510.05167,1420.188,701.49786,283.68082,1100.0833,698.7463,468.66678,1411.0858,704.208,323.82208,1110.8662,697.3092,475.79614,1314.1539,762.80365,-14.303471,1207.0519,762.5013,14.253958,1473.5598,757.5775,-418.3095,1061.4147,713.52234,-389.12717,1415.9062,948.54895,-478.6814,1103.698,921.0951,-200.02342,1386.4518,995.5207,-491.8935,1131.1661,967.33826,-186.62442,1472.4916,965.95905,-651.5574,1042.9812,955.1631,-336.45297\r\nScreenshot_2021-02-11 at 15.28.33.png,squats_down,618.9405,276.98508,-300.17935,624.3057,265.3878,-279.5628,628.8311,265.08136,-279.5847,633.4163,264.68524,-279.6078,611.37427,266.442,-280.57663,606.47485,266.6762,-280.51294,601.57587,267.01535,-280.45386,639.1026,270.58734,-160.19188,595.39276,273.36917,-166.79358,627.78406,288.919,-257.41092,610.69946,290.01288,-258.9955,669.7045,325.86365,-97.468285,564.00116,327.883,-101.150536,701.5935,399.35715,-197.88724,528.7613,400.02808,-212.71619,732.8559,359.6147,-361.05002,507.97217,360.2346,-411.98743,747.52057,343.035,-405.03296,498.16357,348.6937,-451.8554,746.14746,332.48108,-397.11755,500.29843,333.88623,-451.31262,735.8995,338.56046,-365.70248,508.21866,339.6231,-416.32352,646.7696,450.22223,7.322051,585.7655,451.31616,-6.818625,708.7608,470.65378,-354.48672,550.6016,469.47128,-388.49808,672.15405,553.47815,-87.12991,565.15546,561.2957,-159.23447,655.89044,564.29504,-66.373276,575.51776,573.71497,-142.44339,696.95825,594.3364,-178.27943,549.4909,599.74286,-269.8115\nScreenshot_2021-02-11_at_15.51.18.png,squats_down,1262.7028,548.63873,-451.85458,1276.9359,526.5138,-416.43185,1286.4746,526.2067,-416.24857,1296.1483,525.6757,-416.28665,1248.9088,528.56165,-416.5288,1239.1942,529.13806,-416.2128,1229.4567,529.9513,-416.4289,1312.3229,538.13074,-147.1418,1217.3883,543.59155,-152.53763,1281.5973,574.0546,-349.03397,1246.8749,575.5527,-350.33527,1377.695,629.14716,-41.98515,1152.4852,641.6494,-51.485687,1424.1062,713.6355,-432.36493,1110.6196,732.5025,-478.01147,1464.5199,717.92865,-1113.1915,1103.3711,702.92175,-1156.9712,1492.2836,734.9207,-1247.9282,1098.4469,714.7386,-1286.8737,1462.9127,717.3312,-1277.3221,1115.222,684.53735,-1297.9609,1447.1794,717.0731,-1141.6583,1125.7755,688.6607,-1174.3167,1351.6249,894.8241,-0.35477895,1207.6724,902.7744,1.5860529,1473.1101,961.4809,-755.7974,1062.2192,988.99506,-730.9823,1394.711,1176.42,-281.5518,1125.6042,1182.9011,-310.02634,1356.5792,1212.3436,-248.56017,1163.7704,1214.8793,-279.29605,1456.9689,1262.6714,-502.15137,1064.1046,1273.8712,-531.80493\nScreenshot_2021-02-11 at 15.20.52.png,squats_down,603.681,330.32324,-361.75095,609.84406,317.9042,-342.23843,615.05994,317.66287,-342.20874,620.2571,317.34335,-342.1924,595.5765,318.63925,-340.89883,590.3192,318.68283,-340.80408,585.0295,318.85565,-340.86365,627.292,322.10553,-219.52791,579.1388,324.14786,-214.61986,613.928,342.0253,-317.12753,595.07086,342.57526,-315.2056,662.05963,380.8812,-177.4304,548.956,385.77625,-148.81857,652.5346,477.2979,-358.59616,549.51575,487.33102,-332.63757,611.2872,412.27563,-548.61993,582.46893,415.37756,-551.9264,600.3015,393.549,-589.36444,592.4235,396.2515,-590.1721,608.2008,380.38055,-557.7386,584.2806,380.9886,-563.24286,607.0933,386.452,-538.75323,587.71216,387.61868,-543.03613,642.3044,504.2238,-2.5711513,575.8065,506.1577,2.9593463,699.65436,489.03458,-410.94598,532.4174,487.245,-409.15213,669.6417,599.7742,-265.59296,544.53687,607.5444,-307.18616,660.32,610.96655,-256.93225,552.9538,623.5454,-303.23248,666.9503,646.832,-414.82758,539.4749,652.08575,-456.78073\nScreenshot_2021-02-11 at 14.44.55.png,squats_down,464.2285,227.07672,-193.18462,468.9355,222.50934,-171.90903,471.65207,223.28914,-171.90858,474.43616,224.04419,-171.92023,460.36218,220.76712,-174.43817,457.32257,220.12114,-174.3833,454.26495,219.60735,-174.41937,476.90213,230.19247,-70.954185,448.144,224.17046,-85.532135,467.14404,237.64967,-157.88937,457.0705,235.26811,-161.6869,490.69913,268.9839,-93.19008,422.8095,257.53394,-121.57747,517.9603,266.54892,-280.76114,427.22006,274.5008,-297.82062,464.3268,248.57365,-365.29507,477.21533,258.01004,-367.1204,453.87402,243.75114,-392.0445,486.28745,253.36565,-394.16266,448.83685,245.41217,-368.33124,491.3522,250.65671,-374.97513,451.42114,251.08199,-360.4445,487.7501,255.65823,-361.24945,467.4291,364.50406,10.354838,422.13113,357.4191,-10.244105,511.29495,336.91495,-276.46042,390.09952,339.6767,-313.82126,491.80005,420.2462,-115.37131,384.8056,420.90195,-171.29259,478.21524,436.70242,-103.5837,389.6776,437.19937,-161.68726,519.805,441.3908,-209.4998,368.08545,440.34048,-274.596\nScreenshot_2021-02-11 at 15.51.36.png,squats_down,205.28975,449.41492,-298.3568,212.00128,428.95398,-303.38388,218.82556,427.7771,-303.32294,225.61617,426.5247,-303.26035,194.224,430.1807,-304.48148,187.12828,429.7322,-304.34586,180.01735,429.4124,-304.33762,235.53903,424.28546,-239.62358,170.69492,428.33627,-244.2703,217.94981,458.82413,-265.93246,195.55411,460.02502,-266.7859,270.17984,452.44485,-167.00258,153.3565,454.17572,-167.29594,309.03882,530.3845,-215.53922,131.94711,523.2144,-199.28146,237.0353,513.1136,-308.5153,173.42595,514.34326,-321.7837,215.8757,518.71716,-329.18726,185.30783,522.0375,-344.3164,214.14755,498.38654,-314.32666,189.43355,503.98657,-341.49878,217.76675,498.21017,-303.39685,189.8903,502.38754,-321.40726,248.1576,548.07916,-5.592287,190.6271,548.42554,5.602694,282.21158,543.09814,-203.12091,138.52602,540.8304,-193.77158,247.33192,610.80255,-67.130875,178.03299,605.769,-52.018406,236.55093,621.3158,-54.937397,195.92526,615.448,-38.466446,258.1902,648.02094,-120.393005,153.59586,648.73834,-89.51183\nScreenshot_2021-02-11 at 14.32.32.png,squats_down,351.85645,277.35986,-419.53403,357.14154,263.7699,-414.16037,361.40878,263.20435,-414.13342,365.6998,262.5527,-414.06906,345.30347,263.94897,-412.1019,340.95108,263.28488,-412.00644,336.55032,262.7201,-411.95105,372.50473,258.17218,-311.75647,330.32602,258.647,-304.54382,359.4129,281.82086,-374.73065,344.96228,281.75406,-372.1229,403.0604,279.101,-225.25804,303.73346,279.73758,-214.6972,467.71606,324.09735,-323.87097,243.66919,323.15784,-296.65268,448.2777,360.99554,-476.56973,260.24802,367.6163,-460.47552,445.60312,375.64282,-513.7209,262.0809,386.9685,-503.79,433.9459,366.07907,-518.29346,277.12943,377.94046,-509.56216,432.57983,364.81033,-479.7677,278.89578,374.48087,-465.85663,383.50888,388.27658,-5.5785513,330.7936,389.32028,5.9427714,415.98596,399.81158,-344.59445,293.8544,404.4879,-300.30997,398.7895,478.82822,-113.08784,305.88333,478.8719,-71.27258,391.427,489.16464,-95.327866,315.4076,489.72485,-53.29125,404.22736,516.46423,-203.5602,289.15692,513.9914,-161.45601\nScreenshot_2021-02-11 at 14.33.03.png,squats_down,331.411,131.40019,-192.4449,336.91824,118.84446,-178.31804,341.45605,118.58009,-178.32532,346.04593,118.24243,-178.31583,323.79678,119.04737,-179.69499,318.8422,118.77467,-179.57904,313.87744,118.601204,-179.60109,351.21213,120.40867,-68.29126,305.52368,120.736336,-75.33869,339.02164,140.8016,-149.95757,322.06308,140.7451,-151.56676,377.8461,161.85675,-14.659033,274.3511,160.05902,-13.785877,412.74612,218.36197,-126.683586,242.91035,226.27208,-136.40053,385.6309,224.06146,-352.6589,269.10757,216.17497,-368.1245,378.12872,233.1708,-398.8251,276.89938,220.03635,-409.35583,371.00934,221.90802,-391.76422,283.9539,204.65489,-410.57004,370.71072,221.47897,-354.19232,285.11337,206.05669,-370.3625,350.4332,286.9766,2.7524157,292.052,286.73572,-2.4115283,389.37958,267.69736,-344.98877,254.11853,272.13254,-329.81607,372.63174,384.5345,-261.22513,265.51166,379.63724,-247.02235,362.0583,400.84833,-257.20456,273.28055,395.56412,-241.1387,383.94794,424.9196,-379.25107,252.47311,416.86295,-352.6672\nframe__diFjQVUL7wk__0007470.jpg,squats_down,1071.2266,457.09882,47.011425,1064.345,439.65103,57.536884,1060.5698,437.83817,57.736797,1056.7969,436.07486,57.6717,1069.5271,443.1875,0.89381576,1068.9714,443.21014,1.0041982,1068.2163,443.3174,1.130819,1034.5717,433.84183,134.43181,1050.6912,443.03113,-124.25539,1056.487,465.39465,81.51531,1061.3069,468.04758,8.994949,959.8123,477.2007,308.5399,1022.04016,503.40097,-237.27522,955.8171,542.54584,526.3159,1045.1375,598.1842,-222.97546,1015.3624,495.49396,700.3472,1067.213,535.22437,-32.59576,1029.4669,474.33966,751.00195,1077.5542,515.46783,-44.79024,1028.7651,468.74088,740.0447,1071.3562,505.17758,-28.577625,1023.3665,477.40833,698.08435,1065.6642,514.5311,-18.409986,845.4755,603.09985,180.15736,874.7821,616.8541,-180.46912,955.3891,649.1398,556.8408,1021.19885,674.0133,-221.4225,896.8868,766.761,755.52374,968.57117,818.10266,-289.36166,871.9204,787.2806,775.98785,935.2046,844.74567,-290.04926,932.0621,789.38574,847.5855,1024.5763,851.7897,-264.341\r\nframe__MythPbjCmZU__0019103.jpg,squats_down,773.70996,502.35754,-163.92694,780.26135,483.40698,-174.47209,785.73456,481.32358,-174.3884,791.2145,479.1357,-174.17114,770.8051,486.26404,-124.577866,768.55804,486.51395,-124.410614,766.34094,486.9146,-124.352905,814.1474,477.9826,-169.83127,783.1649,487.05377,50.903072,795.36273,511.835,-159.63937,781.04095,516.35986,-95.834305,887.7312,538.4062,-256.83838,809.3621,551.433,192.72237,842.61005,669.47156,-400.78513,780.819,648.4304,84.88618,770.7433,594.6739,-393.91125,752.68494,582.8164,-193.58908,750.2959,573.29584,-429.0629,739.5459,567.0668,-230.27718,766.12915,561.323,-413.80768,749.60016,557.10455,-212.20409,774.9462,569.54706,-384.16077,758.46,562.768,-192.66234,969.41766,680.31964,-116.26774,913.9458,687.3073,116.98449,894.9865,709.3405,-612.797,804.32635,677.3126,-279.0274,958.2903,869.79785,-491.90878,869.75275,823.2415,-249.73251,981.2549,892.3871,-485.1756,897.35876,846.91016,-249.985,922.8914,932.2289,-666.65906,832.61035,872.0101,-380.93228\r\nframe__6g3BE11bR4s__0021022.jpg,squats_down,1120.106,287.31924,-595.35925,1115.5624,264.88168,-544.32574,1120.6587,265.0987,-544.4133,1126.0673,265.3343,-544.47125,1093.9502,263.88416,-591.87225,1083.775,263.0446,-591.7348,1073.6692,262.47357,-591.64014,1109.8575,270.84262,-270.64795,1037.7703,266.84888,-477.12436,1119.8433,310.38486,-492.61414,1094.337,309.5025,-549.7583,1138.1326,357.14175,-142.05743,943.213,384.00076,-491.06696,1297.1898,365.11447,-314.57806,960.12317,568.1455,-855.416,1341.9628,337.49637,-641.50275,1049.2971,437.2864,-1155.6224,1370.5458,330.04056,-701.6352,1079.1711,397.05652,-1233.9067,1340.5054,322.22058,-673.356,1059.8508,363.5343,-1220.999,1327.881,331.8306,-645.9637,1054.4221,380.33774,-1156.2565,1010.20776,615.6826,145.99614,891.3732,622.24176,-145.75119,1214.4241,646.23254,-283.2009,983.03754,672.65076,-914.0176,1111.0643,831.50214,110.323044,917.2298,885.80707,-476.11746,1059.9136,858.9173,140.94847,884.1131,914.1932,-447.2866,1189.615,913.124,-3.8945425,995.75555,960.0251,-711.3405\r\nScreenshot_2021-02-11_at_16.26.32.png,squats_down,1264.1249,692.73505,-736.34125,1280.6533,670.4648,-702.867,1290.8246,670.2191,-702.68146,1301.0778,669.8975,-702.6804,1253.8097,670.59485,-684.53687,1244.755,669.973,-684.46643,1235.699,669.7256,-684.2963,1323.8191,677.0999,-475.47467,1231.7523,675.88544,-394.56845,1285.6393,713.74115,-651.67834,1252.6829,713.0849,-627.57776,1380.238,751.7789,-420.2268,1186.2379,750.6895,-331.8427,1534.7874,697.1789,-778.28204,1008.7222,720.5688,-740.9101,1387.9391,672.5496,-849.33435,1165.6848,673.21985,-956.07605,1356.9219,653.5058,-877.9817,1200.1418,654.1881,-1009.2222,1345.0682,667.03406,-785.5093,1226.4976,654.8023,-908.78375,1353.7584,688.66766,-816.90826,1215.7515,675.6561,-924.37585,1348.14,1027.0466,-35.443398,1229.0607,1019.67035,36.226307,1463.894,958.4151,-844.36847,1064.5361,961.706,-612.1737,1438.4469,1167.5303,-411.2613,1154.8622,1164.2969,-213.20782,1428.738,1189.6978,-375.13516,1197.5558,1188.8555,-179.36057,1435.4939,1252.1741,-676.4843,1090.7434,1253.1882,-424.76196\nframe__ox0kCStCZHc__0006663.jpg,squats_down,905.45966,508.71823,-49.15662,920.35455,491.7257,-78.4699,924.2577,491.02194,-78.29271,928.23486,490.15738,-78.33303,918.65216,493.07373,-15.099057,920.5293,493.553,-15.1439705,922.7013,494.2763,-15.117749,955.8475,496.704,-145.30756,946.7314,502.64645,142.28001,918.48566,526.1035,-72.59266,915.2916,527.38257,11.106704,980.6105,568.4239,-302.8868,991.58887,577.7947,316.4592,839.7916,604.77,-489.28253,856.9383,632.7013,401.52533,744.696,641.4101,-426.06894,760.64417,657.69165,256.33667,721.9896,644.8816,-485.1501,737.7259,651.53937,263.68573,724.9624,637.3925,-447.12274,738.0184,649.0154,200.90462,736.2381,639.3055,-411.21942,746.05225,656.574,224.63965,1158.3673,756.50635,-191.80075,1156.9106,746.0442,192.53181,994.2304,847.5514,-202.96617,1022.2815,831.9276,327.34863,1017.8834,1032.0015,-50.74017,1047.9648,990.8938,512.3306,1039.974,1058.633,-37.47566,1070.1813,1010.96844,528.5907,950.24854,1081.4513,-119.00774,996.02734,1047.5917,477.26437\r\nframe__fFQOVvvPXak__0019928.jpg,squats_down,643.6155,159.36835,-507.46732,663.6191,145.2375,-506.46085,670.90063,146.0963,-506.37363,678.2508,146.84532,-506.38992,649.01733,143.58153,-467.98657,645.66626,142.76903,-467.79645,642.3799,142.3055,-467.6305,704.85,155.72467,-453.5063,657.8264,148.53499,-285.54358,663.27423,179.43188,-488.26337,644.2297,176.32855,-439.76807,745.8844,231.07375,-504.4847,652.1859,226.82002,-179.34999,651.2115,299.80762,-646.0712,541.405,262.28348,-283.80917,519.6739,284.61618,-701.8142,446.82642,242.96329,-461.71082,487.15326,284.25858,-758.7759,418.5478,232.09874,-483.44864,489.0998,266.5566,-741.50073,422.4192,224.57542,-509.29504,503.03778,270.86105,-697.87036,434.8777,232.24103,-481.40012,811.8379,408.1343,-87.2251,751.4839,399.57263,87.60033,735.8523,430.25616,-540.49634,616.4771,377.98495,36.636063,769.4839,578.9978,-310.3198,637.68744,487.08533,332.55557,782.0188,605.83325,-296.5112,656.71014,510.71075,356.4835,716.75354,613.9475,-458.1467,561.2503,509.95764,289.03503\r\nframe__QVNlEfFOWwg__0006900.jpg,squats_down,1062.9373,202.11026,-199.91566,1063.5378,171.88481,-175.33997,1062.7615,172.08307,-175.35562,1062.2509,172.40648,-175.4792,1054.503,169.10707,-235.4799,1047.1807,165.87755,-235.43922,1039.6893,162.90039,-235.36281,1023.2271,181.7735,-23.463327,993.0623,164.4253,-294.06268,1037.0996,234.2926,-139.2493,1024.9246,229.39421,-216.14922,889.5255,283.18924,247.83313,882.1817,310.64523,-429.52725,1040.6145,467.70972,369.31158,1024.3699,524.0057,-358.28577,1127.7827,335.45456,419.7376,1122.6202,335.9595,14.822318,1159.973,301.99326,442.75598,1165.1678,295.93622,-12.921925,1129.2329,274.8414,474.09308,1130.3948,262.238,-58.64986,1109.8616,292.11624,426.0155,1101.9247,276.05115,7.0844,540.12665,534.9418,224.84438,522.1802,561.9316,-224.04523,902.1011,584.04065,375.03046,892.28015,639.0336,-227.78616,734.5467,848.67755,655.5827,758.9048,920.143,76.54147,669.99,878.4567,687.50037,695.6441,954.02856,113.70583,812.5925,955.45197,746.06305,869.5348,1014.6321,132.2618\r\nScreenshot_2021-02-11 at 14.44.11.png,squats_down,155.69533,252.64764,-107.93055,160.74161,245.6198,-92.34387,164.48972,245.607,-92.331,168.27588,245.5156,-92.26315,150.18149,245.93999,-91.62223,146.39508,246.02472,-91.64066,142.5868,246.1878,-91.62392,173.61124,250.99193,-22.392027,137.84938,251.76134,-15.615281,162.60612,262.80426,-83.48465,149.27757,263.07492,-81.53613,192.24826,289.7511,8.423273,118.61989,289.8803,-8.916538,233.87508,316.63034,-88.877144,75.52011,321.58112,-121.59901,175.975,290.7548,-118.726456,125.64742,292.9493,-184.97083,161.71152,282.80313,-122.97457,139.13457,287.0704,-198.97408,157.03183,279.76352,-95.65671,144.01656,280.42026,-167.91684,160.35466,285.80978,-107.694984,141.73448,286.19568,-173.15366,176.58408,378.066,3.2465036,129.45224,378.7917,-3.2520628,207.63783,421.0385,-171.82877,93.631584,426.6294,-195.49925,196.0682,472.0489,-2.208157,102.73373,472.53052,-19.057388,189.27711,477.26404,11.023533,111.74074,478.01874,-4.1100287,203.20634,505.74734,-67.62847,83.34977,503.6192,-81.61433\nframe__bggX6ocjojk__0001935.jpg,squats_down,1859.1095,1095.5989,-453.49313,1872.804,1057.9626,-399.77512,1884.3014,1056.6838,-399.31458,1895.9153,1055.0732,-398.95044,1836.1495,1060.3733,-410.2691,1822.928,1060.15,-409.9072,1809.5524,1060.2083,-410.27213,1909.2698,1055.5143,39.147213,1784.9484,1061.4172,-14.151281,1877.0734,1121.2825,-283.05972,1834.9106,1123.6115,-298.38644,1982.9532,1168.5537,183.63593,1701.7216,1152.2522,118.669136,2011.136,1288.1533,-603.0467,1679.1642,1281.5103,-693.43005,1936.8977,1333.8514,-1583.1459,1773.0789,1318.7284,-1682.9596,1933.2998,1360.2358,-1800.0715,1789.8257,1344.0354,-1876.89,1892.3483,1333.2985,-1782.8125,1821.3748,1318.2784,-1861.1948,1887.6256,1333.4207,-1605.933,1825.1926,1321.794,-1690.7786,1920.2163,1504.199,23.43214,1740.8313,1489.581,-21.69405,2080.0085,1515.9297,-1258.7645,1611.4695,1465.3342,-1318.1958,2052.3071,1842.6945,-1064.8096,1592.0221,1820.2601,-1099.2168,2010.1721,1915.1881,-1077.889,1620.8447,1899.3888,-1104.1532,2152.039,1920.4263,-1527.4188,1513.1774,1909.4437,-1532.6194\r\nframe__x5BuK8JqODU__0046768.jpg,squats_down,1081.9595,537.6567,-1178.2203,1084.6542,531.2569,-1160.8877,1086.2443,531.4128,-1160.7719,1087.5315,531.67725,-1160.7208,1077.6149,535.1383,-1171.0502,1074.4143,535.9345,-1170.789,1071.6738,536.9892,-1170.3132,1082.5138,536.93744,-934.5409,1060.26,546.23755,-980.4525,1081.3549,548.22314,-1087.0834,1073.8333,549.52185,-1101.033,1103.335,538.69226,-596.6615,1027.6652,606.97125,-633.44885,1091.1473,501.9262,-257.1269,990.1236,622.62714,-419.70728,1110.3966,537.97626,268.13217,1056.6431,599.3729,10.42975,1110.3835,541.67633,405.19748,1070.5394,595.2917,109.8668,1120.2838,549.5566,413.168,1088.6041,603.41455,115.81732,1120.0211,548.41614,295.8956,1082.5637,607.30615,28.538227,1154.4082,600.0222,-0.12709188,1107.2307,640.4208,0.2482024,1092.1299,616.368,-600.7718,1072.4963,744.947,-529.9095,1163.9104,720.4257,-338.55304,1157.3195,912.2478,-392.64163,1177.8711,744.0903,-322.60278,1178.9215,932.9592,-393.39072,1151.7499,732.3268,-556.87146,1165.216,948.2108,-633.9995\r\nframe__1BZM2Vre5oc__0005146.jpg,squats_down,864.7505,537.9567,-681.2796,871.9003,525.4553,-657.46423,877.4856,524.91144,-657.6102,883.13403,524.3793,-657.61786,856.26904,526.88495,-657.3025,850.7906,527.43,-657.145,845.26416,528.0079,-657.15607,892.87836,531.7356,-503.34253,840.3039,535.12067,-500.12537,876.95935,551.79254,-624.1312,857.13885,553.3709,-622.3453,929.91614,603.9806,-404.48166,805.4062,588.67883,-414.23856,960.2527,698.7007,-659.8946,765.44586,669.74097,-617.1486,930.55347,647.9789,-931.5825,798.506,641.86053,-834.7935,927.2383,632.7237,-986.7186,804.39606,627.40283,-881.5178,925.9838,622.0915,-942.9045,806.5709,618.96344,-855.3069,920.6707,630.66986,-918.55054,809.56006,627.1825,-828.30774,872.4868,708.03644,12.241214,800.279,697.89105,-11.799542,919.87366,763.7948,-276.98575,771.82855,735.21155,-505.85468,914.8557,836.4441,41.182793,796.7517,806.36554,-45.036163,904.40436,850.91315,66.172165,804.31946,812.3599,-7.4838324,942.3277,872.07776,-48.677994,795.8409,849.08453,-128.37274\r\nScreenshot_2021-02-11 at 15.37.06.png,squats_down,488.6062,187.37756,-193.06203,495.08987,178.01768,-160.35512,500.26694,177.95746,-160.25742,505.55832,177.79893,-160.23047,478.65332,179.46611,-163.79843,472.7923,180.20848,-163.72252,466.9253,181.07968,-163.73749,511.29373,190.02011,-13.498097,456.63217,194.18886,-25.859303,497.79062,206.00237,-141.5884,478.03934,207.6234,-144.89685,547.8874,262.31357,-6.581866,421.93524,267.23184,-52.711437,600.95917,293.22046,-302.75754,403.74585,295.04602,-391.62402,563.7889,286.4767,-571.3185,475.74744,291.517,-647.6733,556.88007,289.6601,-624.3208,487.92615,294.68552,-702.55853,546.0903,282.09027,-606.4344,500.53412,293.90546,-672.7596,545.6413,287.5653,-571.56384,500.14172,299.19724,-641.2414,533.10345,431.15472,10.97953,449.77203,437.81583,-11.002323,616.75494,494.88586,-344.3675,390.47488,516.1909,-395.75015,579.6779,598.89923,-37.98968,427.5612,607.5211,-72.2022,557.0418,616.93506,-16.532806,446.07483,623.81067,-47.06305,621.50433,646.3765,-157.32208,395.43817,653.8243,-186.0038\nScreenshot_2021-02-11 at 15.04.13.png,squats_down,566.3978,327.57526,-187.9749,573.42914,316.19147,-167.43916,577.84766,316.2549,-167.44243,582.30615,316.22443,-167.50807,561.0669,315.945,-168.38751,556.56616,315.54776,-168.41281,552.04486,315.27856,-168.41472,589.5871,321.45947,-49.070362,547.0074,319.83212,-51.528984,574.89374,338.65192,-144.95723,558.64014,337.9749,-145.736,615.27844,368.6304,20.51097,521.13806,362.61398,-7.0237217,666.4465,420.2721,-77.31269,481.27905,422.75995,-150.92099,637.96857,349.6283,-146.16997,507.07645,361.54758,-308.26968,636.0131,326.4843,-170.69376,513.11127,344.2199,-332.1981,628.9629,322.4175,-130.86305,516.5598,335.85287,-320.2829,624.82996,334.34808,-134.17477,518.97614,346.4557,-304.49612,593.63763,489.3806,10.621829,538.71735,487.913,-10.205791,658.5382,481.55283,-352.41818,503.31824,478.8953,-373.58078,628.60864,560.9966,-115.92587,499.32855,562.5394,-169.14383,614.60956,569.34314,-94.96009,506.5571,573.52466,-150.59407,651.07056,606.20776,-200.26833,477.99408,599.9583,-270.5466\nScreenshot_2021-02-11 at 15.21.25.png,squats_down,276.27982,308.39914,-257.83228,282.78644,298.73087,-234.13199,287.2403,298.9523,-234.15263,291.71042,299.07498,-234.08109,269.80627,298.55542,-236.69485,265.09586,298.33487,-236.56152,260.37274,298.23138,-236.49268,295.84418,305.40195,-103.1405,252.66066,303.97717,-113.61289,282.47226,320.9923,-210.2675,266.8641,320.26645,-213.27345,318.8687,349.69406,-43.25013,222.41289,351.12677,-38.7167,356.07065,409.96463,-164.0711,193.64049,410.20844,-205.93335,375.4811,362.47562,-288.42123,180.34024,362.92157,-405.99564,386.25836,343.85132,-320.01614,170.37143,346.93628,-442.12195,382.9312,335.27225,-307.42233,175.09766,337.64542,-431.91818,376.14758,344.10898,-289.12582,182.16417,345.00623,-407.37247,300.43185,464.513,-3.0234869,243.55685,463.99448,3.378607,382.0118,441.0707,-357.43182,182.0952,428.18918,-372.39508,359.91693,537.3178,-259.76596,183.86507,531.4535,-276.23996,346.74902,556.8764,-255.61357,196.91975,555.06604,-272.11392,385.14435,553.88654,-383.70142,143.60881,547.0901,-392.71036\nScreenshot_2021-02-11_at_16.11.54.png,squats_down,1422.3136,591.01746,-1367.561,1434.6613,563.6803,-1335.726,1444.098,562.5699,-1335.9045,1453.4901,561.31866,-1335.8947,1407.4131,565.92487,-1333.7991,1397.7672,565.9231,-1333.5192,1388.0306,566.1441,-1333.3931,1467.3722,562.7494,-1038.5947,1374.369,569.0736,-1037.5392,1440.1469,609.11676,-1246.9092,1406.5012,610.7693,-1246.4019,1537.0753,655.9856,-764.4274,1309.3673,663.41956,-758.3259,1607.7302,830.15875,-1027.7003,1252.3519,838.7234,-1028.786,1484.3357,812.2536,-1451.5781,1374.7133,806.151,-1487.279,1442.6936,812.8858,-1547.4545,1407.7228,804.0569,-1592.1837,1438.6425,781.46967,-1511.9053,1419.4331,776.1224,-1556.802,1445.2102,784.0953,-1440.885,1414.7025,779.75,-1475.024,1487.7528,847.1521,-0.8858117,1363.44,849.8505,1.2382777,1557.9309,942.73566,-830.67694,1323.1165,948.31396,-832.7349,1580.0554,1127.2379,-225.94232,1275.6322,1124.298,-219.94849,1569.2963,1157.3768,-183.95763,1280.0387,1150.5973,-178.13593,1623.2091,1191.191,-540.0912,1239.976,1198.6956,-517.0311\nframe___0CAcnhL5Sw__0013435.jpg,squats_down,741.8344,561.48145,-813.19257,754.88873,535.3263,-815.43225,763.55914,533.5121,-815.39075,772.1792,531.6252,-815.38257,736.8332,538.8185,-774.10547,731.69415,539.196,-773.76685,726.7018,539.7899,-773.3967,801.45807,533.0497,-734.6089,743.93744,541.75885,-558.1527,770.0992,578.5094,-778.66797,745.4742,581.64404,-727.94104,887.452,612.85864,-727.0865,749.03375,615.7628,-382.26608,841.3709,789.30304,-838.5313,672.4623,767.3013,-612.55457,700.5447,706.7065,-870.0532,654.17944,697.20074,-1021.3903,656.96277,693.83636,-913.81793,643.9342,683.39984,-1082.0952,681.74915,656.03436,-923.4066,659.6665,656.3594,-1045.7595,702.38367,656.98956,-869.30743,669.4953,664.3123,-1016.88666,1005.73926,747.98035,-98.04599,921.13434,744.9479,98.942505,947.77264,812.265,-675.8047,735.91437,794.7737,72.682236,1016.8325,999.178,-483.09293,773.3386,906.6882,368.57907,1039.2242,1026.4126,-473.7662,799.6835,925.0659,393.1043,983.6625,1070.0002,-699.1498,699.05725,972.9303,303.9759\r\nScreenshot_2021-02-11 at 15.27.41.png,squats_down,685.6486,379.66525,-137.73438,691.0072,368.3183,-119.34609,695.5416,368.26614,-119.36278,700.14734,368.12085,-119.4741,678.0974,368.64008,-122.06843,673.0774,368.62854,-121.994774,668.0395,368.71936,-121.96602,704.8213,373.79996,-19.600147,660.414,374.50803,-25.864017,693.4829,391.89755,-102.13088,676.38367,392.06516,-103.91083,733.8504,421.74777,22.497416,627.0535,424.8101,15.446921,782.5,480.3668,-109.88736,586.6971,490.43573,-107.40977,780.168,420.35938,-262.06277,581.9796,422.2543,-241.20639,784.46173,400.93173,-291.2904,576.1003,403.5475,-258.70828,778.42065,392.28494,-268.67792,581.05005,394.7877,-243.9328,771.4078,402.49426,-257.10037,589.0242,404.6121,-236.10077,718.0292,549.2172,4.194096,654.44226,550.5609,-3.7758303,796.9171,544.67096,-278.55643,607.36505,532.08997,-312.68033,744.4742,623.3518,-109.43964,629.878,624.2926,-166.59389,726.8803,629.3919,-94.38012,640.535,636.70496,-154.78589,758.5109,668.65314,-180.67096,620.2944,665.5788,-252.38217\nScreenshot_2021-02-11 at 14.53.08.png,squats_down,210.73312,227.08426,-211.61356,215.18115,217.20679,-205.6956,218.54672,216.73929,-205.63174,221.95691,216.21631,-205.54701,205.7221,217.82599,-204.91246,202.36726,217.7158,-204.89128,198.9801,217.69922,-204.96452,228.23395,215.99072,-132.13525,195.48953,217.60309,-125.43587,217.51639,233.02914,-180.99866,206.39853,233.67834,-178.75758,251.57268,241.29042,-83.6492,180.46265,234.48303,-93.30255,268.63452,272.74765,-227.14484,149.05675,258.66498,-231.67267,239.52646,264.58923,-385.1058,186.84647,258.77933,-368.1647,232.93211,266.56833,-415.11438,195.79086,263.35983,-393.11993,225.868,259.1371,-406.33337,205.02855,257.62857,-380.58713,226.74783,261.87805,-384.6305,203.26175,260.2096,-364.09924,234.87424,322.2165,-2.0922594,191.72588,319.33725,2.0723586,265.9875,341.58746,-212.5585,152.51743,330.5562,-232.97424,249.92125,391.88824,-49.917297,169.6967,379.58978,-37.061516,242.83736,397.58066,-36.909042,180.6106,388.11267,-19.231028,251.49327,425.44226,-116.79868,145.96373,407.47668,-86.14427\nScreenshot_2021-02-11 at 15.07.48.png,squats_down,622.11176,271.32245,-130.33641,627.3251,261.39252,-104.602844,632.03644,260.99695,-104.534294,636.82733,260.55792,-104.70699,613.27423,263.58908,-105.1387,608.15625,264.4775,-104.978455,603.03894,265.53394,-104.9454,643.51855,270.04477,12.17637,596.2708,276.71344,10.597123,632.2022,285.7682,-90.615074,613.7894,288.2053,-90.9308,674.88275,328.48135,-6.303882,570.4359,337.66946,-4.8328004,713.0153,354.41077,-281.86072,543.46936,363.27124,-293.5596,710.70416,332.48257,-546.0422,532.60657,326.61014,-582.6307,720.45703,327.95947,-597.8163,525.5183,323.4616,-626.8655,707.9432,327.1561,-578.3613,533.1438,316.61267,-620.64813,701.1988,332.3164,-546.4752,539.92584,321.6598,-585.77155,657.8777,485.3134,-2.5743368,595.6815,485.43454,2.9576752,704.3641,466.56,-395.79514,538.4845,462.83734,-351.40387,670.72485,569.28217,-202.2851,571.51733,558.00543,-171.88965,659.17206,581.4282,-188.98196,586.4614,571.26526,-156.93843,679.9229,610.82825,-314.77396,554.44666,602.41425,-260.57242\nScreenshot_2021-02-11 at 14.39.30.png,squats_down,356.00873,178.092,-127.864044,363.07983,170.14766,-104.2359,367.53363,170.58441,-104.12943,372.06323,170.96573,-104.07512,349.43845,169.7097,-109.3527,344.78882,169.6098,-109.29869,340.13397,169.60335,-109.45169,377.50543,179.33086,25.82098,332.03198,177.20184,3.526522,362.64963,192.18611,-79.969536,346.70065,191.49637,-85.92863,401.54993,230.75856,24.139418,303.4233,224.17506,-22.807026,428.8894,243.25053,-210.45088,303.9316,237.26425,-284.66583,406.24023,231.07532,-445.58313,348.58044,222.29099,-478.9695,404.0735,231.91212,-507.6154,356.8035,221.1283,-530.76636,394.18768,225.2535,-501.6347,361.34677,218.2171,-524.2691,394.09576,229.16124,-453.41788,358.87363,223.06755,-482.92596,387.99423,371.25134,12.710328,320.2587,373.18686,-12.349103,470.83954,408.75766,-219.73529,250.33957,413.31583,-282.04382,445.93826,503.22818,-31.07502,257.0877,510.75537,-104.315056,425.62473,520.50165,-19.266186,271.11633,530.2818,-94.74577,486.16058,541.797,-131.12726,220.3248,545.6926,-216.62625\nScreenshot_2021-02-11 at 14.56.30.png,squats_down,467.46484,300.08658,-424.15588,474.23013,287.92783,-406.35788,479.0151,287.9441,-406.28647,483.77148,287.8907,-406.20926,461.09515,287.54654,-406.29977,456.2653,287.10004,-406.19336,451.4243,286.75604,-406.20004,489.31375,290.89368,-288.77505,444.96576,289.4032,-291.68097,475.30594,310.85837,-380.12814,458.58344,309.9373,-380.62994,515.27637,337.76807,-210.19818,412.00464,340.90637,-224.58586,538.93335,420.30283,-385.01236,407.16153,431.58212,-405.70325,488.22382,373.0934,-562.4491,453.65042,367.00876,-598.34155,472.07462,359.69922,-594.8654,467.32098,348.91364,-630.7531,476.45413,342.89227,-558.3748,460.6043,334.7051,-596.88574,476.7957,348.97116,-550.3389,461.7483,342.1101,-585.3037,490.99008,428.07724,2.5791113,433.34872,430.1533,-2.3991435,526.84595,437.83908,-373.66254,403.94534,445.6045,-361.19034,505.02887,544.135,-203.74817,420.179,545.5294,-213.60284,494.45444,558.93604,-193.67535,428.11133,560.4717,-206.50874,518.99255,582.97546,-338.90814,413.39697,584.4006,-348.12552\nScreenshot_2021-02-11_at_15.54.28.png,squats_down,1372.9904,625.82574,-333.20868,1385.4489,597.9428,-302.04218,1395.835,596.8096,-301.6786,1406.2941,595.5077,-301.78735,1355.703,601.77826,-306.00818,1344.6001,602.6013,-305.62347,1333.5383,603.7329,-305.77893,1420.4731,605.71185,-47.322536,1317.3619,616.7409,-62.953148,1392.4412,649.4026,-235.04625,1353.7863,652.7294,-239.652,1472.315,680.8088,1.2412318,1246.5239,709.2425,6.0477786,1556.1796,770.403,-483.55582,1184.0404,782.90356,-462.87125,1603.9088,753.325,-1181.5709,1149.4613,754.42535,-1127.5326,1629.7914,758.78436,-1296.742,1127.7854,767.5327,-1242.2812,1606.3291,739.58887,-1326.6663,1153.4896,737.78485,-1247.7485,1593.2664,745.57086,-1211.21,1167.0549,740.8318,-1144.9038,1461.7101,1006.8119,-11.387663,1325.8405,1017.7154,12.374415,1602.2776,990.69916,-609.95575,1121.8711,1029.703,-508.93304,1517.1747,1208.2672,-198.9532,1237.1244,1203.3475,-100.86522,1485.3147,1242.8513,-166.59428,1293.3169,1230.8351,-69.7688,1563.672,1294.9989,-347.66092,1156.3773,1311.5813,-213.30649\nframe__jPO_jp4Sb00__0008071.jpg,squats_down,934.4716,547.78876,-104.87844,942.29285,523.94507,-73.87928,950.00885,522.5507,-73.93296,957.78894,520.9622,-73.98016,920.02057,526.4876,-70.79121,911.77295,526.4591,-70.80731,903.489,526.5964,-70.99292,969.71063,520.4283,115.71597,892.6598,527.3736,132.4744,949.86237,562.2802,-34.064693,923.2947,564.761,-30.26155,1026.952,590.2207,169.69208,839.138,589.5027,164.59875,1061.844,712.3833,-144.3844,776.3769,704.5669,-164.73212,957.84503,606.54443,-343.30634,883.46906,591.9864,-398.85986,939.0493,571.5036,-393.38007,903.55524,560.2829,-447.29556,934.2516,558.9212,-317.28006,912.29956,545.8225,-385.2697,931.4782,574.6993,-318.21692,913.90656,563.414,-374.39502,982.96564,813.7943,2.771325,870.1517,815.8589,-1.9793476,1081.1161,798.07007,-749.02527,764.2254,800.3749,-728.3328,1025.1523,968.42426,-295.2902,806.36005,967.96014,-247.56827,1003.75305,990.2439,-256.1902,832.9182,995.9462,-207.02165,1041.2274,1054.1099,-485.176,755.7071,1036.319,-434.0357\r\nScreenshot_2021-02-11 at 14.30.15.png,squats_down,477.95422,296.474,-335.56345,482.18164,284.05746,-313.50293,486.7914,283.59552,-313.3899,491.4465,283.0304,-313.2969,468.778,285.03464,-317.5182,463.30872,285.10123,-317.40567,457.86966,285.3318,-317.28943,495.3528,287.72696,-177.65869,449.4786,290.8863,-193.78009,485.99603,307.826,-284.4194,468.37927,308.75656,-289.47736,529.72424,337.32812,-96.99307,413.1436,340.49554,-96.54691,587.8216,394.9789,-248.99965,364.43408,400.9289,-253.25502,594.70734,340.4169,-470.19727,351.4151,345.328,-447.80438,601.52905,318.03513,-509.82812,342.78024,324.86,-481.29776,596.3343,310.42496,-486.45502,345.8213,318.42123,-460.30682,589.55194,320.53943,-466.80466,354.79718,326.94122,-444.28864,512.28503,448.21863,-1.8130931,443.3588,452.61954,2.264332,580.9221,444.80743,-416.51978,371.2618,465.14633,-437.16815,577.09973,548.962,-229.06534,375.32104,558.18494,-286.77087,567.812,567.2184,-216.56815,384.82123,573.92786,-277.77893,601.24927,573.6746,-368.88828,358.17682,582.3125,-419.3984\nframe__H21pTB9nJ7I__0002366.jpg,squats_down,900.0728,458.72742,-45.395405,914.5866,445.90976,-51.09355,920.3639,446.25467,-50.96106,926.3339,446.4757,-50.776375,906.01605,445.7546,0.833297,905.0518,445.55267,0.9062071,904.03894,445.6012,0.65485644,953.5167,459.80206,-59.920624,923.7745,457.8982,168.56828,918.6307,481.79214,-51.126396,905.7625,481.27966,14.875542,1021.1996,548.1081,-172.53557,911.35223,564.3854,246.82317,919.15515,620.42505,-222.28252,809.91064,649.24677,6.5960035,866.6015,514.2179,-30.19184,840.1436,530.56836,-295.60556,854.0125,488.04654,-28.455835,838.05597,496.6845,-329.1897,867.97565,488.3314,-10.988538,860.50464,487.29208,-275.5295,874.5475,501.75732,-13.223733,867.5415,502.49548,-282.17627,1070.6135,745.95135,-91.48497,987.5703,758.0854,92.20792,1019.72455,720.48865,-787.9546,885.7001,718.62317,-407.23022,1075.6926,910.2927,-688.8417,955.7361,881.924,-352.17532,1091.8977,942.7651,-683.12115,985.18054,907.89624,-347.85745,1044.439,970.91064,-889.6885,916.3634,935.75836,-500.8743\r\nframe__4e8N8lz6lio__0006459.jpg,squats_down,1007.6775,471.5586,139.85979,998.8764,463.9082,146.28288,997.2744,464.74997,146.4574,995.8192,465.5449,146.32953,999.79297,464.51346,109.317825,997.8803,464.9428,109.29437,995.8159,465.61044,109.27409,978.5741,479.58572,174.1016,978.5499,479.61505,6.8756933,998.5756,489.26157,155.00615,997.8406,489.29016,107.093475,949.12054,549.6333,291.72183,954.3715,551.4718,-67.900406,994.284,650.96497,533.22876,1011.5705,634.629,131.16943,994.28125,632.28687,709.5342,1029.3572,552.17834,512.3902,999.11615,631.67737,748.9285,1035.6018,532.0231,545.9974,984.55365,625.3745,747.0061,1029.5078,520.98303,545.3181,977.3257,628.9049,709.8593,1025.4883,529.32074,523.789,911.8397,697.9119,81.35197,893.2579,706.6539,-81.666695,980.8302,686.03345,-62.926933,848.29047,746.84503,-314.73053,914.5818,799.37933,-202.51085,920.93787,804.2453,-106.31157,900.5559,820.12354,-210.13342,929.6502,808.3398,-79.65184,919.5673,818.0397,-255.16637,972.8641,828.16223,-100.584335\r\nframe__Spc5yl47h1Y__0009967.jpg,squats_down,2027.6833,1176.2946,-1755.2755,2052.246,1135.4718,-1693.9233,2068.0405,1136.363,-1693.8916,2083.7664,1137.0416,-1693.6106,2009.2762,1132.4249,-1697.0559,1993.4409,1130.5494,-1696.7411,1977.4669,1128.9042,-1696.5311,2102.684,1149.282,-1265.3872,1955.5724,1137.9766,-1288.1022,2050.9893,1213.4126,-1593.2181,1996.5612,1208.9281,-1598.5717,2175.535,1305.0552,-967.37134,1848.2535,1300.1918,-978.8555,2147.1829,1601.7677,-1506.2018,1850.5104,1600.3282,-1507.086,2093.5881,1419.3959,-2164.0173,1951.1912,1421.6664,-2159.5986,2083.314,1362.7423,-2305.1287,1980.9613,1368.5525,-2306.198,2103.7607,1321.7616,-2218.2312,1961.3022,1320.9928,-2220.5781,2087.967,1338.0776,-2136.8567,1974.5529,1341.8801,-2132.4263,2106.511,1584.629,5.8059626,1923.956,1583.6012,-4.426164,2248.716,1558.6907,-1355.334,1780.4371,1580.843,-1336.348,2250.8062,1828.6044,-413.3054,1757.5005,1839.7822,-417.09537,2233.6482,1870.0056,-342.08255,1775.7285,1882.1791,-353.20984,2290.8557,1942.0892,-797.8706,1704.3168,1947.1642,-831.13416\r\nScreenshot_2021-02-11 at 15.03.16.png,squats_down,520.98517,321.96558,-271.7203,528.3013,313.504,-251.69846,532.43134,313.81784,-251.72481,536.5915,314.02463,-251.6845,516.3548,313.15817,-250.70172,512.3716,312.9725,-250.6311,508.37256,312.8634,-250.71158,543.1582,319.14545,-142.05785,504.0652,317.14517,-139.82642,528.61115,333.61252,-231.95386,514.1313,332.7058,-231.04686,571.5592,373.40717,-78.79878,473.6271,375.67154,-76.31363,593.654,452.52084,-186.62093,464.6135,459.02554,-190.15991,555.65625,421.4806,-356.10895,501.347,419.94058,-364.72357,542.26465,413.20364,-392.7734,513.7252,408.29556,-399.83054,544.7442,397.90616,-371.025,508.36063,393.8449,-383.15146,545.3341,401.7601,-351.46014,509.04907,398.78568,-360.30078,550.2841,478.5288,1.0266224,491.28955,482.51428,-0.83629745,608.62445,503.21506,-340.22864,443.64252,511.0942,-345.77832,605.8694,610.119,-151.59743,447.10617,614.7432,-168.75366,596.3883,627.9483,-139.43669,454.51553,630.568,-155.64682,632.83124,637.8686,-266.6565,428.50537,643.63153,-279.66135\nScreenshot_2021-02-11 at 15.35.59.png,squats_down,577.66833,228.63445,-333.7315,587.51196,216.1837,-311.46887,593.5262,216.25244,-311.41785,599.58484,216.20659,-311.35416,570.4618,216.36015,-311.3051,564.5539,216.2817,-311.25516,558.6502,216.31311,-311.21277,608.53625,223.97708,-173.1709,551.6549,223.24353,-170.05615,587.8098,244.51344,-281.91235,567.594,244.30708,-280.67126,641.0643,293.5634,-76.15014,515.9526,294.2529,-87.410904,671.5586,396.33322,-200.68983,485.3549,396.5592,-221.99817,632.7709,354.57275,-466.94785,528.7235,357.0087,-472.89523,617.78064,348.00842,-519.50854,542.2165,348.34592,-521.61475,618.6023,326.52267,-504.9544,544.05255,328.98917,-505.22226,618.1533,331.46588,-464.8553,545.56824,334.78085,-469.87445,615.87,445.6175,-1.9554213,536.5102,446.46494,2.1118453,727.88965,466.87024,-304.70602,417.23178,466.59967,-290.13205,720.2943,587.462,-42.396015,417.88965,584.82477,-63.526054,704.11816,610.295,-20.496338,434.2401,608.1702,-42.78231,759.7876,621.3674,-131.85876,367.52927,613.3732,-140.8638\nframe__nfRdTJY_xgM__0001146.jpg,squats_down,925.96356,506.93222,-384.82095,938.2816,495.95157,-416.30273,940.9722,496.62692,-416.18878,943.8131,497.13934,-415.91852,937.5205,496.13724,-359.39825,939.07666,497.09528,-359.5006,940.94104,498.2538,-359.44678,962.26636,508.8201,-457.20447,959.0365,511.531,-201.43536,934.3356,525.26294,-401.05664,931.82806,525.9736,-326.6367,978.4115,596.34937,-533.8331,1001.5189,583.7194,31.781347,942.45917,715.3783,-610.34937,964.39874,698.8195,52.9506,878.5564,804.7664,-548.5179,908.7275,776.23065,-104.93704,861.79846,817.41455,-636.8788,892.89557,784.0984,-94.487595,857.7089,811.486,-602.0765,895.93756,782.78613,-164.18149,867.5687,809.29034,-541.7648,902.13306,783.22504,-137.35532,1129.0205,741.12256,-183.5654,1128.8799,726.02795,184.04799,1014.1286,701.63947,-287.8303,992.70776,683.9005,377.64676,1042.5176,873.58966,-70.094345,1011.50995,853.60004,629.2064,1061.3873,905.9016,-49.49568,1026.9647,886.058,651.6612,976.4677,896.24036,-155.27322,956.04944,875.69836,624.15784\r\nframe__8ghtQpeWov8__0013339.jpg,squats_down,1145.2465,525.3618,-49.847683,1143.3698,505.65573,-24.049858,1140.791,504.0619,-24.094934,1138.3804,502.59412,-24.240763,1142.03,506.59665,-86.79312,1138.8048,504.69403,-86.70768,1135.3672,502.98532,-86.68001,1111.4556,501.26096,96.82441,1107.428,498.3576,-189.94653,1125.957,538.24493,1.0149599,1124.0879,539.0415,-80.230156,1029.097,540.3582,315.74713,1049.3141,579.2766,-331.06598,1131.8356,618.0836,455.1011,1149.2759,691.0125,-298.90802,1191.5438,541.5811,470.72,1204.9164,539.9478,-1.648685,1211.3131,527.8411,509.11343,1228.8861,511.17493,-23.547304,1196.7815,512.12354,500.23984,1205.8073,492.7309,-37.845234,1188.0114,520.7109,463.72577,1188.7887,500.7078,2.7330797,841.93744,704.0243,218.3973,847.80444,729.46924,-218.10352,1053.6848,718.13196,394.62833,1084.7241,744.1743,-240.48326,967.56683,866.06226,569.23145,978.07526,898.20264,-68.63406,929.27356,884.8081,586.3316,932.2311,917.96436,-49.223984,1022.3231,915.1517,633.68384,1045.2842,945.26324,-9.995928\r\nScreenshot_2021-02-11 at 15.19.45.png,squats_down,224.4958,186.35951,-169.18526,228.25328,181.5992,-141.12737,231.3259,181.97101,-141.082,234.47147,182.3037,-141.06711,217.99643,181.5788,-146.83218,214.34491,181.72182,-146.7707,210.68092,181.97554,-146.8055,236.52486,190.45047,-16.130838,202.74455,190.06798,-42.205723,228.67702,199.206,-125.67636,216.63524,198.91054,-133.08867,255.88995,239.62141,-45.46259,176.34564,240.10884,-56.97015,265.93866,263.25775,-316.72662,162.42155,260.79453,-310.51956,247.39404,268.908,-555.8269,200.31195,275.98358,-505.70416,248.5846,273.06992,-613.0385,203.86563,283.57657,-549.63617,239.4187,269.63245,-603.90375,216.2458,281.40012,-540.14984,237.69896,272.5223,-560.2462,215.09424,282.30093,-505.944,247.78293,354.57562,5.9312963,193.32689,353.49594,-5.832512,303.24228,347.89038,-306.67618,148.30138,346.15942,-324.35095,292.89432,454.09927,-247.57285,149.22585,457.40878,-272.31003,278.1694,479.03375,-250.56862,161.34035,482.31696,-274.01196,327.89346,473.06747,-368.71484,117.04192,483.23047,-383.5098\nScreenshot_2021-02-11 at 15.02.44.png,squats_down,835.9879,253.06226,-313.7768,838.6182,247.26427,-286.78143,841.51447,247.21864,-286.76117,844.49744,247.08762,-286.76453,828.2594,247.82951,-292.73758,824.6174,248.0877,-292.68045,820.9687,248.41965,-292.59613,846.14185,253.2364,-163.31358,813.2412,255.07129,-189.65926,840.6487,265.1156,-269.5121,829.2491,265.66,-277.10062,876.37744,311.08493,-120.7972,779.42303,312.79956,-154.28613,918.0465,371.93124,-291.76804,744.6149,369.9592,-341.6788,854.49207,335.81146,-434.24097,808.82306,334.52142,-484.84964,839.1794,327.01242,-468.63132,823.6012,324.7495,-513.5847,834.7509,319.67343,-429.38733,827.17676,316.95746,-485.42407,837.5985,325.78357,-421.87448,823.92145,323.62485,-474.27902,849.1291,431.86313,14.065119,786.27435,434.3801,-14.039665,901.5162,504.22726,-285.68143,753.0117,516.4555,-325.43054,900.2776,612.41364,-103.27281,749.4082,616.55884,-103.21573,890.6215,630.705,-91.77377,753.87146,631.36127,-89.53262,928.9048,645.3099,-226.91835,737.8427,652.67615,-241.70634\nScreenshot_2021-02-11 at 15.34.24.png,squats_down,538.26196,320.55453,-392.95197,543.7058,309.8381,-372.53458,548.2734,309.66495,-372.47644,552.82025,309.41577,-372.39807,530.62115,310.4713,-372.51028,525.8705,310.57324,-372.37323,521.10474,310.77423,-372.34512,558.1177,313.71185,-247.48586,514.5392,315.6798,-249.77536,546.4495,331.2036,-347.03238,529.9471,331.7353,-347.38336,584.2746,364.47577,-186.31403,484.24008,364.82837,-182.6192,593.9251,441.1118,-390.43387,478.71283,437.6437,-375.01666,558.2197,387.80453,-608.3814,516.4371,389.61972,-588.9229,547.54626,371.13968,-651.68616,525.9054,375.92975,-628.3759,552.9536,357.76404,-620.92834,522.5252,365.7213,-600.2982,551.5256,364.4041,-600.1159,524.1744,371.3841,-580.2833,561.6267,467.30566,1.480431,501.24194,468.92984,-1.2150388,619.42487,485.0215,-353.64502,460.0464,492.88696,-360.72702,595.78094,579.9658,-146.64511,467.6618,583.2109,-160.10078,584.10016,590.10767,-132.57681,473.72598,595.7215,-147.2152,607.32605,625.1671,-270.57364,459.2848,621.4825,-290.01752\nframe__x0BK_DnHsso__0002186.jpg,squats_down,860.7588,506.3556,-148.37886,877.3328,491.3814,-158.92209,883.565,492.49118,-158.71646,889.85626,493.48767,-158.61322,866.78015,488.68033,-107.447014,865.281,487.22275,-107.33133,863.7701,486.07675,-107.5486,916.70337,504.66074,-163.92262,881.5736,494.0054,62.84079,879.6279,530.4302,-151.37749,864.98596,526.3771,-86.183876,980.6717,593.42456,-242.90494,875.35736,603.8566,160.6699,908.27637,734.35315,-188.18407,784.4245,726.3524,-143.58752,876.18243,653.4237,20.51375,835.3482,639.2058,-573.4053,862.9563,634.7457,33.87028,835.11633,620.8512,-616.2339,884.9917,623.3936,20.83757,864.0354,604.0852,-553.1749,891.88275,633.1163,28.479092,869.924,613.72784,-557.7674,1067.9567,781.8902,-118.76588,987.97064,786.32166,119.02928,1036.2638,790.109,-811.2069,843.40906,777.60706,-190.84183,1095.2104,979.8237,-655.2418,928.8224,933.67535,-38.28518,1112.8151,1007.62976,-650.00073,963.77094,956.9489,-27.402267,1048.032,1040.8033,-895.8881,858.9418,995.66376,-157.6118\r\nScreenshot_2021-02-11 at 15.43.05.png,squats_down,632.25745,255.80832,-51.753716,626.3196,247.92802,-89.4978,621.65204,248.53784,-89.17447,617.1467,249.29385,-89.37727,638.54803,248.36047,-88.44962,642.6248,248.49606,-88.24471,646.7609,248.97302,-88.209366,608.5018,261.88922,-179.58832,651.4261,261.08997,-174.5425,624.93646,268.502,-74.385544,637.3701,267.9433,-72.70574,559.8993,306.75485,-150.00491,695.32715,311.52332,-147.5779,539.95013,206.98071,-96.69597,722.327,209.37714,-119.45145,535.05646,99.8226,-142.02562,737.1765,111.24388,-201.82178,516.68756,74.544945,-177.868,750.0995,89.090675,-255.06606,538.0293,69.06783,-192.51797,733.1623,82.562996,-260.8166,552.079,81.04164,-150.32632,722.56885,91.44553,-209.32558,566.9564,536.93396,7.1928425,654.867,539.5981,-6.4051876,529.2178,546.50995,207.74974,750.6134,528.093,123.96171,509.71066,646.50836,313.11166,720.22577,637.84424,175.21132,512.0157,665.7756,325.8725,704.31354,656.2692,182.17697,489.77426,658.53503,335.18723,728.1737,661.0246,216.88533\nScreenshot_2021-02-11_at_15.38.48.png,squats_down,1332.2609,551.61633,-689.54816,1346.4049,531.57544,-628.6201,1356.0269,532.0337,-628.76025,1365.7024,532.3044,-628.6559,1319.0818,531.2983,-631.45557,1309.3679,530.9625,-631.2868,1299.6367,530.8874,-631.1128,1378.7408,546.9511,-344.50745,1287.3998,544.6068,-360.11847,1349.2644,579.13574,-591.27716,1314.1238,577.94617,-595.2392,1438.5812,668.48846,-227.39133,1216.4176,661.9713,-286.5521,1520.1575,817.32135,-712.5775,1125.6099,817.7033,-816.49316,1417.0387,690.64954,-1030.9269,1244.3887,694.3716,-1226.9685,1394.8512,646.2403,-1082.3818,1273.719,658.9547,-1275.1691,1392.9545,631.3846,-966.4742,1277.4026,637.44434,-1178.31,1389.2743,651.965,-988.6136,1277.4257,658.4597,-1185.809,1384.2556,891.969,23.92286,1251.8988,892.2771,-23.023926,1492.4088,885.99603,-867.23535,1187.523,890.4091,-994.29456,1453.4208,1102.2677,-403.4084,1196.9966,1112.6655,-550.8156,1427.006,1139.7712,-373.8373,1211.7736,1146.6411,-523.8041,1518.3625,1172.4054,-679.1037,1176.3813,1188.5226,-863.51135\nframe__mGvzVjuY8SY__0001209.jpg,squats_down,892.9453,489.82913,-684.51874,909.9114,465.9719,-674.89984,918.91504,465.22083,-674.8249,927.88434,464.41483,-674.86926,890.3401,467.6465,-631.8003,884.712,467.57147,-631.42474,879.20386,467.7427,-631.03357,955.4876,470.63425,-552.254,892.9074,473.60797,-365.1737,917.4844,508.995,-637.51825,890.80743,509.8723,-583.7513,1027.6913,557.4596,-557.3788,888.9436,564.28033,-185.54337,980.1759,713.0089,-685.4696,793.30096,723.55994,-554.57776,885.01843,595.2842,-713.87396,829.5971,591.3409,-1042.1327,854.56287,567.4296,-758.81903,823.51196,559.0087,-1111.8877,884.3595,547.8855,-754.31445,852.12805,537.5885,-1035.243,899.6383,555.9954,-703.8778,862.48114,551.4516,-1023.16327,1123.8077,745.3576,-123.18399,1037.8148,740.1275,124.00493,1005.2947,799.9735,-847.28577,836.9447,775.1537,-212.86845,1103.927,979.0198,-473.14233,894.5967,939.66565,181.75732,1136.9448,1007.12805,-453.34683,929.4204,967.906,212.81184,1051.4369,1052.2758,-722.0988,798.1291,1011.08484,70.97562\r\nframe__J_8p7qnpUe8__0005093.jpg,squats_down,843.25275,491.49304,-288.6453,859.90546,475.87958,-327.6941,864.6552,476.16803,-327.67572,869.35535,476.47626,-327.66202,858.8821,476.19397,-262.23685,861.6975,476.4943,-262.10425,864.9074,476.93225,-262.02994,901.5118,485.1646,-382.42078,895.21625,486.14368,-79.93819,860.6012,513.4312,-313.774,857.83167,513.6175,-225.40984,946.2438,604.67035,-469.7456,925.3324,582.67224,138.93208,835.8736,713.3335,-409.77158,827.57446,687.29016,243.03566,781.6875,598.8528,-140.64984,779.3454,606.34265,224.26958,760.0646,561.9003,-175.24734,761.7371,571.44354,260.80972,785.4174,553.8219,-201.93391,782.51746,566.03,277.27145,798.30817,569.1662,-143.86577,793.0504,583.42786,228.21362,1159.0828,718.0387,-207.94034,1124.0947,702.4871,208.47974,966.9978,758.2924,-404.613,939.13336,740.3397,592.15063,1043.4215,976.65546,-465.1134,1006.1342,899.8839,857.7388,1081.39,1019.6854,-475.39197,1041.3899,931.5818,886.8766,945.15955,1020.94165,-568.9986,921.52814,951.3849,880.40826\r\nframe__26X9x2ta4Dw__0005706.jpg,squats_down,924.0094,495.93832,-261.64343,935.96497,478.4026,-244.3842,943.65326,477.28806,-244.14757,951.43854,476.1574,-244.02377,917.4124,481.9852,-225.03156,910.856,482.91193,-224.95029,904.3467,484.07812,-224.88397,971.2305,486.06512,-106.39194,909.87134,495.46527,-24.795267,945.32635,512.29706,-208.92429,918.8567,515.8181,-185.53537,991.9765,554.0873,-226.27335,948.6914,565.3212,203.84427,896.1498,584.87445,-227.90369,859.9108,598.93787,126.14598,863.1668,567.3672,20.977386,853.9915,578.2141,-140.20673,858.28986,559.26526,9.682695,844.70557,578.2215,-175.16542,861.9617,563.38086,1.5582509,860.28986,569.89185,-178.93875,869.00366,572.3504,22.668987,863.58624,577.4454,-150.73001,1055.167,783.83655,-144.71283,1020.4719,773.3725,144.60095,922.5524,785.01154,-357.01825,881.392,766.28204,24.590538,995.3715,958.2809,-283.71222,954.87866,917.1709,30.9321,1034.2616,988.3853,-275.4511,989.78735,939.903,30.165638,923.6113,1009.4722,-337.4285,900.7876,968.9808,1.3568829\r\nframe__8ghtQpeWov8__0011734.jpg,squats_down,985.2182,495.50763,-885.15155,992.0216,475.48016,-850.1677,998.87146,474.4895,-850.149,1005.90753,473.3969,-849.8683,970.9412,477.99753,-862.72125,962.9313,478.5954,-862.6547,954.891,479.30887,-862.6422,1012.0667,481.21204,-618.121,941.04486,487.9721,-671.9508,996.913,513.30084,-797.87427,970.4647,516.3297,-812.1931,1053.331,554.1555,-446.42657,887.26025,563.468,-552.5352,1158.0759,637.5494,-683.7308,796.40015,661.8377,-700.48047,1108.0012,685.77747,-1094.0748,788.365,747.94965,-905.13745,1105.9484,710.4741,-1190.9849,776.5528,779.0369,-980.9919,1075.3293,697.2056,-1185.9348,805.9882,772.1964,-996.503,1072.1959,698.7059,-1103.6499,811.736,764.85364,-913.6002,993.13214,719.06067,32.25701,895.1149,726.1727,-31.695177,1127.0298,721.0405,-384.73755,820.1146,751.954,-641.9093,1094.3977,872.33026,-22.531837,825.477,916.22864,-245.3427,1067.8928,902.27484,1.8797855,835.64825,943.5862,-220.46939,1160.3018,929.555,-181.27145,806.752,975.3414,-460.5398\r\nScreenshot_2021-02-11 at 15.25.22.png,squats_down,590.5596,335.7018,-108.91583,593.2295,327.25012,-89.45054,596.6883,326.75003,-89.37893,600.23645,326.21887,-89.30544,582.4426,329.23254,-92.69146,578.39014,329.90326,-92.704544,574.3523,330.71326,-92.79763,603.9514,332.35324,14.35345,567.7409,338.53992,1.3168985,597.41437,346.46176,-71.4715,583.9021,348.64902,-74.94024,627.85175,375.64996,-1.3850251,546.56537,377.54648,-25.250404,663.7974,376.628,-275.89273,508.2973,378.99277,-302.73953,659.1339,381.4802,-526.4477,523.8935,374.77274,-546.8491,665.09595,387.7586,-574.72546,522.7699,380.1761,-577.49567,651.9383,388.146,-561.64185,535.97504,380.78766,-568.8704,647.93445,391.30392,-529.0609,538.54724,384.30588,-546.11755,611.6646,497.8878,4.3701005,561.79834,495.225,-4.02319,666.16724,480.23868,-276.46548,505.88855,465.56766,-288.13104,632.4819,578.18945,-170.08884,534.5492,565.2696,-186.94052,616.672,595.2995,-166.90114,549.6337,581.61084,-179.02466,656.32935,608.9041,-277.31427,513.71857,598.2882,-272.53998\nframe__cTTtZM2I8Ro__0003534.jpg,squats_down,891.09283,545.0077,-225.62822,900.4771,531.25793,-266.51178,903.0323,531.40735,-266.38657,905.66187,531.5187,-266.38773,902.66455,530.2985,-205.08986,905.82184,530.40216,-205.1287,909.40283,530.6599,-205.13322,927.899,538.77783,-358.74557,932.55524,538.64185,-80.3994,901.1371,561.7352,-256.44006,902.744,561.64606,-174.60585,955.3254,606.7809,-451.94156,968.89215,598.3234,91.1241,829.33704,634.3023,-618.9359,865.21844,635.8965,109.94727,702.0955,604.9425,-605.5706,745.9142,604.50653,-88.64542,668.46136,588.27954,-700.6231,722.84216,574.33887,-77.707214,674.24115,575.384,-649.5592,712.32794,581.3472,-157.36757,685.96326,584.88116,-593.0659,719.19745,594.18353,-128.08742,1132.3716,756.8888,-190.89627,1125.9897,738.72174,191.67197,994.7873,739.7088,-257.1322,953.92004,714.21277,347.6969,1045.3394,913.1581,-63.20214,1022.58856,869.7801,602.1852,1068.5214,943.8634,-51.547634,1051.2622,894.4499,624.5274,969.2735,937.075,-108.98924,955.7121,905.14795,650.46875\r\nframe__VusCUj61wDA__0003802.jpg,squats_down,908.16754,441.1526,-748.0093,918.66345,425.2144,-737.58514,925.35913,424.91278,-737.5062,932.0,424.63235,-737.5791,902.3738,426.1893,-707.79694,896.9321,426.0179,-707.491,891.6807,425.94363,-706.9701,947.4315,428.6556,-625.5524,895.9573,429.59647,-498.3537,924.7212,454.68903,-703.238,902.4149,455.52438,-667.08374,998.947,489.17917,-614.47144,892.3036,490.8797,-316.43826,997.3352,622.6329,-754.40564,884.1362,615.05457,-572.1472,894.6705,557.25165,-888.0126,873.3799,551.8473,-1018.39886,859.7702,544.82776,-942.69885,864.3457,537.13586,-1079.1621,876.25116,517.254,-940.3047,873.7566,513.43976,-1054.9518,890.5137,516.9832,-885.31146,879.33997,519.49554,-1018.91486,1086.5012,609.45734,-100.744675,1016.9564,602.4641,101.86813,1049.621,739.1377,-629.5203,885.3969,707.29865,-34.701546,1113.1875,850.6462,-364.7444,885.42755,817.37085,266.9538,1132.5719,866.941,-349.62183,899.12787,836.8315,291.2946,1091.7484,901.1289,-560.39197,830.5193,865.2706,179.6917\r\nframe__XJcoOdKlYqk__0010324.jpg,squats_down,2596.3877,997.33655,-1829.0626,2615.3213,960.1097,-1779.758,2628.6282,959.877,-1779.7601,2642.1414,959.5156,-1779.7944,2574.1025,959.55835,-1796.8954,2559.147,958.7439,-1796.8354,2544.1626,958.132,-1796.8715,2650.5964,965.5721,-1375.1661,2517.308,963.07166,-1448.668,2613.1694,1029.1715,-1666.8024,2566.6167,1027.5189,-1686.6727,2719.0151,1104.0164,-984.4598,2402.58,1108.7416,-1125.472,2795.8193,1354.13,-1527.2643,2385.9172,1374.3054,-1642.5299,2686.9702,1178.1404,-2292.3945,2560.2346,1186.3146,-2223.5676,2657.782,1126.4412,-2429.7288,2607.2437,1128.9958,-2340.0957,2658.5051,1086.541,-2339.4197,2601.5542,1091.8729,-2249.0312,2654.4517,1111.4122,-2270.4692,2601.8037,1119.0647,-2194.4917,2592.7957,1359.5164,42.748055,2409.5586,1356.8365,-43.10127,2739.19,1519.9615,-933.0137,2318.032,1532.147,-1008.2288,2649.3384,1793.0575,-243.9727,2316.4524,1810.0677,-360.6229,2605.8264,1839.7289,-194.78247,2326.7268,1858.1053,-319.8063,2712.9424,1914.5802,-545.6629,2288.7236,1922.3973,-740.2425\r\nframe__RjnyMfZb00M__0002138.jpg,squats_down,1000.82416,575.49817,-292.60123,993.8554,560.2963,-259.99097,994.4822,560.44977,-260.18726,995.3135,560.58655,-260.28363,986.3498,560.58105,-310.76135,981.1593,560.5686,-310.80338,976.10834,560.68475,-311.14844,975.3913,568.7019,-84.31223,948.45953,567.72766,-319.8561,994.19196,592.2513,-227.10826,984.1895,592.10693,-293.7103,984.3954,645.29736,6.5848403,871.0054,654.69244,-353.78546,1021.75256,747.20294,-171.99174,904.66235,802.6451,-539.835,1052.7761,672.74365,-540.37964,992.6387,705.8826,-722.9458,1072.867,655.0496,-593.7743,1016.7239,685.8578,-787.4574,1064.199,640.7569,-599.16736,1000.4743,660.67377,-784.66766,1053.0752,648.31586,-552.85535,994.5235,669.0277,-720.1587,909.30536,824.57043,137.42006,838.3181,843.5465,-136.9681,1050.702,774.4634,51.153294,907.5834,781.13043,-647.8169,997.38385,880.5201,220.80916,888.0319,958.96515,-336.8406,967.4087,898.65955,234.21054,867.62506,986.5788,-311.69888,1049.8599,931.9516,127.502716,939.9404,1011.0275,-496.21555\r\nframe__LMEb5jsIokU__0007373.jpg,squats_down,1092.3529,465.7778,-90.57695,1084.251,449.91266,-79.68928,1081.8519,449.91528,-79.56976,1079.6259,449.98068,-79.40558,1083.556,450.50964,-137.9289,1080.5894,450.01593,-137.7751,1077.4766,449.8164,-137.68896,1057.7632,460.37738,6.301577,1054.503,459.57062,-251.57802,1079.8396,487.3632,-55.719078,1078.4227,487.34,-128.87073,997.6254,548.087,220.43987,1026.6727,570.7417,-393.57785,1075.7837,650.38196,394.55106,1101.3589,687.4588,-219.74272,1113.4209,617.12244,495.61392,1116.2667,605.2833,199.14207,1133.601,605.0714,538.6198,1125.8177,583.3182,199.73526,1111.177,597.62976,538.2702,1110.4667,572.19806,195.75092,1098.3174,604.48413,493.05313,1101.484,583.65967,211.15201,850.48254,750.124,196.31866,858.4768,759.9509,-195.98642,1046.8662,776.80505,300.0368,1070.5675,755.87445,-138.33965,943.6046,898.51135,276.30734,938.4695,908.1655,36.695396,912.647,915.69745,281.3006,902.7296,933.52924,57.17639,975.7761,947.71716,376.63477,970.30676,960.3378,149.92824\r\nScreenshot_2021-02-11 at 15.40.26.png,squats_down,589.0234,264.0198,-321.1562,598.24524,250.06671,-308.82974,603.3957,249.5325,-308.8276,608.6348,248.88853,-308.9133,584.1649,251.18388,-304.47916,579.56335,251.27463,-304.52808,574.9328,251.41925,-304.5352,620.1108,252.45126,-198.89156,573.7901,254.75983,-176.58696,600.0989,276.04736,-277.85455,584.1895,277.2711,-271.18088,661.5589,316.43204,-92.06385,547.1798,317.09915,-80.603584,669.8921,428.69122,-157.55493,527.5624,430.13943,-170.37865,616.90344,370.5349,-317.46616,572.3873,378.8719,-371.35205,601.3843,354.05368,-361.1202,587.80176,364.825,-410.23386,604.31415,334.3697,-341.1273,582.9449,345.22186,-399.05545,605.20135,340.7197,-312.45956,584.4531,352.23514,-369.75412,642.4554,455.23608,-3.0491111,570.50214,453.4777,3.2081923,738.4834,505.84094,-279.4857,467.74585,493.25253,-237.84682,721.2794,615.10187,-72.68289,488.46765,615.3226,-77.682236,702.70715,638.3538,-56.438267,508.91144,639.3496,-66.88061,768.2329,641.66547,-182.80132,442.52042,646.3337,-184.58876\nframe__FsqhUFcjL8k__0016706.jpg,squats_down,1097.1498,489.7636,-333.356,1097.485,473.2066,-289.74353,1100.3212,474.48325,-289.60883,1103.3811,475.85468,-289.22153,1084.6625,469.77048,-336.80582,1078.4569,468.03934,-336.6128,1072.1328,466.52542,-336.70282,1093.2576,482.60257,-74.251495,1054.4326,470.46396,-285.82538,1098.433,510.8888,-253.87282,1083.0037,507.11963,-311.10107,1043.5197,557.74805,190.35028,1044.2649,568.1624,-406.29517,1147.7079,645.6744,175.1235,1177.0029,671.5268,-371.0684,1176.9225,558.6718,18.900646,1189.6898,551.8606,-109.57033,1201.9373,531.7715,29.433989,1208.8573,522.526,-140.84528,1174.0801,524.3733,45.136993,1173.5101,515.78546,-156.44022,1164.7462,536.06445,15.687241,1159.8419,530.08813,-105.63687,888.84344,729.3938,201.00046,872.0979,753.25104,-200.53793,1066.6759,770.3742,416.21445,1066.6765,818.1793,-271.7283,983.39685,892.54236,553.9316,997.0999,976.0257,-178.18028,963.0463,915.9886,564.1631,970.97955,1006.865,-174.8685,1038.9983,912.9744,596.7388,1072.2137,1001.444,-199.82217\r\nScreenshot_2021-02-11 at 14.47.20.png,squats_down,433.40555,269.3609,-82.813255,438.8905,254.7968,-69.26043,443.36142,254.036,-69.04074,447.93765,253.15251,-68.950516,425.90448,256.43002,-69.82172,421.1667,256.42996,-69.68332,416.40973,256.53552,-69.87852,453.72092,251.50754,47.828445,409.42056,255.7693,53.211956,441.32834,277.34863,-35.74601,425.7039,278.8302,-33.887848,480.82428,287.87732,102.3369,382.12915,291.67734,90.48432,527.3247,312.24835,-191.72334,360.25485,324.8621,-171.09877,515.2428,294.16568,-495.0523,379.0497,284.32913,-412.64154,517.8522,285.69458,-553.5055,378.81522,271.5213,-459.4921,507.64508,282.3856,-534.79065,386.57367,269.55634,-435.24768,503.77942,288.88226,-496.60416,391.5057,277.8926,-407.75354,457.27057,412.84662,-2.4336977,389.95938,410.1941,3.2211697,525.35175,375.19675,-431.62277,331.45105,368.92004,-428.8643,506.8972,510.05997,-417.02902,344.61597,529.0608,-455.20224,496.92267,532.1414,-423.20068,356.05243,555.81995,-461.9636,521.83594,535.4259,-577.3516,326.8993,565.2836,-602.7529\nScreenshot_2021-02-11_at_15.50.12.png,squats_down,1256.3136,523.2117,-481.3694,1270.2327,500.47476,-443.75067,1280.0791,500.52322,-443.61392,1289.9557,500.36768,-443.79913,1240.7343,501.87186,-449.75027,1230.2344,502.2668,-449.2918,1219.7623,502.87152,-449.25797,1301.9186,514.4899,-167.21869,1203.8624,517.9622,-201.66545,1273.2976,550.42896,-375.09167,1237.054,550.87714,-385.22873,1360.862,614.401,-27.404387,1137.917,629.68286,-41.656887,1422.1085,723.0734,-282.51758,1118.5543,744.3929,-354.23395,1478.5852,710.8574,-909.94556,1096.8757,698.4101,-1011.0594,1505.9327,719.32465,-1029.3132,1088.1614,701.63184,-1137.0161,1484.5735,700.8876,-1066.647,1097.8898,669.888,-1146.1887,1467.4788,701.2121,-936.9094,1109.2926,673.77655,-1026.7329,1355.2075,871.78955,1.5634444,1216.3254,881.90936,-0.56654894,1473.1381,966.2376,-617.5035,1070.8417,1000.1093,-595.39435,1411.1498,1184.4476,-154.83519,1132.0873,1177.3486,-173.26848,1379.6488,1219.9623,-118.8945,1171.5817,1206.0065,-141.05153,1468.5507,1266.7767,-342.97052,1061.3739,1265.033,-363.76645\nframe__ku3vgejAZ0g__0000864.jpg,squats_down,917.7085,339.51636,-1046.441,928.55664,317.7728,-1021.363,936.23334,316.88513,-1021.39185,943.96344,315.88016,-1021.4761,906.45197,319.65228,-1022.3614,898.72546,319.86536,-1022.13525,890.94305,320.22476,-1022.09265,957.7019,319.28168,-790.67236,882.6714,324.487,-798.9164,933.40063,355.5794,-954.95953,906.927,357.23636,-956.40906,1020.9872,399.53067,-580.3483,834.40564,402.10934,-582.32025,1055.6564,551.98663,-801.3349,762.29315,534.52924,-856.6228,960.12866,510.40396,-1210.1432,843.2261,492.82367,-1294.6732,928.13403,503.36057,-1280.5948,870.4091,487.59363,-1363.1428,931.8522,473.8353,-1250.2761,874.6714,457.67645,-1337.8441,936.0584,478.12146,-1198.4597,873.2262,462.9431,-1285.4047,990.7902,570.4017,7.2499685,884.57153,575.2162,-7.682526,1058.6062,685.9891,-456.40762,825.4927,723.8325,-530.09247,1023.84467,844.24194,-57.505028,873.02124,866.9068,-99.22171,1006.33234,870.3715,-28.342337,893.248,892.4717,-69.38155,1052.3763,904.2953,-241.26918,830.938,920.60956,-288.74783\r\nframe__8ghtQpeWov8__0000791.jpg,squats_down,1072.8373,484.57135,-589.9622,1072.857,463.04773,-550.02,1077.7705,462.79062,-549.91943,1082.9767,462.6167,-549.7005,1054.3778,462.27798,-587.6894,1045.9591,461.3892,-587.5316,1037.4731,460.64764,-587.57056,1073.9548,465.06946,-325.59348,1012.40546,461.19763,-491.40903,1074.0,502.56528,-506.28638,1051.6316,502.48404,-552.0893,1074.3082,535.46246,-133.81683,943.2231,536.8517,-548.0829,1152.0286,606.7998,-282.14078,939.6936,681.7469,-619.5233,1181.0997,668.1368,-691.757,1044.8485,722.3349,-525.6271,1199.8615,689.22595,-756.8419,1071.2839,735.806,-585.8388,1185.3395,674.6287,-784.0709,1080.7415,712.8497,-569.50653,1171.0122,674.7273,-717.11115,1068.1488,712.21844,-515.7444,926.2519,707.7104,124.48936,845.2156,709.4287,-124.546364,1081.9658,723.034,-124.97342,953.43866,741.29016,-699.5696,981.3786,871.7074,66.01198,875.55273,897.5578,-400.99573,938.7555,896.3154,77.32204,841.8934,916.79376,-382.16217,1042.2034,935.6849,-49.3176,930.21716,965.9882,-598.0759\r\nframe__4zBnM_uozXM__0006727.jpg,squats_down,963.6898,85.96756,-196.18823,983.4327,65.23298,-222.77805,989.23517,66.12457,-222.54575,995.30585,66.72881,-222.8261,977.9875,64.080765,-171.5235,978.2158,64.25187,-171.64313,978.79236,64.85784,-171.67816,1026.4448,86.37095,-245.55124,1007.2335,81.50751,-11.560344,982.55927,118.04524,-197.45784,971.4053,117.44512,-129.63597,1058.8676,232.20293,-348.25076,1064.3145,227.96394,252.13727,849.5164,355.14032,-413.69058,866.5945,329.80402,355.82776,644.18036,414.59845,-324.22195,670.2111,345.33755,216.4718,591.6414,423.26846,-394.6029,632.71295,322.0703,234.44588,595.72626,400.0337,-350.94708,616.89343,323.83655,152.95012,619.4153,401.29385,-307.5721,631.383,343.6624,179.18266,1297.8654,605.86774,-206.28555,1286.2026,581.24426,206.67369,1024.3082,571.7013,-227.19589,1029.7422,552.2706,341.39536,1114.5037,885.70087,54.259388,1095.3838,853.43005,591.8904,1166.3687,935.2176,80.070145,1139.6487,903.1357,612.83276,1004.17,947.22345,46.042713,988.34735,932.56177,621.95856\r\nframe__MG69sFM1UIw__0005616.jpg,squats_down,922.065,596.5781,-961.76447,930.6007,578.32776,-937.9278,936.98083,578.2857,-937.87604,943.4159,578.1772,-937.728,911.8943,577.56714,-944.99915,905.03253,576.8493,-944.8267,898.141,576.1811,-944.7939,949.03754,582.4226,-747.55774,886.15674,579.1457,-773.0934,931.003,611.16656,-886.18835,908.74835,610.1898,-892.6424,984.2468,640.2131,-558.57056,840.7277,641.4983,-580.1786,983.2425,772.27844,-749.1403,835.9328,782.9387,-785.3152,947.6495,701.717,-1034.2411,897.6611,700.6357,-1072.9551,939.6025,679.8169,-1092.4404,914.39343,671.25336,-1141.1427,945.31067,657.2147,-1061.5011,910.1496,651.83234,-1096.804,942.3574,664.25867,-1024.7244,913.8384,662.67413,-1059.8617,956.251,729.53986,3.76337,875.47955,734.7981,-3.8350031,1036.7186,784.477,-502.11874,794.9465,812.9223,-506.1565,1088.353,900.486,-122.65555,768.12244,918.8079,-112.96174,1086.5986,920.0675,-93.585236,774.5521,935.1967,-88.78218,1120.414,944.8803,-286.9378,745.1842,970.1576,-295.15356\r\nScreenshot_2021-02-11 at 14.24.58.png,squats_down,621.14435,265.75598,-635.1445,628.0769,250.14865,-611.9321,633.7781,249.30061,-611.89557,639.60156,248.26099,-611.7568,611.7414,252.39592,-609.235,605.8517,252.97658,-609.1124,599.96643,253.64754,-609.041,649.42377,253.75266,-469.19318,594.3962,260.6132,-454.68344,633.80096,278.82834,-581.9129,612.70795,281.3906,-577.2585,696.7112,318.53632,-370.41113,560.68195,323.8759,-336.76282,776.3006,393.31348,-396.26285,485.17642,399.3404,-363.25528,789.9546,486.58685,-489.97342,482.8528,484.3527,-462.2896,803.5555,512.3906,-535.4169,474.44818,510.7603,-504.8553,781.1296,515.9005,-559.7969,496.41724,509.77948,-530.7519,772.4293,508.82645,-501.85968,504.03934,502.2933,-474.42752,668.39154,459.62473,-4.5466046,593.5282,460.6307,4.6453934,761.9833,511.8147,-374.45468,525.1595,514.50226,-320.50262,750.29987,630.7397,-80.81982,531.4048,630.5217,-43.58037,736.2021,646.1034,-56.6297,546.32275,648.19214,-22.48592,782.885,685.2262,-190.81052,495.89285,682.31305,-163.82738\nframe__NsCiNjVEzTM__0009996.jpg,squats_down,1180.4945,315.47253,-6.5863533,1173.9401,293.51675,-5.037045,1169.892,291.7081,-4.9328504,1165.9252,290.05966,-5.129271,1178.402,296.33224,-66.613106,1177.6014,295.90778,-66.453735,1176.5557,295.77454,-66.464905,1143.434,288.8557,62.51004,1155.8413,294.41815,-228.47981,1164.4614,329.0767,27.829866,1170.0448,332.52228,-54.019615,1059.9241,360.24774,330.9012,1122.3414,374.62637,-381.5934,1190.8843,390.71506,709.99615,1283.1501,414.12012,-319.06363,1218.4503,354.99667,979.3189,1225.0974,339.1756,157.8862,1238.1475,347.6312,1042.2043,1211.8608,318.08548,173.33366,1209.1965,348.08936,1031.7307,1200.2412,331.0134,172.65608,1197.9664,353.93124,981.9363,1198.806,339.92896,175.97267,917.34973,617.1081,237.66264,954.91284,627.70166,-238.00156,1038.9086,694.69995,777.3525,1191.6799,710.65765,-152.8248,981.3281,834.6734,1021.77295,1103.9629,909.77045,-125.99698,952.48865,859.47046,1051.243,1056.8005,944.3768,-119.721306,1036.6226,865.6262,1174.653,1188.3785,952.04266,-39.673065\r\nframe__8sbJpaXfYwM__0011892.jpg,squats_down,954.63916,506.05252,-164.49495,959.2512,482.2601,-134.02457,962.6858,482.4734,-134.1046,966.2668,482.6882,-134.11879,946.05786,479.657,-181.47743,939.1715,477.25497,-181.39859,932.27295,474.9761,-181.69427,951.07837,481.96033,37.674297,908.4885,472.88864,-174.08846,949.1747,524.0728,-97.88185,930.9753,520.0396,-156.94716,890.97015,551.18945,268.24286,864.4551,567.5921,-276.91522,933.4789,665.1367,284.0744,914.78107,730.06824,-189.25356,999.1031,596.5568,66.87644,996.8603,623.9068,108.536835,1018.4769,575.5098,51.677597,1022.93005,596.016,97.29426,1016.30194,556.82117,38.236294,1013.15356,566.0819,96.10374,1007.89056,570.44,54.03483,1002.19,581.18085,118.09116,776.9033,763.1699,200.36725,746.7786,782.7025,-200.42253,972.52386,714.21875,339.86276,966.8178,765.3271,-437.273,899.9934,868.4852,397.0954,850.9173,966.2164,-473.74518,859.5552,899.88275,402.15656,795.24146,996.90234,-475.87604,977.4897,908.735,399.7203,938.59674,1037.368,-531.25806\r\nScreenshot_2021-02-11 at 15.05.25.png,squats_down,551.467,210.4827,-413.1437,560.5717,197.04532,-385.2728,566.5038,196.55356,-385.25565,572.46796,195.92213,-385.32666,543.38727,199.33908,-383.98425,537.6261,200.07991,-383.88486,531.85364,200.92345,-383.8114,582.8748,203.17303,-230.60417,527.0734,209.08502,-219.61148,564.1195,226.36922,-356.03482,544.10065,228.44215,-353.02258,633.17114,282.10535,-128.78049,493.91473,292.50626,-124.9969,659.64197,404.2255,-281.11136,484.82385,412.05487,-268.89474,595.8296,346.27228,-555.3054,537.6284,351.39572,-539.51587,575.2754,334.83154,-613.68304,551.83093,335.96063,-593.9713,578.4625,310.00125,-592.76685,547.4654,316.81683,-577.96796,581.0589,315.38284,-551.94696,548.6448,324.07816,-537.6485,621.25586,454.92804,-5.7344723,532.48315,461.57346,5.994367,755.3999,488.17947,-324.5247,407.1693,505.363,-316.9156,782.83325,642.5492,-99.75598,392.39468,644.88574,-94.39934,769.6866,672.05493,-82.41911,406.6371,672.0448,-75.949715,836.3435,679.2333,-225.17467,338.11453,679.4642,-198.69963\nframe__zbt1g9WX6bA__0009416.jpg,squats_down,1845.2277,1100.7185,-1328.8918,1867.4148,1071.7982,-1259.6674,1880.0458,1072.9076,-1259.6442,1892.7346,1073.7439,-1259.4264,1830.1288,1069.4286,-1261.1898,1817.4253,1068.3745,-1260.854,1804.6378,1067.5409,-1260.938,1909.6586,1089.3142,-847.01025,1786.9071,1079.4332,-858.6364,1863.7971,1137.5183,-1175.6277,1820.4777,1133.9491,-1178.8599,1988.1956,1264.1593,-563.7739,1682.217,1238.5764,-603.24286,1984.7848,1528.9954,-1022.27466,1634.3458,1492.8215,-1098.76,1891.2672,1385.6077,-1674.6154,1766.9667,1396.5394,-1755.2023,1867.2762,1340.6594,-1834.6755,1798.9587,1363.7631,-1903.3257,1884.1938,1297.545,-1746.7054,1794.2207,1326.3826,-1839.0873,1877.5647,1311.9087,-1653.5109,1800.8302,1341.4407,-1738.9734,1922.8374,1548.8947,10.282632,1745.7234,1540.9946,-9.152322,2118.2944,1571.8514,-1175.2207,1593.0283,1541.8368,-1249.6526,2073.4636,1876.4667,-397.77325,1549.8104,1858.1122,-465.16187,2035.9877,1933.7361,-347.49518,1571.5194,1920.1376,-417.23764,2155.3599,1968.7831,-810.2776,1455.4697,1939.9423,-895.7947\r\nScreenshot_2021-02-11 at 15.16.55.png,squats_down,482.88248,350.64536,-538.0018,490.46887,335.9975,-519.1931,496.23584,335.39313,-519.1396,502.00983,334.73694,-519.0034,475.81375,337.08078,-515.2368,470.539,336.9884,-515.1725,465.23065,336.97903,-515.0297,513.6578,337.1624,-391.43558,462.12042,340.03616,-366.9986,496.2124,360.21274,-490.3198,476.79025,361.22415,-482.70352,554.5507,379.70865,-285.03662,440.93063,380.662,-282.83334,575.75183,461.1904,-457.6216,406.81815,462.1137,-482.66202,508.64923,407.3151,-602.6878,452.42728,406.18652,-655.5373,490.056,394.8169,-629.10425,466.19873,391.85114,-678.3454,489.76776,381.17828,-583.9929,465.83997,378.03076,-645.89545,492.4107,388.59036,-583.0045,467.12323,386.64297,-642.835,528.7891,481.22766,-2.3954697,464.9971,482.554,2.52048,563.6848,492.30508,-403.55063,443.73846,518.26874,-364.84366,541.5402,594.882,-182.03577,463.98038,600.39233,-126.087814,535.0108,604.1467,-163.85402,470.5374,606.6262,-106.34467,535.057,651.99567,-318.73587,461.7658,653.92444,-247.90967\nframe__4e8N8lz6lio__0003708.jpg,squats_down,1334.1996,597.2565,-43.827114,1329.3942,576.49255,-21.148804,1326.104,575.11816,-21.129618,1322.9314,573.7969,-21.246187,1332.3098,576.61005,-76.61685,1330.9991,574.97144,-76.46584,1329.7781,573.5767,-76.38647,1299.4976,568.34845,72.01807,1308.4463,567.65106,-178.02417,1318.258,607.3364,-7.9368668,1321.083,606.9088,-78.68474,1236.8445,626.94543,205.91196,1273.1533,626.38696,-332.3426,1356.6611,691.29565,217.22923,1381.6337,697.9949,-468.5342,1471.6837,729.39374,28.829258,1484.6892,719.932,-427.02502,1499.571,727.4214,27.261696,1514.9321,719.7984,-490.45874,1497.3676,722.90875,-27.096403,1509.3021,708.3641,-453.36047,1489.2931,728.06525,0.5649997,1496.738,710.6079,-411.86053,1113.6655,814.69586,164.57141,1125.9277,825.3506,-164.33165,1241.979,717.0878,366.00473,1280.6737,720.0008,-198.77042,1207.4541,859.52936,638.7261,1221.8892,884.4169,23.305841,1195.5496,878.1122,668.74347,1201.7783,909.46954,43.720028,1241.6584,905.0763,776.0652,1262.447,917.8209,102.23629\r\nframe__R6Bbis0z-o4__0005000.jpg,squats_down,873.02325,520.7624,-446.05682,881.232,505.37775,-456.63605,886.0947,503.9134,-456.62006,891.2487,502.4242,-456.55585,872.6206,509.43427,-421.77124,870.6513,510.41916,-421.67255,868.5858,511.53708,-421.65015,916.12726,503.80853,-420.63892,885.13434,515.2394,-251.54535,890.8909,532.044,-429.06854,880.6644,537.1394,-379.2031,995.5277,571.3817,-387.8557,888.9486,562.09357,-121.774734,992.92523,674.607,-523.2693,862.73596,649.7282,-235.16669,889.9838,627.6518,-650.9361,837.38,624.4646,-585.5102,856.7009,626.96204,-690.01,827.7635,621.3715,-641.6206,859.87195,598.47845,-681.5714,833.0087,606.0825,-657.3498,870.9409,602.9184,-642.6466,842.53546,610.432,-600.53455,967.96454,717.7386,-79.33633,902.53876,710.77484,79.732544,1015.8587,742.45905,-523.69275,888.3843,731.3495,78.28158,1038.1641,872.9645,-465.6412,936.9054,790.2436,427.40665,1042.784,901.08655,-461.0257,952.06305,804.6721,463.03592,1025.8986,903.5315,-638.891,924.16473,814.61127,364.9761\r\nframe__dxA21IeBB8o__0001291.jpg,squats_down,1808.3934,1120.7311,-2057.0894,1830.7594,1081.8647,-1997.0555,1844.6312,1082.672,-1997.2585,1858.474,1083.2361,-1996.785,1790.3583,1078.3644,-2001.28,1775.9519,1076.1223,-2000.8175,1761.4073,1074.0375,-2000.579,1873.3438,1087.0198,-1559.6458,1739.6643,1074.8611,-1573.3698,1826.6699,1152.9196,-1888.3254,1780.2708,1148.3053,-1891.7952,1957.2986,1223.8628,-1251.8137,1628.1053,1212.4268,-1278.0079,1968.0673,1488.5378,-1866.6641,1616.3678,1479.445,-1838.9695,1850.1609,1301.8229,-2422.6707,1756.628,1306.4999,-2297.1245,1829.2457,1232.5348,-2562.7922,1788.5458,1239.8572,-2411.756,1840.0804,1200.9209,-2436.8425,1772.7188,1210.5336,-2318.341,1830.4857,1224.5911,-2379.6345,1780.235,1234.7815,-2265.2463,1892.029,1495.7562,11.76943,1697.0132,1491.7699,-11.303694,2098.211,1524.7804,-1121.8102,1527.1685,1525.3956,-1161.7074,2090.9805,1805.0243,-278.24564,1480.2933,1804.2084,-318.65585,2066.4185,1857.9185,-217.30112,1498.1923,1860.9731,-263.9747,2150.541,1902.2018,-658.64746,1400.0043,1893.8359,-736.75\r\nScreenshot_2021-02-11_at_15.47.07.png,squats_down,1239.8582,637.4296,-1338.5043,1252.1573,611.51074,-1292.7896,1261.7687,610.8391,-1292.6888,1271.3193,609.9992,-1292.4857,1223.2429,614.26874,-1297.6354,1213.1115,614.95233,-1297.2744,1202.9396,615.8611,-1297.369,1280.2653,616.4197,-994.4226,1187.2023,624.0611,-1012.20734,1255.5319,661.5787,-1224.3759,1222.7494,663.4551,-1229.7567,1346.5771,714.7051,-779.60767,1118.2108,740.7695,-829.82,1407.6112,870.45166,-1271.3291,1086.3308,896.5119,-1358.4352,1294.4417,783.7126,-1823.9824,1200.8563,786.4627,-1835.2365,1258.7898,763.38684,-1914.4198,1221.6525,753.2563,-1924.8467,1263.6569,731.29285,-1841.5891,1227.2161,736.60565,-1837.657,1267.0391,745.6803,-1799.1729,1230.979,752.12665,-1803.392,1309.8888,892.3249,-0.8059434,1177.9979,907.0103,0.7706969,1389.5565,973.8944,-842.2989,1096.9493,1002.14954,-848.6132,1371.4312,1199.2964,-455.93848,1092.6914,1206.1554,-437.56888,1355.3966,1236.2338,-435.6572,1105.2102,1240.9359,-417.8185,1403.8441,1275.7358,-771.06006,1060.9878,1279.3132,-756.5516\nScreenshot_2021-02-11 at 14.42.01.png,squats_down,475.03043,244.11755,-430.4767,482.32745,231.77994,-410.79333,487.64865,231.83902,-410.66504,492.95468,231.83333,-410.47043,468.13812,231.36963,-410.92838,462.8792,230.9124,-410.8179,457.591,230.55804,-410.62387,499.2766,236.96376,-275.47983,450.91095,235.50745,-271.71613,484.16864,255.27051,-380.04803,465.1839,254.59227,-378.55408,521.15247,283.1476,-176.95914,421.47583,285.57782,-189.20439,520.6509,359.6805,-356.55975,425.00156,368.9007,-380.77075,523.9158,294.49323,-594.5641,434.8983,304.8449,-615.8056,526.8332,274.28177,-645.4522,434.13077,283.90784,-661.11816,530.92847,264.75708,-628.2388,430.45316,273.8983,-637.58795,525.6997,271.61307,-594.143,435.05786,281.6354,-612.08545,495.90482,379.50504,6.6395082,438.61804,383.70038,-6.3378115,523.0494,404.03317,-403.46252,435.38977,426.98892,-361.49646,517.2859,512.9815,-177.87894,432.5991,525.2906,-146.82396,511.70572,519.86566,-160.6008,435.8191,533.07745,-132.09816,514.7438,578.36523,-308.08762,430.86,585.22015,-270.08426\nframe__8ghtQpeWov8__0014360.jpg,squats_down,1165.2162,575.99786,-84.055435,1168.7113,557.5744,-60.407074,1166.8846,554.9232,-60.228195,1165.235,552.48584,-60.24122,1167.9094,561.5214,-112.10029,1165.8309,561.19354,-112.04128,1163.6216,561.2056,-112.20929,1145.4648,555.1477,31.484549,1142.7036,563.94604,-202.85112,1147.9595,589.80554,-47.355164,1146.6339,593.22864,-114.03752,1072.2517,603.5532,212.2573,1084.4188,630.74884,-369.73126,1222.3951,633.7856,276.65097,1232.7147,661.05994,-574.93427,1323.052,600.2162,74.97082,1358.6392,613.20245,-545.4284,1345.6572,577.61005,81.12425,1398.3257,598.947,-607.5902,1345.8132,572.10114,20.57316,1380.4656,577.7437,-575.77423,1339.5763,588.9489,42.206615,1362.6405,581.99426,-531.53253,852.77185,772.30426,194.9143,850.5247,790.73663,-194.3318,1070.6006,766.921,317.1814,1077.2096,755.72437,-236.93677,955.0558,892.0233,626.7751,948.0571,899.8996,92.60584,927.861,910.00476,658.6083,914.5365,917.4871,125.031364,968.2584,927.1799,724.1157,971.9531,941.8207,164.32198\r\nframe__NTng60w9N7w__0001999.jpg,squats_down,832.95044,510.34985,-658.67645,840.4175,488.6741,-666.81995,846.7012,486.3586,-666.7321,852.97437,484.01462,-666.7561,826.6078,492.3442,-630.9161,822.3975,492.6548,-630.55396,818.26086,493.20422,-630.2283,872.6629,476.16153,-595.2278,828.2643,487.79074,-432.09552,852.0437,515.815,-623.98785,834.8084,519.46655,-576.57764,946.9878,510.59012,-515.6764,813.02155,523.4012,-284.41364,954.38904,633.55255,-694.81506,753.03906,629.12067,-569.47375,848.9993,537.83966,-839.31494,768.06665,517.06903,-915.7377,818.2875,519.6268,-878.2523,768.131,488.72256,-956.96173,834.5761,492.72412,-868.7632,781.3322,473.65286,-903.5462,846.4191,498.10468,-831.916,788.1932,485.91983,-901.35876,1000.5967,655.12714,-85.02514,920.9355,656.77045,85.394,989.1839,695.59283,-661.9648,786.6933,681.3213,-134.841,1019.2324,850.4759,-387.16647,798.0661,809.7276,92.39041,1030.0088,875.6548,-371.57843,818.09534,835.0469,108.18826,985.9455,903.6734,-597.9139,725.3107,855.21454,-17.897259\r\nScreenshot_2021-02-11_at_15.58.03.png,squats_down,1361.8796,473.46875,-375.3339,1374.3231,449.1617,-316.57147,1384.7694,447.88248,-315.8559,1395.2555,446.59903,-316.48212,1343.2909,454.77365,-321.02866,1332.3907,456.9141,-320.71573,1321.4606,459.39166,-320.9038,1413.8383,465.97818,-52.604584,1312.8568,482.50134,-68.22486,1388.4462,502.9603,-285.10876,1347.7815,509.44077,-289.4545,1469.4465,597.1859,-124.44368,1277.1418,610.84955,-83.898705,1492.9001,685.8279,-680.08295,1214.4733,656.8016,-648.2171,1500.4856,621.3787,-1145.1521,1181.1908,573.1774,-1208.1428,1532.693,596.63464,-1253.0737,1151.5731,552.6132,-1305.4116,1506.4418,597.9284,-1212.7742,1165.504,542.0255,-1307.7223,1487.1431,609.88074,-1151.3972,1184.9539,554.7157,-1223.4286,1445.2098,895.24115,-2.114866,1323.9225,894.17664,1.8795991,1521.5023,856.61896,-759.0601,1220.2384,894.44965,-707.3673,1476.7522,1081.0104,-361.7964,1262.4078,1081.2269,-322.59644,1458.3262,1113.5126,-336.27628,1287.2488,1097.767,-297.22537,1507.9303,1170.949,-593.83795,1226.054,1187.5011,-557.104\nframe__mGvzVjuY8SY__0009296.jpg,squats_down,955.8465,545.56274,-800.1119,968.5429,522.5263,-774.9392,976.169,522.3722,-774.96515,983.84503,522.0894,-774.87384,946.42914,521.8105,-774.6644,938.778,520.8642,-774.51196,931.0831,519.99286,-774.5332,993.9871,522.40967,-572.9846,921.423,519.1448,-569.27075,967.83093,561.78973,-721.1936,942.4504,560.4563,-719.7147,1045.211,603.1679,-419.7964,868.12573,601.1622,-415.3198,1058.4955,756.44403,-681.1902,847.49835,750.4445,-674.351,988.20374,667.3198,-1005.7458,915.4862,665.76056,-983.4422,966.6526,639.0297,-1075.1357,934.042,637.50037,-1048.3329,976.28265,613.6004,-1018.9738,926.54395,617.06726,-998.1188,975.84827,624.69006,-987.067,931.017,628.90326,-967.27124,1009.76245,780.3525,-5.308931,907.39703,779.73804,5.7851634,1096.817,831.1055,-614.8232,824.0613,821.05457,-595.51697,1100.057,994.91113,-237.86589,809.1381,983.99524,-219.14003,1091.9221,1021.57404,-211.6201,819.2072,1010.52795,-195.47298,1117.1611,1049.3569,-460.19162,777.3884,1040.3717,-443.5574\r\nframe__exXWoE0ZUME__0003930.jpg,squats_down,977.95465,441.25784,-948.1458,988.5711,423.73822,-915.9898,995.1632,423.54172,-916.10034,1001.8658,423.1841,-916.13525,968.9494,424.2553,-918.5033,962.16956,424.32697,-918.3597,955.3719,424.5095,-918.4895,1011.9183,430.05463,-692.22046,947.8194,431.22546,-710.784,989.7094,460.29425,-862.54297,966.7576,460.16013,-867.5428,1064.5006,521.71765,-473.54077,894.7229,522.96277,-504.8235,1095.5901,643.32825,-596.8056,856.867,652.14844,-634.98035,1043.9137,630.21277,-973.1118,938.37854,647.59296,-988.145,1030.045,629.2856,-1066.5627,970.624,651.9501,-1069.2384,1022.1681,606.3078,-1057.208,969.5183,622.99854,-1065.5914,1021.5942,605.63464,-978.32654,964.3095,622.6896,-988.2207,1022.4163,654.50134,8.432075,926.20544,654.2888,-8.219311,1057.9332,758.73083,-576.26776,902.2543,748.2028,-610.7368,1063.0354,965.28546,-386.3759,885.2733,951.90137,-376.6256,1051.8813,1000.38544,-382.3949,889.62714,984.5473,-368.61642,1087.7722,1012.338,-656.0539,870.68,1006.3096,-642.60266\r\nframe__Rs9IdyUQwlY__0002144.jpg,squats_down,1047.9293,613.077,-70.31682,1047.8047,587.18713,-49.43847,1044.6791,585.14325,-49.37758,1041.774,583.1566,-49.31908,1049.0531,588.2857,-118.315445,1046.4152,585.9706,-118.41205,1043.7867,583.9851,-118.368996,1016.64984,575.2948,61.24247,1019.1755,575.9182,-258.2099,1028.6082,624.83075,-25.797369,1029.6122,624.866,-116.67589,956.9947,645.00964,259.41074,954.36145,640.0103,-459.8372,1096.5128,679.3659,329.15292,1085.8674,701.2943,-692.8467,1213.757,668.6556,80.81321,1218.271,677.55383,-660.9371,1236.1726,653.9552,70.19894,1255.995,662.0404,-755.2601,1238.0493,641.0194,-10.240944,1245.664,639.9768,-710.07,1233.672,652.4064,39.037846,1231.7983,648.84924,-645.113,826.34644,878.9208,230.66838,816.6389,888.2764,-229.76526,1026.9044,784.7637,486.84705,1028.2513,793.0945,-319.4181,967.5056,948.98975,809.59766,945.19684,964.9838,43.795773,941.93274,976.23376,839.08405,916.26556,990.75275,79.55443,1016.4161,977.5301,920.60626,982.3909,989.32214,145.07317\r\nScreenshot_2021-02-11 at 15.22.02.png,squats_down,677.6394,293.78833,-175.1901,680.4515,287.5624,-151.63666,683.6814,287.18954,-151.57732,686.98584,286.7911,-151.68266,670.26526,289.69217,-155.08661,666.51276,290.62497,-154.99037,662.75586,291.6912,-154.9034,691.19763,295.64398,-37.9349,657.34564,302.1234,-54.88473,684.9677,305.47742,-135.53168,671.99457,307.93448,-140.28078,712.9866,344.28732,-52.06885,640.3153,347.90167,-65.60773,732.39636,361.9184,-286.8664,611.5165,357.80392,-319.54916,747.026,331.47104,-481.85086,623.7918,335.83478,-542.03687,761.82385,319.77615,-525.39575,620.06995,332.27615,-580.11456,754.3907,322.53845,-515.98553,627.58246,331.74615,-571.59143,747.0128,329.0391,-487.01614,630.55005,336.6477,-543.73047,701.9833,471.23508,8.708115,651.8561,471.20288,-8.749758,761.2408,498.4505,-282.6257,597.2617,498.30835,-316.475,741.7681,572.09546,-73.47037,615.72327,570.19226,-94.76776,728.2718,584.1139,-58.325275,629.0028,581.0827,-76.069435,769.1478,603.5047,-152.13445,588.7306,605.51874,-163.38887\nframe__7lVFsE7WJSE__0011255.jpg,squats_down,1063.8981,524.8302,-1158.4465,1076.8058,496.52905,-1145.3992,1084.5956,495.96652,-1145.3969,1092.4681,495.29834,-1145.3928,1054.0664,495.21576,-1151.0734,1045.9357,493.4244,-1150.8317,1037.7219,491.69846,-1150.6487,1102.7765,491.38568,-925.9916,1024.9641,484.83258,-943.6374,1074.0289,538.214,-1067.0809,1048.6902,537.0962,-1070.0857,1154.5193,557.5417,-675.03046,963.7017,540.61145,-733.9864,1167.5245,709.0256,-938.9655,935.7416,703.9463,-949.71423,1107.9387,669.55786,-1372.663,1030.783,674.85034,-1274.4403,1096.6375,660.43884,-1468.84,1059.6113,667.7311,-1362.004,1092.9669,632.9273,-1443.3169,1059.7506,638.0926,-1337.1616,1088.1819,636.4285,-1370.8799,1058.754,642.6641,-1271.1963,1097.3008,692.5787,2.4903145,994.40686,687.71405,-2.4187796,1228.3496,688.7838,-529.57495,869.8204,687.8836,-589.5665,1177.3593,819.3236,-45.260654,886.92975,832.0546,-94.521576,1148.2585,844.94293,-6.555493,902.13055,864.13696,-55.780502,1226.1232,886.09686,-205.11154,831.64355,892.8167,-254.28337\r\nScreenshot_2021-02-11_at_16.31.06.png,squats_down,1390.3772,671.35657,-895.9186,1400.8329,647.2697,-864.6072,1408.9376,646.34155,-864.5169,1417.0126,645.2884,-864.43726,1377.2803,648.69165,-861.5311,1369.0607,648.4637,-861.3214,1360.8059,648.40735,-861.27277,1427.4713,644.99396,-634.16876,1350.6489,649.5179,-624.4129,1405.3171,687.4121,-806.774,1377.8754,688.1914,-803.502,1488.2644,729.109,-464.96805,1294.2446,732.82355,-466.48242,1545.3773,870.45996,-828.7957,1250.7346,862.31226,-841.3929,1457.2972,803.1721,-1201.8612,1336.035,778.66583,-1225.161,1429.5817,781.4234,-1270.1387,1357.8479,752.95514,-1293.6895,1431.1947,755.73615,-1202.8896,1358.0951,736.22485,-1224.9824,1432.7826,767.4592,-1178.1736,1359.7191,749.8959,-1200.5297,1451.5411,920.0272,-2.505481,1336.6876,924.0752,2.8723576,1533.7013,1014.80023,-618.95874,1252.3799,1028.7505,-601.54877,1528.853,1190.3215,-236.00067,1251.2021,1183.1641,-219.17429,1515.3989,1216.2551,-210.45436,1260.6388,1208.7219,-196.05238,1556.0361,1259.5513,-475.73303,1229.3196,1240.3088,-461.20828\nframe__GauW8uJtvFs__0016681.jpg,squats_down,925.3057,417.7319,-297.1941,937.74493,399.82974,-336.82266,941.5742,399.42285,-336.80792,945.39496,398.95505,-336.85315,938.2583,399.52487,-267.10785,941.8874,399.84705,-267.2637,945.8457,400.34775,-267.18625,974.5252,404.82745,-436.6172,976.44965,405.551,-120.80362,942.2099,436.10602,-331.30655,942.66565,436.01324,-239.74837,1037.8212,492.70258,-530.2368,1013.578,485.18933,65.79198,917.44525,573.8021,-659.12317,895.4147,560.8279,107.171715,767.37067,594.17224,-674.4059,761.8449,590.16754,-43.84883,725.0948,588.42554,-788.33264,727.9891,574.34607,-37.2323,725.4823,569.12646,-750.2675,723.9012,579.38416,-126.53085,739.7358,576.0348,-668.92725,737.04846,588.2788,-89.26603,1253.5228,617.0422,-206.54134,1219.0432,601.2879,207.35721,1103.5675,753.60614,-244.2745,1058.2186,723.6397,262.55682,1138.4915,956.0364,-68.976036,1107.0338,909.8418,451.975,1164.5565,1001.2839,-67.04513,1130.4056,946.8393,467.61337,1029.5022,988.95215,-234.17776,1024.4777,947.15186,395.3826\r\nframe__BiYyOx9x7ls__0009707.jpg,squats_down,1090.9182,379.21082,-49.395603,1106.4891,363.23123,-91.08761,1109.017,365.8747,-90.878624,1111.6188,368.46936,-90.58792,1108.1139,356.5373,-30.176594,1111.35,354.04782,-30.025188,1114.8052,351.6282,-30.107876,1137.6989,385.6913,-196.81224,1142.5084,364.54984,82.85542,1102.4479,409.13507,-93.152695,1101.3193,400.81845,-12.48727,1199.8251,514.77386,-342.79083,1177.2338,521.3558,287.59027,1110.5502,718.04816,-100.092514,1176.4198,698.5208,206.72585,1065.5098,610.5844,260.16522,1100.277,612.9954,-139.5046,1041.4224,588.12396,248.3016,1075.3525,579.9594,-181.67583,1077.4752,579.8055,205.3115,1075.8163,571.30475,-165.57256,1092.7562,590.33276,255.67886,1089.37,581.0223,-150.75046,1355.8333,779.575,-195.28886,1317.0363,764.46124,197.09099,1137.7917,636.86774,-329.50256,1096.8163,633.54895,345.67352,1250.7645,878.58984,-189.84389,1216.0764,838.3703,384.68152,1306.782,910.951,-170.95096,1261.6426,854.66364,386.88815,1164.3865,942.6926,-142.10417,1171.896,928.8834,412.6202\r\nframe__NsCiNjVEzTM__0019290.jpg,squats_down,1026.4064,507.03534,300.58057,1021.69775,490.97748,298.7839,1017.01746,491.43607,298.92456,1012.53076,491.88544,298.93042,1029.2699,490.54294,251.64073,1028.4718,490.37057,252.02199,1027.5115,490.63763,251.92023,991.50146,501.03464,316.76096,1008.45667,498.1461,85.14247,1010.6301,525.7309,313.20398,1017.9648,526.45703,247.5842,916.1089,561.52625,455.59943,994.6829,590.3575,-47.349472,1037.5725,617.1048,734.0151,1174.0366,666.3923,76.056366,1060.7156,561.58966,1026.631,1084.9689,557.6207,598.0869,1080.4738,538.09644,1077.318,1067.0308,527.4044,616.0575,1061.3492,544.41534,1085.4413,1056.7202,538.6822,599.3544,1050.3364,559.09894,1039.0847,1057.828,558.5594,605.95905,755.25757,810.97845,195.72989,811.2415,817.2212,-194.8904,934.6342,749.3619,579.531,1057.2803,734.21466,-215.70789,862.70886,919.1393,627.7637,966.618,971.6355,-227.71242,832.4199,941.0996,641.91797,925.2965,1019.1417,-233.04498,924.44855,964.4456,755.3492,1063.6985,1016.977,-152.50026\r\nframe__H21pTB9nJ7I__0007372.jpg,squats_down,844.8275,517.2237,-237.34901,852.8302,494.63654,-218.15842,853.3603,493.67117,-218.09064,854.1767,492.75574,-218.09465,848.3409,493.2735,-266.31897,845.17725,490.15707,-266.31717,841.97565,487.34326,-266.36026,837.0052,478.50995,-62.396706,819.94995,472.3553,-287.21106,829.3336,521.3951,-175.04343,823.08154,518.6011,-239.14049,804.0531,533.5333,102.12878,733.34766,493.8316,-412.4362,903.84094,600.89734,123.22699,833.2947,587.0702,-617.90674,998.3092,628.1594,-61.41981,959.95734,616.5553,-677.4262,1024.1027,640.4256,-91.25753,986.1384,630.5569,-769.8611,1021.0419,623.6296,-143.32321,996.0576,617.0358,-753.5844,1009.15845,623.6163,-95.08026,982.4146,614.23895,-674.8036,656.9304,714.9252,166.61462,596.679,713.6772,-166.33234,838.10486,694.64746,220.63615,805.0051,734.6616,-521.02466,778.5881,862.89166,372.10767,711.98535,897.0764,-288.87018,742.46436,890.0338,385.8656,670.1924,911.91516,-264.07565,834.2017,923.6552,343.86624,768.84,966.8105,-334.78848\r\nframe__X2uZY0XRYKI__0005823.jpg,squats_down,594.2059,420.031,-1.4734313,594.41504,409.687,-29.746552,595.57446,409.6621,-29.763233,596.80457,409.56915,-29.744091,595.0134,406.77707,9.136512,596.5595,404.75198,9.239777,598.3082,402.7684,9.194794,611.4112,406.67487,-107.89563,613.05566,398.76483,66.97394,605.65546,428.43127,-29.049929,606.1211,424.9782,21.622355,656.8208,443.28903,-192.50526,660.06067,434.45236,186.31514,636.8979,513.8749,-161.90855,646.19806,493.63516,341.45813,596.49396,466.98077,19.393734,597.7097,464.5756,436.02222,580.7903,456.92804,10.647699,583.69934,454.2198,462.17178,592.20135,443.59644,1.9653192,584.95776,448.70258,459.84082,600.7472,447.84857,21.126461,589.721,453.36575,433.54312,785.39856,517.9563,-120.063644,778.1881,509.8182,120.38949,674.53485,536.7905,-183.71559,666.4963,537.91187,229.15831,720.4986,643.8923,-101.9657,710.3113,629.51434,350.8389,739.8987,661.869,-94.82823,725.4292,642.4488,361.6159,686.3169,671.64014,-108.94127,690.61096,662.8251,363.0891\r\nScreenshot_2021-02-11 at 14.48.00.png,squats_down,462.59427,258.16278,-558.85736,469.23224,245.92328,-542.54663,473.53558,245.89436,-542.5994,477.8836,245.7049,-542.4657,456.55057,245.4758,-542.9129,452.01236,245.01662,-542.74713,447.46332,244.66,-542.7884,483.62152,247.88023,-422.42032,440.37,246.17876,-423.59543,469.5617,267.96844,-511.378,453.8932,267.40662,-511.47888,511.85828,289.35403,-334.66977,406.0349,286.29666,-326.17157,539.49567,359.23022,-341.10245,364.78577,351.81876,-356.9221,547.9143,436.79132,-402.51993,349.23865,425.42258,-420.26352,557.9042,456.80695,-442.56192,336.9989,443.2886,-458.18335,545.542,457.50198,-466.80783,349.88278,446.11945,-486.65195,537.6084,451.3879,-415.2423,358.06195,441.58713,-434.39154,485.89563,378.85065,-6.459825,429.2597,378.18704,6.546063,528.2037,407.55722,-390.495,388.94986,399.0551,-377.1215,513.6115,467.29208,-61.47987,402.70102,472.3024,-58.83315,503.55038,474.53723,-34.247204,413.86624,484.04993,-33.792965,529.05835,505.8774,-144.75792,382.05347,507.966,-164.11124\nScreenshot_2021-02-11_at_16.24.45.png,squats_down,1323.414,639.54535,-61.819195,1337.9736,623.1841,-12.60709,1347.7759,623.819,-12.419044,1357.6631,624.3243,-12.495009,1310.101,624.05115,-7.522454,1300.5195,624.3781,-7.0480437,1290.9095,625.03,-6.8666253,1373.5482,642.61584,215.85991,1278.5748,642.90076,242.5808,1341.736,669.70056,15.594617,1306.7856,669.736,23.467636,1428.8414,754.3564,84.44834,1219.0933,753.32404,166.79828,1434.8873,798.0356,-591.6892,1191.4333,800.7965,-475.67438,1358.6182,757.6171,-1050.0605,1255.1506,750.03094,-961.2382,1338.3022,753.1671,-1149.1902,1268.4945,743.3132,-1048.6392,1329.3658,738.11816,-1106.6343,1282.6223,730.6659,-1017.1962,1331.8695,749.76086,-1044.6893,1283.979,742.3541,-959.09155,1386.9761,1069.1688,-10.95197,1248.8544,1067.1238,12.112725,1522.7196,961.0403,-701.0394,1110.5531,951.89185,-707.20026,1502.3716,1210.4767,-722.549,1151.7914,1191.7278,-632.569,1486.3522,1250.6158,-734.9618,1181.6143,1241.5624,-634.99164,1512.5773,1285.6216,-1004.4804,1094.8079,1253.8439,-851.37427\nScreenshot_2021-02-11_at_16.20.32.png,squats_down,1326.004,720.7076,-257.7466,1334.277,702.7931,-226.31635,1341.0077,702.47955,-226.1845,1347.887,702.0381,-226.32306,1313.554,704.2789,-232.43002,1305.6716,704.6024,-232.33485,1297.8013,705.15375,-232.25986,1355.6296,712.6689,-22.947746,1284.0515,716.40704,-48.48539,1337.5474,740.29565,-181.50955,1311.3408,741.25574,-189.1567,1400.6409,782.44745,25.956701,1239.4451,784.42725,4.374214,1481.0945,836.58826,-332.6543,1175.1682,846.22504,-302.34845,1454.4739,818.26794,-697.9868,1193.8142,829.543,-680.6839,1456.9705,822.64685,-767.158,1189.9352,836.40094,-740.0799,1436.7052,811.76025,-747.20844,1213.2896,823.3935,-735.49304,1432.5559,819.2055,-701.71265,1219.0088,828.21106,-682.3171,1374.8335,992.8688,7.3050275,1281.0475,992.4554,-6.9182777,1465.1006,965.1206,-491.30484,1190.7297,940.5186,-549.3194,1432.4443,1132.2703,-212.53334,1226.893,1109.6033,-236.6445,1407.4716,1163.8746,-192.87762,1258.358,1148.9368,-207.93143,1482.0178,1197.2101,-376.15588,1137.7875,1161.1803,-370.01852\nframe__8ghtQpeWov8__0012026.jpg,squats_down,974.1487,438.54498,-812.6236,981.22156,417.13757,-775.80115,988.54456,416.0168,-775.7986,995.8586,414.76096,-775.69586,959.2406,419.60187,-779.641,951.17163,420.1136,-779.47107,943.13464,420.7332,-779.4001,1004.50916,418.3278,-547.44916,931.3645,426.83667,-567.24115,987.9873,454.68613,-726.9176,961.5661,457.57312,-732.44946,1056.6924,507.2219,-367.1957,882.6733,500.29382,-419.4769,1106.3094,640.6308,-614.25793,859.09247,622.6363,-679.17505,1028.1431,588.7692,-940.15106,956.8807,574.7375,-970.5716,1007.97534,570.67914,-1002.7193,984.9851,564.7529,-1023.1185,1007.04895,552.11176,-948.2329,983.9379,546.6196,-987.73535,1007.80347,558.4781,-923.72205,980.4435,551.95886,-955.9262,1008.60376,671.00946,13.482793,904.56714,669.2056,-13.202712,1110.4323,727.22186,-523.4322,834.3117,758.5792,-558.3568,1113.1211,885.8059,-161.87982,837.3272,912.61743,-182.28418,1098.8248,913.9784,-136.59956,847.1439,937.4216,-157.53368,1159.4014,932.8991,-358.80774,807.3866,966.6596,-411.77365\r\nScreenshot_2021-02-11_at_15.39.15.png,squats_down,1330.6171,571.3591,-532.7838,1345.6616,545.46063,-482.55267,1356.5096,545.1071,-482.6912,1367.4441,544.5784,-482.6382,1316.2051,546.7411,-482.8958,1305.3677,546.8543,-482.81577,1294.5001,547.2083,-482.50204,1382.4486,557.81573,-236.61464,1282.0754,560.42175,-236.88986,1350.5356,598.4753,-445.2737,1312.2357,599.2761,-445.4969,1435.9436,672.1329,-121.43693,1219.5735,672.11383,-156.94113,1533.5443,818.3388,-458.46396,1119.3658,843.7776,-553.3193,1412.4062,701.7002,-589.68054,1242.6963,719.49866,-801.6908,1389.5673,657.2041,-612.95483,1272.5745,684.578,-832.2352,1377.9624,645.10364,-498.4808,1280.9469,658.3203,-730.3085,1376.5538,667.9142,-542.68036,1281.9132,680.4965,-756.4357,1391.0558,914.21594,22.694078,1259.7343,916.16956,-22.196762,1523.3691,895.026,-858.65405,1161.7441,922.7335,-908.76086,1467.088,1101.279,-281.59488,1197.6045,1105.7003,-344.7169,1437.6332,1134.8868,-235.76541,1219.0706,1133.6321,-300.58286,1526.2491,1180.899,-494.77618,1167.1337,1182.2294,-591.48804\nScreenshot_2021-02-11 at 15.30.02.png,squats_down,155.14902,272.76022,-245.82588,163.14967,262.0225,-223.39528,168.73596,261.57013,-223.29205,174.37973,261.0381,-223.35475,148.73569,264.85654,-217.45793,143.7154,266.02313,-217.41963,138.679,267.36032,-217.49228,186.50917,272.01196,-126.571526,138.59236,279.79135,-96.87954,169.27386,289.3856,-212.5297,150.70753,292.12335,-203.90613,233.21481,345.46777,-121.96551,114.92998,351.52054,-68.1487,214.35672,434.90338,-246.63872,50.727516,420.01553,-238.97609,160.13104,334.42398,-299.20132,106.93473,320.83566,-376.35278,148.5796,309.036,-315.23813,114.49813,295.75372,-400.3826,156.16743,298.32693,-291.8688,127.3991,285.53116,-352.65768,159.5538,309.08478,-291.4433,129.41008,298.58685,-361.3169,231.09833,490.05362,-14.409351,159.98944,498.12692,14.476683,285.5375,466.16772,-358.97275,75.83336,478.97263,-238.52124,294.8958,609.2528,-207.39427,93.180176,601.8298,-82.73266,288.86313,632.74884,-195.22334,111.23908,624.21765,-69.85453,316.13596,663.78076,-317.62634,49.583393,652.03845,-152.40443\nScreenshot_2021-02-11 at 15.48.48.png,squats_down,616.37274,400.30075,-487.74332,622.71967,387.7055,-474.9773,627.95557,387.5279,-474.94473,633.3231,387.3298,-474.84177,608.05286,388.1278,-476.03784,602.8003,388.1624,-475.92725,597.45953,388.2221,-475.89157,640.4351,393.4578,-368.91962,590.1625,392.91614,-365.39413,625.5827,413.46106,-446.02774,607.44763,414.11377,-444.26425,669.5308,438.26257,-262.9252,563.4353,440.70355,-302.735,722.1781,515.0878,-434.41068,532.6368,522.615,-448.9345,649.1552,481.8863,-635.6092,596.30664,487.96588,-604.0947,631.1094,477.25836,-669.9212,615.6574,481.09564,-639.0186,627.19104,462.42758,-645.4211,613.57135,463.6534,-625.1522,629.7745,470.2866,-628.01227,609.96173,469.3808,-601.2267,608.5237,534.67615,18.849226,550.5735,534.8245,-18.729822,701.3104,541.72577,-222.69066,553.52734,539.1254,-443.2975,692.6399,642.8988,-56.356197,539.45636,649.3413,-217.98131,677.4507,664.629,-47.332,541.50806,668.3329,-201.52075,726.84357,677.37616,-142.18912,522.0311,683.04645,-329.7367\nframe__awBQVJ39sKM__0001470.jpg,squats_down,1876.044,1086.8092,-1989.9949,1891.2302,1048.2725,-1931.583,1903.9103,1046.0978,-1931.6588,1916.801,1043.6992,-1931.0499,1854.2933,1053.2487,-1928.2823,1840.441,1054.6095,-1928.0354,1826.697,1056.1621,-1927.8835,1933.1697,1056.1985,-1534.877,1810.5952,1072.4669,-1512.3572,1900.3815,1115.8724,-1838.9011,1852.0308,1121.2318,-1833.1013,2004.0404,1206.2362,-1280.6381,1752.5269,1217.4984,-1222.2133,1953.1357,1463.68,-1402.3463,1828.8333,1477.3867,-1376.302,1811.3741,1665.3805,-1582.2916,1922.8721,1717.6356,-1601.2255,1803.5359,1735.2435,-1713.4547,1927.2917,1799.4626,-1729.655,1752.2444,1733.2837,-1741.3115,1963.9529,1793.6324,-1774.1389,1753.1697,1705.0785,-1596.2251,1964.2864,1760.1709,-1624.8569,1961.291,1461.3196,-25.078856,1806.347,1467.3033,25.47482,2136.9287,1633.6257,-1136.8545,1613.024,1636.4011,-1031.3428,2142.8167,1872.8851,-290.20926,1580.2671,1870.7386,-171.3712,2121.1687,1900.7988,-218.05154,1601.4658,1909.4673,-105.53912,2202.095,2000.9493,-632.4092,1503.9269,1977.241,-572.15674\r\nframe__fH_1skamnFk__0011049.jpg,squats_down,1490.6439,529.4112,79.177795,1484.2457,508.34692,92.52392,1480.3179,507.8421,92.58306,1476.5055,507.39587,92.6942,1487.0757,507.409,35.566216,1484.7633,505.31503,35.690887,1482.4844,503.49567,35.735046,1447.9589,512.30414,165.51308,1456.8375,507.6078,-94.88902,1472.083,549.8251,105.40509,1472.5227,546.42017,31.221445,1373.8479,623.14075,306.6864,1410.0536,619.52423,-268.2527,1422.2064,747.9147,298.05695,1466.4464,774.44916,-181.86598,1511.171,730.01587,16.339231,1511.8767,730.0023,165.94617,1521.9326,717.8948,-5.172564,1521.0492,710.6092,162.79329,1526.0221,705.64886,-33.45927,1507.9706,692.6492,170.2465,1522.7715,712.7022,-2.2950249,1503.3828,699.71246,178.67494,1247.051,861.64,193.00534,1265.1732,858.1197,-192.78677,1449.2057,741.12933,303.37213,1501.7549,691.7745,-231.18314,1353.7281,913.1717,473.96823,1384.5377,938.2295,-71.301216,1322.1177,936.5089,490.56177,1344.4962,970.757,-50.926945,1376.5764,968.5909,528.5564,1409.6604,1016.70685,5.2028837\r\nScreenshot_2021-02-11 at 14.57.35.png,squats_down,490.98444,316.2595,-363.80463,499.32074,305.18445,-344.894,503.78992,305.70312,-344.89066,508.2787,306.13205,-344.7601,486.2715,303.7282,-347.39447,481.764,302.9273,-347.3228,477.25116,302.18542,-347.3784,513.2777,309.02258,-227.08836,470.7931,303.40457,-238.6821,497.09332,327.41885,-319.41583,481.8912,325.13953,-322.93207,536.3748,359.96057,-158.59325,434.35385,349.6333,-163.75334,540.56903,445.9737,-310.85315,429.37277,436.7517,-329.7637,501.44867,384.16647,-468.78625,474.7563,384.14282,-495.0336,490.96973,366.10532,-506.54868,483.5723,365.64587,-529.5424,495.87366,352.39304,-467.9298,480.7577,354.88242,-503.9584,496.26822,359.41922,-456.92313,483.0151,362.2508,-487.649,505.404,456.02173,5.299692,445.84457,454.57227,-5.0634665,582.9295,457.13354,-325.445,396.25095,447.77637,-349.3597,578.26624,562.5587,-167.9355,376.3528,555.2898,-186.22287,567.30817,582.1605,-159.83838,380.92252,574.45953,-178.11192,607.20215,594.62897,-284.2274,349.89758,585.74176,-308.6744\nScreenshot_2021-02-11 at 14.51.02.png,squats_down,176.37714,187.5016,-42.491596,183.6399,181.15813,-19.514025,187.91031,181.87473,-19.451176,192.21465,182.48872,-19.456085,171.69102,180.51309,-20.747272,167.37387,180.38673,-20.763924,163.06012,180.39493,-20.824871,198.33899,192.12338,72.44724,157.9849,189.0913,68.211075,183.79187,202.65816,-11.612133,168.60071,201.34787,-13.017949,228.39917,245.58083,80.27325,124.507576,249.40297,67.402824,265.23364,297.50833,-83.464035,92.75667,305.72345,-105.83998,202.21805,230.18277,-182.13234,143.48433,231.81145,-201.80634,187.87427,212.57712,-201.37042,152.8284,212.42093,-215.8639,184.33598,204.96536,-165.49112,157.99704,205.39902,-183.20747,184.79547,215.23575,-169.99347,159.07922,215.90941,-189.38593,210.06772,372.23813,4.4495053,144.62631,375.57642,-4.3717127,271.40594,359.47052,-279.57272,94.06002,363.49533,-255.2955,261.08942,497.32852,-227.56342,101.6281,496.13986,-201.83435,249.19203,519.4504,-226.38657,112.70084,520.9595,-199.63171,281.8654,535.08527,-343.83426,75.77191,529.2712,-295.5624\nframe__ZwbX1A-LlTs__0010261.jpg,squats_down,1086.991,488.63126,-394.52734,1085.0267,467.9639,-372.2298,1083.7534,466.16003,-372.27295,1082.6195,464.2575,-372.53293,1083.5696,471.94864,-429.71454,1080.7157,471.6914,-429.87985,1077.8429,471.65613,-429.58676,1058.9324,457.28537,-211.11487,1054.0929,466.06662,-478.5288,1069.7898,496.50156,-330.7591,1068.7977,500.49222,-405.02875,1032.6626,532.03925,-28.09909,960.4761,509.21045,-587.08844,1100.0565,598.4197,107.676834,989.8321,645.11127,-882.18677,1185.4923,612.8462,95.710434,1115.8649,641.0623,-1080.431,1204.8024,618.37744,104.43724,1149.2971,650.156,-1162.9282,1200.0083,603.78284,64.17647,1154.957,630.3528,-1152.3761,1189.4332,607.026,79.07712,1142.1251,633.65485,-1077.7784,841.26843,670.70984,175.6105,776.7677,669.85706,-176.55971,1004.30365,666.14777,479.67114,873.62036,730.6619,-727.7375,943.0726,785.3349,795.4467,830.68964,927.8528,-642.5161,900.492,806.0963,833.3862,795.6382,963.61975,-634.0143,1013.0301,842.0031,828.90106,899.5835,992.8526,-796.1312\r\nframe__h9E_JHENdNI__0002052.jpg,squats_down,563.7284,259.43985,-248.98332,573.51306,252.60234,-250.54767,576.90063,253.13779,-250.56319,580.3874,253.5805,-250.48799,567.34766,251.61194,-218.63916,566.20483,251.17604,-218.44952,565.0744,250.85623,-218.3653,595.5484,260.51816,-223.84808,575.80426,256.48764,-78.949104,574.2714,272.62277,-241.59882,566.09064,270.80038,-199.44641,628.2809,308.17657,-281.1831,582.4517,311.5166,12.125722,589.0963,376.36972,-342.90308,548.1619,375.07928,-181.9563,555.18744,317.24496,-250.93825,543.6817,319.54123,-460.09128,541.9059,302.26685,-251.29926,531.26514,302.98285,-489.82092,561.8287,296.60638,-247.00854,543.4644,297.17072,-454.63315,568.8311,303.39767,-240.41574,552.3328,303.176,-454.1719,686.3956,412.17773,-82.62341,650.1971,416.59018,83.03405,671.0753,465.26242,-437.26556,601.1516,484.2709,29.396322,689.0931,551.59125,-299.5404,620.45404,542.8616,249.4474,699.3759,568.05756,-291.9996,635.0788,557.333,267.77557,657.97186,579.8443,-425.04672,572.03577,563.8348,178.72827\r\nframe__iPCJs2jh4Hk__0001964.jpg,squats_down,1089.3254,577.07025,81.34874,1080.7065,563.388,101.48709,1076.082,563.5619,101.468285,1071.5908,563.73,101.65307,1085.6769,562.42816,45.36801,1084.5117,561.1887,45.4296,1083.1659,560.1466,45.28993,1046.973,569.1539,196.521,1063.0905,563.92206,-66.121506,1072.9552,594.3651,115.13812,1078.7769,592.97925,41.297165,980.3318,650.1519,378.37033,1037.5558,657.1761,-221.7198,1066.9918,743.6549,466.5383,1134.0999,759.2622,-82.53133,1103.6907,672.1943,511.8448,1126.0037,660.1176,275.09103,1125.9093,646.3412,545.1814,1135.144,630.6089,252.45229,1108.8995,647.01215,565.95465,1113.5979,630.0517,230.41632,1098.5469,656.4386,517.6623,1104.3926,647.55475,276.8316,843.35175,808.3167,195.11574,865.6859,817.19714,-194.88652,1002.84863,789.5484,441.21826,1063.6765,825.6935,-253.69812,945.0067,934.19116,493.4572,970.4548,982.7044,-256.19815,925.63617,964.69293,500.71082,941.96466,1017.7016,-259.08038,997.08685,956.6492,587.70984,1024.2091,1004.2839,-201.48634\r\nScreenshot_2021-02-11 at 14.40.44.png,squats_down,406.39246,207.91615,-345.40448,414.3551,196.01793,-318.18372,419.7902,195.9661,-318.2178,425.2718,195.76955,-318.13187,398.3083,196.86627,-318.5621,392.77164,197.23082,-318.54443,387.22855,197.71121,-318.46066,433.22888,204.25453,-193.14107,380.97687,206.79373,-195.89142,417.51724,223.1135,-302.203,396.84183,223.99477,-302.49948,468.06955,279.3822,-125.87753,342.93518,274.29834,-129.34428,539.9518,335.26428,-92.317696,269.76245,344.98532,-85.796074,477.76077,398.23557,-25.141766,332.7617,395.81104,10.955142,464.20514,413.6627,-28.317501,353.11176,413.4284,11.659438,449.1357,409.38815,-15.471722,365.6441,401.74268,21.93783,452.99783,405.54254,-15.218464,359.93335,398.2164,20.708431,441.10068,422.77594,6.893874,362.22626,422.55212,-7.0778813,550.14764,451.23373,-247.7336,262.481,464.4998,-266.06543,547.29456,571.3799,-6.8295593,238.67226,572.1611,-53.46837,534.36304,590.2755,14.298043,245.63414,589.36743,-35.152878,588.8609,609.7904,-81.0689,204.32669,606.9667,-152.94078\nframe__QVNlEfFOWwg__0007191.jpg,squats_down,1056.1178,224.18138,-24.78703,1054.712,193.23975,-12.437555,1052.6187,190.87517,-12.202885,1050.8894,188.95609,-12.409791,1049.6882,194.2152,-68.33284,1044.2292,191.44235,-68.142136,1038.563,189.02052,-68.33197,1014.9251,186.8741,84.61275,997.6403,187.21721,-168.20439,1028.4517,248.37462,14.479186,1022.0232,246.87689,-57.566364,886.5723,297.79306,283.33267,903.23065,275.3778,-362.36267,1121.9044,372.8434,449.5483,1154.5867,344.31436,-556.45276,1315.1708,378.789,315.943,1367.977,332.33176,-445.19052,1350.1716,355.02234,320.9533,1426.8617,318.0921,-510.5016,1350.2102,343.5371,260.33838,1416.6584,286.6904,-462.67307,1340.9875,358.8777,286.13623,1394.2568,293.7167,-428.03357,512.036,572.3694,214.52466,506.90237,564.5737,-214.04425,848.21344,626.08215,325.09485,872.4845,665.507,-231.0354,705.2313,845.0359,518.9113,725.0132,884.3383,143.31676,653.2799,869.8322,539.6122,669.91095,898.3929,186.37457,768.0154,921.711,568.765,791.8903,979.8822,249.52435\r\nScreenshot_2021-02-11_at_15.51.55.png,squats_down,1322.8125,553.037,-392.20584,1335.2059,537.3824,-328.75885,1344.8959,537.2856,-328.91608,1354.6904,536.96985,-329.0324,1305.7683,540.6334,-326.7765,1295.7278,542.3935,-326.663,1285.6777,544.40045,-326.71048,1371.5703,559.6745,-83.84457,1275.0555,569.26843,-74.64002,1344.3951,587.612,-313.3461,1309.0853,591.1953,-310.6578,1463.1914,719.0368,-57.116386,1221.8464,729.69885,-43.79653,1527.7963,898.4031,-375.09637,1200.6334,922.56946,-412.16812,1382.6007,778.00946,-611.41016,1318.4756,779.6036,-755.0874,1347.8876,741.3553,-673.8936,1348.7427,738.7171,-806.8799,1345.8176,720.4788,-580.2406,1335.8564,710.01324,-748.82446,1348.1287,738.1582,-578.32544,1337.1316,730.53375,-732.96497,1433.3038,996.4717,7.329498,1284.2479,1000.87244,-6.814107,1569.9792,997.0548,-797.04266,1162.8417,1010.4041,-856.8943,1498.5742,1229.4452,-229.93492,1190.8604,1240.0048,-305.1731,1463.0975,1268.8059,-184.02867,1217.9291,1279.3955,-259.7673,1565.651,1309.6521,-441.3525,1125.2346,1317.999,-531.78864\nframe__miPKBTdcCIY__0005579.jpg,squats_down,945.861,490.77112,-154.9197,947.41046,470.3013,-143.96205,946.48474,467.76547,-144.08728,945.7698,465.4857,-144.1627,945.8048,474.36008,-199.9664,943.53345,473.52985,-199.91708,941.3369,472.95093,-200.19682,931.20056,453.11563,-32.08327,925.4612,463.45346,-290.31787,934.8436,492.22464,-110.30838,933.2761,495.78766,-184.08969,901.6669,502.93008,126.15846,842.4997,487.7276,-379.20038,974.867,471.2089,288.12772,790.7352,456.06924,-602.77496,1004.7074,436.77893,402.77652,777.3452,394.43417,-913.6734,1012.2413,433.08902,429.29996,764.04443,376.12988,-1005.9686,1005.38806,435.5887,393.08752,780.885,370.27295,-1007.00433,1004.07587,439.1569,387.93814,784.34595,377.85898,-925.81555,775.30566,703.475,179.9075,730.2757,709.0833,-179.5047,931.9716,693.55457,300.99768,887.7877,733.23517,-342.15448,846.55023,844.00867,428.09146,779.73773,866.05426,-142.04831,809.0572,865.2122,441.68866,733.60156,869.71014,-112.35144,881.406,891.9812,456.71817,833.7106,937.5939,-133.15439\r\nScreenshot_2021-02-11 at 15.00.10.png,squats_down,666.9811,275.0581,-575.66907,675.0563,262.4071,-542.6969,681.3156,262.97763,-542.6002,687.5624,263.44113,-542.44055,657.09534,261.87738,-547.40466,650.3866,261.67566,-547.32434,643.6445,261.62183,-547.2664,692.26074,273.17682,-370.8497,632.78125,271.13214,-389.36127,676.3876,293.2074,-514.1522,653.65674,292.05713,-519.26184,726.459,339.3898,-325.22403,591.7787,352.1289,-328.00433,740.365,431.6573,-623.7713,605.20715,454.0639,-639.3981,691.4289,343.0404,-838.5933,648.03455,351.84744,-863.3021,681.3267,315.91162,-883.2578,652.3254,318.63873,-904.3945,685.9974,305.52344,-827.8726,646.8695,310.33127,-853.293,683.6578,317.6574,-820.5802,651.9687,322.45535,-847.8524,705.49194,477.74103,7.9456344,623.2308,485.50815,-7.6731415,769.2293,484.64517,-474.57333,569.74176,497.84656,-519.85474,758.23175,620.89777,-181.39056,566.1231,629.4279,-211.87512,747.8375,639.7509,-161.16939,572.5135,646.71454,-193.47968,777.4386,680.3417,-334.3564,557.5805,689.90826,-377.1292\nframe__S6J5twMTzGA__0021021.jpg,squats_down,986.3324,509.6296,-767.7388,992.2387,492.16028,-760.10297,998.2689,491.88333,-759.95734,1004.17053,491.61118,-760.13477,976.2031,492.4109,-750.57495,970.4433,491.6991,-750.26776,964.7623,491.2248,-750.0884,1009.9963,490.51273,-598.5799,957.4059,491.2044,-557.3289,996.05347,521.8541,-701.5756,975.9714,520.4743,-690.707,1052.9524,521.977,-457.74942,918.4199,554.74786,-397.461,1101.8492,622.5374,-661.62756,917.94354,652.6177,-588.63324,1036.7025,606.4881,-967.26434,955.56934,612.3877,-911.00977,1016.767,611.72485,-1024.9242,962.43005,608.6475,-970.71216,1010.0043,585.2183,-1035.1349,964.56104,593.4864,-958.67664,1015.8188,589.062,-973.6608,966.5506,597.2049,-910.4664,1094.7158,688.787,-26.028296,1006.22546,700.1102,26.445969,1150.6449,648.7697,-497.86017,857.4172,669.0929,-153.51427,1152.4581,824.5577,-296.07025,862.1147,819.8424,-75.93167,1141.6211,846.59607,-278.17722,881.364,847.8817,-74.83924,1178.0491,881.42804,-434.24915,813.2586,874.93536,-198.32507\r\nScreenshot_2021-02-11 at 15.12.15.png,squats_down,720.1791,519.0098,-338.25833,721.0165,515.41815,-354.66803,723.59906,514.6529,-354.4918,726.10846,514.06775,-354.56808,713.25165,517.0734,-343.46228,710.2184,517.47675,-343.31726,707.0872,517.8033,-343.1212,726.7553,513.1832,-358.4745,700.18115,518.0016,-301.6652,723.1253,518.2924,-333.38614,713.96814,520.50696,-317.70078,733.84863,502.6743,-272.84583,682.9312,530.5764,-171.85133,728.2758,515.1352,-188.5306,655.59344,546.29156,-98.34783,673.0456,510.53018,-116.91911,624.5584,531.5477,-81.084496,659.48975,508.24725,-111.83624,614.1495,523.635,-79.536125,652.3227,507.02142,-129.64241,618.2739,519.8253,-92.65562,654.4199,508.8111,-118.57689,625.2843,521.4447,-85.5589,683.57715,464.55655,-34.10899,659.67004,495.5599,33.953823,636.5908,498.1041,-150.82175,611.9926,552.4917,35.27444,693.08746,612.8731,-64.786705,642.31494,657.25995,159.82619,707.5276,635.7764,-57.922504,653.2776,669.27356,164.76875,696.9604,643.9786,-99.08331,644.85376,700.7648,94.8927\nScreenshot_2021-02-11 at 14.26.20.png,squats_down,637.6488,326.9885,-442.75858,645.809,308.7406,-433.58542,652.37225,308.14798,-433.53986,658.9033,307.44717,-433.56064,628.06995,309.4049,-431.59122,621.49725,309.13745,-431.42313,614.90125,308.9819,-431.53162,668.1604,308.12604,-317.23047,607.21246,310.0277,-314.3224,649.6903,338.9089,-394.4702,627.5563,339.1692,-393.22964,709.8438,364.96432,-211.32774,568.4391,369.43973,-202.93968,750.18945,485.16254,-332.8349,553.5481,491.57474,-310.78708,682.22327,443.88574,-540.9038,610.499,446.43323,-539.6075,657.4326,437.71628,-581.3895,633.32996,437.2406,-575.6087,658.94196,407.34622,-554.0786,626.1572,411.80136,-554.5205,660.7283,410.93478,-531.0651,624.43134,416.17014,-530.74713,689.64825,498.96887,-3.5381367,610.4883,501.93173,3.826958,772.195,535.983,-334.5682,533.95154,549.9446,-294.28375,716.768,646.2678,-141.5714,579.0837,653.13904,-110.21891,698.63354,658.1998,-125.22949,596.7814,669.6444,-96.43718,728.9253,695.2253,-249.7646,558.23926,696.2607,-215.39531\nScreenshot_2021-02-11 at 15.52.19.png,squats_down,204.77391,369.38672,-341.66962,212.90767,354.29758,-332.19382,218.90868,353.1651,-332.03983,224.9722,351.99878,-332.04132,197.48363,357.34573,-323.4768,192.10262,358.17715,-323.46625,186.80777,359.2491,-323.5047,239.80063,356.33658,-242.41063,186.088,365.9372,-204.72743,220.15651,379.81207,-308.56937,199.84071,383.28638,-297.0985,276.62277,397.977,-177.64755,174.5284,411.5054,-151.2053,334.5381,320.54175,-288.083,85.213036,387.80374,-212.82506,240.7722,311.40866,-301.85394,167.76947,335.88727,-201.34637,217.47433,305.2148,-317.99417,187.92998,321.2535,-202.95662,217.88087,314.35095,-277.20966,197.65219,322.21527,-162.2295,224.41138,321.72382,-290.23724,193.24509,331.1184,-185.28242,266.69925,550.0883,-17.023165,208.45964,548.00006,17.343645,270.76096,545.9838,-308.61615,140.08665,535.0737,-196.65819,258.13174,604.1355,-80.580055,198.27852,598.4441,15.901836,252.13472,610.09247,-56.85713,223.96852,608.9223,34.289326,271.81946,643.7268,-104.15468,153.92473,644.18353,-7.647079\nScreenshot_2021-02-11 at 14.51.26.png,squats_down,481.86185,275.148,-457.4672,487.70987,262.27048,-443.10727,492.37387,262.00186,-443.0401,497.0776,261.61612,-442.87344,473.6294,263.05524,-450.0952,468.30508,263.01624,-450.05972,463.00446,263.08765,-450.1496,501.31546,265.9369,-306.27087,453.04257,267.31448,-335.9715,488.77945,286.3013,-401.8413,471.24933,286.9004,-410.55414,526.8015,308.34326,-178.90129,420.54425,316.36694,-200.20946,544.4343,374.40793,-137.66602,408.93185,383.66956,-123.67151,535.63763,428.05118,-309.21298,435.3109,431.04706,-219.12039,541.8825,450.09387,-365.5221,433.72192,452.10754,-268.34512,525.5274,445.3284,-400.9368,453.43985,444.79285,-295.2005,520.7748,438.9556,-328.43936,456.37097,436.70624,-231.91255,504.56772,420.2476,1.2286965,445.65628,423.6927,-1.1514597,591.3353,408.68365,-260.52408,358.45865,411.52356,-243.57715,566.7768,520.9699,-169.62071,388.64874,524.2862,-120.08435,550.69275,545.5845,-166.63809,407.52417,547.99915,-113.1719,603.3388,543.4561,-273.24994,352.79297,555.0064,-221.49324\nframe__g9QFlwHD_oQ__0005238.jpg,squats_down,509.19873,594.258,-335.4155,503.62003,578.74097,-307.3858,504.95172,577.22864,-307.5737,506.49222,575.9251,-307.4375,493.73376,581.98334,-346.09528,488.0624,583.1364,-346.15683,482.39932,584.4144,-346.15015,490.41412,580.6728,-164.11131,459.04382,590.2437,-333.24982,504.75253,606.8103,-286.2718,493.27777,612.97894,-332.77264,479.6491,658.9298,-54.598145,399.57678,645.1375,-400.24838,508.8719,744.3612,-291.25555,429.014,756.50793,-476.49954,526.0908,700.2879,-668.20526,511.63852,696.81744,-403.36462,540.5659,693.21094,-710.1291,541.024,687.22144,-434.6427,524.9453,670.22003,-686.11694,524.94714,667.81744,-435.63757,513.69836,676.38544,-670.52734,511.09897,671.2376,-398.54068,337.73022,755.45667,120.67381,274.03625,746.5167,-120.239296,454.76257,811.30994,1.6653482,347.15607,805.7267,-608.7005,388.14355,901.1059,97.7818,271.84094,938.58124,-466.12204,361.68555,911.9409,107.026306,247.87686,953.96405,-456.57736,418.65582,948.1884,34.35423,300.65607,1003.1273,-611.5608\r\nScreenshot_2021-02-11 at 14.21.10.png,squats_down,798.76263,383.7053,-391.31445,811.2369,369.57504,-350.70587,818.8659,370.45667,-350.5723,826.4944,371.1552,-350.43918,790.0614,368.03766,-350.96744,782.4705,367.28256,-350.70535,774.87164,366.6781,-350.54776,837.0341,381.84177,-129.40367,765.1883,376.1303,-130.78017,811.4346,402.93304,-312.85965,783.943,400.22424,-313.33594,874.0643,454.0692,-81.67504,714.4146,448.56332,-50.016045,853.6957,562.36847,-492.64352,718.07697,542.6301,-449.509,820.6561,453.6404,-856.39056,759.5561,443.59775,-822.1191,816.0597,424.6491,-925.84454,766.58655,416.6979,-882.549,824.1146,416.65665,-875.1316,764.5411,405.8722,-839.4705,818.35815,426.94998,-841.3278,770.028,417.57104,-808.5446,846.90356,615.88947,-0.10870997,746.3496,621.861,1.1373407,905.9213,644.2168,-654.4349,704.25916,650.63824,-633.3216,911.3102,843.8747,-503.53247,717.41473,849.7198,-484.06564,901.25946,868.80725,-498.7226,726.89905,877.78796,-477.61264,924.4757,925.46173,-753.9144,707.48883,919.4048,-720.21686\nframe__W5uGfeHb-jE__0012691.jpg,pushups_down,1507.5568,827.17395,-128.03448,1534.789,809.4371,-112.80613,1534.5996,808.6922,-112.73214,1534.5085,808.16144,-112.95495,1533.4413,805.59827,-174.01242,1532.6472,800.1066,-173.91272,1531.7351,794.6384,-174.12727,1514.0144,783.9877,13.861249,1510.2168,766.797,-246.95624,1476.1697,823.77313,-69.02704,1474.706,813.18634,-144.12108,1327.1841,729.26184,202.90602,1353.6349,756.5975,-357.41037,1119.8888,710.5831,300.09927,1115.7866,716.37177,-373.18768,1186.9573,841.1078,276.4251,1220.2609,909.3066,-385.29828,1225.6906,858.73285,289.813,1259.1918,965.30145,-451.44238,1251.3191,900.103,229.67853,1289.7924,955.72363,-416.34937,1236.4705,893.0388,246.32272,1269.9221,933.4592,-370.85727,866.4064,759.86475,188.85005,864.61017,788.90955,-187.95346,568.28094,798.82697,272.27582,544.0015,822.0115,-25.020939,301.3901,794.0734,438.14716,244.0476,798.3625,106.95399,259.78717,766.4242,451.53754,196.74133,761.52905,112.97827,244.46451,892.73615,394.19098,186.009,914.2853,0.7742244\r\nScreenshot_2021-02-11_at_14.27.08.png,pushups_down,733.7733,1215.8953,-1012.5815,749.59454,1218.1246,-1068.3406,756.0944,1220.7272,-1068.1313,762.4488,1222.9723,-1068.5726,728.24176,1205.1279,-1068.5841,719.83795,1198.2456,-1068.0255,711.7586,1191.1542,-1067.7933,772.61664,1190.5986,-1109.2432,703.6256,1151.4691,-1123.7169,744.36597,1194.6149,-999.0117,725.38965,1178.9713,-1000.5659,864.52856,1084.3462,-855.78424,578.97266,1011.69934,-969.4669,986.1799,1030.6315,-634.46265,390.2945,1000.7298,-872.94324,1116.956,1143.3186,-707.40027,375.96765,1177.1417,-1023.5263,1164.9767,1156.1881,-811.029,347.42545,1205.5569,-1134.0745,1150.3137,1177.3247,-815.6362,377.05344,1224.3835,-1181.8036,1119.1442,1176.9259,-717.6398,399.48135,1217.5195,-1048.3824,916.6502,940.6182,-4.770243,799.37396,880.50684,5.594835,953.3065,965.0184,899.6061,760.28,854.89734,682.984,963.34296,877.2782,1694.2347,787.7517,886.051,1503.7717,960.7555,854.0514,1783.7579,786.2471,891.867,1605.8846,962.95026,888.3592,1868.2825,807.3206,916.9237,1684.9457\nframe__topJ0ianBlQ__0018477.jpg,pushups_down,693.64825,812.9325,-31.597668,679.89124,801.3208,-65.82925,680.09503,799.49475,-65.89247,680.24097,797.4093,-66.02396,679.5641,799.51825,-19.5286,679.7108,796.8562,-19.52645,680.1603,794.0912,-19.866776,689.0942,778.7852,-146.76761,688.8316,775.4229,67.79148,711.005,806.9386,-54.474552,710.68335,806.5924,7.9224997,774.06976,788.8909,-228.28242,794.4686,745.7205,230.11171,778.72375,919.93317,-130.46571,796.58545,874.6245,296.33328,688.4639,888.07056,111.430885,691.5714,880.1231,304.80432,659.2095,896.18097,83.58698,658.94037,885.63806,319.61987,661.1167,871.1465,71.97639,656.39777,868.59985,320.06656,676.8385,863.45435,112.20866,666.96295,865.89966,300.47156,1021.06067,756.9855,-140.15102,1026.9954,735.192,140.42186,1173.7345,796.3422,-25.74272,1192.3204,795.6559,217.9218,1343.1202,810.3666,90.498825,1348.3113,822.2993,344.23712,1377.685,802.01215,99.748505,1379.3688,817.82965,353.61652,1340.9601,864.0096,65.75744,1359.5851,875.8109,326.09158\r\nframe__S-cQ8SHmkNE__0008023.jpg,pushups_down,1271.1725,830.6336,-13.413812,1289.412,818.98065,10.741952,1289.1539,815.4609,10.955221,1288.9761,812.00055,10.771878,1290.4268,821.7744,-52.69258,1291.4408,819.4523,-52.71055,1292.305,817.10565,-53.00057,1278.5314,785.20465,114.539246,1282.0688,793.14825,-162.24023,1250.1707,817.54675,31.56906,1252.0315,816.8976,-46.91906,1168.0336,717.4696,295.15012,1179.7344,771.3234,-324.34848,1065.1565,676.4156,580.1036,1053.6975,771.4926,-666.4229,1098.0524,761.63794,835.0815,1123.9945,853.9125,-922.69116,1115.1385,774.09845,882.01245,1148.6483,869.69037,-976.98315,1124.3655,782.36255,839.6037,1164.4877,861.43317,-954.5587,1118.1565,781.4694,820.70337,1153.4164,856.40924,-914.47784,882.49945,739.47205,201.6622,878.28015,772.9161,-201.39069,673.3686,743.9092,312.5303,653.85565,786.4665,-119.31132,486.99405,738.9596,444.1029,454.55396,761.17413,-60.341347,447.1715,722.6545,449.62045,412.83218,740.97205,-61.626743,459.8219,814.6509,381.4662,428.48315,828.5687,-170.75072\r\nframe__LMEb5jsIokU__0016481.jpg,pushups_down,616.98236,868.4864,-392.6002,599.1661,852.681,-426.35056,599.77246,848.05786,-426.17,600.4089,843.25885,-426.13232,597.45575,857.05884,-367.81097,596.6241,857.1123,-367.69223,595.9871,857.1862,-367.85272,613.7881,816.0087,-466.09647,606.12115,831.09467,-198.63142,640.9392,852.1369,-399.385,638.6945,860.65784,-321.21176,731.24725,805.5032,-527.2535,691.84705,796.9579,-5.1273103,792.3384,960.6728,-576.88245,731.0541,938.40344,-21.338583,638.5681,965.0261,-499.03073,616.18005,960.23303,-221.27173,595.18665,972.4756,-564.2517,578.40393,961.9877,-273.5476,590.7017,944.95856,-569.55835,575.39514,952.6987,-278.60043,608.48224,937.98047,-500.95447,594.01074,948.91266,-240.16054,1014.3402,800.8093,-167.62401,983.3767,794.0962,168.32162,1184.3419,859.3221,51.731907,1165.0438,841.7007,352.2166,1356.3285,843.2149,362.29034,1319.3778,843.5739,656.4503,1377.2141,820.8774,389.87286,1340.266,825.8775,682.0174,1425.027,910.22327,259.56396,1381.1237,910.0528,576.3967\r\nframe__yu1UF7WSFE8__0000857.jpg,pushups_down,474.86783,780.40283,-174.09122,451.1811,757.6334,-209.82243,451.29712,751.17975,-209.6723,451.38553,744.3841,-209.99454,450.9415,764.46826,-148.68675,450.97897,763.8922,-148.5951,451.41025,763.2538,-148.80542,464.68878,711.06757,-237.40633,462.539,734.15393,38.771385,501.44635,763.14294,-172.55083,500.9887,773.4049,-92.13354,581.0746,723.4879,-338.81735,618.9564,664.23865,319.99,585.98596,931.68665,-363.78348,642.44464,840.9193,433.7684,430.78537,947.2575,-205.49364,474.5022,859.73694,439.68347,379.76703,959.3041,-280.19894,422.74802,859.123,458.529,380.30988,932.1856,-282.79102,415.53107,845.9655,450.2579,408.09128,920.90094,-204.11287,435.94144,844.36426,431.92853,966.1301,637.1224,-209.60509,968.7446,612.5194,209.92981,1233.6396,770.2409,-132.1689,1213.7788,748.17413,279.10406,1519.0493,839.8946,-46.909073,1460.9779,826.3393,426.94504,1578.2306,827.6645,-45.43563,1512.1179,819.8038,434.64722,1514.2638,959.57465,-164.64388,1477.6558,932.9172,364.3714\r\nframe__ku3vgejAZ0g__0004878.jpg,pushups_down,1306.1124,808.7318,105.30775,1320.5138,789.76996,129.07944,1320.847,787.72327,129.2201,1321.3185,785.7444,128.86906,1318.2001,788.35046,71.41748,1316.7784,784.253,71.3841,1315.1041,780.1511,71.174706,1311.4572,765.06287,231.30893,1302.7295,757.8361,-16.523365,1291.5424,806.77234,154.09412,1288.523,802.4389,83.085815,1203.718,724.8804,400.75372,1241.2456,762.68933,-193.30461,1093.2786,764.3824,641.1215,1099.6128,824.9112,-444.9694,1158.2687,856.78925,847.1189,1150.3448,929.32324,-653.49036,1177.6074,872.3214,914.8211,1160.6642,952.39465,-699.34094,1195.5424,880.4807,867.93115,1181.5961,954.5823,-660.3487,1185.6282,879.5322,835.09436,1172.5793,948.42474,-635.08923,967.7329,823.6504,181.72496,988.8811,851.7866,-181.81128,761.52856,848.99866,198.51117,762.6209,929.0944,-213.44792,556.7941,841.138,239.8478,542.5676,912.53784,-240.28647,515.93256,825.76685,242.66719,501.94577,888.2566,-239.75066,526.9274,898.8099,202.25993,495.3986,984.7537,-308.80472\r\nScreenshot_2021-02-11_at_15.24.01.png,pushups_down,819.45764,1062.5668,-709.4082,796.5036,1045.9626,-786.88007,797.9867,1041.1978,-786.7082,799.16516,1036.4348,-787.0495,794.86865,1041.1936,-708.5993,794.9014,1035.2504,-708.2463,795.04333,1030.0598,-708.94385,818.6514,976.6573,-926.26025,812.04565,975.5098,-576.74457,855.682,1032.7748,-735.9993,858.17615,1030.6394,-634.58154,1092.7782,859.08673,-911.66693,885.94196,855.0109,-303.12665,1378.4403,808.5474,-775.5068,1039.5475,836.1939,208.14154,1351.1598,1097.9169,-477.4026,1027.0347,1029.2701,498.64963,1355.1865,1144.3458,-518.7266,1010.927,1061.2311,462.01697,1306.492,1165.9995,-547.83154,1004.515,1069.7094,388.39252,1288.038,1148.3339,-487.055,1022.18665,1059.1929,466.53122,1508.2068,874.71704,-242.19638,1400.5845,875.28546,240.24324,1818.8047,919.55237,148.93489,1623.5946,779.9715,752.48334,2105.3708,875.7683,603.94696,1796.1052,639.5432,1266.4532,2144.3884,829.057,653.5789,1834.6008,588.8919,1321.022,2173.1567,1008.1058,593.21686,1830.3578,718.2109,1322.2798\nframe__NTng60w9N7w__0002816.jpg,pushups_down,573.3409,819.0539,46.30839,554.4168,805.0941,5.4396257,553.76575,802.3085,5.520666,553.0379,799.26306,5.4825616,555.26843,804.35175,55.710136,555.30725,801.63086,55.606762,555.6194,798.8662,55.404083,558.5473,775.82355,-95.106735,560.97034,776.12415,135.61754,589.5084,810.26904,15.87423,590.1756,810.7148,83.45686,632.4641,783.17566,-195.31407,676.519,737.92053,280.3146,634.1944,920.9294,-105.91052,698.0658,847.3103,365.79922,559.7089,884.7041,162.46362,601.7737,857.84064,422.51923,531.9619,888.6164,141.16656,572.4062,862.089,450.5161,538.7143,866.94604,129.59421,566.0695,849.90656,452.1512,554.27136,862.115,164.43329,575.609,846.43463,422.11618,907.818,763.3529,-151.9867,920.06055,742.90106,152.18805,1108.6943,838.31757,-125.176575,1107.1951,806.5124,156.51228,1309.8483,867.0522,-111.9945,1296.8093,825.6887,207.84006,1350.2456,855.93066,-112.91478,1334.5391,814.58746,208.75482,1319.5061,936.77295,-170.53568,1321.3802,897.61285,173.5618\r\nframe__48tN82L4nD0__0017116.jpg,pushups_down,1182.9043,1749.6768,-94.6448,1146.24,1725.1425,-162.5583,1145.5306,1717.2897,-162.58293,1144.7141,1709.0087,-162.97351,1145.6653,1731.0356,-61.163956,1144.8575,1728.2378,-61.089134,1144.5099,1725.4089,-61.453506,1158.1547,1662.5315,-274.20212,1155.2188,1685.1246,177.01892,1217.8823,1725.7206,-124.23286,1217.5577,1735.5002,6.9490833,1307.8077,1667.2593,-500.78326,1365.3942,1587.7504,559.9251,1296.4531,1967.6763,-467.45837,1358.8038,1859.4884,670.7474,1080.4614,1934.535,-167.57336,1120.9022,1879.4773,588.8594,1015.43677,1945.3342,-287.2833,1057.2793,1890.1409,594.68384,1015.50134,1900.1794,-324.68542,1044.1713,1848.5453,591.5064,1049.9885,1890.1843,-179.24814,1063.1243,1843.3823,575.4501,1769.746,1540.3206,-338.35657,1794.4618,1514.096,339.33264,2148.5493,1703.3665,-374.2452,2142.9016,1667.885,256.75385,2535.7437,1748.8779,-411.70642,2500.6558,1727.0436,405.19913,2622.523,1727.5674,-430.999,2579.1724,1715.5941,403.43002,2533.2715,1914.1769,-699.2564,2518.195,1891.4907,204.1299\r\nScreenshot_2021-02-11_at_14.08.26.png,pushups_down,1683.3076,846.42554,-949.7597,1682.6522,858.48206,-981.03345,1680.0975,862.0475,-981.1737,1677.56,865.7868,-981.16986,1694.1487,849.4593,-982.4623,1699.0034,847.69885,-982.485,1703.6316,845.59143,-982.69,1682.4054,880.59393,-897.8724,1722.1746,850.1826,-909.1788,1684.1434,852.2728,-894.4206,1694.9973,845.2781,-896.1715,1677.3993,908.81104,-698.7837,1755.9977,836.1021,-685.7363,1646.5474,872.2424,-510.4451,1737.1497,767.99054,-566.5807,1679.9039,796.2196,-407.20258,1685.7932,780.3561,-526.9511,1685.4963,780.71783,-421.42352,1675.4099,780.6169,-553.3629,1697.0171,779.0202,-429.46335,1674.3474,791.6194,-556.8793,1696.0413,786.84216,-406.94717,1678.4364,792.8891,-526.2946,1680.8165,867.1211,4.5452523,1714.8491,829.59406,-4.5399804,1681.4119,857.10974,562.6516,1710.3759,819.2904,530.34296,1697.5402,845.3927,1157.029,1709.1011,821.22894,1127.2369,1703.6239,847.91315,1228.3623,1714.6455,823.77814,1194.929,1692.2444,826.16095,1213.7612,1698.4636,814.2869,1167.0225\nframe__k-vA3uKXdE8__0009128.jpg,pushups_down,1471.5109,723.46027,-100.04772,1493.1057,710.1807,-81.48458,1492.0885,709.56134,-81.23562,1491.1476,709.1772,-81.31373,1493.8035,707.60974,-134.87373,1493.54,703.5835,-134.72345,1493.15,699.6632,-134.83746,1468.7979,689.04144,29.8392,1471.2875,678.3893,-193.16586,1438.5801,720.38995,-46.986183,1439.643,711.6381,-111.655,1291.1427,607.41516,194.00896,1318.2972,691.03705,-327.94522,1120.1698,589.429,347.06686,1122.9943,660.48193,-440.67062,1118.1616,713.22626,443.07346,1117.1058,784.44617,-534.54095,1132.6815,730.544,453.97046,1130.5436,806.91956,-588.9087,1148.4684,748.3788,405.4701,1144.5509,812.55066,-569.9926,1140.3622,744.36035,420.93573,1134.0011,797.95105,-527.1387,877.0565,616.057,178.16737,877.5449,676.6618,-177.11874,579.053,606.2018,288.1634,533.7556,680.16254,-63.647255,319.8626,589.1978,415.78348,236.27347,629.97034,-13.8153925,273.1094,564.13055,421.9864,186.88654,595.4453,-18.93896,290.13513,687.3116,366.4739,198.2511,738.3381,-138.2836\r\nframe__dJllYrQxd1Q__0013932.jpg,pushups_down,1448.4814,680.8304,-10.560807,1468.4618,659.5823,8.50796,1468.0829,656.3346,8.6528635,1467.8373,653.5082,8.477387,1466.1978,658.221,-60.6409,1465.5979,653.75824,-60.626472,1464.7725,649.16876,-60.772827,1452.1053,627.9278,144.6186,1450.0996,621.77673,-165.89983,1421.4263,676.7279,48.915302,1419.3646,674.8301,-41.495445,1298.6454,592.75775,378.32086,1331.2507,642.612,-312.01788,1333.8281,796.9962,484.05435,1350.4547,845.1749,-280.95642,1497.317,792.4549,519.3653,1483.0845,823.3269,47.86756,1543.3635,798.3007,553.3225,1527.0577,831.46906,7.8026266,1547.1641,768.2308,560.25336,1522.9531,806.0247,-0.23188318,1528.5156,763.6092,520.1198,1496.2493,797.92993,47.55654,960.70404,530.2814,215.96115,970.34064,555.15906,-215.75085,701.317,648.7383,265.41595,701.24164,676.21545,-169.50371,461.04984,746.3481,340.96393,420.85962,751.8942,-128.64536,403.4004,745.91986,347.98682,360.2228,743.2542,-131.20888,465.62308,871.5683,286.811,420.21985,887.3957,-227.66402\r\nframe__El38L7SUq0k__0019247.jpg,pushups_down,586.21204,888.506,110.99627,565.9918,876.7981,81.683655,562.97186,872.1189,81.65524,559.8761,867.19806,81.5307,571.8324,882.18384,143.14594,572.8135,881.53394,143.1,574.05054,880.8848,142.84549,554.6652,838.03174,18.361195,571.1057,855.9823,295.89713,592.50824,870.2681,91.337036,598.859,876.4891,172.57501,592.081,792.49524,-119.25167,648.83936,827.62036,442.80756,574.058,902.0337,-193.02435,614.6795,899.2224,616.3472,519.8296,934.5388,-11.170218,546.7368,913.3309,648.42426,493.83795,937.5902,-19.57195,525.3484,908.3627,662.205,499.98297,932.7933,-1.42015,523.31555,910.6282,632.65094,512.3946,932.7633,1.2293675,530.16205,911.52136,630.2884,858.75916,805.7608,-177.04405,886.7875,829.06866,176.7869,1025.3231,848.25055,-324.06366,1093.6383,858.7151,36.183372,1220.3843,875.2373,-471.73593,1300.4583,878.1802,-53.873894,1252.803,858.1517,-488.48578,1337.3884,862.1673,-70.9905,1266.5083,936.7901,-614.8665,1351.8386,945.6376,-187.02545\r\nframe__vIEKfSf6JAE__0022023.jpg,pushups_down,496.99796,619.919,-540.36694,491.67984,588.6745,-592.3892,496.8627,584.65405,-592.06995,501.8819,580.52844,-592.1664,487.3743,592.52594,-523.9672,488.76205,591.8828,-524.0733,490.3622,591.3697,-524.4984,540.46027,561.9838,-693.14844,522.7444,576.918,-382.87085,534.3432,622.3611,-568.2385,527.8504,630.48553,-477.53183,699.17975,604.135,-738.67316,643.2842,595.9737,-127.62849,706.5933,797.26697,-711.2024,637.34436,796.76465,-62.473892,536.684,808.4197,-722.08624,517.48706,812.3974,-237.35564,487.32355,818.3617,-844.27924,475.51215,802.8898,-289.2915,483.28098,769.7879,-862.2843,476.3022,797.6744,-337.81097,504.2181,763.9244,-740.3308,498.46698,801.04474,-272.41125,1031.2256,586.15015,-207.42296,989.31805,568.1304,208.1277,1224.3357,656.7858,258.9868,1181.4386,633.5988,576.2258,1402.2792,682.6028,713.2407,1347.7231,660.9063,1075.9974,1444.7969,664.6466,742.2796,1391.1156,644.9883,1122.7861,1399.6555,791.7522,535.9758,1343.623,784.56586,1002.2754\r\nframe__GUC67V37m1U__0010759.jpg,pushups_down,761.0251,930.1053,-89.83701,740.01215,923.5305,-136.28249,738.79767,920.62463,-136.22241,737.5911,917.45294,-136.37335,740.55304,923.7368,-76.89108,740.08105,921.32837,-76.78925,739.91174,918.81226,-77.01039,735.41205,893.5604,-227.143,737.7157,896.648,43.307472,772.5795,917.01794,-114.483864,773.97955,917.2607,-35.38518,794.3969,880.2723,-353.14774,814.6184,826.6123,272.9875,805.8452,1029.0852,-308.8588,812.0596,969.43994,332.77,726.17456,996.1061,-14.268986,726.7085,976.726,276.33078,695.269,996.139,-57.146126,698.6079,982.8437,290.89026,700.05524,974.4505,-59.258904,697.3691,964.1864,274.16058,717.44617,969.0711,-8.310974,708.2917,961.67175,264.32092,1054.8993,813.5925,-194.99252,1059.9469,790.40344,195.23264,1223.3846,895.865,-145.12114,1216.9227,880.1835,253.68567,1409.6862,936.7258,-50.58997,1382.46,925.8483,397.0576,1456.5312,929.21313,-48.372524,1424.2595,918.937,405.29993,1392.7556,1023.85565,-155.3175,1377.4672,1019.0306,338.02856\r\nframe__ecDggpGrS7Q__0004182.jpg,pushups_down,556.47437,635.70953,35.122787,544.552,617.57825,-9.8161125,545.4966,614.8862,-9.653981,546.3685,611.8935,-9.816531,544.6085,615.886,49.537186,545.66675,612.7776,49.534313,547.02655,609.6396,49.239223,563.3296,588.75793,-114.81612,562.7843,586.3662,152.27612,578.72864,631.4974,5.784794,578.971,630.6737,82.63196,657.9695,612.5879,-266.72,700.3664,564.4335,355.0596,657.147,784.33136,-269.52856,693.8476,702.65894,409.87704,524.6972,785.3275,-167.88701,553.238,734.9848,389.86005,477.6722,794.8602,-235.2028,503.8695,740.5894,397.24106,474.98593,771.7969,-239.80438,504.3578,736.81104,378.8056,500.32626,764.6435,-169.45305,521.608,732.1533,372.1673,972.1539,601.893,-197.3786,985.1367,569.2923,197.89182,1185.6244,673.5335,-113.42484,1189.1295,634.09656,202.22418,1401.95,679.55,-49.019646,1387.287,645.427,295.60815,1440.8236,657.0751,-46.607094,1426.3762,627.4968,299.5246,1413.3357,767.32043,-126.627304,1403.0237,742.2643,242.78787\r\nframe__Bv00SMbu0JY__0002776.jpg,pushups_down,322.26,544.9101,288.67575,288.67923,531.728,243.76334,284.1795,526.33966,244.17422,279.5071,520.5253,244.35863,298.9725,536.02045,305.01816,301.40573,533.748,304.84955,304.2552,531.547,304.19333,275.2351,487.63785,144.56546,307.07166,504.6838,435.0423,334.30585,526.0275,262.53656,345.11758,532.9063,347.93723,353.4409,469.01987,6.623413,458.0802,440.0678,579.4954,293.39697,703.6096,-32.95501,483.46423,680.15625,778.84204,225.18065,734.1581,178.85277,333.01883,711.5912,866.2639,183.83377,737.6454,154.39885,281.29327,701.22345,899.615,195.05344,713.6789,158.68155,270.69363,688.0825,880.90717,219.08049,713.33734,182.49892,290.62842,689.5007,857.41345,833.3007,480.46817,-204.05356,867.8887,457.88998,203.41815,1223.7148,608.7505,-217.3511,1211.1987,599.7285,197.0746,1604.6238,689.71594,-249.207,1546.1821,693.61597,243.80202,1672.6925,671.15515,-250.53664,1616.6458,671.53357,239.76984,1625.4373,798.8554,-360.91357,1569.2648,831.80865,150.89485\r\nframe__VQKqjHtY8jA__0008781.jpg,pushups_down,1270.4625,795.476,-261.82794,1294.1382,791.5123,-219.11903,1294.8102,797.4021,-219.13947,1295.5132,803.43494,-219.21771,1292.6199,772.3419,-267.74265,1292.5038,762.51044,-267.6894,1292.2458,752.8476,-268.04376,1285.0742,789.96173,38.95264,1279.5736,728.6897,-169.31703,1248.0967,803.2201,-158.61386,1246.1737,774.86475,-219.53922,1153.5908,718.0276,323.06274,1174.1011,747.63885,-254.58157,1046.8464,704.06116,595.6672,1071.1462,765.58093,-594.46454,1072.5386,776.5814,805.05255,1099.3453,872.92914,-924.13135,1089.5433,793.4609,850.2194,1113.7621,880.86115,-982.9401,1102.6359,797.23535,824.45685,1126.3577,883.6525,-955.4261,1093.1489,795.69446,799.38776,1113.4365,876.13446,-914.00146,804.3318,699.7402,204.68275,801.66113,716.0121,-204.9765,565.66016,765.87146,185.11935,541.2853,806.4886,-270.2218,313.74142,731.9091,218.44322,276.4693,724.55237,-401.36746,264.6609,701.4632,215.8368,230.09897,672.246,-415.3242,269.4312,827.9857,164.93852,220.18181,827.6614,-511.92294\r\nframe__NTng60w9N7w__0012356.jpg,pushups_down,628.49396,800.12714,57.469254,611.2884,787.09204,18.8801,610.6974,784.51483,18.897682,610.00385,781.6862,18.787802,612.8277,786.0777,70.5269,613.42664,783.2001,70.49351,614.32043,780.2701,70.299385,617.30963,759.8454,-79.50275,622.22217,759.12476,156.7377,645.43506,792.6639,29.097454,647.081,792.3166,98.3897,692.4432,765.2911,-184.57205,730.80005,722.96924,312.5166,696.88763,894.67834,-158.38988,750.6385,842.6986,435.96152,632.1483,888.11646,56.595325,657.459,861.97876,471.22696,607.5548,892.7565,28.669807,629.95776,862.64075,500.6855,611.5406,871.324,30.22499,622.8145,852.0047,485.515,625.2444,865.50397,63.212734,632.7569,852.04004,465.2104,965.73474,727.43994,-154.80095,977.0809,708.1392,155.02109,1146.4976,815.6792,-115.35983,1147.0397,796.60114,174.0303,1339.8286,855.926,-84.50105,1329.7838,833.4889,244.21152,1381.5488,849.3481,-87.702545,1370.9374,827.52167,246.50786,1329.2349,931.3594,-167.99266,1328.5953,906.91327,196.32567\r\nframe___qNmbXRZtfY__0009828.jpg,pushups_down,1370.3818,778.8403,-793.1263,1383.5405,741.95197,-752.5804,1383.976,739.3322,-752.681,1384.5941,737.22516,-753.21326,1374.6868,740.86487,-824.3369,1368.9484,735.39,-824.48584,1363.0154,730.13446,-824.6178,1354.2579,698.7343,-543.1906,1325.0077,687.2605,-846.70056,1335.4353,775.0145,-704.9072,1328.4016,771.14105,-791.66583,1256.0891,672.6583,-333.14975,1120.9269,698.41656,-849.4241,1237.503,903.0236,-395.1183,1096.398,979.3459,-930.0269,1352.0889,933.32416,-690.85046,1344.3333,959.9717,-984.3316,1410.9982,933.0135,-744.2898,1414.1111,976.82764,-1084.4368,1404.8835,905.7014,-754.54236,1419.686,920.3535,-1097.1049,1366.9619,908.8888,-709.94727,1391.0078,909.93274,-994.6369,879.2555,683.41943,184.6028,796.9452,689.20044,-183.3346,650.86224,768.2763,447.21713,577.0244,795.9175,144.74358,477.86496,797.8704,899.687,385.0972,861.81494,498.04395,436.8448,788.8184,941.99225,340.55997,845.0219,521.4098,468.99606,912.1803,886.4753,381.15308,983.5917,395.2644\r\nframe__Jg9_-uI08iw__0000668.jpg,pushups_down,1290.6901,711.96375,-385.60168,1312.7605,726.1204,-400.822,1313.4622,728.5943,-400.5865,1313.8582,731.2633,-400.86465,1306.705,720.67883,-381.96817,1303.5255,719.1372,-381.95187,1299.8611,717.583,-381.96338,1285.1956,730.21765,-417.97632,1265.6046,714.6009,-332.3525,1253.5374,709.41785,-383.1418,1247.7577,700.2625,-357.53406,1159.8525,655.2978,-337.6904,1072.8708,696.84216,-338.2745,1063.0293,865.1213,-391.55646,982.49805,881.52576,-314.24536,1298.9298,980.21655,-591.418,1192.6888,927.38306,-166.548,1383.2758,1001.6785,-670.12286,1246.065,960.0358,-170.50873,1393.8315,1004.1094,-635.446,1265.8699,916.98126,-197.81633,1347.2727,987.5632,-589.5403,1245.6893,896.7614,-181.70215,728.95844,422.49762,18.713408,681.19604,452.6343,-16.687387,532.58185,419.1439,501.28943,462.4808,479.95877,432.4112,392.78033,436.66855,958.7555,299.1631,510.55194,801.9906,355.1071,434.29575,1006.43634,270.8723,494.00336,840.3508,384.2134,460.10754,1020.63684,270.7617,565.83203,830.65753\r\nframe__AYdQUS7jfPA__0009954.jpg,pushups_down,505.437,952.0564,-49.318993,500.8175,930.7599,-76.91598,502.51178,928.9308,-77.2683,504.04782,926.99365,-77.79895,502.86554,930.26746,-9.775287,505.96436,927.93555,-9.776689,509.1186,925.56494,-9.502798,528.30743,911.99603,-140.2169,533.4708,912.09564,161.497,528.00903,956.9711,-66.25876,529.6606,955.53503,19.19315,641.0228,913.4992,-289.67392,654.9693,900.6927,334.73297,800.2036,896.0689,-477.03214,823.10297,885.3932,308.26352,738.8154,1035.0548,-757.68805,782.73413,1002.513,94.31894,695.21027,1050.1671,-825.7412,748.4648,1008.1071,59.04235,684.6922,1034.6199,-777.83264,742.70514,1013.9993,10.6351385,694.08606,1033.8707,-747.5475,752.4712,1014.2677,63.988144,938.85266,910.8534,-210.50365,933.3363,893.8379,211.12216,1181.7441,924.38574,-136.70592,1174.5104,926.15063,219.85576,1411.1597,931.3475,-8.793879,1394.0376,933.4839,345.7739,1445.064,905.70465,1.2843959,1426.7675,904.9591,344.93292,1443.022,1007.3762,-150.24905,1438.2397,1018.9683,192.05312\r\nframe__k-vA3uKXdE8__0002009.jpg,pushups_down,1680.3234,680.64136,276.8415,1689.4274,661.2574,304.1558,1687.9065,660.28516,304.37692,1686.5525,659.53143,304.2016,1691.2926,658.48914,243.30548,1691.1802,654.32306,243.11426,1691.0131,650.1081,242.78249,1664.7909,637.9131,417.36493,1668.7802,629.1767,151.0626,1651.9799,680.4173,326.4935,1653.8196,673.3779,249.42072,1490.9891,623.5993,534.50214,1564.1941,621.7687,-57.879665,1343.4209,627.25507,796.8444,1415.5063,673.88684,-316.6317,1436.7451,692.99506,1005.86255,1498.5469,759.3007,-613.4629,1464.0647,705.34174,1043.0826,1523.9784,776.93207,-669.1861,1484.9398,715.53,1009.2121,1538.9382,768.9893,-653.1576,1476.4857,712.1576,989.1156,1524.1368,761.5777,-611.56726,1155.704,664.07654,204.78531,1186.207,664.2049,-204.46086,801.21893,699.08124,35.689945,819.5565,727.55884,-342.26227,455.61566,689.44965,-70.16262,463.85434,708.04034,-589.87726,394.64166,660.32245,-89.20855,403.42935,669.24896,-616.7432,413.22516,786.71783,-218.74596,410.4031,828.75464,-794.56036\r\nScreenshot_2021-02-11_at_14.03.11.png,pushups_down,1428.6722,1116.8883,-457.44672,1388.6163,1095.9873,-535.6031,1390.2109,1084.9795,-534.9598,1391.6808,1073.8495,-535.159,1379.7537,1107.2732,-461.13873,1376.3274,1107.127,-461.11597,1373.0272,1106.2219,-460.87872,1405.3379,998.2944,-679.03406,1376.0098,1039.7197,-346.41928,1469.5603,1058.6112,-490.95724,1464.7004,1079.217,-396.29355,1654.4083,791.972,-761.89044,1439.3997,824.72943,2.8102849,1946.0261,812.55457,-576.6897,1578.3239,881.3453,372.48776,1841.4446,1099.8484,-296.58014,1574.262,1101.192,453.4765,1829.5812,1165.0696,-400.136,1550.2435,1151.0723,484.8974,1758.0963,1183.5344,-390.11612,1554.5404,1167.8074,430.2705,1752.6471,1150.3468,-293.28943,1574.6729,1144.2804,425.53467,1985.3813,215.04321,-271.99103,1864.2603,259.31888,275.4082,2145.1511,337.49133,45.65797,2076.504,467.03864,678.6672,2365.2598,98.075066,684.8935,2246.05,168.87834,1157.1669,2369.4995,20.509836,746.26245,2238.6301,98.75977,1206.2113,2515.4668,192.40102,775.5248,2391.4263,191.51616,1303.2775\nframe__GKmvLWcSUoY__0016014.jpg,pushups_down,405.1264,755.4214,-70.848404,386.10425,729.7798,-128.32504,387.67215,725.81244,-128.28441,389.14615,721.50793,-128.7158,385.3898,728.9755,-62.135246,386.4933,725.4407,-62.02294,388.03522,721.89374,-62.02775,416.38647,691.28595,-234.75845,412.32358,690.6953,63.67312,441.08316,748.60803,-97.243095,439.9668,749.939,-11.004903,574.2007,735.2367,-366.38684,616.26465,662.75415,330.53012,570.3614,968.667,-313.77182,638.18024,876.4725,412.4849,412.60974,977.5079,-175.99046,473.53024,912.9768,457.3419,362.5221,993.9409,-267.78534,420.74295,922.1426,466.68594,364.91336,962.2566,-293.61774,420.7442,906.6822,464.4604,394.69855,950.49207,-189.18053,441.26163,901.77435,447.33517,1032.9745,709.3545,-220.09492,1030.0142,676.1972,220.87576,1348.2483,814.32733,-161.95622,1291.2579,780.4532,304.05646,1671.7365,843.0896,-121.984276,1554.2045,813.93115,473.39322,1738.8308,825.8708,-128.62097,1614.1422,798.8328,484.19965,1668.154,966.5898,-252.7426,1556.9489,943.72943,435.0693\r\nframe__yH1dSycnp24__0002718.jpg,pushups_down,470.05283,580.92725,33.730656,457.6587,573.0056,-1.2002318,457.15704,571.0836,-1.1418257,456.55667,569.061,-1.1542019,457.80176,572.68976,49.90051,457.32498,570.6006,49.84051,456.86523,568.4854,49.64106,458.47775,552.0092,-92.90929,458.2288,549.9335,142.01428,480.95413,572.6461,3.1282225,480.71716,572.3438,71.40242,519.82855,535.25574,-211.81276,520.5452,517.7756,244.61697,605.1408,574.23724,-161.41252,607.7584,527.2418,122.18495,567.2398,608.0281,75.45024,571.5374,571.7177,-173.55618,557.774,617.931,73.89165,558.7484,585.77124,-209.17178,550.1543,612.02313,67.61897,550.38684,584.19434,-206.78476,553.0918,605.4519,79.89312,553.8584,578.6435,-186.80551,701.4584,545.6209,-154.68488,695.1024,535.26855,154.53275,843.36035,561.44,-190.06119,832.4784,543.7671,206.70738,995.0243,538.0004,-215.95108,964.8514,533.1659,279.47665,1017.0686,517.18896,-220.3822,986.8113,519.04816,280.48227,1036.6333,587.7906,-297.63004,1000.7041,578.40314,216.56493\r\nScreenshot_2021-02-11_at_15.08.17.png,pushups_down,1131.5779,959.3466,-639.1243,1111.1421,943.4119,-691.70654,1114.16,938.3091,-691.47565,1117.2051,933.1582,-691.56995,1101.9523,945.3374,-628.78796,1098.7214,942.6061,-628.44934,1095.7532,939.95465,-628.8868,1135.4067,888.6991,-766.52386,1102.9556,893.5012,-480.09613,1165.4388,930.74396,-646.74567,1157.6147,937.1681,-562.71265,1378.8953,816.6196,-726.60126,1164.4553,746.923,-268.91318,1634.9845,831.289,-634.324,1248.199,759.1309,147.01599,1531.4733,957.58856,-456.9421,1204.2673,891.234,375.29868,1516.6456,990.85767,-520.87274,1177.9987,911.46545,383.01093,1468.2045,979.42566,-515.20496,1180.0005,920.26807,348.79684,1463.8907,960.0084,-450.9127,1198.9994,913.8162,365.5765,1679.112,764.5,-191.47247,1577.1979,720.9824,192.1773,1881.5873,749.0836,327.5671,1775.7164,723.12506,665.67096,2039.4092,693.5708,888.0969,1929.6025,689.16235,1236.7983,2069.7666,658.01,945.6171,1962.3734,660.7714,1299.2747,2053.1436,786.37744,914.16235,1941.7214,776.6077,1293.6609\nScreenshot_2021-02-11_at_12.26.39.png,pushups_down,940.62744,1104.9858,230.88914,929.8938,1088.1877,203.01108,937.13666,1084.5254,202.86998,944.26514,1081.0378,203.05695,907.35376,1090.2642,178.0397,897.0918,1089.0725,177.96478,887.37067,1088.437,177.70526,957.55945,1056.1481,134.56659,883.0428,1070.7869,27.137653,973.69995,1100.3237,213.42145,949.04584,1107.3542,182.2216,1126.0887,1030.6552,129.49048,881.1008,1030.5958,-155.95853,1388.4021,1087.5865,256.1161,805.2762,1098.858,-287.04602,1582.8341,1156.9688,393.10132,841.6976,1204.9302,-555.8039,1658.3518,1158.614,455.7927,846.003,1252.4224,-537.68744,1636.083,1183.1432,447.25912,879.1415,1236.1848,-482.6002,1591.8196,1182.3962,402.25366,888.5251,1226.7147,-522.4394,1400.3418,1086.8148,70.292145,1295.337,1095.6108,-65.571144,1608.7953,989.7535,440.69205,1418.1746,1052.072,302.54382,1512.42,1155.988,411.87964,1443.3159,1135.6433,187.221,1456.2355,1183.5251,416.60214,1427.4865,1129.8557,181.91727,1576.615,1240.5765,417.46167,1497.9452,1211.4026,201.24849\nframe__pBo_DjHqVws__0000794.jpg,pushups_down,1591.2197,537.215,-485.9408,1610.2288,521.39294,-435.9274,1614.5372,526.91956,-435.86118,1619.0449,532.76166,-435.96704,1595.6338,504.26486,-476.45404,1589.4956,495.30472,-475.94247,1583.1216,486.48242,-475.9019,1601.499,535.5084,-134.42853,1554.2699,477.38937,-308.1951,1572.0366,566.75934,-367.65268,1552.6324,539.6918,-416.97717,1416.6038,512.85565,241.11632,1468.8092,619.16626,-383.33795,1445.179,741.0821,371.81955,1488.8975,833.19965,-316.16962,1587.0657,712.9438,491.55652,1626.1195,787.46313,-89.46717,1635.2639,717.4566,516.2279,1670.8971,793.0744,-147.50262,1626.4806,689.051,543.2914,1661.292,756.15173,-192.98904,1602.9766,691.75604,501.72382,1628.337,748.463,-109.53827,1022.86145,555.06604,206.01215,1050.4202,633.86664,-206.27336,753.5607,633.10767,283.90714,728.2744,706.85095,-153.54698,490.19873,642.3641,384.7323,415.0842,678.0963,-177.05818,439.07828,626.0652,399.2824,353.56647,653.8683,-178.74661,468.87204,747.00977,450.77734,397.91238,772.99896,-224.46144\r\nScreenshot_2021-02-11_at_14.26.39.png,pushups_down,746.1647,1188.8684,-741.78326,752.69714,1191.1143,-782.61755,756.7686,1191.384,-782.68024,760.8949,1191.4813,-783.3018,737.90405,1186.0591,-772.0654,731.81824,1182.4259,-771.2815,726.10236,1178.6752,-771.0172,761.6259,1162.112,-841.3197,713.81744,1147.8771,-801.4658,752.1918,1167.1771,-746.41986,740.8887,1161.4722,-732.65027,847.11676,1025.0498,-713.5085,596.76526,1028.7441,-722.4877,995.67224,975.9575,-682.1299,455.77847,1040.395,-617.53595,1123.0061,1146.4905,-720.63947,412.4881,1171.0667,-709.2276,1175.5905,1171.996,-794.831,378.7383,1196.1134,-794.2496,1153.1493,1198.093,-786.0549,395.82544,1205.1827,-826.62915,1120.8745,1193.3776,-718.03723,417.9169,1193.1349,-728.86615,884.6433,944.7688,-40.185886,779.6448,930.6172,39.67983,929.71124,917.77435,621.6729,806.68964,932.6667,641.45984,946.9198,865.0581,1220.4279,837.02295,886.5049,1251.9325,938.6482,848.61096,1288.7788,838.3062,870.0841,1326.0267,984.48364,897.14124,1338.106,856.88165,914.318,1356.1224\nScreenshot_2021-02-11_at_13.39.01.png,pushups_down,1174.522,1116.2443,-680.46027,1193.3102,1121.0547,-734.72424,1198.6744,1127.156,-734.4795,1204.3326,1133.5875,-734.3785,1178.3458,1102.6537,-731.8814,1174.4607,1094.6111,-731.8851,1170.4219,1086.7905,-732.06604,1209.3092,1133.2913,-718.21796,1164.3649,1064.8344,-721.091,1161.0023,1121.3658,-643.91296,1147.2666,1102.8638,-643.9527,1230.3329,1056.282,-526.6539,1102.1777,1038.747,-561.3599,1202.923,986.55634,-184.96295,1020.55505,984.2109,-222.86664,1187.2654,1089.5416,-33.90615,1056.7648,1065.7039,-65.05022,1202.7767,1111.2223,-42.76779,1055.8774,1069.7361,-121.17036,1195.3796,1113.4066,-78.928986,1080.577,1068.1144,-144.4546,1183.126,1105.5688,-54.16013,1082.9132,1069.1173,-82.43184,1027.9956,1035.2507,51.174877,971.3251,1031.0831,-50.12265,970.065,1050.8639,502.39178,920.7563,1075.9868,392.91718,928.04974,1074.6167,1035.9858,895.2895,1130.8519,927.16565,920.93274,1070.5857,1098.3126,890.0024,1133.4612,988.78436,915.0011,1105.0024,1088.9022,884.5544,1185.043,972.9828\nframe__hbcB2rk4AEo__0001333.jpg,pushups_down,174.12839,370.15668,-294.0167,160.25006,350.86865,-341.8771,161.9912,347.35098,-341.6174,163.74847,343.75092,-341.57233,158.23138,352.5918,-293.54962,158.19466,351.1799,-293.4233,158.38516,349.7627,-293.4563,186.07414,318.01135,-418.25586,175.97992,324.50204,-197.98445,203.26266,359.42224,-310.56897,200.60211,363.96387,-245.6746,317.895,337.84308,-454.57178,283.35095,282.32462,-26.689476,320.5861,511.74307,-459.34552,284.98944,450.23474,5.9430976,176.20868,522.7559,-445.40326,165.98102,493.76834,-121.48266,131.76674,533.8307,-524.5238,121.41102,495.80826,-166.15135,128.15936,498.12125,-534.6599,122.421,489.84528,-184.0604,146.08319,488.1569,-456.44678,143.48233,489.86157,-142.43527,653.3408,299.85083,-143.99165,619.1007,271.47775,144.75069,860.1749,363.43597,32.952606,812.60223,330.32208,275.6962,1061.4094,373.60675,212.67017,993.0264,361.18036,476.62085,1098.3856,354.35202,226.08347,1028.0266,343.31384,494.36978,1081.1775,459.4376,114.826385,1019.9877,455.124,432.7963\r\nframe__ku3vgejAZ0g__0012175.jpg,pushups_down,909.9055,915.71106,-646.4232,922.382,907.79675,-671.65466,926.5447,908.6906,-671.74146,930.5805,909.4632,-671.6449,910.5742,901.50256,-673.76276,906.8277,898.05493,-673.71747,903.1361,894.51764,-673.6501,939.9318,893.4785,-621.1254,899.8466,872.75134,-633.3177,913.2538,909.6024,-609.5737,901.4937,903.03973,-612.0371,972.57764,871.96326,-446.77386,843.299,831.0288,-465.97626,1000.0771,865.52527,-229.16759,790.18384,823.90015,-317.35684,952.459,917.9179,-144.59372,795.90063,903.565,-307.66943,950.94366,928.3324,-167.05887,788.955,915.91034,-344.16293,937.9798,923.15564,-181.74405,802.9112,924.8741,-362.8894,934.6722,916.826,-149.01477,809.2888,919.95795,-316.7301,941.5307,792.5835,10.554963,881.5571,774.61664,-10.01987,948.4327,782.4525,425.2946,900.41394,755.33856,414.954,974.5174,745.54346,866.7046,912.30756,717.1906,842.2969,979.3774,734.1006,918.02954,913.68555,703.29675,893.7471,979.204,770.3359,958.48694,918.08105,739.27844,937.06525\r\nScreenshot_2021-02-11_at_15.25.07.png,pushups_down,816.748,1111.0431,-776.43054,793.83264,1090.7949,-863.875,795.9458,1086.0774,-863.7252,797.73175,1081.1837,-864.05225,790.51416,1084.8657,-766.8786,790.05475,1078.068,-766.4723,789.87067,1071.9181,-767.0668,817.67053,1019.3906,-1031.316,807.1814,1013.1132,-597.9486,854.48004,1082.0175,-812.11597,853.7398,1078.3549,-686.49207,1090.5366,889.67944,-1032.5502,892.19617,919.6029,-275.29132,1373.1997,840.4785,-871.221,1036.9902,881.48395,323.54654,1355.4232,1109.6927,-441.81796,1015.772,1044.3137,778.8972,1361.4779,1157.0521,-465.29953,1002.7438,1070.9213,794.3714,1314.8105,1177.6744,-481.34363,995.2773,1082.333,730.4024,1299.2426,1159.1544,-440.66867,1011.0758,1074.0583,756.9148,1520.8811,890.3671,-270.42227,1415.9663,914.51624,268.85434,1858.9806,914.3145,106.20927,1589.0261,832.41296,982.3486,2156.6482,865.1681,547.5771,1733.8722,704.4973,1640.5842,2199.5637,821.4728,596.8638,1767.7605,667.02094,1709.5964,2230.7002,990.2826,503.74402,1758.7794,761.41034,1718.9656\nframe___qNmbXRZtfY__0014587.jpg,pushups_down,1385.8794,755.0916,528.0722,1405.9551,747.0428,545.8301,1405.9298,744.44684,545.97705,1406.229,742.1576,545.67944,1408.2665,749.0256,489.87695,1410.8154,747.70233,489.84027,1413.1674,746.10767,489.56314,1408.4941,725.26685,615.8541,1419.5643,728.42145,357.19232,1372.7687,746.9493,560.011,1375.85,748.17584,484.91953,1302.1025,693.1025,711.92737,1367.1509,720.7558,155.99443,1260.7255,825.0793,809.8814,1307.1351,882.74426,230.64688,1331.3833,859.75946,840.9918,1338.3694,878.85724,608.99036,1358.3882,874.34375,886.62067,1358.2096,892.91504,625.769,1360.413,873.66785,884.3642,1356.442,867.8659,619.8571,1350.6146,867.45795,839.72815,1342.8809,863.3313,615.3217,1042.4788,707.5235,186.08592,1059.6888,723.5384,-186.1503,754.11176,784.5413,126.66816,744.75073,805.1266,-248.12224,491.75732,857.45795,74.41772,472.29755,871.2735,-314.74518,443.79822,856.93964,63.72727,432.82352,867.1833,-324.54315,464.35306,941.901,-37.0943,431.01947,950.208,-422.83688\r\nScreenshot_2021-02-11_at_15.07.42.png,pushups_down,1129.4795,976.78845,-625.33594,1109.0071,958.9994,-677.0512,1112.6748,953.4884,-676.8879,1116.3531,947.9336,-677.05084,1098.0002,961.1959,-614.25696,1093.9932,958.31134,-613.8195,1090.2533,955.52783,-614.1942,1135.044,901.32996,-751.85803,1096.7145,907.73047,-468.9449,1164.6588,946.9908,-633.6442,1154.4363,954.37396,-550.83014,1391.387,819.83295,-714.62854,1166.1373,760.105,-266.30838,1660.9336,810.14795,-601.9556,1259.7664,749.8575,161.56116,1547.8882,957.5534,-409.45602,1221.3147,888.77026,402.96982,1531.0294,994.0116,-465.71243,1198.2247,911.1827,411.97067,1481.5356,987.70654,-461.49207,1198.0066,921.4475,376.66092,1475.804,967.7224,-402.78287,1215.278,912.98944,392.57983,1685.768,772.90875,-191.07262,1587.516,732.28894,191.39316,1891.5872,752.4796,325.5651,1811.1519,723.5098,639.77344,2049.5234,689.1231,872.3206,1967.9327,681.59143,1182.0677,2080.443,651.453,929.0243,2000.3519,651.0933,1241.5481,2066.251,782.3831,910.7173,1986.1168,774.931,1235.592\nframe__--pHGLXZTBk__0007824.jpg,pushups_down,1477.986,843.2307,36.712643,1484.6609,822.4369,78.91279,1483.5358,819.7234,78.88406,1482.5583,817.12115,78.72947,1484.0725,824.26404,13.219448,1482.7831,822.4355,13.350742,1481.4656,820.5846,13.357253,1462.8652,803.2982,215.71416,1462.5648,809.82214,-64.894516,1458.038,846.562,94.02261,1457.186,847.20984,13.28001,1338.5707,795.916,384.37103,1371.2706,840.4875,-240.29257,1198.3369,821.25433,419.561,1210.9304,822.7316,-306.0012,1211.6473,926.418,254.4501,1228.147,932.69604,-258.68665,1229.7386,940.7881,248.82706,1244.2539,961.6158,-295.64487,1242.436,961.4374,200.74443,1255.3119,952.3068,-266.78378,1239.3284,959.68945,224.0891,1250.3789,939.4769,-242.49593,1094.9541,861.00183,199.81155,1097.18,894.14716,-199.20908,885.42786,902.5056,185.32132,864.32697,907.6874,-171.64276,685.46576,898.65186,338.20383,665.2386,907.76294,-40.44062,661.1121,879.6126,347.18216,640.3469,889.0958,-27.239923,620.9738,944.9487,248.15405,607.5933,950.35297,-156.78363\r\nframe__4zBnM_uozXM__0009650.jpg,pushups_down,293.2226,579.144,-178.4346,289.5025,546.41064,-219.48885,293.05475,542.1973,-219.25262,296.44592,537.7421,-219.03331,290.3168,548.8274,-144.73035,294.36618,547.6867,-144.77193,298.69308,546.6313,-144.93176,338.44992,518.7565,-299.61023,338.85315,531.9661,34.129623,329.55316,585.38074,-191.90518,330.2572,590.49506,-97.18317,505.66052,570.11066,-424.4483,515.8864,524.9144,245.77191,730.5551,619.30634,-673.3098,719.8843,584.7439,427.66367,632.968,834.5336,-1056.9607,682.83954,770.2835,627.34076,581.0567,871.77356,-1132.8723,641.7465,780.73267,672.5469,554.2193,843.08813,-1057.565,639.7662,788.5291,601.98315,573.7059,833.56714,-1033.198,657.8216,787.44476,605.8154,950.83545,635.0328,-219.25603,943.3687,596.71643,219.5508,1269.625,713.5928,-78.45972,1259.1893,692.3951,268.58258,1579.833,739.86597,66.2773,1549.354,722.3503,453.50906,1637.8218,717.2463,71.73163,1602.0853,695.32434,461.01486,1590.5283,837.4847,-94.72445,1578.696,828.9293,338.50742\r\nframe__TkaYafQ-XC4__0002720.jpg,pushups_down,919.9619,614.88074,-550.77405,925.7973,601.5492,-583.79706,929.8302,601.2397,-583.55725,934.03906,600.9187,-583.9927,914.6406,600.00745,-577.9516,910.0106,598.2456,-577.70496,905.7762,596.6691,-577.75934,939.25946,594.2432,-539.06226,895.8317,593.8619,-514.0909,926.8474,623.024,-512.72046,913.38885,619.8224,-504.6318,968.2515,598.35693,-414.17886,853.2253,620.53546,-432.06714,1030.9872,612.3682,-236.58383,833.46783,526.5218,-257.27548,1035.3639,621.813,-225.75218,840.9903,481.01648,-132.9895,1042.974,610.54724,-270.38245,832.8844,470.09863,-158.61308,1032.6753,620.968,-296.9926,837.1496,469.94562,-156.59119,1024.3182,626.3114,-240.05716,840.17487,477.6673,-136.57498,1017.70294,705.59186,-3.8565884,974.78827,722.22424,5.4205527,1053.8505,646.54474,643.953,927.77905,647.11884,745.2938,974.2867,602.2959,1389.1957,892.37946,597.4946,1516.2021,945.02985,587.8052,1481.352,880.0275,585.4101,1600.6243,977.3095,613.61316,1482.9287,882.7216,584.4807,1582.5984\r\nframe__YHKStY2-e9M__0001990.jpg,pushups_down,556.04083,866.7111,-93.67656,528.1098,852.42725,-153.20506,526.9712,848.8287,-153.11266,525.8372,844.91205,-153.41753,528.6178,851.32336,-93.34954,528.10205,847.2778,-93.27453,527.89844,843.19604,-93.479034,528.595,807.93506,-264.40518,529.7638,809.1604,5.7424874,576.37463,848.63116,-122.14286,577.6092,847.7572,-43.153133,639.20215,785.60065,-372.54745,662.8125,743.66095,244.06274,652.9731,977.1187,-354.68982,673.8903,938.664,301.26898,496.14963,985.05035,-189.33208,514.748,967.99493,265.78674,445.5478,999.33154,-267.70782,463.09955,977.2539,263.4635,445.4694,970.5464,-285.2144,458.86438,956.3671,266.1495,469.2889,958.9969,-197.91202,477.604,950.3673,255.7126,1001.01953,723.87616,-194.68112,994.5621,710.8,195.38684,1250.7761,844.49347,-132.32391,1222.9907,825.40106,227.59474,1514.2495,877.338,-71.923805,1468.8364,866.74115,329.20377,1574.2068,861.3201,-77.24265,1525.1707,849.964,333.04987,1495.2994,1001.08215,-209.15742,1469.8778,1000.16266,265.0239\r\nframe__ihCpHCvZ4Ok__0021234.jpg,pushups_down,1304.8923,728.7023,-360.194,1289.5863,734.75586,-378.00317,1283.5001,733.914,-378.06012,1277.2058,732.8731,-378.1536,1304.0392,742.9106,-392.13504,1307.8074,747.87573,-392.11658,1311.7097,752.662,-392.2183,1259.0579,742.2617,-360.29547,1307.029,774.32104,-422.93155,1299.5343,729.6136,-341.5222,1314.1482,736.00085,-359.03973,1243.8524,749.0739,-271.7325,1318.0034,805.52795,-327.6964,1243.0997,749.0474,-82.48449,1389.2516,815.6425,-245.01222,1316.4663,793.0586,-58.896812,1427.3623,839.18036,-216.36389,1330.9017,798.6366,-77.42629,1437.4651,856.8089,-229.7536,1340.7648,810.0496,-75.00347,1430.2618,849.0832,-242.35657,1339.0947,806.0825,-56.471863,1425.7294,840.2261,-220.41856,1341.7323,718.958,34.453506,1373.2484,758.6548,-34.17491,1347.9662,615.06573,177.21591,1400.1246,736.56805,78.388885,1300.7125,556.45435,395.23245,1403.1852,782.85785,321.309,1299.5607,555.7769,425.01358,1396.2588,784.3103,352.8339,1301.3358,523.1517,451.94397,1438.5653,798.3186,407.09286\r\nScreenshot_2021-02-11_at_14.07.01.png,pushups_down,1523.476,894.63873,-1766.6447,1530.729,876.6119,-1818.6482,1540.3827,875.7543,-1817.2653,1549.3638,874.1919,-1818.58,1510.6714,874.2099,-1797.0184,1504.349,874.5148,-1797.8506,1498.909,875.0544,-1798.529,1582.909,871.556,-1737.299,1512.2954,865.55536,-1640.6774,1555.1978,903.26135,-1700.499,1533.586,904.26025,-1669.7108,1761.5988,895.00116,-1497.1735,1546.3721,869.9995,-1260.9841,1952.8158,976.011,-1399.048,1648.0807,873.9378,-598.68225,2025.9802,1095.7349,-1495.918,1688.6168,961.64935,-152.8165,2068.4314,1115.3989,-1668.0573,1686.2687,975.3582,-122.9847,2038.0833,1117.7733,-1686.9122,1693.1602,989.4746,-190.06982,2008.9448,1112.3163,-1514.4054,1699.747,985.5772,-157.64752,1914.1616,928.8198,-130.70639,1844.7703,918.45654,132.49199,1953.6157,902.4295,1137.341,1871.9014,935.6542,1309.1937,1978.6735,944.0975,2225.9895,1918.3789,932.3264,2546.041,1986.417,948.45935,2341.4124,1933.9377,937.182,2674.8354,1968.0177,997.4516,2347.9038,1911.1676,967.9477,2761.4219\nScreenshot_2021-02-11_at_14.45.03.png,pushups_down,1707.3352,789.4358,-726.8703,1726.1243,747.44403,-698.70654,1727.6003,744.0594,-698.6002,1729.0204,741.5029,-698.76074,1712.3632,745.9737,-778.265,1704.7306,739.7651,-778.24176,1696.8231,733.76733,-778.3681,1692.073,703.8635,-469.7406,1651.1791,694.9017,-809.8184,1667.6677,788.431,-623.3652,1652.9495,783.7087,-720.59656,1541.038,680.4473,-160.5667,1409.1438,688.0763,-793.3555,1467.5055,662.8172,322.18906,1140.0002,609.3628,-813.5929,1513.1908,831.744,713.4937,1194.067,830.8586,-827.2911,1540.0927,858.62054,734.64453,1209.3337,884.6052,-912.3346,1543.7462,865.0414,677.627,1251.2693,884.4514,-903.6381,1521.2583,856.9895,698.0317,1242.8855,867.9029,-823.3813,1039.8705,676.4268,238.1604,973.9869,672.6576,-236.88461,805.0994,710.8672,898.10846,685.11237,686.9517,386.4047,562.43396,688.9231,1599.5303,409.84155,643.0187,961.4291,516.636,654.70325,1669.6005,359.25043,601.33844,1021.3482,529.3767,787.44977,1660.5372,369.11026,775.9208,953.1085\nframe__Zx52nD7pDy4__0001833.jpg,pushups_down,1263.517,928.70386,-373.76437,1276.6653,917.31537,-370.22095,1277.1259,913.9119,-370.1501,1277.5732,910.88153,-370.12958,1273.7404,921.5883,-416.64465,1272.6565,920.47546,-416.6424,1271.4735,919.4628,-416.812,1268.9906,886.8881,-278.5095,1261.7417,900.21564,-488.11008,1248.1733,915.079,-328.1364,1246.3613,919.3748,-388.32193,1211.055,826.44415,-92.35245,1169.4777,872.38574,-508.68414,1129.3594,818.1895,136.37787,1049.3868,873.33026,-517.8166,1140.7164,905.676,284.85056,1058.0525,963.19086,-490.17413,1149.9496,921.8957,297.76102,1061.473,988.5346,-548.0394,1157.4807,929.12866,262.6198,1080.8436,981.5182,-538.8685,1151.1149,924.7628,272.9229,1079.1411,970.459,-486.509,1000.20776,787.9137,142.3449,971.1209,806.1777,-141.71912,862.848,807.0332,365.56314,841.29504,832.15955,127.26296,716.41364,817.91907,595.1796,709.0624,817.9208,398.38098,685.58746,802.856,617.0024,677.9225,795.10236,422.90585,706.5632,880.5523,578.04285,705.68506,887.54346,372.14203\r\nframe__Yg3ZRcFrI2I__0006136.jpg,pushups_down,639.799,773.9393,-136.58781,619.78406,757.4466,-194.82596,621.24084,755.5945,-194.72487,622.702,753.40356,-194.88647,616.7002,753.5302,-140.05713,615.67645,749.72864,-139.78024,615.0115,745.7613,-139.73468,640.4296,731.66486,-318.6411,628.50354,719.4048,-67.35119,669.9907,769.2492,-168.21347,665.73944,766.5844,-94.4771,772.9704,770.8792,-415.51572,765.36676,668.43524,153.66174,804.7437,951.0163,-330.99872,757.319,838.4334,312.688,663.3511,921.64,-25.054518,639.9019,877.6679,355.62115,621.1393,928.36835,-51.99452,603.75745,879.7716,343.7009,625.72675,893.4125,-69.1502,602.21674,867.57056,343.3582,649.2239,882.729,-25.092892,622.2178,869.50134,346.70172,1176.1975,750.8162,-198.37506,1170.6571,691.7594,199.16313,1437.1145,857.1768,-112.6226,1389.9583,741.10815,531.2502,1693.473,903.85876,-59.542442,1578.9171,757.7657,875.19336,1744.6638,887.89154,-58.542072,1623.6692,740.2421,908.73694,1715.2742,1016.526,-167.85995,1592.2976,859.2648,887.3127\r\nframe___qNmbXRZtfY__0010208.jpg,pushups_down,1205.1693,973.0374,48.418274,1225.3507,960.54395,66.95843,1225.5303,957.4841,67.13416,1225.9369,954.5098,67.48012,1226.5459,961.14734,5.9293475,1228.4381,958.1133,5.3014393,1230.2296,955.011,4.2011223,1229.5197,921.944,181.12485,1235.2849,923.4374,-90.856445,1192.9028,956.14514,98.90628,1195.103,957.4267,20.161953,1142.1337,873.35486,331.02148,1173.579,893.7842,-200.18166,1136.5854,1001.0722,343.53757,1155.8357,1033.6072,-177.35974,1227.8236,1008.7043,263.49786,1243.6586,1024.4802,100.41999,1258.9089,1016.0253,259.31686,1277.0371,1027.8567,73.32793,1263.0947,1004.6017,244.98367,1276.1956,1010.5283,85.038765,1251.8903,1000.9751,250.56636,1258.8895,1007.17633,109.303505,910.47626,896.34283,164.96892,908.2983,906.4224,-164.72765,704.8786,953.6684,117.94223,697.99744,965.7045,-163.18997,509.38156,989.40027,142.69609,480.1605,1000.8961,-131.34207,470.0043,981.76746,143.81387,435.01468,989.2762,-135.43831,507.20685,1055.9462,74.85403,484.6121,1072.9465,-225.18921\r\nframe__q_LFDHqkFLo__0011082.jpg,pushups_down,1414.4927,673.6284,-10.348855,1431.926,650.6278,3.6742027,1430.9991,646.6791,3.7784917,1430.2089,642.99384,3.6355786,1430.9395,653.3745,-57.293095,1430.267,650.2049,-57.27783,1429.3644,647.026,-57.232746,1411.8986,617.3781,94.68533,1411.0977,622.6769,-173.4367,1386.3816,668.40753,32.303864,1386.0061,669.9583,-45.79971,1250.02,594.40546,279.0844,1290.6733,649.2715,-313.29523,1254.796,756.9796,381.0729,1263.4304,841.7145,-290.77936,1377.6395,775.9052,356.9523,1390.6853,823.4528,-49.93725,1420.3033,780.2702,360.1771,1438.7834,827.191,-103.04783,1423.2817,770.49524,343.634,1437.3452,790.92944,-126.76841,1406.5337,769.97034,344.11572,1412.3564,787.48395,-58.505215,915.99744,593.93396,184.27136,927.3498,622.7632,-183.81631,693.77344,666.28015,239.07927,684.3235,708.4096,-138.74815,474.93326,685.70715,337.91626,438.60324,705.7452,-35.07559,434.18787,672.1663,343.96265,400.0752,687.9278,-29.783617,450.05878,761.81177,312.60052,403.30548,772.57983,-83.18274\r\nScreenshot_2021-02-11_at_12.04.47.png,pushups_down,1147.0765,985.0151,-664.28125,1159.4554,979.72424,-768.4894,1173.8921,977.79205,-768.09393,1188.1354,975.57794,-768.3422,1122.6796,979.2362,-749.137,1109.23,976.8747,-748.63763,1096.02,974.3042,-747.8562,1218.8799,934.6316,-986.2949,1085.6285,930.44977,-892.64343,1183.9967,950.3337,-709.4561,1141.6799,951.9426,-680.5727,1372.4104,828.89905,-906.7255,997.0344,779.59503,-742.9553,1561.6023,867.7001,-640.8212,925.02106,846.0379,-431.1315,1603.5186,1049.5502,-683.2884,878.2483,1043.1976,-370.78766,1649.3865,1076.0151,-786.92883,842.9553,1077.3385,-428.82697,1601.3326,1091.8553,-816.2945,871.35114,1094.3413,-469.13196,1571.5203,1077.5138,-695.06866,896.42004,1084.1217,-387.28345,1351.3348,643.0384,-70.96447,1166.3329,607.0084,72.273605,1478.5472,772.09,882.9243,1230.4807,702.7637,958.60065,1479.2252,811.00824,1892.2374,1311.3889,733.3986,1966.208,1473.5764,787.76776,2001.2997,1326.8076,718.29474,2067.571,1490.1967,941.05896,2018.7948,1301.9948,818.62634,2085.3762\nframe__4e2_6rHBsXo__0001636.jpg,pushups_down,466.0413,679.4503,-24.79151,450.04367,656.074,-71.79542,451.6983,652.8755,-71.71306,453.2654,649.3485,-72.01933,447.91763,655.2409,-16.824038,448.2906,651.4303,-16.689308,448.9935,647.5333,-16.618961,473.728,620.9812,-159.44171,465.5616,620.8269,93.10312,495.51767,674.4169,-49.36374,493.24545,673.78436,24.268555,606.68054,670.8404,-283.31577,648.6709,581.23694,308.7854,599.66693,895.8682,-188.05916,674.5103,793.85144,311.86575,467.71207,834.3553,-15.2720995,502.16348,805.29596,349.37332,415.59042,839.28,-97.65018,439.29794,810.99756,358.06012,421.87207,799.4882,-132.61876,442.47717,791.4469,374.02826,450.45758,791.8253,-30.694574,464.92093,787.36194,346.13693,1036.7864,622.05945,-194.2547,1030.0765,575.9966,195.26353,1337.4376,714.5438,-150.35526,1294.112,684.00604,274.68118,1649.7207,758.75226,-162.31076,1569.7988,725.2768,365.5797,1708.9877,744.0141,-167.93506,1627.8962,707.713,370.43295,1642.4294,867.73785,-242.13881,1580.847,850.1199,334.84064\r\nframe__x5BuK8JqODU__0054286.jpg,pushups_down,1175.63,894.3324,-36.868088,1192.061,886.6127,-13.057215,1190.9452,886.52936,-13.075002,1190.0114,886.73785,-13.229864,1195.2897,881.1829,-68.316475,1197.7692,876.5809,-68.36981,1200.0652,871.8114,-68.66312,1189.6287,866.71704,173.39912,1203.7615,848.5134,-85.4589,1160.1335,889.4785,40.81778,1164.8417,882.2328,-33.72302,1085.3903,827.8492,443.01385,1140.5295,842.57336,-210.6328,1069.454,987.67285,524.2323,1131.7322,1014.20123,-153.22742,1221.5499,959.14844,551.5767,1241.758,959.872,118.840515,1257.0891,968.4717,560.86176,1265.9779,959.89374,66.8843,1261.4955,941.8291,582.29584,1258.6055,945.0695,24.165293,1246.8188,932.7325,553.583,1238.8994,940.176,104.13138,829.8204,797.6883,226.69702,840.2944,802.7943,-226.36275,628.3288,851.6524,203.1663,642.7439,863.65393,-262.15967,430.67142,844.5658,239.32016,409.501,866.7273,-299.4252,384.4384,827.1391,243.40863,357.20746,844.7459,-310.6125,419.16556,946.4249,190.52893,402.91687,967.22296,-417.8728\r\nScreenshot_2021-02-11_at_11.40.24.png,pushups_down,1180.7457,684.2351,-490.21042,1199.619,697.2494,-524.3939,1201.3179,703.32385,-524.4941,1203.0344,709.66907,-524.4052,1200.884,680.6764,-518.01733,1203.9095,675.4467,-518.0183,1206.6204,670.1944,-518.2691,1224.1509,728.0377,-542.28143,1231.0928,665.40015,-520.40564,1184.3075,694.8701,-480.81726,1186.344,676.44885,-473.6464,1221.8969,771.00195,-416.86008,1235.3556,644.23663,-412.41855,1162.8976,754.44196,-145.76927,1147.5642,637.4802,-229.22173,1128.1857,702.471,57.52842,1128.3398,679.4268,-76.957695,1117.8937,695.27826,93.13696,1126.542,686.00775,-62.883488,1121.9789,692.885,88.43546,1129.879,688.34735,-56.365517,1128.9126,690.6859,62.190006,1132.4312,690.6832,-68.53718,1126.7052,723.45844,9.117882,1134.9423,671.7334,-8.29409,1068.4343,724.65027,383.55893,1070.1367,673.9027,295.96094,1104.7466,707.82446,806.62,1103.0089,652.3103,700.5047,1122.7499,706.16956,861.991,1123.8881,652.14606,750.99,1082.4598,694.3383,930.7882,1070.4553,642.37506,807.5683\nScreenshot_2021-02-11_at_12.25.54.png,pushups_down,845.1885,928.9942,641.77075,835.16,928.82245,659.0018,839.6293,927.46216,659.9581,844.1472,925.9716,659.5927,820.48175,934.9926,615.1685,814.35376,937.5635,614.9253,808.4504,940.46686,614.8022,848.1029,938.55963,777.7556,809.30756,962.8798,576.35706,871.34357,937.4022,682.0114,855.4098,946.9939,621.29095,996.8676,973.9339,708.95764,850.09076,1001.6876,328.40515,1132.0887,1042.0594,646.8163,899.84454,1104.5428,-189.02014,1236.0192,1110.8705,465.13446,861.93524,1195.4944,-746.4672,1280.823,1129.2041,468.9361,842.5449,1238.126,-807.4168,1274.666,1131.1489,442.2027,869.3514,1217.4717,-811.5336,1253.8984,1122.0743,454.48798,879.91254,1198.4592,-746.6835,1334.3384,992.0456,141.38997,1234.1418,1009.60345,-138.53954,1614.5012,913.19977,256.97266,1467.3081,904.4883,-177.86023,1583.5475,1083.8761,121.9635,1436.596,1071.9775,-368.93765,1547.7534,1110.2137,99.57061,1399.2858,1077.486,-385.3019,1660.4879,1150.4255,-22.466225,1552.9851,1182.5919,-509.5471\nframe__QfAY5JsB7qY__0001811.jpg,pushups_down,616.7926,970.1571,-20.697895,610.8372,954.0645,-45.827854,612.37897,953.08954,-45.767803,613.78503,951.94226,-45.760067,610.7164,951.35297,8.211294,612.3574,948.603,8.240535,614.15405,945.81305,8.367219,631.71155,940.67816,-111.42319,631.86975,933.04913,131.70816,636.1884,975.0375,-37.522453,635.56433,971.92255,30.87566,714.2027,948.1236,-240.47731,727.96484,913.3561,273.79092,806.24976,923.37604,-441.43594,826.5615,882.8538,471.4834,794.3482,1003.0186,-743.13605,812.2246,954.875,628.3649,760.0931,1006.2182,-802.6762,784.9553,952.14166,658.4451,759.09924,994.4594,-749.8492,786.2473,957.11444,610.1435,768.50415,997.2488,-729.9145,794.3523,961.6757,612.27496,963.3163,933.3228,-176.96571,958.9372,907.0381,176.91133,1145.1506,967.3067,-200.8217,1134.2567,931.9998,173.57304,1319.9155,932.9386,-135.45741,1292.3575,903.1541,307.32214,1342.4955,906.1833,-130.01431,1314.4323,877.8592,309.51392,1360.6107,984.0915,-249.88737,1337.0183,957.85187,196.97375\r\nframe__nOUZPfm0aLY__0003376.jpg,pushups_down,1361.9862,745.73505,-28.931007,1372.4443,723.72314,-18.740381,1371.2961,721.6146,-18.566042,1370.2983,719.7752,-18.65306,1369.1732,723.3168,-74.59308,1366.4016,719.92975,-74.49727,1363.4176,716.5203,-74.40263,1345.4279,706.7717,98.740715,1337.3809,701.67883,-147.68759,1334.4187,752.6269,24.212387,1330.9795,750.5844,-46.987507,1183.6218,724.03864,295.75797,1219.9229,762.0721,-275.46304,1173.6445,898.8118,256.3279,1192.6075,955.49207,-197.79134,1294.6323,907.21826,129.63083,1310.4863,930.4606,61.07824,1338.8461,909.7881,126.97347,1356.3398,929.5695,8.462837,1339.5162,895.1522,117.98203,1350.3066,899.81946,-13.706005,1319.7332,895.8785,117.71348,1327.0422,899.8431,53.09716,861.72504,759.67035,191.67172,876.16003,782.3451,-191.21823,604.511,817.4909,164.98889,602.89374,826.87427,-171.7585,355.60147,810.67255,224.94211,328.73944,854.1519,-136.05188,304.9526,788.3593,227.11902,279.6713,843.5102,-143.14584,342.30646,912.2043,175.64148,307.08777,936.53345,-257.4127\r\nScreenshot_2021-02-11_at_11.11.56.png,pushups_down,1306.373,826.5466,-631.52734,1294.9094,837.82434,-697.7941,1297.1471,839.10645,-697.47186,1299.3837,840.18854,-697.6584,1287.0323,829.33044,-711.4806,1284.4908,826.23035,-711.3058,1282.1656,823.1819,-710.5186,1316.1549,828.25494,-739.8018,1293.3275,803.3687,-800.11633,1337.2988,814.8929,-619.0076,1331.9427,805.5328,-634.5585,1500.2982,843.73663,-480.89813,1285.7484,614.2298,-720.9468,1642.945,743.0286,-222.97931,1235.9552,510.85602,-439.94827,1533.22,817.3367,-131.18185,1231.252,723.67224,-189.62653,1505.0996,832.47406,-162.8032,1222.0427,770.3822,-169.53322,1490.496,839.6107,-160.57472,1245.8507,781.47375,-184.33516,1487.7097,827.73157,-137.08336,1258.1403,775.89355,-183.85495,1787.5637,693.6542,61.97117,1680.2235,575.1464,-60.897808,2069.4702,661.4648,355.3629,1878.1748,597.23596,116.326,2031.9645,853.8676,598.64325,1833.7174,814.9756,191.59694,2016.7495,874.3013,633.19507,1824.816,820.24963,207.9462,2046.6663,945.68774,796.12067,1837.7678,937.1183,321.58597\nframe___6UF5ZfpAQA__0020634.jpg,pushups_down,1209.4685,760.3805,-84.42977,1223.8723,744.49713,-54.572266,1222.5613,743.9851,-54.502552,1221.3584,743.7861,-54.689716,1224.5802,738.23553,-109.2484,1224.8582,732.81915,-109.12278,1224.9454,727.329,-109.17105,1207.0234,726.69495,115.87264,1213.2267,706.2811,-130.70079,1184.754,763.0379,-13.862094,1185.9672,754.9348,-86.04367,1061.0176,693.25934,372.10623,1110.416,746.28186,-254.4776,1057.8228,863.77814,460.2922,1107.172,920.0986,-190.6968,1187.4808,853.9379,499.2147,1208.0216,879.4159,77.02315,1227.316,858.92053,536.59344,1245.6001,878.05457,35.47461,1229.6055,834.3804,541.23364,1238.611,854.1984,20.8577,1214.2097,830.6595,499.9395,1215.5663,849.73773,73.34578,771.7069,645.92523,197.45355,788.63025,675.5224,-197.01909,564.53644,720.4348,258.5184,574.4101,754.31226,-118.334724,373.49783,773.73535,346.56906,353.3642,799.1323,-26.642345,325.24017,771.16113,353.45972,303.35272,790.5382,-25.21423,385.96735,875.1456,301.41565,363.81827,909.7556,-109.202385\r\nframe__J4sTsUuJzcw__0026153.jpg,pushups_down,358.6052,522.88464,47.996944,351.56036,511.72174,24.630451,351.92865,509.81635,24.610651,352.22467,507.77194,24.528559,351.66608,511.84393,62.727562,352.16406,510.25156,62.69903,352.82272,508.63885,62.528732,360.4129,494.40103,-35.71431,360.27573,495.74265,135.33952,370.40433,519.89716,27.628197,370.41122,520.4862,77.65689,409.53467,507.75153,-125.320984,436.37695,484.85413,236.14261,417.4442,611.761,-74.81425,447.90268,578.26105,274.5239,363.2047,593.6987,84.87954,380.56882,580.17303,263.51926,342.471,596.4148,62.271873,359.36456,582.12067,270.37506,347.00018,579.4437,49.74566,357.17987,570.5863,271.94714,357.99817,576.16736,83.224724,364.43893,568.8643,260.64465,561.2634,491.3775,-111.833084,574.5852,480.879,112.07924,677.572,531.7767,-111.20194,685.37933,530.2202,91.00572,807.82587,554.4842,-124.38631,807.75024,548.7678,109.59011,835.6079,548.88794,-127.617676,835.60156,543.63873,107.268745,803.7689,600.09314,-173.37593,806.09344,598.83734,64.7692\r\nframe__hTo7Qn41s-A__0003966.jpg,pushups_down,552.6432,720.2488,-22.306936,535.8173,701.12787,-53.078358,536.1849,696.17175,-53.0999,536.4888,690.96094,-53.28482,535.3608,706.9607,1.3287129,535.27625,706.60175,1.4223161,535.4291,706.17615,1.4106811,548.379,664.7679,-106.99072,544.5531,683.3508,139.39395,574.50757,707.4333,-35.54226,573.2245,715.4679,36.450237,639.6169,676.6269,-217.74731,664.60895,654.2389,333.91873,684.07495,843.59796,-115.747444,703.81006,820.2311,414.03174,580.9847,818.1902,191.99428,596.2499,805.6173,405.05075,547.5075,820.04285,173.34103,565.2743,803.02264,413.64963,551.165,796.43085,157.8569,558.861,785.7709,424.23975,569.40466,789.9054,192.93701,572.43634,785.462,403.41953,913.2804,663.8035,-175.97757,922.1454,654.0613,176.27687,1123.618,758.2463,-200.88126,1113.0942,715.84814,228.53665,1346.8055,790.6315,-242.11562,1310.4686,733.0803,309.91736,1398.1824,778.0446,-249.80759,1355.0516,722.52704,314.89456,1343.4814,881.03284,-350.5552,1318.499,813.3137,267.40485\r\nframe___50-LmEMF3A__0008929.jpg,pushups_down,1457.4349,835.6759,263.8006,1474.4047,821.7841,276.22226,1473.334,817.8592,276.4731,1472.4504,814.0196,276.31464,1478.2303,826.76556,222.14757,1480.3977,825.6157,222.2843,1482.3591,824.4059,222.21347,1466.5339,786.8828,334.7898,1479.3833,802.2301,83.58543,1438.032,823.15485,294.03317,1442.7877,827.043,222.29593,1363.9722,723.9607,478.97012,1404.7106,813.24835,-58.97804,1334.9609,845.8475,605.5404,1376.4502,962.788,28.955305,1443.1852,882.8895,664.5032,1465.4314,921.39105,387.9834,1483.3658,887.6391,702.39136,1501.7046,919.3377,403.19458,1485.8146,890.7892,706.2208,1497.3418,896.39307,396.84427,1468.7883,892.46857,665.5084,1478.7351,894.19476,396.92053,1099.8497,782.7572,177.10118,1104.8301,828.0929,-176.85793,867.3198,844.49884,185.03679,854.8621,881.0009,-215.2634,648.44556,883.4174,216.16853,620.44586,913.3662,-278.50467,615.15216,877.0207,214.02657,583.34143,902.981,-288.912,601.0123,938.6142,167.55614,575.088,980.2423,-367.78397\r\nScreenshot_2021-02-11_at_15.31.23.png,pushups_down,849.656,989.9005,-1085.1411,843.3446,956.34863,-1148.6887,850.5081,948.55676,-1148.1613,857.37164,940.89,-1147.7975,827.72437,963.32043,-1077.463,822.98,961.74615,-1077.2719,818.49,960.6574,-1077.7677,886.4603,882.9038,-1165.8007,832.3765,913.2174,-831.6831,895.5135,965.64935,-1059.7758,881.3284,974.9825,-961.29877,1123.1404,841.70135,-977.37805,884.9296,776.69446,-497.64362,1366.616,808.85034,-749.5927,975.4717,763.6707,58.799507,1297.1576,981.5465,-516.652,979.733,940.2469,312.39514,1288.7064,1012.42865,-580.82965,962.18555,970.653,281.3411,1233.0092,1006.9689,-606.1998,970.00305,976.08826,216.81595,1225.5767,994.60547,-525.48364,987.4092,973.66925,285.832,1465.4736,826.19196,-232.10208,1355.825,794.3696,231.93613,1700.9185,794.54193,215.29034,1570.5659,794.3059,815.2707,1958.3711,728.09357,749.40765,1787.1045,747.1524,1468.4415,2006.3275,694.0651,804.3254,1842.7968,705.5797,1538.3618,1975.8239,840.2491,738.245,1790.3728,892.2753,1574.4723\nframe__PLr0s-htu10__0011833.jpg,pushups_down,1465.0925,716.6479,49.060867,1494.7202,698.6751,68.47971,1495.2502,693.17444,68.49538,1495.9376,688.0002,68.249435,1495.9758,702.63806,-20.879232,1498.6531,699.48535,-20.713085,1501.1494,696.3241,-20.931057,1496.4763,649.07336,211.06624,1504.7548,659.1589,-196.17996,1442.2025,696.2953,114.693245,1444.6813,699.999,-3.128338,1322.6477,550.9763,460.51584,1394.1266,644.043,-371.57385,1279.6202,772.35876,585.9356,1373.9092,889.35236,-275.64172,1469.7782,764.1546,607.5225,1508.9374,797.4127,172.42421,1526.3307,777.2939,640.6986,1553.7286,787.9771,148.07701,1529.8988,754.4363,649.49945,1543.6147,765.32074,114.40447,1511.041,747.33417,608.75226,1515.7343,759.8178,170.18091,909.0974,519.87695,267.25797,919.325,570.0586,-266.61655,570.91534,622.20325,261.0766,560.4434,658.79004,-203.67703,241.73361,626.2518,257.99896,199.24667,686.7197,-211.80594,180.42474,599.38074,253.37024,131.8122,660.15753,-222.06058,212.34729,750.43384,179.98285,179.96956,831.80365,-337.69296\r\nframe__mjVH087fgSg__0004752.jpg,pushups_down,1427.3802,791.0962,-42.86107,1452.2573,762.9209,-26.546211,1451.6895,758.7755,-26.380789,1451.2863,755.0199,-26.437305,1451.4373,763.65533,-102.80766,1451.4869,758.3623,-102.912155,1451.3704,753.04987,-103.08295,1437.9426,711.543,115.302444,1437.3799,711.00024,-222.12527,1397.2678,775.66815,22.620758,1397.1194,775.30005,-75.87359,1256.004,657.1608,334.28754,1303.7286,714.9003,-346.85776,1232.0254,863.6958,393.87778,1268.1724,924.4256,-339.32758,1408.1735,880.54193,357.19196,1417.9656,926.8453,-110.44623,1462.2759,884.80206,360.2767,1469.4102,942.13336,-180.82495,1471.2737,866.5585,350.13217,1472.1185,906.96454,-197.23053,1448.0596,862.3588,344.54727,1444.0004,898.02203,-120.07434,882.4558,653.9225,200.888,888.6678,690.6885,-200.27739,578.7188,736.1941,209.48077,585.5678,772.11053,-170.46228,314.21094,768.9589,268.46863,288.81815,797.7894,-143.18103,253.7198,757.92065,274.35776,219.47777,785.06067,-151.58223,324.2854,877.54114,212.57153,312.48755,914.8004,-270.65802\r\nframe__48tN82L4nD0__0014095.jpg,pushups_down,2497.6248,1866.9714,145.28201,2531.6252,1851.7887,194.60332,2532.083,1847.2401,194.92087,2532.7075,1842.9288,194.50348,2532.5078,1853.0724,83.95808,2534.673,1848.6738,83.85085,2536.7458,1844.2959,83.379654,2526.762,1807.1206,407.96292,2532.2854,1810.766,-79.24132,2470.7356,1852.5897,238.75484,2473.3684,1850.4038,99.1008,2344.1519,1713.6448,756.2306,2391.9678,1758.8043,-394.16473,2148.3425,1684.4773,1126.4994,2185.846,1711.1405,-892.1351,2192.0144,1835.2435,1283.8799,2243.7048,1927.2957,-1285.1438,2231.3462,1858.1638,1355.7592,2277.8606,1972.3313,-1378.4757,2248.6208,1893.347,1278.8903,2299.354,1972.2634,-1315.5033,2240.004,1891.5398,1247.9318,2285.2812,1954.511,-1260.6973,1898.6416,1723.4363,375.74207,1898.7179,1755.4943,-374.90073,1504.4984,1731.4169,342.4523,1494.1344,1759.859,-390.61365,1149.2285,1698.7585,467.4664,1119.2988,1730.5963,-335.93002,1085.5936,1662.8324,467.00958,1063.1167,1690.5314,-345.2643,1078.0042,1856.4834,298.0183,1032.1847,1881.4125,-586.16\r\nframe__hnCg8x3xi8M__0011465.jpg,pushups_down,670.4447,854.553,17.303171,643.3477,839.51544,-46.327812,643.0028,836.6412,-46.343746,642.649,833.43335,-46.667206,642.50446,836.6153,22.260845,641.6918,832.1319,22.320501,641.2017,827.55975,22.108833,649.7105,801.20575,-195.07564,645.8755,795.17676,111.49296,693.01794,841.16364,-26.401455,692.2116,838.9563,63.373154,759.99963,796.8302,-329.75937,780.95404,736.1385,324.4026,785.3036,987.72925,-222.84352,787.0509,910.6597,424.50366,657.35095,958.80505,116.937,662.7593,931.4923,431.096,615.08905,965.5655,74.556946,624.2491,938.52185,440.95496,617.9741,932.7896,55.73684,619.31177,918.07947,442.94687,638.2537,924.5075,114.73077,633.59125,915.23846,425.05917,1107.2598,749.0616,-205.34604,1110.4244,723.4622,205.94138,1360.0094,840.3313,-181.8115,1334.7288,820.62524,218.68546,1624.551,877.59906,-138.95428,1574.336,861.98663,342.22464,1682.0068,867.96466,-143.56378,1629.3524,853.4031,346.70963,1617.3477,977.7351,-274.37485,1572.2751,967.96716,267.82037\r\nframe__LL5e2xno6bc__0002228.jpg,pushups_down,1273.9187,690.6811,91.536896,1281.5525,674.69763,106.65087,1280.0913,670.68506,106.89138,1278.7362,666.77924,106.79868,1282.3013,681.62,54.161137,1281.9688,682.0188,54.17456,1281.4365,682.3472,53.983627,1264.9003,657.7922,175.25882,1269.1482,678.0162,-61.843723,1257.4143,692.5796,124.836044,1258.7944,699.4735,56.233223,1162.0522,658.7313,347.67392,1201.7993,718.0111,-215.9827,1156.2382,777.37256,454.37045,1198.4285,857.5155,-182.138,1232.093,793.17786,458.6766,1277.6152,846.0649,-22.25727,1264.5281,793.72546,483.46613,1314.2552,845.9846,-67.0883,1265.7445,790.7093,450.8962,1313.6556,820.47455,-60.641663,1255.475,791.7782,443.40698,1296.7786,818.88055,-16.986675,944.1684,679.2878,180.18413,953.94244,713.35675,-179.95123,798.2368,724.9056,327.55536,765.9941,736.92114,-96.08048,644.33496,749.3003,525.5601,603.38947,750.01135,13.952146,614.161,744.895,542.5543,578.6451,741.9254,19.66763,632.00446,801.52625,510.35168,582.4993,790.007,-66.70731\r\nframe__GauW8uJtvFs__0029419.jpg,pushups_down,1199.2311,560.9652,-183.23438,1217.3687,545.838,-158.25917,1217.5679,542.4446,-158.28432,1217.7584,539.2228,-158.4905,1217.5199,547.68134,-222.62898,1218.5297,545.09534,-222.64409,1219.3817,542.4967,-222.91519,1216.9015,510.3173,-8.369325,1219.4132,514.8779,-310.75952,1184.9888,546.97186,-120.78103,1185.5543,549.2511,-206.86253,1130.4095,469.9554,184.17078,1142.9556,491.84375,-409.95502,1064.8992,595.5764,263.35446,1075.4856,615.9689,-440.67184,1171.9259,626.20734,265.72266,1191.7975,645.6696,-282.94968,1204.263,641.4438,258.09775,1225.6558,664.93744,-327.1165,1210.5723,628.3124,271.69897,1234.3857,640.25226,-342.11996,1199.1729,620.7673,263.8559,1218.7197,629.97284,-281.33636,880.8943,406.02957,199.4802,871.8858,413.37097,-199.31258,741.86646,448.56857,636.68005,685.5564,490.97025,-177.005,606.1245,429.2182,1018.31726,482.6782,512.2725,-157.15942,577.0198,411.6719,1054.9294,442.8513,493.93622,-162.31807,581.1755,499.84293,1061.7151,454.39807,595.0333,-261.29105\r\nframe__VQKqjHtY8jA__0016076.jpg,pushups_down,1276.5696,746.7906,-783.65686,1304.7306,719.58984,-778.2088,1308.4016,716.8363,-778.1871,1312.0459,714.7452,-778.45416,1290.6589,716.0576,-833.3087,1284.9222,709.73035,-833.4094,1278.9697,703.6101,-833.6279,1298.6215,673.34454,-611.0814,1256.1681,660.165,-850.70636,1252.7041,735.32666,-698.60205,1239.1521,729.3743,-766.87213,1233.158,614.7671,-363.9802,1047.5652,619.2213,-755.831,1215.09,643.7564,56.353367,826.97394,645.097,-684.92993,1243.891,767.64935,260.12732,865.451,822.5544,-614.94,1268.8076,789.1705,257.4487,868.27094,869.7283,-683.0717,1256.4364,800.3326,199.94835,908.28314,858.83093,-676.4325,1232.592,793.70386,241.02625,909.6943,843.73456,-614.4887,837.4404,646.372,162.58179,748.559,644.3608,-162.42046,723.6611,681.87555,784.22595,593.1444,660.6655,462.8792,619.7942,671.8293,1480.4044,465.86252,644.2186,1104.9756,592.5354,646.51715,1553.6925,437.09348,616.0875,1170.9462,612.3053,755.9598,1527.9087,444.5973,734.46936,1107.6864\r\nframe__TpG8u6W8-Ec__0001498.jpg,pushups_down,1100.3755,760.63763,-39.523895,1116.8644,742.8438,-21.12365,1116.2233,739.1183,-20.950102,1115.7072,735.5832,-21.113335,1116.0139,745.36896,-82.658585,1115.6809,742.7202,-82.569595,1115.1637,739.9966,-82.5951,1102.8661,713.9804,90.23164,1103.0498,719.36487,-187.63687,1078.319,756.0772,10.416008,1077.8953,757.89764,-69.2279,973.85034,688.3995,306.7507,1004.2591,737.67896,-336.2182,969.43414,813.2758,440.43732,976.14557,892.55347,-355.75,1064.7388,850.923,445.43546,1074.5953,897.31165,-195.64937,1105.1746,857.25446,472.32217,1117.5892,904.87946,-259.39822,1107.1449,850.3796,443.3244,1117.3792,875.3102,-264.2529,1092.5133,848.9986,429.67633,1096.1089,872.2306,-196.64764,702.30133,698.5043,200.8435,711.60645,728.6498,-200.42177,512.2175,757.1033,275.94977,510.0368,781.42834,-148.43031,331.19345,782.2806,417.2363,311.75745,802.2644,-43.492855,288.5722,775.7917,429.1747,268.11298,793.894,-46.42583,331.88135,867.51624,377.2125,312.26834,887.4839,-160.77756\r\nframe__J4sTsUuJzcw__0001083.jpg,pushups_down,349.89935,506.0838,-45.72805,346.29358,494.5105,-66.206184,347.54883,492.91663,-66.16018,348.73834,491.1902,-66.22756,345.22955,495.0415,-32.90617,345.69434,494.1064,-32.880836,346.3122,493.1818,-33.005806,359.89365,482.281,-100.32048,355.49744,484.31506,48.04762,362.59488,506.3443,-54.985928,360.921,507.5595,-11.903247,409.08698,507.06732,-174.81956,427.84656,484.0805,184.40698,419.06097,602.30664,-118.32028,440.79413,582.4572,190.41507,362.2727,596.92664,-5.3116016,372.07077,592.66364,136.5814,342.01453,599.52356,-41.04487,348.9295,594.7583,132.10303,343.17053,587.4012,-51.801422,347.10126,586.6416,126.74079,354.6355,584.1952,-9.45673,356.1228,584.79803,128.73384,565.38586,489.91568,-114.2656,571.6189,478.4699,114.466255,685.49506,530.0612,-80.24003,684.64185,526.3176,121.74094,813.76685,547.91644,-48.52884,802.61,548.1558,165.25427,841.1274,541.5478,-48.219833,827.70685,543.64636,165.90903,807.88947,597.677,-103.58942,804.1265,598.2822,119.00142\r\nframe__NkWl7-gi-BM__0003984.jpg,pushups_down,433.42157,703.27155,20.152546,404.22397,684.0794,-44.026752,402.957,679.94226,-43.91455,401.68155,675.4052,-44.108177,406.16592,682.73627,28.073692,406.6036,678.4338,28.026138,407.42282,674.1053,27.544643,409.87726,637.9649,-186.34842,415.63043,638.6441,142.85971,457.40836,687.66925,-19.696974,460.29877,687.83826,76.58661,530.11163,649.99304,-332.2543,590.1207,592.237,383.71985,534.31537,892.657,-253.31177,617.37854,819.32947,476.3891,369.54156,858.7078,5.584954,424.96008,806.09753,516.36316,311.8553,871.5137,-67.00644,361.9099,804.7697,532.25385,317.2566,830.899,-94.73782,357.0001,781.3029,544.866,346.23624,820.6249,-2.961429,377.75705,778.42017,513.1206,942.77026,647.6671,-212.4643,961.729,618.6705,212.69928,1238.5773,755.0697,-149.86061,1242.249,719.3663,234.12518,1548.2922,802.5568,-107.31323,1529.732,751.8919,355.06097,1610.253,793.34814,-109.62113,1588.8987,743.7035,358.34088,1541.9669,898.2969,-212.78818,1538.8574,841.39325,278.85092\r\nScreenshot_2021-02-11_at_12.53.21.png,pushups_down,1068.2865,863.3959,-315.47995,1073.6927,873.3205,-369.2785,1076.3663,875.4332,-369.32983,1078.755,877.5285,-369.4592,1067.4174,867.52325,-371.2052,1065.8043,866.11273,-371.12357,1064.0283,864.5669,-371.2385,1087.7017,875.80334,-444.0998,1068.4103,858.3369,-455.39005,1074.158,853.8449,-319.22717,1066.3759,850.24615,-322.0116,1166.233,851.30023,-356.8833,1032.8077,807.3731,-374.20343,1212.1017,813.5793,-99.79002,1034.7574,720.84174,-94.41298,1158.3237,861.09,64.11801,1034.7369,781.20654,94.8046,1154.8209,875.8593,70.32421,1033.6561,792.8572,98.30813,1142.056,873.57446,49.0613,1051.3829,802.5439,92.2894,1137.5752,865.4401,57.274105,1051.9263,799.56946,95.28338,1130.2734,727.0748,18.186388,1061.1017,710.99475,-17.498367,1136.5009,731.6066,476.24374,1065.089,721.22974,444.88632,1135.0137,735.933,979.9258,1068.4984,726.37836,982.1373,1132.7507,727.29156,1035.3783,1071.7185,714.03217,1041.6478,1143.2009,774.7742,1029.6577,1070.2554,768.06525,1047.5924\nScreenshot_2021-02-11_at_15.19.24.png,pushups_down,859.5178,1092.0276,-978.47833,867.8495,1037.5349,-1043.7156,880.5188,1030.2354,-1043.3447,892.9413,1022.97437,-1043.6456,846.21674,1041.3746,-958.4486,842.1125,1038.559,-958.2012,838.37445,1036.2661,-958.8615,951.3421,964.9256,-1088.5778,875.9092,985.1088,-714.4169,918.07965,1079.7161,-971.97217,894.20184,1089.6724,-863.15845,1280.6631,916.3108,-934.79694,953.5135,921.66437,-501.07278,1602.7659,834.6056,-762.5791,959.7733,902.605,5.557322,1484.276,1124.4363,-542.0912,897.99176,1107.5428,59.576893,1478.8727,1183.058,-600.09973,870.7074,1142.5536,-24.881964,1395.7208,1177.343,-619.47925,872.88654,1143.7076,-107.59254,1380.4865,1146.7842,-548.0735,898.4793,1133.9391,17.036934,1639.9623,927.69666,-218.82832,1505.0015,924.5883,219.96797,1857.6046,940.8863,483.80502,1694.4664,961.33704,977.5153,2027.3674,890.9106,1213.8296,1857.0529,921.2233,1719.6685,2062.4177,851.8337,1297.2612,1897.4932,884.7315,1803.2318,2042.7737,1015.6079,1267.9775,1867.9952,1041.1665,1809.4823\nScreenshot_2021-02-11_at_15.13.38.png,pushups_down,1005.51654,1023.99976,-1875.1879,1019.3516,968.8724,-1911.0332,1034.8453,958.02094,-1910.6764,1050.1694,946.9519,-1910.7515,985.1734,987.2575,-1866.1783,974.56635,991.9339,-1865.6432,964.36725,996.964,-1865.5569,1109.5958,904.91376,-1746.532,993.90265,973.9985,-1555.0392,1078.4287,1016.1015,-1784.8322,1038.506,1042.5469,-1727.1025,1389.8016,928.20056,-1399.7753,1059.7048,888.61725,-1087.137,1637.2744,934.8928,-1042.1835,1074.4166,840.7522,-355.53168,1633.3792,1096.4961,-891.04364,1047.3553,1011.64526,-172.89491,1656.5002,1115.5858,-993.76733,1024.8739,1045.2396,-221.05817,1611.1304,1125.4618,-1034.9761,1037.6332,1049.701,-297.47696,1587.7472,1116.8759,-911.8256,1057.6392,1042.64,-203.63712,1582.5498,907.2232,-150.98685,1453.3718,890.6267,152.49554,1688.3799,867.0051,906.5616,1591.8033,911.39716,1185.0875,1758.7301,833.23035,2087.037,1708.2587,883.6331,2293.6145,1780.2593,817.1664,2219.0544,1738.4711,855.78754,2419.5068,1772.8568,887.2087,2241.4248,1737.4473,977.308,2451.822\nScreenshot_2021-02-11_at_12.03.27.png,pushups_down,1147.9552,989.9279,-682.3653,1164.4843,985.23175,-766.14545,1179.0421,985.0706,-766.09686,1193.184,984.6025,-766.2862,1124.3599,977.8107,-763.5705,1110.635,972.45514,-763.1074,1097.0891,966.93176,-762.9066,1218.4631,938.5894,-880.08167,1082.5437,914.714,-863.6013,1175.6083,956.1375,-690.74066,1133.2697,949.951,-683.8512,1367.1323,818.78326,-728.72516,957.90845,767.8392,-709.43933,1487.1273,728.84033,-369.81833,859.6546,726.6345,-381.95575,1496.0726,869.5444,-248.45572,848.2233,932.3658,-197.96515,1523.2028,891.7473,-305.89813,810.563,974.7506,-227.90205,1490.3224,905.049,-309.75525,858.6552,1000.28625,-248.99692,1463.82,894.0991,-247.08476,884.5249,983.4267,-204.54953,1287.443,615.7243,-35.498245,1087.47,575.9436,36.873486,1314.4902,651.6692,865.1292,1114.5725,594.56915,923.25885,1304.066,602.8119,1722.7119,1178.5651,586.67444,1802.7,1298.5695,570.6603,1824.5226,1195.2844,561.57007,1910.2745,1336.3378,709.2528,1908.449,1162.2145,689.4586,2000.8556\nframe__3HwW3mEM5Ws__0013542.jpg,pushups_down,331.37747,759.97815,74.82903,306.96915,740.075,21.748877,305.71658,735.4182,21.691498,304.32053,730.464,21.521114,309.7526,740.50793,91.124596,310.75003,736.45984,90.97733,312.10855,732.4026,90.619446,313.37503,694.89685,-103.065834,323.42596,701.14197,213.24628,353.40997,746.4542,37.966747,356.7757,747.84326,130.34695,416.1553,686.25836,-247.11102,480.08188,645.3141,428.97278,418.2263,870.9471,-251.20828,518.47253,808.17126,554.09955,302.20282,889.0233,-75.23453,387.3883,867.2196,524.34064,249.8287,897.88403,-141.27805,335.18277,873.87054,554.4288,253.08759,868.58813,-133.05315,327.09216,862.5165,525.55695,279.036,863.76196,-69.39356,344.3025,858.3788,510.1733,769.3025,636.4783,-213.24731,792.5514,616.5225,213.74191,1037.8977,749.84686,-179.77077,1054.993,736.6734,198.5773,1325.2585,807.2794,-166.0481,1323.0781,777.3318,264.97473,1382.7971,795.3164,-172.77997,1380.4274,763.4284,264.70056,1310.1586,914.5728,-283.1896,1321.9464,889.40643,182.45819\r\nScreenshot_2021-02-11_at_11.26.27.png,pushups_down,1167.037,786.36383,252.64165,1162.3612,792.47516,277.52682,1164.1405,792.50867,277.6075,1165.8704,792.27747,277.41904,1160.6763,796.1729,237.22786,1160.67,798.67255,237.41698,1160.8312,801.28687,237.67595,1178.1426,793.56885,394.99408,1169.9927,808.3531,227.0646,1185.1084,781.66046,295.38898,1183.576,784.5406,246.6969,1266.6307,774.6207,467.7051,1209.4033,795.4751,61.06363,1367.1782,818.727,395.2138,1180.9817,891.41644,-97.826416,1461.6726,867.623,311.08243,1190.0853,959.1221,-293.807,1482.5657,877.57635,334.74423,1182.3916,985.64874,-348.02,1484.0,882.6261,309.50278,1194.1847,965.2462,-326.27176,1477.069,877.658,303.86713,1204.1459,953.88275,-286.82544,1498.252,810.2964,146.42186,1461.605,823.6139,-144.32704,1505.5005,777.6124,291.246,1408.1459,884.5617,-203.82611,1411.1873,908.7368,184.14603,1374.0237,945.3078,-226.14143,1392.1398,911.688,160.89662,1375.1595,939.2484,-230.51263,1374.6127,966.7175,162.23056,1326.9973,1007.8637,-243.77881\nframe__cbCt69XAUKA__0012324.jpg,pushups_down,636.17834,653.84814,22.58714,615.5553,632.6703,3.205667,614.83527,625.20575,3.2602558,614.06525,617.4447,3.184982,617.7788,645.3461,64.74257,618.3081,647.33356,64.745155,619.1732,649.2588,64.484665,623.6415,586.19434,-19.33666,627.6223,626.1887,260.0791,655.9647,633.58203,18.575838,657.40027,650.7006,100.71056,708.7186,589.8317,-169.69327,751.03796,581.37885,463.9643,725.9917,802.7163,-46.341366,762.39545,744.935,559.73566,637.54675,765.9415,366.43948,652.62115,732.6173,501.55753,603.6612,764.68555,360.41556,622.59595,731.62756,509.66833,609.5865,740.196,346.6735,613.6968,711.9521,506.92526,627.5157,736.54865,372.20905,626.4393,710.22644,494.96548,1022.93005,596.3504,-201.15706,1038.9946,599.5378,201.07301,1275.2242,706.815,-228.06725,1270.526,687.61035,178.07626,1538.5503,763.4091,-248.53815,1513.4377,740.0184,213.2001,1592.6017,751.26733,-252.5422,1562.6987,733.67267,209.31836,1552.2043,855.08844,-377.6049,1539.0975,823.36884,118.89043\r\nframe__UswHz7_nvZQ__0005691.jpg,pushups_down,890.16077,733.3239,-263.61316,892.1279,742.12726,-349.1188,899.17834,739.94763,-349.01025,906.3447,737.42786,-349.23572,868.1731,744.2835,-317.71936,858.4099,743.51654,-317.64554,848.8345,742.54156,-317.6798,917.95905,704.96106,-595.9367,837.71954,711.5397,-461.45157,911.5921,700.9264,-336.22736,887.7181,704.28156,-295.27808,1034.2039,579.72864,-607.4217,758.3415,589.5751,-385.41022,1180.6929,646.7938,-480.83154,751.3214,638.2755,-44.238857,1052.0801,834.62244,-419.94327,740.99255,759.45807,77.8403,1046.1921,882.80225,-487.39145,720.3058,787.86176,39.436085,990.36346,861.36914,-530.91766,733.0824,788.64996,16.541552,984.772,840.8438,-440.068,752.3338,776.6428,64.945435,1116.6174,366.2169,-103.61522,968.67975,373.49158,105.02745,1243.9047,394.12357,450.78506,1023.10785,437.7554,723.13574,1281.5334,333.28134,1095.1439,1063.4515,401.21045,1457.8195,1274.9116,309.9323,1172.0801,1071.1906,373.53137,1536.8735,1335.7349,373.0598,1205.2833,1083.2006,458.92874,1561.6046\r\nframe__j2yXx2--Zjs__0000735.jpg,pushups_down,1077.1002,798.3124,-461.74088,1091.2681,772.6934,-444.30872,1091.4917,769.3484,-444.18274,1091.7444,766.4024,-444.40042,1085.1458,774.0672,-499.26923,1081.0963,770.5907,-499.2309,1076.9655,767.22974,-499.48236,1066.0302,728.755,-303.9249,1047.395,731.60065,-541.6953,1046.9065,785.0377,-397.1592,1041.3884,784.45996,-464.94516,968.22406,638.0863,-136.16783,873.25867,726.7731,-507.51675,842.6802,626.0226,144.9499,686.66754,748.5071,-414.09372,850.27655,724.3956,300.5447,752.47424,896.7306,-291.69672,870.6378,732.5183,304.7,772.56525,935.26697,-340.6986,879.7816,744.59546,260.25363,807.82355,920.4954,-324.55023,864.9268,745.48065,284.64835,799.842,902.4925,-284.34903,667.52673,646.9689,135.85542,604.96106,692.5562,-135.61897,486.01346,671.4089,390.2377,413.83255,687.69946,149.6548,311.72598,638.28217,696.0575,236.1981,648.1165,425.6898,277.72614,612.54175,732.18665,199.73007,622.7775,455.76123,298.94672,718.31805,785.44745,231.35716,724.8878,446.8066\r\nframe__8p9Wv9Myu4E__0013580.jpg,pushups_down,1265.6984,727.80273,23.62637,1288.9414,730.73517,50.927723,1290.9133,729.3656,50.8547,1292.7999,728.372,50.565487,1289.3486,728.7869,-10.92538,1292.1226,726.37274,-10.77531,1294.7626,723.82166,-10.906069,1304.1294,710.9625,173.2437,1307.6045,704.9655,-108.91448,1259.2931,714.6131,76.499596,1259.7612,712.1364,-5.359291,1239.9702,635.5701,358.71378,1257.844,664.793,-231.88506,1247.2131,757.20135,470.1668,1265.9192,801.9443,-268.74292,1350.4447,770.5444,334.41846,1357.6106,783.55634,-35.54299,1376.8518,771.53595,331.83118,1386.3689,780.4237,-71.55615,1388.7467,757.57446,311.4031,1381.852,767.85565,-54.58004,1381.2026,759.11224,321.43237,1368.4482,768.08575,-22.20864,967.2908,519.8186,194.29684,966.08264,524.2655,-194.14291,789.3199,625.06616,249.37166,787.381,650.2994,-71.808075,614.18964,714.7581,415.4124,614.86316,751.6641,61.211163,575.03656,719.92035,421.8911,574.98096,755.7068,67.69928,631.52496,784.96124,296.11078,639.6421,823.6175,-90.80558\r\nScreenshot_2021-02-11_at_15.24.30.png,pushups_down,833.897,1073.2268,-796.64026,812.7745,1055.3945,-871.738,816.0805,1051.4503,-871.47797,819.1311,1047.5391,-871.7479,806.20984,1048.6782,-797.87213,804.39886,1042.0413,-797.5563,802.7279,1036.1224,-798.20325,841.0883,992.4617,-982.9505,818.2691,982.9916,-654.8414,872.8186,1048.0768,-809.71674,868.8518,1044.2814,-714.7802,1117.3553,893.185,-948.0881,896.26276,850.50085,-357.623,1415.6439,822.1907,-785.11304,1058.4435,830.83154,166.9307,1382.3466,1087.0994,-445.30762,1053.7731,1023.8162,427.7266,1384.7831,1130.3751,-483.7784,1037.5618,1054.7035,393.0876,1332.5284,1148.6387,-511.78256,1032.6464,1063.5688,318.06522,1315.1864,1128.6896,-453.27927,1049.7139,1055.3032,396.77762,1547.5624,886.2965,-241.42822,1432.8854,867.23627,239.70462,1848.207,914.3934,291.0714,1633.3646,819.37933,857.99927,2115.678,861.72723,870.009,1790.2391,733.44666,1496.6573,2155.1565,814.7304,935.43945,1826.7683,691.01117,1566.9456,2169.8608,990.37897,896.1501,1815.3131,826.97894,1592.2662\nframe__7IyYtxdDqJw__0021597.jpg,pushups_down,626.2155,839.90674,-592.9243,616.4675,837.7365,-652.0919,621.399,834.4682,-651.82117,626.4253,831.0534,-651.94684,600.0299,838.3026,-595.88837,593.28674,834.5079,-595.7744,586.92035,830.55505,-596.264,638.99884,791.79553,-778.1119,583.31024,791.0455,-513.3137,654.39813,814.4407,-621.8499,639.8512,814.55225,-543.4549,793.7125,715.8733,-831.8572,603.79626,652.92377,-337.25015,782.3571,943.2836,-975.9456,538.24585,868.97784,-297.3025,561.5339,1019.32214,-1085.2749,420.43304,975.72095,-560.7728,473.65002,1034.1229,-1227.2719,339.9132,966.9464,-651.973,452.55884,972.28564,-1197.1709,355.72293,968.48315,-728.5693,474.6781,969.1125,-1089.0532,391.50537,979.27356,-609.9442,1106.1869,688.01886,-185.5118,1020.6294,664.7435,186.24654,1351.8367,757.72705,133.41711,1255.9672,742.6868,451.4869,1567.4547,779.08734,514.80237,1480.7682,763.5053,906.2052,1608.0122,756.59503,552.4652,1531.7605,742.3074,946.8725,1574.5719,845.885,432.69812,1491.0396,857.08496,850.6658\r\nframe__A61dLcsS9Ck__0001399.jpg,pushups_down,390.03415,674.65106,37.29618,377.43976,651.63007,-2.021196,377.99417,647.99854,-1.9782592,378.40353,644.1727,-1.9650997,379.69397,652.7647,63.950092,381.54562,649.76416,63.87358,383.4629,646.7932,63.578453,399.7736,619.1842,-125.82141,404.83792,623.9677,175.40648,418.05215,670.04645,0.5051278,419.72302,672.4591,87.37259,517.52527,660.6268,-301.2677,550.51154,595.7039,348.68573,668.834,737.5708,-300.87622,694.7883,626.67255,506.33725,606.6642,842.76715,-92.16606,635.67145,712.70013,513.80444,586.0777,869.8292,-102.21409,613.8185,721.8985,526.5519,560.93396,854.29785,-90.81093,597.7505,734.4882,481.52716,570.41595,841.9332,-81.30168,605.28577,734.7683,488.90002,841.0924,736.36945,-206.15466,851.62714,687.7103,205.4757,1113.8629,775.55286,-150.1267,1111.2587,702.01746,204.98044,1387.6561,738.50165,-83.43195,1358.2924,694.5943,296.13947,1423.9143,704.02234,-77.99281,1398.2443,671.1818,297.39328,1451.2124,811.26965,-148.87231,1408.5853,763.643,243.92084\r\nframe__S-cQ8SHmkNE__0000706.jpg,pushups_down,1349.0879,828.2475,-85.18763,1364.0774,810.97754,-52.87684,1363.8455,807.74506,-52.655453,1363.6826,804.6458,-52.944786,1363.4556,812.2699,-126.03952,1363.1549,808.8383,-126.02417,1362.6771,805.37463,-126.2753,1349.2195,774.48755,86.18927,1346.344,776.6687,-232.72562,1327.2947,816.9341,-28.322979,1326.5696,814.5221,-119.350845,1233.1421,719.1698,283.318,1246.321,745.5287,-383.34253,1151.4208,703.9544,650.1113,1149.9259,759.9115,-810.6153,1197.0864,775.14655,982.75415,1231.8945,844.30084,-1132.1984,1215.3313,789.48303,1042.1471,1257.616,857.7195,-1188.9149,1222.3542,790.83276,1000.8655,1265.8495,852.32635,-1165.7893,1214.1017,788.8942,970.9923,1251.6808,847.5316,-1124.6981,937.4305,735.9104,213.56364,938.97235,752.6459,-213.68283,733.9448,744.06006,307.6129,718.46045,778.3236,-156.7561,540.55,734.2598,417.40366,506.18356,758.2153,-147.11423,501.51764,714.8321,421.00732,462.7997,732.6184,-151.56432,505.73938,807.9998,352.16644,470.3174,825.9455,-261.28128\r\nframe__q6NIWNnvOK0__0020563.jpg,pushups_down,272.82635,561.0322,-3.0424953,257.5878,540.2993,-54.39816,259.21194,537.7046,-54.281933,260.6637,534.8331,-54.489906,257.71585,538.414,6.7026935,259.3285,534.5433,6.8049,261.359,530.46515,6.631422,282.02505,509.79602,-152.118,282.33353,507.20483,125.433525,302.03613,558.0099,-28.678167,302.0904,555.9313,52.9893,417.55804,547.33954,-276.19223,446.95303,448.68933,348.43103,410.7981,774.70056,-151.31285,456.7925,661.01306,418.21515,263.8797,735.4966,103.8409,282.1095,697.81067,516.52515,212.34479,746.3237,35.95907,224.6022,706.1341,545.3807,214.89865,699.5364,7.56555,218.682,684.56055,542.9831,243.41452,687.2027,95.95875,240.67578,681.2479,512.7731,867.4764,389.03912,-217.70123,856.76874,347.93686,218.47583,1179.5398,543.7934,-141.42496,1154.1296,515.39667,237.05276,1508.8152,619.68695,-104.75359,1464.419,608.55585,321.02844,1580.2745,605.86304,-107.00651,1534.3953,595.33154,324.31586,1487.8491,770.6694,-211.36758,1469.3488,769.6488,265.55872\r\nframe__IabsFQG2uyU__0003044.jpg,pushups_down,572.373,799.5177,-95.68728,553.4743,777.6635,-149.47437,554.485,774.46936,-149.42468,555.44336,770.9933,-149.77916,552.96277,776.78296,-89.080185,553.6693,773.6176,-88.942345,554.703,770.3489,-88.95963,574.56335,742.8094,-252.491,571.5452,742.1279,18.203985,601.32056,792.056,-122.31154,600.5951,792.2787,-43.520626,711.78186,777.6108,-368.2348,723.83435,697.40497,237.51239,734.84656,965.38245,-291.30322,735.95447,879.25134,308.57828,591.91907,937.7364,-57.830677,588.82007,921.67737,329.144,543.77966,946.28546,-117.82025,538.15576,929.233,328.70706,541.3077,911.8199,-139.42874,537.01544,916.46533,326.54385,566.76746,901.9379,-65.03646,558.401,913.15106,318.82883,1105.7662,733.1276,-197.92798,1092.7181,688.2638,198.87503,1360.1519,811.731,-126.217636,1317.1592,775.4058,277.31152,1622.0258,839.44324,-75.64929,1546.9469,812.398,402.46762,1677.111,823.38464,-77.44521,1601.6646,794.702,411.63565,1615.8884,947.7506,-163.13847,1544.5972,938.90125,380.55\r\nframe__hxjKZcOT17E__0005884.jpg,pushups_down,689.9227,577.177,-113.92135,672.4901,566.28815,-155.4973,672.2563,563.53467,-155.4031,671.998,560.52997,-155.44339,672.419,566.27576,-98.72667,672.3719,564.088,-98.59157,672.56195,561.85956,-98.781044,679.3631,537.53314,-241.69618,679.22656,539.60065,13.41061,707.96356,566.4453,-138.56404,707.9856,567.88525,-64.0031,760.473,540.26746,-350.87433,772.4973,502.83856,206.93393,772.715,679.3061,-290.4184,792.7267,637.99365,245.66881,680.8685,649.2877,-31.992702,708.8384,645.1007,157.79836,652.6537,652.1442,-67.426926,685.58344,650.1959,153.76735,658.5576,627.99744,-86.8548,681.4911,630.40796,153.57399,674.5477,621.71985,-34.269413,691.5248,627.3821,150.99025,983.9382,511.3922,-175.10733,982.54156,492.90765,175.47438,1147.1262,565.06055,-72.21809,1134.9563,546.52155,276.1465,1316.0007,589.18207,15.4799185,1286.9272,571.9498,423.81137,1355.0665,582.271,18.253902,1322.6892,567.7032,433.778,1312.205,661.258,-76.994705,1287.8765,639.3186,374.24878\r\nframe__EKJoeNhkNzU__0001939.jpg,pushups_down,1252.0532,755.1876,52.92388,1269.8207,739.541,59.123596,1269.605,734.5341,59.340134,1269.4839,729.6445,59.23217,1269.4252,745.81744,-0.6670601,1269.6361,744.5535,-0.7375204,1269.6477,743.19226,-0.82478774,1261.7659,703.32715,128.32294,1262.1654,722.6105,-148.5966,1234.0686,744.441,90.1155,1234.653,750.458,11.196196,1154.9131,651.68665,306.04697,1180.9158,738.722,-284.49854,1128.6482,766.80817,470.13428,1151.5887,911.6102,-255.96823,1240.2322,816.87384,462.97977,1261.8064,884.01715,-46.41748,1279.7404,830.20764,481.4063,1300.3059,888.9046,-89.60927,1283.3931,830.5151,456.28018,1298.6934,858.10596,-107.12383,1268.2617,826.6589,448.3683,1280.7166,853.9859,-48.8331,900.2654,704.6836,199.14401,906.9041,752.14105,-198.65616,706.5376,741.3659,277.1728,697.7689,780.98914,-170.9388,517.8414,757.2143,436.76102,500.8192,780.1841,-114.63967,477.20578,745.84534,450.38123,463.96896,764.2081,-116.42126,509.7132,833.74316,404.82138,483.75726,846.999,-222.81288\r\nframe__RTF4ADblouI__0006276.jpg,pushups_down,2847.4807,1473.1564,-920.50964,2894.218,1386.2728,-881.82635,2895.3145,1378.3204,-881.64935,2896.6091,1371.5712,-882.4415,2877.37,1385.803,-1009.8777,2866.067,1372.8434,-1010.1917,2854.2307,1360.165,-1010.26636,2823.0012,1278.9977,-612.87,2764.5212,1266.4952,-1144.1641,2757.9717,1459.0297,-797.507,2739.1506,1454.5322,-948.78357,2492.164,1236.9648,-296.17456,2297.5464,1291.5709,-1324.6244,2507.0146,1706.2538,-372.44934,2236.0808,1876.9856,-1469.0741,2834.4946,1899.5897,-1058.2354,2755.6313,1946.7979,-1618.6271,2993.0315,1902.9486,-1215.3276,2934.1255,1988.6937,-1862.267,2992.165,1880.7539,-1299.779,2944.717,1856.8619,-1892.1431,2902.5898,1890.9226,-1133.3802,2874.4844,1836.7079,-1652.8519,1416.9985,1370.9421,362.02484,1285.3608,1402.0654,-358.59842,931.8096,1455.9138,1065.3783,756.7124,1512.6366,477.30606,523.3518,1387.6691,1914.2473,300.149,1521.4862,1108.358,431.58267,1320.454,2002.3995,193.09227,1450.4341,1166.0101,455.76038,1596.3208,1993.2191,261.26508,1778.2972,1000.5738\r\nScreenshot_2021-02-11_at_12.43.21.png,pushups_down,1135.559,948.9763,-1536.9789,1152.1075,924.73303,-1557.0598,1164.1234,925.2215,-1556.7079,1176.1705,925.54425,-1556.9539,1119.1678,918.0268,-1539.7714,1106.9478,912.9694,-1539.231,1095.1417,908.5372,-1539.3936,1193.0775,900.9147,-1417.3619,1080.8811,882.9993,-1351.0583,1157.1316,951.28436,-1461.5118,1120.4233,945.7081,-1439.9541,1333.0798,884.9999,-1105.2972,1006.4988,854.78937,-1147.8522,1496.8204,977.4352,-1192.7997,865.295,933.95135,-1036.5891,1613.3971,1140.3539,-1348.491,798.6038,1073.7283,-1147.6565,1655.7493,1164.177,-1460.3723,744.6366,1083.1116,-1252.719,1631.4222,1174.4268,-1496.2578,777.61334,1101.0999,-1293.3499,1600.9705,1172.8553,-1377.516,812.39197,1103.9131,-1170.4297,1375.2643,903.7747,-36.163967,1260.1299,908.2493,35.83845,1515.6431,895.4193,766.83203,1400.7328,860.19525,790.3109,1480.1895,894.23254,1822.9464,1451.9492,896.2013,1752.6664,1463.7942,885.8605,1936.2781,1442.0605,901.2945,1859.9204,1501.6088,918.0302,1949.9241,1512.1265,911.63837,1851.8826\nScreenshot_2021-02-11_at_14.43.19.png,pushups_down,1690.0742,783.3283,-533.01843,1716.743,751.12354,-503.05118,1718.4908,750.20105,-502.83878,1720.2505,749.87396,-502.9739,1705.2983,744.49225,-569.95984,1699.1979,736.9915,-569.9724,1692.9316,729.6152,-570.2494,1688.4739,716.69775,-314.27423,1652.8306,690.70276,-596.2355,1649.7932,783.4196,-449.59283,1637.369,771.06366,-530.15643,1516.2524,682.3632,-65.905014,1409.4902,667.0489,-592.6807,1425.8492,661.4619,354.36838,1130.161,613.2657,-609.3259,1494.7303,816.73535,717.0807,1179.1179,838.75,-661.67053,1526.1592,841.4739,728.48,1192.2223,896.01013,-741.02045,1536.9066,854.44354,683.3828,1236.3993,892.9232,-736.2118,1514.7048,845.53906,702.45905,1229.8234,872.9851,-659.5904,1008.6414,666.1895,187.70236,966.99994,654.5851,-186.80519,675.22986,651.1215,504.3477,642.91174,661.39636,233.35905,369.70242,620.9261,871.2934,333.15613,607.9138,593.49664,316.70166,586.21155,898.2255,279.29578,561.4425,623.2697,318.63275,719.48444,795.4673,277.6427,743.9576,519.23706\nframe__SOyAVe-cUzA__0004852.jpg,pushups_down,1403.6049,648.0551,-544.73584,1429.6838,642.34503,-496.13715,1431.5756,650.69916,-496.17587,1433.5153,659.2381,-496.32202,1423.4855,617.45056,-537.4699,1420.5918,605.4498,-537.3146,1417.4597,593.6577,-537.349,1410.9254,654.1681,-227.17166,1389.1455,570.26654,-400.90863,1373.9321,668.05084,-439.18146,1364.6953,631.1577,-488.1947,1256.6759,618.0564,89.918396,1243.8186,641.16064,-508.3994,1236.1163,811.8761,84.057274,1184.0431,863.9594,-556.63885,1368.8743,827.5361,-126.502335,1387.5405,848.2619,-489.2331,1412.1439,834.3727,-165.15309,1454.2119,859.78534,-544.3764,1420.7533,810.9839,-164.95682,1454.3582,814.60516,-554.71924,1397.6478,811.481,-140.49103,1422.397,806.4481,-490.21225,830.8619,665.19904,199.18275,808.9894,689.69867,-198.44923,582.23474,731.2763,360.0041,511.5182,722.3745,-18.785143,354.6311,736.3875,654.2858,264.48938,690.6412,156.79813,310.69635,714.4573,680.931,215.42484,657.2881,174.05807,296.28387,842.796,688.2462,207.6226,776.35864,81.763054\r\nframe__RTF4ADblouI__0001576.jpg,pushups_down,3213.9875,1734.6984,-1224.5242,3249.8237,1651.1143,-1156.2959,3247.2505,1642.8596,-1156.1042,3245.1094,1635.8434,-1156.5499,3237.2043,1652.6249,-1319.055,3226.465,1639.5378,-1318.8177,3215.4802,1626.5267,-1318.5182,3149.9727,1532.6615,-758.2238,3112.0227,1522.999,-1439.998,3112.3076,1709.0314,-1051.7493,3100.915,1696.999,-1246.7234,2773.3044,1373.3782,-400.65662,2556.057,1475.5422,-1386.8931,2346.0635,1321.0941,93.33833,1881.1561,1297.305,-1289.4814,2218.8418,1643.1011,243.7753,1779.3213,1792.1787,-1162.4126,2238.446,1680.7335,265.60236,1753.997,1933.0792,-1303.639,2248.303,1759.4946,116.15338,1865.9198,1928.2867,-1285.6375,2213.258,1747.3188,188.2552,1865.6536,1865.7524,-1151.9186,1701.1041,1456.0481,364.55814,1550.5771,1526.71,-362.59717,1137.9719,1566.5332,1029.6549,959.5626,1556.8817,562.06384,653.9883,1516.3203,1915.5659,473.19647,1490.1449,1404.2386,575.9459,1435.3993,2007.4768,388.76895,1419.021,1489.5104,545.2184,1753.5142,1972.589,392.90417,1720.596,1339.3931\r\nframe__J4sTsUuJzcw__0008954.jpg,pushups_down,333.7204,522.5155,25.991203,327.83643,511.56186,2.4677799,328.40927,509.92453,2.435925,328.90576,508.16397,2.3725734,327.77408,511.36438,37.44751,328.3332,509.7856,37.45002,329.04373,508.18594,37.337513,337.90228,496.27496,-54.107513,337.14523,496.70355,102.67251,345.69687,520.8934,7.531184,345.4448,520.81604,53.387215,386.24365,510.31485,-132.65448,412.9187,489.9105,203.55023,392.9157,605.0788,-79.95212,428.1739,578.58246,228.75365,350.8171,593.3154,64.44438,366.48892,585.1358,210.40887,333.23636,595.8482,39.27487,345.596,587.55005,213.56422,337.3853,582.25665,27.723333,343.0298,577.5308,213.16446,347.74582,579.14386,62.05689,350.68985,575.2977,206.55609,541.81946,485.8725,-104.01521,553.7368,477.9828,104.3176,656.4011,528.8217,-90.20938,663.75195,530.52313,87.05826,784.64264,550.87335,-94.777,782.88574,552.12256,100.012825,812.6832,544.6019,-97.71886,809.6595,546.4762,97.32109,777.42737,598.8472,-138.23148,781.2352,601.08716,60.74709\r\nScreenshot_2021-02-11_at_15.14.44.png,pushups_down,978.11597,1061.529,-1580.3256,995.7401,1000.3595,-1626.6921,1012.02795,990.25775,-1626.3168,1028.1079,979.98865,-1626.069,962.76495,1014.8173,-1560.26,953.8276,1017.4571,-1560.0952,945.2824,1020.50476,-1560.372,1093.635,934.72943,-1534.292,981.0461,991.6214,-1242.9857,1050.0234,1058.2017,-1521.1278,1011.6748,1079.4258,-1434.8683,1375.207,960.0999,-1235.5829,1071.007,918.55,-871.3295,1635.9877,932.9116,-927.6257,1139.2706,846.91034,-194.48253,1616.1411,1078.9799,-757.3512,1105.81,991.04816,89.129135,1627.4176,1095.3241,-840.8972,1074.5562,1014.3929,84.44439,1583.1667,1101.5173,-870.44836,1083.9543,1022.5082,20.690443,1566.2953,1093.9408,-771.04315,1108.1447,1016.49023,69.17921,1613.2058,934.2831,-171.04503,1490.1066,914.90845,172.80151,1741.0171,909.0657,749.91565,1647.2759,943.44775,1076.7684,1823.3119,856.8371,1831.5778,1764.0063,890.0657,2104.338,1847.2827,835.6925,1953.2269,1796.4475,849.7214,2226.094,1829.1755,931.4145,1957.4022,1781.4911,1003.02594,2268.1335\nframe__3a8QJhuFZx8__0016348.jpg,pushups_down,404.57895,708.41425,-131.81912,382.7104,690.3411,-189.17567,382.68912,687.15247,-189.22493,382.60345,683.5422,-189.45512,383.41943,688.38513,-125.18764,383.94955,684.6768,-124.93996,384.89288,680.8719,-124.84042,396.89313,654.48816,-303.12796,398.02185,652.18396,-1.2239505,430.93164,699.47955,-162.41643,431.99457,698.9791,-74.16698,515.0431,675.2792,-425.99393,547.14215,612.35223,260.7513,507.35663,886.1177,-363.91272,525.06274,802.3335,327.70148,391.66925,851.61005,-109.41848,397.4526,817.87616,215.58115,348.2535,859.2689,-167.60774,352.91638,819.0939,200.36008,356.7816,821.473,-189.09717,352.0153,799.9232,200.7344,381.92844,814.02936,-112.643105,370.18073,798.78033,204.82521,891.88434,657.6156,-244.81404,895.83936,620.4877,245.356,1151.0955,787.11035,-220.48248,1061.7883,693.2814,720.965,1416.6279,826.437,-265.6152,1246.473,698.6988,1162.0388,1476.2013,806.4842,-276.80637,1295.8195,680.5431,1206.5276,1410.1295,952.65497,-400.1617,1242.0261,813.1748,1212.4861\r\nScreenshot_2021-02-11_at_15.01.32.png,pushups_down,1130.9978,992.6692,-617.90063,1107.985,974.94965,-672.8376,1111.3793,969.6691,-672.6996,1114.8079,964.3845,-672.7823,1097.1655,976.499,-611.2511,1092.7816,973.22327,-610.8319,1088.66,970.0912,-611.0641,1130.6064,917.74255,-737.96545,1091.7927,922.144,-458.9098,1164.6532,963.5167,-620.2637,1154.1464,969.5211,-538.599,1379.4492,848.0801,-688.0359,1153.3601,767.92566,-260.8676,1640.19,809.87164,-492.94138,1250.5867,717.7817,119.90557,1546.9022,955.62665,-180.25446,1216.2714,860.4077,303.49524,1535.3148,988.9768,-211.95886,1195.5465,882.60046,290.6315,1489.7926,988.4514,-224.86743,1193.7305,896.73883,265.4636,1481.465,967.42017,-179.12505,1209.2156,889.1377,292.85928,1692.6359,783.5228,-185.06482,1595.6532,731.9829,185.39233,1892.832,753.836,341.47882,1828.1222,711.0382,653.79596,2057.5852,693.48773,911.01013,1988.0172,667.6423,1183.5289,2089.6985,656.37994,971.8057,2020.8282,634.7573,1241.5221,2076.9895,784.8954,983.3792,2011.3344,765.59515,1246.5265\nframe__SOyAVe-cUzA__0006158.jpg,pushups_down,1551.2864,850.0225,-113.88691,1586.3245,835.1016,-92.93708,1587.7206,831.8437,-92.78882,1589.184,828.78033,-93.116714,1585.0854,834.843,-173.0484,1586.1503,829.46484,-173.11716,1587.1262,824.09973,-173.40941,1586.2118,786.2181,40.98189,1583.541,782.0816,-301.97427,1527.527,828.4426,-47.81007,1527.3059,824.4085,-146.53131,1445.699,672.7977,240.16457,1447.5062,725.3097,-409.05975,1270.9346,669.67694,510.8931,1226.8888,709.314,-570.92004,1308.1058,817.84845,655.7482,1284.9833,884.52234,-702.30475,1334.2797,844.50586,683.0168,1310.6978,928.18604,-774.67224,1355.988,867.7357,630.36487,1337.7286,926.5233,-739.2332,1344.3384,859.2559,634.15436,1323.5092,909.6548,-686.4802,998.3054,691.26373,211.02713,987.5387,726.52075,-210.63382,715.4758,708.13885,393.18564,694.78156,733.16064,31.38104,468.7768,694.8699,637.8243,433.8225,697.2176,258.65607,426.23462,665.61096,657.53284,389.61423,659.9357,276.7936,420.97263,795.22797,584.04443,380.61102,798.0983,178.12819\r\nframe__iGZUw_fn0X0__0010426.jpg,pushups_down,1109.3339,955.11865,43.39494,1128.3425,943.64246,62.873806,1129.5715,941.25806,63.03987,1130.9325,939.03467,62.795685,1126.4124,944.0598,3.264008,1126.836,941.57513,3.3899903,1127.1096,939.0541,3.153532,1132.51,916.1302,165.11536,1126.6774,916.50366,-99.68697,1098.4183,945.2452,90.93304,1096.5055,944.5559,15.527415,1073.3832,870.25635,340.1366,1059.8427,889.8258,-249.88583,1025.1807,883.88684,597.77527,953.8942,922.3773,-413.31042,1047.7742,942.1423,751.92285,1003.4593,1004.91235,-447.4817,1056.9135,954.4793,793.4762,1017.5917,1029.0355,-481.10883,1063.5354,957.34515,765.9747,1033.835,1016.8248,-468.4005,1058.9019,958.1302,743.3096,1025.1912,1006.91974,-438.09213,821.5895,866.8347,197.47726,804.10095,874.9255,-197.6751,613.57635,886.9684,192.81271,585.4858,915.39294,-236.5929,413.15894,890.4682,255.52362,374.02792,916.4344,-302.42493,379.54715,874.7327,256.53043,342.6189,888.59564,-311.321,363.34534,958.2841,181.8541,314.37854,1004.3857,-415.4051\r\nframe__CI3o5FYbtOo__0000500.jpg,pushups_down,477.99933,736.58276,-35.223633,461.85263,715.46405,-85.39211,462.9911,712.43823,-85.44505,464.0161,709.17065,-85.787674,461.0632,714.619,-30.669004,461.6691,710.9297,-30.404488,462.54788,707.11975,-30.136961,481.84686,681.1847,-184.66469,478.12534,681.4388,66.17952,504.66992,730.44745,-64.08391,503.6356,729.3244,9.103222,604.9891,707.3751,-292.8215,629.8057,646.70087,265.2864,630.2085,900.1512,-200.95709,645.3199,824.22437,270.58203,519.4957,865.2107,9.934411,523.2675,848.93396,216.7118,475.96478,870.08746,-49.809013,476.35562,856.10126,209.13597,482.66052,832.9803,-80.190956,477.662,836.03723,222.89555,505.57318,826.3165,-0.7644712,495.84778,832.6986,211.1521,965.53,641.37164,-190.44934,961.3015,615.98553,191.4929,1247.9204,754.10315,-221.3156,1167.6792,705.66724,342.08133,1529.4752,777.16815,-274.25278,1392.1444,703.30066,504.83276,1593.3884,760.5389,-290.01422,1447.8958,678.99963,517.4337,1509.6407,905.6382,-424.91467,1384.2844,833.73987,486.51547\r\nframe__RTF4ADblouI__0004513.jpg,pushups_down,2945.765,1469.9797,-922.4591,2989.7222,1369.9426,-889.6011,2991.55,1359.4927,-889.6473,2993.892,1350.222,-889.93756,2965.958,1374.1962,-1046.3429,2950.3225,1362.5293,-1046.2792,2934.5732,1350.9957,-1046.4679,2912.2937,1249.5029,-605.2665,2833.316,1248.673,-1260.9988,2853.935,1452.4775,-784.0046,2828.0754,1452.0947,-970.9955,2572.0261,1167.0485,-263.68326,2299.5684,1237.9402,-1198.0255,2210.161,1220.5592,395.3416,1685.8695,1274.2985,-1093.3593,2223.5479,1635.4606,582.2062,1823.886,1778.5973,-897.1163,2282.9058,1686.5874,566.1654,1866.705,1908.6973,-1045.377,2314.828,1745.0729,419.24445,1974.5068,1875.3657,-1007.5097,2256.8052,1729.8519,525.1599,1956.1981,1826.3003,-883.16785,1605.3636,1369.4808,350.74875,1441.479,1392.6545,-348.9235,1072.9965,1545.2318,794.5962,864.6432,1491.8163,288.5757,608.17725,1535.5304,1546.7767,365.62317,1442.6763,933.9944,508.63266,1461.3325,1620.9849,263.78918,1370.4708,991.0836,561.10156,1790.1252,1624.2885,337.60645,1715.9958,882.9659\r\nScreenshot_2021-02-11_at_11.11.08.png,pushups_down,931.13153,881.8389,-1267.7894,938.69775,850.21014,-1368.4357,951.3537,837.38403,-1368.1288,964.1002,824.07385,-1368.3828,899.4464,874.823,-1341.2886,883.1284,881.1904,-1341.0613,867.35895,887.8046,-1341.2947,963.81067,761.7476,-1469.1799,829.4225,861.065,-1363.1467,951.08813,850.96344,-1260.4038,909.9301,882.1588,-1226.9176,1059.694,579.1313,-1159.0267,699.8407,756.1192,-1187.9387,1293.3022,595.41925,-973.1333,574.97296,754.5474,-839.58844,1393.8778,765.72034,-1047.1082,565.6961,898.38837,-827.313,1438.4655,783.6095,-1189.4148,526.0365,943.08405,-946.8901,1394.551,807.5119,-1229.9847,567.2432,929.66,-972.1231,1367.8539,810.6959,-1085.2184,594.1921,910.5855,-853.76514,1110.6888,609.80334,-87.335144,972.50684,715.1684,89.367,1279.8422,642.43097,802.0729,1088.7023,755.4521,956.4301,1242.735,613.29944,1838.3341,1129.6472,729.80145,1988.8555,1215.0034,591.751,1955.8728,1118.0106,712.5105,2104.3376,1278.7825,681.90247,1924.9834,1182.283,769.6623,2062.7258\nScreenshot_2021-02-11_at_15.26.48.png,pushups_down,1542.5739,1009.18207,-1480.1394,1568.9465,990.85175,-1591.1705,1582.6976,988.4226,-1591.683,1597.3372,986.9816,-1591.7131,1525.2866,987.81696,-1600.0962,1511.0447,983.3078,-1600.3629,1496.6389,979.17694,-1600.255,1615.1011,948.13086,-1551.268,1474.1448,931.534,-1647.746,1537.4524,998.8398,-1407.2892,1502.2876,998.89246,-1432.3485,1747.0143,770.8086,-1256.5942,1299.1434,787.41394,-1345.7504,1733.421,676.75793,-561.6081,1056.2312,660.0597,-859.6757,1711.263,955.94574,-271.56052,1123.7301,965.10364,-711.14874,1765.58,1003.25793,-295.3685,1093.7032,1000.6964,-853.55304,1738.1667,969.12213,-370.02386,1173.1793,1006.05554,-880.945,1699.6763,957.21265,-299.6055,1191.6476,999.87494,-729.3141,1412.7535,773.9856,163.7587,1232.7002,778.59814,-162.5276,1353.8757,667.4253,1415.53,1181.718,694.1978,1081.9463,1347.9156,572.02344,2609.811,1189.0494,573.7984,2224.0254,1351.4868,547.3796,2750.0989,1185.9331,527.95746,2361.26,1363.8224,607.7554,2758.373,1207.0181,638.96405,2380.2996\nScreenshot_2021-02-11_at_12.51.58.png,pushups_down,1138.295,935.80914,-304.03156,1149.253,942.4846,-359.174,1157.2296,943.43677,-359.25458,1164.881,944.17456,-359.2814,1129.2108,938.3171,-360.98846,1121.9233,936.5244,-360.78256,1114.6521,934.6156,-360.8432,1174.4303,933.26483,-431.38943,1104.1376,921.84863,-443.19897,1146.0931,928.22266,-308.44516,1124.5974,925.0928,-310.30862,1252.0131,885.862,-354.82693,1027.8298,875.4829,-354.6608,1314.7815,822.2942,-158.6442,971.16266,854.8393,-130.46375,1308.9497,893.992,-90.98405,1015.9532,973.77313,1.9998395,1319.4254,909.27783,-112.96651,1011.11456,1005.399,-10.91234,1298.1569,913.5438,-125.08131,1042.2778,1009.35724,-14.77509,1285.2708,906.6126,-91.97307,1049.0724,998.2846,1.4683864,1200.4073,784.66174,5.5647883,1076.8668,774.40564,-5.4938254,1208.8761,816.2755,530.3274,1068.0204,780.35815,506.51334,1216.0204,825.2057,1059.3363,1083.6183,795.6965,1069.0137,1212.6301,812.91095,1118.8833,1090.733,786.2733,1133.6079,1236.0507,882.1225,1134.9973,1080.7593,849.82855,1159.904\nframe__hglfthV89Zk__0002805.jpg,pushups_down,1443.8408,810.28033,-458.51358,1458.3242,784.0326,-440.29935,1459.0933,781.2242,-440.15707,1459.9484,778.9629,-440.26712,1450.9104,784.0508,-501.28384,1446.3379,780.0655,-501.23724,1441.6603,776.1276,-501.45383,1435.171,747.57605,-291.3837,1411.9675,744.6576,-556.554,1413.6085,802.80225,-388.64844,1405.8513,800.8399,-464.05197,1321.777,688.95935,-95.471565,1248.1344,751.75275,-547.7499,1193.4841,700.3059,205.72948,1048.5697,759.852,-491.116,1245.2567,817.4065,350.81024,1095.5806,901.52655,-414.25568,1273.4279,832.8719,338.438,1111.9446,936.18567,-478.13425,1289.4368,840.4263,278.25824,1143.3304,926.31714,-467.0027,1270.0516,838.8189,327.71326,1134.2361,911.7494,-408.6673,964.4045,738.8444,167.75131,925.07306,775.1557,-167.28409,774.8003,735.82007,528.7475,751.6571,760.9642,265.93433,608.51965,699.5253,901.8693,574.6594,706.5604,691.7653,569.3498,671.1376,941.5995,531.3476,678.83453,735.0561,601.80884,775.4853,926.7196,571.2146,774.3582,694.1665\r\nframe__tTFQh_EDN_4__0005052.jpg,pushups_down,566.4449,849.95325,-29.402214,545.05066,834.95874,-85.64631,544.4707,831.9059,-85.62849,543.85406,828.58435,-85.7536,545.87964,833.08734,-17.034431,545.94806,829.2637,-16.884047,546.26807,825.4243,-16.898705,552.05554,797.64105,-212.76115,553.59265,795.028,94.604065,587.0365,836.8859,-69.20208,587.9761,836.08936,20.383717,642.8041,794.0487,-358.7908,673.991,759.13605,303.89713,635.949,968.37976,-299.35056,681.9782,919.12555,356.93713,547.63745,951.0646,17.18291,585.2018,924.30927,261.7,516.0396,951.3218,-27.213837,557.4091,930.7406,258.01953,524.05835,929.5355,-38.762405,554.77765,910.541,251.58774,540.6618,924.94257,17.422077,565.226,908.0485,249.88203,924.15686,782.4189,-200.90776,932.0693,774.7746,201.47906,1141.9166,837.1056,-212.53131,1138.7238,838.7464,169.35025,1369.4639,852.2085,-194.60028,1351.1964,863.60345,256.92767,1414.7295,843.9962,-201.0575,1394.3398,858.06476,257.32568,1387.86,930.30664,-340.57233,1368.6232,939.2852,147.80566\r\nframe__4ZUNCOjTIh4__0000670.jpg,pushups_down,812.75543,835.22577,-857.38214,809.58466,815.57336,-898.58,814.7432,811.4747,-898.2313,819.86035,807.4149,-897.9626,796.74,815.3526,-859.6132,793.0629,812.4515,-859.32965,789.5713,809.88776,-859.4935,839.3069,766.3933,-894.21265,796.26917,769.86755,-721.17285,843.1092,816.02313,-837.6959,832.40985,817.3609,-785.5629,1008.84717,697.5625,-745.2086,800.5238,633.0298,-524.64624,1187.6211,655.57764,-645.1112,830.89575,541.14557,-144.66098,1171.8132,810.2905,-615.2418,861.95886,642.5674,37.561363,1174.0964,837.8264,-695.0305,845.87195,653.32385,20.955488,1138.1669,836.80255,-714.5695,857.65594,661.15497,-16.996193,1129.6084,825.9936,-623.6639,872.3253,661.3466,28.216093,1127.8853,627.4783,-137.50037,1029.5442,591.9675,137.08209,1261.7501,596.1,353.36542,1128.8369,569.8854,624.3917,1372.2867,530.8401,828.7788,1231.5481,500.33252,1147.5978,1393.7656,500.1406,878.73694,1251.7621,470.48666,1207.8192,1385.2318,621.8945,867.56323,1245.7396,570.67725,1261.2062\r\nframe__jJZMebnFIC4__0006034.jpg,pushups_down,217.97733,185.61174,-45.59675,214.49246,181.50507,-55.546684,214.71576,180.701,-55.553204,214.9431,179.84169,-55.574905,214.5778,181.84286,-37.65172,214.7957,181.38196,-37.606915,215.07547,180.91809,-37.628574,220.36157,174.03195,-78.20122,220.09303,174.6066,3.2167923,225.12408,183.03922,-51.93396,224.98865,183.86627,-28.197432,248.7737,178.27534,-116.26677,249.7016,167.28117,65.06424,252.32182,214.5959,-99.06447,251.36139,204.88261,47.333744,228.09058,213.40869,-12.566201,231.2433,209.30615,-49.091663,220.41801,214.08383,-21.164412,226.47247,209.96675,-59.13686,220.83313,208.52092,-21.949623,224.83847,204.80907,-65.73364,224.90073,206.37474,-11.194842,227.61331,205.04646,-55.68103,322.278,171.03564,-60.389744,320.75034,166.34543,60.49413,372.94455,185.5775,-77.98778,368.48486,179.66412,86.38713,428.18423,189.81639,-65.466194,417.0781,186.91234,129.34871,440.86374,186.91815,-68.70221,428.5093,186.22296,131.102,427.0707,212.29776,-118.676285,414.0304,208.32317,104.02979\r\nScreenshot_2021-02-11_at_15.15.07.png,pushups_down,998.74927,1071.9562,-1693.7721,1027.1759,1006.8508,-1723.8722,1046.304,997.5288,-1723.5331,1065.186,988.0728,-1723.5502,985.55,1020.8338,-1668.732,973.1482,1022.0799,-1668.5928,961.1528,1023.97595,-1668.6837,1125.4539,938.3975,-1561.3322,984.29333,991.5006,-1329.3735,1064.3275,1070.8341,-1608.1029,1017.10016,1089.2026,-1538.7612,1375.1128,937.2754,-1212.337,1013.69275,944.85443,-931.7674,1615.0338,922.0529,-952.1036,996.6006,854.302,-269.40887,1637.6029,1102.6552,-857.20776,989.65265,1008.17975,-23.996178,1665.6339,1119.7941,-951.0546,962.8886,1037.6171,-73.60244,1623.5471,1132.9062,-986.39514,985.47577,1045.7935,-123.30553,1595.0446,1129.3147,-876.51355,1008.07684,1045.1653,-46.28754,1541.7662,931.2875,-141.9407,1406.3716,943.4568,142.4525,1711.9127,868.8854,658.93744,1586.6083,940.8184,1000.301,1823.782,856.9899,1677.2285,1720.172,888.20544,1989.5585,1833.4,849.24036,1794.9426,1742.9464,857.4287,2103.0894,1875.2614,918.7117,1769.6741,1763.295,973.09186,2082.913\nScreenshot_2021-02-11_at_15.32.02.png,pushups_down,876.283,982.7893,-1030.9033,862.7667,948.2633,-1088.0692,867.8355,937.2005,-1087.6505,872.59406,926.1955,-1087.3612,850.6884,964.1748,-1016.2101,846.3626,966.7609,-1015.91785,842.3423,969.692,-1016.35785,895.5427,869.11816,-1086.4484,853.85925,931.3993,-747.886,920.2994,953.8622,-1000.511,908.6384,974.0967,-901.09717,1109.1102,834.87384,-920.00635,916.75195,813.0139,-391.4474,1319.4247,799.5047,-642.53314,1016.63544,802.44385,170.27545,1282.0201,986.888,-378.99466,1010.9184,953.9892,399.46506,1283.9113,1021.69226,-444.69263,999.29443,979.98883,378.4141,1233.8527,1029.7642,-459.96573,997.29974,985.81635,308.26968,1224.5139,1016.64526,-383.69812,1010.5487,981.10767,370.12375,1466.9023,825.63855,-234.23216,1372.7373,815.5322,234.56454,1691.1375,799.1517,145.72281,1563.9795,804.42487,861.3216,1931.6393,735.7015,621.648,1761.4723,751.1932,1522.6039,1973.4617,703.7937,669.0563,1809.5579,711.70593,1593.6803,1969.9175,847.1319,581.5482,1784.8397,882.1234,1620.5928\nframe__cbCt69XAUKA__0015364.jpg,pushups_down,1450.927,693.85657,-137.09622,1464.0701,673.36115,-120.29823,1462.1309,670.1336,-120.1492,1460.3103,667.2543,-120.248825,1464.1464,674.0555,-182.45834,1463.574,670.5103,-182.52618,1462.8179,666.8597,-182.77498,1439.5767,642.2605,12.321717,1444.1628,641.52374,-266.5425,1423.0089,689.3145,-79.50676,1424.2948,688.8494,-160.10774,1293.0228,615.1917,254.59276,1323.3206,660.70447,-393.677,1290.9413,807.5345,316.19586,1300.665,847.48785,-337.37003,1426.4462,814.2035,299.88733,1442.3002,829.3928,-110.587204,1471.5579,821.08685,306.3036,1489.2719,837.8949,-177.56299,1470.5665,796.4048,309.26398,1485.6804,805.89044,-210.75163,1451.5697,790.91125,292.1364,1460.4979,798.43964,-125.02052,1000.1406,567.9465,204.62663,1004.48834,596.225,-203.90521,765.89667,621.02313,281.61758,774.08887,655.42694,-93.27607,562.8107,654.4149,417.6752,548.10144,664.1838,51.54601,512.05963,646.1989,429.4941,496.35388,647.51587,52.43545,573.81824,767.01996,350.22116,561.1887,790.7246,-72.69358\r\nScreenshot_2021-02-11_at_15.30.42.png,pushups_down,854.5238,982.18256,-982.9089,847.1858,947.9985,-1038.8083,854.71124,940.43835,-1038.4097,861.9912,932.99225,-1038.2286,830.44946,954.651,-973.5987,825.1207,952.5008,-973.36304,820.0167,950.7968,-973.90967,892.2674,875.75165,-1048.5514,833.8855,902.1966,-747.5234,900.41675,957.64197,-957.5165,884.0179,967.5183,-869.16095,1131.5984,827.1161,-878.48914,903.9983,777.8353,-451.19067,1379.844,786.68085,-647.46136,1006.387,762.11676,27.169056,1299.1212,974.1415,-384.00647,975.72925,929.79126,238.03423,1291.9642,1010.744,-421.6406,950.7073,955.96295,199.37141,1235.6584,1009.0682,-444.94284,954.994,964.43616,155.55434,1227.3872,991.25995,-388.8818,973.32074,959.7523,218.23509,1476.4955,822.3661,-203.20044,1376.7117,796.42706,203.20782,1710.345,796.38464,247.02724,1581.2413,793.036,738.4676,1956.5215,742.0753,782.33075,1786.964,746.4155,1348.4633,1996.5616,709.89844,841.131,1835.8047,705.4174,1412.6443,1984.0945,845.04175,792.21216,1796.7097,873.7066,1431.8439\nframe__7IyYtxdDqJw__0021826.jpg,pushups_down,506.1667,848.1396,16.329939,494.15967,828.26843,-34.683884,494.99857,825.89276,-34.6003,495.7275,823.2106,-34.846058,495.01123,825.61926,30.146942,496.5171,821.89215,30.157413,498.3348,818.1695,29.83217,512.2824,800.1593,-145.67798,513.7053,795.3595,142.8525,526.8252,845.7565,-16.43653,527.8192,843.8633,67.49691,600.978,830.42676,-288.97235,647.7553,780.5649,341.13278,563.577,1008.955,-244.62965,633.2041,951.94934,386.89087,445.2191,986.32666,-80.552986,485.84152,950.0326,406.2565,405.28644,991.6631,-150.61105,440.985,949.6601,419.2481,408.4064,963.13214,-168.41093,439.69653,929.44824,415.26584,430.3378,957.9027,-86.81142,455.12296,928.32837,398.66278,914.5364,797.38983,-195.02924,929.64856,775.0412,195.58095,1164.4109,867.5529,-157.25087,1167.7023,856.16016,159.2329,1419.5242,889.1817,-138.30258,1413.4084,883.58685,228.40164,1467.2448,878.0059,-142.4261,1461.348,876.56696,228.62555,1422.2891,969.01086,-247.20007,1424.3916,966.8928,141.14195\r\nScreenshot_2021-02-11_at_12.58.20.png,pushups_down,1129.6407,1200.6665,-218.18889,1144.3588,1199.9307,-294.90268,1154.9468,1197.8807,-295.0654,1165.0869,1195.6879,-295.37964,1116.3213,1200.507,-299.46994,1106.5189,1199.4512,-299.814,1096.9333,1198.4143,-299.64664,1191.3054,1161.034,-378.726,1076.9443,1166.3026,-390.89008,1146.5536,1177.3578,-211.09778,1117.999,1181.2301,-211.03204,1276.7488,1024.073,-356.2306,986.2721,1024.3116,-405.64886,1418.4753,883.58997,-115.74349,879.67755,888.5788,-183.19829,1400.255,1060.1814,-163.81384,908.1889,1076.4576,-209.2278,1426.8955,1088.1251,-202.81847,880.63837,1112.259,-247.53525,1384.3984,1096.9294,-222.7395,925.6122,1123.6672,-262.5185,1365.6212,1089.8878,-163.41853,940.78186,1112.1656,-212.8722,1204.3516,862.0577,16.501715,1080.8025,857.0264,-17.04618,1208.7954,804.4988,675.64557,1098.5089,795.01575,663.2691,1187.8798,760.65393,1413.6658,1110.9788,753.98004,1386.0991,1185.9888,734.6773,1495.9714,1115.6016,726.9833,1472.5111,1191.2472,825.6939,1621.2721,1112.7594,816.7339,1631.8868\nframe___aYRTXZnZ5g__0007666.jpg,pushups_down,1459.3232,778.21423,-559.0992,1468.2568,749.137,-533.84784,1469.8585,746.4457,-533.90247,1471.4482,744.3349,-534.047,1456.672,749.73987,-590.363,1449.9084,746.22095,-590.20636,1443.0004,742.88684,-590.42303,1440.4636,721.20685,-357.94763,1403.2468,721.47107,-600.4078,1430.4927,781.0896,-483.18832,1417.4146,778.0773,-551.9517,1320.0023,698.13855,-133.33342,1232.2118,746.5578,-586.73,1234.4567,710.4908,203.95341,1038.567,745.56305,-482.7169,1291.5725,833.9238,398.9975,1105.9418,874.7573,-356.42432,1319.6135,849.5675,403.18658,1126.2195,907.42065,-403.9295,1326.578,857.8766,357.04297,1156.0095,892.6343,-398.25098,1307.6897,854.9369,384.3348,1147.9216,881.813,-352.71594,970.5968,729.89886,177.74008,927.6311,755.63617,-177.22752,813.2784,733.833,636.80835,757.18445,742.85175,366.194,671.6806,694.4656,1123.6213,610.25977,702.08,867.5618,638.08466,663.05493,1177.6877,574.7208,675.07764,922.764,658.0845,779.4716,1212.455,598.531,779.8739,917.49835\r\nframe__9bTERUS811A__0005464.jpg,pushups_down,542.5092,796.39386,21.073175,518.3984,777.0701,-31.72465,517.89453,773.42584,-31.673338,517.3421,769.4697,-31.9041,519.18695,776.70276,28.823175,519.34076,772.7453,28.972195,519.7958,768.7002,29.038197,527.6056,734.9937,-141.10017,529.0804,737.615,135.71278,566.47656,783.3559,-9.317095,567.3262,783.3935,71.713745,637.47577,743.4436,-270.1432,682.55615,688.10077,352.5727,638.32526,935.405,-212.59848,698.3091,872.91754,422.3699,520.6415,907.0996,62.15573,552.9345,885.06476,394.3918,475.79413,912.8869,14.827671,507.29297,890.46716,403.25397,482.82434,882.17914,-6.8119755,502.45032,870.6065,406.12057,506.1115,873.8848,56.364464,519.19745,867.14215,388.2157,1006.70654,703.4762,-207.11139,1014.0725,677.7419,207.53944,1277.3881,824.44745,-193.65277,1257.6033,779.17017,225.7179,1557.0881,865.3044,-191.01836,1519.4662,814.1647,319.5249,1618.5839,848.4776,-199.42607,1581.4838,793.212,322.8667,1540.27,991.6148,-310.06552,1515.8096,957.6416,273.47644\r\nframe__0S3Fz7p6WGc__0005209.jpg,pushups_down,1481.4333,582.3441,-56.92559,1495.189,552.56757,-38.97872,1492.771,546.9682,-38.754116,1490.5568,541.7626,-38.625965,1494.1576,557.26227,-120.65911,1492.6561,554.0955,-120.779,1490.9402,550.78656,-121.017395,1463.0402,514.0989,103.82807,1465.5785,523.97534,-260.7958,1447.3428,579.8898,7.5657015,1447.8729,584.437,-98.179726,1263.9513,510.34418,381.49228,1317.8427,564.50415,-445.04205,1240.8983,719.17316,442.7274,1295.1116,814.87317,-423.5587,1403.9377,729.97504,383.54404,1477.4368,780.8955,-248.77664,1467.459,736.8075,393.9294,1545.5797,790.4062,-358.88824,1468.2078,717.607,372.01428,1535.5085,740.7703,-394.191,1444.2245,714.56537,363.47998,1502.6378,734.15076,-267.7499,931.6805,505.18744,254.44035,944.4641,543.0074,-253.05865,640.9788,564.82324,314.9386,626.86395,591.6289,-226.27208,384.61963,587.5279,495.98013,322.622,596.814,-112.20566,329.33475,580.58655,511.12192,263.33377,592.6631,-120.50511,385.90417,693.2495,432.83893,328.49493,692.75854,-287.6363\r\nframe__cdWzb1eZpI8__0008780.jpg,pushups_down,1005.9473,515.88336,85.32483,1024.6543,507.80136,97.25045,1025.3582,505.52618,97.35799,1026.1055,503.3139,97.04093,1024.0598,508.77927,48.990395,1024.7612,506.08002,49.135548,1025.4021,503.43146,49.078323,1023.1565,477.48022,149.75711,1022.87463,480.874,-60.23039,990.61804,502.52356,114.526764,990.7777,501.43036,53.785954,927.08386,377.644,234.40189,944.046,471.35196,-154.83725,790.4853,358.65216,383.07278,805.26294,492.8715,-142.25085,797.26086,433.6291,496.34363,833.59985,582.9868,-42.798225,804.9474,445.23312,528.8094,845.7144,607.20044,-55.303,819.0024,463.59714,501.29367,860.46313,602.47516,-34.595226,816.3971,462.36945,487.15182,853.341,591.52795,-29.074356,653.1094,408.79675,131.58582,655.1385,459.12048,-131.2036,438.83185,431.47675,150.46338,437.06177,470.883,-74.58633,244.13693,431.735,238.07849,233.14694,457.4056,2.9327102,215.16281,413.40155,243.78189,203.22647,434.94595,6.6873083,208.52432,492.69064,202.7959,192.57092,526.05743,-44.843887\r\nScreenshot_2021-02-11_at_14.20.40.png,pushups_down,1368.5963,1029.5608,-917.5564,1389.603,1006.40295,-931.0832,1393.4266,1000.0061,-930.9649,1397.0125,994.23083,-930.46106,1374.602,1013.7258,-995.5709,1369.0138,1011.72363,-995.4095,1362.9584,1010.0272,-995.5358,1379.2845,944.2651,-791.8171,1334.3735,967.5879,-1083.8778,1344.1199,1003.73267,-839.6901,1331.4717,1010.0881,-921.44257,1341.6499,808.21124,-444.0936,1129.5381,921.726,-950.02637,1342.9315,750.861,94.040146,921.71027,880.27423,-706.1214,1388.2775,873.7168,523.5411,939.4908,983.73584,-462.97543,1412.9807,891.43054,555.12616,925.7642,1003.93414,-511.72937,1394.9008,906.9459,503.28784,957.47833,1008.1144,-519.2736,1374.3915,905.924,504.3511,968.9081,999.6086,-463.76706,933.48926,785.01746,237.33968,819.816,835.9386,-237.30054,932.55255,912.67413,861.004,879.3809,1044.334,-185.08205,715.22156,869.5777,1665.6105,633.1284,913.8461,487.38162,675.6098,833.3835,1757.5675,594.1554,866.2762,572.1383,657.05176,945.72174,1945.0693,562.4298,979.60065,704.63196\nScreenshot_2021-02-11_at_12.56.31.png,pushups_down,1121.0079,1144.554,-560.36176,1134.1887,1142.0302,-606.05963,1142.2621,1141.6145,-606.451,1149.9618,1141.0371,-606.6093,1111.1726,1138.2056,-607.9357,1103.1346,1135.1471,-608.02985,1095.1349,1132.0935,-608.0333,1166.2882,1116.1296,-583.04016,1082.0697,1106.2538,-593.154,1130.7676,1132.953,-524.8809,1109.3801,1130.9728,-526.685,1256.1809,1034.2607,-458.26923,994.5397,1016.7433,-453.2916,1388.2174,937.96204,-214.82204,887.11426,935.53937,-206.86472,1365.46,1075.7202,-90.76085,931.61066,1099.1357,-80.27519,1383.6843,1107.5957,-107.6311,920.77795,1141.9065,-95.78312,1355.8193,1115.3745,-115.58163,954.69415,1152.9648,-92.10255,1339.7952,1099.3245,-85.2357,961.7697,1133.5173,-73.75605,1201.69,906.37933,5.2806005,1085.4536,900.27167,-5.1525497,1202.2842,844.5218,514.6607,1094.4694,843.0191,461.3865,1192.1173,780.94415,990.3118,1111.1367,795.8347,960.09656,1183.3369,758.417,1054.0948,1116.6904,775.2291,1025.8173,1215.066,836.9945,1169.0696,1104.4762,858.4771,1153.7672\nframe__jb_nImb4p48__0008550.jpg,pushups_down,574.68945,771.462,-80.698715,559.60156,749.78577,-131.22247,561.1772,745.7215,-131.27007,562.6745,741.40875,-131.65358,556.79675,750.16425,-64.0797,556.6301,747.04767,-63.90425,556.7364,743.90436,-63.9616,580.49207,710.9921,-226.71425,570.7835,715.77814,70.90931,602.2419,762.42175,-108.36685,599.07635,763.9388,-21.723202,689.5332,727.3802,-374.1605,711.8992,681.1743,309.05875,700.02136,917.4229,-313.63745,729.40765,866.5045,350.71017,557.76227,896.49243,-91.37924,587.69116,878.20123,321.206,514.5978,901.1473,-158.42537,545.07465,884.28656,322.19925,519.9142,872.1769,-187.80223,543.6094,861.55096,326.50046,543.5686,865.08124,-100.79684,560.50806,857.77527,312.76138,989.30566,662.6526,-215.9102,990.8472,644.76666,216.94984,1204.4788,742.8834,-193.32224,1187.0645,738.9186,246.49854,1451.2673,784.3761,-166.13548,1402.7354,779.5822,342.74542,1508.5851,774.65845,-171.70332,1457.1554,771.4559,345.97226,1432.0493,893.6104,-282.16446,1387.7015,889.46533,277.68246\r\nframe__vx7I0X7-32U__0001324.jpg,pushups_down,1547.7695,623.34,408.74625,1561.9318,619.96576,433.4614,1559.1659,619.1462,433.55988,1556.6882,618.6102,433.2035,1570.0419,618.46124,385.42157,1573.9491,616.1002,385.37216,1577.6788,613.52014,385.14758,1550.1519,603.48914,531.6322,1579.212,594.08734,308.1859,1528.5259,615.0839,446.052,1538.5424,611.0554,380.87363,1438.5312,582.6706,604.9652,1532.5432,566.8637,159.61237,1423.1874,710.24896,707.2493,1540.8383,696.76447,214.09647,1520.687,695.4335,787.3284,1583.6355,681.45496,545.0773,1547.982,695.41846,820.4953,1604.5707,684.10614,551.7292,1555.48,686.6033,838.73553,1596.9333,669.692,543.51044,1545.0355,682.3419,793.53986,1580.6517,669.0444,545.92554,1221.6575,566.6579,159.1578,1253.9004,554.94,-158.75156,1006.52185,664.5939,81.47395,1027.1392,653.7603,-225.57857,793.176,729.59357,7.9829826,789.3036,733.35236,-324.58426,752.9804,724.90784,-2.294172,749.1297,726.88055,-335.45947,763.15125,806.7986,-77.52692,756.67236,817.25946,-414.53418\r\nframe__jJZMebnFIC4__0014335.jpg,pushups_down,129.3143,186.78394,-161.87703,118.710144,177.95302,-169.94601,119.39267,173.77222,-169.87627,120.10732,169.5616,-169.85052,116.444214,186.46568,-152.5658,115.240906,188.76454,-152.58705,114.16222,190.99774,-152.77953,128.035,155.33607,-160.8424,118.103516,182.27234,-80.600075,142.50966,174.47284,-154.80309,139.6935,186.7735,-130.96577,194.20248,154.6123,-185.80614,158.55875,143.70442,8.59075,207.15051,242.03653,-194.05399,160.85762,219.418,35.553593,149.674,258.01923,-156.51796,116.52066,247.328,-57.12441,134.56496,268.59213,-182.46791,98.5525,253.26016,-84.65298,127.53738,250.71603,-189.70314,96.83717,248.05931,-92.015755,133.86803,243.72177,-160.02437,107.33671,245.12627,-66.498344,355.31842,120.08669,-64.81288,338.4825,112.24924,65.08983,452.60202,145.95062,27.533817,430.98312,127.96624,149.90475,544.561,142.2514,120.62701,514.8671,132.99373,258.1189,562.9989,129.57516,127.411964,531.9794,123.308334,265.60175,555.3815,183.43697,71.5901,526.5165,175.90123,225.63115\r\nScreenshot_2021-02-11_at_13.21.39.png,pushups_down,1235.3157,919.9253,-903.2409,1215.1641,922.26807,-988.0246,1208.875,920.0046,-988.34515,1202.0151,917.4446,-988.37524,1231.7401,938.3645,-992.6456,1235.8602,947.7751,-992.329,1240.2974,956.6459,-992.7267,1174.5728,939.34357,-1065.2415,1240.5992,1001.8941,-1078.5961,1230.7947,925.01294,-893.0334,1244.6259,942.22705,-895.23816,1131.7816,934.8635,-864.1431,1273.7223,1059.8496,-867.53766,1178.7969,852.23035,-355.37857,1352.3743,1002.95483,-557.8609,1290.2871,834.33954,-60.546406,1334.3932,1089.2524,-360.4975,1310.0643,817.8637,-39.2687,1331.149,1140.3594,-347.73068,1317.3347,839.28375,-46.53505,1335.5762,1139.1105,-334.4153,1316.8262,847.3941,-57.120743,1329.4802,1114.303,-352.73938,1265.6254,814.61926,-2.802791,1338.2122,880.72656,3.6726172,1325.2179,724.4316,705.9585,1388.9026,756.58923,713.9575,1348.8934,704.3553,1499.6857,1392.4122,736.6783,1499.6614,1343.767,706.3867,1586.4656,1395.6866,740.8569,1588.8057,1378.8909,665.8985,1587.2943,1406.6676,689.76544,1572.6377\nframe__hnCg8x3xi8M__0017041.jpg,pushups_down,210.16783,773.15045,-354.16876,176.41068,749.34973,-441.29715,177.96994,743.6355,-440.9088,179.62424,737.7243,-440.89508,172.33452,751.08905,-366.47406,170.68301,747.6202,-366.32202,169.47406,744.0598,-366.30634,203.58153,687.4927,-600.98535,184.36981,696.3892,-259.78397,253.47856,745.6511,-392.28482,248.83118,750.0104,-291.43182,417.65012,662.3575,-648.2481,356.45044,595.33484,-17.57184,458.51416,945.9471,-576.43945,406.27075,879.0738,61.76041,203.55132,959.70953,-446.53882,210.04927,930.28564,-85.91757,129.55931,984.0264,-554.5581,135.4953,929.47784,-149.30061,115.229706,916.7221,-584.41016,128.99031,919.5589,-149.53723,142.9819,901.02655,-465.93027,163.13867,919.9925,-104.12821,988.3105,521.3203,-216.38939,926.39844,503.63577,217.89471,1379.4015,639.4638,7.0139217,1241.2197,626.66876,445.9572,1732.567,663.9583,279.69577,1538.6594,685.72253,825.6724,1803.8262,636.1476,297.28967,1603.5188,654.96094,858.2955,1758.8909,820.07007,99.87543,1579.0223,858.5097,778.3075\r\nframe__wBy8-ilMe4c__0000706.jpg,pushups_down,534.48724,759.29114,-29.730385,500.96127,740.14624,-78.83144,499.05338,734.3641,-78.81007,497.0479,728.42163,-78.71141,502.7689,744.47034,-16.760756,501.98285,742.78766,-16.831625,501.32687,741.1319,-16.95234,502.49817,686.8184,-181.74886,503.81992,703.60956,103.71198,561.1499,733.0427,-56.72941,562.2345,740.4481,25.760345,658.1227,645.83575,-278.94498,676.3019,617.4626,263.564,870.2045,702.1131,-354.09354,881.8116,653.38464,385.90784,784.0525,827.8379,-244.88585,798.03485,780.61096,405.92865,754.64825,868.6235,-263.48273,760.63556,804.78046,417.00644,718.5015,858.23987,-245.13922,741.91064,829.34424,393.29608,734.7969,843.5323,-234.38211,758.28424,818.44574,388.64282,1125.6339,627.3008,-186.96864,1107.2163,613.07825,187.68852,1482.655,694.6897,-112.39515,1443.8613,638.6655,171.5276,1830.5706,660.559,-54.91019,1786.1543,613.81793,190.81363,1886.0839,619.4208,-55.13425,1847.9315,572.7638,184.62979,1892.6161,774.8185,-148.26126,1846.1515,743.0804,116.651276\r\nScreenshot_2021-02-11_at_12.24.57.png,pushups_down,986.1671,1131.242,-1668.098,965.7826,1100.3595,-1695.9441,970.02734,1087.4297,-1696.2441,974.584,1074.208,-1696.0822,945.7473,1130.1539,-1663.0088,937.2059,1136.4761,-1662.6617,928.7687,1143.1316,-1662.9795,974.53204,1006.1912,-1552.6704,906.485,1111.8845,-1396.4235,1012.8519,1090.131,-1593.4312,998.1169,1121.0652,-1543.8113,1177.081,858.73267,-1255.6145,876.21326,1008.71124,-1069.9761,1464.8411,963.95764,-1233.2058,742.55286,1138.1971,-740.55096,1618.0496,1258.8931,-1250.252,820.6158,1254.1986,-716.01697,1671.243,1309.3088,-1348.7659,784.6936,1285.4321,-751.8943,1625.8417,1326.1378,-1389.1974,824.2381,1267.526,-767.69116,1601.918,1306.6954,-1269.3883,858.34827,1253.2456,-729.484,1350.7622,941.1351,-94.957664,1235.4901,1026.2058,94.854836,1447.841,976.6461,892.134,1346.1383,1028.8008,1029.3352,1463.952,948.86597,1914.1136,1421.4921,981.22217,2014.5477,1455.8965,924.9437,2009.0604,1425.748,953.879,2114.9026,1496.2972,1009.4046,1791.9297,1459.9407,1018.1528,1928.9712\nframe__qYPTxdZNGDg__0007885.jpg,pushups_down,637.94196,718.0039,-700.2643,647.2576,694.2753,-740.6554,655.93317,693.80695,-740.39197,664.53406,693.3082,-740.4975,630.63696,686.6917,-697.0739,626.75555,681.464,-696.8139,623.13995,676.31006,-696.8276,699.449,669.523,-777.3046,642.2721,645.9825,-590.26294,672.40314,718.91156,-699.3936,654.0315,712.704,-645.04614,892.463,660.8308,-669.0369,670.2785,580.6819,-441.3792,1069.1,668.3604,-535.6142,644.6401,593.67554,-135.99547,1010.40936,787.83527,-497.4618,591.2326,707.59076,-11.984718,1007.66943,814.43066,-568.0555,562.4597,717.91833,-30.75052,967.42993,806.4282,-581.9408,569.2472,729.70825,-75.57389,957.9632,793.1161,-508.54562,589.5665,731.8322,-26.323439,1050.385,600.1858,-111.226776,952.37463,552.19495,112.20237,1171.0574,552.2151,402.4365,910.4073,545.36664,723.25073,1261.6171,495.67313,939.4413,922.5754,489.7537,1342.0156,1278.927,472.2905,1001.5418,937.12415,471.67224,1413.2976,1264.4846,550.60767,1005.096,879.6474,535.24805,1463.8191\r\nframe__TuAm4brPkBk__0003998.jpg,pushups_down,1553.8988,755.82153,-683.2988,1565.0708,725.372,-660.0819,1564.3093,721.0318,-660.1119,1563.563,717.47406,-660.1167,1558.2118,728.1,-730.90643,1553.2234,724.3406,-730.90955,1548.0354,720.8458,-731.1322,1528.9105,683.5352,-463.9922,1510.4493,690.1309,-775.83276,1517.1346,747.906,-594.6748,1511.5012,749.6309,-684.52466,1413.4078,644.4612,-183.54031,1305.6182,689.6766,-750.8332,1314.5328,677.1497,205.26949,1096.6973,687.81854,-642.1516,1345.9303,811.20544,393.63098,1162.5942,858.3593,-484.3256,1374.7073,822.465,402.78525,1192.1787,898.63416,-556.16364,1384.4795,833.02026,330.7262,1227.6844,877.9119,-533.0223,1364.4379,833.24005,369.31247,1217.5292,864.2613,-476.1613,1074.0333,672.0144,217.47311,1006.7585,689.51,-216.62889,886.0565,714.8005,681.84766,812.7062,708.0978,314.588,710.15063,679.6332,1235.8741,643.23145,682.8417,872.70764,675.79675,643.07697,1300.0189,605.9762,651.254,934.7992,687.3546,782.338,1343.6222,636.0215,787.5963,923.4416\r\nframe__gMhF8v6E5yQ__0008672.jpg,pushups_down,307.39224,635.4642,-378.20264,293.6845,596.07214,-376.49756,298.04752,583.38983,-376.12585,302.27063,570.40314,-375.97385,284.61847,622.817,-329.02426,281.67737,630.5203,-329.03668,278.86804,638.42267,-329.0917,330.43756,538.0867,-230.96506,296.09683,624.9993,-15.046166,345.17377,616.5017,-312.60443,331.52658,653.13104,-251.3396,451.33942,592.818,-388.89734,458.3893,587.3786,354.41293,610.6213,689.7422,-760.0837,610.5317,680.00354,639.84875,509.6997,868.7494,-1092.9443,505.10416,820.28503,937.2863,476.5244,898.4268,-1155.7404,463.74258,837.4749,1002.74023,449.66028,894.0705,-1104.5457,455.15292,853.4498,967.4848,469.7024,881.0654,-1074.871,476.76273,849.6344,927.56006,886.81006,718.07556,-244.98155,873.7677,699.0149,243.84842,1251.3547,760.6475,-360.92215,1222.2814,715.7519,172.07634,1595.7668,727.5045,-384.9443,1544.7238,679.97656,244.57947,1658.5201,680.3181,-391.6417,1610.3024,641.8083,241.27896,1648.6686,850.1667,-592.42346,1584.0919,811.4895,111.38086\r\nframe__9d0VKo-LnL8__0009192.jpg,pushups_down,550.7824,764.76874,-580.2241,550.623,736.06177,-638.27795,556.4171,733.2726,-637.70734,562.1414,730.52905,-637.55963,544.35284,734.7934,-568.6822,545.04065,732.0075,-568.6139,546.11066,729.12463,-568.68427,602.2184,704.0262,-738.531,577.6029,700.4678,-416.6248,589.08093,762.2269,-602.4567,583.38385,762.6663,-506.99655,777.86365,735.34076,-719.92096,662.5598,661.34656,-210.31326,813.767,953.5568,-722.1303,644.5505,806.9021,-26.374384,639.9915,1011.1134,-745.9848,550.7733,895.66895,-217.69987,597.07697,1034.4875,-866.1354,508.2359,899.47705,-267.69128,576.0681,983.2392,-863.73175,515.26263,898.8524,-326.67795,591.0165,972.49536,-754.2367,540.8636,904.09375,-253.15945,1096.1469,624.52185,-180.68927,1032.2727,585.91986,181.98328,1314.271,639.4996,168.82852,1207.091,598.3365,555.2639,1486.6964,605.4234,518.76953,1368.0017,564.6888,1032.1277,1520.482,586.36365,543.5036,1404.1404,541.04987,1079.4872,1494.554,684.7792,402.62265,1368.0056,651.8231,1046.4347\r\nframe__SOyAVe-cUzA__0008551.jpg,pushups_down,1288.6533,1000.3157,-649.97626,1330.8705,986.0688,-691.86084,1338.1667,980.71533,-691.9887,1345.2546,976.06934,-692.2496,1310.6342,988.12305,-730.47394,1304.4146,984.27136,-730.88385,1297.9834,980.50323,-731.11816,1347.1041,925.1095,-705.34125,1285.5823,931.6269,-876.9219,1267.4248,968.2986,-624.0783,1249.9962,972.34625,-672.5842,1324.5846,791.5572,-553.5931,1042.4285,800.92944,-748.90106,1226.6567,745.9699,-92.568794,732.695,774.16797,-564.10706,1264.0623,899.2805,113.761765,825.64795,989.3004,-451.96323,1317.0436,927.14825,92.89341,841.91785,1055.908,-532.2002,1306.5819,954.8639,62.634056,917.8528,1036.86,-537.7136,1276.3657,946.00793,103.389755,919.4825,1017.6513,-463.59866,953.2761,713.6894,113.06038,816.2308,723.38916,-112.962105,935.2025,696.15405,851.4858,768.0053,644.5254,608.49854,913.0945,673.9018,1513.2477,762.51306,537.66833,1260.7902,905.02057,650.25836,1589.1669,759.4676,507.646,1335.9054,921.4618,744.048,1675.0881,764.10895,586.2983,1400.9674\r\nframe__ecDggpGrS7Q__0007865.jpg,pushups_down,478.2168,679.34973,-127.8794,461.0365,662.2174,-179.50854,461.75327,659.06415,-179.40807,462.51508,655.6516,-179.69426,460.528,660.94464,-119.95223,461.0278,657.82623,-119.880646,461.87378,654.67706,-120.17333,478.29535,629.0303,-273.68466,476.10138,627.9947,-6.0064616,503.0777,670.2418,-149.14769,502.8853,670.9057,-71.88772,594.50604,647.2176,-398.02878,610.1744,584.04987,227.57207,577.4879,830.19666,-458.75577,592.76654,729.00714,286.20343,414.66248,832.1303,-442.31076,450.98782,761.6018,189.36388,363.2239,843.4487,-537.18335,403.07666,767.3946,175.98155,357.961,814.27264,-537.74255,405.09253,757.049,144.3468,385.44336,806.0927,-446.49344,424.10208,752.3044,164.32172,934.73254,628.2588,-201.20923,927.45215,585.5441,201.64828,1158.9579,670.2902,-6.242758,1142.5514,628.4445,314.02774,1380.9945,675.3252,130.75194,1330.9723,646.201,481.8449,1417.6548,656.0261,138.01828,1366.0316,634.1087,496.04266,1399.6138,761.29736,52.26292,1346.295,740.017,448.07678\r\nScreenshot_2021-02-11_at_14.44.00.png,pushups_down,1699.1953,774.91077,-535.6951,1722.2683,737.8777,-508.1124,1722.832,735.16986,-507.9178,1723.4407,733.12274,-508.05344,1712.4756,734.7347,-584.5891,1706.4635,728.0573,-584.5412,1700.2533,721.5057,-584.8066,1687.0297,694.4359,-315.93854,1657.4774,679.4545,-641.2459,1655.3607,771.10516,-449.09305,1645.207,763.9524,-542.11285,1517.5447,650.5897,-60.22486,1401.7554,665.2396,-638.71857,1424.1746,627.9571,400.26508,1115.6631,610.7153,-618.46606,1494.604,802.0937,817.0074,1179.1718,843.4917,-595.543,1528.527,829.7279,833.6107,1198.1271,902.6425,-673.4496,1539.849,840.03735,786.5358,1244.146,897.2294,-665.26605,1515.4113,831.78925,803.0881,1234.5374,875.44305,-590.5314,984.3801,657.2523,210.74342,933.7179,659.67755,-209.61687,644.5125,656.75006,552.9811,603.7813,669.97876,220.11548,329.57376,628.5244,941.8345,281.7147,611.49316,584.3521,273.6595,590.9865,973.3201,222.52814,561.8933,615.93726,284.31815,738.25806,899.18713,237.38757,758.99066,528.10425\nframe__VIaz00i95pU__0008806.jpg,pushups_down,1422.5157,694.9924,52.52944,1436.4805,674.19495,69.423775,1435.0323,670.4696,69.64132,1433.7435,667.023,69.574295,1437.017,676.9123,6.6154423,1436.9385,674.44305,6.7714124,1436.6895,671.8237,6.6682897,1418.9508,646.4924,182.17496,1424.0747,652.39746,-102.63115,1399.5107,692.9775,103.80746,1400.6554,694.62787,21.711838,1282.5941,620.34,404.42505,1332.2704,688.0744,-231.19244,1250.2106,781.60254,490.37756,1312.324,857.08215,-139.40793,1362.766,782.22546,503.11072,1398.117,832.42535,160.0407,1407.22,779.266,540.6543,1440.6367,826.65826,126.66903,1409.1486,762.20056,533.5381,1435.9431,804.2447,122.29437,1391.115,763.1738,499.25153,1414.0244,803.3339,161.07547,1020.99817,596.19696,211.94635,1034.9117,637.296,-211.29845,815.30804,666.97205,288.64697,806.1702,709.3586,-171.10004,622.7816,691.82416,432.41797,579.6075,737.69934,-127.35852,572.22705,686.05145,443.40213,525.03265,728.3268,-136.61823,642.7039,791.0824,393.74432,600.4299,842.3451,-247.87294\r\nframe__ieyzL5OaPZk__0020539.jpg,pushups_down,1320.9661,852.1133,-43.453304,1331.5247,839.81537,-31.842077,1330.9331,837.9621,-31.736916,1330.3634,836.1976,-31.70298,1330.8575,841.26965,-76.024124,1329.9287,839.8782,-75.83178,1328.9084,838.5424,-75.87691,1315.5251,824.53204,47.71768,1314.5337,829.8238,-150.18906,1301.2811,852.9821,-5.7011437,1300.2834,852.5302,-62.09511,1198.0653,796.25824,229.70601,1221.0665,866.2983,-264.3925,1085.6248,813.6541,384.7321,1101.8638,893.4673,-295.21387,1082.5503,905.88934,411.7525,1109.9734,1001.05035,-294.0381,1090.0507,916.69165,423.71887,1121.3552,1026.0516,-345.26154,1102.7318,925.14014,370.44016,1133.2808,1025.7925,-310.74005,1101.5308,926.3895,390.28522,1126.5526,1013.19196,-275.01404,968.52344,863.5969,164.81538,976.6017,912.28107,-164.52359,803.909,865.97107,330.30927,777.617,938.5294,-183.79715,629.5775,830.0171,532.04596,574.77466,897.1634,-214.82219,593.5245,814.58514,550.354,538.1467,871.67053,-221.38228,614.9882,874.7336,546.3873,542.3893,961.5159,-305.10126\r\nframe__neBQT0z3xk0__0009666.jpg,pushups_down,1276.4182,657.2172,-119.49741,1302.3815,641.4771,-135.58487,1305.8766,634.077,-135.38072,1309.2618,626.9378,-135.6181,1290.3694,651.65515,-181.3345,1286.4567,651.42847,-181.20999,1282.2212,651.15515,-180.89674,1293.6532,588.60657,-145.74596,1257.8595,622.3678,-353.53433,1249.5933,634.09845,-105.23734,1238.5201,645.4651,-164.82898,1197.1862,460.21667,-25.463957,1085.0864,616.3543,-428.90665,1188.3676,614.9011,230.8329,1036.7574,830.3081,-393.60794,1292.5222,735.19965,240.22443,1230.6552,839.64905,-266.392,1344.5544,759.7703,212.1283,1288.7936,860.169,-348.46884,1332.9158,755.81177,168.06845,1302.8702,807.45886,-374.15247,1302.9565,752.91486,216.31488,1278.0604,792.4753,-277.59967,756.57477,467.91025,142.6153,697.1591,549.35706,-142.07507,576.4124,516.94763,569.5441,545.4252,564.59955,328.93866,400.12045,497.85593,953.8629,365.35123,544.2456,699.2527,367.29623,476.574,998.4116,328.7562,517.0845,737.9615,365.07114,554.0731,1047.8604,344.18402,625.4671,766.3863\r\nframe__TnREmIrNkC4__0008294.jpg,pushups_down,1189.8644,836.9329,-70.31663,1194.9169,815.65625,-50.150753,1193.3236,813.12775,-49.91113,1191.8601,810.89996,-49.880123,1193.0681,816.0679,-113.30392,1190.899,813.2994,-113.19938,1188.5616,810.4685,-113.093445,1171.9878,798.47296,90.92076,1168.2507,796.6547,-200.00314,1168.7145,841.9842,-10.610937,1166.6891,842.58966,-93.59931,1060.1344,813.4287,302.8912,1086.3381,838.0109,-349.21918,1088.1626,935.92706,357.67966,1107.6329,978.8927,-416.19315,1162.1041,966.74963,212.52971,1172.2595,1005.53925,-273.1455,1198.7253,966.9367,209.57002,1209.2572,1007.51495,-345.95276,1198.059,956.09875,167.58546,1203.8279,984.561,-327.21655,1183.4058,959.68896,187.99263,1185.8213,983.4919,-267.21396,804.5063,826.6979,217.45323,814.4464,840.31915,-216.85854,628.1856,894.48303,212.09528,639.2499,898.5871,-251.5841,442.44717,907.32056,292.0273,432.9058,922.26794,-184.02887,400.69412,895.4251,295.40216,386.08707,910.9832,-192.94025,448.07193,986.60455,200.81744,442.72943,1001.2865,-344.88235\r\nframe___7i9ao_ajKw__0013573.jpg,pushups_down,1522.4628,747.3978,-240.39038,1543.8522,736.2873,-204.0118,1544.2722,740.1173,-203.9349,1544.8545,744.2071,-204.1792,1540.1733,720.3406,-251.00958,1538.7987,711.0805,-250.913,1537.1555,701.8608,-251.05742,1527.7233,728.1177,23.473156,1517.9595,676.0761,-184.38504,1494.119,755.9363,-147.29044,1490.0728,733.9096,-207.79216,1348.1699,701.73395,324.58282,1388.6511,722.21545,-292.32642,1331.9797,896.0912,396.6521,1374.9329,943.1335,-267.0718,1480.3373,870.8307,395.59988,1539.9495,926.2479,-78.20694,1524.5496,872.4126,400.21954,1589.9799,937.19446,-145.74384,1529.2372,849.6578,411.48627,1589.65,902.4443,-176.49286,1509.3718,847.34686,393.49374,1560.6252,895.90845,-91.712364,983.7208,699.80493,206.51852,989.2376,714.03033,-206.35562,729.98724,769.12634,295.8768,700.0567,789.11707,-173.02628,488.8353,799.9601,453.47754,410.18326,780.1129,-146.29121,437.4416,784.5576,468.03473,362.77805,754.1024,-149.54619,464.96194,921.55817,443.11044,362.92667,888.97754,-245.2597\r\nScreenshot_2021-02-11_at_15.22.42.png,pushups_down,505.3151,1035.4299,-929.8116,484.46323,977.6734,-1007.7829,493.6074,965.5348,-1007.589,502.70078,953.4801,-1008.30023,468.8686,988.9214,-906.1127,466.2258,987.6761,-905.65247,463.93048,986.7793,-905.75934,560.38153,872.82947,-1111.0388,503.68436,910.4678,-665.5008,575.90186,996.63666,-945.10693,560.2642,1018.1437,-815.6408,1013.3083,798.658,-991.56384,653.4527,735.1788,-470.58978,1498.0259,777.87915,-824.0008,787.1971,715.0009,97.61603,1411.585,1090.0526,-657.31354,685.66754,973.6588,301.5952,1412.4275,1150.3541,-759.0712,630.67725,1004.93854,253.22981,1320.8995,1160.6775,-773.01416,624.84076,1037.0741,182.9088,1301.596,1129.7975,-665.8089,665.0054,1022.8943,271.21472,1512.559,758.2726,-244.65282,1349.3511,702.8204,245.85411,1797.6924,793.73474,469.75314,1599.4513,733.51306,984.8085,1998.0306,727.9479,1239.7139,1819.9597,664.4413,1708.1501,2048.497,679.49194,1325.6211,1875.0735,608.9598,1790.0972,1998.119,880.73376,1341.1143,1829.6459,817.7957,1845.9553\nframe__S2r3Zp_fMNw__0008234.jpg,pushups_down,877.0871,948.59454,-764.7228,881.0437,941.28973,-791.4565,885.2061,940.24976,-791.2523,889.20465,939.3161,-791.7852,871.0379,939.58386,-781.99493,867.98346,938.76227,-781.67896,865.041,937.94543,-782.1501,904.438,931.54095,-753.8226,869.861,928.183,-705.00037,894.3125,947.5491,-734.9973,884.6465,946.6501,-718.9431,990.4826,935.7729,-593.497,868.6086,879.5154,-542.18243,1080.0957,950.6488,-497.72122,859.9828,840.8367,-216.24489,1092.7322,1013.24585,-507.7522,875.99884,894.04926,-7.3478093,1102.5331,1022.5925,-568.8847,868.5573,903.35846,2.985411,1086.8763,1021.5273,-570.02856,878.95264,910.2011,-25.675774,1080.7483,1018.29114,-510.83667,887.4151,913.4347,-12.157899,1054.2228,907.75836,-48.00176,1002.5289,881.7903,47.398846,1068.474,890.3432,475.63864,1023.48865,879.3128,557.67773,1088.5952,890.80994,976.80554,1045.9507,870.2605,1071.3671,1101.1204,886.5084,1032.1951,1059.3329,868.28625,1128.7987,1068.165,900.9239,1082.6635,1037.2275,884.9813,1193.7094\r\nframe__UswHz7_nvZQ__0003894.jpg,pushups_down,720.94366,705.056,-610.758,713.30206,699.1635,-683.83075,718.81244,695.76843,-683.55194,724.3994,692.1768,-683.6831,697.53406,698.42175,-626.03357,691.94183,694.91974,-625.90283,686.71014,691.4001,-626.47546,747.6544,655.906,-849.0131,695.015,653.0337,-586.02625,756.19653,681.81964,-650.1965,741.6441,683.8553,-572.20917,940.8779,588.3049,-827.27795,738.0777,524.9864,-440.45642,1040.5985,776.73004,-897.70715,735.1313,651.58057,-240.42166,871.0934,857.0618,-993.1605,657.12604,765.8827,-438.0521,830.159,881.8982,-1115.9618,612.2161,775.1102,-512.5446,796.35364,834.0597,-1101.337,621.05664,777.62854,-576.8002,802.21484,825.8676,-999.03546,647.922,777.74915,-471.51505,1197.8231,552.05524,-156.23187,1110.2544,523.18317,157.1282,1384.6335,592.1297,281.92188,1279.2782,575.1221,594.24084,1536.3165,580.0449,813.8521,1433.8107,573.38324,1189.6292,1568.5886,556.8302,862.1428,1473.9468,558.91846,1250.9818,1540.6393,657.217,770.08246,1436.4425,650.5518,1213.3004\r\nframe__3a8QJhuFZx8__0010649.jpg,pushups_down,387.9179,734.7509,-4.907602,363.86392,722.8889,-56.955566,363.27094,719.10425,-56.91245,362.5857,714.9996,-57.28407,363.24268,722.8944,3.3224452,362.69464,719.61163,3.2577937,362.49744,716.20905,2.9153237,366.6848,685.7941,-159.24402,366.6649,690.712,114.49652,406.91232,721.8078,-32.382927,407.36484,722.6421,47.403053,460.09753,683.66113,-307.76306,495.76617,611.456,350.8667,454.8196,885.95764,-243.73927,498.5813,800.1284,376.3593,327.93216,842.8636,3.1096323,361.5558,805.5069,347.79257,285.23557,851.848,-66.725296,317.42078,815.0509,368.93146,288.6931,813.1565,-95.07198,313.88422,789.46045,375.3266,312.2595,803.66986,-3.2465625,328.0373,785.22327,344.96744,805.05096,562.4722,-209.6284,813.1202,530.01434,210.08023,1053.9607,679.806,-166.01875,1049.4506,654.03973,218.63269,1326.5774,730.8243,-157.51811,1295.4451,714.204,319.52722,1389.0684,719.5475,-165.65512,1356.353,707.3612,322.442,1302.9639,856.0559,-285.69592,1283.1511,844.86017,245.79251\r\nframe__dCNS-QVXa6k__0003906.jpg,pushups_down,1542.8807,689.9654,413.84036,1569.7545,679.5426,427.72717,1567.941,677.16626,427.89215,1566.4233,675.04456,427.4355,1577.4216,678.6469,361.1872,1582.0725,674.4334,361.3793,1586.4064,670.1794,361.0049,1562.5289,641.45087,514.925,1589.851,633.64545,203.32703,1517.9415,671.59503,457.63052,1528.136,668.3196,367.18756,1404.0363,560.5701,648.5175,1523.4142,610.8299,20.346594,1353.0432,698.13116,925.73627,1550.644,828.4033,85.39071,1507.9814,695.6578,1179.4095,1691.068,807.085,442.22635,1553.9532,694.2036,1241.218,1737.6992,811.299,423.49026,1564.6188,692.8159,1243.766,1736.7222,785.59186,408.80026,1546.6476,692.41974,1182.7798,1708.3971,783.8398,442.84857,1041.0166,619.4727,205.65228,1075.2655,645.0538,-204.9495,680.77826,740.16956,151.9151,705.031,758.0896,-252.60641,330.83456,790.1694,100.339485,324.90744,813.4171,-412.50372,261.46573,769.3454,90.65883,254.54962,793.7733,-436.33716,303.67493,917.54767,20.05956,293.43384,935.54736,-550.68555\r\nframe__iPCJs2jh4Hk__0013860.jpg,pushups_down,1302.4078,729.8637,-578.01776,1306.8918,704.3838,-553.9932,1305.8146,704.0078,-553.7912,1304.764,704.18134,-553.87915,1302.3281,699.5575,-613.16364,1298.5117,694.8609,-613.1916,1294.4312,690.26715,-613.3058,1276.9465,685.94073,-374.46295,1263.8145,665.78455,-634.54,1274.4196,734.6863,-501.46735,1270.1718,728.7918,-575.7912,1193.8843,692.9654,-133.12311,1127.4855,694.8177,-657.57526,1191.7671,846.03156,-203.05168,1100.8474,858.3855,-694.83954,1266.4957,855.5313,-535.60724,1242.8555,858.81824,-592.42017,1293.8541,850.8744,-591.01526,1285.8826,865.7549,-640.4652,1298.2908,823.2825,-604.4475,1283.7365,828.60583,-648.27673,1278.625,827.9364,-556.1929,1268.1588,823.40955,-592.5024,896.2152,650.25916,189.076,852.6088,642.0133,-187.92871,720.25385,742.7039,438.36,673.79016,715.1381,68.31609,557.8327,776.5668,838.043,490.52628,757.35046,399.38397,518.5663,765.26044,873.4045,449.83612,743.4009,422.28024,547.5225,883.53766,809.05756,477.07098,850.2868,295.50027\r\nframe__CI3o5FYbtOo__0004831.jpg,pushups_down,526.6173,729.8859,-20.904219,510.62976,705.1012,-65.98458,512.214,700.6467,-66.00365,513.7123,695.9248,-66.317604,508.8293,707.1465,-3.563617,509.2431,704.76953,-3.3961098,509.92154,702.2921,-3.3758478,534.912,665.75085,-152.42653,527.27167,674.79456,129.23874,555.605,720.9667,-45.2329,553.58594,725.3336,37.12529,657.75653,707.31146,-278.59158,690.1505,642.04596,335.98517,686.9032,915.5971,-168.89139,723.71686,836.1099,378.30096,557.50946,863.7644,108.74683,578.3996,843.8238,376.34775,512.4368,863.4626,56.941208,529.3949,846.51056,383.20264,516.7791,830.0506,26.303421,529.176,829.7309,397.9202,541.23987,823.81396,99.9241,548.79956,827.47723,373.02817,1004.46967,678.0778,-204.5326,1012.39526,644.053,205.33136,1284.0096,760.77124,-231.68303,1266.7976,726.7167,236.64009,1580.7043,773.0577,-265.50055,1531.1091,741.969,335.55368,1639.5941,758.1765,-276.36935,1590.3973,725.8372,341.1374,1580.9575,874.5553,-383.6518,1527.2793,856.4825,288.47528\r\nScreenshot_2021-02-11_at_12.52.37.png,pushups_down,1077.9006,881.3632,-162.92885,1088.2292,883.5494,-220.21236,1096.7257,879.063,-220.46463,1104.869,874.45306,-220.37735,1066.4849,891.49536,-221.48796,1058.4949,893.701,-221.26186,1050.3401,895.36206,-221.5739,1116.7382,849.451,-343.02582,1040.4243,879.3206,-347.89185,1089.7793,858.1864,-187.04811,1066.6542,869.6321,-188.20279,1205.4645,767.9207,-349.86963,951.80035,811.3577,-305.5332,1323.0851,727.8956,-208.20467,902.5635,772.59924,-75.52199,1368.2252,859.61444,-134.11737,909.4866,880.4425,45.00326,1405.8646,888.67487,-142.54622,901.36945,918.58044,27.667463,1363.0419,906.877,-159.23485,932.2975,923.5046,29.550762,1339.4197,895.80664,-132.69728,939.33765,910.0485,46.956078,1131.9187,665.20245,-1.399792,997.1054,679.4542,0.9805104,1128.1165,695.1463,515.812,972.2166,698.2584,470.206,1122.9767,682.5978,1034.1211,981.8032,694.2483,1023.13965,1117.3506,667.3519,1093.3586,987.3489,679.8208,1084.6522,1131.6519,743.1771,1106.2899,981.98096,762.63385,1108.4386\nScreenshot_2021-02-11_at_13.13.22.png,pushups_down,1365.1901,843.599,-448.52444,1317.6432,844.9571,-437.86578,1312.1462,831.3251,-437.80792,1306.5657,817.4348,-438.09186,1327.6182,881.9337,-450.16632,1330.1597,898.4492,-449.884,1332.9042,914.90173,-450.1651,1304.4337,810.5625,-250.49461,1340.7441,942.4002,-296.13626,1387.0557,816.50775,-363.9451,1400.5917,865.4282,-375.55542,1452.293,760.5167,-127.836395,1438.7762,944.2769,-252.33511,1712.0668,672.6571,-39.832764,1469.5603,892.4971,-256.62393,1873.4612,685.046,-140.06781,1276.6642,855.8268,-139.3264,1926.1089,681.021,-210.23732,1218.7471,830.81744,-184.84164,1908.9872,708.0837,-219.96635,1199.4163,859.69714,-179.68512,1892.8201,721.475,-151.68604,1223.094,856.4991,-146.42738,1975.6304,714.6127,25.012821,1984.0879,816.3224,-23.836819,2169.6938,619.3058,228.31049,2202.0715,835.769,169.75075,2417.4133,606.9875,594.5201,2442.1448,982.97217,569.8493,2447.5327,628.62866,629.10547,2472.9717,1004.8777,612.75964,2548.7192,565.4359,469.03864,2569.8406,993.3239,455.403\nframe__xmrFNeuq2zg__0023255.jpg,pushups_down,435.88852,638.93304,42.139484,408.92773,619.59015,-13.957252,408.96365,615.2509,-13.9493475,408.95627,610.502,-14.2945385,408.04172,619.6558,52.601048,407.53293,615.79224,52.652508,407.43192,611.7776,52.34216,421.7788,574.9488,-144.47383,418.21747,579.618,163.30313,463.79214,624.58246,4.940665,463.14996,626.643,94.90683,555.9169,586.9535,-300.20718,594.5461,514.55676,406.50812,572.2595,837.3927,-140.53207,592.5483,736.18524,432.2847,447.5186,786.89575,255.09897,436.73657,765.444,345.80466,398.10065,796.8546,207.32004,380.96356,779.9068,360.31522,404.8781,757.63605,181.36818,379.97522,755.9295,362.05664,431.36325,746.898,252.0104,400.06558,748.45886,338.0604,969.3869,536.0294,-222.1997,982.59076,501.4294,222.78827,1259.3842,639.3038,-144.97034,1269.3301,614.1437,257.5467,1571.8727,684.7279,-72.14528,1559.3557,667.15906,363.0627,1640.2104,670.1799,-74.27024,1624.3792,657.32385,365.4849,1552.5488,799.0113,-173.23071,1557.0366,785.59875,307.21237\r\nframe__TuAm4brPkBk__0001631.jpg,pushups_down,459.00958,847.9499,-598.19995,448.7711,823.9828,-644.7505,452.51782,818.7491,-644.6379,456.09238,813.5393,-644.58966,443.04816,825.5226,-581.8478,442.70142,823.36163,-581.68713,442.5637,821.437,-582.30676,486.89227,770.42737,-713.99194,466.1954,780.887,-428.69904,497.14633,826.2438,-608.46545,493.21454,833.4481,-524.9412,726.1016,720.85535,-682.92175,562.62634,680.4766,-227.36818,943.7216,716.23914,-576.5511,687.3949,681.24023,159.79543,886.7782,883.1492,-447.20468,669.7934,812.06006,383.09412,880.4543,917.1544,-510.62283,651.49927,831.9234,376.1492,834.0956,921.1328,-513.193,648.3529,841.33264,324.93372,828.2283,904.8337,-448.36404,664.68884,834.48157,363.26068,1008.605,683.6713,-186.4279,931.5713,661.27405,186.48346,1217.8181,657.1923,197.67346,1153.332,651.78015,528.88654,1397.123,589.1094,623.69946,1318.0612,593.57056,951.3218,1427.8667,555.29297,666.30005,1348.1553,557.9452,998.1919,1423.0183,673.4566,639.46826,1347.6182,686.7531,1000.22595\r\nScreenshot_2021-02-11_at_14.22.29.png,pushups_down,1355.4432,1087.3325,-1170.5906,1370.8821,1055.2596,-1165.5848,1374.8328,1045.9584,-1165.6984,1378.5386,1037.358,-1165.5232,1353.8937,1068.4502,-1243.9164,1346.7241,1067.612,-1243.5652,1339.1667,1067.0858,-1243.4082,1356.1656,975.7772,-961.7182,1303.4731,1019.1552,-1313.8552,1332.4584,1055.439,-1069.351,1318.258,1066.8187,-1169.3429,1320.2444,815.2184,-661.78424,1108.5875,963.71643,-1158.3285,1346.3718,751.48645,-134.71725,922.5683,905.4968,-1008.2088,1364.9478,899.3286,286.8017,918.5473,1033.6265,-783.95605,1378.5151,915.7322,312.79956,902.0411,1061.0648,-840.0489,1359.1554,932.67084,261.6628,929.8626,1059.5831,-832.84625,1340.7538,932.2822,274.38422,942.5105,1048.5172,-778.7015,923.2191,809.8216,235.2142,819.86725,883.1348,-234.77559,800.2816,873.6921,1172.8591,723.41644,959.0835,555.19006,665.56494,866.3858,2106.9116,590.8903,938.033,1379.6735,638.1166,839.096,2212.8142,560.8666,906.9495,1468.2283,643.90045,952.304,2293.271,572.7652,1028.248,1473.2129\nframe__1BZM2Vre5oc__0015129.jpg,pushups_down,639.99194,965.63666,-401.13705,630.0574,955.4909,-447.28748,630.9503,953.3027,-446.8698,631.8343,951.0211,-447.02838,629.01776,954.37866,-395.88052,629.3954,951.6743,-395.67313,629.9354,948.921,-395.92365,644.4206,928.2168,-535.6291,641.89233,926.9028,-299.60733,662.1197,954.8257,-424.52573,662.2672,953.4704,-354.6636,757.3642,901.11914,-542.253,690.96985,860.9454,-96.45125,868.6591,925.83746,-612.7575,749.60046,858.8719,256.0523,827.63275,1008.855,-691.74634,737.4246,928.6997,505.56735,810.1556,1025.593,-774.9962,721.2135,938.1311,545.4404,790.9329,1019.314,-754.02545,722.01697,943.48395,503.7174,797.2855,1014.0093,-687.5529,732.1149,941.5274,496.01514,954.8888,879.7168,-160.73859,915.36566,855.1237,160.81596,1079.0559,862.8194,236.15013,1067.5067,847.5177,501.35645,1204.3279,850.29376,657.9085,1184.9397,838.9372,904.0242,1230.6312,835.221,695.7102,1210.9513,824.1373,948.9652,1223.5701,911.0106,666.3282,1205.8014,906.46136,966.9197\r\nframe__mUAw2Gvs79M__0018049.jpg,pushups_down,451.1907,630.6846,-56.00641,434.4741,606.49524,-104.87259,434.84222,601.8788,-104.87191,435.13098,596.98737,-104.998116,435.8357,608.47986,-40.089413,437.32306,606.33154,-40.21912,439.07733,604.1906,-40.608433,453.34467,565.184,-203.8092,456.67892,575.78,88.76971,476.7525,620.0353,-83.41338,478.3089,624.67664,1.602529,580.95654,588.493,-311.00537,611.84894,561.5082,294.2668,639.4665,759.83386,-276.40887,666.3501,723.3385,397.2399,496.43622,752.8888,-155.34337,512.26843,738.311,492.93607,448.93127,762.7725,-226.06789,461.49738,743.7111,516.0183,447.77872,737.7915,-233.11043,457.72763,729.5713,516.08496,471.98804,728.92285,-159.32426,476.61105,722.7601,486.2403,906.7856,622.00073,-182.5881,909.39594,602.1714,183.11388,1144.103,684.97705,-103.79947,1144.1519,663.19525,175.87543,1388.0441,682.58563,-32.4545,1373.3823,661.6923,261.12692,1433.2885,663.17834,-29.346634,1417.8524,644.684,267.96875,1399.2983,767.01044,-107.50457,1390.5989,750.3099,221.4799\r\nframe__J5FZeUV6l0E__0015107.jpg,pushups_down,252.57156,439.25168,-90.12428,247.94543,423.6838,-123.20779,249.71677,421.55206,-123.14111,251.40552,419.27243,-123.26003,246.99738,423.65152,-77.64307,248.12802,421.98877,-77.5952,249.46857,420.3331,-77.71608,270.37137,405.064,-187.35414,266.5443,407.1324,17.912794,273.01733,439.05066,-107.96391,271.9855,440.0463,-48.38639,356.15158,430.84045,-277.35583,367.43484,411.5854,182.15515,357.57217,551.5825,-263.87402,375.0552,536.81604,186.33131,286.31232,553.66766,-176.39404,300.119,554.7795,81.82067,260.23746,556.61,-238.41576,271.74344,557.8306,71.1381,260.3968,540.29767,-245.23053,271.8552,547.0534,53.29576,275.13977,537.3045,-181.88275,284.0164,544.7953,66.20975,590.4576,415.89087,-152.49506,587.8431,405.68344,152.99243,745.05524,470.41937,-95.32736,733.7339,453.62643,196.24565,915.26294,492.75415,-39.450287,881.4472,469.1534,290.66595,951.9658,483.24356,-41.92656,915.10815,461.4335,296.45792,903.3099,566.01337,-129.07735,874.27185,539.03613,248.83653\r\nframe__yEllr_kIV4I__0017675.jpg,pushups_down,1407.8995,810.47797,75.983925,1423.2301,788.567,79.76029,1422.069,785.1897,79.97861,1421.0817,782.12445,80.20883,1422.7894,789.9739,21.03155,1422.1963,787.15015,21.094177,1421.4304,784.2882,21.06174,1407.6927,759.004,174.34528,1408.5587,761.12585,-87.583916,1384.9485,806.7211,121.72341,1385.1212,808.26825,45.226555,1263.528,753.61896,364.91858,1312.2646,790.45135,-217.31384,1265.399,931.94006,301.59027,1296.544,974.89374,-158.08173,1378.1241,923.3319,126.35044,1388.3536,946.3162,138.64532,1418.0651,924.9425,120.94103,1428.2925,939.8324,110.89188,1419.4694,900.63214,115.51154,1421.973,918.6797,102.06266,1401.4226,899.6322,115.57923,1400.6698,918.971,138.7139,995.8476,756.56775,192.8414,1014.1668,779.2643,-192.3339,759.37683,822.192,202.16675,773.6619,856.7003,-222.93874,546.36115,835.86725,243.91705,515.05994,881.41376,-288.77448,495.93326,825.4543,246.1893,458.1374,872.3665,-307.55276,560.4023,930.42285,200.84222,530.0485,984.29065,-422.57974\r\nframe__oYZRHB0aq2I__0003153.jpg,pushups_down,1331.198,704.2326,-141.32733,1350.666,679.4385,-125.300674,1350.7698,674.41547,-125.22531,1350.9622,669.79236,-125.4689,1347.2426,684.86505,-190.8592,1345.6134,681.9769,-190.88145,1343.7213,679.0756,-191.00507,1333.0497,636.2251,-7.558408,1323.4788,649.9061,-287.8119,1303.3088,693.50964,-84.28731,1299.916,697.2406,-164.42839,1190.4082,588.0538,212.78867,1190.5265,679.39325,-416.00336,1198.6355,741.7073,340.2205,1171.7351,882.7121,-469.18176,1322.0991,783.2955,280.12146,1339.6434,899.33716,-470.15982,1365.5945,791.3949,281.95682,1393.7832,918.225,-585.6563,1364.7433,784.45447,237.32292,1394.3163,873.0718,-597.4063,1344.4812,784.9116,257.2269,1366.9576,863.41986,-481.2731,832.836,652.23975,196.36462,822.8213,700.6963,-196.14009,584.692,686.67816,323.91855,561.84045,717.0788,-18.894941,374.27588,687.80493,555.2288,345.40265,690.5591,196.44225,336.7745,674.50287,579.52106,302.42026,672.4908,211.23512,339.18118,744.4447,532.0912,324.21863,749.90375,121.5767\r\nframe__-0eYiItN2D8__0008015.jpg,pushups_down,1358.9562,594.2152,-127.6277,1378.8062,585.54425,-103.085655,1379.3167,582.54065,-102.9396,1379.8796,579.637,-103.176445,1377.3212,586.6359,-161.80714,1377.39,583.8386,-161.74037,1377.3389,581.03296,-161.94707,1370.8925,551.52423,10.265429,1367.8303,555.2024,-249.28004,1337.618,579.9408,-73.265915,1337.4081,578.4546,-147.75615,1264.7719,448.87607,236.6523,1255.577,532.43494,-363.03683,1151.2034,485.43146,568.8237,1109.6393,596.1429,-432.7585,1200.2098,601.78265,816.70764,1181.1089,712.92615,-453.17413,1230.5083,621.5313,854.06995,1212.1213,744.3869,-513.0743,1238.2799,629.6969,806.0045,1232.817,730.6023,-496.90207,1224.3662,626.3622,798.43933,1217.1244,716.7935,-442.37875,955.88995,461.82184,192.55501,939.0179,514.12146,-192.79158,752.2938,488.29495,477.65262,729.5202,550.3294,81.91183,561.58826,507.62775,727.0534,528.01953,542.7795,317.1854,519.4356,490.88596,751.907,483.36908,521.7471,338.28387,552.4862,601.8322,733.51935,526.8659,628.56537,294.57712\r\nframe__z0u-9E2HmdA__0014571.jpg,pushups_down,1303.13,1593.4802,-1335.6191,1298.1992,1568.0687,-1405.1902,1307.6598,1563.9415,-1404.6415,1317.1475,1559.6741,-1404.6711,1274.4156,1563.6401,-1346.9459,1266.6051,1558.1193,-1346.3619,1259.1666,1552.9817,-1346.9102,1351.6598,1503.999,-1454.0264,1271.3212,1493.718,-1188.4233,1352.3983,1567.7793,-1321.8871,1328.7261,1567.7626,-1243.2133,1655.2516,1400.819,-1241.4985,1285.7906,1315.7693,-885.2807,1957.608,1402.0875,-1027.8256,1285.0499,1312.4467,-275.1945,1864.928,1610.46,-968.90497,1243.9398,1517.1349,-100.52482,1865.6832,1658.3809,-1100.4216,1204.2993,1543.169,-156.15794,1792.4718,1644.2058,-1132.2972,1218.3594,1562.8796,-218.82964,1772.0629,1624.2958,-988.08276,1247.2961,1558.102,-124.52043,1856.1825,1327.8987,-210.97218,1698.0311,1268.429,212.28238,2033.9036,1294.6783,749.2839,1788.8235,1247.9243,1223.8157,2177.057,1187.3939,1695.5125,1889.6511,1165.4965,2268.602,2203.8655,1131.8702,1798.227,1922.5454,1127.7859,2383.5374,2193.5654,1314.9186,1754.0682,1879.8551,1271.1093,2416.9968\r\nframe__QVNlEfFOWwg__0001809.jpg,pushups_down,1394.4242,868.072,84.4095,1426.9824,854.96356,96.86947,1426.7301,852.24835,97.06128,1426.5847,849.7045,96.72481,1429.0514,854.9431,27.09527,1430.6605,850.12604,27.001835,1432.2102,845.32446,26.722445,1419.0703,816.8897,198.54149,1426.4852,812.7215,-101.234795,1367.8901,852.98,138.81973,1371.531,849.329,52.706455,1264.4325,721.8358,380.53983,1299.5388,781.2536,-266.51712,1082.3055,707.6604,640.5526,1093.0361,796.62244,-607.3096,1096.2396,844.05554,832.07947,1158.3273,986.1049,-879.2372,1117.8805,860.41943,883.16785,1190.485,1025.5443,-939.04315,1141.3313,879.6785,835.63464,1216.6238,1024.1958,-880.0735,1132.1521,874.05426,815.51855,1199.1554,1008.91144,-855.0806,871.18384,801.6529,211.5804,882.0276,841.5724,-211.45782,567.088,815.66235,258.5167,547.49176,871.21173,-170.68399,294.5759,786.819,388.11163,246.76375,832.11005,-121.87763,244.5865,760.9989,396.48535,191.54268,801.3592,-129.03085,263.72595,884.9854,307.99054,216.20715,938.7027,-264.32333\r\nframe__hjklQnYRz_8__0010520.jpg,pushups_down,1146.8435,936.54034,-30.834461,1163.903,919.4084,0.30692315,1164.3849,917.24506,0.4929818,1165.0016,915.2326,0.42627546,1160.6686,918.7223,-67.06529,1159.2898,915.2608,-67.01804,1157.8578,911.8201,-67.17228,1151.3676,895.3743,148.10474,1141.6774,892.21655,-142.87944,1127.3893,934.58984,31.70812,1123.5898,930.7268,-51.56287,1028.4515,866.4954,359.17816,1036.6781,890.89075,-313.56735,913.3167,869.57855,384.67612,894.77405,879.94617,-471.40637,940.85767,955.2958,209.00763,944.81573,1002.0917,-543.0217,967.5888,968.0509,208.01004,971.77264,1032.743,-599.28503,977.9629,988.7367,157.55812,987.04047,1020.9154,-569.34,970.90094,987.15247,176.4126,977.7534,1009.33105,-529.8032,764.82214,884.7076,214.9029,756.8993,906.33466,-214.23392,542.31305,900.2254,209.127,520.97235,926.0254,-177.12529,342.33316,897.786,314.20868,308.7686,922.4618,-93.30295,307.45233,883.5064,316.85498,274.25113,906.3885,-95.33043,308.5805,979.6272,206.07344,273.9178,1002.5604,-252.19339\r\nframe___qNmbXRZtfY__0009637.jpg,pushups_down,1215.9065,929.7536,-100.54587,1230.7301,912.4901,-82.22614,1229.4191,908.6341,-82.06423,1228.2529,905.14343,-81.88523,1231.2992,914.5533,-147.7923,1231.6854,911.6554,-148.18301,1231.9015,908.65784,-148.78535,1217.9012,879.555,50.306618,1224.6654,883.3766,-242.55086,1196.5638,921.8546,-42.962578,1198.5212,923.6569,-127.25909,1104.5222,850.4032,278.66687,1131.6682,889.5446,-373.53668,1133.887,1007.50134,272.24808,1144.8293,1061.2252,-390.3326,1234.5288,1010.4282,132.71803,1257.7303,1043.9823,-238.37207,1274.5414,1013.42114,134.80994,1304.217,1047.5042,-318.64114,1272.9158,992.0874,109.14483,1293.2396,1018.1629,-320.23956,1258.5045,990.9833,111.10522,1270.9109,1012.51843,-240.76483,870.7784,832.52783,204.4405,871.2374,858.4709,-203.82463,676.53326,913.9827,238.88496,678.4415,946.67096,-150.05939,499.90494,970.30005,373.92136,475.86533,989.9455,-30.961231,455.05106,971.18256,385.58035,423.34967,986.9595,-35.65553,523.9724,1070.0297,306.0069,515.1963,1086.6094,-168.87419\r\nframe__eQWFHpDRurQ__0024095.jpg,pushups_down,1350.3002,835.4072,57.327415,1374.0641,839.1816,-8.181583,1379.6835,832.17816,-7.8610735,1385.0364,825.3295,-7.975689,1357.1688,856.2412,-28.901989,1352.1274,860.8029,-28.694069,1346.8569,865.05273,-28.67402,1380.7847,797.89734,-173.05887,1329.1306,855.03204,-260.10742,1338.1332,805.4078,16.698772,1323.0116,823.1052,-7.889089,1324.7644,616.8072,-206.50801,1179.5165,804.07153,-317.188,1222.292,470.30896,0.7413709,992.91595,752.7763,-119.579765,1200.2222,573.8347,323.4694,1029.2917,783.2727,108.764206,1214.2958,594.19946,354.23108,1036.5515,801.33795,117.00717,1211.8645,625.90155,330.8447,1065.623,789.9294,117.05254,1200.4169,624.0982,318.00647,1063.1593,782.7022,115.24267,961.6651,467.3595,47.70129,899.6831,569.9433,-47.21577,841.0154,438.43,565.0851,818.62463,508.88217,482.91675,717.57135,388.17252,999.0907,719.2785,415.1121,982.50146,698.3733,374.64374,1048.3315,701.40454,395.31604,1035.9056,692.0745,389.93802,1085.1736,696.655,399.1259,1091.3345\r\nframe__a8P8FauOYRw__0026906.jpg,pushups_down,474.15143,619.2094,55.251644,467.28745,588.23285,10.83433,470.99002,584.189,10.843906,474.57883,579.8877,10.777538,463.6365,590.58105,74.906845,464.53577,588.4841,74.964355,465.74313,586.3022,74.84186,507.53064,556.187,-91.58497,492.39453,566.1657,196.9544,509.32245,619.73016,20.895096,504.0362,623.6185,105.66596,649.4934,632.1849,-221.0722,683.29504,585.4064,362.36597,699.5382,856.4546,-48.825287,756.906,795.9929,413.30338,576.35956,788.89667,291.61652,600.6397,796.71625,438.69412,527.89087,786.14154,260.98434,543.707,793.4499,453.70657,533.7059,749.95026,231.03314,538.336,777.22534,465.77237,559.9791,746.6255,284.43826,563.90125,775.528,435.53525,1075.8262,642.53656,-189.05849,1081.4053,617.0874,190.15599,1409.7598,726.42535,-181.82224,1394.9825,690.16565,250.03535,1746.8838,766.1564,-203.98865,1702.172,710.1522,306.8034,1807.8438,754.5811,-210.72421,1763.372,692.17664,308.2585,1766.0386,859.7829,-301.2169,1725.3732,811.2839,259.8522\r\nframe__VQKqjHtY8jA__0012133.jpg,pushups_down,1490.1082,670.16174,48.180508,1514.4208,652.7947,74.28036,1514.3038,649.9112,74.56175,1514.3615,647.1856,74.27403,1514.8938,652.11,-3.9255738,1515.4125,647.6353,-4.0559683,1515.8517,643.2109,-4.3845387,1503.9474,613.33057,208.09102,1504.3699,610.37683,-133.36559,1463.6458,657.6422,110.122,1464.1699,654.77264,11.920027,1352.4983,553.4206,405.21948,1391.3622,588.3013,-321.48575,1221.5042,608.668,667.0252,1274.8218,702.47205,-621.07007,1256.1633,708.49805,759.9453,1341.7639,813.4238,-787.4313,1272.9633,725.86127,799.0222,1367.3403,832.31635,-850.1406,1289.8774,736.47174,742.3358,1377.5396,820.1505,-825.9193,1282.4056,734.52246,737.1921,1363.9899,812.0211,-776.9467,1002.8532,588.32745,229.6241,1002.5205,606.8495,-229.07114,726.9733,644.65533,231.60252,712.6102,660.2704,-260.6725,463.26532,646.13074,321.37415,426.50586,653.36316,-303.88162,413.9075,618.9465,322.24387,376.7624,619.4356,-316.68204,428.1994,748.7706,223.52182,385.7218,772.09607,-473.74677\r\nframe__gUXOyOrFQcw__0011966.jpg,pushups_down,1636.5653,718.56744,53.433994,1666.7334,696.66235,64.082146,1666.4973,694.9267,64.2798,1666.483,693.52856,64.4288,1664.9205,692.40875,5.260798,1664.9023,686.08466,5.397395,1664.6589,679.8016,5.4525514,1648.4795,658.7358,176.22345,1645.2476,641.50946,-74.80913,1602.8136,709.8881,109.2731,1601.6807,700.39954,35.224426,1437.6561,586.59393,366.7358,1494.1731,687.6955,-183.48573,1366.8755,809.76917,402.71082,1441.891,908.04913,-78.58701,1529.3717,793.7934,452.8045,1594.1908,864.42285,169.15767,1590.4326,789.2024,465.43857,1655.2646,861.0493,135.21854,1598.9271,772.1309,483.843,1655.282,830.22687,102.60318,1572.6405,772.7099,454.05777,1620.7659,824.4186,157.55017,1042.9581,596.18536,174.15271,1044.121,670.26044,-173.68784,675.22,674.40753,245.3149,652.64294,797.5288,-148.82167,383.36884,702.59344,353.31274,284.1906,843.26215,-242.19374,324.22092,690.4764,363.71417,205.00282,836.55927,-261.1294,376.41843,817.9523,325.84653,302.96356,952.91437,-372.57632\r\nframe__HRxXKX8zzs8__0016016.jpg,pushups_down,1295.0234,823.0598,30.930965,1317.8776,806.0071,42.16744,1317.6602,801.741,42.292114,1317.5276,797.848,42.09395,1318.306,807.6748,-18.49527,1319.9832,804.4437,-18.536411,1321.4855,801.1024,-18.643406,1313.7988,768.5712,146.77457,1320.5846,771.4178,-127.40949,1275.0624,810.8296,79.16403,1276.9006,812.36597,-1.6154493,1173.3083,719.45844,359.75943,1225.0499,774.1154,-252.12236,1172.7025,904.17676,399.51328,1234.9978,954.8938,-196.48907,1336.5618,893.9584,415.07446,1372.5594,906.04095,5.543279,1390.5061,901.109,451.70523,1424.8926,904.8515,-59.96282,1392.1083,878.9377,455.5505,1418.9795,877.57324,-78.44677,1373.7006,874.1238,410.6494,1391.0004,872.3901,-3.407827,897.94495,682.7578,186.01135,912.6496,707.44745,-185.7454,670.76843,780.7671,243.01836,673.79974,787.328,-131.52621,459.7599,829.4269,344.47226,430.35077,827.02167,-78.5011,407.96735,825.54456,353.06625,373.03207,823.8016,-84.2708,469.16214,936.73553,285.8671,447.57053,925.21246,-193.84087\r\nframe__RK8ld0M_n_4__0009893.jpg,pushups_down,355.4306,368.63843,-265.34744,341.49713,360.7515,-303.0744,342.11847,357.79245,-302.94788,342.77045,354.6987,-302.93298,339.20746,362.651,-260.25623,338.22748,361.7196,-260.28183,337.4057,360.77826,-260.68195,351.75858,333.3603,-381.1124,343.24152,340.57837,-183.80266,373.7929,355.22568,-284.06198,371.6591,359.78088,-225.47655,447.46872,317.1027,-413.23398,400.7638,292.58636,-25.263283,492.4982,451.7275,-385.716,431.09146,389.30603,154.13214,374.124,473.62817,-286.93417,349.21445,412.7188,154.0642,345.98465,486.92892,-336.01474,322.25806,412.89963,148.4065,335.40826,461.48734,-339.99677,317.69238,409.22412,128.47171,347.8818,452.1634,-288.81342,332.4466,407.8306,142.06529,661.7272,308.86053,-126.20622,635.448,294.26083,126.38484,801.2057,330.49036,130.98964,776.9986,319.79376,351.79993,924.5633,341.02066,401.04956,886.7496,329.87906,669.7403,944.77,329.35193,422.96597,908.87805,319.15497,700.4846,954.462,397.5951,327.72632,904.3246,392.48276,647.7794\r\nframe__1GxTkJpufx0__0015921.jpg,pushups_down,1139.9718,1662.4283,-90.88625,1100.9716,1635.6855,-159.78828,1099.9841,1627.4182,-159.59947,1098.6506,1618.6344,-160.12517,1100.6619,1639.4598,-45.120663,1100.1896,1635.1342,-45.36963,1100.4319,1630.6874,-45.979645,1111.8013,1564.2461,-276.78882,1114.0872,1583.2198,235.95453,1178.5563,1636.446,-122.83705,1179.4264,1643.4475,26.422962,1279.7617,1545.7206,-534.9229,1358.7286,1452.0435,690.3122,1279.6533,1888.7155,-540.87024,1392.0687,1771.8109,907.76074,1001.44476,1887.0836,-257.7063,1106.4731,1815.1035,1020.46796,917.87946,1904.2432,-403.57358,1026.3765,1829.7195,1090.9337,918.29114,1852.0524,-436.82248,1010.39197,1787.7769,1092.614,964.4829,1835.5352,-266.9707,1038.1173,1782.9987,1019.63525,1838.5752,1299.3198,-381.2446,1869.2411,1260.2645,382.0336,2271.5752,1544.4698,-310.62955,2301.5679,1477.3628,367.3268,2715.9465,1676.7705,-255.305,2700.8335,1598.6029,539.37897,2817.5867,1663.3364,-258.27017,2799.6025,1593.3439,544.8125,2698.9573,1895.2926,-470.95984,2697.5332,1815.963,362.8615\r\nframe__S2r3Zp_fMNw__0003146.jpg,pushups_down,770.46063,849.92566,-136.62112,767.85205,827.8133,-148.31802,771.68677,823.5911,-148.19717,775.5025,819.04407,-148.32729,761.4351,833.4771,-102.764366,760.2614,834.3508,-102.67264,759.2821,835.3022,-102.87872,799.65027,804.97534,-148.20503,777.0417,823.4239,55.371365,797.4828,849.1318,-133.8236,788.4009,858.5976,-75.45194,886.57416,872.47485,-284.4001,901.5066,824.6416,274.56982,889.96466,1033.8179,-219.89748,905.1394,958.5248,381.89908,799.1803,985.2512,-14.7071295,792.7821,976.648,462.40778,753.0873,986.44257,-46.92531,744.6044,982.76245,481.46753,754.74615,962.7136,-60.99334,748.11597,975.79095,478.3253,778.7278,960.0613,-15.907582,769.69653,973.9425,454.4518,1156.7781,926.6644,-183.5059,1158.0056,888.6708,183.55731,1376.6152,957.53094,-219.0042,1362.0151,920.1729,235.1518,1583.7834,964.20807,-249.57968,1545.5331,908.418,348.06927,1608.9067,940.9408,-246.65663,1571.8147,886.76434,358.4104,1637.6132,1012.708,-302.02612,1597.715,967.02356,306.6742\r\nframe__dxA21IeBB8o__0020029.jpg,pushups_down,2363.3555,1794.5732,138.10562,2395.8777,1775.0508,192.15916,2395.057,1771.9269,192.72232,2394.489,1769.0127,192.20056,2395.844,1772.0795,84.95279,2396.1724,1765.4412,85.0059,2396.369,1758.7424,84.37325,2373.8333,1740.6097,449.77725,2377.0977,1727.4236,-34.605427,2329.8398,1793.8403,249.44426,2330.5796,1784.1804,110.92255,2155.6035,1670.7532,842.7345,2222.3582,1728.1487,-409.5052,1952.0874,1697.4889,1118.2769,2016.437,1725.9369,-1104.5065,1978.1964,1853.3499,1235.9227,2075.9707,1945.9175,-1688.6045,2024.68,1863.644,1358.3055,2122.942,1980.8528,-1812.9941,2042.7732,1899.2328,1264.8363,2138.2207,1979.8644,-1718.7369,2030.0302,1904.6705,1194.538,2116.9802,1970.5562,-1656.0333,1723.0361,1761.8799,403.21417,1736.1326,1811.8326,-402.6295,1329.938,1771.6034,453.87125,1280.0055,1820.6826,-504.48932,962.22815,1747.603,640.89246,904.41473,1781.5734,-471.33304,895.28345,1725.6038,645.4928,848.0332,1758.7025,-488.23767,902.06476,1894.8647,425.2381,829.03253,1906.1792,-821.3278\r\nframe__yxiYs9htplg__0021323.jpg,pushups_down,781.5221,666.6202,15.69584,757.1882,650.6601,-32.856884,756.4719,646.9959,-32.735313,755.70166,643.0326,-32.87834,757.30054,649.7767,19.80278,756.9196,645.99567,19.835228,756.8747,642.2068,19.610035,763.3335,608.1667,-134.42029,762.9541,609.94165,107.39639,803.585,651.1101,-12.165032,804.1172,650.9397,58.43562,873.1406,602.1067,-236.23186,912.00867,551.388,299.1026,902.09106,806.929,-154.1163,949.69727,738.3886,376.84793,768.7228,783.0891,32.104744,792.75055,741.78,465.84305,722.9807,795.5431,-17.240456,740.2024,745.4966,484.7221,726.3429,761.7249,-47.491142,736.6548,727.1972,505.9894,750.2742,751.1141,22.32715,755.2806,722.7383,468.3576,1228.1614,548.07837,-162.9215,1228.8739,527.76324,163.3183,1485.1145,646.4633,-73.941055,1458.7712,627.3368,193.69205,1741.6969,676.4747,-27.398615,1692.681,669.6946,262.00772,1791.6344,661.031,-26.356613,1740.6127,655.3726,263.86914,1746.4648,773.47864,-89.562614,1715.2402,776.1781,230.82059\r\nScreenshot_2021-02-11_at_15.20.27.png,pushups_down,731.0344,1099.5769,-1259.9427,739.18353,1056.9142,-1314.7714,754.02875,1051.0238,-1314.5204,768.69885,1045.0719,-1315.3671,703.75964,1057.205,-1256.352,692.5786,1053.3351,-1255.6605,681.79504,1049.8059,-1255.4525,813.2481,993.7535,-1323.0663,691.541,994.00183,-1075.883,788.4806,1084.275,-1239.459,751.1522,1090.7021,-1166.3568,1128.8483,929.99036,-1156.5056,716.5906,852.57806,-827.98645,1471.0673,929.3647,-1087.3457,612.67865,839.16223,-501.1953,1544.8787,1192.9368,-1034.4791,485.8537,1046.9568,-454.2491,1591.8474,1232.8794,-1152.293,425.48373,1067.8717,-546.65564,1541.6974,1256.8955,-1166.7194,443.01178,1089.2179,-613.78326,1503.0745,1238.9623,-1043.4694,484.89505,1084.984,-487.54355,1437.6652,864.3005,-178.89322,1278.0476,812.67737,178.34894,1629.7252,859.75684,555.3278,1498.5491,846.2829,839.22864,1801.2817,788.35535,1310.149,1694.2584,807.97614,1555.2108,1835.9268,744.75275,1386.3448,1742.3617,767.7974,1634.2838,1814.6827,900.59717,1362.5557,1708.1504,954.27527,1620.1431\nframe__GXADVSLXPpc__0012459.jpg,pushups_down,1041.4283,928.48883,-353.46625,1046.5734,938.5249,-372.53287,1046.4346,941.30176,-372.49066,1046.1652,944.21814,-372.39786,1048.8776,931.2565,-373.466,1050.7648,929.0232,-373.46375,1052.5072,926.74963,-373.64014,1048.9563,949.2984,-372.51202,1060.3137,924.4515,-375.63916,1038.151,927.6781,-342.283,1041.159,920.5993,-342.7657,1058.4261,936.5416,-290.9157,1044.4072,899.0268,-299.27466,1049.4908,906.0612,-118.54662,1018.16724,851.8047,-186.08192,1027.5717,896.4636,-20.97438,992.5597,846.3369,-117.29791,1024.299,896.3857,-15.715685,986.55176,841.131,-126.35744,1019.93555,896.5463,-27.078241,989.14075,846.9718,-131.31493,1020.6299,895.0518,-22.936134,992.12366,851.263,-120.05266,1027.9631,884.33246,11.325583,1019.7623,872.2163,-10.818472,1026.1707,871.8689,287.77847,1018.7214,860.8525,246.9738,1027.9753,858.371,560.59576,1022.2554,853.0786,528.5035,1028.7405,856.3027,590.97284,1025.7211,849.78564,559.70624,1024.2108,854.21564,594.9724,1011.2684,854.8363,568.35406\r\nframe__64qsroYqaRE__0003157.jpg,pushups_down,403.00558,715.2366,-97.96221,390.50165,694.41284,-152.20563,392.2794,691.6776,-152.14522,393.9738,688.5913,-152.43092,388.7008,691.3187,-84.98525,389.4648,687.1839,-84.90541,390.60217,683.0167,-85.14963,415.37997,660.53296,-270.9374,409.84366,656.7416,35.046696,431.96756,710.4778,-134.00764,430.28647,708.3964,-45.36142,544.0364,675.9415,-411.20874,576.9923,640.3906,275.0993,552.75073,870.39044,-332.92322,612.7881,814.2918,310.1831,426.4521,848.6171,-129.60037,456.14966,832.1589,265.31113,378.44067,857.557,-209.76317,399.11237,838.49756,265.51846,380.9551,827.9641,-232.00595,397.67688,821.6945,256.40143,407.31595,820.89246,-138.65167,418.56653,814.8647,249.93665,906.8526,636.13153,-218.41367,903.745,618.57574,219.11902,1159.2454,704.0501,-101.39881,1126.2509,691.1802,304.0829,1417.8921,719.9206,-3.736327,1345.0905,713.42053,457.3436,1465.7988,701.8232,-0.74758005,1389.907,699.1692,468.0613,1420.9696,819.06396,-90.98542,1359.2075,811.0603,413.5697\r\nframe__nhy9aJ-veTw__0003280.jpg,pushups_down,1501.7379,650.5682,-726.0951,1508.5029,594.2158,-696.10583,1512.668,588.3774,-696.32117,1516.8999,583.3587,-696.52185,1482.1967,601.0443,-756.22626,1466.7583,598.0388,-755.88495,1451.2747,595.25555,-755.74976,1459.8502,555.176,-481.5537,1374.4305,570.6186,-727.5712,1458.8727,663.1328,-635.94214,1429.0476,667.0283,-705.3281,1290.4099,539.07355,-293.51883,1105.2839,632.4004,-658.4192,1186.5452,531.0013,62.37183,827.47424,608.96265,-523.35406,1229.6555,705.9627,275.1613,898.32874,815.6498,-325.05304,1282.7535,724.2728,285.80212,925.08044,865.10376,-372.49304,1274.0542,744.62964,239.76015,971.6154,845.67413,-358.6304,1235.0402,742.1461,262.9823,961.79675,827.31134,-322.85046,827.95056,570.88446,153.4784,739.2327,614.0202,-152.42639,634.03326,561.2537,556.1576,521.78503,582.9102,365.9236,477.7331,509.3676,1036.6874,371.63095,503.4344,867.6596,441.8653,470.90155,1096.0624,336.02048,470.31824,927.813,486.3683,594.56305,1220.0287,393.01096,611.37756,993.3323\r\nframe__Bv00SMbu0JY__0000662.jpg,pushups_down,727.6642,796.47644,-71.58198,701.27655,779.44684,-132.189,700.3102,775.4348,-132.16219,699.32874,771.1122,-132.3694,701.8725,778.8801,-66.49385,701.50494,775.09106,-66.37893,701.44257,771.3078,-66.54548,704.1836,732.54895,-256.9236,705.4668,736.2175,38.96156,749.63446,778.8871,-107.50744,750.343,778.8857,-21.433683,816.80347,705.1273,-387.0465,837.3745,705.73474,255.49184,843.86206,903.90173,-323.90884,857.6885,891.4767,307.96857,703.5467,899.8147,-100.92861,698.78955,897.78253,262.42526,658.51575,908.7532,-161.50076,648.62317,902.70276,254.26366,659.18524,882.36505,-189.70773,641.8808,882.1543,265.58755,681.2096,874.496,-111.835075,660.1352,874.6399,254.74731,1157.0553,710.031,-199.35382,1150.6948,718.2314,200.00171,1403.9185,780.9525,-149.77945,1370.3818,803.045,206.27399,1658.7495,799.35565,-101.520935,1596.5652,827.86066,293.82205,1712.6467,782.97546,-105.629326,1650.667,808.802,298.0327,1661.7417,912.8274,-224.4588,1599.6544,957.59436,238.70596\r\nframe__dCNS-QVXa6k__0003662.jpg,pushups_down,1562.4298,568.36945,-133.64561,1578.1394,550.0647,-83.28273,1576.3014,555.19006,-83.33484,1574.644,560.8158,-83.60675,1577.6167,530.3959,-142.77309,1576.3573,520.0004,-142.6862,1574.7506,509.7213,-142.80339,1547.7096,550.04596,197.54124,1549.0164,486.33224,-66.848274,1526.2871,586.4866,-22.902971,1525.5845,561.45465,-100.84404,1333.3652,553.9423,532.0548,1417.4664,566.85333,-213.89915,1346.5713,804.4449,636.2349,1465.7166,798.34686,-214.3902,1561.3021,766.9736,672.0303,1636.8253,798.0582,67.18412,1622.984,755.057,679.38525,1697.871,805.8138,8.398777,1633.9194,723.36005,699.51587,1691.7382,769.2973,2.6962287,1609.1978,727.42633,672.4691,1656.7009,764.4877,63.500576,929.23737,485.76102,249.81857,957.718,494.78683,-249.16185,610.5347,634.2875,202.05745,632.8002,665.70374,-267.3165,306.95956,722.6299,179.67062,267.4689,775.55066,-368.14087,238.28041,713.1233,172.74454,195.4284,759.1227,-379.50977,298.32996,872.5676,137.23643,244.67377,921.92474,-474.74658\r\nframe__8p9Wv9Myu4E__0008086.jpg,pushups_down,1469.5878,637.20734,83.720604,1470.0292,613.5084,136.66478,1467.8688,611.1704,136.50867,1465.9186,608.92523,136.20892,1469.9633,615.97864,67.01,1468.2715,615.2505,67.25267,1466.4874,614.4422,67.28016,1443.5365,606.25543,265.82028,1445.564,611.7946,-28.058548,1449.1354,649.66223,139.1278,1449.6416,653.1277,55.11226,1313.0299,627.376,434.9487,1367.0819,682.26855,-245.91714,1172.8364,647.7136,414.41815,1217.529,687.7107,-201.09663,1192.2502,769.89374,166.02855,1225.6278,815.01044,-50.1207,1214.5685,773.7727,151.37212,1245.8524,831.8111,-90.245476,1221.3027,790.3012,106.04404,1250.3568,827.49194,-72.49114,1215.7241,795.0555,134.32298,1245.0365,821.1993,-38.597572,1085.1326,720.7633,230.7074,1097.4364,766.1854,-229.6944,877.4159,734.8437,255.18307,861.3454,783.23895,-189.50346,672.4429,743.1285,353.41586,630.0134,774.2996,-124.150955,639.62714,719.66644,353.93488,597.12244,742.5916,-114.80996,609.8814,783.69904,223.34032,561.5904,805.4529,-260.12912\r\nframe__Arr4DVlreRs__0003227.jpg,pushups_down,926.68896,515.19446,-107.67314,939.4829,504.27975,-93.08716,938.80884,502.19434,-93.06041,938.2566,500.38458,-93.34686,940.4746,504.23166,-135.96104,941.1682,501.1219,-136.01709,941.7135,497.94833,-136.14963,931.73944,475.16052,15.251819,935.9118,472.3243,-177.53802,909.2372,503.30316,-61.911564,911.0863,501.5882,-116.676254,830.64514,443.27148,159.91101,849.25854,454.29874,-247.54341,805.65247,547.3703,236.92438,796.0803,584.3433,-251.0666,916.86096,560.8645,263.90436,911.1245,578.54236,-144.73213,953.4515,572.9081,272.8878,946.6991,591.9932,-189.53586,956.37805,565.1913,277.70258,949.9881,569.56805,-213.92532,940.6404,557.51105,260.9041,930.1651,564.8583,-155.98364,608.36194,475.9893,137.19595,608.2016,486.01035,-137.24121,438.66003,512.8928,151.07504,427.79364,519.4951,-120.849686,277.55948,500.0434,214.91362,244.38342,513.6521,-79.63487,242.35074,483.12323,225.66866,204.85176,499.1155,-82.41492,267.99472,578.8429,209.06766,239.66083,586.86127,-159.24966\r\nScreenshot_2021-02-11_at_13.12.40.png,pushups_down,1248.4135,983.67914,-355.17047,1218.7834,979.73413,-410.45898,1216.4769,972.0245,-410.4155,1214.059,964.04346,-410.65308,1216.9509,994.1039,-368.8119,1213.7947,997.7609,-368.6293,1211.0457,1001.4632,-369.20584,1193.2899,929.175,-475.89008,1189.1403,983.47107,-289.98047,1253.3678,953.2679,-361.2478,1253.7142,970.4906,-305.9632,1271.2354,773.42957,-420.79834,1213.5726,965.9356,-182.75877,1400.4065,792.4881,-385.14783,1244.8148,949.9678,-8.376754,1401.6744,966.2905,-428.45654,1211.7999,980.21014,178.03955,1411.7255,1008.97107,-473.41617,1192.812,982.1734,186.21294,1377.641,1017.70166,-445.57706,1194.4655,994.1228,187.27985,1374.0051,1009.2439,-418.63846,1200.9873,984.0217,178.06204,1656.2137,777.6232,-111.70917,1628.9272,889.6677,112.05859,1931.7799,838.1687,-3.542994,1892.1754,935.80493,325.6215,2091.6921,719.35187,394.20456,2097.771,892.4626,756.2641,2096.0,695.65576,438.18698,2118.9812,868.1075,797.4518,2209.3943,729.45294,374.57214,2209.7773,926.1572,697.2542\nframe__3v-P5h0fBKg__0002848.jpg,pushups_down,644.93207,233.28308,17.356163,658.2393,224.73235,21.464281,658.446,223.22476,21.519253,658.73016,221.85466,21.398733,657.42615,224.70409,-6.758592,657.63367,222.55588,-6.774502,657.74335,220.39061,-6.8635864,654.72205,207.604,67.31726,653.56226,205.40005,-57.660988,632.763,228.61598,39.858536,632.2202,227.38142,3.148608,568.1915,179.80116,161.6407,595.5048,210.71922,-118.51134,547.94366,281.6113,197.5975,574.1838,313.90887,-77.59389,623.80804,281.72876,218.62416,639.2242,292.5697,68.71215,648.5959,284.32632,227.64073,663.2384,291.68033,50.57735,652.8508,274.60367,231.74652,663.2899,278.97574,36.868847,643.0669,271.86157,217.80711,649.3724,276.14297,64.93008,392.95526,170.13281,88.14966,402.4599,189.5729,-87.90318,257.78903,208.87158,104.078835,265.58786,225.43091,-43.528122,139.40668,217.63954,123.7023,133.75568,228.04124,-18.547352,111.35649,206.65892,125.094154,105.29702,216.94823,-21.726381,142.54512,283.71133,101.6516,136.37894,294.84235,-66.02968\r\nframe___6UF5ZfpAQA__0021097.jpg,pushups_down,1705.5874,536.75946,167.36864,1735.1736,506.65234,167.1036,1735.9948,503.48642,167.15454,1737.006,500.89734,167.03934,1730.7971,506.50516,102.39464,1729.6273,502.43262,102.701385,1728.1619,498.354,102.906525,1716.8179,477.90167,241.48238,1705.7177,471.46072,-42.490227,1670.9653,539.31555,208.62875,1665.5424,535.1698,124.49969,1474.9319,470.9222,456.49274,1544.7457,536.7117,-199.99577,1426.0026,742.0735,529.2105,1559.3461,784.3094,-119.46902,1631.9442,701.63336,541.0401,1692.8195,697.5768,319.2715,1691.6768,696.3934,567.17377,1743.6837,678.4746,315.12848,1706.5352,663.95245,583.08844,1736.5116,656.6538,306.64044,1682.8818,663.1975,544.0319,1706.26,653.6087,320.00565,990.98303,455.47708,213.76271,1009.6527,490.9677,-213.1802,577.6473,586.6955,224.73125,593.7682,630.85614,-169.16425,211.45334,641.5157,252.6941,154.06076,699.48376,-230.57973,138.3133,620.7133,251.75525,74.362335,679.4076,-242.88446,200.05217,797.848,195.48149,124.04217,869.19714,-348.54492\r\nScreenshot_2021-02-11_at_13.40.48.png,pushups_down,1199.0416,1157.3398,-738.73303,1213.917,1141.5077,-777.18915,1222.375,1142.1736,-776.85394,1231.2712,1143.3348,-776.745,1185.0283,1134.278,-784.1071,1174.2925,1128.4015,-783.9073,1163.593,1122.9443,-783.85693,1226.3109,1118.7942,-676.40247,1132.8442,1089.9086,-733.96765,1183.7834,1156.3079,-671.0289,1156.9906,1147.6104,-686.0267,1272.9945,983.7471,-480.01895,1029.1854,1054.2002,-552.4122,1265.2593,878.4522,-123.958786,926.3797,976.77673,-228.02196,1234.2803,1052.922,27.708042,984.34436,1133.6016,-95.03277,1257.5906,1081.9662,-5.435188,979.34985,1151.3398,-179.57349,1242.0062,1073.2891,-45.37615,1018.63885,1144.6191,-206.97025,1220.9896,1068.9166,3.4209576,1022.54376,1137.3219,-115.46706,1030.2008,982.9852,94.75697,928.6318,1019.0221,-94.09193,933.8161,960.3795,615.6716,875.7492,1005.6935,418.91385,851.2799,929.5993,1202.1675,812.43665,971.94135,987.9759,836.44543,910.9636,1273.0457,796.1232,956.20465,1052.3524,835.7321,974.65936,1263.2302,808.1574,1024.9261,1013.35\nframe__q2FvQunl5k8__0008237.jpg,pushups_down,1355.0723,634.2212,-9.416228,1368.2062,611.0623,-2.917385,1366.5294,607.4025,-2.7715054,1365.0463,604.0122,-2.697463,1366.4552,613.4699,-64.27518,1364.718,610.5801,-64.26973,1362.7767,607.65704,-64.42432,1342.8169,586.1913,97.97537,1340.3678,589.3406,-176.59482,1326.9224,636.23315,37.813015,1326.0734,637.59454,-42.528164,1168.6744,600.8985,317.37863,1220.2018,638.2225,-328.07257,1167.6816,802.32227,315.35397,1206.868,841.65564,-265.26764,1296.897,807.4452,242.2812,1317.0183,821.3842,-43.13129,1352.4055,805.749,246.8386,1367.8137,816.7401,-109.38144,1353.0762,788.20404,229.7323,1361.0951,786.1077,-131.66579,1332.0924,787.43945,225.31683,1335.385,786.4547,-52.521584,869.44366,615.919,205.30624,885.87915,642.34216,-204.58205,639.8048,709.0783,259.7069,619.53284,715.3001,-157.73105,421.05585,724.51685,381.75616,367.56985,748.7598,-96.90421,367.03995,712.8621,390.5008,315.61667,749.4792,-109.314964,437.0642,839.8207,347.57632,381.3679,841.1314,-246.69077\r\nframe__TuAm4brPkBk__0002712.jpg,pushups_down,1653.3809,736.4247,61.717293,1661.4556,714.8775,88.46897,1659.3917,713.5478,88.427574,1657.4105,712.4698,88.30283,1663.3246,711.6766,24.84941,1662.8386,707.41125,24.840296,1662.3416,703.2371,24.70619,1632.2789,691.14136,217.65038,1638.8445,682.02844,-57.504574,1624.528,737.69476,117.86904,1626.7699,731.0775,38.61039,1468.8124,665.7922,390.40652,1521.6873,703.29584,-215.92607,1299.837,646.1343,585.97095,1355.0609,701.939,-491.81625,1322.1912,752.5999,717.6582,1411.2219,821.8022,-774.2302,1339.4625,766.6163,767.09973,1434.2177,842.10065,-840.4852,1355.2122,792.89716,708.7559,1446.2417,842.0462,-797.43304,1350.9812,791.75397,696.4259,1434.4595,832.5894,-759.9302,1137.9163,696.83167,196.39905,1150.7996,722.4904,-195.7594,825.6966,719.6623,119.58438,815.96454,748.33344,-209.59262,531.9153,718.34485,142.99522,498.96533,733.94946,-269.54855,485.30164,698.859,135.34029,445.39914,704.484,-281.66034,486.1829,785.215,33.0643,455.7928,822.34314,-421.3041\r\nframe__p2Dg4UYYOSE__0002266.jpg,pushups_down,1340.1842,690.7153,-279.91132,1361.3357,681.71185,-238.55939,1361.5237,685.66656,-238.40637,1361.8716,689.81354,-238.65422,1360.0457,667.0364,-286.89,1359.9929,658.7655,-286.78516,1359.723,650.50793,-286.88165,1352.8828,676.3189,7.8133063,1349.7777,626.52826,-206.17921,1319.783,697.9658,-180.94159,1318.0244,676.8398,-242.58852,1228.626,633.4733,325.88257,1263.9934,666.3934,-293.16168,1220.4193,817.14606,407.97018,1251.0928,823.0755,-236.47003,1328.2534,773.33435,409.59583,1361.6769,788.5863,29.773708,1357.4116,771.90985,419.97293,1395.8523,790.394,2.1706266,1358.7755,742.26935,440.50357,1389.6523,770.18054,-19.887829,1342.661,741.03436,413.33838,1366.9583,763.8413,25.461853,930.6843,614.5099,196.76228,936.8416,637.3625,-196.47401,709.2721,672.8103,207.857,697.66956,682.2135,-168.32619,508.74487,707.0564,335.05664,477.02197,694.3428,-118.29974,468.33392,699.2183,346.27975,434.948,677.2121,-119.210304,488.32706,806.3597,291.4521,456.1725,782.15656,-235.58485\r\nScreenshot_2021-02-11_at_14.11.55.png,pushups_down,1505.9413,803.9985,395.5415,1493.5374,804.4739,431.02756,1496.6555,803.4651,430.95847,1499.6647,802.07416,430.0226,1482.9583,811.04956,382.27698,1477.7733,815.28406,382.14728,1472.6448,819.7439,382.00522,1506.1223,825.13885,562.77405,1473.1802,851.72144,360.09204,1531.8939,821.04486,445.28918,1518.4182,831.012,384.70724,1643.3369,862.05255,574.64374,1521.2723,937.65436,176.12975,1809.4172,856.77423,571.17084,1557.1821,1012.1498,-237.75484,1857.6705,816.3819,560.3119,1483.1664,1036.9609,-613.97156,1872.6885,804.14886,609.81647,1456.4722,1061.7322,-652.5657,1857.876,798.56445,574.6862,1470.06,1046.7831,-599.35364,1847.9994,808.43274,546.12286,1486.6312,1037.3754,-599.0357,1944.098,909.38434,141.10042,1908.3496,963.39984,-138.76868,2152.3064,761.072,181.0123,2133.232,857.9137,-175.39055,1998.77,986.8189,180.0298,1974.0273,1074.4059,-130.78638,1946.1016,1008.16876,178.77611,1925.9678,1093.1362,-123.852325,2037.4214,1068.8151,254.07108,2018.8016,1182.7441,-91.886955\nframe__VQKqjHtY8jA__0009569.jpg,pushups_down,1239.8757,812.8148,-99.72543,1267.6858,795.9636,-76.4237,1268.741,792.1564,-76.3397,1269.8152,788.5516,-76.69653,1265.092,796.4267,-146.44905,1265.1167,791.45966,-146.64264,1265.0758,786.52075,-146.81097,1263.1257,744.7975,36.76578,1256.1603,743.7724,-264.58142,1215.4799,789.86487,-45.387997,1214.0497,788.23346,-132.07324,1147.9116,625.22144,198.17767,1127.8224,690.77423,-358.12598,1039.5112,645.9933,491.04453,951.96844,719.15533,-518.0536,1120.7025,775.48364,719.1128,1053.279,860.5059,-649.50757,1161.0947,796.2693,752.9187,1095.0153,895.5063,-722.3686,1173.1688,808.24023,709.6231,1121.186,881.79614,-703.2487,1154.5315,802.8766,701.7145,1100.652,868.8168,-641.9577,782.457,589.3144,179.1392,757.697,626.51965,-178.95425,548.0683,661.27814,343.18268,516.61884,699.5632,24.265818,338.02982,643.8082,584.88184,287.81787,676.45746,219.12732,300.57025,610.3099,607.34546,240.99901,642.49036,238.37115,305.95087,743.5855,570.7055,272.96466,769.31525,191.83482\r\nframe__8dS4DUkLhBU__0020191.jpg,pushups_down,342.59387,890.3019,11.296735,319.9961,870.8856,-27.496761,319.72372,867.3323,-27.75933,319.33673,863.5958,-28.11377,321.82263,871.00555,44.758904,322.88452,867.479,44.696445,324.0813,864.0189,44.88373,332.20667,833.6451,-108.09165,337.20596,837.10254,211.62337,367.8152,880.60376,-4.926946,369.4129,880.60284,85.991425,447.70093,794.9253,-282.18585,480.92978,776.71594,411.25833,613.5069,738.5195,-466.17828,660.3036,727.8721,544.71716,606.6948,936.3351,-736.5371,649.90643,887.80035,477.88425,573.0097,967.8689,-797.9968,619.02386,902.83417,467.76953,558.8778,959.8594,-746.62195,611.4149,911.4444,396.8331,569.439,951.8916,-720.59985,619.9627,907.9222,444.30957,820.64215,775.35254,-227.41864,818.9287,768.0304,227.48245,1137.846,820.70294,-195.90512,1123.7611,818.87524,163.96318,1432.7375,827.6057,-171.57211,1418.4657,822.292,252.02557,1484.2501,800.2535,-179.20537,1469.0835,791.9652,243.54001,1460.4298,936.1988,-386.43185,1462.3585,938.32416,70.21772\r\nScreenshot_2021-02-11_at_12.27.53.png,pushups_down,1355.3212,864.12177,-637.3735,1341.5878,850.4375,-692.3053,1340.4203,841.8285,-692.2909,1339.2465,832.87335,-692.2404,1337.6519,875.26855,-690.95264,1333.27,884.421,-691.04443,1329.1843,893.5662,-691.7339,1310.8248,815.63293,-707.3617,1294.6268,908.4606,-706.7795,1346.901,853.47675,-612.998,1342.5444,878.09265,-611.52106,1281.8956,757.88464,-562.8787,1232.7891,939.73096,-550.3704,1403.961,743.7351,-483.8852,1307.2717,973.4723,-499.40967,1476.9585,799.35315,-584.9069,1311.1038,957.4301,-556.75104,1494.1272,801.55023,-639.74567,1295.0531,962.0595,-615.23883,1482.8584,815.28705,-641.76636,1295.5096,955.8655,-595.3695,1474.9293,821.4914,-592.13135,1304.2323,945.8407,-557.5743,1339.8203,808.60913,-15.245506,1321.7307,898.91327,15.755296,1431.4161,816.8069,434.194,1416.5542,904.6383,402.04218,1475.5912,815.88666,936.4063,1445.0449,911.40656,918.152,1475.2928,810.3158,989.5346,1444.151,903.4968,971.7811,1520.845,841.6257,939.07294,1487.6569,942.217,922.86884\nframe__iGZUw_fn0X0__0007362.jpg,pushups_down,1086.9545,850.8613,5.9017553,1106.5507,836.6027,24.210356,1106.6232,833.5989,24.31095,1106.8276,830.87335,24.111877,1105.3079,836.9131,-39.23231,1105.8752,833.3856,-39.188793,1106.2291,829.6854,-39.239105,1102.0891,804.6122,148.96931,1102.0908,802.16785,-137.16383,1070.8446,840.3143,59.45321,1070.4669,839.44147,-22.272186,1003.2066,768.91614,335.35043,1026.8269,789.8604,-261.701,994.1455,921.2192,404.97797,1005.11865,927.334,-228.28577,1119.464,907.6226,452.16763,1127.3168,900.12427,4.053452,1155.5869,912.4451,486.4867,1162.9778,903.745,-35.766365,1159.4977,890.917,503.89056,1161.6404,884.7709,-56.146008,1143.3645,885.21857,456.09915,1141.0682,879.68945,-1.3376431,780.7447,720.70416,192.93268,783.04114,731.4175,-192.94142,607.8463,799.20526,265.08337,588.1682,816.82837,-251.2534,433.15497,827.9453,404.97693,365.4133,835.9657,-365.18646,394.14117,821.6294,418.82388,318.5759,818.3654,-385.37543,424.01834,916.95734,369.62534,351.2616,942.5519,-506.10602\r\nframe__Arr4DVlreRs__0003419.jpg,pushups_down,337.21817,520.1629,-5.162988,316.48776,508.00647,-40.731464,315.0907,504.12415,-40.727684,313.6656,500.0518,-40.820957,318.5399,510.43073,3.121655,318.84854,508.81845,3.0645504,319.33453,507.20947,2.8016708,316.7218,471.01855,-116.53044,322.67096,481.92056,83.521,351.8615,504.03665,-26.5453,354.64355,507.79886,31.844122,404.59488,453.62915,-201.4935,427.64252,442.17563,219.23004,476.06348,600.19214,-143.0876,507.045,555.7692,333.454,361.58453,583.0349,31.863382,390.11295,557.64996,442.59338,323.21936,590.4416,6.066327,352.63214,559.07916,464.72873,322.06506,565.1793,-11.298442,344.46506,551.0986,477.90344,339.43988,559.3886,28.48834,358.13318,545.9577,444.95337,648.72186,461.87445,-129.71663,648.5465,455.79663,129.9668,840.32104,502.5345,-96.98051,831.1665,494.81915,111.36982,1031.4741,501.64502,-82.185555,1012.9084,491.76028,147.94638,1067.7361,485.7106,-83.12662,1051.5791,474.54565,149.40854,1046.3597,570.127,-135.23271,1027.9425,574.67535,125.01103\r\nframe__7qsM3yHt4Rk__0006093.jpg,pushups_down,1467.2332,731.05365,-95.337906,1489.1045,718.65656,-62.680172,1488.9757,718.80725,-62.500935,1489.0409,719.11273,-62.816704,1488.3851,711.7782,-118.84989,1488.5709,705.9012,-118.79281,1488.5717,699.95667,-118.94428,1477.7461,697.61096,114.08838,1477.5449,674.8031,-135.32257,1442.9857,729.83746,-21.84315,1442.3717,719.3157,-93.84553,1321.4043,652.95715,364.96738,1367.6575,691.4988,-268.41928,1281.7262,810.9028,500.2466,1320.5227,875.2373,-239.14156,1403.854,809.1989,526.1442,1444.6395,853.38293,13.899385,1440.3542,815.3845,541.7995,1485.876,861.18146,-31.933891,1446.4058,799.3318,536.635,1484.379,831.9477,-61.763283,1429.7764,794.85175,519.99506,1459.8939,827.0064,3.6505775,1009.4709,650.6631,206.72415,1017.95667,677.92035,-206.46526,760.2933,710.8137,191.0087,753.9718,737.523,-167.978,530.03876,726.47845,258.18716,497.715,748.1116,-108.13096,481.8465,710.20074,264.03012,448.5953,730.6136,-112.21943,520.0383,835.8181,201.66277,488.47348,848.4691,-224.04924\r\nframe__i4di_AXtnvY__0011729.jpg,pushups_down,479.33682,752.1579,108.2763,457.8322,735.0499,69.751175,457.19473,732.07916,69.67666,456.41086,728.7974,69.697174,458.91888,733.46124,142.49727,459.19058,729.6484,142.61551,459.7071,725.81024,142.7278,464.95038,701.5687,-27.233816,467.8095,699.0501,300.80698,501.0335,744.4481,83.46081,501.5094,742.86707,177.1214,558.47925,680.64166,-248.77246,599.1385,632.2753,470.1713,673.5023,706.709,-555.74603,742.9435,618.8113,747.31714,638.6095,857.81287,-878.9987,720.17163,746.4232,987.44617,597.85565,887.2428,-930.095,684.9929,755.1774,1029.6858,587.91034,869.4039,-881.5492,680.30756,763.2712,966.8463,604.2675,861.77124,-861.12714,690.88574,764.3072,965.0043,948.5305,671.663,-232.55843,949.77985,641.8369,232.12042,1279.1978,697.5956,-256.18973,1255.5792,678.4935,213.01569,1603.6583,716.79205,-361.56424,1551.8604,674.7718,223.65366,1649.3477,691.8271,-372.95166,1596.9294,644.9144,213.1408,1670.7161,801.43427,-506.24084,1622.103,758.9477,75.68648\r\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/BitmapUtils.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport android.content.ContentResolver;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.ImageFormat;\nimport android.graphics.Matrix;\nimport android.graphics.Rect;\nimport android.graphics.YuvImage;\nimport android.media.Image;\nimport android.media.Image.Plane;\nimport android.net.Uri;\nimport android.os.Build.VERSION_CODES;\nimport android.provider.MediaStore;\nimport android.util.Log;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.core.ExperimentalGetImage;\nimport androidx.camera.core.ImageProxy;\nimport androidx.exifinterface.media.ExifInterface;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\n\n/** Utils functions for bitmap conversions. */\npublic class BitmapUtils {\n  private static final String TAG = \"BitmapUtils\";\n\n  /** Converts NV21 format byte buffer to bitmap. */\n  @Nullable\n  public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {\n    data.rewind();\n    byte[] imageInBuffer = new byte[data.limit()];\n    data.get(imageInBuffer, 0, imageInBuffer.length);\n    try {\n      YuvImage image =\n          new YuvImage(\n              imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);\n      ByteArrayOutputStream stream = new ByteArrayOutputStream();\n      image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 80, stream);\n\n      Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());\n\n      stream.close();\n      return rotateBitmap(bmp, metadata.getRotation(), false, false);\n    } catch (Exception e) {\n      Log.e(\"VisionProcessorBase\", \"Error: \" + e.getMessage());\n    }\n    return null;\n  }\n\n  /** Converts a YUV_420_888 image from CameraX API to a bitmap. */\n  @RequiresApi(VERSION_CODES.LOLLIPOP)\n  @Nullable\n  @ExperimentalGetImage\n  public static Bitmap getBitmap(ImageProxy image) {\n    FrameMetadata frameMetadata =\n        new FrameMetadata.Builder()\n            .setWidth(image.getWidth())\n            .setHeight(image.getHeight())\n            .setRotation(image.getImageInfo().getRotationDegrees())\n            .build();\n\n    ByteBuffer nv21Buffer =\n        yuv420ThreePlanesToNV21(image.getImage().getPlanes(), image.getWidth(), image.getHeight());\n    return getBitmap(nv21Buffer, frameMetadata);\n  }\n\n  /** Rotates a bitmap if it is converted from a bytebuffer. */\n  private static Bitmap rotateBitmap(\n      Bitmap bitmap, int rotationDegrees, boolean flipX, boolean flipY) {\n    Matrix matrix = new Matrix();\n\n    // Rotate the image back to straight.\n    matrix.postRotate(rotationDegrees);\n\n    // Mirror the image along the X or Y axis.\n    matrix.postScale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);\n    Bitmap rotatedBitmap =\n        Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);\n\n    // Recycle the old bitmap if it has changed.\n    if (rotatedBitmap != bitmap) {\n      bitmap.recycle();\n    }\n    return rotatedBitmap;\n  }\n\n  @Nullable\n  public static Bitmap getBitmapFromContentUri(ContentResolver contentResolver, Uri imageUri)\n      throws IOException {\n    Bitmap decodedBitmap = MediaStore.Images.Media.getBitmap(contentResolver, imageUri);\n    if (decodedBitmap == null) {\n      return null;\n    }\n    int orientation = getExifOrientationTag(contentResolver, imageUri);\n\n    int rotationDegrees = 0;\n    boolean flipX = false;\n    boolean flipY = false;\n    // See e.g. https://magnushoff.com/articles/jpeg-orientation/ for a detailed explanation on each\n    // orientation.\n    switch (orientation) {\n      case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:\n        flipX = true;\n        break;\n      case ExifInterface.ORIENTATION_ROTATE_90:\n        rotationDegrees = 90;\n        break;\n      case ExifInterface.ORIENTATION_TRANSPOSE:\n        rotationDegrees = 90;\n        flipX = true;\n        break;\n      case ExifInterface.ORIENTATION_ROTATE_180:\n        rotationDegrees = 180;\n        break;\n      case ExifInterface.ORIENTATION_FLIP_VERTICAL:\n        flipY = true;\n        break;\n      case ExifInterface.ORIENTATION_ROTATE_270:\n        rotationDegrees = -90;\n        break;\n      case ExifInterface.ORIENTATION_TRANSVERSE:\n        rotationDegrees = -90;\n        flipX = true;\n        break;\n      case ExifInterface.ORIENTATION_UNDEFINED:\n      case ExifInterface.ORIENTATION_NORMAL:\n      default:\n        // No transformations necessary in this case.\n    }\n\n    return rotateBitmap(decodedBitmap, rotationDegrees, flipX, flipY);\n  }\n\n  private static int getExifOrientationTag(ContentResolver resolver, Uri imageUri) {\n    // We only support parsing EXIF orientation tag from local file on the device.\n    // See also:\n    // https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html\n    if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())\n        && !ContentResolver.SCHEME_FILE.equals(imageUri.getScheme())) {\n      return 0;\n    }\n\n    ExifInterface exif;\n    try (InputStream inputStream = resolver.openInputStream(imageUri)) {\n      if (inputStream == null) {\n        return 0;\n      }\n\n      exif = new ExifInterface(inputStream);\n    } catch (IOException e) {\n      Log.e(TAG, \"failed to open file to read rotation meta data: \" + imageUri, e);\n      return 0;\n    }\n\n    return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);\n  }\n\n  /**\n   * Converts YUV_420_888 to NV21 bytebuffer.\n   *\n   * <p>The NV21 format consists of a single byte array containing the Y, U and V values. For an\n   * image of size S, the first S positions of the array contain all the Y values. The remaining\n   * positions contain interleaved V and U values. U and V are subsampled by a factor of 2 in both\n   * dimensions, so there are S/4 U values and S/4 V values. In summary, the NV21 array will contain\n   * S Y values followed by S/4 VU values: YYYYYYYYYYYYYY(...)YVUVUVUVU(...)VU\n   *\n   * <p>YUV_420_888 is a generic format that can describe any YUV image where U and V are subsampled\n   * by a factor of 2 in both dimensions. {@link Image#getPlanes} returns an array with the Y, U and\n   * V planes. The Y plane is guaranteed not to be interleaved, so we can just copy its values into\n   * the first part of the NV21 array. The U and V planes may already have the representation in the\n   * NV21 format. This happens if the planes share the same buffer, the V buffer is one position\n   * before the U buffer and the planes have a pixelStride of 2. If this is case, we can just copy\n   * them to the NV21 array.\n   */\n  private static ByteBuffer yuv420ThreePlanesToNV21(\n      Plane[] yuv420888planes, int width, int height) {\n    int imageSize = width * height;\n    byte[] out = new byte[imageSize + 2 * (imageSize / 4)];\n\n    if (areUVPlanesNV21(yuv420888planes, width, height)) {\n      // Copy the Y values.\n      yuv420888planes[0].getBuffer().get(out, 0, imageSize);\n\n      ByteBuffer uBuffer = yuv420888planes[1].getBuffer();\n      ByteBuffer vBuffer = yuv420888planes[2].getBuffer();\n      // Get the first V value from the V buffer, since the U buffer does not contain it.\n      vBuffer.get(out, imageSize, 1);\n      // Copy the first U value and the remaining VU values from the U buffer.\n      uBuffer.get(out, imageSize + 1, 2 * imageSize / 4 - 1);\n    } else {\n      // Fallback to copying the UV values one by one, which is slower but also works.\n      // Unpack Y.\n      unpackPlane(yuv420888planes[0], width, height, out, 0, 1);\n      // Unpack U.\n      unpackPlane(yuv420888planes[1], width, height, out, imageSize + 1, 2);\n      // Unpack V.\n      unpackPlane(yuv420888planes[2], width, height, out, imageSize, 2);\n    }\n\n    return ByteBuffer.wrap(out);\n  }\n\n  /** Checks if the UV plane buffers of a YUV_420_888 image are in the NV21 format. */\n  private static boolean areUVPlanesNV21(Plane[] planes, int width, int height) {\n    int imageSize = width * height;\n\n    ByteBuffer uBuffer = planes[1].getBuffer();\n    ByteBuffer vBuffer = planes[2].getBuffer();\n\n    // Backup buffer properties.\n    int vBufferPosition = vBuffer.position();\n    int uBufferLimit = uBuffer.limit();\n\n    // Advance the V buffer by 1 byte, since the U buffer will not contain the first V value.\n    vBuffer.position(vBufferPosition + 1);\n    // Chop off the last byte of the U buffer, since the V buffer will not contain the last U value.\n    uBuffer.limit(uBufferLimit - 1);\n\n    // Check that the buffers are equal and have the expected number of elements.\n    boolean areNV21 =\n        (vBuffer.remaining() == (2 * imageSize / 4 - 2)) && (vBuffer.compareTo(uBuffer) == 0);\n\n    // Restore buffers to their initial state.\n    vBuffer.position(vBufferPosition);\n    uBuffer.limit(uBufferLimit);\n\n    return areNV21;\n  }\n\n  /**\n   * Unpack an image plane into a byte array.\n   *\n   * <p>The input plane data will be copied in 'out', starting at 'offset' and every pixel will be\n   * spaced by 'pixelStride'. Note that there is no row padding on the output.\n   */\n  private static void unpackPlane(\n      Plane plane, int width, int height, byte[] out, int offset, int pixelStride) {\n    ByteBuffer buffer = plane.getBuffer();\n    buffer.rewind();\n\n    // Compute the size of the current plane.\n    // We assume that it has the aspect ratio as the original image.\n    int numRow = (buffer.limit() + plane.getRowStride() - 1) / plane.getRowStride();\n    if (numRow == 0) {\n      return;\n    }\n    int scaleFactor = height / numRow;\n    int numCol = width / scaleFactor;\n\n    // Extract the data in the output buffer.\n    int outputPos = offset;\n    int rowStart = 0;\n    for (int row = 0; row < numRow; row++) {\n      int inputPos = rowStart;\n      for (int col = 0; col < numCol; col++) {\n        out[outputPos] = buffer.get(inputPos);\n        outputPos += pixelStride;\n        inputPos += plane.getPixelStride();\n      }\n      rowStart += plane.getRowStride();\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/CameraImageGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\n\n/** Draw camera image to background. */\npublic class CameraImageGraphic extends Graphic {\n\n  private final Bitmap bitmap;\n\n  public CameraImageGraphic(GraphicOverlay overlay, Bitmap bitmap) {\n    super(overlay);\n    this.bitmap = bitmap;\n  }\n\n  @Override\n  public void draw(Canvas canvas) {\n    canvas.drawBitmap(bitmap, getTransformationMatrix(), null);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/CameraSource.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.ImageFormat;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.Camera;\nimport android.hardware.Camera.CameraInfo;\nimport android.hardware.Camera.Parameters;\nimport android.util.Log;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\nimport android.view.WindowManager;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport com.google.android.gms.common.images.Size;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.IdentityHashMap;\nimport java.util.List;\n\n/**\n * Manages the camera and allows UI updates on top of it (e.g. overlaying extra Graphics or\n * displaying extra information). This receives preview frames from the camera at a specified rate,\n * sending those frames to child classes' detectors / classifiers as fast as it is able to process.\n */\npublic class CameraSource {\n  @SuppressLint(\"InlinedApi\")\n  public static final int CAMERA_FACING_BACK = CameraInfo.CAMERA_FACING_BACK;\n\n  @SuppressLint(\"InlinedApi\")\n  public static final int CAMERA_FACING_FRONT = CameraInfo.CAMERA_FACING_FRONT;\n\n  public static final int IMAGE_FORMAT = ImageFormat.NV21;\n  public static final int DEFAULT_REQUESTED_CAMERA_PREVIEW_WIDTH = 480;\n  public static final int DEFAULT_REQUESTED_CAMERA_PREVIEW_HEIGHT = 360;\n\n  private static final String TAG = \"MIDemoApp:CameraSource\";\n\n  /**\n   * The dummy surface texture must be assigned a chosen name. Since we never use an OpenGL context,\n   * we can choose any ID we want here. The dummy surface texture is not a crazy hack - it is\n   * actually how the camera team recommends using the camera without a preview.\n   */\n  private static final int DUMMY_TEXTURE_NAME = 100;\n\n  /**\n   * If the absolute difference between a preview size aspect ratio and a picture size aspect ratio\n   * is less than this tolerance, they are considered to be the same aspect ratio.\n   */\n  private static final float ASPECT_RATIO_TOLERANCE = 0.01f;\n\n  protected Activity activity;\n\n  private Camera camera;\n\n  private int facing = CAMERA_FACING_BACK;\n\n  /** Rotation of the device, and thus the associated preview images captured from the device. */\n  private int rotationDegrees;\n\n  private Size previewSize;\n\n  private static final float REQUESTED_FPS = 30.0f;\n  private static final boolean REQUESTED_AUTO_FOCUS = true;\n\n  // This instance needs to be held onto to avoid GC of its underlying resources. Even though it\n  // isn't used outside of the method that creates it, it still must have hard references maintained\n  // to it.\n  private SurfaceTexture dummySurfaceTexture;\n\n  private final GraphicOverlay graphicOverlay;\n\n  /**\n   * Dedicated thread and associated runnable for calling into the detector with frames, as the\n   * frames become available from the camera.\n   */\n  private Thread processingThread;\n\n  private final FrameProcessingRunnable processingRunnable;\n  private final Object processorLock = new Object();\n\n  private VisionImageProcessor frameProcessor;\n\n  /**\n   * Map to convert between a byte array, received from the camera, and its associated byte buffer.\n   * We use byte buffers internally because this is a more efficient way to call into native code\n   * later (avoids a potential copy).\n   *\n   * <p><b>Note:</b> uses IdentityHashMap here instead of HashMap because the behavior of an array's\n   * equals, hashCode and toString methods is both useless and unexpected. IdentityHashMap enforces\n   * identity ('==') check on the keys.\n   */\n  private final IdentityHashMap<byte[], ByteBuffer> bytesToByteBuffer = new IdentityHashMap<>();\n\n  public CameraSource(Activity activity, GraphicOverlay overlay) {\n    this.activity = activity;\n    graphicOverlay = overlay;\n    graphicOverlay.clear();\n    processingRunnable = new FrameProcessingRunnable();\n  }\n\n  // ==============================================================================================\n  // Public\n  // ==============================================================================================\n\n  /** Stops the camera and releases the resources of the camera and underlying detector. */\n  public void release() {\n    synchronized (processorLock) {\n      stop();\n      cleanScreen();\n\n      if (frameProcessor != null) {\n        frameProcessor.stop();\n      }\n    }\n  }\n\n  /**\n   * Opens the camera and starts sending preview frames to the underlying detector. The preview\n   * frames are not displayed.\n   *\n   * @throws IOException if the camera's preview texture or display could not be initialized\n   */\n  @RequiresPermission(Manifest.permission.CAMERA)\n  public synchronized CameraSource start() throws IOException {\n    if (camera != null) {\n      return this;\n    }\n\n    camera = createCamera();\n    dummySurfaceTexture = new SurfaceTexture(DUMMY_TEXTURE_NAME);\n    camera.setPreviewTexture(dummySurfaceTexture);\n    camera.startPreview();\n\n    processingThread = new Thread(processingRunnable);\n    processingRunnable.setActive(true);\n    processingThread.start();\n    return this;\n  }\n\n  /**\n   * Opens the camera and starts sending preview frames to the underlying detector. The supplied\n   * surface holder is used for the preview so frames can be displayed to the user.\n   *\n   * @param surfaceHolder the surface holder to use for the preview frames\n   * @throws IOException if the supplied surface holder could not be used as the preview display\n   */\n  @RequiresPermission(Manifest.permission.CAMERA)\n  public synchronized CameraSource start(SurfaceHolder surfaceHolder) throws IOException {\n    if (camera != null) {\n      return this;\n    }\n\n    camera = createCamera();\n    camera.setPreviewDisplay(surfaceHolder);\n    camera.startPreview();\n\n    processingThread = new Thread(processingRunnable);\n    processingRunnable.setActive(true);\n    processingThread.start();\n    return this;\n  }\n\n  /**\n   * Closes the camera and stops sending frames to the underlying frame detector.\n   *\n   * <p>This camera source may be restarted again by calling {@link #start()} or {@link\n   * #start(SurfaceHolder)}.\n   *\n   * <p>Call {@link #release()} instead to completely shut down this camera source and release the\n   * resources of the underlying detector.\n   */\n  public synchronized void stop() {\n    processingRunnable.setActive(false);\n    if (processingThread != null) {\n      try {\n        // Wait for the thread to complete to ensure that we can't have multiple threads\n        // executing at the same time (i.e., which would happen if we called start too\n        // quickly after stop).\n        processingThread.join();\n      } catch (InterruptedException e) {\n        Log.d(TAG, \"Frame processing thread interrupted on release.\");\n      }\n      processingThread = null;\n    }\n\n    if (camera != null) {\n      camera.stopPreview();\n      camera.setPreviewCallbackWithBuffer(null);\n      try {\n        camera.setPreviewTexture(null);\n        dummySurfaceTexture = null;\n        camera.setPreviewDisplay(null);\n      } catch (Exception e) {\n        Log.e(TAG, \"Failed to clear camera preview: \" + e);\n      }\n      camera.release();\n      camera = null;\n    }\n\n    // Release the reference to any image buffers, since these will no longer be in use.\n    bytesToByteBuffer.clear();\n  }\n\n  /** Changes the facing of the camera. */\n  public synchronized void setFacing(int facing) {\n    if ((facing != CAMERA_FACING_BACK) && (facing != CAMERA_FACING_FRONT)) {\n      throw new IllegalArgumentException(\"Invalid camera: \" + facing);\n    }\n    this.facing = facing;\n  }\n\n  /** Returns the preview size that is currently in use by the underlying camera. */\n  public Size getPreviewSize() {\n    return previewSize;\n  }\n\n  /**\n   * Returns the selected camera; one of {@link #CAMERA_FACING_BACK} or {@link\n   * #CAMERA_FACING_FRONT}.\n   */\n  public int getCameraFacing() {\n    return facing;\n  }\n\n  public boolean setZoom(float zoomRatio) {\n    Log.d(TAG, \"setZoom: \" + zoomRatio);\n    if (camera == null) {\n      return false;\n    }\n\n    Parameters parameters = camera.getParameters();\n    parameters.setZoom(getZoomValue(parameters, zoomRatio));\n    camera.setParameters(parameters);\n    return true;\n  }\n\n  /**\n   * Calculate the zoom value of the target zoom ratio.\n   *\n   * <p>According to the camera API, {@link Parameters#getZoomRatios()} will return a list of zoom\n   * ratios with length {@link Parameters#getMaxZoom()}+1. Each of this value indicates a actual\n   * zoom ratio of the camera.\n   *\n   * <p>E.g. Assume {@link Parameters#getZoomRatios()} return {@code [100, 114, 131, 151, 174, 200,\n   * 234, 268, 300]}, where {@link Parameters#getMaxZoom()}=8. It means, {@code setZoom(0)} will\n   * actual perform 1.00x to the camera, {@code setZoom(1)} will actual perform 1.14x to the camera,\n   * {@code setZoom(2)} will actual perform 1.31x to the camera, ..., {@code setZoom(8)} will actual\n   * perform 3.00x to the camera.\n   *\n   * @param params The parameters of the camera.\n   * @param zoomRatio The target zoom ratio.\n   * @return The maximum zoom value that will not exceed the target {@code zoomRatio}.\n   */\n  private static int getZoomValue(Camera.Parameters params, float zoomRatio) {\n    int zoom = (int) (Math.max(zoomRatio, 1) * 100);\n    List<Integer> zoomRatios = params.getZoomRatios();\n    int maxZoom = params.getMaxZoom();\n    for (int i = 0; i < maxZoom; ++i) {\n      if (zoomRatios.get(i + 1) > zoom) {\n        return i;\n      }\n    }\n    return maxZoom;\n  }\n\n  /**\n   * Opens the camera and applies the user settings.\n   *\n   * @throws IOException if camera cannot be found or preview cannot be processed\n   */\n  @SuppressLint(\"InlinedApi\")\n  private Camera createCamera() throws IOException {\n    int requestedCameraId = getIdForRequestedCamera(facing);\n    if (requestedCameraId == -1) {\n      throw new IOException(\"Could not find requested camera.\");\n    }\n    Camera camera = Camera.open(requestedCameraId);\n\n    SizePair sizePair = PreferenceUtils.getCameraPreviewSizePair(activity, requestedCameraId);\n    if (sizePair == null) {\n      sizePair =\n          selectSizePair(\n              camera,\n              DEFAULT_REQUESTED_CAMERA_PREVIEW_WIDTH,\n              DEFAULT_REQUESTED_CAMERA_PREVIEW_HEIGHT);\n    }\n\n    if (sizePair == null) {\n      throw new IOException(\"Could not find suitable preview size.\");\n    }\n\n    previewSize = sizePair.preview;\n    Log.v(TAG, \"Camera preview size: \" + previewSize);\n\n    int[] previewFpsRange = selectPreviewFpsRange(camera, REQUESTED_FPS);\n    if (previewFpsRange == null) {\n      throw new IOException(\"Could not find suitable preview frames per second range.\");\n    }\n\n    Camera.Parameters parameters = camera.getParameters();\n\n    Size pictureSize = sizePair.picture;\n    if (pictureSize != null) {\n      Log.v(TAG, \"Camera picture size: \" + pictureSize);\n      parameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());\n    }\n    parameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());\n    parameters.setPreviewFpsRange(\n        previewFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],\n        previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);\n    // Use YV12 so that we can exercise YV12->NV21 auto-conversion logic for OCR detection\n    parameters.setPreviewFormat(IMAGE_FORMAT);\n\n    setRotation(camera, parameters, requestedCameraId);\n\n    if (REQUESTED_AUTO_FOCUS) {\n      if (parameters\n          .getSupportedFocusModes()\n          .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {\n        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);\n      } else {\n        Log.i(TAG, \"Camera auto focus is not supported on this device.\");\n      }\n    }\n\n    camera.setParameters(parameters);\n\n    // Four frame buffers are needed for working with the camera:\n    //\n    //   one for the frame that is currently being executed upon in doing detection\n    //   one for the next pending frame to process immediately upon completing detection\n    //   two for the frames that the camera uses to populate future preview images\n    //\n    // Through trial and error it appears that two free buffers, in addition to the two buffers\n    // used in this code, are needed for the camera to work properly.  Perhaps the camera has\n    // one thread for acquiring images, and another thread for calling into user code.  If only\n    // three buffers are used, then the camera will spew thousands of warning messages when\n    // detection takes a non-trivial amount of time.\n    camera.setPreviewCallbackWithBuffer(new CameraPreviewCallback());\n    camera.addCallbackBuffer(createPreviewBuffer(previewSize));\n    camera.addCallbackBuffer(createPreviewBuffer(previewSize));\n    camera.addCallbackBuffer(createPreviewBuffer(previewSize));\n    camera.addCallbackBuffer(createPreviewBuffer(previewSize));\n\n    return camera;\n  }\n\n  /**\n   * Gets the id for the camera specified by the direction it is facing. Returns -1 if no such\n   * camera was found.\n   *\n   * @param facing the desired camera (front-facing or rear-facing)\n   */\n  private static int getIdForRequestedCamera(int facing) {\n    CameraInfo cameraInfo = new CameraInfo();\n    for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {\n      Camera.getCameraInfo(i, cameraInfo);\n      if (cameraInfo.facing == facing) {\n        return i;\n      }\n    }\n    return -1;\n  }\n\n  /**\n   * Selects the most suitable preview and picture size, given the desired width and height.\n   *\n   * <p>Even though we only need to find the preview size, it's necessary to find both the preview\n   * size and the picture size of the camera together, because these need to have the same aspect\n   * ratio. On some hardware, if you would only set the preview size, you will get a distorted\n   * image.\n   *\n   * @param camera the camera to select a preview size from\n   * @param desiredWidth the desired width of the camera preview frames\n   * @param desiredHeight the desired height of the camera preview frames\n   * @return the selected preview and picture size pair\n   */\n  public static SizePair selectSizePair(Camera camera, int desiredWidth, int desiredHeight) {\n    List<SizePair> validPreviewSizes = generateValidPreviewSizeList(camera);\n\n    // The method for selecting the best size is to minimize the sum of the differences between\n    // the desired values and the actual values for width and height.  This is certainly not the\n    // only way to select the best size, but it provides a decent tradeoff between using the\n    // closest aspect ratio vs. using the closest pixel area.\n    SizePair selectedPair = null;\n    int minDiff = Integer.MAX_VALUE;\n    for (SizePair sizePair : validPreviewSizes) {\n      Size size = sizePair.preview;\n      int diff =\n          Math.abs(size.getWidth() - desiredWidth) + Math.abs(size.getHeight() - desiredHeight);\n      if (diff < minDiff) {\n        selectedPair = sizePair;\n        minDiff = diff;\n      }\n    }\n\n    return selectedPair;\n  }\n\n  /**\n   * Stores a preview size and a corresponding same-aspect-ratio picture size. To avoid distorted\n   * preview images on some devices, the picture size must be set to a size that is the same aspect\n   * ratio as the preview size or the preview may end up being distorted. If the picture size is\n   * null, then there is no picture size with the same aspect ratio as the preview size.\n   */\n  public static class SizePair {\n    public final Size preview;\n    @Nullable public final Size picture;\n\n    SizePair(Camera.Size previewSize, @Nullable Camera.Size pictureSize) {\n      preview = new Size(previewSize.width, previewSize.height);\n      picture = pictureSize != null ? new Size(pictureSize.width, pictureSize.height) : null;\n    }\n\n    public SizePair(Size previewSize, @Nullable Size pictureSize) {\n      preview = previewSize;\n      picture = pictureSize;\n    }\n  }\n\n  /**\n   * Generates a list of acceptable preview sizes. Preview sizes are not acceptable if there is not\n   * a corresponding picture size of the same aspect ratio. If there is a corresponding picture size\n   * of the same aspect ratio, the picture size is paired up with the preview size.\n   *\n   * <p>This is necessary because even if we don't use still pictures, the still picture size must\n   * be set to a size that is the same aspect ratio as the preview size we choose. Otherwise, the\n   * preview images may be distorted on some devices.\n   */\n  public static List<SizePair> generateValidPreviewSizeList(Camera camera) {\n    Camera.Parameters parameters = camera.getParameters();\n    List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();\n    List<Camera.Size> supportedPictureSizes = parameters.getSupportedPictureSizes();\n    List<SizePair> validPreviewSizes = new ArrayList<>();\n    for (Camera.Size previewSize : supportedPreviewSizes) {\n      float previewAspectRatio = (float) previewSize.width / (float) previewSize.height;\n\n      // By looping through the picture sizes in order, we favor the higher resolutions.\n      // We choose the highest resolution in order to support taking the full resolution\n      // picture later.\n      for (Camera.Size pictureSize : supportedPictureSizes) {\n        float pictureAspectRatio = (float) pictureSize.width / (float) pictureSize.height;\n        if (Math.abs(previewAspectRatio - pictureAspectRatio) < ASPECT_RATIO_TOLERANCE) {\n          validPreviewSizes.add(new SizePair(previewSize, pictureSize));\n          break;\n        }\n      }\n    }\n\n    // If there are no picture sizes with the same aspect ratio as any preview sizes, allow all\n    // of the preview sizes and hope that the camera can handle it.  Probably unlikely, but we\n    // still account for it.\n    if (validPreviewSizes.size() == 0) {\n      Log.w(TAG, \"No preview sizes have a corresponding same-aspect-ratio picture size\");\n      for (Camera.Size previewSize : supportedPreviewSizes) {\n        // The null picture size will let us know that we shouldn't set a picture size.\n        validPreviewSizes.add(new SizePair(previewSize, null));\n      }\n    }\n\n    return validPreviewSizes;\n  }\n\n  /**\n   * Selects the most suitable preview frames per second range, given the desired frames per second.\n   *\n   * @param camera the camera to select a frames per second range from\n   * @param desiredPreviewFps the desired frames per second for the camera preview frames\n   * @return the selected preview frames per second range\n   */\n  @SuppressLint(\"InlinedApi\")\n  private static int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) {\n    // The camera API uses integers scaled by a factor of 1000 instead of floating-point frame\n    // rates.\n    int desiredPreviewFpsScaled = (int) (desiredPreviewFps * 1000.0f);\n\n    // Selects a range with whose upper bound is as close as possible to the desired fps while its\n    // lower bound is as small as possible to properly expose frames in low light conditions. Note\n    // that this may select a range that the desired value is outside of. For example, if the\n    // desired frame rate is 30.5, the range (30, 30) is probably more desirable than (30, 40).\n    int[] selectedFpsRange = null;\n    int minUpperBoundDiff = Integer.MAX_VALUE;\n    int minLowerBound = Integer.MAX_VALUE;\n    List<int[]> previewFpsRangeList = camera.getParameters().getSupportedPreviewFpsRange();\n    for (int[] range : previewFpsRangeList) {\n      int upperBoundDiff =\n          Math.abs(desiredPreviewFpsScaled - range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);\n      int lowerBound = range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];\n      if (upperBoundDiff <= minUpperBoundDiff && lowerBound <= minLowerBound) {\n        selectedFpsRange = range;\n        minUpperBoundDiff = upperBoundDiff;\n        minLowerBound = lowerBound;\n      }\n    }\n    return selectedFpsRange;\n  }\n\n  /**\n   * Calculates the correct rotation for the given camera id and sets the rotation in the\n   * parameters. It also sets the camera's display orientation and rotation.\n   *\n   * @param parameters the camera parameters for which to set the rotation\n   * @param cameraId the camera id to set rotation based on\n   */\n  private void setRotation(Camera camera, Camera.Parameters parameters, int cameraId) {\n    WindowManager windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);\n    int degrees = 0;\n    int rotation = windowManager.getDefaultDisplay().getRotation();\n    switch (rotation) {\n      case Surface.ROTATION_0:\n        degrees = 0;\n        break;\n      case Surface.ROTATION_90:\n        degrees = 90;\n        break;\n      case Surface.ROTATION_180:\n        degrees = 180;\n        break;\n      case Surface.ROTATION_270:\n        degrees = 270;\n        break;\n      default:\n        Log.e(TAG, \"Bad rotation value: \" + rotation);\n    }\n\n    CameraInfo cameraInfo = new CameraInfo();\n    Camera.getCameraInfo(cameraId, cameraInfo);\n\n    int displayAngle;\n    if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {\n      this.rotationDegrees = (cameraInfo.orientation + degrees) % 360;\n      displayAngle = (360 - this.rotationDegrees) % 360; // compensate for it being mirrored\n    } else { // back-facing\n      this.rotationDegrees = (cameraInfo.orientation - degrees + 360) % 360;\n      displayAngle = this.rotationDegrees;\n    }\n    Log.d(TAG, \"Display rotation is: \" + rotation);\n    Log.d(TAG, \"Camera face is: \" + cameraInfo.facing);\n    Log.d(TAG, \"Camera rotation is: \" + cameraInfo.orientation);\n    // This value should be one of the degrees that ImageMetadata accepts: 0, 90, 180 or 270.\n    Log.d(TAG, \"RotationDegrees is: \" + this.rotationDegrees);\n\n    camera.setDisplayOrientation(displayAngle);\n    parameters.setRotation(this.rotationDegrees);\n  }\n\n  /**\n   * Creates one buffer for the camera preview callback. The size of the buffer is based off of the\n   * camera preview size and the format of the camera image.\n   *\n   * @return a new preview buffer of the appropriate size for the current camera settings\n   */\n  @SuppressLint(\"InlinedApi\")\n  private byte[] createPreviewBuffer(Size previewSize) {\n    int bitsPerPixel = ImageFormat.getBitsPerPixel(IMAGE_FORMAT);\n    long sizeInBits = (long) previewSize.getHeight() * previewSize.getWidth() * bitsPerPixel;\n    int bufferSize = (int) Math.ceil(sizeInBits / 8.0d) + 1;\n\n    // Creating the byte array this way and wrapping it, as opposed to using .allocate(),\n    // should guarantee that there will be an array to work with.\n    byte[] byteArray = new byte[bufferSize];\n    ByteBuffer buffer = ByteBuffer.wrap(byteArray);\n    if (!buffer.hasArray() || (buffer.array() != byteArray)) {\n      // I don't think that this will ever happen.  But if it does, then we wouldn't be\n      // passing the preview content to the underlying detector later.\n      throw new IllegalStateException(\"Failed to create valid buffer for camera source.\");\n    }\n\n    bytesToByteBuffer.put(byteArray, buffer);\n    return byteArray;\n  }\n\n  // ==============================================================================================\n  // Frame processing\n  // ==============================================================================================\n\n  /** Called when the camera has a new preview frame. */\n  private class CameraPreviewCallback implements Camera.PreviewCallback {\n    @Override\n    public void onPreviewFrame(byte[] data, Camera camera) {\n      processingRunnable.setNextFrame(data, camera);\n    }\n  }\n\n  public void setMachineLearningFrameProcessor(VisionImageProcessor processor) {\n    synchronized (processorLock) {\n      cleanScreen();\n      if (frameProcessor != null) {\n        frameProcessor.stop();\n      }\n      frameProcessor = processor;\n    }\n  }\n\n  /**\n   * This runnable controls access to the underlying receiver, calling it to process frames when\n   * available from the camera. This is designed to run detection on frames as fast as possible\n   * (i.e., without unnecessary context switching or waiting on the next frame).\n   *\n   * <p>While detection is running on a frame, new frames may be received from the camera. As these\n   * frames come in, the most recent frame is held onto as pending. As soon as detection and its\n   * associated processing is done for the previous frame, detection on the mostly recently received\n   * frame will immediately start on the same thread.\n   */\n  private class FrameProcessingRunnable implements Runnable {\n\n    // This lock guards all of the member variables below.\n    private final Object lock = new Object();\n    private boolean active = true;\n\n    // These pending variables hold the state associated with the new frame awaiting processing.\n    private ByteBuffer pendingFrameData;\n\n    FrameProcessingRunnable() {}\n\n    /** Marks the runnable as active/not active. Signals any blocked threads to continue. */\n    void setActive(boolean active) {\n      synchronized (lock) {\n        this.active = active;\n        lock.notifyAll();\n      }\n    }\n\n    /**\n     * Sets the frame data received from the camera. This adds the previous unused frame buffer (if\n     * present) back to the camera, and keeps a pending reference to the frame data for future use.\n     */\n    @SuppressWarnings(\"ByteBufferBackingArray\")\n    void setNextFrame(byte[] data, Camera camera) {\n      synchronized (lock) {\n        if (pendingFrameData != null) {\n          camera.addCallbackBuffer(pendingFrameData.array());\n          pendingFrameData = null;\n        }\n\n        if (!bytesToByteBuffer.containsKey(data)) {\n          Log.d(\n              TAG,\n              \"Skipping frame. Could not find ByteBuffer associated with the image \"\n                  + \"data from the camera.\");\n          return;\n        }\n\n        pendingFrameData = bytesToByteBuffer.get(data);\n\n        // Notify the processor thread if it is waiting on the next frame (see below).\n        lock.notifyAll();\n      }\n    }\n\n    /**\n     * As long as the processing thread is active, this executes detection on frames continuously.\n     * The next pending frame is either immediately available or hasn't been received yet. Once it\n     * is available, we transfer the frame info to local variables and run detection on that frame.\n     * It immediately loops back for the next frame without pausing.\n     *\n     * <p>If detection takes longer than the time in between new frames from the camera, this will\n     * mean that this loop will run without ever waiting on a frame, avoiding any context switching\n     * or frame acquisition time latency.\n     *\n     * <p>If you find that this is using more CPU than you'd like, you should probably decrease the\n     * FPS setting above to allow for some idle time in between frames.\n     */\n    @SuppressLint(\"InlinedApi\")\n    @SuppressWarnings({\"GuardedBy\", \"ByteBufferBackingArray\"})\n    @Override\n    public void run() {\n      ByteBuffer data;\n\n      while (true) {\n        synchronized (lock) {\n          while (active && (pendingFrameData == null)) {\n            try {\n              // Wait for the next frame to be received from the camera, since we\n              // don't have it yet.\n              lock.wait();\n            } catch (InterruptedException e) {\n              Log.d(TAG, \"Frame processing loop terminated.\", e);\n              return;\n            }\n          }\n\n          if (!active) {\n            // Exit the loop once this camera source is stopped or released.  We check\n            // this here, immediately after the wait() above, to handle the case where\n            // setActive(false) had been called, triggering the termination of this\n            // loop.\n            return;\n          }\n\n          // Hold onto the frame data locally, so that we can use this for detection\n          // below.  We need to clear pendingFrameData to ensure that this buffer isn't\n          // recycled back to the camera before we are done using that data.\n          data = pendingFrameData;\n          pendingFrameData = null;\n        }\n\n        // The code below needs to run outside of synchronization, because this will allow\n        // the camera to add pending frame(s) while we are running detection on the current\n        // frame.\n\n        try {\n          synchronized (processorLock) {\n            frameProcessor.processByteBuffer(\n                data,\n                new FrameMetadata.Builder()\n                    .setWidth(previewSize.getWidth())\n                    .setHeight(previewSize.getHeight())\n                    .setRotation(rotationDegrees)\n                    .build(),\n                graphicOverlay);\n          }\n        } catch (Exception t) {\n          Log.e(TAG, \"Exception thrown from receiver.\", t);\n        } finally {\n          camera.addCallbackBuffer(data.array());\n        }\n      }\n    }\n  }\n\n  /** Cleans up graphicOverlay and child classes can do their cleanups as well . */\n  private void cleanScreen() {\n    graphicOverlay.clear();\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/CameraSourcePreview.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.SurfaceHolder;\nimport android.view.SurfaceView;\nimport android.view.ViewGroup;\nimport com.google.android.gms.common.images.Size;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport java.io.IOException;\n\n/** Preview the camera image in the screen. */\npublic class CameraSourcePreview extends ViewGroup {\n  private static final String TAG = \"MIDemoApp:Preview\";\n\n  private final Context context;\n  private final SurfaceView surfaceView;\n  private boolean startRequested;\n  private boolean surfaceAvailable;\n  private CameraSource cameraSource;\n\n  private GraphicOverlay overlay;\n\n  public CameraSourcePreview(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    this.context = context;\n    startRequested = false;\n    surfaceAvailable = false;\n\n    surfaceView = new SurfaceView(context);\n    surfaceView.getHolder().addCallback(new SurfaceCallback());\n    addView(surfaceView);\n  }\n\n  private void start(CameraSource cameraSource) throws IOException {\n    this.cameraSource = cameraSource;\n\n    if (this.cameraSource != null) {\n      startRequested = true;\n      startIfReady();\n    }\n  }\n\n  public void start(CameraSource cameraSource, GraphicOverlay overlay) throws IOException {\n    this.overlay = overlay;\n    start(cameraSource);\n  }\n\n  public void stop() {\n    if (cameraSource != null) {\n      cameraSource.stop();\n    }\n  }\n\n  public void release() {\n    if (cameraSource != null) {\n      cameraSource.release();\n      cameraSource = null;\n    }\n    surfaceView.getHolder().getSurface().release();\n  }\n\n  private void startIfReady() throws IOException, SecurityException {\n    if (startRequested && surfaceAvailable) {\n      if (PreferenceUtils.isCameraLiveViewportEnabled(context)) {\n        cameraSource.start(surfaceView.getHolder());\n      } else {\n        cameraSource.start();\n      }\n      requestLayout();\n\n      if (overlay != null) {\n        Size size = cameraSource.getPreviewSize();\n        int min = Math.min(size.getWidth(), size.getHeight());\n        int max = Math.max(size.getWidth(), size.getHeight());\n        boolean isImageFlipped = cameraSource.getCameraFacing() == CameraSource.CAMERA_FACING_FRONT;\n        if (isPortraitMode()) {\n          // Swap width and height sizes when in portrait, since it will be rotated by 90 degrees.\n          // The camera preview and the image being processed have the same size.\n          overlay.setImageSourceInfo(min, max, isImageFlipped);\n        } else {\n          overlay.setImageSourceInfo(max, min, isImageFlipped);\n        }\n        overlay.clear();\n      }\n      startRequested = false;\n    }\n  }\n\n  private class SurfaceCallback implements SurfaceHolder.Callback {\n    @Override\n    public void surfaceCreated(SurfaceHolder surface) {\n      surfaceAvailable = true;\n      try {\n        startIfReady();\n      } catch (IOException e) {\n        Log.e(TAG, \"Could not start camera source.\", e);\n      }\n    }\n\n    @Override\n    public void surfaceDestroyed(SurfaceHolder surface) {\n      surfaceAvailable = false;\n    }\n\n    @Override\n    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}\n  }\n\n  @Override\n  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n    int width = 320;\n    int height = 240;\n    if (cameraSource != null) {\n      Size size = cameraSource.getPreviewSize();\n      if (size != null) {\n        width = size.getWidth();\n        height = size.getHeight();\n      }\n    }\n\n    // Swap width and height sizes when in portrait, since it will be rotated 90 degrees\n    if (isPortraitMode()) {\n      int tmp = width;\n      width = height;\n      height = tmp;\n    }\n\n    float previewAspectRatio = (float) width / height;\n    int layoutWidth = right - left;\n    int layoutHeight = bottom - top;\n    float layoutAspectRatio = (float) layoutWidth / layoutHeight;\n    if (previewAspectRatio > layoutAspectRatio) {\n      // The preview input is wider than the layout area. Fit the layout height and crop\n      // the preview input horizontally while keep the center.\n      int horizontalOffset = (int) (previewAspectRatio * layoutHeight - layoutWidth) / 2;\n      surfaceView.layout(-horizontalOffset, 0, layoutWidth + horizontalOffset, layoutHeight);\n    } else {\n      // The preview input is taller than the layout area. Fit the layout width and crop the preview\n      // input vertically while keep the center.\n      int verticalOffset = (int) (layoutWidth / previewAspectRatio - layoutHeight) / 2;\n      surfaceView.layout(0, -verticalOffset, layoutWidth, layoutHeight + verticalOffset);\n    }\n  }\n\n  private boolean isPortraitMode() {\n    int orientation = context.getResources().getConfiguration().orientation;\n    if (orientation == Configuration.ORIENTATION_LANDSCAPE) {\n      return false;\n    }\n    if (orientation == Configuration.ORIENTATION_PORTRAIT) {\n      return true;\n    }\n\n    Log.d(TAG, \"isPortraitMode returning false by default\");\n    return false;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/CameraXViewModel.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport android.app.Application;\nimport android.os.Build.VERSION_CODES;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.lifecycle.ProcessCameraProvider;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport java.util.concurrent.ExecutionException;\n\n/** View model for interacting with CameraX. */\n@RequiresApi(VERSION_CODES.LOLLIPOP)\npublic final class CameraXViewModel extends AndroidViewModel {\n\n  private static final String TAG = \"CameraXViewModel\";\n  private MutableLiveData<ProcessCameraProvider> cameraProviderLiveData;\n\n  /**\n   * Create an instance which interacts with the camera service via the given application context.\n   */\n  public CameraXViewModel(@NonNull Application application) {\n    super(application);\n  }\n\n  public LiveData<ProcessCameraProvider> getProcessCameraProvider() {\n    if (cameraProviderLiveData == null) {\n      cameraProviderLiveData = new MutableLiveData<>();\n\n      ListenableFuture<ProcessCameraProvider> cameraProviderFuture =\n          ProcessCameraProvider.getInstance(getApplication());\n      cameraProviderFuture.addListener(\n          () -> {\n            try {\n              cameraProviderLiveData.setValue(cameraProviderFuture.get());\n            } catch (ExecutionException | InterruptedException e) {\n              // Handle any errors (including cancellation) here.\n              Log.e(TAG, \"Unhandled exception\", e);\n            }\n          },\n          ContextCompat.getMainExecutor(getApplication()));\n    }\n\n    return cameraProviderLiveData;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/EntryChoiceActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo\n\nimport android.Manifest\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.widget.TextView\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport com.google.mlkit.vision.demo.java.ChooserActivity\nimport java.util.ArrayList\n\nclass EntryChoiceActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_vision_entry_choice)\n\n    findViewById<TextView>(R.id.java_entry_point).setOnClickListener {\n      val intent = Intent(this@EntryChoiceActivity, ChooserActivity::class.java)\n      startActivity(intent)\n    }\n\n    findViewById<TextView>(R.id.kotlin_entry_point).setOnClickListener {\n      val intent =\n        Intent(\n          this@EntryChoiceActivity,\n          com.google.mlkit.vision.demo.kotlin.ChooserActivity::class.java\n        )\n      startActivity(intent)\n    }\n\n    if (!allRuntimePermissionsGranted()) {\n      getRuntimePermissions()\n    }\n  }\n\n  private fun allRuntimePermissionsGranted(): Boolean {\n    for (permission in REQUIRED_RUNTIME_PERMISSIONS) {\n      permission?.let {\n        if (!isPermissionGranted(this, it)) {\n          return false\n        }\n      }\n    }\n    return true\n  }\n\n  private fun getRuntimePermissions() {\n    val permissionsToRequest = ArrayList<String>()\n    for (permission in REQUIRED_RUNTIME_PERMISSIONS) {\n      permission?.let {\n        if (!isPermissionGranted(this, it)) {\n          permissionsToRequest.add(permission)\n        }\n      }\n    }\n\n    if (permissionsToRequest.isNotEmpty()) {\n      ActivityCompat.requestPermissions(\n        this,\n        permissionsToRequest.toTypedArray(),\n        PERMISSION_REQUESTS\n      )\n    }\n  }\n\n  private fun isPermissionGranted(context: Context, permission: String): Boolean {\n    if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED\n    ) {\n      Log.i(TAG, \"Permission granted: $permission\")\n      return true\n    }\n    Log.i(TAG, \"Permission NOT granted: $permission\")\n    return false\n  }\n\n  companion object {\n    private const val TAG = \"EntryChoiceActivity\"\n    private const val PERMISSION_REQUESTS = 1\n\n    private val REQUIRED_RUNTIME_PERMISSIONS =\n      arrayOf(\n        Manifest.permission.CAMERA,\n        Manifest.permission.WRITE_EXTERNAL_STORAGE,\n        Manifest.permission.READ_EXTERNAL_STORAGE\n      )\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/FrameMetadata.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\n/** Describing a frame info. */\npublic class FrameMetadata {\n\n  private final int width;\n  private final int height;\n  private final int rotation;\n\n  public int getWidth() {\n    return width;\n  }\n\n  public int getHeight() {\n    return height;\n  }\n\n  public int getRotation() {\n    return rotation;\n  }\n\n  private FrameMetadata(int width, int height, int rotation) {\n    this.width = width;\n    this.height = height;\n    this.rotation = rotation;\n  }\n\n  /** Builder of {@link FrameMetadata}. */\n  public static class Builder {\n\n    private int width;\n    private int height;\n    private int rotation;\n\n    public Builder setWidth(int width) {\n      this.width = width;\n      return this;\n    }\n\n    public Builder setHeight(int height) {\n      this.height = height;\n      return this;\n    }\n\n    public Builder setRotation(int rotation) {\n      this.rotation = rotation;\n      return this;\n    }\n\n    public FrameMetadata build() {\n      return new FrameMetadata(width, height, rotation);\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/GraphicOverlay.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Matrix;\nimport android.graphics.Paint;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport com.google.common.base.Preconditions;\nimport com.google.common.primitives.Ints;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * A view which renders a series of custom graphics to be overlayed on top of an associated preview\n * (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove\n * them, triggering the appropriate drawing and invalidation within the view.\n *\n * <p>Supports scaling and mirroring of the graphics relative the camera's preview properties. The\n * idea is that detection items are expressed in terms of an image size, but need to be scaled up to\n * the full view size, and also mirrored in the case of the front-facing camera.\n *\n * <p>Associated {@link Graphic} items should use the following methods to convert to view\n * coordinates for the graphics that are drawn:\n *\n * <ol>\n *   <li>{@link Graphic#scale(float)} adjusts the size of the supplied value from the image scale to\n *       the view scale.\n *   <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n *       coordinate from the image's coordinate system to the view coordinate system.\n * </ol>\n */\npublic class GraphicOverlay extends View {\n  private final Object lock = new Object();\n  private final List<Graphic> graphics = new ArrayList<>();\n  // Matrix for transforming from image coordinates to overlay view coordinates.\n  private final Matrix transformationMatrix = new Matrix();\n\n  private int imageWidth;\n  private int imageHeight;\n  // The factor of overlay View size to image size. Anything in the image coordinates need to be\n  // scaled by this amount to fit with the area of overlay View.\n  private float scaleFactor = 1.0f;\n  // The number of horizontal pixels needed to be cropped on each side to fit the image with the\n  // area of overlay View after scaling.\n  private float postScaleWidthOffset;\n  // The number of vertical pixels needed to be cropped on each side to fit the image with the\n  // area of overlay View after scaling.\n  private float postScaleHeightOffset;\n  private boolean isImageFlipped;\n  private boolean needUpdateTransformation = true;\n\n  /**\n   * Base class for a custom graphics object to be rendered within the graphic overlay. Subclass\n   * this and implement the {@link Graphic#draw(Canvas)} method to define the graphics element. Add\n   * instances to the overlay using {@link GraphicOverlay#add(Graphic)}.\n   */\n  public abstract static class Graphic {\n    private GraphicOverlay overlay;\n\n    public Graphic(GraphicOverlay overlay) {\n      this.overlay = overlay;\n    }\n\n    /**\n     * Draw the graphic on the supplied canvas. Drawing should use the following methods to convert\n     * to view coordinates for the graphics that are drawn:\n     *\n     * <ol>\n     *   <li>{@link Graphic#scale(float)} adjusts the size of the supplied value from the image\n     *       scale to the view scale.\n     *   <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the\n     *       coordinate from the image's coordinate system to the view coordinate system.\n     * </ol>\n     *\n     * @param canvas drawing canvas\n     */\n    public abstract void draw(Canvas canvas);\n\n    protected void drawRect(\n        Canvas canvas, float left, float top, float right, float bottom, Paint paint) {\n      canvas.drawRect(left, top, right, bottom, paint);\n    }\n\n    protected void drawText(Canvas canvas, String text, float x, float y, Paint paint) {\n      canvas.drawText(text, x, y, paint);\n    }\n\n    /** Adjusts the supplied value from the image scale to the view scale. */\n    public float scale(float imagePixel) {\n      return imagePixel * overlay.scaleFactor;\n    }\n\n    /** Returns the application context of the app. */\n    public Context getApplicationContext() {\n      return overlay.getContext().getApplicationContext();\n    }\n\n    public boolean isImageFlipped() {\n      return overlay.isImageFlipped;\n    }\n\n    /**\n     * Adjusts the x coordinate from the image's coordinate system to the view coordinate system.\n     */\n    public float translateX(float x) {\n      if (overlay.isImageFlipped) {\n        return overlay.getWidth() - (scale(x) - overlay.postScaleWidthOffset);\n      } else {\n        return scale(x) - overlay.postScaleWidthOffset;\n      }\n    }\n\n    /**\n     * Adjusts the y coordinate from the image's coordinate system to the view coordinate system.\n     */\n    public float translateY(float y) {\n      return scale(y) - overlay.postScaleHeightOffset;\n    }\n\n    /**\n     * Returns a {@link Matrix} for transforming from image coordinates to overlay view coordinates.\n     */\n    public Matrix getTransformationMatrix() {\n      return overlay.transformationMatrix;\n    }\n\n    public void postInvalidate() {\n      overlay.postInvalidate();\n    }\n\n    /**\n     * Given the {@code zInImagePixel}, update the color for the passed in {@code paint}. The color will be\n     * more red if the {@code zInImagePixel} is smaller, or more blue ish vice versa. This is\n     * useful to visualize the z value of landmarks via color for features like Pose and Face Mesh.\n     *\n     * @param paint the paint to update color with\n     * @param canvas the canvas used to draw with paint\n     * @param visualizeZ if true, paint color will be changed.\n     * @param rescaleZForVisualization if true, re-scale the z value with zMin and zMax to make\n     *     color more distinguishable\n     * @param zInImagePixel the z value used to update the paint color\n     * @param zMin min value of all z values going to be passed in\n     * @param zMax max value of all z values going to be passed in\n     */\n    public void updatePaintColorByZValue(\n        Paint paint,\n        Canvas canvas,\n        boolean visualizeZ,\n        boolean rescaleZForVisualization,\n        float zInImagePixel,\n        float zMin,\n        float zMax) {\n      if (!visualizeZ) {\n        return;\n      }\n\n      // When visualizeZ is true, sets up the paint to different colors based on z values.\n      // Gets the range of z value.\n      float zLowerBoundInScreenPixel;\n      float zUpperBoundInScreenPixel;\n\n      if (rescaleZForVisualization) {\n        zLowerBoundInScreenPixel = min(-0.001f, scale(zMin));\n        zUpperBoundInScreenPixel = max(0.001f, scale(zMax));\n      } else {\n        // By default, assume the range of z value in screen pixel is [-canvasWidth, canvasWidth].\n        float defaultRangeFactor = 1f;\n        zLowerBoundInScreenPixel = -defaultRangeFactor * canvas.getWidth();\n        zUpperBoundInScreenPixel = defaultRangeFactor * canvas.getWidth();\n      }\n\n      float zInScreenPixel = scale(zInImagePixel);\n\n      if (zInScreenPixel < 0) {\n        // Sets up the paint to be red if the item is in front of the z origin.\n        // Maps values within [zLowerBoundInScreenPixel, 0) to [255, 0) and use it to control the\n        // color. The larger the value is, the more red it will be.\n        int v = (int) (zInScreenPixel / zLowerBoundInScreenPixel * 255);\n        v = Ints.constrainToRange(v, 0, 255);\n        paint.setARGB(255, 255, 255 - v, 255 - v);\n      } else {\n        // Sets up the paint to be blue if the item is behind the z origin.\n        // Maps values within [0, zUpperBoundInScreenPixel] to [0, 255] and use it to control the\n        // color. The larger the value is, the more blue it will be.\n        int v = (int) (zInScreenPixel / zUpperBoundInScreenPixel * 255);\n        v = Ints.constrainToRange(v, 0, 255);\n        paint.setARGB(255, 255 - v, 255 - v, 255);\n      }\n    }\n  }\n\n  public GraphicOverlay(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    addOnLayoutChangeListener(\n        (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->\n            needUpdateTransformation = true);\n  }\n\n  /** Removes all graphics from the overlay. */\n  public void clear() {\n    synchronized (lock) {\n      graphics.clear();\n    }\n    postInvalidate();\n  }\n\n  /** Adds a graphic to the overlay. */\n  public void add(Graphic graphic) {\n    synchronized (lock) {\n      graphics.add(graphic);\n    }\n  }\n\n  /** Removes a graphic from the overlay. */\n  public void remove(Graphic graphic) {\n    synchronized (lock) {\n      graphics.remove(graphic);\n    }\n    postInvalidate();\n  }\n\n  /**\n   * Sets the source information of the image being processed by detectors, including size and\n   * whether it is flipped, which informs how to transform image coordinates later.\n   *\n   * @param imageWidth the width of the image sent to ML Kit detectors\n   * @param imageHeight the height of the image sent to ML Kit detectors\n   * @param isFlipped whether the image is flipped. Should set it to true when the image is from the\n   *     front camera.\n   */\n  public void setImageSourceInfo(int imageWidth, int imageHeight, boolean isFlipped) {\n    Preconditions.checkState(imageWidth > 0, \"image width must be positive\");\n    Preconditions.checkState(imageHeight > 0, \"image height must be positive\");\n    synchronized (lock) {\n      this.imageWidth = imageWidth;\n      this.imageHeight = imageHeight;\n      this.isImageFlipped = isFlipped;\n      needUpdateTransformation = true;\n    }\n    postInvalidate();\n  }\n\n  public int getImageWidth() {\n    return imageWidth;\n  }\n\n  public int getImageHeight() {\n    return imageHeight;\n  }\n\n  private void updateTransformationIfNeeded() {\n    if (!needUpdateTransformation || imageWidth <= 0 || imageHeight <= 0) {\n      return;\n    }\n    float viewAspectRatio = (float) getWidth() / getHeight();\n    float imageAspectRatio = (float) imageWidth / imageHeight;\n    postScaleWidthOffset = 0;\n    postScaleHeightOffset = 0;\n    if (viewAspectRatio > imageAspectRatio) {\n      // The image needs to be vertically cropped to be displayed in this view.\n      scaleFactor = (float) getWidth() / imageWidth;\n      postScaleHeightOffset = ((float) getWidth() / imageAspectRatio - getHeight()) / 2;\n    } else {\n      // The image needs to be horizontally cropped to be displayed in this view.\n      scaleFactor = (float) getHeight() / imageHeight;\n      postScaleWidthOffset = ((float) getHeight() * imageAspectRatio - getWidth()) / 2;\n    }\n\n    transformationMatrix.reset();\n    transformationMatrix.setScale(scaleFactor, scaleFactor);\n    transformationMatrix.postTranslate(-postScaleWidthOffset, -postScaleHeightOffset);\n\n    if (isImageFlipped) {\n      transformationMatrix.postScale(-1f, 1f, getWidth() / 2f, getHeight() / 2f);\n    }\n\n    needUpdateTransformation = false;\n  }\n\n  /** Draws the overlay with its associated graphic objects. */\n  @Override\n  protected void onDraw(Canvas canvas) {\n    super.onDraw(canvas);\n\n    synchronized (lock) {\n      updateTransformationIfNeeded();\n\n      for (Graphic graphic : graphics) {\n        graphic.draw(canvas);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/InferenceInfoGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport androidx.annotation.Nullable;\n\n/** Graphic instance for rendering inference info (latency, FPS, resolution) in an overlay view. */\npublic class InferenceInfoGraphic extends GraphicOverlay.Graphic {\n\n  private static final int TEXT_COLOR = Color.WHITE;\n  private static final float TEXT_SIZE = 60.0f;\n\n  private final Paint textPaint;\n  private final GraphicOverlay overlay;\n  private final long frameLatency;\n  private final long detectorLatency;\n\n  // Only valid when a stream of input images is being processed. Null for single image mode.\n  @Nullable private final Integer framesPerSecond;\n  private boolean showLatencyInfo = true;\n\n  public InferenceInfoGraphic(\n      GraphicOverlay overlay,\n      long frameLatency,\n      long detectorLatency,\n      @Nullable Integer framesPerSecond) {\n    super(overlay);\n    this.overlay = overlay;\n    this.frameLatency = frameLatency;\n    this.detectorLatency = detectorLatency;\n    this.framesPerSecond = framesPerSecond;\n    textPaint = new Paint();\n    textPaint.setColor(TEXT_COLOR);\n    textPaint.setTextSize(TEXT_SIZE);\n    textPaint.setShadowLayer(5.0f, 0f, 0f, Color.BLACK);\n    postInvalidate();\n  }\n\n  /** Creates an {@link InferenceInfoGraphic} to only display image size. */\n  public InferenceInfoGraphic(GraphicOverlay overlay) {\n    this(overlay, 0, 0, null);\n    showLatencyInfo = false;\n  }\n\n  @Override\n  public synchronized void draw(Canvas canvas) {\n    float x = TEXT_SIZE * 0.5f;\n    float y = TEXT_SIZE * 1.5f;\n\n    canvas.drawText(\n        \"InputImage size: \" + overlay.getImageHeight() + \"x\" + overlay.getImageWidth(),\n        x,\n        y,\n        textPaint);\n\n    if (!showLatencyInfo) {\n      return;\n    }\n    // Draw FPS (if valid) and inference latency\n    if (framesPerSecond != null) {\n      canvas.drawText(\n          \"FPS: \" + framesPerSecond + \", Frame latency: \" + frameLatency + \" ms\",\n          x,\n          y + TEXT_SIZE,\n          textPaint);\n    } else {\n      canvas.drawText(\"Frame latency: \" + frameLatency + \" ms\", x, y + TEXT_SIZE, textPaint);\n    }\n    canvas.drawText(\n        \"Detector latency: \" + detectorLatency + \" ms\", x, y + TEXT_SIZE * 2, textPaint);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/ScopedExecutor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport androidx.annotation.NonNull;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Wraps an existing executor to provide a {@link #shutdown} method that allows subsequent\n * cancellation of submitted runnables.\n */\npublic class ScopedExecutor implements Executor {\n\n  private final Executor executor;\n  private final AtomicBoolean shutdown = new AtomicBoolean();\n\n  public ScopedExecutor(@NonNull Executor executor) {\n    this.executor = executor;\n  }\n\n  @Override\n  public void execute(@NonNull Runnable command) {\n    // Return early if this object has been shut down.\n    if (shutdown.get()) {\n      return;\n    }\n    executor.execute(\n        () -> {\n          // Check again in case it has been shut down in the mean time.\n          if (shutdown.get()) {\n            return;\n          }\n          command.run();\n        });\n  }\n\n  /**\n   * After this method is called, no runnables that have been submitted or are subsequently\n   * submitted will start to execute, turning this executor into a no-op.\n   *\n   * <p>Runnables that have already started to execute will continue.\n   */\n  public void shutdown() {\n    shutdown.set(true);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/TemperatureMonitor.java",
    "content": "package com.google.mlkit.vision.demo;\n\nimport android.content.Context;\nimport android.hardware.Sensor;\nimport android.hardware.SensorEvent;\nimport android.hardware.SensorEventListener;\nimport android.hardware.SensorManager;\nimport android.util.Log;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\n/**\n * Monitors device temperature.\n */\npublic final class TemperatureMonitor implements SensorEventListener {\n\n  private static final String TAG = \"TemperatureMonitor\";\n\n  public Map<String, Float> sensorReadingsCelsius = new HashMap<>();\n\n  private final SensorManager sensorManager;\n\n  public TemperatureMonitor(Context context) {\n    sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);\n    List<Sensor> allSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);\n    for (Sensor sensor : allSensors) {\n      // Assumes sensors with \"temperature\" substring in their names are temperature sensors.\n      // Those sensors may measure the temperature of different parts of the device. It makes more\n      // sense to track the change of themselves, e.g. compare the reading before and after running\n      // a detector for a certain amount of time, rather than relying on their absolute values at a\n      // certain time.\n      if (sensor.getName().toLowerCase().contains(\"temperature\")) {\n        sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);\n\n      }\n    }\n  }\n\n  public void stop() {\n    sensorManager.unregisterListener(this);\n  }\n\n  public void logTemperature() {\n    for (Map.Entry<String, Float> entry : sensorReadingsCelsius.entrySet()) {\n      float tempC = entry.getValue();\n      // Skips likely invalid sensor readings\n      if (tempC < 0) {\n        continue;\n      }\n      float tempF = tempC * 1.8f + 32f;\n      Log.i(TAG, String.format(Locale.US, \"%s:\\t%.1fC\\t%.1fF\", entry.getKey(), tempC, tempF));\n    }\n  }\n\n  @Override\n  public void onAccuracyChanged(Sensor sensor, int accuracy) {}\n\n  @Override\n  public void onSensorChanged(SensorEvent sensorEvent) {\n    sensorReadingsCelsius.put(sensorEvent.sensor.getName(), sensorEvent.values[0]);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/VisionImageProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo;\n\nimport android.graphics.Bitmap;\nimport androidx.camera.core.ImageProxy;\nimport com.google.mlkit.common.MlKitException;\nimport java.nio.ByteBuffer;\n\n/** An interface to process the images with different vision detectors and custom image models. */\npublic interface VisionImageProcessor {\n\n  /** Processes a bitmap image. */\n  void processBitmap(Bitmap bitmap, GraphicOverlay graphicOverlay);\n\n  /** Processes ByteBuffer image data, e.g. used for Camera1 live preview case. */\n  void processByteBuffer(\n      ByteBuffer data, FrameMetadata frameMetadata, GraphicOverlay graphicOverlay)\n      throws MlKitException;\n\n  /** Processes ImageProxy image data, e.g. used for CameraX live preview case. */\n  void processImageProxy(ImageProxy image, GraphicOverlay graphicOverlay) throws MlKitException;\n\n  /** Stops the underlying machine learning model and release resources. */\n  void stop();\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/CameraXLivePreviewActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java;\n\nimport android.content.Intent;\nimport android.os.Build.VERSION_CODES;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.util.Size;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.CompoundButton;\nimport android.widget.ImageView;\nimport android.widget.Spinner;\nimport android.widget.Toast;\nimport android.widget.ToggleButton;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.core.Camera;\nimport androidx.camera.core.CameraInfoUnavailableException;\nimport androidx.camera.core.CameraSelector;\nimport androidx.camera.core.ImageAnalysis;\nimport androidx.camera.core.Preview;\nimport androidx.camera.lifecycle.ProcessCameraProvider;\nimport androidx.camera.view.PreviewView;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory;\nimport com.google.android.gms.common.annotation.KeepName;\nimport com.google.common.util.concurrent.ListenableFuture;\nimport com.google.mlkit.common.MlKitException;\nimport com.google.mlkit.common.model.LocalModel;\nimport com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback;\nimport com.google.mlkit.vision.demo.CameraXViewModel;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.R;\nimport com.google.mlkit.vision.demo.VisionImageProcessor;\nimport com.google.mlkit.vision.demo.java.barcodescanner.BarcodeScannerProcessor;\nimport com.google.mlkit.vision.demo.java.facedetector.FaceDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.labeldetector.LabelDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.objectdetector.ObjectDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.posedetector.PoseDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.segmenter.SegmenterProcessor;\nimport com.google.mlkit.vision.demo.java.textdetector.TextRecognitionProcessor;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.demo.preference.SettingsActivity;\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions;\nimport com.google.mlkit.vision.label.defaults.ImageLabelerOptions;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions;\nimport com.google.mlkit.vision.pose.PoseDetectorOptionsBase;\nimport com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions;\nimport com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions;\nimport com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions;\nimport com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions;\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** Live preview demo app for ML Kit APIs using CameraX. */\n@KeepName\n@RequiresApi(VERSION_CODES.LOLLIPOP)\npublic final class CameraXLivePreviewActivity extends AppCompatActivity\n    implements OnItemSelectedListener, CompoundButton.OnCheckedChangeListener {\n  private static final String TAG = \"CameraXLivePreview\";\n\n  private static final String OBJECT_DETECTION = \"Object Detection\";\n  private static final String OBJECT_DETECTION_CUSTOM = \"Custom Object Detection\";\n  private static final String CUSTOM_AUTOML_OBJECT_DETECTION =\n      \"Custom AutoML Object Detection (Flower)\";\n  private static final String FACE_DETECTION = \"Face Detection\";\n  private static final String BARCODE_SCANNING = \"Barcode Scanning\";\n  private static final String IMAGE_LABELING = \"Image Labeling\";\n  private static final String IMAGE_LABELING_CUSTOM = \"Custom Image Labeling (Birds)\";\n  private static final String CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling (Flower)\";\n  private static final String POSE_DETECTION = \"Pose Detection\";\n  private static final String SELFIE_SEGMENTATION = \"Selfie Segmentation\";\n  private static final String TEXT_RECOGNITION_LATIN = \"Text Recognition Latin\";\n  private static final String TEXT_RECOGNITION_CHINESE = \"Text Recognition Chinese\";\n  private static final String TEXT_RECOGNITION_DEVANAGARI = \"Text Recognition Devanagari\";\n  private static final String TEXT_RECOGNITION_JAPANESE = \"Text Recognition Japanese\";\n  private static final String TEXT_RECOGNITION_KOREAN = \"Text Recognition Korean\";\n  private static final String FACE_MESH_DETECTION = \"Face Mesh Detection (Beta)\";\n\n  private static final String STATE_SELECTED_MODEL = \"selected_model\";\n\n  private PreviewView previewView;\n  private GraphicOverlay graphicOverlay;\n\n  @Nullable private ProcessCameraProvider cameraProvider;\n  @Nullable private Camera camera;\n  @Nullable private Preview previewUseCase;\n  @Nullable private ImageAnalysis analysisUseCase;\n  @Nullable private VisionImageProcessor imageProcessor;\n  private boolean needUpdateGraphicOverlayImageSourceInfo;\n\n  private String selectedModel = OBJECT_DETECTION;\n  private int lensFacing = CameraSelector.LENS_FACING_BACK;\n  private CameraSelector cameraSelector;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    Log.d(TAG, \"onCreate\");\n\n    if (savedInstanceState != null) {\n      selectedModel = savedInstanceState.getString(STATE_SELECTED_MODEL, OBJECT_DETECTION);\n    }\n    cameraSelector = new CameraSelector.Builder().requireLensFacing(lensFacing).build();\n\n    setContentView(R.layout.activity_vision_camerax_live_preview);\n    previewView = findViewById(R.id.preview_view);\n    if (previewView == null) {\n      Log.d(TAG, \"previewView is null\");\n    }\n    graphicOverlay = findViewById(R.id.graphic_overlay);\n    if (graphicOverlay == null) {\n      Log.d(TAG, \"graphicOverlay is null\");\n    }\n\n    Spinner spinner = findViewById(R.id.spinner);\n    List<String> options = new ArrayList<>();\n    options.add(OBJECT_DETECTION);\n    options.add(OBJECT_DETECTION_CUSTOM);\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION);\n    options.add(FACE_DETECTION);\n    options.add(BARCODE_SCANNING);\n    options.add(IMAGE_LABELING);\n    options.add(IMAGE_LABELING_CUSTOM);\n    options.add(CUSTOM_AUTOML_LABELING);\n    options.add(POSE_DETECTION);\n    options.add(SELFIE_SEGMENTATION);\n    options.add(TEXT_RECOGNITION_LATIN);\n    options.add(TEXT_RECOGNITION_CHINESE);\n    options.add(TEXT_RECOGNITION_DEVANAGARI);\n    options.add(TEXT_RECOGNITION_JAPANESE);\n    options.add(TEXT_RECOGNITION_KOREAN);\n    options.add(FACE_MESH_DETECTION);\n\n    // Creating adapter for spinner\n    ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // attaching data adapter to spinner\n    spinner.setAdapter(dataAdapter);\n    spinner.setOnItemSelectedListener(this);\n\n    ToggleButton facingSwitch = findViewById(R.id.facing_switch);\n    facingSwitch.setOnCheckedChangeListener(this);\n\n    new ViewModelProvider(this, AndroidViewModelFactory.getInstance(getApplication()))\n        .get(CameraXViewModel.class)\n        .getProcessCameraProvider()\n        .observe(\n            this,\n            provider -> {\n              cameraProvider = provider;\n              bindAllCameraUseCases();\n            });\n\n    ImageView settingsButton = findViewById(R.id.settings_button);\n    settingsButton.setOnClickListener(\n        v -> {\n          Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);\n          intent.putExtra(\n              SettingsActivity.EXTRA_LAUNCH_SOURCE,\n              SettingsActivity.LaunchSource.CAMERAX_LIVE_PREVIEW);\n          startActivity(intent);\n        });\n  }\n\n  @Override\n  protected void onSaveInstanceState(@NonNull Bundle bundle) {\n    super.onSaveInstanceState(bundle);\n    bundle.putString(STATE_SELECTED_MODEL, selectedModel);\n  }\n\n  @Override\n  public synchronized void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {\n    // An item was selected. You can retrieve the selected item using\n    // parent.getItemAtPosition(pos)\n    selectedModel = parent.getItemAtPosition(pos).toString();\n    Log.d(TAG, \"Selected model: \" + selectedModel);\n    bindAnalysisUseCase();\n  }\n\n  @Override\n  public void onNothingSelected(AdapterView<?> parent) {\n    // Do nothing.\n  }\n\n  @Override\n  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n    if (cameraProvider == null) {\n      return;\n    }\n    int newLensFacing =\n        lensFacing == CameraSelector.LENS_FACING_FRONT\n            ? CameraSelector.LENS_FACING_BACK\n            : CameraSelector.LENS_FACING_FRONT;\n    CameraSelector newCameraSelector =\n        new CameraSelector.Builder().requireLensFacing(newLensFacing).build();\n    try {\n      if (cameraProvider.hasCamera(newCameraSelector)) {\n        Log.d(TAG, \"Set facing to \" + newLensFacing);\n        lensFacing = newLensFacing;\n        cameraSelector = newCameraSelector;\n        bindAllCameraUseCases();\n        return;\n      }\n    } catch (CameraInfoUnavailableException e) {\n      // Falls through\n    }\n    Toast.makeText(\n            getApplicationContext(),\n            \"This device does not have lens with facing: \" + newLensFacing,\n            Toast.LENGTH_SHORT)\n        .show();\n  }\n\n  @Override\n  public void onResume() {\n    super.onResume();\n    bindAllCameraUseCases();\n  }\n\n  @Override\n  protected void onPause() {\n    super.onPause();\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n  }\n\n  @Override\n  public void onDestroy() {\n    super.onDestroy();\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n  }\n\n  private void bindAllCameraUseCases() {\n    if (cameraProvider != null) {\n      // As required by CameraX API, unbinds all use cases before trying to re-bind any of them.\n      cameraProvider.unbindAll();\n      bindPreviewUseCase();\n      bindAnalysisUseCase();\n    }\n  }\n\n  private void bindPreviewUseCase() {\n    if (!PreferenceUtils.isCameraLiveViewportEnabled(this)) {\n      return;\n    }\n    if (cameraProvider == null) {\n      return;\n    }\n    if (previewUseCase != null) {\n      cameraProvider.unbind(previewUseCase);\n    }\n\n    Preview.Builder builder = new Preview.Builder();\n    Size targetResolution = PreferenceUtils.getCameraXTargetResolution(this, lensFacing);\n    if (targetResolution != null) {\n      builder.setTargetResolution(targetResolution);\n    }\n    previewUseCase = builder.build();\n    previewUseCase.setSurfaceProvider(previewView.getSurfaceProvider());\n    camera =\n        cameraProvider.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector, previewUseCase);\n  }\n\n  private void bindAnalysisUseCase() {\n    if (cameraProvider == null) {\n      return;\n    }\n    if (analysisUseCase != null) {\n      cameraProvider.unbind(analysisUseCase);\n    }\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n\n    try {\n      switch (selectedModel) {\n        case OBJECT_DETECTION:\n          Log.i(TAG, \"Using Object Detector Processor\");\n          ObjectDetectorOptions objectDetectorOptions =\n              PreferenceUtils.getObjectDetectorOptionsForLivePreview(this);\n          imageProcessor = new ObjectDetectorProcessor(this, objectDetectorOptions);\n          break;\n        case OBJECT_DETECTION_CUSTOM:\n          Log.i(TAG, \"Using Custom Object Detector Processor\");\n          LocalModel localModel =\n              new LocalModel.Builder()\n                  .setAssetFilePath(\"custom_models/object_labeler.tflite\")\n                  .build();\n          CustomObjectDetectorOptions customObjectDetectorOptions =\n              PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(this, localModel);\n          imageProcessor = new ObjectDetectorProcessor(this, customObjectDetectorOptions);\n          break;\n        case CUSTOM_AUTOML_OBJECT_DETECTION:\n          Log.i(TAG, \"Using Custom AutoML Object Detector Processor\");\n          LocalModel customAutoMLODTLocalModel =\n              new LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build();\n          CustomObjectDetectorOptions customAutoMLODTOptions =\n              PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(\n                  this, customAutoMLODTLocalModel);\n          imageProcessor = new ObjectDetectorProcessor(this, customAutoMLODTOptions);\n          break;\n        case TEXT_RECOGNITION_CHINESE:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Chinese.\");\n          imageProcessor =\n              new TextRecognitionProcessor(\n                  this, new ChineseTextRecognizerOptions.Builder().build());\n          break;\n        case TEXT_RECOGNITION_DEVANAGARI:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Devanagari.\");\n          imageProcessor =\n              new TextRecognitionProcessor(\n                  this, new DevanagariTextRecognizerOptions.Builder().build());\n          break;\n        case TEXT_RECOGNITION_JAPANESE:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Japanese.\");\n          imageProcessor =\n              new TextRecognitionProcessor(\n                  this, new JapaneseTextRecognizerOptions.Builder().build());\n          break;\n        case TEXT_RECOGNITION_KOREAN:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Korean.\");\n          imageProcessor =\n              new TextRecognitionProcessor(this, new KoreanTextRecognizerOptions.Builder().build());\n          break;\n        case TEXT_RECOGNITION_LATIN:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin.\");\n          imageProcessor =\n              new TextRecognitionProcessor(this, new TextRecognizerOptions.Builder().build());\n          break;\n        case FACE_DETECTION:\n          Log.i(TAG, \"Using Face Detector Processor\");\n          imageProcessor = new FaceDetectorProcessor(this);\n          break;\n        case BARCODE_SCANNING:\n          Log.i(TAG, \"Using Barcode Detector Processor\");\n          ZoomCallback zoomCallback = null;\n          if (PreferenceUtils.shouldEnableAutoZoom(this)) {\n            zoomCallback =\n                zoomLevel -> {\n                  Log.i(TAG, \"Set zoom ratio \" + zoomLevel);\n                  @SuppressWarnings(\"FutureReturnValueIgnored\")\n                  ListenableFuture<Void> ignored =\n                      camera.getCameraControl().setZoomRatio(zoomLevel);\n                  return true;\n                };\n          }\n          imageProcessor = new BarcodeScannerProcessor(this, zoomCallback);\n          break;\n        case IMAGE_LABELING:\n          Log.i(TAG, \"Using Image Label Detector Processor\");\n          imageProcessor = new LabelDetectorProcessor(this, ImageLabelerOptions.DEFAULT_OPTIONS);\n          break;\n        case IMAGE_LABELING_CUSTOM:\n          Log.i(TAG, \"Using Custom Image Label (Birds) Detector Processor\");\n          LocalModel localClassifier =\n              new LocalModel.Builder()\n                  .setAssetFilePath(\"custom_models/bird_classifier.tflite\")\n                  .build();\n          CustomImageLabelerOptions customImageLabelerOptions =\n              new CustomImageLabelerOptions.Builder(localClassifier).build();\n          imageProcessor = new LabelDetectorProcessor(this, customImageLabelerOptions);\n          break;\n        case CUSTOM_AUTOML_LABELING:\n          Log.i(TAG, \"Using Custom AutoML Image Label Detector Processor\");\n          LocalModel customAutoMLLabelLocalModel =\n              new LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build();\n          CustomImageLabelerOptions customAutoMLLabelOptions =\n              new CustomImageLabelerOptions.Builder(customAutoMLLabelLocalModel)\n                  .setConfidenceThreshold(0)\n                  .build();\n          imageProcessor = new LabelDetectorProcessor(this, customAutoMLLabelOptions);\n          break;\n        case POSE_DETECTION:\n          PoseDetectorOptionsBase poseDetectorOptions =\n              PreferenceUtils.getPoseDetectorOptionsForLivePreview(this);\n          boolean shouldShowInFrameLikelihood =\n              PreferenceUtils.shouldShowPoseDetectionInFrameLikelihoodLivePreview(this);\n          boolean visualizeZ = PreferenceUtils.shouldPoseDetectionVisualizeZ(this);\n          boolean rescaleZ = PreferenceUtils.shouldPoseDetectionRescaleZForVisualization(this);\n          boolean runClassification = PreferenceUtils.shouldPoseDetectionRunClassification(this);\n          imageProcessor =\n              new PoseDetectorProcessor(\n                  this,\n                  poseDetectorOptions,\n                  shouldShowInFrameLikelihood,\n                  visualizeZ,\n                  rescaleZ,\n                  runClassification,\n                  /* isStreamMode = */ true);\n          break;\n        case SELFIE_SEGMENTATION:\n          imageProcessor = new SegmenterProcessor(this);\n          break;\n        case FACE_MESH_DETECTION:\n          imageProcessor = new FaceMeshDetectorProcessor(this);\n          break;\n        default:\n          throw new IllegalStateException(\"Invalid model name\");\n      }\n    } catch (Exception e) {\n      Log.e(TAG, \"Can not create image processor: \" + selectedModel, e);\n      Toast.makeText(\n              getApplicationContext(),\n              \"Can not create image processor: \" + e.getLocalizedMessage(),\n              Toast.LENGTH_LONG)\n          .show();\n      return;\n    }\n\n    ImageAnalysis.Builder builder = new ImageAnalysis.Builder();\n    Size targetResolution = PreferenceUtils.getCameraXTargetResolution(this, lensFacing);\n    if (targetResolution != null) {\n      builder.setTargetResolution(targetResolution);\n    }\n    analysisUseCase = builder.build();\n\n    needUpdateGraphicOverlayImageSourceInfo = true;\n    analysisUseCase.setAnalyzer(\n        // imageProcessor.processImageProxy will use another thread to run the detection underneath,\n        // thus we can just runs the analyzer itself on main thread.\n        ContextCompat.getMainExecutor(this),\n        imageProxy -> {\n          if (needUpdateGraphicOverlayImageSourceInfo) {\n            boolean isImageFlipped = lensFacing == CameraSelector.LENS_FACING_FRONT;\n            int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();\n            if (rotationDegrees == 0 || rotationDegrees == 180) {\n              graphicOverlay.setImageSourceInfo(\n                  imageProxy.getWidth(), imageProxy.getHeight(), isImageFlipped);\n            } else {\n              graphicOverlay.setImageSourceInfo(\n                  imageProxy.getHeight(), imageProxy.getWidth(), isImageFlipped);\n            }\n            needUpdateGraphicOverlayImageSourceInfo = false;\n          }\n          try {\n            imageProcessor.processImageProxy(imageProxy, graphicOverlay);\n          } catch (MlKitException e) {\n            Log.e(TAG, \"Failed to process image. Error: \" + e.getLocalizedMessage());\n            Toast.makeText(getApplicationContext(), e.getLocalizedMessage(), Toast.LENGTH_SHORT)\n                .show();\n          }\n        });\n\n    cameraProvider.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector, analysisUseCase);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/CameraXSourceDemoActivity.java",
    "content": "/*\n * Copyright 2021 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java;\n\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.os.Build.VERSION_CODES;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.util.Size;\nimport android.widget.CompoundButton;\nimport android.widget.ImageView;\nimport android.widget.Toast;\nimport android.widget.ToggleButton;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.view.PreviewView;\nimport com.google.android.gms.common.annotation.KeepName;\nimport com.google.mlkit.common.model.LocalModel;\nimport com.google.mlkit.vision.camera.CameraSourceConfig;\nimport com.google.mlkit.vision.camera.CameraXSource;\nimport com.google.mlkit.vision.camera.DetectionTaskCallback;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.InferenceInfoGraphic;\nimport com.google.mlkit.vision.demo.R;\nimport com.google.mlkit.vision.demo.java.objectdetector.ObjectGraphic;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.demo.preference.SettingsActivity;\nimport com.google.mlkit.vision.objects.DetectedObject;\nimport com.google.mlkit.vision.objects.ObjectDetection;\nimport com.google.mlkit.vision.objects.ObjectDetector;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport java.util.List;\nimport java.util.Objects;\n\n/** Live preview demo app for ML Kit APIs using CameraXSource API. */\n@KeepName\n@RequiresApi(VERSION_CODES.LOLLIPOP)\npublic final class CameraXSourceDemoActivity extends AppCompatActivity\n    implements CompoundButton.OnCheckedChangeListener {\n  private static final String TAG = \"CameraXSourceDemo\";\n\n  private static final LocalModel localModel =\n      new LocalModel.Builder().setAssetFilePath(\"custom_models/object_labeler.tflite\").build();\n\n  private PreviewView previewView;\n  private GraphicOverlay graphicOverlay;\n\n  private boolean needUpdateGraphicOverlayImageSourceInfo;\n\n  private int lensFacing = CameraSourceConfig.CAMERA_FACING_BACK;\n  private DetectionTaskCallback<List<DetectedObject>> detectionTaskCallback;\n  private CameraXSource cameraXSource;\n  private CustomObjectDetectorOptions customObjectDetectorOptions;\n  private Size targetResolution;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    Log.d(TAG, \"onCreate\");\n\n    setContentView(R.layout.activity_vision_cameraxsource_demo);\n    previewView = findViewById(R.id.preview_view);\n    if (previewView == null) {\n      Log.d(TAG, \"previewView is null\");\n    }\n    graphicOverlay = findViewById(R.id.graphic_overlay);\n    if (graphicOverlay == null) {\n      Log.d(TAG, \"graphicOverlay is null\");\n    }\n\n    ToggleButton facingSwitch = findViewById(R.id.facing_switch);\n    facingSwitch.setOnCheckedChangeListener(this);\n\n    ImageView settingsButton = findViewById(R.id.settings_button);\n    settingsButton.setOnClickListener(\n        v -> {\n          Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);\n          intent.putExtra(\n              SettingsActivity.EXTRA_LAUNCH_SOURCE,\n              SettingsActivity.LaunchSource.CAMERAXSOURCE_DEMO);\n          startActivity(intent);\n        });\n    detectionTaskCallback =\n        detectionTask ->\n            detectionTask\n                .addOnSuccessListener(this::onDetectionTaskSuccess)\n                .addOnFailureListener(this::onDetectionTaskFailure);\n  }\n\n  @Override\n  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n    lensFacing =\n        lensFacing == CameraSourceConfig.CAMERA_FACING_FRONT\n            ? CameraSourceConfig.CAMERA_FACING_BACK\n            : CameraSourceConfig.CAMERA_FACING_FRONT;\n\n    createThenStartCameraXSource();\n  }\n\n  @Override\n  public void onResume() {\n    super.onResume();\n    if (cameraXSource != null\n        && PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(this, localModel)\n            .equals(customObjectDetectorOptions)\n        && PreferenceUtils.getCameraXTargetResolution(getApplicationContext(), lensFacing) != null\n        && Objects.requireNonNull(\n                PreferenceUtils.getCameraXTargetResolution(getApplicationContext(), lensFacing))\n            .equals(targetResolution)) {\n      cameraXSource.start();\n    } else {\n      createThenStartCameraXSource();\n    }\n  }\n\n  @Override\n  protected void onPause() {\n    super.onPause();\n    if (cameraXSource != null) {\n      cameraXSource.stop();\n    }\n  }\n\n  @Override\n  public void onDestroy() {\n    super.onDestroy();\n    if (cameraXSource != null) {\n      cameraXSource.close();\n    }\n  }\n\n  private void createThenStartCameraXSource() {\n    if (cameraXSource != null) {\n      cameraXSource.close();\n    }\n    customObjectDetectorOptions =\n        PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(\n            getApplicationContext(), localModel);\n    ObjectDetector objectDetector = ObjectDetection.getClient(customObjectDetectorOptions);\n    CameraSourceConfig.Builder builder =\n        new CameraSourceConfig.Builder(\n                getApplicationContext(), objectDetector, detectionTaskCallback)\n            .setFacing(lensFacing);\n    targetResolution =\n        PreferenceUtils.getCameraXTargetResolution(getApplicationContext(), lensFacing);\n    if (targetResolution != null) {\n      builder.setRequestedPreviewSize(targetResolution.getWidth(), targetResolution.getHeight());\n    }\n    cameraXSource = new CameraXSource(builder.build(), previewView);\n    needUpdateGraphicOverlayImageSourceInfo = true;\n    cameraXSource.start();\n  }\n\n  private void onDetectionTaskSuccess(List<DetectedObject> results) {\n    graphicOverlay.clear();\n    if (needUpdateGraphicOverlayImageSourceInfo) {\n      Size size = cameraXSource.getPreviewSize();\n      if (size != null) {\n        Log.d(TAG, \"preview width: \" + size.getWidth());\n        Log.d(TAG, \"preview height: \" + size.getHeight());\n        boolean isImageFlipped =\n            cameraXSource.getCameraFacing() == CameraSourceConfig.CAMERA_FACING_FRONT;\n        if (isPortraitMode()) {\n          // Swap width and height sizes when in portrait, since it will be rotated by\n          // 90 degrees. The camera preview and the image being processed have the same size.\n          graphicOverlay.setImageSourceInfo(size.getHeight(), size.getWidth(), isImageFlipped);\n        } else {\n          graphicOverlay.setImageSourceInfo(size.getWidth(), size.getHeight(), isImageFlipped);\n        }\n        needUpdateGraphicOverlayImageSourceInfo = false;\n      } else {\n        Log.d(TAG, \"previewsize is null\");\n      }\n    }\n    Log.v(TAG, \"Number of object been detected: \" + results.size());\n    for (DetectedObject object : results) {\n      graphicOverlay.add(new ObjectGraphic(graphicOverlay, object));\n    }\n    graphicOverlay.add(new InferenceInfoGraphic(graphicOverlay));\n    graphicOverlay.postInvalidate();\n  }\n\n  private void onDetectionTaskFailure(Exception e) {\n    graphicOverlay.clear();\n    graphicOverlay.postInvalidate();\n    String error = \"Failed to process. Error: \" + e.getLocalizedMessage();\n    Toast.makeText(\n            graphicOverlay.getContext(), error + \"\\nCause: \" + e.getCause(), Toast.LENGTH_SHORT)\n        .show();\n    Log.d(TAG, error);\n  }\n\n  private boolean isPortraitMode() {\n    return getApplicationContext().getResources().getConfiguration().orientation\n        != Configuration.ORIENTATION_LANDSCAPE;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/ChooserActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build.VERSION;\nimport android.os.Build.VERSION_CODES;\nimport android.os.Bundle;\nimport android.os.StrictMode;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\nimport com.google.mlkit.vision.demo.BuildConfig;\nimport com.google.mlkit.vision.demo.R;\n\n/** Demo app chooser which allows you pick from all available testing Activities. */\npublic final class ChooserActivity extends AppCompatActivity\n    implements AdapterView.OnItemClickListener {\n  private static final String TAG = \"ChooserActivity\";\n\n  @SuppressWarnings(\"NewApi\") // CameraX is only available on API 21+\n  private static final Class<?>[] CLASSES =\n      VERSION.SDK_INT < VERSION_CODES.LOLLIPOP\n          ? new Class<?>[] {\n            LivePreviewActivity.class, StillImageActivity.class,\n          }\n          : new Class<?>[] {\n            LivePreviewActivity.class,\n            StillImageActivity.class,\n            CameraXLivePreviewActivity.class,\n            CameraXSourceDemoActivity.class,\n          };\n\n  private static final int[] DESCRIPTION_IDS =\n      VERSION.SDK_INT < VERSION_CODES.LOLLIPOP\n          ? new int[] {\n            R.string.desc_camera_source_activity, R.string.desc_still_image_activity,\n          }\n          : new int[] {\n            R.string.desc_camera_source_activity,\n            R.string.desc_still_image_activity,\n            R.string.desc_camerax_live_preview_activity,\n            R.string.desc_cameraxsource_demo_activity,\n          };\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    if (BuildConfig.DEBUG) {\n      StrictMode.setThreadPolicy(\n          new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());\n      StrictMode.setVmPolicy(\n          new StrictMode.VmPolicy.Builder()\n              .detectLeakedSqlLiteObjects()\n              .detectLeakedClosableObjects()\n              .penaltyLog()\n              .build());\n    }\n    super.onCreate(savedInstanceState);\n    Log.d(TAG, \"onCreate\");\n\n    setContentView(R.layout.activity_chooser);\n\n    // Set up ListView and Adapter\n    ListView listView = findViewById(R.id.test_activity_list_view);\n\n    MyArrayAdapter adapter = new MyArrayAdapter(this, android.R.layout.simple_list_item_2, CLASSES);\n    adapter.setDescriptionIds(DESCRIPTION_IDS);\n\n    listView.setAdapter(adapter);\n    listView.setOnItemClickListener(this);\n  }\n\n  @Override\n  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n    Class<?> clicked = CLASSES[position];\n    startActivity(new Intent(this, clicked));\n  }\n\n  private static class MyArrayAdapter extends ArrayAdapter<Class<?>> {\n\n    private final Context context;\n    private final Class<?>[] classes;\n    private int[] descriptionIds;\n\n    MyArrayAdapter(Context context, int resource, Class<?>[] objects) {\n      super(context, resource, objects);\n\n      this.context = context;\n      classes = objects;\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n      View view = convertView;\n\n      if (convertView == null) {\n        LayoutInflater inflater =\n            (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);\n        view = inflater.inflate(android.R.layout.simple_list_item_2, null);\n      }\n\n      ((TextView) view.findViewById(android.R.id.text1)).setText(classes[position].getSimpleName());\n      ((TextView) view.findViewById(android.R.id.text2)).setText(descriptionIds[position]);\n\n      return view;\n    }\n\n    void setDescriptionIds(int[] descriptionIds) {\n      this.descriptionIds = descriptionIds;\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/LivePreviewActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.CompoundButton;\nimport android.widget.ImageView;\nimport android.widget.Spinner;\nimport android.widget.Toast;\nimport android.widget.ToggleButton;\nimport com.google.android.gms.common.annotation.KeepName;\nimport com.google.mlkit.common.model.LocalModel;\nimport com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback;\nimport com.google.mlkit.vision.demo.CameraSource;\nimport com.google.mlkit.vision.demo.CameraSourcePreview;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.R;\nimport com.google.mlkit.vision.demo.java.barcodescanner.BarcodeScannerProcessor;\nimport com.google.mlkit.vision.demo.java.facedetector.FaceDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.labeldetector.LabelDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.objectdetector.ObjectDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.posedetector.PoseDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.segmenter.SegmenterProcessor;\nimport com.google.mlkit.vision.demo.java.textdetector.TextRecognitionProcessor;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.demo.preference.SettingsActivity;\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions;\nimport com.google.mlkit.vision.label.defaults.ImageLabelerOptions;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions;\nimport com.google.mlkit.vision.pose.PoseDetectorOptionsBase;\nimport com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions;\nimport com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions;\nimport com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions;\nimport com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions;\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** Live preview demo for ML Kit APIs. */\n@KeepName\npublic final class LivePreviewActivity extends AppCompatActivity\n    implements OnItemSelectedListener, CompoundButton.OnCheckedChangeListener {\n  private static final String OBJECT_DETECTION = \"Object Detection\";\n  private static final String OBJECT_DETECTION_CUSTOM = \"Custom Object Detection\";\n  private static final String CUSTOM_AUTOML_OBJECT_DETECTION =\n      \"Custom AutoML Object Detection (Flower)\";\n  private static final String FACE_DETECTION = \"Face Detection\";\n  private static final String BARCODE_SCANNING = \"Barcode Scanning\";\n  private static final String IMAGE_LABELING = \"Image Labeling\";\n  private static final String IMAGE_LABELING_CUSTOM = \"Custom Image Labeling (Birds)\";\n  private static final String CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling (Flower)\";\n  private static final String POSE_DETECTION = \"Pose Detection\";\n  private static final String SELFIE_SEGMENTATION = \"Selfie Segmentation\";\n  private static final String TEXT_RECOGNITION_LATIN = \"Text Recognition Latin\";\n  private static final String TEXT_RECOGNITION_CHINESE = \"Text Recognition Chinese\";\n  private static final String TEXT_RECOGNITION_DEVANAGARI = \"Text Recognition Devanagari\";\n  private static final String TEXT_RECOGNITION_JAPANESE = \"Text Recognition Japanese\";\n  private static final String TEXT_RECOGNITION_KOREAN = \"Text Recognition Korean\";\n  private static final String FACE_MESH_DETECTION = \"Face Mesh Detection (Beta)\";\n\n  private static final String TAG = \"LivePreviewActivity\";\n\n  private CameraSource cameraSource = null;\n  private CameraSourcePreview preview;\n  private GraphicOverlay graphicOverlay;\n  private String selectedModel = OBJECT_DETECTION;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    Log.d(TAG, \"onCreate\");\n\n    setContentView(R.layout.activity_vision_live_preview);\n\n    preview = findViewById(R.id.preview_view);\n    if (preview == null) {\n      Log.d(TAG, \"Preview is null\");\n    }\n    graphicOverlay = findViewById(R.id.graphic_overlay);\n    if (graphicOverlay == null) {\n      Log.d(TAG, \"graphicOverlay is null\");\n    }\n\n    Spinner spinner = findViewById(R.id.spinner);\n    List<String> options = new ArrayList<>();\n    options.add(OBJECT_DETECTION);\n    options.add(OBJECT_DETECTION_CUSTOM);\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION);\n    options.add(FACE_DETECTION);\n    options.add(BARCODE_SCANNING);\n    options.add(IMAGE_LABELING);\n    options.add(IMAGE_LABELING_CUSTOM);\n    options.add(CUSTOM_AUTOML_LABELING);\n    options.add(POSE_DETECTION);\n    options.add(SELFIE_SEGMENTATION);\n    options.add(TEXT_RECOGNITION_LATIN);\n    options.add(TEXT_RECOGNITION_CHINESE);\n    options.add(TEXT_RECOGNITION_DEVANAGARI);\n    options.add(TEXT_RECOGNITION_JAPANESE);\n    options.add(TEXT_RECOGNITION_KOREAN);\n    options.add(FACE_MESH_DETECTION);\n\n    // Creating adapter for spinner\n    ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // attaching data adapter to spinner\n    spinner.setAdapter(dataAdapter);\n    spinner.setOnItemSelectedListener(this);\n\n    ToggleButton facingSwitch = findViewById(R.id.facing_switch);\n    facingSwitch.setOnCheckedChangeListener(this);\n\n    ImageView settingsButton = findViewById(R.id.settings_button);\n    settingsButton.setOnClickListener(\n        v -> {\n          Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);\n          intent.putExtra(\n              SettingsActivity.EXTRA_LAUNCH_SOURCE, SettingsActivity.LaunchSource.LIVE_PREVIEW);\n          startActivity(intent);\n        });\n\n    createCameraSource(selectedModel);\n  }\n\n  @Override\n  public synchronized void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {\n    // An item was selected. You can retrieve the selected item using\n    // parent.getItemAtPosition(pos)\n    selectedModel = parent.getItemAtPosition(pos).toString();\n    Log.d(TAG, \"Selected model: \" + selectedModel);\n    preview.stop();\n    createCameraSource(selectedModel);\n    startCameraSource();\n  }\n\n  @Override\n  public void onNothingSelected(AdapterView<?> parent) {\n    // Do nothing.\n  }\n\n  @Override\n  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n    Log.d(TAG, \"Set facing\");\n    if (cameraSource != null) {\n      if (isChecked) {\n        cameraSource.setFacing(CameraSource.CAMERA_FACING_FRONT);\n      } else {\n        cameraSource.setFacing(CameraSource.CAMERA_FACING_BACK);\n      }\n    }\n    preview.stop();\n    startCameraSource();\n  }\n\n  private void createCameraSource(String model) {\n    // If there's no existing cameraSource, create one.\n    if (cameraSource == null) {\n      cameraSource = new CameraSource(this, graphicOverlay);\n    }\n\n    try {\n      switch (model) {\n        case OBJECT_DETECTION:\n          Log.i(TAG, \"Using Object Detector Processor\");\n          ObjectDetectorOptions objectDetectorOptions =\n              PreferenceUtils.getObjectDetectorOptionsForLivePreview(this);\n          cameraSource.setMachineLearningFrameProcessor(\n              new ObjectDetectorProcessor(this, objectDetectorOptions));\n          break;\n        case OBJECT_DETECTION_CUSTOM:\n          Log.i(TAG, \"Using Custom Object Detector Processor\");\n          LocalModel localModel =\n              new LocalModel.Builder()\n                  .setAssetFilePath(\"custom_models/object_labeler.tflite\")\n                  .build();\n          CustomObjectDetectorOptions customObjectDetectorOptions =\n              PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(this, localModel);\n          cameraSource.setMachineLearningFrameProcessor(\n              new ObjectDetectorProcessor(this, customObjectDetectorOptions));\n          break;\n        case CUSTOM_AUTOML_OBJECT_DETECTION:\n          Log.i(TAG, \"Using Custom AutoML Object Detector Processor\");\n          LocalModel customAutoMLODTLocalModel =\n              new LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build();\n          CustomObjectDetectorOptions customAutoMLODTOptions =\n              PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(\n                  this, customAutoMLODTLocalModel);\n          cameraSource.setMachineLearningFrameProcessor(\n              new ObjectDetectorProcessor(this, customAutoMLODTOptions));\n          break;\n        case TEXT_RECOGNITION_LATIN:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin.\");\n          cameraSource.setMachineLearningFrameProcessor(\n              new TextRecognitionProcessor(this, new TextRecognizerOptions.Builder().build()));\n          break;\n        case TEXT_RECOGNITION_CHINESE:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Chinese.\");\n          cameraSource.setMachineLearningFrameProcessor(\n              new TextRecognitionProcessor(\n                  this, new ChineseTextRecognizerOptions.Builder().build()));\n          break;\n        case TEXT_RECOGNITION_DEVANAGARI:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Devanagari.\");\n          cameraSource.setMachineLearningFrameProcessor(\n              new TextRecognitionProcessor(\n                  this, new DevanagariTextRecognizerOptions.Builder().build()));\n          break;\n        case TEXT_RECOGNITION_JAPANESE:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Japanese.\");\n          cameraSource.setMachineLearningFrameProcessor(\n              new TextRecognitionProcessor(\n                  this, new JapaneseTextRecognizerOptions.Builder().build()));\n          break;\n        case TEXT_RECOGNITION_KOREAN:\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Korean.\");\n          cameraSource.setMachineLearningFrameProcessor(\n              new TextRecognitionProcessor(\n                  this, new KoreanTextRecognizerOptions.Builder().build()));\n          break;\n        case FACE_DETECTION:\n          Log.i(TAG, \"Using Face Detector Processor\");\n          cameraSource.setMachineLearningFrameProcessor(new FaceDetectorProcessor(this));\n          break;\n        case BARCODE_SCANNING:\n          Log.i(TAG, \"Using Barcode Detector Processor\");\n          ZoomCallback zoomCallback = null;\n          if (PreferenceUtils.shouldEnableAutoZoom(this)) {\n            zoomCallback = zoomLevel -> cameraSource.setZoom(zoomLevel);\n          }\n          cameraSource.setMachineLearningFrameProcessor(\n              new BarcodeScannerProcessor(this, zoomCallback));\n          break;\n        case IMAGE_LABELING:\n          Log.i(TAG, \"Using Image Label Detector Processor\");\n          cameraSource.setMachineLearningFrameProcessor(\n              new LabelDetectorProcessor(this, ImageLabelerOptions.DEFAULT_OPTIONS));\n          break;\n        case IMAGE_LABELING_CUSTOM:\n          Log.i(TAG, \"Using Custom Image Label Detector Processor\");\n          LocalModel localClassifier =\n              new LocalModel.Builder()\n                  .setAssetFilePath(\"custom_models/bird_classifier.tflite\")\n                  .build();\n          CustomImageLabelerOptions customImageLabelerOptions =\n              new CustomImageLabelerOptions.Builder(localClassifier).build();\n          cameraSource.setMachineLearningFrameProcessor(\n              new LabelDetectorProcessor(this, customImageLabelerOptions));\n          break;\n        case CUSTOM_AUTOML_LABELING:\n          Log.i(TAG, \"Using Custom AutoML Image Label Detector Processor\");\n          LocalModel customAutoMLLabelLocalModel =\n              new LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build();\n          CustomImageLabelerOptions customAutoMLLabelOptions =\n              new CustomImageLabelerOptions.Builder(customAutoMLLabelLocalModel)\n                  .setConfidenceThreshold(0)\n                  .build();\n          cameraSource.setMachineLearningFrameProcessor(\n              new LabelDetectorProcessor(this, customAutoMLLabelOptions));\n          break;\n        case POSE_DETECTION:\n          PoseDetectorOptionsBase poseDetectorOptions =\n              PreferenceUtils.getPoseDetectorOptionsForLivePreview(this);\n          Log.i(TAG, \"Using Pose Detector with options \" + poseDetectorOptions);\n          boolean shouldShowInFrameLikelihood =\n              PreferenceUtils.shouldShowPoseDetectionInFrameLikelihoodLivePreview(this);\n          boolean visualizeZ = PreferenceUtils.shouldPoseDetectionVisualizeZ(this);\n          boolean rescaleZ = PreferenceUtils.shouldPoseDetectionRescaleZForVisualization(this);\n          boolean runClassification = PreferenceUtils.shouldPoseDetectionRunClassification(this);\n          cameraSource.setMachineLearningFrameProcessor(\n              new PoseDetectorProcessor(\n                  this,\n                  poseDetectorOptions,\n                  shouldShowInFrameLikelihood,\n                  visualizeZ,\n                  rescaleZ,\n                  runClassification,\n                  /* isStreamMode = */ true));\n          break;\n        case SELFIE_SEGMENTATION:\n          cameraSource.setMachineLearningFrameProcessor(new SegmenterProcessor(this));\n          break;\n        case FACE_MESH_DETECTION:\n          cameraSource.setMachineLearningFrameProcessor(new FaceMeshDetectorProcessor(this));\n          break;\n        default:\n          Log.e(TAG, \"Unknown model: \" + model);\n      }\n    } catch (RuntimeException e) {\n      Log.e(TAG, \"Can not create image processor: \" + model, e);\n      Toast.makeText(\n              getApplicationContext(),\n              \"Can not create image processor: \" + e.getMessage(),\n              Toast.LENGTH_LONG)\n          .show();\n    }\n  }\n\n  /**\n   * Starts or restarts the camera source, if it exists. If the camera source doesn't exist yet\n   * (e.g., because onResume was called before the camera source was created), this will be called\n   * again when the camera source is created.\n   */\n  private void startCameraSource() {\n    if (cameraSource != null) {\n      try {\n        if (preview == null) {\n          Log.d(TAG, \"resume: Preview is null\");\n        }\n        if (graphicOverlay == null) {\n          Log.d(TAG, \"resume: graphOverlay is null\");\n        }\n        preview.start(cameraSource, graphicOverlay);\n      } catch (IOException e) {\n        Log.e(TAG, \"Unable to start camera source.\", e);\n        cameraSource.release();\n        cameraSource = null;\n      }\n    }\n  }\n\n  @Override\n  public void onResume() {\n    super.onResume();\n    Log.d(TAG, \"onResume\");\n    createCameraSource(selectedModel);\n    startCameraSource();\n  }\n\n  /** Stops the camera. */\n  @Override\n  protected void onPause() {\n    super.onPause();\n    preview.stop();\n  }\n\n  @Override\n  public void onDestroy() {\n    super.onDestroy();\n    if (cameraSource != null) {\n      cameraSource.release();\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/StillImageActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java;\n\nimport static java.lang.Math.max;\n\nimport android.content.ContentValues;\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Build.VERSION;\nimport android.os.Bundle;\nimport android.provider.MediaStore;\nimport androidx.appcompat.app.AppCompatActivity;\nimport android.util.Log;\nimport android.util.Pair;\nimport android.view.MenuInflater;\nimport android.view.View;\nimport android.view.ViewTreeObserver.OnGlobalLayoutListener;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.ImageView;\nimport android.widget.PopupMenu;\nimport android.widget.Spinner;\nimport android.widget.Toast;\nimport com.google.android.gms.common.annotation.KeepName;\nimport com.google.mlkit.common.model.LocalModel;\nimport com.google.mlkit.vision.demo.BitmapUtils;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.R;\nimport com.google.mlkit.vision.demo.VisionImageProcessor;\nimport com.google.mlkit.vision.demo.java.barcodescanner.BarcodeScannerProcessor;\nimport com.google.mlkit.vision.demo.java.facedetector.FaceDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.facemeshdetector.FaceMeshDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.labeldetector.LabelDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.objectdetector.ObjectDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.posedetector.PoseDetectorProcessor;\nimport com.google.mlkit.vision.demo.java.segmenter.SegmenterProcessor;\nimport com.google.mlkit.vision.demo.java.subjectsegmenter.SubjectSegmenterProcessor;\nimport com.google.mlkit.vision.demo.java.textdetector.TextRecognitionProcessor;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.demo.preference.SettingsActivity;\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions;\nimport com.google.mlkit.vision.label.defaults.ImageLabelerOptions;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions;\nimport com.google.mlkit.vision.pose.PoseDetectorOptionsBase;\nimport com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions;\nimport com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions;\nimport com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions;\nimport com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions;\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/** Activity demonstrating different image detector features with a still image from camera. */\n@KeepName\npublic final class StillImageActivity extends AppCompatActivity {\n\n  private static final String TAG = \"StillImageActivity\";\n\n  private static final String OBJECT_DETECTION = \"Object Detection\";\n  private static final String OBJECT_DETECTION_CUSTOM = \"Custom Object Detection\";\n  private static final String CUSTOM_AUTOML_OBJECT_DETECTION =\n      \"Custom AutoML Object Detection (Flower)\";\n  private static final String FACE_DETECTION = \"Face Detection\";\n  private static final String BARCODE_SCANNING = \"Barcode Scanning\";\n  private static final String IMAGE_LABELING = \"Image Labeling\";\n  private static final String IMAGE_LABELING_CUSTOM = \"Custom Image Labeling (Birds)\";\n  private static final String CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling (Flower)\";\n  private static final String POSE_DETECTION = \"Pose Detection\";\n  private static final String SELFIE_SEGMENTATION = \"Selfie Segmentation\";\n  private static final String TEXT_RECOGNITION_LATIN = \"Text Recognition Latin\";\n  private static final String TEXT_RECOGNITION_CHINESE = \"Text Recognition Chinese\";\n  private static final String TEXT_RECOGNITION_DEVANAGARI = \"Text Recognition Devanagari\";\n  private static final String TEXT_RECOGNITION_JAPANESE = \"Text Recognition Japanese\";\n  private static final String TEXT_RECOGNITION_KOREAN = \"Text Recognition Korean\";\n  private static final String FACE_MESH_DETECTION = \"Face Mesh Detection (Beta)\";\n  private static final String SUBJECT_SEGMENTATION = \"Subject Segmentation (Beta)\";\n\n  private static final String SIZE_SCREEN = \"w:screen\"; // Match screen width\n  private static final String SIZE_1024_768 = \"w:1024\"; // ~1024*768 in a normal ratio\n  private static final String SIZE_640_480 = \"w:640\"; // ~640*480 in a normal ratio\n  private static final String SIZE_ORIGINAL = \"w:original\"; // Original image size\n\n  private static final String KEY_IMAGE_URI = \"com.google.mlkit.vision.demo.KEY_IMAGE_URI\";\n  private static final String KEY_SELECTED_SIZE = \"com.google.mlkit.vision.demo.KEY_SELECTED_SIZE\";\n\n  private static final int REQUEST_IMAGE_CAPTURE = 1001;\n  private static final int REQUEST_CHOOSE_IMAGE = 1002;\n\n  private ImageView preview;\n  private GraphicOverlay graphicOverlay;\n  private String selectedMode = OBJECT_DETECTION;\n  private String selectedSize = SIZE_SCREEN;\n\n  boolean isLandScape;\n\n  private Uri imageUri;\n  private int imageMaxWidth;\n  private int imageMaxHeight;\n  private VisionImageProcessor imageProcessor;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    setContentView(R.layout.activity_still_image);\n\n    findViewById(R.id.select_image_button)\n        .setOnClickListener(\n            view -> {\n              // Menu for selecting either: a) take new photo b) select from existing\n              PopupMenu popup = new PopupMenu(StillImageActivity.this, view);\n              popup.setOnMenuItemClickListener(\n                  menuItem -> {\n                    int itemId = menuItem.getItemId();\n                    if (itemId == R.id.select_images_from_local) {\n                      startChooseImageIntentForResult();\n                      return true;\n                    } else if (itemId == R.id.take_photo_using_camera) {\n                      startCameraIntentForResult();\n                      return true;\n                    }\n                    return false;\n                  });\n              MenuInflater inflater = popup.getMenuInflater();\n              inflater.inflate(R.menu.camera_button_menu, popup.getMenu());\n              popup.show();\n            });\n    preview = findViewById(R.id.preview);\n    graphicOverlay = findViewById(R.id.graphic_overlay);\n\n    populateFeatureSelector();\n    populateSizeSelector();\n\n    isLandScape =\n        (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);\n\n    if (savedInstanceState != null) {\n      imageUri = savedInstanceState.getParcelable(KEY_IMAGE_URI);\n      selectedSize = savedInstanceState.getString(KEY_SELECTED_SIZE);\n    }\n\n    View rootView = findViewById(R.id.root);\n    rootView\n        .getViewTreeObserver()\n        .addOnGlobalLayoutListener(\n            new OnGlobalLayoutListener() {\n              @Override\n              public void onGlobalLayout() {\n                rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);\n                imageMaxWidth = rootView.getWidth();\n                imageMaxHeight = rootView.getHeight() - findViewById(R.id.control).getHeight();\n                if (SIZE_SCREEN.equals(selectedSize)) {\n                  tryReloadAndDetectInImage();\n                }\n              }\n            });\n\n    ImageView settingsButton = findViewById(R.id.settings_button);\n    settingsButton.setOnClickListener(\n        v -> {\n          Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);\n          intent.putExtra(\n              SettingsActivity.EXTRA_LAUNCH_SOURCE, SettingsActivity.LaunchSource.STILL_IMAGE);\n          startActivity(intent);\n        });\n  }\n\n  @Override\n  public void onResume() {\n    super.onResume();\n    Log.d(TAG, \"onResume\");\n    createImageProcessor();\n    tryReloadAndDetectInImage();\n  }\n\n  @Override\n  public void onPause() {\n    super.onPause();\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n  }\n\n  @Override\n  public void onDestroy() {\n    super.onDestroy();\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n  }\n\n  private void populateFeatureSelector() {\n    Spinner featureSpinner = findViewById(R.id.feature_selector);\n    List<String> options = new ArrayList<>();\n    options.add(OBJECT_DETECTION);\n    options.add(OBJECT_DETECTION_CUSTOM);\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION);\n    options.add(FACE_DETECTION);\n    options.add(BARCODE_SCANNING);\n    options.add(IMAGE_LABELING);\n    options.add(IMAGE_LABELING_CUSTOM);\n    options.add(CUSTOM_AUTOML_LABELING);\n    options.add(POSE_DETECTION);\n    options.add(SELFIE_SEGMENTATION);\n    options.add(TEXT_RECOGNITION_LATIN);\n    options.add(TEXT_RECOGNITION_CHINESE);\n    options.add(TEXT_RECOGNITION_DEVANAGARI);\n    options.add(TEXT_RECOGNITION_JAPANESE);\n    options.add(TEXT_RECOGNITION_KOREAN);\n    options.add(FACE_MESH_DETECTION);\n    if (VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n      options.add(SUBJECT_SEGMENTATION);\n    }\n\n    // Creating adapter for featureSpinner\n    ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // attaching data adapter to spinner\n    featureSpinner.setAdapter(dataAdapter);\n    featureSpinner.setOnItemSelectedListener(\n        new OnItemSelectedListener() {\n\n          @Override\n          public void onItemSelected(\n              AdapterView<?> parentView, View selectedItemView, int pos, long id) {\n            selectedMode = parentView.getItemAtPosition(pos).toString();\n            createImageProcessor();\n            tryReloadAndDetectInImage();\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> arg0) {}\n        });\n  }\n\n  private void populateSizeSelector() {\n    Spinner sizeSpinner = findViewById(R.id.size_selector);\n    List<String> options = new ArrayList<>();\n    options.add(SIZE_SCREEN);\n    options.add(SIZE_1024_768);\n    options.add(SIZE_640_480);\n    options.add(SIZE_ORIGINAL);\n\n    // Creating adapter for featureSpinner\n    ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n    // attaching data adapter to spinner\n    sizeSpinner.setAdapter(dataAdapter);\n    sizeSpinner.setOnItemSelectedListener(\n        new OnItemSelectedListener() {\n\n          @Override\n          public void onItemSelected(\n              AdapterView<?> parentView, View selectedItemView, int pos, long id) {\n            selectedSize = parentView.getItemAtPosition(pos).toString();\n            tryReloadAndDetectInImage();\n          }\n\n          @Override\n          public void onNothingSelected(AdapterView<?> arg0) {}\n        });\n  }\n\n  @Override\n  public void onSaveInstanceState(Bundle outState) {\n    super.onSaveInstanceState(outState);\n    outState.putParcelable(KEY_IMAGE_URI, imageUri);\n    outState.putString(KEY_SELECTED_SIZE, selectedSize);\n  }\n\n  private void startCameraIntentForResult() {\n    // Clean up last time's image\n    imageUri = null;\n    preview.setImageBitmap(null);\n\n    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);\n    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {\n      ContentValues values = new ContentValues();\n      values.put(MediaStore.Images.Media.TITLE, \"New Picture\");\n      values.put(MediaStore.Images.Media.DESCRIPTION, \"From Camera\");\n      imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);\n      takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);\n      startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);\n    }\n  }\n\n  private void startChooseImageIntentForResult() {\n    Intent intent = new Intent();\n    intent.setType(\"image/*\");\n    intent.setAction(Intent.ACTION_GET_CONTENT);\n    startActivityForResult(Intent.createChooser(intent, \"Select Picture\"), REQUEST_CHOOSE_IMAGE);\n  }\n\n  @Override\n  protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {\n      tryReloadAndDetectInImage();\n    } else if (requestCode == REQUEST_CHOOSE_IMAGE && resultCode == RESULT_OK) {\n      // In this case, imageUri is returned by the chooser, save it.\n      imageUri = data.getData();\n      tryReloadAndDetectInImage();\n    } else {\n      super.onActivityResult(requestCode, resultCode, data);\n    }\n  }\n\n  private void tryReloadAndDetectInImage() {\n    Log.d(TAG, \"Try reload and detect image\");\n    try {\n      if (imageUri == null) {\n        return;\n      }\n\n      if (SIZE_SCREEN.equals(selectedSize) && imageMaxWidth == 0) {\n        // UI layout has not finished yet, will reload once it's ready.\n        return;\n      }\n\n      Bitmap imageBitmap = BitmapUtils.getBitmapFromContentUri(getContentResolver(), imageUri);\n      if (imageBitmap == null) {\n        return;\n      }\n\n      // Clear the overlay first\n      graphicOverlay.clear();\n\n      Bitmap resizedBitmap;\n      if (selectedSize.equals(SIZE_ORIGINAL)) {\n        resizedBitmap = imageBitmap;\n      } else {\n        // Get the dimensions of the image view\n        Pair<Integer, Integer> targetedSize = getTargetedWidthHeight();\n\n        // Determine how much to scale down the image\n        float scaleFactor =\n            max(\n                (float) imageBitmap.getWidth() / (float) targetedSize.first,\n                (float) imageBitmap.getHeight() / (float) targetedSize.second);\n\n        resizedBitmap =\n            Bitmap.createScaledBitmap(\n                imageBitmap,\n                (int) (imageBitmap.getWidth() / scaleFactor),\n                (int) (imageBitmap.getHeight() / scaleFactor),\n                true);\n      }\n\n      preview.setImageBitmap(resizedBitmap);\n\n      if (imageProcessor != null) {\n        graphicOverlay.setImageSourceInfo(\n            resizedBitmap.getWidth(), resizedBitmap.getHeight(), /* isFlipped= */ false);\n        imageProcessor.processBitmap(resizedBitmap, graphicOverlay);\n      } else {\n        Log.e(TAG, \"Null imageProcessor, please check adb logs for imageProcessor creation error\");\n      }\n    } catch (IOException e) {\n      Log.e(TAG, \"Error retrieving saved image\");\n      imageUri = null;\n    }\n  }\n\n  private Pair<Integer, Integer> getTargetedWidthHeight() {\n    int targetWidth;\n    int targetHeight;\n\n    switch (selectedSize) {\n      case SIZE_SCREEN:\n        targetWidth = imageMaxWidth;\n        targetHeight = imageMaxHeight;\n        break;\n      case SIZE_640_480:\n        targetWidth = isLandScape ? 640 : 480;\n        targetHeight = isLandScape ? 480 : 640;\n        break;\n      case SIZE_1024_768:\n        targetWidth = isLandScape ? 1024 : 768;\n        targetHeight = isLandScape ? 768 : 1024;\n        break;\n      default:\n        throw new IllegalStateException(\"Unknown size\");\n    }\n\n    return new Pair<>(targetWidth, targetHeight);\n  }\n\n  private void createImageProcessor() {\n    if (imageProcessor != null) {\n      imageProcessor.stop();\n    }\n    try {\n      switch (selectedMode) {\n        case OBJECT_DETECTION:\n          Log.i(TAG, \"Using Object Detector Processor\");\n          ObjectDetectorOptions objectDetectorOptions =\n              PreferenceUtils.getObjectDetectorOptionsForStillImage(this);\n          imageProcessor = new ObjectDetectorProcessor(this, objectDetectorOptions);\n          break;\n        case OBJECT_DETECTION_CUSTOM:\n          Log.i(TAG, \"Using Custom Object Detector Processor\");\n          LocalModel localModel =\n              new LocalModel.Builder()\n                  .setAssetFilePath(\"custom_models/object_labeler.tflite\")\n                  .build();\n          CustomObjectDetectorOptions customObjectDetectorOptions =\n              PreferenceUtils.getCustomObjectDetectorOptionsForStillImage(this, localModel);\n          imageProcessor = new ObjectDetectorProcessor(this, customObjectDetectorOptions);\n          break;\n        case CUSTOM_AUTOML_OBJECT_DETECTION:\n          Log.i(TAG, \"Using Custom AutoML Object Detector Processor\");\n          LocalModel customAutoMLODTLocalModel =\n              new LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build();\n          CustomObjectDetectorOptions customAutoMLODTOptions =\n              PreferenceUtils.getCustomObjectDetectorOptionsForStillImage(\n                  this, customAutoMLODTLocalModel);\n          imageProcessor = new ObjectDetectorProcessor(this, customAutoMLODTOptions);\n          break;\n        case FACE_DETECTION:\n          Log.i(TAG, \"Using Face Detector Processor\");\n          imageProcessor = new FaceDetectorProcessor(this);\n          break;\n        case BARCODE_SCANNING:\n          imageProcessor = new BarcodeScannerProcessor(this, /* zoomCallback= */ null);\n          break;\n        case TEXT_RECOGNITION_LATIN:\n          if (imageProcessor != null) {\n            imageProcessor.stop();\n          }\n          imageProcessor =\n              new TextRecognitionProcessor(this, new TextRecognizerOptions.Builder().build());\n          break;\n        case TEXT_RECOGNITION_CHINESE:\n          if (imageProcessor != null) {\n            imageProcessor.stop();\n          }\n          imageProcessor =\n              new TextRecognitionProcessor(\n                  this, new ChineseTextRecognizerOptions.Builder().build());\n          break;\n        case TEXT_RECOGNITION_DEVANAGARI:\n          if (imageProcessor != null) {\n            imageProcessor.stop();\n          }\n          imageProcessor =\n              new TextRecognitionProcessor(\n                  this, new DevanagariTextRecognizerOptions.Builder().build());\n          break;\n        case TEXT_RECOGNITION_JAPANESE:\n          if (imageProcessor != null) {\n            imageProcessor.stop();\n          }\n          imageProcessor =\n              new TextRecognitionProcessor(\n                  this, new JapaneseTextRecognizerOptions.Builder().build());\n          break;\n        case TEXT_RECOGNITION_KOREAN:\n          if (imageProcessor != null) {\n            imageProcessor.stop();\n          }\n          imageProcessor =\n              new TextRecognitionProcessor(this, new KoreanTextRecognizerOptions.Builder().build());\n          break;\n        case IMAGE_LABELING:\n          imageProcessor = new LabelDetectorProcessor(this, ImageLabelerOptions.DEFAULT_OPTIONS);\n          break;\n        case IMAGE_LABELING_CUSTOM:\n          Log.i(TAG, \"Using Custom Image Label Detector Processor\");\n          LocalModel localClassifier =\n              new LocalModel.Builder()\n                  .setAssetFilePath(\"custom_models/bird_classifier.tflite\")\n                  .build();\n          CustomImageLabelerOptions customImageLabelerOptions =\n              new CustomImageLabelerOptions.Builder(localClassifier).build();\n          imageProcessor = new LabelDetectorProcessor(this, customImageLabelerOptions);\n          break;\n        case CUSTOM_AUTOML_LABELING:\n          Log.i(TAG, \"Using Custom AutoML Image Label Detector Processor\");\n          LocalModel customAutoMLLabelLocalModel =\n              new LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build();\n          CustomImageLabelerOptions customAutoMLLabelOptions =\n              new CustomImageLabelerOptions.Builder(customAutoMLLabelLocalModel)\n                  .setConfidenceThreshold(0)\n                  .build();\n          imageProcessor = new LabelDetectorProcessor(this, customAutoMLLabelOptions);\n          break;\n        case POSE_DETECTION:\n          PoseDetectorOptionsBase poseDetectorOptions =\n              PreferenceUtils.getPoseDetectorOptionsForStillImage(this);\n          Log.i(TAG, \"Using Pose Detector with options \" + poseDetectorOptions);\n          boolean shouldShowInFrameLikelihood =\n              PreferenceUtils.shouldShowPoseDetectionInFrameLikelihoodStillImage(this);\n          boolean visualizeZ = PreferenceUtils.shouldPoseDetectionVisualizeZ(this);\n          boolean rescaleZ = PreferenceUtils.shouldPoseDetectionRescaleZForVisualization(this);\n          boolean runClassification = PreferenceUtils.shouldPoseDetectionRunClassification(this);\n          imageProcessor =\n              new PoseDetectorProcessor(\n                  this,\n                  poseDetectorOptions,\n                  shouldShowInFrameLikelihood,\n                  visualizeZ,\n                  rescaleZ,\n                  runClassification,\n                  /* isStreamMode = */ false);\n          break;\n        case SELFIE_SEGMENTATION:\n          imageProcessor = new SegmenterProcessor(this, /* isStreamMode= */ false);\n          break;\n        case FACE_MESH_DETECTION:\n          imageProcessor = new FaceMeshDetectorProcessor(this);\n          break;\n        case SUBJECT_SEGMENTATION:\n          if (VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            imageProcessor = new SubjectSegmenterProcessor(this);\n            break;\n          }\n          // fall through\n        default:\n          Log.e(TAG, \"Unknown selectedMode: \" + selectedMode);\n      }\n    } catch (Exception e) {\n      Log.e(TAG, \"Can not create image processor: \" + selectedMode, e);\n      Toast.makeText(\n              getApplicationContext(),\n              \"Can not create image processor: \" + e.getMessage(),\n              Toast.LENGTH_LONG)\n          .show();\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/VisionProcessorBase.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java;\n\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\n\nimport android.app.ActivityManager;\nimport android.app.ActivityManager.MemoryInfo;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.Build.VERSION_CODES;\nimport android.os.SystemClock;\nimport android.util.Log;\nimport android.widget.Toast;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.camera.core.ExperimentalGetImage;\nimport androidx.camera.core.ImageProxy;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.gms.tasks.TaskExecutors;\nimport com.google.android.gms.tasks.Tasks;\nimport com.google.android.odml.image.BitmapMlImageBuilder;\nimport com.google.android.odml.image.ByteBufferMlImageBuilder;\nimport com.google.android.odml.image.MediaMlImageBuilder;\nimport com.google.android.odml.image.MlImage;\nimport com.google.mlkit.common.MlKitException;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.BitmapUtils;\nimport com.google.mlkit.vision.demo.CameraImageGraphic;\nimport com.google.mlkit.vision.demo.FrameMetadata;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.InferenceInfoGraphic;\nimport com.google.mlkit.vision.demo.ScopedExecutor;\nimport com.google.mlkit.vision.demo.TemperatureMonitor;\nimport com.google.mlkit.vision.demo.VisionImageProcessor;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport java.nio.ByteBuffer;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\n/**\n * Abstract base class for vision frame processors. Subclasses need to implement {@link\n * #onSuccess(Object, GraphicOverlay)} to define what they want to with the detection results and\n * {@link #detectInImage(InputImage)} to specify the detector object.\n *\n * @param <T> The type of the detected feature.\n */\npublic abstract class VisionProcessorBase<T> implements VisionImageProcessor {\n\n  protected static final String MANUAL_TESTING_LOG = \"LogTagForTest\";\n  private static final String TAG = \"VisionProcessorBase\";\n\n  private final ActivityManager activityManager;\n  private final Timer fpsTimer = new Timer();\n  private final ScopedExecutor executor;\n  private final TemperatureMonitor temperatureMonitor;\n\n  // Whether this processor is already shut down\n  private boolean isShutdown;\n\n  // Used to calculate latency, running in the same thread, no sync needed.\n  private int numRuns = 0;\n  private long totalFrameMs = 0;\n  private long maxFrameMs = 0;\n  private long minFrameMs = Long.MAX_VALUE;\n  private long totalDetectorMs = 0;\n  private long maxDetectorMs = 0;\n  private long minDetectorMs = Long.MAX_VALUE;\n\n  // Frame count that have been processed so far in an one second interval to calculate FPS.\n  private int frameProcessedInOneSecondInterval = 0;\n  private int framesPerSecond = 0;\n\n  // To keep the latest images and its metadata.\n  @GuardedBy(\"this\")\n  private ByteBuffer latestImage;\n\n  @GuardedBy(\"this\")\n  private FrameMetadata latestImageMetaData;\n  // To keep the images and metadata in process.\n  @GuardedBy(\"this\")\n  private ByteBuffer processingImage;\n\n  @GuardedBy(\"this\")\n  private FrameMetadata processingMetaData;\n\n  protected VisionProcessorBase(Context context) {\n    activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n    executor = new ScopedExecutor(TaskExecutors.MAIN_THREAD);\n    fpsTimer.scheduleAtFixedRate(\n        new TimerTask() {\n          @Override\n          public void run() {\n            framesPerSecond = frameProcessedInOneSecondInterval;\n            frameProcessedInOneSecondInterval = 0;\n          }\n        },\n        /* delay= */ 0,\n        /* period= */ 1000);\n    temperatureMonitor = new TemperatureMonitor(context);\n  }\n\n  // -----------------Code for processing single still image----------------------------------------\n  @Override\n  public void processBitmap(Bitmap bitmap, final GraphicOverlay graphicOverlay) {\n    long frameStartMs = SystemClock.elapsedRealtime();\n\n    if (isMlImageEnabled(graphicOverlay.getContext())) {\n      MlImage mlImage = new BitmapMlImageBuilder(bitmap).build();\n      requestDetectInImage(\n          mlImage,\n          graphicOverlay,\n          /* originalCameraImage= */ null,\n          /* shouldShowFps= */ false,\n          frameStartMs);\n      mlImage.close();\n\n      return;\n    }\n\n    requestDetectInImage(\n        InputImage.fromBitmap(bitmap, 0),\n        graphicOverlay,\n        /* originalCameraImage= */ null,\n        /* shouldShowFps= */ false,\n        frameStartMs);\n  }\n\n  // -----------------Code for processing live preview frame from Camera1 API-----------------------\n  @Override\n  public synchronized void processByteBuffer(\n      ByteBuffer data, final FrameMetadata frameMetadata, final GraphicOverlay graphicOverlay) {\n    latestImage = data;\n    latestImageMetaData = frameMetadata;\n    if (processingImage == null && processingMetaData == null) {\n      processLatestImage(graphicOverlay);\n    }\n  }\n\n  private synchronized void processLatestImage(final GraphicOverlay graphicOverlay) {\n    processingImage = latestImage;\n    processingMetaData = latestImageMetaData;\n    latestImage = null;\n    latestImageMetaData = null;\n    if (processingImage != null && processingMetaData != null && !isShutdown) {\n      processImage(processingImage, processingMetaData, graphicOverlay);\n    }\n  }\n\n  private void processImage(\n      ByteBuffer data, final FrameMetadata frameMetadata, final GraphicOverlay graphicOverlay) {\n    long frameStartMs = SystemClock.elapsedRealtime();\n\n    // If live viewport is on (that is the underneath surface view takes care of the camera preview\n    // drawing), skip the unnecessary bitmap creation that used for the manual preview drawing.\n    Bitmap bitmap =\n        PreferenceUtils.isCameraLiveViewportEnabled(graphicOverlay.getContext())\n            ? null\n            : BitmapUtils.getBitmap(data, frameMetadata);\n\n    if (isMlImageEnabled(graphicOverlay.getContext())) {\n      MlImage mlImage =\n          new ByteBufferMlImageBuilder(\n                  data,\n                  frameMetadata.getWidth(),\n                  frameMetadata.getHeight(),\n                  MlImage.IMAGE_FORMAT_NV21)\n              .setRotation(frameMetadata.getRotation())\n              .build();\n\n      requestDetectInImage(mlImage, graphicOverlay, bitmap, /* shouldShowFps= */ true, frameStartMs)\n          .addOnSuccessListener(executor, results -> processLatestImage(graphicOverlay));\n\n      // This is optional. Java Garbage collection can also close it eventually.\n      mlImage.close();\n      return;\n    }\n\n    requestDetectInImage(\n            InputImage.fromByteBuffer(\n                data,\n                frameMetadata.getWidth(),\n                frameMetadata.getHeight(),\n                frameMetadata.getRotation(),\n                InputImage.IMAGE_FORMAT_NV21),\n            graphicOverlay,\n            bitmap,\n            /* shouldShowFps= */ true,\n            frameStartMs)\n        .addOnSuccessListener(executor, results -> processLatestImage(graphicOverlay));\n  }\n\n  // -----------------Code for processing live preview frame from CameraX API-----------------------\n  @Override\n  @RequiresApi(VERSION_CODES.LOLLIPOP)\n  @ExperimentalGetImage\n  public void processImageProxy(ImageProxy image, GraphicOverlay graphicOverlay) {\n    long frameStartMs = SystemClock.elapsedRealtime();\n    if (isShutdown) {\n      image.close();\n      return;\n    }\n\n    Bitmap bitmap = null;\n    if (!PreferenceUtils.isCameraLiveViewportEnabled(graphicOverlay.getContext())) {\n      bitmap = BitmapUtils.getBitmap(image);\n    }\n\n    if (isMlImageEnabled(graphicOverlay.getContext())) {\n      MlImage mlImage =\n          new MediaMlImageBuilder(image.getImage())\n              .setRotation(image.getImageInfo().getRotationDegrees())\n              .build();\n\n      requestDetectInImage(\n              mlImage,\n              graphicOverlay,\n              /* originalCameraImage= */ bitmap,\n              /* shouldShowFps= */ true,\n              frameStartMs)\n          // When the image is from CameraX analysis use case, must call image.close() on received\n          // images when finished using them. Otherwise, new images may not be received or the\n          // camera may stall.\n          // Currently MlImage doesn't support ImageProxy directly, so we still need to call\n          // ImageProxy.close() here.\n          .addOnCompleteListener(results -> image.close());\n      return;\n    }\n\n    requestDetectInImage(\n            InputImage.fromMediaImage(image.getImage(), image.getImageInfo().getRotationDegrees()),\n            graphicOverlay,\n            /* originalCameraImage= */ bitmap,\n            /* shouldShowFps= */ true,\n            frameStartMs)\n        // When the image is from CameraX analysis use case, must call image.close() on received\n        // images when finished using them. Otherwise, new images may not be received or the camera\n        // may stall.\n        .addOnCompleteListener(results -> image.close());\n  }\n\n  // -----------------Common processing logic-------------------------------------------------------\n  private Task<T> requestDetectInImage(\n      final InputImage image,\n      final GraphicOverlay graphicOverlay,\n      @Nullable final Bitmap originalCameraImage,\n      boolean shouldShowFps,\n      long frameStartMs) {\n    return setUpListener(\n        detectInImage(image), graphicOverlay, originalCameraImage, shouldShowFps, frameStartMs);\n  }\n\n  private Task<T> requestDetectInImage(\n      final MlImage image,\n      final GraphicOverlay graphicOverlay,\n      @Nullable final Bitmap originalCameraImage,\n      boolean shouldShowFps,\n      long frameStartMs) {\n    return setUpListener(\n        detectInImage(image), graphicOverlay, originalCameraImage, shouldShowFps, frameStartMs);\n  }\n\n  private Task<T> setUpListener(\n      Task<T> task,\n      final GraphicOverlay graphicOverlay,\n      @Nullable final Bitmap originalCameraImage,\n      boolean shouldShowFps,\n      long frameStartMs) {\n    final long detectorStartMs = SystemClock.elapsedRealtime();\n    return task.addOnSuccessListener(\n            executor,\n            results -> {\n              long endMs = SystemClock.elapsedRealtime();\n              long currentFrameLatencyMs = endMs - frameStartMs;\n              long currentDetectorLatencyMs = endMs - detectorStartMs;\n              if (numRuns >= 500) {\n                resetLatencyStats();\n              }\n              numRuns++;\n              frameProcessedInOneSecondInterval++;\n              totalFrameMs += currentFrameLatencyMs;\n              maxFrameMs = max(currentFrameLatencyMs, maxFrameMs);\n              minFrameMs = min(currentFrameLatencyMs, minFrameMs);\n              totalDetectorMs += currentDetectorLatencyMs;\n              maxDetectorMs = max(currentDetectorLatencyMs, maxDetectorMs);\n              minDetectorMs = min(currentDetectorLatencyMs, minDetectorMs);\n\n              // Only log inference info once per second. When frameProcessedInOneSecondInterval is\n              // equal to 1, it means this is the first frame processed during the current second.\n              if (frameProcessedInOneSecondInterval == 1) {\n                Log.d(TAG, \"Num of Runs: \" + numRuns);\n                Log.d(\n                    TAG,\n                    \"Frame latency: max=\"\n                        + maxFrameMs\n                        + \", min=\"\n                        + minFrameMs\n                        + \", avg=\"\n                        + totalFrameMs / numRuns);\n                Log.d(\n                    TAG,\n                    \"Detector latency: max=\"\n                        + maxDetectorMs\n                        + \", min=\"\n                        + minDetectorMs\n                        + \", avg=\"\n                        + totalDetectorMs / numRuns);\n                MemoryInfo mi = new MemoryInfo();\n                activityManager.getMemoryInfo(mi);\n                long availableMegs = mi.availMem / 0x100000L;\n                Log.d(TAG, \"Memory available in system: \" + availableMegs + \" MB\");\n                temperatureMonitor.logTemperature();\n              }\n\n              graphicOverlay.clear();\n              if (originalCameraImage != null) {\n                graphicOverlay.add(new CameraImageGraphic(graphicOverlay, originalCameraImage));\n              }\n              VisionProcessorBase.this.onSuccess(results, graphicOverlay);\n              if (!PreferenceUtils.shouldHideDetectionInfo(graphicOverlay.getContext())) {\n                graphicOverlay.add(\n                    new InferenceInfoGraphic(\n                        graphicOverlay,\n                        currentFrameLatencyMs,\n                        currentDetectorLatencyMs,\n                        shouldShowFps ? framesPerSecond : null));\n              }\n              graphicOverlay.postInvalidate();\n            })\n        .addOnFailureListener(\n            executor,\n            e -> {\n              graphicOverlay.clear();\n              graphicOverlay.postInvalidate();\n              String error = \"Failed to process. Error: \" + e.getLocalizedMessage();\n              Toast.makeText(\n                      graphicOverlay.getContext(),\n                      error + \"\\nCause: \" + e.getCause(),\n                      Toast.LENGTH_SHORT)\n                  .show();\n              Log.d(TAG, error);\n              e.printStackTrace();\n              VisionProcessorBase.this.onFailure(e);\n            });\n  }\n\n  @Override\n  public void stop() {\n    executor.shutdown();\n    isShutdown = true;\n    resetLatencyStats();\n    fpsTimer.cancel();\n    temperatureMonitor.stop();\n  }\n\n  private void resetLatencyStats() {\n    numRuns = 0;\n    totalFrameMs = 0;\n    maxFrameMs = 0;\n    minFrameMs = Long.MAX_VALUE;\n    totalDetectorMs = 0;\n    maxDetectorMs = 0;\n    minDetectorMs = Long.MAX_VALUE;\n  }\n\n  protected abstract Task<T> detectInImage(InputImage image);\n\n  protected Task<T> detectInImage(MlImage image) {\n    return Tasks.forException(\n        new MlKitException(\n            \"MlImage is currently not demonstrated for this feature\",\n            MlKitException.INVALID_ARGUMENT));\n  }\n\n  protected abstract void onSuccess(@NonNull T results, @NonNull GraphicOverlay graphicOverlay);\n\n  protected abstract void onFailure(@NonNull Exception e);\n\n  protected boolean isMlImageEnabled(Context context) {\n    return false;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/barcodescanner/BarcodeGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.barcodescanner;\n\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport com.google.mlkit.vision.barcode.common.Barcode;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\n\n/** Graphic instance for rendering Barcode position and content information in an overlay view. */\npublic class BarcodeGraphic extends Graphic {\n\n  private static final int TEXT_COLOR = Color.BLACK;\n  private static final int MARKER_COLOR = Color.WHITE;\n  private static final float TEXT_SIZE = 54.0f;\n  private static final float STROKE_WIDTH = 4.0f;\n\n  private final Paint rectPaint;\n  private final Paint barcodePaint;\n  private final Barcode barcode;\n  private final Paint labelPaint;\n\n  BarcodeGraphic(GraphicOverlay overlay, Barcode barcode) {\n    super(overlay);\n\n    this.barcode = barcode;\n\n    rectPaint = new Paint();\n    rectPaint.setColor(MARKER_COLOR);\n    rectPaint.setStyle(Paint.Style.STROKE);\n    rectPaint.setStrokeWidth(STROKE_WIDTH);\n\n    barcodePaint = new Paint();\n    barcodePaint.setColor(TEXT_COLOR);\n    barcodePaint.setTextSize(TEXT_SIZE);\n\n    labelPaint = new Paint();\n    labelPaint.setColor(MARKER_COLOR);\n    labelPaint.setStyle(Paint.Style.FILL);\n  }\n\n  /**\n   * Draws the barcode block annotations for position, size, and raw value on the supplied canvas.\n   */\n  @Override\n  public void draw(Canvas canvas) {\n    if (barcode == null) {\n      throw new IllegalStateException(\"Attempting to draw a null barcode.\");\n    }\n\n    // Draws the bounding box around the BarcodeBlock.\n    RectF rect = new RectF(barcode.getBoundingBox());\n    // If the image is flipped, the left will be translated to right, and the right to left.\n    float x0 = translateX(rect.left);\n    float x1 = translateX(rect.right);\n    rect.left = min(x0, x1);\n    rect.right = max(x0, x1);\n    rect.top = translateY(rect.top);\n    rect.bottom = translateY(rect.bottom);\n    canvas.drawRect(rect, rectPaint);\n\n    // Draws other object info.\n    float lineHeight = TEXT_SIZE + (2 * STROKE_WIDTH);\n    float textWidth = barcodePaint.measureText(barcode.getDisplayValue());\n    canvas.drawRect(\n        rect.left - STROKE_WIDTH,\n        rect.top - lineHeight,\n        rect.left + textWidth + (2 * STROKE_WIDTH),\n        rect.top,\n        labelPaint);\n    // Renders the barcode at the bottom of the box.\n    canvas.drawText(barcode.getDisplayValue(), rect.left, rect.top - STROKE_WIDTH, barcodePaint);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/barcodescanner/BarcodeScannerProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.barcodescanner;\n\nimport android.content.Context;\nimport android.graphics.Point;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.odml.image.MlImage;\nimport com.google.mlkit.vision.barcode.BarcodeScanner;\nimport com.google.mlkit.vision.barcode.BarcodeScannerOptions;\nimport com.google.mlkit.vision.barcode.BarcodeScanning;\nimport com.google.mlkit.vision.barcode.ZoomSuggestionOptions;\nimport com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback;\nimport com.google.mlkit.vision.barcode.common.Barcode;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport java.util.List;\n\n/** Barcode Detector Demo. */\npublic class BarcodeScannerProcessor extends VisionProcessorBase<List<Barcode>> {\n\n  private static final String TAG = \"BarcodeProcessor\";\n\n  private final BarcodeScanner barcodeScanner;\n\n  public BarcodeScannerProcessor(Context context, @Nullable ZoomCallback zoomCallback) {\n    super(context);\n    // Note that if you know which format of barcode your app is dealing with, detection will be\n    // faster to specify the supported barcode formats one by one, e.g.\n    // new BarcodeScannerOptions.Builder()\n    //     .setBarcodeFormats(Barcode.FORMAT_QR_CODE)\n    //     .build();\n    if (zoomCallback != null) {\n      BarcodeScannerOptions options =\n          new BarcodeScannerOptions.Builder()\n              .setZoomSuggestionOptions(new ZoomSuggestionOptions.Builder(zoomCallback).build())\n              .build();\n      barcodeScanner = BarcodeScanning.getClient(options);\n    } else {\n      barcodeScanner = BarcodeScanning.getClient();\n    }\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    barcodeScanner.close();\n  }\n\n  @Override\n  protected Task<List<Barcode>> detectInImage(InputImage image) {\n    return barcodeScanner.process(image);\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull List<Barcode> barcodes, @NonNull GraphicOverlay graphicOverlay) {\n    if (barcodes.isEmpty()) {\n      Log.v(MANUAL_TESTING_LOG, \"No barcode has been detected\");\n    }\n    for (int i = 0; i < barcodes.size(); ++i) {\n      Barcode barcode = barcodes.get(i);\n      graphicOverlay.add(new BarcodeGraphic(graphicOverlay, barcode));\n      logExtrasForTesting(barcode);\n    }\n  }\n\n  private static void logExtrasForTesting(Barcode barcode) {\n    if (barcode != null) {\n      if (barcode.getBoundingBox() != null) {\n        Log.v(\n            MANUAL_TESTING_LOG,\n            String.format(\n                \"Detected barcode's bounding box: %s\", barcode.getBoundingBox().flattenToString()));\n      }\n      if (barcode.getCornerPoints() != null) {\n        Log.v(\n            MANUAL_TESTING_LOG,\n            String.format(\n                \"Expected corner point size is 4, get %d\", barcode.getCornerPoints().length));\n      }\n      for (Point point : barcode.getCornerPoints()) {\n        Log.v(\n            MANUAL_TESTING_LOG,\n            String.format(\"Corner point is located at: x = %d, y = %d\", point.x, point.y));\n      }\n      Log.v(MANUAL_TESTING_LOG, \"barcode display value: \" + barcode.getDisplayValue());\n      Log.v(MANUAL_TESTING_LOG, \"barcode raw value: \" + barcode.getRawValue());\n      Barcode.DriverLicense dl = barcode.getDriverLicense();\n      if (dl != null) {\n        Log.v(MANUAL_TESTING_LOG, \"driver license city: \" + dl.getAddressCity());\n        Log.v(MANUAL_TESTING_LOG, \"driver license state: \" + dl.getAddressState());\n        Log.v(MANUAL_TESTING_LOG, \"driver license street: \" + dl.getAddressStreet());\n        Log.v(MANUAL_TESTING_LOG, \"driver license zip code: \" + dl.getAddressZip());\n        Log.v(MANUAL_TESTING_LOG, \"driver license birthday: \" + dl.getBirthDate());\n        Log.v(MANUAL_TESTING_LOG, \"driver license document type: \" + dl.getDocumentType());\n        Log.v(MANUAL_TESTING_LOG, \"driver license expiry date: \" + dl.getExpiryDate());\n        Log.v(MANUAL_TESTING_LOG, \"driver license first name: \" + dl.getFirstName());\n        Log.v(MANUAL_TESTING_LOG, \"driver license middle name: \" + dl.getMiddleName());\n        Log.v(MANUAL_TESTING_LOG, \"driver license last name: \" + dl.getLastName());\n        Log.v(MANUAL_TESTING_LOG, \"driver license gender: \" + dl.getGender());\n        Log.v(MANUAL_TESTING_LOG, \"driver license issue date: \" + dl.getIssueDate());\n        Log.v(MANUAL_TESTING_LOG, \"driver license issue country: \" + dl.getIssuingCountry());\n        Log.v(MANUAL_TESTING_LOG, \"driver license number: \" + dl.getLicenseNumber());\n      }\n    }\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.e(TAG, \"Barcode detection failed \" + e);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/facedetector/FaceDetectorProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.facedetector;\n\nimport android.content.Context;\nimport android.graphics.PointF;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.face.Face;\nimport com.google.mlkit.vision.face.FaceDetection;\nimport com.google.mlkit.vision.face.FaceDetector;\nimport com.google.mlkit.vision.face.FaceDetectorOptions;\nimport com.google.mlkit.vision.face.FaceLandmark;\nimport java.util.List;\nimport java.util.Locale;\n\n/** Face Detector Demo. */\npublic class FaceDetectorProcessor extends VisionProcessorBase<List<Face>> {\n\n  private static final String TAG = \"FaceDetectorProcessor\";\n\n  private final FaceDetector detector;\n\n  public FaceDetectorProcessor(Context context) {\n    super(context);\n    FaceDetectorOptions faceDetectorOptions = PreferenceUtils.getFaceDetectorOptions(context);\n    Log.v(MANUAL_TESTING_LOG, \"Face detector options: \" + faceDetectorOptions);\n    detector = FaceDetection.getClient(faceDetectorOptions);\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    detector.close();\n  }\n\n  @Override\n  protected Task<List<Face>> detectInImage(InputImage image) {\n    return detector.process(image);\n  }\n\n  @Override\n  protected void onSuccess(@NonNull List<Face> faces, @NonNull GraphicOverlay graphicOverlay) {\n    for (Face face : faces) {\n      graphicOverlay.add(new FaceGraphic(graphicOverlay, face));\n      logExtrasForTesting(face);\n    }\n  }\n\n  private static void logExtrasForTesting(Face face) {\n    if (face != null) {\n      Log.v(MANUAL_TESTING_LOG, \"face bounding box: \" + face.getBoundingBox().flattenToString());\n      Log.v(MANUAL_TESTING_LOG, \"face Euler Angle X: \" + face.getHeadEulerAngleX());\n      Log.v(MANUAL_TESTING_LOG, \"face Euler Angle Y: \" + face.getHeadEulerAngleY());\n      Log.v(MANUAL_TESTING_LOG, \"face Euler Angle Z: \" + face.getHeadEulerAngleZ());\n\n      // All landmarks\n      int[] landMarkTypes =\n          new int[] {\n            FaceLandmark.MOUTH_BOTTOM,\n            FaceLandmark.MOUTH_RIGHT,\n            FaceLandmark.MOUTH_LEFT,\n            FaceLandmark.RIGHT_EYE,\n            FaceLandmark.LEFT_EYE,\n            FaceLandmark.RIGHT_EAR,\n            FaceLandmark.LEFT_EAR,\n            FaceLandmark.RIGHT_CHEEK,\n            FaceLandmark.LEFT_CHEEK,\n            FaceLandmark.NOSE_BASE\n          };\n      String[] landMarkTypesStrings =\n          new String[] {\n            \"MOUTH_BOTTOM\",\n            \"MOUTH_RIGHT\",\n            \"MOUTH_LEFT\",\n            \"RIGHT_EYE\",\n            \"LEFT_EYE\",\n            \"RIGHT_EAR\",\n            \"LEFT_EAR\",\n            \"RIGHT_CHEEK\",\n            \"LEFT_CHEEK\",\n            \"NOSE_BASE\"\n          };\n      for (int i = 0; i < landMarkTypes.length; i++) {\n        FaceLandmark landmark = face.getLandmark(landMarkTypes[i]);\n        if (landmark == null) {\n          Log.v(\n              MANUAL_TESTING_LOG,\n              \"No landmark of type: \" + landMarkTypesStrings[i] + \" has been detected\");\n        } else {\n          PointF landmarkPosition = landmark.getPosition();\n          String landmarkPositionStr =\n              String.format(Locale.US, \"x: %f , y: %f\", landmarkPosition.x, landmarkPosition.y);\n          Log.v(\n              MANUAL_TESTING_LOG,\n              \"Position for face landmark: \"\n                  + landMarkTypesStrings[i]\n                  + \" is :\"\n                  + landmarkPositionStr);\n        }\n      }\n      Log.v(\n          MANUAL_TESTING_LOG,\n          \"face left eye open probability: \" + face.getLeftEyeOpenProbability());\n      Log.v(\n          MANUAL_TESTING_LOG,\n          \"face right eye open probability: \" + face.getRightEyeOpenProbability());\n      Log.v(MANUAL_TESTING_LOG, \"face smiling probability: \" + face.getSmilingProbability());\n      Log.v(MANUAL_TESTING_LOG, \"face tracking id: \" + face.getTrackingId());\n    }\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.e(TAG, \"Face detection failed \" + e);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/facedetector/FaceGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.facedetector;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.PointF;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.face.Face;\nimport com.google.mlkit.vision.face.FaceContour;\nimport com.google.mlkit.vision.face.FaceLandmark;\nimport com.google.mlkit.vision.face.FaceLandmark.LandmarkType;\nimport java.util.Locale;\n\n/**\n * Graphic instance for rendering face position, contour, and landmarks within the associated\n * graphic overlay view.\n */\npublic class FaceGraphic extends Graphic {\n  private static final float FACE_POSITION_RADIUS = 8.0f;\n  private static final float ID_TEXT_SIZE = 30.0f;\n  private static final float ID_Y_OFFSET = 40.0f;\n  private static final float BOX_STROKE_WIDTH = 5.0f;\n  private static final int NUM_COLORS = 10;\n  private static final int[][] COLORS =\n      new int[][] {\n        // {Text color, background color}\n        {Color.BLACK, Color.WHITE},\n        {Color.WHITE, Color.MAGENTA},\n        {Color.BLACK, Color.LTGRAY},\n        {Color.WHITE, Color.RED},\n        {Color.WHITE, Color.BLUE},\n        {Color.WHITE, Color.DKGRAY},\n        {Color.BLACK, Color.CYAN},\n        {Color.BLACK, Color.YELLOW},\n        {Color.WHITE, Color.BLACK},\n        {Color.BLACK, Color.GREEN}\n      };\n\n  private final Paint facePositionPaint;\n  private final Paint[] idPaints;\n  private final Paint[] boxPaints;\n  private final Paint[] labelPaints;\n\n  private volatile Face face;\n\n  FaceGraphic(GraphicOverlay overlay, Face face) {\n    super(overlay);\n\n    this.face = face;\n    final int selectedColor = Color.WHITE;\n\n    facePositionPaint = new Paint();\n    facePositionPaint.setColor(selectedColor);\n\n    int numColors = COLORS.length;\n    idPaints = new Paint[numColors];\n    boxPaints = new Paint[numColors];\n    labelPaints = new Paint[numColors];\n    for (int i = 0; i < numColors; i++) {\n      idPaints[i] = new Paint();\n      idPaints[i].setColor(COLORS[i][0] /* text color */);\n      idPaints[i].setTextSize(ID_TEXT_SIZE);\n\n      boxPaints[i] = new Paint();\n      boxPaints[i].setColor(COLORS[i][1] /* background color */);\n      boxPaints[i].setStyle(Paint.Style.STROKE);\n      boxPaints[i].setStrokeWidth(BOX_STROKE_WIDTH);\n\n      labelPaints[i] = new Paint();\n      labelPaints[i].setColor(COLORS[i][1] /* background color */);\n      labelPaints[i].setStyle(Paint.Style.FILL);\n    }\n  }\n\n  /** Draws the face annotations for position on the supplied canvas. */\n  @Override\n  public void draw(Canvas canvas) {\n    Face face = this.face;\n    if (face == null) {\n      return;\n    }\n\n    // Draws a circle at the position of the detected face, with the face's track id below.\n    float x = translateX(face.getBoundingBox().centerX());\n    float y = translateY(face.getBoundingBox().centerY());\n    canvas.drawCircle(x, y, FACE_POSITION_RADIUS, facePositionPaint);\n\n    // Calculate positions.\n    float left = x - scale(face.getBoundingBox().width() / 2.0f);\n    float top = y - scale(face.getBoundingBox().height() / 2.0f);\n    float right = x + scale(face.getBoundingBox().width() / 2.0f);\n    float bottom = y + scale(face.getBoundingBox().height() / 2.0f);\n    float lineHeight = ID_TEXT_SIZE + BOX_STROKE_WIDTH;\n    float yLabelOffset = (face.getTrackingId() == null) ? 0 : -lineHeight;\n\n    // Decide color based on face ID\n    int colorID = (face.getTrackingId() == null) ? 0 : Math.abs(face.getTrackingId() % NUM_COLORS);\n\n    // Calculate width and height of label box\n    float textWidth = idPaints[colorID].measureText(\"ID: \" + face.getTrackingId());\n    if (face.getSmilingProbability() != null) {\n      yLabelOffset -= lineHeight;\n      textWidth =\n          Math.max(\n              textWidth,\n              idPaints[colorID].measureText(\n                  String.format(Locale.US, \"Happiness: %.2f\", face.getSmilingProbability())));\n    }\n    if (face.getLeftEyeOpenProbability() != null) {\n      yLabelOffset -= lineHeight;\n      textWidth =\n          Math.max(\n              textWidth,\n              idPaints[colorID].measureText(\n                  String.format(\n                      Locale.US, \"Left eye open: %.2f\", face.getLeftEyeOpenProbability())));\n    }\n    if (face.getRightEyeOpenProbability() != null) {\n      yLabelOffset -= lineHeight;\n      textWidth =\n          Math.max(\n              textWidth,\n              idPaints[colorID].measureText(\n                  String.format(\n                      Locale.US, \"Right eye open: %.2f\", face.getRightEyeOpenProbability())));\n    }\n\n    yLabelOffset = yLabelOffset - 3 * lineHeight;\n    textWidth =\n        Math.max(\n            textWidth,\n            idPaints[colorID].measureText(\n                String.format(Locale.US, \"EulerX: %.2f\", face.getHeadEulerAngleX())));\n    textWidth =\n        Math.max(\n            textWidth,\n            idPaints[colorID].measureText(\n                String.format(Locale.US, \"EulerY: %.2f\", face.getHeadEulerAngleY())));\n    textWidth =\n        Math.max(\n            textWidth,\n            idPaints[colorID].measureText(\n                String.format(Locale.US, \"EulerZ: %.2f\", face.getHeadEulerAngleZ())));\n    // Draw labels\n    canvas.drawRect(\n        left - BOX_STROKE_WIDTH,\n        top + yLabelOffset,\n        left + textWidth + (2 * BOX_STROKE_WIDTH),\n        top,\n        labelPaints[colorID]);\n    yLabelOffset += ID_TEXT_SIZE;\n    canvas.drawRect(left, top, right, bottom, boxPaints[colorID]);\n    if (face.getTrackingId() != null) {\n      canvas.drawText(\"ID: \" + face.getTrackingId(), left, top + yLabelOffset, idPaints[colorID]);\n      yLabelOffset += lineHeight;\n    }\n\n    // Draws all face contours.\n    for (FaceContour contour : face.getAllContours()) {\n      for (PointF point : contour.getPoints()) {\n        canvas.drawCircle(\n            translateX(point.x), translateY(point.y), FACE_POSITION_RADIUS, facePositionPaint);\n      }\n    }\n\n    // Draws smiling and left/right eye open probabilities.\n    if (face.getSmilingProbability() != null) {\n      canvas.drawText(\n          \"Smiling: \" + String.format(Locale.US, \"%.2f\", face.getSmilingProbability()),\n          left,\n          top + yLabelOffset,\n          idPaints[colorID]);\n      yLabelOffset += lineHeight;\n    }\n\n    FaceLandmark leftEye = face.getLandmark(FaceLandmark.LEFT_EYE);\n    if (face.getLeftEyeOpenProbability() != null) {\n      canvas.drawText(\n          \"Left eye open: \" + String.format(Locale.US, \"%.2f\", face.getLeftEyeOpenProbability()),\n          left,\n          top + yLabelOffset,\n          idPaints[colorID]);\n      yLabelOffset += lineHeight;\n    }\n    if (leftEye != null) {\n      float leftEyeLeft =\n          translateX(leftEye.getPosition().x) - idPaints[colorID].measureText(\"Left Eye\") / 2.0f;\n      canvas.drawRect(\n          leftEyeLeft - BOX_STROKE_WIDTH,\n          translateY(leftEye.getPosition().y) + ID_Y_OFFSET - ID_TEXT_SIZE,\n          leftEyeLeft + idPaints[colorID].measureText(\"Left Eye\") + BOX_STROKE_WIDTH,\n          translateY(leftEye.getPosition().y) + ID_Y_OFFSET + BOX_STROKE_WIDTH,\n          labelPaints[colorID]);\n      canvas.drawText(\n          \"Left Eye\",\n          leftEyeLeft,\n          translateY(leftEye.getPosition().y) + ID_Y_OFFSET,\n          idPaints[colorID]);\n    }\n\n    FaceLandmark rightEye = face.getLandmark(FaceLandmark.RIGHT_EYE);\n    if (face.getRightEyeOpenProbability() != null) {\n      canvas.drawText(\n          \"Right eye open: \" + String.format(Locale.US, \"%.2f\", face.getRightEyeOpenProbability()),\n          left,\n          top + yLabelOffset,\n          idPaints[colorID]);\n      yLabelOffset += lineHeight;\n    }\n    if (rightEye != null) {\n      float rightEyeLeft =\n          translateX(rightEye.getPosition().x) - idPaints[colorID].measureText(\"Right Eye\") / 2.0f;\n      canvas.drawRect(\n          rightEyeLeft - BOX_STROKE_WIDTH,\n          translateY(rightEye.getPosition().y) + ID_Y_OFFSET - ID_TEXT_SIZE,\n          rightEyeLeft + idPaints[colorID].measureText(\"Right Eye\") + BOX_STROKE_WIDTH,\n          translateY(rightEye.getPosition().y) + ID_Y_OFFSET + BOX_STROKE_WIDTH,\n          labelPaints[colorID]);\n      canvas.drawText(\n          \"Right Eye\",\n          rightEyeLeft,\n          translateY(rightEye.getPosition().y) + ID_Y_OFFSET,\n          idPaints[colorID]);\n    }\n\n    canvas.drawText(\n        \"EulerX: \" + face.getHeadEulerAngleX(), left, top + yLabelOffset, idPaints[colorID]);\n    yLabelOffset += lineHeight;\n    canvas.drawText(\n        \"EulerY: \" + face.getHeadEulerAngleY(), left, top + yLabelOffset, idPaints[colorID]);\n    yLabelOffset += lineHeight;\n    canvas.drawText(\n        \"EulerZ: \" + face.getHeadEulerAngleZ(), left, top + yLabelOffset, idPaints[colorID]);\n\n    // Draw facial landmarks\n    drawFaceLandmark(canvas, FaceLandmark.LEFT_EYE);\n    drawFaceLandmark(canvas, FaceLandmark.RIGHT_EYE);\n    drawFaceLandmark(canvas, FaceLandmark.LEFT_CHEEK);\n    drawFaceLandmark(canvas, FaceLandmark.RIGHT_CHEEK);\n  }\n\n  private void drawFaceLandmark(Canvas canvas, @LandmarkType int landmarkType) {\n    FaceLandmark faceLandmark = face.getLandmark(landmarkType);\n    if (faceLandmark != null) {\n      canvas.drawCircle(\n          translateX(faceLandmark.getPosition().x),\n          translateY(faceLandmark.getPosition().y),\n          FACE_POSITION_RADIUS,\n          facePositionPaint);\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/facemeshdetector/FaceMeshDetectorProcessor.java",
    "content": "/*\n * Copyright 2022 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.facemeshdetector;\n\nimport android.content.Context;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.odml.image.MlImage;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.facemesh.FaceMesh;\nimport com.google.mlkit.vision.facemesh.FaceMeshDetection;\nimport com.google.mlkit.vision.facemesh.FaceMeshDetector;\nimport com.google.mlkit.vision.facemesh.FaceMeshDetectorOptions;\nimport java.util.List;\n\n/** Selfie Face Detector Demo. */\npublic class FaceMeshDetectorProcessor extends VisionProcessorBase<List<FaceMesh>> {\n\n  private static final String TAG = \"SelfieFaceProcessor\";\n\n  private final FaceMeshDetector detector;\n\n  public FaceMeshDetectorProcessor(Context context) {\n    super(context);\n    FaceMeshDetectorOptions.Builder optionsBuilder = new FaceMeshDetectorOptions.Builder();\n    if (PreferenceUtils.getFaceMeshUseCase(context) == FaceMeshDetectorOptions.BOUNDING_BOX_ONLY) {\n      optionsBuilder.setUseCase(FaceMeshDetectorOptions.BOUNDING_BOX_ONLY);\n    }\n\n    detector = FaceMeshDetection.getClient(optionsBuilder.build());\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    detector.close();\n  }\n\n  @Override\n  protected Task<List<FaceMesh>> detectInImage(InputImage image) {\n    return detector.process(image);\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull List<FaceMesh> faces, @NonNull GraphicOverlay graphicOverlay) {\n    for (FaceMesh face : faces) {\n      graphicOverlay.add(new FaceMeshGraphic(graphicOverlay, face));\n    }\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.e(TAG, \"Face detection failed \" + e);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/facemeshdetector/FaceMeshGraphic.java",
    "content": "/*\n * Copyright 2022 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.facemeshdetector;\n\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Style;\nimport android.graphics.RectF;\nimport com.google.mlkit.vision.common.PointF3D;\nimport com.google.mlkit.vision.common.Triangle;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.facemesh.FaceMesh;\nimport com.google.mlkit.vision.facemesh.FaceMesh.ContourType;\nimport com.google.mlkit.vision.facemesh.FaceMeshDetectorOptions;\nimport com.google.mlkit.vision.facemesh.FaceMeshPoint;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Graphic instance for rendering face position and mesh info within the associated graphic overlay\n * view.\n */\npublic class FaceMeshGraphic extends Graphic {\n  private static final int USE_CASE_CONTOUR_ONLY = 999;\n\n  private static final float FACE_POSITION_RADIUS = 8.0f;\n  private static final float BOX_STROKE_WIDTH = 5.0f;\n\n  private final Paint positionPaint;\n  private final Paint boxPaint;\n  private volatile FaceMesh faceMesh;\n  private final int useCase;\n  private float zMin;\n  private float zMax;\n\n  @ContourType\n  private static final int[] DISPLAY_CONTOURS = {\n    FaceMesh.FACE_OVAL,\n    FaceMesh.LEFT_EYEBROW_TOP,\n    FaceMesh.LEFT_EYEBROW_BOTTOM,\n    FaceMesh.RIGHT_EYEBROW_TOP,\n    FaceMesh.RIGHT_EYEBROW_BOTTOM,\n    FaceMesh.LEFT_EYE,\n    FaceMesh.RIGHT_EYE,\n    FaceMesh.UPPER_LIP_TOP,\n    FaceMesh.UPPER_LIP_BOTTOM,\n    FaceMesh.LOWER_LIP_TOP,\n    FaceMesh.LOWER_LIP_BOTTOM,\n    FaceMesh.NOSE_BRIDGE\n  };\n\n  FaceMeshGraphic(GraphicOverlay overlay, FaceMesh faceMesh) {\n    super(overlay);\n\n    this.faceMesh = faceMesh;\n    final int selectedColor = Color.WHITE;\n\n    positionPaint = new Paint();\n    positionPaint.setColor(selectedColor);\n\n    boxPaint = new Paint();\n    boxPaint.setColor(selectedColor);\n    boxPaint.setStyle(Style.STROKE);\n    boxPaint.setStrokeWidth(BOX_STROKE_WIDTH);\n\n    useCase = PreferenceUtils.getFaceMeshUseCase(getApplicationContext());\n  }\n\n  /** Draws the face annotations for position on the supplied canvas. */\n  @Override\n  public void draw(Canvas canvas) {\n    if (faceMesh == null) {\n      return;\n    }\n\n    // Draws the bounding box.\n    RectF rect = new RectF(faceMesh.getBoundingBox());\n    // If the image is flipped, the left will be translated to right, and the right to left.\n    float x0 = translateX(rect.left);\n    float x1 = translateX(rect.right);\n    rect.left = min(x0, x1);\n    rect.right = max(x0, x1);\n    rect.top = translateY(rect.top);\n    rect.bottom = translateY(rect.bottom);\n    canvas.drawRect(rect, boxPaint);\n\n    // Draw face mesh\n    List<FaceMeshPoint> points =\n        useCase == USE_CASE_CONTOUR_ONLY ? getContourPoints(faceMesh) : faceMesh.getAllPoints();\n    List<Triangle<FaceMeshPoint>> triangles = faceMesh.getAllTriangles();\n\n    zMin = Float.MAX_VALUE;\n    zMax = Float.MIN_VALUE;\n    for (FaceMeshPoint point : points) {\n      zMin = min(zMin, point.getPosition().getZ());\n      zMax = max(zMax, point.getPosition().getZ());\n    }\n\n    // Draw face mesh points\n    for (FaceMeshPoint point : points) {\n      updatePaintColorByZValue(\n          positionPaint,\n          canvas,\n          /* visualizeZ= */ true,\n          /* rescaleZForVisualization= */ true,\n          point.getPosition().getZ(),\n          zMin,\n          zMax);\n      canvas.drawCircle(\n          translateX(point.getPosition().getX()),\n          translateY(point.getPosition().getY()),\n          FACE_POSITION_RADIUS,\n          positionPaint);\n    }\n\n    if (useCase == FaceMeshDetectorOptions.FACE_MESH) {\n      // Draw face mesh triangles\n      for (Triangle<FaceMeshPoint> triangle : triangles) {\n        List<FaceMeshPoint> faceMeshPoints = triangle.getAllPoints();\n        PointF3D point1 = faceMeshPoints.get(0).getPosition();\n        PointF3D point2 = faceMeshPoints.get(1).getPosition();\n        PointF3D point3 = faceMeshPoints.get(2).getPosition();\n\n        drawLine(canvas, point1, point2);\n        drawLine(canvas, point2, point3);\n        drawLine(canvas, point3, point1);\n      }\n    }\n  }\n\n  private List<FaceMeshPoint> getContourPoints(FaceMesh faceMesh) {\n    List<FaceMeshPoint> contourPoints = new ArrayList<>();\n    for (int type : DISPLAY_CONTOURS) {\n      contourPoints.addAll(faceMesh.getPoints(type));\n    }\n    return contourPoints;\n  }\n\n  private void drawLine(Canvas canvas, PointF3D point1, PointF3D point2) {\n    updatePaintColorByZValue(\n        positionPaint,\n        canvas,\n        /* visualizeZ= */ true,\n        /* rescaleZForVisualization= */ true,\n        (point1.getZ() + point2.getZ()) / 2,\n        zMin,\n        zMax);\n    canvas.drawLine(\n        translateX(point1.getX()),\n        translateY(point1.getY()),\n        translateX(point2.getX()),\n        translateY(point2.getY()),\n        positionPaint);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/labeldetector/LabelDetectorProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.labeldetector;\n\nimport android.content.Context;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport com.google.mlkit.vision.label.ImageLabel;\nimport com.google.mlkit.vision.label.ImageLabeler;\nimport com.google.mlkit.vision.label.ImageLabelerOptionsBase;\nimport com.google.mlkit.vision.label.ImageLabeling;\nimport java.util.List;\n\n/** Custom InputImage Classifier Demo. */\npublic class LabelDetectorProcessor extends VisionProcessorBase<List<ImageLabel>> {\n\n  private static final String TAG = \"LabelDetectorProcessor\";\n\n  private final ImageLabeler imageLabeler;\n\n  public LabelDetectorProcessor(Context context, ImageLabelerOptionsBase options) {\n    super(context);\n    imageLabeler = ImageLabeling.getClient(options);\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    imageLabeler.close();\n  }\n\n  @Override\n  protected Task<List<ImageLabel>> detectInImage(InputImage image) {\n    return imageLabeler.process(image);\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull List<ImageLabel> labels, @NonNull GraphicOverlay graphicOverlay) {\n    graphicOverlay.add(new LabelGraphic(graphicOverlay, labels));\n    logExtrasForTesting(labels);\n  }\n\n  private static void logExtrasForTesting(List<ImageLabel> labels) {\n    if (labels == null) {\n      Log.v(MANUAL_TESTING_LOG, \"No labels detected\");\n    } else {\n      for (ImageLabel label : labels) {\n        Log.v(\n            MANUAL_TESTING_LOG,\n            String.format(\"Label %s, confidence %f\", label.getText(), label.getConfidence()));\n      }\n    }\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.w(TAG, \"Label detection failed.\" + e);\n  }\n}\n\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/labeldetector/LabelGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.labeldetector;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport com.google.common.primitives.Floats;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.label.ImageLabel;\nimport java.util.List;\nimport java.util.Locale;\n\n/** Graphic instance for rendering a label within an associated graphic overlay view. */\npublic class LabelGraphic extends GraphicOverlay.Graphic {\n\n  private static final float TEXT_SIZE = 70.0f;\n  private static final String LABEL_FORMAT = \"%.2f%% confidence (index: %d)\";\n\n  private final Paint textPaint;\n  private final Paint labelPaint;\n  private final GraphicOverlay overlay;\n\n  private final List<ImageLabel> labels;\n\n  public LabelGraphic(GraphicOverlay overlay, List<ImageLabel> labels) {\n    super(overlay);\n    this.overlay = overlay;\n    this.labels = labels;\n    textPaint = new Paint();\n    textPaint.setColor(Color.WHITE);\n    textPaint.setTextSize(TEXT_SIZE);\n\n    labelPaint = new Paint();\n    labelPaint.setColor(Color.BLACK);\n    labelPaint.setStyle(Paint.Style.FILL);\n    labelPaint.setAlpha(200);\n  }\n\n  @Override\n  public synchronized void draw(Canvas canvas) {\n    // First try to find maxWidth and totalHeight in order to draw to the center of the screen.\n    float maxWidth = 0;\n    float totalHeight = labels.size() * 2 * TEXT_SIZE;\n    for (ImageLabel label : labels) {\n      float line1Width = textPaint.measureText(label.getText());\n      float line2Width =\n          textPaint.measureText(\n              String.format(\n                  Locale.US, LABEL_FORMAT, label.getConfidence() * 100, label.getIndex()));\n      maxWidth = Floats.max(maxWidth, line1Width, line2Width);\n    }\n    float x = Math.max(0, overlay.getWidth() / 2.0f - maxWidth / 2.0f);\n    float y = Math.max(200, overlay.getHeight() / 2.0f - totalHeight / 2.0f);\n\n    if (!labels.isEmpty()) {\n      float padding = 20;\n      drawRect(\n          canvas,\n          x - padding,\n          y - padding,\n          x + maxWidth + padding,\n          y + totalHeight + padding,\n          labelPaint);\n    }\n\n    for (ImageLabel label : labels) {\n      if (y + TEXT_SIZE * 2 > overlay.getHeight()) {\n        break;\n      }\n      drawText(canvas, label.getText(), x, y + TEXT_SIZE, textPaint);\n      y += TEXT_SIZE;\n      drawText(\n          canvas,\n          String.format(Locale.US, LABEL_FORMAT, label.getConfidence() * 100, label.getIndex()),\n          x,\n          y + TEXT_SIZE,\n          textPaint);\n      y += TEXT_SIZE;\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/objectdetector/ObjectDetectorProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.objectdetector;\n\nimport android.content.Context;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport com.google.mlkit.vision.objects.DetectedObject;\nimport com.google.mlkit.vision.objects.ObjectDetection;\nimport com.google.mlkit.vision.objects.ObjectDetector;\nimport com.google.mlkit.vision.objects.ObjectDetectorOptionsBase;\nimport java.util.List;\n\n/** A processor to run object detector. */\npublic class ObjectDetectorProcessor extends VisionProcessorBase<List<DetectedObject>> {\n\n  private static final String TAG = \"ObjectDetectorProcessor\";\n\n  private final ObjectDetector detector;\n\n  public ObjectDetectorProcessor(Context context, ObjectDetectorOptionsBase options) {\n    super(context);\n    detector = ObjectDetection.getClient(options);\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    detector.close();\n  }\n\n  @Override\n  protected Task<List<DetectedObject>> detectInImage(InputImage image) {\n    return detector.process(image);\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull List<DetectedObject> results, @NonNull GraphicOverlay graphicOverlay) {\n    for (DetectedObject object : results) {\n      graphicOverlay.add(new ObjectGraphic(graphicOverlay, object));\n    }\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.e(TAG, \"Object detection failed!\", e);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/objectdetector/ObjectGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.objectdetector;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.objects.DetectedObject;\nimport com.google.mlkit.vision.objects.DetectedObject.Label;\nimport java.util.Locale;\n\n/** Draw the detected object info in preview. */\npublic class ObjectGraphic extends Graphic {\n\n  private static final float TEXT_SIZE = 54.0f;\n  private static final float STROKE_WIDTH = 4.0f;\n  private static final int NUM_COLORS = 10;\n  private static final int[][] COLORS =\n      new int[][] {\n        // {Text color, background color}\n        {Color.BLACK, Color.WHITE},\n        {Color.WHITE, Color.MAGENTA},\n        {Color.BLACK, Color.LTGRAY},\n        {Color.WHITE, Color.RED},\n        {Color.WHITE, Color.BLUE},\n        {Color.WHITE, Color.DKGRAY},\n        {Color.BLACK, Color.CYAN},\n        {Color.BLACK, Color.YELLOW},\n        {Color.WHITE, Color.BLACK},\n        {Color.BLACK, Color.GREEN}\n      };\n  private static final String LABEL_FORMAT = \"%.2f%% confidence (index: %d)\";\n\n  private final DetectedObject object;\n  private final Paint[] boxPaints;\n  private final Paint[] textPaints;\n  private final Paint[] labelPaints;\n\n  public ObjectGraphic(GraphicOverlay overlay, DetectedObject object) {\n    super(overlay);\n\n    this.object = object;\n\n    int numColors = COLORS.length;\n    textPaints = new Paint[numColors];\n    boxPaints = new Paint[numColors];\n    labelPaints = new Paint[numColors];\n    for (int i = 0; i < numColors; i++) {\n      textPaints[i] = new Paint();\n      textPaints[i].setColor(COLORS[i][0] /* text color */);\n      textPaints[i].setTextSize(TEXT_SIZE);\n\n      boxPaints[i] = new Paint();\n      boxPaints[i].setColor(COLORS[i][1] /* background color */);\n      boxPaints[i].setStyle(Paint.Style.STROKE);\n      boxPaints[i].setStrokeWidth(STROKE_WIDTH);\n\n      labelPaints[i] = new Paint();\n      labelPaints[i].setColor(COLORS[i][1] /* background color */);\n      labelPaints[i].setStyle(Paint.Style.FILL);\n    }\n  }\n\n  @Override\n  public void draw(Canvas canvas) {\n    // Decide color based on object tracking ID\n    int colorID =\n        object.getTrackingId() == null ? 0 : Math.abs(object.getTrackingId() % NUM_COLORS);\n    float textWidth = textPaints[colorID].measureText(\"Tracking ID: \" + object.getTrackingId());\n    float lineHeight = TEXT_SIZE + STROKE_WIDTH;\n    float yLabelOffset = -lineHeight;\n\n    // Calculate width and height of label box\n    for (Label label : object.getLabels()) {\n      textWidth = Math.max(textWidth, textPaints[colorID].measureText(label.getText()));\n      textWidth =\n          Math.max(\n              textWidth,\n              textPaints[colorID].measureText(\n                  String.format(\n                      Locale.US, LABEL_FORMAT, label.getConfidence() * 100, label.getIndex())));\n      yLabelOffset -= 2 * lineHeight;\n    }\n\n    // Draws the bounding box.\n    RectF rect = new RectF(object.getBoundingBox());\n    // If the image is flipped, the left will be translated to right, and the right to left.\n    float x0 = translateX(rect.left);\n    float x1 = translateX(rect.right);\n    rect.left = Math.min(x0, x1);\n    rect.right = Math.max(x0, x1);\n    rect.top = translateY(rect.top);\n    rect.bottom = translateY(rect.bottom);\n    canvas.drawRect(rect, boxPaints[colorID]);\n\n    // Draws other object info.\n    canvas.drawRect(\n        rect.left - STROKE_WIDTH,\n        rect.top + yLabelOffset,\n        rect.left + textWidth + (2 * STROKE_WIDTH),\n        rect.top,\n        labelPaints[colorID]);\n    yLabelOffset += TEXT_SIZE;\n    canvas.drawText(\n        \"Tracking ID: \" + object.getTrackingId(),\n        rect.left,\n        rect.top + yLabelOffset,\n        textPaints[colorID]);\n    yLabelOffset += lineHeight;\n\n    for (Label label : object.getLabels()) {\n      canvas.drawText(label.getText(), rect.left, rect.top + yLabelOffset, textPaints[colorID]);\n      yLabelOffset += lineHeight;\n      canvas.drawText(\n          String.format(Locale.US, LABEL_FORMAT, label.getConfidence() * 100, label.getIndex()),\n          rect.left,\n          rect.top + yLabelOffset,\n          textPaints[colorID]);\n\n      yLabelOffset += lineHeight;\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/PoseDetectorProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector;\n\nimport android.content.Context;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.android.odml.image.MlImage;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport com.google.mlkit.vision.demo.java.posedetector.classification.PoseClassifierProcessor;\nimport com.google.mlkit.vision.pose.Pose;\nimport com.google.mlkit.vision.pose.PoseDetection;\nimport com.google.mlkit.vision.pose.PoseDetector;\nimport com.google.mlkit.vision.pose.PoseDetectorOptionsBase;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\n\n/** A processor to run pose detector. */\npublic class PoseDetectorProcessor\n    extends VisionProcessorBase<PoseDetectorProcessor.PoseWithClassification> {\n  private static final String TAG = \"PoseDetectorProcessor\";\n\n  private final PoseDetector detector;\n\n  private final boolean showInFrameLikelihood;\n  private final boolean visualizeZ;\n  private final boolean rescaleZForVisualization;\n  private final boolean runClassification;\n  private final boolean isStreamMode;\n  private final Context context;\n  private final Executor classificationExecutor;\n\n  private PoseClassifierProcessor poseClassifierProcessor;\n  /** Internal class to hold Pose and classification results. */\n  protected static class PoseWithClassification {\n    private final Pose pose;\n    private final List<String> classificationResult;\n\n    public PoseWithClassification(Pose pose, List<String> classificationResult) {\n      this.pose = pose;\n      this.classificationResult = classificationResult;\n    }\n\n    public Pose getPose() {\n      return pose;\n    }\n\n    public List<String> getClassificationResult() {\n      return classificationResult;\n    }\n  }\n\n  public PoseDetectorProcessor(\n      Context context,\n      PoseDetectorOptionsBase options,\n      boolean showInFrameLikelihood,\n      boolean visualizeZ,\n      boolean rescaleZForVisualization,\n      boolean runClassification,\n      boolean isStreamMode) {\n    super(context);\n    this.showInFrameLikelihood = showInFrameLikelihood;\n    this.visualizeZ = visualizeZ;\n    this.rescaleZForVisualization = rescaleZForVisualization;\n    detector = PoseDetection.getClient(options);\n    this.runClassification = runClassification;\n    this.isStreamMode = isStreamMode;\n    this.context = context;\n    classificationExecutor = Executors.newSingleThreadExecutor();\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    detector.close();\n  }\n\n  @Override\n  protected Task<PoseWithClassification> detectInImage(InputImage image) {\n    return detector\n        .process(image)\n        .continueWith(\n            classificationExecutor,\n            task -> {\n              Pose pose = task.getResult();\n              List<String> classificationResult = new ArrayList<>();\n              if (runClassification) {\n                if (poseClassifierProcessor == null) {\n                  poseClassifierProcessor = new PoseClassifierProcessor(context, isStreamMode);\n                }\n                classificationResult = poseClassifierProcessor.getPoseResult(pose);\n              }\n              return new PoseWithClassification(pose, classificationResult);\n            });\n  }\n\n  @Override\n  protected Task<PoseWithClassification> detectInImage(MlImage image) {\n    return detector\n        .process(image)\n        .continueWith(\n            classificationExecutor,\n            task -> {\n              Pose pose = task.getResult();\n              List<String> classificationResult = new ArrayList<>();\n              if (runClassification) {\n                if (poseClassifierProcessor == null) {\n                  poseClassifierProcessor = new PoseClassifierProcessor(context, isStreamMode);\n                }\n                classificationResult = poseClassifierProcessor.getPoseResult(pose);\n              }\n              return new PoseWithClassification(pose, classificationResult);\n            });\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull PoseWithClassification poseWithClassification,\n      @NonNull GraphicOverlay graphicOverlay) {\n    graphicOverlay.add(\n        new PoseGraphic(\n            graphicOverlay,\n            poseWithClassification.pose,\n            showInFrameLikelihood,\n            visualizeZ,\n            rescaleZForVisualization,\n            poseWithClassification.classificationResult));\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.e(TAG, \"Pose detection failed!\", e);\n  }\n\n  @Override\n  protected boolean isMlImageEnabled(Context context) {\n    // Use MlImage in Pose Detection by default, change it to OFF to switch to InputImage.\n    return true;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/PoseGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector;\n\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport com.google.mlkit.vision.common.PointF3D;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.pose.Pose;\nimport com.google.mlkit.vision.pose.PoseLandmark;\nimport java.util.List;\nimport java.util.Locale;\n\n/** Draw the detected pose in preview. */\npublic class PoseGraphic extends Graphic {\n\n  private static final float DOT_RADIUS = 8.0f;\n  private static final float IN_FRAME_LIKELIHOOD_TEXT_SIZE = 30.0f;\n  private static final float STROKE_WIDTH = 10.0f;\n  private static final float POSE_CLASSIFICATION_TEXT_SIZE = 60.0f;\n\n  private final Pose pose;\n  private final boolean showInFrameLikelihood;\n  private final boolean visualizeZ;\n  private final boolean rescaleZForVisualization;\n  private float zMin = Float.MAX_VALUE;\n  private float zMax = Float.MIN_VALUE;\n\n  private final List<String> poseClassification;\n  private final Paint classificationTextPaint;\n  private final Paint leftPaint;\n  private final Paint rightPaint;\n  private final Paint whitePaint;\n\n  PoseGraphic(\n      GraphicOverlay overlay,\n      Pose pose,\n      boolean showInFrameLikelihood,\n      boolean visualizeZ,\n      boolean rescaleZForVisualization,\n      List<String> poseClassification) {\n    super(overlay);\n    this.pose = pose;\n    this.showInFrameLikelihood = showInFrameLikelihood;\n    this.visualizeZ = visualizeZ;\n    this.rescaleZForVisualization = rescaleZForVisualization;\n\n    this.poseClassification = poseClassification;\n    classificationTextPaint = new Paint();\n    classificationTextPaint.setColor(Color.WHITE);\n    classificationTextPaint.setTextSize(POSE_CLASSIFICATION_TEXT_SIZE);\n    classificationTextPaint.setShadowLayer(5.0f, 0f, 0f, Color.BLACK);\n\n    whitePaint = new Paint();\n    whitePaint.setStrokeWidth(STROKE_WIDTH);\n    whitePaint.setColor(Color.WHITE);\n    whitePaint.setTextSize(IN_FRAME_LIKELIHOOD_TEXT_SIZE);\n    leftPaint = new Paint();\n    leftPaint.setStrokeWidth(STROKE_WIDTH);\n    leftPaint.setColor(Color.GREEN);\n    rightPaint = new Paint();\n    rightPaint.setStrokeWidth(STROKE_WIDTH);\n    rightPaint.setColor(Color.YELLOW);\n  }\n\n  @Override\n  public void draw(Canvas canvas) {\n    List<PoseLandmark> landmarks = pose.getAllPoseLandmarks();\n    if (landmarks.isEmpty()) {\n      return;\n    }\n\n    // Draw pose classification text.\n    float classificationX = POSE_CLASSIFICATION_TEXT_SIZE * 0.5f;\n    for (int i = 0; i < poseClassification.size(); i++) {\n      float classificationY =\n          (canvas.getHeight()\n              - POSE_CLASSIFICATION_TEXT_SIZE * 1.5f * (poseClassification.size() - i));\n      canvas.drawText(\n          poseClassification.get(i), classificationX, classificationY, classificationTextPaint);\n    }\n\n    // Draw all the points\n    for (PoseLandmark landmark : landmarks) {\n      drawPoint(canvas, landmark, whitePaint);\n      if (visualizeZ && rescaleZForVisualization) {\n        zMin = min(zMin, landmark.getPosition3D().getZ());\n        zMax = max(zMax, landmark.getPosition3D().getZ());\n      }\n    }\n\n    PoseLandmark nose = pose.getPoseLandmark(PoseLandmark.NOSE);\n    PoseLandmark lefyEyeInner = pose.getPoseLandmark(PoseLandmark.LEFT_EYE_INNER);\n    PoseLandmark lefyEye = pose.getPoseLandmark(PoseLandmark.LEFT_EYE);\n    PoseLandmark leftEyeOuter = pose.getPoseLandmark(PoseLandmark.LEFT_EYE_OUTER);\n    PoseLandmark rightEyeInner = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE_INNER);\n    PoseLandmark rightEye = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE);\n    PoseLandmark rightEyeOuter = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE_OUTER);\n    PoseLandmark leftEar = pose.getPoseLandmark(PoseLandmark.LEFT_EAR);\n    PoseLandmark rightEar = pose.getPoseLandmark(PoseLandmark.RIGHT_EAR);\n    PoseLandmark leftMouth = pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH);\n    PoseLandmark rightMouth = pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH);\n\n    PoseLandmark leftShoulder = pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER);\n    PoseLandmark rightShoulder = pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER);\n    PoseLandmark leftElbow = pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW);\n    PoseLandmark rightElbow = pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW);\n    PoseLandmark leftWrist = pose.getPoseLandmark(PoseLandmark.LEFT_WRIST);\n    PoseLandmark rightWrist = pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST);\n    PoseLandmark leftHip = pose.getPoseLandmark(PoseLandmark.LEFT_HIP);\n    PoseLandmark rightHip = pose.getPoseLandmark(PoseLandmark.RIGHT_HIP);\n    PoseLandmark leftKnee = pose.getPoseLandmark(PoseLandmark.LEFT_KNEE);\n    PoseLandmark rightKnee = pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE);\n    PoseLandmark leftAnkle = pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE);\n    PoseLandmark rightAnkle = pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE);\n\n    PoseLandmark leftPinky = pose.getPoseLandmark(PoseLandmark.LEFT_PINKY);\n    PoseLandmark rightPinky = pose.getPoseLandmark(PoseLandmark.RIGHT_PINKY);\n    PoseLandmark leftIndex = pose.getPoseLandmark(PoseLandmark.LEFT_INDEX);\n    PoseLandmark rightIndex = pose.getPoseLandmark(PoseLandmark.RIGHT_INDEX);\n    PoseLandmark leftThumb = pose.getPoseLandmark(PoseLandmark.LEFT_THUMB);\n    PoseLandmark rightThumb = pose.getPoseLandmark(PoseLandmark.RIGHT_THUMB);\n    PoseLandmark leftHeel = pose.getPoseLandmark(PoseLandmark.LEFT_HEEL);\n    PoseLandmark rightHeel = pose.getPoseLandmark(PoseLandmark.RIGHT_HEEL);\n    PoseLandmark leftFootIndex = pose.getPoseLandmark(PoseLandmark.LEFT_FOOT_INDEX);\n    PoseLandmark rightFootIndex = pose.getPoseLandmark(PoseLandmark.RIGHT_FOOT_INDEX);\n\n    // Face\n    drawLine(canvas, nose, lefyEyeInner, whitePaint);\n    drawLine(canvas, lefyEyeInner, lefyEye, whitePaint);\n    drawLine(canvas, lefyEye, leftEyeOuter, whitePaint);\n    drawLine(canvas, leftEyeOuter, leftEar, whitePaint);\n    drawLine(canvas, nose, rightEyeInner, whitePaint);\n    drawLine(canvas, rightEyeInner, rightEye, whitePaint);\n    drawLine(canvas, rightEye, rightEyeOuter, whitePaint);\n    drawLine(canvas, rightEyeOuter, rightEar, whitePaint);\n    drawLine(canvas, leftMouth, rightMouth, whitePaint);\n\n    drawLine(canvas, leftShoulder, rightShoulder, whitePaint);\n    drawLine(canvas, leftHip, rightHip, whitePaint);\n\n    // Left body\n    drawLine(canvas, leftShoulder, leftElbow, leftPaint);\n    drawLine(canvas, leftElbow, leftWrist, leftPaint);\n    drawLine(canvas, leftShoulder, leftHip, leftPaint);\n    drawLine(canvas, leftHip, leftKnee, leftPaint);\n    drawLine(canvas, leftKnee, leftAnkle, leftPaint);\n    drawLine(canvas, leftWrist, leftThumb, leftPaint);\n    drawLine(canvas, leftWrist, leftPinky, leftPaint);\n    drawLine(canvas, leftWrist, leftIndex, leftPaint);\n    drawLine(canvas, leftIndex, leftPinky, leftPaint);\n    drawLine(canvas, leftAnkle, leftHeel, leftPaint);\n    drawLine(canvas, leftHeel, leftFootIndex, leftPaint);\n\n    // Right body\n    drawLine(canvas, rightShoulder, rightElbow, rightPaint);\n    drawLine(canvas, rightElbow, rightWrist, rightPaint);\n    drawLine(canvas, rightShoulder, rightHip, rightPaint);\n    drawLine(canvas, rightHip, rightKnee, rightPaint);\n    drawLine(canvas, rightKnee, rightAnkle, rightPaint);\n    drawLine(canvas, rightWrist, rightThumb, rightPaint);\n    drawLine(canvas, rightWrist, rightPinky, rightPaint);\n    drawLine(canvas, rightWrist, rightIndex, rightPaint);\n    drawLine(canvas, rightIndex, rightPinky, rightPaint);\n    drawLine(canvas, rightAnkle, rightHeel, rightPaint);\n    drawLine(canvas, rightHeel, rightFootIndex, rightPaint);\n\n    // Draw inFrameLikelihood for all points\n    if (showInFrameLikelihood) {\n      for (PoseLandmark landmark : landmarks) {\n        canvas.drawText(\n            String.format(Locale.US, \"%.2f\", landmark.getInFrameLikelihood()),\n            translateX(landmark.getPosition().x),\n            translateY(landmark.getPosition().y),\n            whitePaint);\n      }\n    }\n  }\n\n  void drawPoint(Canvas canvas, PoseLandmark landmark, Paint paint) {\n    PointF3D point = landmark.getPosition3D();\n    updatePaintColorByZValue(\n        paint, canvas, visualizeZ, rescaleZForVisualization, point.getZ(), zMin, zMax);\n    canvas.drawCircle(translateX(point.getX()), translateY(point.getY()), DOT_RADIUS, paint);\n  }\n\n  void drawLine(Canvas canvas, PoseLandmark startLandmark, PoseLandmark endLandmark, Paint paint) {\n    PointF3D start = startLandmark.getPosition3D();\n    PointF3D end = endLandmark.getPosition3D();\n\n    // Gets average z for the current body line\n    float avgZInImagePixel = (start.getZ() + end.getZ()) / 2;\n    updatePaintColorByZValue(\n        paint, canvas, visualizeZ, rescaleZForVisualization, avgZInImagePixel, zMin, zMax);\n\n    canvas.drawLine(\n        translateX(start.getX()),\n        translateY(start.getY()),\n        translateX(end.getX()),\n        translateY(end.getY()),\n        paint);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/classification/ClassificationResult.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector.classification;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static java.util.Collections.max;\n\n/**\n * Represents Pose classification result as outputted by {@link PoseClassifier}. Can be manipulated.\n */\npublic class ClassificationResult {\n  // For an entry in this map, the key is the class name, and the value is how many times this class\n  // appears in the top K nearest neighbors. The value is in range [0, K] and could be a float after\n  // EMA smoothing. We use this number to represent the confidence of a pose being in this class.\n  private final Map<String, Float> classConfidences;\n\n  public ClassificationResult() {\n    classConfidences = new HashMap<>();\n  }\n\n  public Set<String> getAllClasses() {\n    return classConfidences.keySet();\n  }\n\n  public float getClassConfidence(String className) {\n    return classConfidences.containsKey(className) ? classConfidences.get(className) : 0;\n  }\n\n  public String getMaxConfidenceClass() {\n    return max(\n        classConfidences.entrySet(),\n        (entry1, entry2) -> (int) (entry1.getValue() - entry2.getValue()))\n        .getKey();\n  }\n\n  public void incrementClassConfidence(String className) {\n    classConfidences.put(className,\n        classConfidences.containsKey(className) ? classConfidences.get(className) + 1 : 1);\n  }\n\n  public void putClassConfidence(String className, float confidence) {\n    classConfidences.put(className, confidence);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/classification/EMASmoothing.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector.classification;\n\nimport android.os.SystemClock;\nimport java.util.Deque;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.LinkedBlockingDeque;\n\n/**\n * Runs EMA smoothing over a window with given stream of pose classification results.\n */\npublic class EMASmoothing {\n  private static final int DEFAULT_WINDOW_SIZE = 10;\n  private static final float DEFAULT_ALPHA = 0.2f;\n\n  private static final long RESET_THRESHOLD_MS = 100;\n\n  private final int windowSize;\n  private final float alpha;\n  // This is a window of {@link ClassificationResult}s as outputted by the {@link PoseClassifier}.\n  // We run smoothing over this window of size {@link windowSize}.\n  private final Deque<ClassificationResult> window;\n\n  private long lastInputMs;\n\n  public EMASmoothing() {\n    this(DEFAULT_WINDOW_SIZE, DEFAULT_ALPHA);\n  }\n\n  public EMASmoothing(int windowSize, float alpha) {\n    this.windowSize = windowSize;\n    this.alpha = alpha;\n    this.window = new LinkedBlockingDeque<>(windowSize);\n  }\n\n  public ClassificationResult getSmoothedResult(ClassificationResult classificationResult) {\n    // Resets memory if the input is too far away from the previous one in time.\n    long nowMs = SystemClock.elapsedRealtime();\n    if (nowMs - lastInputMs > RESET_THRESHOLD_MS) {\n      window.clear();\n    }\n    lastInputMs = nowMs;\n\n    // If we are at window size, remove the last (oldest) result.\n    if (window.size() == windowSize) {\n      window.pollLast();\n    }\n    // Insert at the beginning of the window.\n    window.addFirst(classificationResult);\n\n    Set<String> allClasses = new HashSet<>();\n    for (ClassificationResult result : window) {\n      allClasses.addAll(result.getAllClasses());\n    }\n\n    ClassificationResult smoothedResult = new ClassificationResult();\n\n    for (String className : allClasses) {\n      float factor = 1;\n      float topSum = 0;\n      float bottomSum = 0;\n      for (ClassificationResult result : window) {\n        float value = result.getClassConfidence(className);\n\n        topSum += factor * value;\n        bottomSum += factor;\n\n        factor = (float) (factor * (1.0 - alpha));\n      }\n      smoothedResult.putClassConfidence(className, topSum / bottomSum);\n    }\n\n    return smoothedResult;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/classification/PoseClassifier.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector.classification;\n\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.PoseEmbedding.getPoseEmbedding;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.maxAbs;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.multiply;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.multiplyAll;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.subtract;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.sumAbs;\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\n\nimport android.util.Pair;\nimport com.google.mlkit.vision.common.PointF3D;\nimport com.google.mlkit.vision.pose.Pose;\nimport com.google.mlkit.vision.pose.PoseLandmark;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.PriorityQueue;\n\n/**\n * Classifies {link Pose} based on given {@link PoseSample}s.\n *\n * <p>Inspired by K-Nearest Neighbors Algorithm with outlier filtering.\n * https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm\n */\npublic class PoseClassifier {\n  private static final String TAG = \"PoseClassifier\";\n  private static final int MAX_DISTANCE_TOP_K = 30;\n  private static final int MEAN_DISTANCE_TOP_K = 10;\n  // Note Z has a lower weight as it is generally less accurate than X & Y.\n  private static final PointF3D AXES_WEIGHTS = PointF3D.from(1, 1, 0.2f);\n\n  private final List<PoseSample> poseSamples;\n  private final int maxDistanceTopK;\n  private final int meanDistanceTopK;\n  private final PointF3D axesWeights;\n\n  public PoseClassifier(List<PoseSample> poseSamples) {\n    this(poseSamples, MAX_DISTANCE_TOP_K, MEAN_DISTANCE_TOP_K, AXES_WEIGHTS);\n  }\n\n  public PoseClassifier(List<PoseSample> poseSamples, int maxDistanceTopK,\n      int meanDistanceTopK, PointF3D axesWeights) {\n    this.poseSamples = poseSamples;\n    this.maxDistanceTopK = maxDistanceTopK;\n    this.meanDistanceTopK = meanDistanceTopK;\n    this.axesWeights = axesWeights;\n  }\n\n  private static List<PointF3D> extractPoseLandmarks(Pose pose) {\n    List<PointF3D> landmarks = new ArrayList<>();\n    for (PoseLandmark poseLandmark : pose.getAllPoseLandmarks()) {\n      landmarks.add(poseLandmark.getPosition3D());\n    }\n    return landmarks;\n  }\n\n  /**\n   * Returns the max range of confidence values.\n   *\n   * <p><Since we calculate confidence by counting {@link PoseSample}s that survived\n   * outlier-filtering by maxDistanceTopK and meanDistanceTopK, this range is the minimum of two.\n   */\n  public int confidenceRange() {\n    return min(maxDistanceTopK, meanDistanceTopK);\n  }\n\n  public ClassificationResult classify(Pose pose) {\n    return classify(extractPoseLandmarks(pose));\n  }\n\n  public ClassificationResult classify(List<PointF3D> landmarks) {\n    ClassificationResult result = new ClassificationResult();\n    // Return early if no landmarks detected.\n    if (landmarks.isEmpty()) {\n      return result;\n    }\n\n    // We do flipping on X-axis so we are horizontal (mirror) invariant.\n    List<PointF3D> flippedLandmarks = new ArrayList<>(landmarks);\n    multiplyAll(flippedLandmarks, PointF3D.from(-1, 1, 1));\n\n    List<PointF3D> embedding = getPoseEmbedding(landmarks);\n    List<PointF3D> flippedEmbedding = getPoseEmbedding(flippedLandmarks);\n\n\n    // Classification is done in two stages:\n    //  * First we pick top-K samples by MAX distance. It allows to remove samples that are almost\n    //    the same as given pose, but maybe has few joints bent in the other direction.\n    //  * Then we pick top-K samples by MEAN distance. After outliers are removed, we pick samples\n    //    that are closest by average.\n\n    // Keeps max distance on top so we can pop it when top_k size is reached.\n    PriorityQueue<Pair<PoseSample, Float>> maxDistances = new PriorityQueue<>(\n        maxDistanceTopK, (o1, o2) -> -Float.compare(o1.second, o2.second));\n    // Retrieve top K poseSamples by least distance to remove outliers.\n    for (PoseSample poseSample : poseSamples) {\n      List<PointF3D> sampleEmbedding = poseSample.getEmbedding();\n\n      float originalMax = 0;\n      float flippedMax = 0;\n      for (int i = 0; i < embedding.size(); i++) {\n        originalMax =\n            max(\n                originalMax,\n                maxAbs(multiply(subtract(embedding.get(i), sampleEmbedding.get(i)), axesWeights)));\n        flippedMax =\n            max(\n                flippedMax,\n                maxAbs(\n                    multiply(\n                        subtract(flippedEmbedding.get(i), sampleEmbedding.get(i)), axesWeights)));\n      }\n      // Set the max distance as min of original and flipped max distance.\n      maxDistances.add(new Pair<>(poseSample, min(originalMax, flippedMax)));\n      // We only want to retain top n so pop the highest distance.\n      if (maxDistances.size() > maxDistanceTopK) {\n        maxDistances.poll();\n      }\n    }\n\n    // Keeps higher mean distances on top so we can pop it when top_k size is reached.\n    PriorityQueue<Pair<PoseSample, Float>> meanDistances = new PriorityQueue<>(\n        meanDistanceTopK, (o1, o2) -> -Float.compare(o1.second, o2.second));\n    // Retrive top K poseSamples by least mean distance to remove outliers.\n    for (Pair<PoseSample, Float> sampleDistances : maxDistances) {\n      PoseSample poseSample = sampleDistances.first;\n      List<PointF3D> sampleEmbedding = poseSample.getEmbedding();\n\n      float originalSum = 0;\n      float flippedSum = 0;\n      for (int i = 0; i < embedding.size(); i++) {\n        originalSum += sumAbs(multiply(\n            subtract(embedding.get(i), sampleEmbedding.get(i)), axesWeights));\n        flippedSum += sumAbs(\n            multiply(subtract(flippedEmbedding.get(i), sampleEmbedding.get(i)), axesWeights));\n      }\n      // Set the mean distance as min of original and flipped mean distances.\n      float meanDistance = min(originalSum, flippedSum) / (embedding.size() * 2);\n      meanDistances.add(new Pair<>(poseSample, meanDistance));\n      // We only want to retain top k so pop the highest mean distance.\n      if (meanDistances.size() > meanDistanceTopK) {\n        meanDistances.poll();\n      }\n    }\n\n    for (Pair<PoseSample, Float> sampleDistances : meanDistances) {\n      String className = sampleDistances.first.getClassName();\n      result.incrementClassConfidence(className);\n    }\n\n    return result;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/classification/PoseClassifierProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector.classification;\n\nimport android.content.Context;\nimport android.media.AudioManager;\nimport android.media.ToneGenerator;\nimport android.os.Looper;\nimport android.util.Log;\nimport androidx.annotation.WorkerThread;\nimport com.google.common.base.Preconditions;\nimport com.google.mlkit.vision.pose.Pose;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\n/**\n * Accepts a stream of {@link Pose} for classification and Rep counting.\n */\npublic class PoseClassifierProcessor {\n  private static final String TAG = \"PoseClassifierProcessor\";\n  private static final String POSE_SAMPLES_FILE = \"pose/fitness_pose_samples.csv\";\n\n  // Specify classes for which we want rep counting.\n  // These are the labels in the given {@code POSE_SAMPLES_FILE}. You can set your own class labels\n  // for your pose samples.\n  private static final String PUSHUPS_CLASS = \"pushups_down\";\n  private static final String SQUATS_CLASS = \"squats_down\";\n  private static final String[] POSE_CLASSES = {\n    PUSHUPS_CLASS, SQUATS_CLASS\n  };\n\n  private final boolean isStreamMode;\n\n  private EMASmoothing emaSmoothing;\n  private List<RepetitionCounter> repCounters;\n  private PoseClassifier poseClassifier;\n  private String lastRepResult;\n\n  @WorkerThread\n  public PoseClassifierProcessor(Context context, boolean isStreamMode) {\n    Preconditions.checkState(Looper.myLooper() != Looper.getMainLooper());\n    this.isStreamMode = isStreamMode;\n    if (isStreamMode) {\n      emaSmoothing = new EMASmoothing();\n      repCounters = new ArrayList<>();\n      lastRepResult = \"\";\n    }\n    loadPoseSamples(context);\n  }\n\n  private void loadPoseSamples(Context context) {\n    List<PoseSample> poseSamples = new ArrayList<>();\n    try {\n      BufferedReader reader = new BufferedReader(\n          new InputStreamReader(context.getAssets().open(POSE_SAMPLES_FILE)));\n      String csvLine = reader.readLine();\n      while (csvLine != null) {\n        // If line is not a valid {@link PoseSample}, we'll get null and skip adding to the list.\n        PoseSample poseSample = PoseSample.getPoseSample(csvLine, \",\");\n        if (poseSample != null) {\n          poseSamples.add(poseSample);\n        }\n        csvLine = reader.readLine();\n      }\n    } catch (IOException e) {\n      Log.e(TAG, \"Error when loading pose samples.\\n\" + e);\n    }\n    poseClassifier = new PoseClassifier(poseSamples);\n    if (isStreamMode) {\n      for (String className : POSE_CLASSES) {\n        repCounters.add(new RepetitionCounter(className));\n      }\n    }\n  }\n\n  /**\n   * Given a new {@link Pose} input, returns a list of formatted {@link String}s with Pose\n   * classification results.\n   *\n   * <p>Currently it returns up to 2 strings as following:\n   * 0: PoseClass : X reps\n   * 1: PoseClass : [0.0-1.0] confidence\n   */\n  @WorkerThread\n  public List<String> getPoseResult(Pose pose) {\n    Preconditions.checkState(Looper.myLooper() != Looper.getMainLooper());\n    List<String> result = new ArrayList<>();\n    ClassificationResult classification = poseClassifier.classify(pose);\n\n    // Update {@link RepetitionCounter}s if {@code isStreamMode}.\n    if (isStreamMode) {\n      // Feed pose to smoothing even if no pose found.\n      classification = emaSmoothing.getSmoothedResult(classification);\n\n      // Return early without updating repCounter if no pose found.\n      if (pose.getAllPoseLandmarks().isEmpty()) {\n        result.add(lastRepResult);\n        return result;\n      }\n\n      for (RepetitionCounter repCounter : repCounters) {\n        int repsBefore = repCounter.getNumRepeats();\n        int repsAfter = repCounter.addClassificationResult(classification);\n        if (repsAfter > repsBefore) {\n          // Play a fun beep when rep counter updates.\n          ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);\n          tg.startTone(ToneGenerator.TONE_PROP_BEEP);\n          lastRepResult = String.format(\n              Locale.US, \"%s : %d reps\", repCounter.getClassName(), repsAfter);\n          break;\n        }\n      }\n      result.add(lastRepResult);\n    }\n\n    // Add maxConfidence class of current frame to result if pose is found.\n    if (!pose.getAllPoseLandmarks().isEmpty()) {\n      String maxConfidenceClass = classification.getMaxConfidenceClass();\n      String maxConfidenceClassResult = String.format(\n          Locale.US,\n          \"%s : %.2f confidence\",\n          maxConfidenceClass,\n          classification.getClassConfidence(maxConfidenceClass)\n              / poseClassifier.confidenceRange());\n      result.add(maxConfidenceClassResult);\n    }\n\n    return result;\n  }\n\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/classification/PoseEmbedding.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector.classification;\n\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.average;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.l2Norm2D;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.multiplyAll;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.subtract;\nimport static com.google.mlkit.vision.demo.java.posedetector.classification.Utils.subtractAll;\n\nimport com.google.mlkit.vision.common.PointF3D;\nimport com.google.mlkit.vision.pose.PoseLandmark;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Generates embedding for given list of Pose landmarks.\n */\npublic class PoseEmbedding {\n  // Multiplier to apply to the torso to get minimal body size. Picked this by experimentation.\n  private static final float TORSO_MULTIPLIER = 2.5f;\n\n  public static List<PointF3D> getPoseEmbedding(List<PointF3D> landmarks) {\n    List<PointF3D> normalizedLandmarks = normalize(landmarks);\n    return getEmbedding(normalizedLandmarks);\n  }\n\n  private static List<PointF3D> normalize(List<PointF3D> landmarks) {\n    List<PointF3D> normalizedLandmarks = new ArrayList<>(landmarks);\n    // Normalize translation.\n    PointF3D center = average(\n        landmarks.get(PoseLandmark.LEFT_HIP), landmarks.get(PoseLandmark.RIGHT_HIP));\n    subtractAll(center, normalizedLandmarks);\n\n    // Normalize scale.\n    multiplyAll(normalizedLandmarks, 1 / getPoseSize(normalizedLandmarks));\n    // Multiplication by 100 is not required, but makes it easier to debug.\n    multiplyAll(normalizedLandmarks, 100);\n    return normalizedLandmarks;\n  }\n\n  // Translation normalization should've been done prior to calling this method.\n  private static float getPoseSize(List<PointF3D> landmarks) {\n    // Note: This approach uses only 2D landmarks to compute pose size as using Z wasn't helpful\n    // in our experimentation but you're welcome to tweak.\n    PointF3D hipsCenter = average(\n        landmarks.get(PoseLandmark.LEFT_HIP), landmarks.get(PoseLandmark.RIGHT_HIP));\n\n    PointF3D shouldersCenter = average(\n        landmarks.get(PoseLandmark.LEFT_SHOULDER),\n        landmarks.get(PoseLandmark.RIGHT_SHOULDER));\n\n    float torsoSize = l2Norm2D(subtract(hipsCenter, shouldersCenter));\n\n    float maxDistance = torsoSize * TORSO_MULTIPLIER;\n    // torsoSize * TORSO_MULTIPLIER is the floor we want based on experimentation but actual size\n    // can be bigger for a given pose depending on extension of limbs etc so we calculate that.\n    for (PointF3D landmark : landmarks) {\n      float distance = l2Norm2D(subtract(hipsCenter, landmark));\n      if (distance > maxDistance) {\n        maxDistance = distance;\n      }\n    }\n    return maxDistance;\n  }\n\n  private static List<PointF3D> getEmbedding(List<PointF3D> lm) {\n    List<PointF3D> embedding = new ArrayList<>();\n\n    // We use several pairwise 3D distances to form pose embedding. These were selected\n    // based on experimentation for best results with our default pose classes as captued in the\n    // pose samples csv. Feel free to play with this and add or remove for your use-cases.\n\n    // We group our distances by number of joints between the pairs.\n    // One joint.\n    embedding.add(subtract(\n        average(lm.get(PoseLandmark.LEFT_HIP), lm.get(PoseLandmark.RIGHT_HIP)),\n        average(lm.get(PoseLandmark.LEFT_SHOULDER), lm.get(PoseLandmark.RIGHT_SHOULDER))\n    ));\n\n    embedding.add(subtract(\n        lm.get(PoseLandmark.LEFT_SHOULDER), lm.get(PoseLandmark.LEFT_ELBOW)));\n    embedding.add(subtract(\n        lm.get(PoseLandmark.RIGHT_SHOULDER), lm.get(PoseLandmark.RIGHT_ELBOW)));\n\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_ELBOW), lm.get(PoseLandmark.LEFT_WRIST)));\n    embedding.add(subtract(lm.get(PoseLandmark.RIGHT_ELBOW), lm.get(PoseLandmark.RIGHT_WRIST)));\n\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_HIP), lm.get(PoseLandmark.LEFT_KNEE)));\n    embedding.add(subtract(lm.get(PoseLandmark.RIGHT_HIP), lm.get(PoseLandmark.RIGHT_KNEE)));\n\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_KNEE), lm.get(PoseLandmark.LEFT_ANKLE)));\n    embedding.add(subtract(lm.get(PoseLandmark.RIGHT_KNEE), lm.get(PoseLandmark.RIGHT_ANKLE)));\n\n    // Two joints.\n    embedding.add(subtract(\n        lm.get(PoseLandmark.LEFT_SHOULDER), lm.get(PoseLandmark.LEFT_WRIST)));\n    embedding.add(subtract(\n        lm.get(PoseLandmark.RIGHT_SHOULDER), lm.get(PoseLandmark.RIGHT_WRIST)));\n\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_HIP), lm.get(PoseLandmark.LEFT_ANKLE)));\n    embedding.add(subtract(lm.get(PoseLandmark.RIGHT_HIP), lm.get(PoseLandmark.RIGHT_ANKLE)));\n\n    // Four joints.\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_HIP), lm.get(PoseLandmark.LEFT_WRIST)));\n    embedding.add(subtract(lm.get(PoseLandmark.RIGHT_HIP), lm.get(PoseLandmark.RIGHT_WRIST)));\n\n    // Five joints.\n    embedding.add(subtract(\n        lm.get(PoseLandmark.LEFT_SHOULDER), lm.get(PoseLandmark.LEFT_ANKLE)));\n    embedding.add(subtract(\n        lm.get(PoseLandmark.RIGHT_SHOULDER), lm.get(PoseLandmark.RIGHT_ANKLE)));\n\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_HIP), lm.get(PoseLandmark.LEFT_WRIST)));\n    embedding.add(subtract(lm.get(PoseLandmark.RIGHT_HIP), lm.get(PoseLandmark.RIGHT_WRIST)));\n\n    // Cross body.\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_ELBOW), lm.get(PoseLandmark.RIGHT_ELBOW)));\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_KNEE), lm.get(PoseLandmark.RIGHT_KNEE)));\n\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_WRIST), lm.get(PoseLandmark.RIGHT_WRIST)));\n    embedding.add(subtract(lm.get(PoseLandmark.LEFT_ANKLE), lm.get(PoseLandmark.RIGHT_ANKLE)));\n\n    return embedding;\n  }\n\n  private PoseEmbedding() {}\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/classification/PoseSample.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector.classification;\n\nimport android.util.Log;\nimport com.google.common.base.Splitter;\nimport com.google.mlkit.vision.common.PointF3D;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Reads Pose samples from a csv file.\n */\npublic class PoseSample {\n  private static final String TAG = \"PoseSample\";\n  private static final int NUM_LANDMARKS = 33;\n  private static final int NUM_DIMS = 3;\n\n  private final String name;\n  private final String className;\n  private final List<PointF3D> embedding;\n\n  public PoseSample(String name, String className, List<PointF3D> landmarks) {\n    this.name = name;\n    this.className = className;\n    this.embedding = PoseEmbedding.getPoseEmbedding(landmarks);\n  }\n\n  public String getName() {\n    return name;\n  }\n\n  public String getClassName() {\n    return className;\n  }\n\n  public List<PointF3D> getEmbedding() {\n    return embedding;\n  }\n\n  public static PoseSample getPoseSample(String csvLine, String separator) {\n    List<String> tokens = Splitter.onPattern(separator).splitToList(csvLine);\n    // Format is expected to be Name,Class,X1,Y1,Z1,X2,Y2,Z2...\n    // + 2 is for Name & Class.\n    if (tokens.size() != (NUM_LANDMARKS * NUM_DIMS) + 2) {\n      Log.e(TAG, \"Invalid number of tokens for PoseSample\");\n      return null;\n    }\n    String name = tokens.get(0);\n    String className = tokens.get(1);\n    List<PointF3D> landmarks = new ArrayList<>();\n    // Read from the third token, first 2 tokens are name and class.\n    for (int i = 2; i < tokens.size(); i += NUM_DIMS) {\n      try {\n        landmarks.add(\n            PointF3D.from(\n                Float.parseFloat(tokens.get(i)),\n                Float.parseFloat(tokens.get(i + 1)),\n                Float.parseFloat(tokens.get(i + 2))));\n      } catch (NullPointerException | NumberFormatException e) {\n        Log.e(TAG, \"Invalid value \" + tokens.get(i) + \" for landmark position.\");\n        return null;\n      }\n    }\n    return new PoseSample(name, className, landmarks);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/classification/RepetitionCounter.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector.classification;\n\n/**\n * Counts reps for the give class.\n */\npublic class RepetitionCounter {\n  // These thresholds can be tuned in conjunction with the Top K values in {@link PoseClassifier}.\n  // The default Top K value is 10 so the range here is [0-10].\n  private static final float DEFAULT_ENTER_THRESHOLD = 6f;\n  private static final float DEFAULT_EXIT_THRESHOLD = 4f;\n\n  private final String className;\n  private final float enterThreshold;\n  private final float exitThreshold;\n\n  private int numRepeats;\n  private boolean poseEntered;\n\n  public RepetitionCounter(String className) {\n    this(className, DEFAULT_ENTER_THRESHOLD, DEFAULT_EXIT_THRESHOLD);\n  }\n\n  public RepetitionCounter(String className, float enterThreshold, float exitThreshold) {\n    this.className = className;\n    this.enterThreshold = enterThreshold;\n    this.exitThreshold = exitThreshold;\n    numRepeats = 0;\n    poseEntered = false;\n  }\n\n  /**\n   * Adds a new Pose classification result and updates reps for given class.\n   *\n   * @param classificationResult {link ClassificationResult} of class to confidence values.\n   * @return number of reps.\n   */\n  public int addClassificationResult(ClassificationResult classificationResult) {\n    float poseConfidence = classificationResult.getClassConfidence(className);\n\n    if (!poseEntered) {\n      poseEntered = poseConfidence > enterThreshold;\n      return numRepeats;\n    }\n\n    if (poseConfidence < exitThreshold) {\n      numRepeats++;\n      poseEntered = false;\n    }\n\n    return numRepeats;\n  }\n\n  public String getClassName() {\n    return className;\n  }\n\n  public int getNumRepeats() {\n    return numRepeats;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/posedetector/classification/Utils.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.posedetector.classification;\n\nimport static com.google.common.primitives.Floats.max;\n\nimport com.google.mlkit.vision.common.PointF3D;\nimport java.util.List;\nimport java.util.ListIterator;\n\n/**\n * Utility methods for operations on {@link PointF3D}.\n */\npublic class Utils {\n  private Utils() {}\n\n  public static PointF3D add(PointF3D a, PointF3D b) {\n    return PointF3D.from(a.getX() + b.getX(), a.getY() + b.getY(), a.getZ() + b.getZ());\n  }\n\n  public static PointF3D subtract(PointF3D b, PointF3D a) {\n    return PointF3D.from(a.getX() - b.getX(), a.getY() - b.getY(), a.getZ() - b.getZ());\n  }\n\n  public static PointF3D multiply(PointF3D a, float multiple) {\n    return PointF3D.from(a.getX() * multiple, a.getY() * multiple, a.getZ() * multiple);\n  }\n\n  public static PointF3D multiply(PointF3D a, PointF3D multiple) {\n    return PointF3D.from(\n        a.getX() * multiple.getX(), a.getY() * multiple.getY(), a.getZ() * multiple.getZ());\n  }\n\n  public static PointF3D average(PointF3D a, PointF3D b) {\n    return PointF3D.from(\n        (a.getX() + b.getX()) * 0.5f, (a.getY() + b.getY()) * 0.5f, (a.getZ() + b.getZ()) * 0.5f);\n  }\n\n  public static float l2Norm2D(PointF3D point) {\n    return (float) Math.hypot(point.getX(), point.getY());\n  }\n\n  public static float maxAbs(PointF3D point) {\n    return max(Math.abs(point.getX()), Math.abs(point.getY()), Math.abs(point.getZ()));\n  }\n\n  public static float sumAbs(PointF3D point) {\n    return Math.abs(point.getX()) + Math.abs(point.getY()) + Math.abs(point.getZ());\n  }\n\n  public static void addAll(List<PointF3D> pointsList, PointF3D p) {\n    ListIterator<PointF3D> iterator = pointsList.listIterator();\n    while (iterator.hasNext()) {\n      iterator.set(add(iterator.next(), p));\n    }\n  }\n\n  public static void subtractAll(PointF3D p, List<PointF3D> pointsList) {\n    ListIterator<PointF3D> iterator = pointsList.listIterator();\n    while (iterator.hasNext()) {\n      iterator.set(subtract(p, iterator.next()));\n    }\n  }\n\n  public static void multiplyAll(List<PointF3D> pointsList, float multiple) {\n    ListIterator<PointF3D> iterator = pointsList.listIterator();\n    while (iterator.hasNext()) {\n      iterator.set(multiply(iterator.next(), multiple));\n    }\n  }\n\n  public static void multiplyAll(List<PointF3D> pointsList, PointF3D multiple) {\n    ListIterator<PointF3D> iterator = pointsList.listIterator();\n    while (iterator.hasNext()) {\n      iterator.set(multiply(iterator.next(), multiple));\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/segmenter/SegmentationGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.segmenter;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Matrix;\nimport androidx.annotation.ColorInt;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.segmentation.SegmentationMask;\nimport java.nio.ByteBuffer;\n\n/** Draw the mask from SegmentationResult in preview. */\npublic class SegmentationGraphic extends Graphic {\n\n  private final ByteBuffer mask;\n  private final int maskWidth;\n  private final int maskHeight;\n  private final boolean isRawSizeMaskEnabled;\n  private final float scaleX;\n  private final float scaleY;\n\n  public SegmentationGraphic(\n      GraphicOverlay overlay,\n      SegmentationMask segmentationMask) {\n    super(overlay);\n    mask = segmentationMask.getBuffer();\n    maskWidth = segmentationMask.getWidth();\n    maskHeight = segmentationMask.getHeight();\n\n    isRawSizeMaskEnabled =\n        maskWidth != overlay.getImageWidth()\n        || maskHeight != overlay.getImageHeight();\n    scaleX = overlay.getImageWidth() * 1f / maskWidth;\n    scaleY = overlay.getImageHeight() * 1f / maskHeight;\n  }\n\n  /** Draws the segmented background on the supplied canvas. */\n  @Override\n  public void draw(Canvas canvas) {\n    Bitmap bitmap =\n        Bitmap.createBitmap(\n            maskColorsFromByteBuffer(mask), maskWidth, maskHeight, Config.ARGB_8888);\n    if (isRawSizeMaskEnabled) {\n      Matrix matrix = new Matrix(getTransformationMatrix());\n      matrix.preScale(scaleX, scaleY);\n      canvas.drawBitmap(bitmap, matrix, null);\n    } else {\n      canvas.drawBitmap(bitmap, getTransformationMatrix(), null);\n    }\n    bitmap.recycle();\n    // Reset byteBuffer pointer to beginning, so that the mask can be redrawn if screen is refreshed\n    mask.rewind();\n  }\n\n  /** Converts byteBuffer floats to ColorInt array that can be used as a mask. */\n  @ColorInt\n  private int[] maskColorsFromByteBuffer(ByteBuffer byteBuffer) {\n    @ColorInt int[] colors = new int[maskWidth * maskHeight];\n    for (int i = 0; i < maskWidth * maskHeight; i++) {\n      float backgroundLikelihood = 1 - byteBuffer.getFloat();\n      if (backgroundLikelihood > 0.9) {\n        colors[i] = Color.argb(128, 255, 0, 255);\n      } else if (backgroundLikelihood > 0.2) {\n        // Linear interpolation to make sure when backgroundLikelihood is 0.2, the alpha is 0 and\n        // when backgroundLikelihood is 0.9, the alpha is 128.\n        // +0.5 to round the float value to the nearest int.\n        int alpha = (int) (182.9 * backgroundLikelihood - 36.6 + 0.5);\n        colors[i] = Color.argb(alpha, 255, 0, 255);\n      }\n    }\n    return colors;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/segmenter/SegmenterProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.segmenter;\n\nimport android.content.Context;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.segmentation.Segmentation;\nimport com.google.mlkit.vision.segmentation.SegmentationMask;\nimport com.google.mlkit.vision.segmentation.Segmenter;\nimport com.google.mlkit.vision.segmentation.selfie.SelfieSegmenterOptions;\n\n/** A processor to run Segmenter. */\npublic class SegmenterProcessor extends VisionProcessorBase<SegmentationMask> {\n\n  private static final String TAG = \"SegmenterProcessor\";\n\n  private final Segmenter segmenter;\n\n  public SegmenterProcessor(Context context) {\n    this(context, /* isStreamMode= */ true);\n  }\n\n  public SegmenterProcessor(Context context, boolean isStreamMode) {\n    super(context);\n    SelfieSegmenterOptions.Builder optionsBuilder = new SelfieSegmenterOptions.Builder();\n    optionsBuilder.setDetectorMode(\n      isStreamMode ? SelfieSegmenterOptions.STREAM_MODE : SelfieSegmenterOptions.SINGLE_IMAGE_MODE);\n    if (PreferenceUtils.shouldSegmentationEnableRawSizeMask(context)) {\n      optionsBuilder.enableRawSizeMask();\n    }\n\n    SelfieSegmenterOptions options = optionsBuilder.build();\n    segmenter = Segmentation.getClient(options);\n    Log.d(TAG, \"SegmenterProcessor created with option: \" + options);\n  }\n\n  @Override\n  protected Task<SegmentationMask> detectInImage(InputImage image) {\n    return segmenter.process(image);\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull SegmentationMask segmentationMask, @NonNull GraphicOverlay graphicOverlay) {\n    graphicOverlay.add(new SegmentationGraphic(graphicOverlay, segmentationMask));\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.e(TAG, \"Segmentation failed: \" + e);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/subjectsegmenter/SubjectSegmentationGraphic.java",
    "content": "/*\n * Copyright 2023 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.subjectsegmenter;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Matrix;\nimport android.os.Build;\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.RequiresApi;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.segmentation.subject.Subject;\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmentationResult;\nimport java.nio.FloatBuffer;\nimport java.util.List;\n\n/** Draw the mask from {@link SubjectSegmentationResult} in preview. */\n@RequiresApi(Build.VERSION_CODES.N)\npublic class SubjectSegmentationGraphic extends Graphic {\n\n  private static final int[][] COLORS = {\n    {255, 0, 255},\n    {0, 255, 255},\n    {255, 255, 0},\n    {255, 0, 0},\n    {0, 255, 0},\n    {0, 0, 255},\n    {128, 0, 128},\n    {0, 128, 128},\n    {128, 128, 0},\n    {128, 0, 0},\n    {0, 128, 0},\n    {0, 0, 128}\n  };\n\n  private final List<Subject> subjects;\n  private final int imageWidth;\n  private final int imageHeight;\n  private final boolean isRawSizeMaskEnabled;\n  private final float scaleX;\n  private final float scaleY;\n\n  public SubjectSegmentationGraphic(\n      GraphicOverlay overlay,\n      SubjectSegmentationResult segmentationResult,\n      int imageWidth,\n      int imageHeight) {\n    super(overlay);\n    subjects = segmentationResult.getSubjects();\n    this.imageWidth = imageWidth;\n    this.imageHeight = imageHeight;\n\n    isRawSizeMaskEnabled =\n        imageWidth != overlay.getImageWidth() || imageHeight != overlay.getImageHeight();\n    scaleX = overlay.getImageWidth() * 1f / imageWidth;\n    scaleY = overlay.getImageHeight() * 1f / imageHeight;\n  }\n\n  /** Draws the segmented background on the supplied canvas. */\n  @Override\n  public void draw(Canvas canvas) {\n    Bitmap bitmap =\n        Bitmap.createBitmap(maskColorsFromFloatBuffer(), imageWidth, imageHeight, Config.ARGB_8888);\n    if (isRawSizeMaskEnabled) {\n      Matrix matrix = new Matrix(getTransformationMatrix());\n      matrix.preScale(scaleX, scaleY);\n      canvas.drawBitmap(bitmap, matrix, null);\n    } else {\n      canvas.drawBitmap(bitmap, getTransformationMatrix(), null);\n    }\n\n    bitmap.recycle();\n  }\n\n  /** Converts FloatBuffer floats from all subjects to ColorInt array that can be used as a mask. */\n  @ColorInt\n  private int[] maskColorsFromFloatBuffer() {\n    @ColorInt int[] colors = new int[imageWidth * imageHeight];\n    for (int k = 0; k < subjects.size(); k++) {\n      Subject subject = subjects.get(k);\n      int[] rgb = COLORS[k % COLORS.length];\n      int color = Color.argb(128, rgb[0], rgb[1], rgb[2]);\n      FloatBuffer mask = subject.getConfidenceMask();\n      for (int j = 0; j < subject.getHeight(); j++) {\n        for (int i = 0; i < subject.getWidth(); i++) {\n          if (mask.get() > 0.5) {\n            colors[(subject.getStartY() + j) * imageWidth + subject.getStartX() + i] = color;\n          }\n        }\n      }\n      // Reset FloatBuffer pointer to beginning, so that the mask can be redrawn if screen is\n      // refreshed\n      mask.rewind();\n    }\n    return colors;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/subjectsegmenter/SubjectSegmenterProcessor.java",
    "content": "/*\n * Copyright 2023 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.subjectsegmenter;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmentation;\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmentationResult;\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmenter;\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmenterOptions;\n\n/** A processor to run Subject Segmenter. */\n@RequiresApi(Build.VERSION_CODES.N)\npublic class SubjectSegmenterProcessor extends VisionProcessorBase<SubjectSegmentationResult> {\n\n  private static final String TAG = \"SbjSegmenterProcessor\";\n\n  private final SubjectSegmenter subjectSegmenter;\n  private int imageWidth;\n  private int imageHeight;\n\n  public SubjectSegmenterProcessor(Context context) {\n    super(context);\n    subjectSegmenter =\n        SubjectSegmentation.getClient(\n            new SubjectSegmenterOptions.Builder()\n                .enableMultipleSubjects(\n                    new SubjectSegmenterOptions.SubjectResultOptions.Builder()\n                        .enableConfidenceMask()\n                        .build())\n                .build());\n\n    Log.d(TAG, \"SubjectSegmenterProcessor created\");\n  }\n\n  @Override\n  protected Task<SubjectSegmentationResult> detectInImage(InputImage image) {\n    this.imageWidth = image.getWidth();\n    this.imageHeight = image.getHeight();\n    return subjectSegmenter.process(image);\n  }\n\n  @Override\n  protected void onSuccess(\n      @NonNull SubjectSegmentationResult segmentationResult,\n      @NonNull GraphicOverlay graphicOverlay) {\n    graphicOverlay.add(\n        new SubjectSegmentationGraphic(\n            graphicOverlay, segmentationResult, imageWidth, imageHeight));\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.e(TAG, \"Subject segmentation failed: \", e);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/textdetector/TextGraphic.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.textdetector;\n\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.util.Log;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic;\nimport com.google.mlkit.vision.text.Text;\nimport com.google.mlkit.vision.text.Text.Element;\nimport com.google.mlkit.vision.text.Text.Line;\nimport com.google.mlkit.vision.text.Text.Symbol;\nimport com.google.mlkit.vision.text.Text.TextBlock;\nimport java.util.Arrays;\nimport java.util.Locale;\n\n/**\n * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic\n * overlay view.\n */\npublic class TextGraphic extends Graphic {\n\n  private static final String TAG = \"TextGraphic\";\n  private static final String TEXT_WITH_LANGUAGE_TAG_FORMAT = \"%s:%s\";\n\n  private static final int TEXT_COLOR = Color.BLACK;\n  private static final int MARKER_COLOR = Color.WHITE;\n  private static final float TEXT_SIZE = 54.0f;\n  private static final float STROKE_WIDTH = 4.0f;\n\n  private final Paint rectPaint;\n  private final Paint textPaint;\n  private final Paint labelPaint;\n  private final Text text;\n  private final boolean shouldGroupTextInBlocks;\n  private final boolean showLanguageTag;\n  private final boolean showConfidence;\n\n  TextGraphic(\n      GraphicOverlay overlay,\n      Text text,\n      boolean shouldGroupTextInBlocks,\n      boolean showLanguageTag,\n      boolean showConfidence) {\n    super(overlay);\n\n    this.text = text;\n    this.shouldGroupTextInBlocks = shouldGroupTextInBlocks;\n    this.showLanguageTag = showLanguageTag;\n    this.showConfidence = showConfidence;\n\n    rectPaint = new Paint();\n    rectPaint.setColor(MARKER_COLOR);\n    rectPaint.setStyle(Paint.Style.STROKE);\n    rectPaint.setStrokeWidth(STROKE_WIDTH);\n\n    textPaint = new Paint();\n    textPaint.setColor(TEXT_COLOR);\n    textPaint.setTextSize(TEXT_SIZE);\n\n    labelPaint = new Paint();\n    labelPaint.setColor(MARKER_COLOR);\n    labelPaint.setStyle(Paint.Style.FILL);\n    // Redraw the overlay, as this graphic has been added.\n    postInvalidate();\n  }\n\n  /** Draws the text block annotations for position, size, and raw value on the supplied canvas. */\n  @Override\n  public void draw(Canvas canvas) {\n    Log.d(TAG, \"Text is: \" + text.getText());\n    for (TextBlock textBlock : text.getTextBlocks()) {\n      // Renders the text at the bottom of the box.\n      Log.d(TAG, \"TextBlock text is: \" + textBlock.getText());\n      Log.d(TAG, \"TextBlock boundingbox is: \" + textBlock.getBoundingBox());\n      Log.d(TAG, \"TextBlock cornerpoint is: \" + Arrays.toString(textBlock.getCornerPoints()));\n      if (shouldGroupTextInBlocks) {\n        String text =\n            showLanguageTag\n                ? String.format(\n                    TEXT_WITH_LANGUAGE_TAG_FORMAT,\n                    textBlock.getRecognizedLanguage(),\n                    textBlock.getText())\n                : textBlock.getText();\n        drawText(\n            text,\n            new RectF(textBlock.getBoundingBox()),\n            TEXT_SIZE * textBlock.getLines().size() + 2 * STROKE_WIDTH,\n            canvas);\n      } else {\n        for (Line line : textBlock.getLines()) {\n          Log.d(TAG, \"Line text is: \" + line.getText());\n          Log.d(TAG, \"Line boundingbox is: \" + line.getBoundingBox());\n          Log.d(TAG, \"Line cornerpoint is: \" + Arrays.toString(line.getCornerPoints()));\n          Log.d(TAG, \"Line confidence is: \" + line.getConfidence());\n          Log.d(TAG, \"Line angle is: \" + line.getAngle());\n          String text =\n              showLanguageTag\n                  ? String.format(\n                      TEXT_WITH_LANGUAGE_TAG_FORMAT, line.getRecognizedLanguage(), line.getText())\n                  : line.getText();\n          text =\n              showConfidence\n                  ? String.format(Locale.US, \"%s (%.2f)\", text, line.getConfidence())\n                  : text;\n          drawText(text, new RectF(line.getBoundingBox()), TEXT_SIZE + 2 * STROKE_WIDTH, canvas);\n\n          for (Element element : line.getElements()) {\n            Log.d(TAG, \"Element text is: \" + element.getText());\n            Log.d(TAG, \"Element boundingbox is: \" + element.getBoundingBox());\n            Log.d(TAG, \"Element cornerpoint is: \" + Arrays.toString(element.getCornerPoints()));\n            Log.d(TAG, \"Element language is: \" + element.getRecognizedLanguage());\n            Log.d(TAG, \"Element confidence is: \" + element.getConfidence());\n            Log.d(TAG, \"Element angle is: \" + element.getAngle());\n            for (Symbol symbol : element.getSymbols()) {\n              Log.d(TAG, \"Symbol text is: \" + symbol.getText());\n              Log.d(TAG, \"Symbol boundingbox is: \" + symbol.getBoundingBox());\n              Log.d(TAG, \"Symbol cornerpoint is: \" + Arrays.toString(symbol.getCornerPoints()));\n              Log.d(TAG, \"Symbol confidence is: \" + symbol.getConfidence());\n              Log.d(TAG, \"Symbol angle is: \" + symbol.getAngle());\n            }\n          }\n        }\n      }\n    }\n  }\n\n  private void drawText(String text, RectF rect, float textHeight, Canvas canvas) {\n    // If the image is flipped, the left will be translated to right, and the right to left.\n    float x0 = translateX(rect.left);\n    float x1 = translateX(rect.right);\n    rect.left = min(x0, x1);\n    rect.right = max(x0, x1);\n    rect.top = translateY(rect.top);\n    rect.bottom = translateY(rect.bottom);\n    canvas.drawRect(rect, rectPaint);\n    float textWidth = textPaint.measureText(text);\n    canvas.drawRect(\n        rect.left - STROKE_WIDTH,\n        rect.top - textHeight,\n        rect.left + textWidth + 2 * STROKE_WIDTH,\n        rect.top,\n        labelPaint);\n    // Renders the text at the bottom of the box.\n    canvas.drawText(text, rect.left, rect.top - STROKE_WIDTH, textPaint);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/textdetector/TextRecognitionProcessor.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.java.textdetector;\n\nimport android.content.Context;\nimport android.graphics.Point;\nimport android.util.Log;\nimport androidx.annotation.NonNull;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.google.mlkit.vision.demo.GraphicOverlay;\nimport com.google.mlkit.vision.demo.java.VisionProcessorBase;\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils;\nimport com.google.mlkit.vision.text.Text;\nimport com.google.mlkit.vision.text.Text.Element;\nimport com.google.mlkit.vision.text.Text.Line;\nimport com.google.mlkit.vision.text.TextRecognition;\nimport com.google.mlkit.vision.text.TextRecognizer;\nimport com.google.mlkit.vision.text.TextRecognizerOptionsInterface;\nimport java.util.List;\n\n/** Processor for the text detector demo. */\npublic class TextRecognitionProcessor extends VisionProcessorBase<Text> {\n\n  private static final String TAG = \"TextRecProcessor\";\n\n  private final TextRecognizer textRecognizer;\n  private final Boolean shouldGroupRecognizedTextInBlocks;\n  private final Boolean showLanguageTag;\n  private final boolean showConfidence;\n\n  public TextRecognitionProcessor(\n      Context context, TextRecognizerOptionsInterface textRecognizerOptions) {\n    super(context);\n    shouldGroupRecognizedTextInBlocks = PreferenceUtils.shouldGroupRecognizedTextInBlocks(context);\n    showLanguageTag = PreferenceUtils.showLanguageTag(context);\n    showConfidence = PreferenceUtils.shouldShowTextConfidence(context);\n    textRecognizer = TextRecognition.getClient(textRecognizerOptions);\n  }\n\n  @Override\n  public void stop() {\n    super.stop();\n    textRecognizer.close();\n  }\n\n  @Override\n  protected Task<Text> detectInImage(InputImage image) {\n    return textRecognizer.process(image);\n  }\n\n  @Override\n  protected void onSuccess(@NonNull Text text, @NonNull GraphicOverlay graphicOverlay) {\n    Log.d(TAG, \"On-device Text detection successful\");\n    logExtrasForTesting(text);\n    graphicOverlay.add(\n        new TextGraphic(\n            graphicOverlay,\n            text,\n            shouldGroupRecognizedTextInBlocks,\n            showLanguageTag,\n            showConfidence));\n  }\n\n  private static void logExtrasForTesting(Text text) {\n    if (text != null) {\n      Log.v(MANUAL_TESTING_LOG, \"Detected text has : \" + text.getTextBlocks().size() + \" blocks\");\n      for (int i = 0; i < text.getTextBlocks().size(); ++i) {\n        List<Line> lines = text.getTextBlocks().get(i).getLines();\n        Log.v(\n            MANUAL_TESTING_LOG,\n            String.format(\"Detected text block %d has %d lines\", i, lines.size()));\n        for (int j = 0; j < lines.size(); ++j) {\n          List<Element> elements = lines.get(j).getElements();\n          Log.v(\n              MANUAL_TESTING_LOG,\n              String.format(\"Detected text line %d has %d elements\", j, elements.size()));\n          for (int k = 0; k < elements.size(); ++k) {\n            Element element = elements.get(k);\n            Log.v(\n                MANUAL_TESTING_LOG,\n                String.format(\"Detected text element %d says: %s\", k, element.getText()));\n            Log.v(\n                MANUAL_TESTING_LOG,\n                String.format(\n                    \"Detected text element %d has a bounding box: %s\",\n                    k, element.getBoundingBox().flattenToString()));\n            Log.v(\n                MANUAL_TESTING_LOG,\n                String.format(\n                    \"Expected corner point size is 4, get %d\", element.getCornerPoints().length));\n            for (Point point : element.getCornerPoints()) {\n              Log.v(\n                  MANUAL_TESTING_LOG,\n                  String.format(\n                      \"Corner point for element %d is located at: x - %d, y = %d\",\n                      k, point.x, point.y));\n            }\n          }\n        }\n      }\n    }\n  }\n\n  @Override\n  protected void onFailure(@NonNull Exception e) {\n    Log.w(TAG, \"Text detection failed.\" + e);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/CameraXLivePreviewActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin\n\nimport android.content.Intent\nimport android.os.Build.VERSION_CODES\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.view.View\nimport android.widget.AdapterView\nimport android.widget.AdapterView.OnItemSelectedListener\nimport android.widget.ArrayAdapter\nimport android.widget.CompoundButton\nimport android.widget.ImageView\nimport android.widget.Spinner\nimport android.widget.Toast\nimport android.widget.ToggleButton\nimport androidx.annotation.RequiresApi\nimport androidx.camera.core.Camera\nimport androidx.camera.core.CameraInfoUnavailableException\nimport androidx.camera.core.CameraSelector\nimport androidx.camera.core.ImageAnalysis\nimport androidx.camera.core.ImageProxy\nimport androidx.camera.core.Preview\nimport androidx.camera.lifecycle.ProcessCameraProvider\nimport androidx.camera.view.PreviewView\nimport androidx.core.content.ContextCompat\nimport androidx.lifecycle.Observer\nimport androidx.lifecycle.ViewModelProvider\nimport com.google.android.gms.common.annotation.KeepName\nimport com.google.mlkit.common.MlKitException\nimport com.google.mlkit.common.model.LocalModel\nimport com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback\nimport com.google.mlkit.vision.demo.CameraXViewModel\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.R\nimport com.google.mlkit.vision.demo.VisionImageProcessor\nimport com.google.mlkit.vision.demo.kotlin.barcodescanner.BarcodeScannerProcessor\nimport com.google.mlkit.vision.demo.kotlin.facedetector.FaceDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.facemeshdetector.FaceMeshDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.labeldetector.LabelDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.objectdetector.ObjectDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.posedetector.PoseDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.segmenter.SegmenterProcessor\nimport com.google.mlkit.vision.demo.kotlin.textdetector.TextRecognitionProcessor\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport com.google.mlkit.vision.demo.preference.SettingsActivity\nimport com.google.mlkit.vision.demo.preference.SettingsActivity.LaunchSource\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions\nimport com.google.mlkit.vision.label.defaults.ImageLabelerOptions\nimport com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions\nimport com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions\nimport com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions\nimport com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions\n\n/** Live preview demo app for ML Kit APIs using CameraX. */\n@KeepName\n@RequiresApi(VERSION_CODES.LOLLIPOP)\nclass CameraXLivePreviewActivity :\n  AppCompatActivity(), OnItemSelectedListener, CompoundButton.OnCheckedChangeListener {\n\n  private var previewView: PreviewView? = null\n  private var graphicOverlay: GraphicOverlay? = null\n  private var cameraProvider: ProcessCameraProvider? = null\n  private var camera: Camera? = null\n  private var previewUseCase: Preview? = null\n  private var analysisUseCase: ImageAnalysis? = null\n  private var imageProcessor: VisionImageProcessor? = null\n  private var needUpdateGraphicOverlayImageSourceInfo = false\n  private var selectedModel = OBJECT_DETECTION\n  private var lensFacing = CameraSelector.LENS_FACING_BACK\n  private var cameraSelector: CameraSelector? = null\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    Log.d(TAG, \"onCreate\")\n    if (savedInstanceState != null) {\n      selectedModel = savedInstanceState.getString(STATE_SELECTED_MODEL, OBJECT_DETECTION)\n    }\n    cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()\n    setContentView(R.layout.activity_vision_camerax_live_preview)\n    previewView = findViewById(R.id.preview_view)\n    if (previewView == null) {\n      Log.d(TAG, \"previewView is null\")\n    }\n    graphicOverlay = findViewById(R.id.graphic_overlay)\n    if (graphicOverlay == null) {\n      Log.d(TAG, \"graphicOverlay is null\")\n    }\n    val spinner = findViewById<Spinner>(R.id.spinner)\n    val options: MutableList<String> = ArrayList()\n    options.add(OBJECT_DETECTION)\n    options.add(OBJECT_DETECTION_CUSTOM)\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION)\n    options.add(FACE_DETECTION)\n    options.add(BARCODE_SCANNING)\n    options.add(IMAGE_LABELING)\n    options.add(IMAGE_LABELING_CUSTOM)\n    options.add(CUSTOM_AUTOML_LABELING)\n    options.add(POSE_DETECTION)\n    options.add(SELFIE_SEGMENTATION)\n    options.add(TEXT_RECOGNITION_LATIN)\n    options.add(TEXT_RECOGNITION_CHINESE)\n    options.add(TEXT_RECOGNITION_DEVANAGARI)\n    options.add(TEXT_RECOGNITION_JAPANESE)\n    options.add(TEXT_RECOGNITION_KOREAN)\n    options.add(FACE_MESH_DETECTION)\n\n    // Creating adapter for spinner\n    val dataAdapter = ArrayAdapter(this, R.layout.spinner_style, options)\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n    // attaching data adapter to spinner\n    spinner.adapter = dataAdapter\n    spinner.onItemSelectedListener = this\n    val facingSwitch = findViewById<ToggleButton>(R.id.facing_switch)\n    facingSwitch.setOnCheckedChangeListener(this)\n    ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(application))\n      .get(CameraXViewModel::class.java)\n      .processCameraProvider\n      .observe(\n        this,\n        Observer { provider: ProcessCameraProvider? ->\n          cameraProvider = provider\n          bindAllCameraUseCases()\n        },\n      )\n\n    val settingsButton = findViewById<ImageView>(R.id.settings_button)\n    settingsButton.setOnClickListener {\n      val intent = Intent(applicationContext, SettingsActivity::class.java)\n      intent.putExtra(SettingsActivity.EXTRA_LAUNCH_SOURCE, LaunchSource.CAMERAX_LIVE_PREVIEW)\n      startActivity(intent)\n    }\n  }\n\n  override fun onSaveInstanceState(bundle: Bundle) {\n    super.onSaveInstanceState(bundle)\n    bundle.putString(STATE_SELECTED_MODEL, selectedModel)\n  }\n\n  @Synchronized\n  override fun onItemSelected(parent: AdapterView<*>?, view: View?, pos: Int, id: Long) {\n    // An item was selected. You can retrieve the selected item using\n    // parent.getItemAtPosition(pos)\n    selectedModel = parent?.getItemAtPosition(pos).toString()\n    Log.d(TAG, \"Selected model: $selectedModel\")\n    bindAnalysisUseCase()\n  }\n\n  override fun onNothingSelected(parent: AdapterView<*>?) {\n    // Do nothing.\n  }\n\n  override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {\n    if (cameraProvider == null) {\n      return\n    }\n    val newLensFacing =\n      if (lensFacing == CameraSelector.LENS_FACING_FRONT) {\n        CameraSelector.LENS_FACING_BACK\n      } else {\n        CameraSelector.LENS_FACING_FRONT\n      }\n    val newCameraSelector = CameraSelector.Builder().requireLensFacing(newLensFacing).build()\n    try {\n      if (cameraProvider!!.hasCamera(newCameraSelector)) {\n        Log.d(TAG, \"Set facing to \" + newLensFacing)\n        lensFacing = newLensFacing\n        cameraSelector = newCameraSelector\n        bindAllCameraUseCases()\n        return\n      }\n    } catch (e: CameraInfoUnavailableException) {\n      // Falls through\n    }\n    Toast.makeText(\n        applicationContext,\n        \"This device does not have lens with facing: $newLensFacing\",\n        Toast.LENGTH_SHORT,\n      )\n      .show()\n  }\n\n  public override fun onResume() {\n    super.onResume()\n    bindAllCameraUseCases()\n  }\n\n  override fun onPause() {\n    super.onPause()\n\n    imageProcessor?.run { this.stop() }\n  }\n\n  public override fun onDestroy() {\n    super.onDestroy()\n    imageProcessor?.run { this.stop() }\n  }\n\n  private fun bindAllCameraUseCases() {\n    if (cameraProvider != null) {\n      // As required by CameraX API, unbinds all use cases before trying to re-bind any of them.\n      cameraProvider!!.unbindAll()\n      bindPreviewUseCase()\n      bindAnalysisUseCase()\n    }\n  }\n\n  private fun bindPreviewUseCase() {\n    if (!PreferenceUtils.isCameraLiveViewportEnabled(this)) {\n      return\n    }\n    if (cameraProvider == null) {\n      return\n    }\n    if (previewUseCase != null) {\n      cameraProvider!!.unbind(previewUseCase)\n    }\n\n    val builder = Preview.Builder()\n    val targetResolution = PreferenceUtils.getCameraXTargetResolution(this, lensFacing)\n    if (targetResolution != null) {\n      builder.setTargetResolution(targetResolution)\n    }\n    previewUseCase = builder.build()\n    previewUseCase!!.setSurfaceProvider(previewView!!.getSurfaceProvider())\n    camera = cameraProvider!!.bindToLifecycle(this, cameraSelector!!, previewUseCase)\n  }\n\n  private fun bindAnalysisUseCase() {\n    if (cameraProvider == null) {\n      return\n    }\n    if (analysisUseCase != null) {\n      cameraProvider!!.unbind(analysisUseCase)\n    }\n    if (imageProcessor != null) {\n      imageProcessor!!.stop()\n    }\n    imageProcessor =\n      try {\n        when (selectedModel) {\n          OBJECT_DETECTION -> {\n            Log.i(TAG, \"Using Object Detector Processor\")\n            val objectDetectorOptions = PreferenceUtils.getObjectDetectorOptionsForLivePreview(this)\n            ObjectDetectorProcessor(this, objectDetectorOptions)\n          }\n          OBJECT_DETECTION_CUSTOM -> {\n            Log.i(TAG, \"Using Custom Object Detector (with object labeler) Processor\")\n            val localModel =\n              LocalModel.Builder().setAssetFilePath(\"custom_models/object_labeler.tflite\").build()\n            val customObjectDetectorOptions =\n              PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(this, localModel)\n            ObjectDetectorProcessor(this, customObjectDetectorOptions)\n          }\n          CUSTOM_AUTOML_OBJECT_DETECTION -> {\n            Log.i(TAG, \"Using Custom AutoML Object Detector Processor\")\n            val customAutoMLODTLocalModel =\n              LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build()\n            val customAutoMLODTOptions =\n              PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(\n                this,\n                customAutoMLODTLocalModel,\n              )\n            ObjectDetectorProcessor(this, customAutoMLODTOptions)\n          }\n          TEXT_RECOGNITION_LATIN -> {\n            Log.i(TAG, \"Using on-device Text recognition Processor for Latin\")\n            TextRecognitionProcessor(this, TextRecognizerOptions.Builder().build())\n          }\n          TEXT_RECOGNITION_CHINESE -> {\n            Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Chinese\")\n            TextRecognitionProcessor(this, ChineseTextRecognizerOptions.Builder().build())\n          }\n          TEXT_RECOGNITION_DEVANAGARI -> {\n            Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Devanagari\")\n            TextRecognitionProcessor(this, DevanagariTextRecognizerOptions.Builder().build())\n          }\n          TEXT_RECOGNITION_JAPANESE -> {\n            Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Japanese\")\n            TextRecognitionProcessor(this, JapaneseTextRecognizerOptions.Builder().build())\n          }\n          TEXT_RECOGNITION_KOREAN -> {\n            Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Korean\")\n            TextRecognitionProcessor(this, KoreanTextRecognizerOptions.Builder().build())\n          }\n          FACE_DETECTION -> {\n            Log.i(TAG, \"Using Face Detector Processor\")\n            val faceDetectorOptions = PreferenceUtils.getFaceDetectorOptions(this)\n            FaceDetectorProcessor(this, faceDetectorOptions)\n          }\n          BARCODE_SCANNING -> {\n            Log.i(TAG, \"Using Barcode Detector Processor\")\n            var zoomCallback: ZoomCallback? = null\n            if (PreferenceUtils.shouldEnableAutoZoom(this)) {\n              zoomCallback = ZoomCallback { zoomLevel: Float ->\n                Log.i(TAG, \"Set zoom ratio $zoomLevel\")\n                val ignored = camera!!.cameraControl.setZoomRatio(zoomLevel)\n                true\n              }\n            }\n            BarcodeScannerProcessor(this, zoomCallback)\n          }\n          IMAGE_LABELING -> {\n            Log.i(TAG, \"Using Image Label Detector Processor\")\n            LabelDetectorProcessor(this, ImageLabelerOptions.DEFAULT_OPTIONS)\n          }\n          IMAGE_LABELING_CUSTOM -> {\n            Log.i(TAG, \"Using Custom Image Label (Birds) Detector Processor\")\n            val localClassifier =\n              LocalModel.Builder().setAssetFilePath(\"custom_models/bird_classifier.tflite\").build()\n            val customImageLabelerOptions =\n              CustomImageLabelerOptions.Builder(localClassifier).build()\n            LabelDetectorProcessor(this, customImageLabelerOptions)\n          }\n          CUSTOM_AUTOML_LABELING -> {\n            Log.i(TAG, \"Using Custom AutoML Image Label Detector Processor\")\n            val customAutoMLLabelLocalModel =\n              LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build()\n            val customAutoMLLabelOptions =\n              CustomImageLabelerOptions.Builder(customAutoMLLabelLocalModel)\n                .setConfidenceThreshold(0f)\n                .build()\n            LabelDetectorProcessor(this, customAutoMLLabelOptions)\n          }\n          POSE_DETECTION -> {\n            val poseDetectorOptions = PreferenceUtils.getPoseDetectorOptionsForLivePreview(this)\n            val shouldShowInFrameLikelihood =\n              PreferenceUtils.shouldShowPoseDetectionInFrameLikelihoodLivePreview(this)\n            val visualizeZ = PreferenceUtils.shouldPoseDetectionVisualizeZ(this)\n            val rescaleZ = PreferenceUtils.shouldPoseDetectionRescaleZForVisualization(this)\n            val runClassification = PreferenceUtils.shouldPoseDetectionRunClassification(this)\n            PoseDetectorProcessor(\n              this,\n              poseDetectorOptions,\n              shouldShowInFrameLikelihood,\n              visualizeZ,\n              rescaleZ,\n              runClassification,\n              /* isStreamMode = */ true,\n            )\n          }\n          SELFIE_SEGMENTATION -> SegmenterProcessor(this)\n          FACE_MESH_DETECTION -> FaceMeshDetectorProcessor(this)\n          else -> throw IllegalStateException(\"Invalid model name\")\n        }\n      } catch (e: Exception) {\n        Log.e(TAG, \"Can not create image processor: $selectedModel\", e)\n        Toast.makeText(\n            applicationContext,\n            \"Can not create image processor: \" + e.localizedMessage,\n            Toast.LENGTH_LONG,\n          )\n          .show()\n        return\n      }\n\n    val builder = ImageAnalysis.Builder()\n    val targetResolution = PreferenceUtils.getCameraXTargetResolution(this, lensFacing)\n    if (targetResolution != null) {\n      builder.setTargetResolution(targetResolution)\n    }\n    analysisUseCase = builder.build()\n\n    needUpdateGraphicOverlayImageSourceInfo = true\n\n    analysisUseCase?.setAnalyzer(\n      // imageProcessor.processImageProxy will use another thread to run the detection underneath,\n      // thus we can just runs the analyzer itself on main thread.\n      ContextCompat.getMainExecutor(this),\n      ImageAnalysis.Analyzer { imageProxy: ImageProxy ->\n        if (needUpdateGraphicOverlayImageSourceInfo) {\n          val isImageFlipped = lensFacing == CameraSelector.LENS_FACING_FRONT\n          val rotationDegrees = imageProxy.imageInfo.rotationDegrees\n          if (rotationDegrees == 0 || rotationDegrees == 180) {\n            graphicOverlay!!.setImageSourceInfo(imageProxy.width, imageProxy.height, isImageFlipped)\n          } else {\n            graphicOverlay!!.setImageSourceInfo(imageProxy.height, imageProxy.width, isImageFlipped)\n          }\n          needUpdateGraphicOverlayImageSourceInfo = false\n        }\n        try {\n          imageProcessor!!.processImageProxy(imageProxy, graphicOverlay)\n        } catch (e: MlKitException) {\n          Log.e(TAG, \"Failed to process image. Error: \" + e.localizedMessage)\n          Toast.makeText(applicationContext, e.localizedMessage, Toast.LENGTH_SHORT).show()\n        }\n      },\n    )\n    cameraProvider!!.bindToLifecycle(this, cameraSelector!!, analysisUseCase)\n  }\n\n  companion object {\n    private const val TAG = \"CameraXLivePreview\"\n    private const val OBJECT_DETECTION = \"Object Detection\"\n    private const val OBJECT_DETECTION_CUSTOM = \"Custom Object Detection\"\n    private const val CUSTOM_AUTOML_OBJECT_DETECTION = \"Custom AutoML Object Detection (Flower)\"\n    private const val FACE_DETECTION = \"Face Detection\"\n    private const val TEXT_RECOGNITION_LATIN = \"Text Recognition Latin\"\n    private const val TEXT_RECOGNITION_CHINESE = \"Text Recognition Chinese\"\n    private const val TEXT_RECOGNITION_DEVANAGARI = \"Text Recognition Devanagari\"\n    private const val TEXT_RECOGNITION_JAPANESE = \"Text Recognition Japanese\"\n    private const val TEXT_RECOGNITION_KOREAN = \"Text Recognition Korean\"\n    private const val BARCODE_SCANNING = \"Barcode Scanning\"\n    private const val IMAGE_LABELING = \"Image Labeling\"\n    private const val IMAGE_LABELING_CUSTOM = \"Custom Image Labeling (Birds)\"\n    private const val CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling (Flower)\"\n    private const val POSE_DETECTION = \"Pose Detection\"\n    private const val SELFIE_SEGMENTATION = \"Selfie Segmentation\"\n    private const val FACE_MESH_DETECTION = \"Face Mesh Detection (Beta)\"\n\n    private const val STATE_SELECTED_MODEL = \"selected_model\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/CameraXSourceDemoActivity.kt",
    "content": "/*\n * Copyright 2021 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin\n\nimport android.content.Intent\nimport android.content.res.Configuration\nimport android.os.Build.VERSION_CODES\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.util.Size\nimport android.widget.CompoundButton\nimport android.widget.ImageView\nimport android.widget.Toast\nimport android.widget.ToggleButton\nimport androidx.annotation.RequiresApi\nimport androidx.camera.view.PreviewView\nimport com.google.android.gms.common.annotation.KeepName\nimport com.google.mlkit.common.model.LocalModel\nimport com.google.mlkit.vision.camera.CameraSourceConfig\nimport com.google.mlkit.vision.camera.CameraXSource\nimport com.google.mlkit.vision.camera.DetectionTaskCallback\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.InferenceInfoGraphic\nimport com.google.mlkit.vision.demo.R\nimport com.google.mlkit.vision.demo.kotlin.objectdetector.ObjectGraphic\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport com.google.mlkit.vision.demo.preference.SettingsActivity\nimport com.google.mlkit.vision.demo.preference.SettingsActivity.LaunchSource\nimport com.google.mlkit.vision.objects.DetectedObject\nimport com.google.mlkit.vision.objects.ObjectDetection\nimport com.google.mlkit.vision.objects.ObjectDetector\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions\nimport java.util.Objects\nimport kotlin.collections.List\n\n/** Live preview demo app for ML Kit APIs using CameraXSource API. */\n@KeepName\n@RequiresApi(VERSION_CODES.LOLLIPOP)\nclass CameraXSourceDemoActivity : AppCompatActivity(), CompoundButton.OnCheckedChangeListener {\n  private var previewView: PreviewView? = null\n  private var graphicOverlay: GraphicOverlay? = null\n  private var needUpdateGraphicOverlayImageSourceInfo = false\n  private var lensFacing: Int = CameraSourceConfig.CAMERA_FACING_BACK\n  private var cameraXSource: CameraXSource? = null\n  private var customObjectDetectorOptions: CustomObjectDetectorOptions? = null\n  private var targetResolution: Size? = null\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    Log.d(TAG, \"onCreate\")\n    setContentView(R.layout.activity_vision_cameraxsource_demo)\n    previewView = findViewById(R.id.preview_view)\n    if (previewView == null) {\n      Log.d(TAG, \"previewView is null\")\n    }\n    graphicOverlay = findViewById(R.id.graphic_overlay)\n    if (graphicOverlay == null) {\n      Log.d(TAG, \"graphicOverlay is null\")\n    }\n    val facingSwitch = findViewById<ToggleButton>(R.id.facing_switch)\n    facingSwitch.setOnCheckedChangeListener(this)\n    val settingsButton = findViewById<ImageView>(R.id.settings_button)\n    settingsButton.setOnClickListener {\n      val intent = Intent(applicationContext, SettingsActivity::class.java)\n      intent.putExtra(SettingsActivity.EXTRA_LAUNCH_SOURCE, LaunchSource.CAMERAXSOURCE_DEMO)\n      startActivity(intent)\n    }\n  }\n\n  override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {\n    if (lensFacing == CameraSourceConfig.CAMERA_FACING_FRONT) {\n      lensFacing = CameraSourceConfig.CAMERA_FACING_BACK\n    } else {\n      lensFacing = CameraSourceConfig.CAMERA_FACING_FRONT\n    }\n    createThenStartCameraXSource()\n  }\n\n  public override fun onResume() {\n    super.onResume()\n    if (cameraXSource != null &&\n        PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(this, localModel)\n          .equals(customObjectDetectorOptions) &&\n        PreferenceUtils.getCameraXTargetResolution(getApplicationContext(), lensFacing) != null &&\n        (Objects.requireNonNull(\n          PreferenceUtils.getCameraXTargetResolution(getApplicationContext(), lensFacing)\n        ) == targetResolution)\n    ) {\n      cameraXSource!!.start()\n    } else {\n      createThenStartCameraXSource()\n    }\n  }\n\n  override fun onPause() {\n    super.onPause()\n    if (cameraXSource != null) {\n      cameraXSource!!.stop()\n    }\n  }\n\n  override fun onDestroy() {\n    super.onDestroy()\n    if (cameraXSource != null) {\n      cameraXSource!!.stop()\n    }\n  }\n\n  private fun createThenStartCameraXSource() {\n    if (cameraXSource != null) {\n      cameraXSource!!.close()\n    }\n    customObjectDetectorOptions =\n      PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(\n        getApplicationContext(),\n        localModel\n      )\n    val objectDetector: ObjectDetector = ObjectDetection.getClient(customObjectDetectorOptions!!)\n    var detectionTaskCallback: DetectionTaskCallback<List<DetectedObject>> =\n      DetectionTaskCallback<List<DetectedObject>> { detectionTask ->\n        detectionTask\n          .addOnSuccessListener { results -> onDetectionTaskSuccess(results) }\n          .addOnFailureListener { e -> onDetectionTaskFailure(e) }\n      }\n    val builder: CameraSourceConfig.Builder =\n      CameraSourceConfig.Builder(getApplicationContext(), objectDetector!!, detectionTaskCallback)\n        .setFacing(lensFacing)\n    targetResolution =\n      PreferenceUtils.getCameraXTargetResolution(getApplicationContext(), lensFacing)\n    if (targetResolution != null) {\n      builder.setRequestedPreviewSize(targetResolution!!.width, targetResolution!!.height)\n    }\n    cameraXSource = CameraXSource(builder.build(), previewView!!)\n    needUpdateGraphicOverlayImageSourceInfo = true\n    cameraXSource!!.start()\n  }\n\n  private fun onDetectionTaskSuccess(results: List<DetectedObject>) {\n    graphicOverlay!!.clear()\n    if (needUpdateGraphicOverlayImageSourceInfo) {\n      val size: Size = cameraXSource!!.getPreviewSize()!!\n      if (size != null) {\n        Log.d(TAG, \"preview width: \" + size.width)\n        Log.d(TAG, \"preview height: \" + size.height)\n        val isImageFlipped =\n          cameraXSource!!.getCameraFacing() == CameraSourceConfig.CAMERA_FACING_FRONT\n        if (isPortraitMode) {\n          // Swap width and height sizes when in portrait, since it will be rotated by\n          // 90 degrees. The camera preview and the image being processed have the same size.\n          graphicOverlay!!.setImageSourceInfo(size.height, size.width, isImageFlipped)\n        } else {\n          graphicOverlay!!.setImageSourceInfo(size.width, size.height, isImageFlipped)\n        }\n        needUpdateGraphicOverlayImageSourceInfo = false\n      } else {\n        Log.d(TAG, \"previewsize is null\")\n      }\n    }\n    Log.v(TAG, \"Number of object been detected: \" + results.size)\n    for (`object` in results) {\n      graphicOverlay!!.add(ObjectGraphic(graphicOverlay!!, `object`))\n    }\n    graphicOverlay!!.add(InferenceInfoGraphic(graphicOverlay!!))\n    graphicOverlay!!.postInvalidate()\n  }\n\n  private fun onDetectionTaskFailure(e: Exception) {\n    graphicOverlay!!.clear()\n    graphicOverlay!!.postInvalidate()\n    val error = \"Failed to process. Error: \" + e.localizedMessage\n    Toast.makeText(\n        graphicOverlay!!.getContext(),\n        \"\"\"\n   $error\n   Cause: ${e.cause}\n      \"\"\".trimIndent(),\n        Toast.LENGTH_SHORT\n      )\n      .show()\n    Log.d(TAG, error)\n  }\n\n  private val isPortraitMode: Boolean\n    private get() =\n      (getApplicationContext().getResources().getConfiguration().orientation !==\n        Configuration.ORIENTATION_LANDSCAPE)\n\n  companion object {\n    private const val TAG = \"CameraXSourcePreview\"\n    private val localModel: LocalModel =\n      LocalModel.Builder().setAssetFilePath(\"custom_models/object_labeler.tflite\").build()\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/ChooserActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build.VERSION\nimport android.os.Build.VERSION_CODES\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.AdapterView\nimport android.widget.AdapterView.OnItemClickListener\nimport android.widget.ArrayAdapter\nimport android.widget.ListView\nimport android.widget.TextView\nimport androidx.core.app.ActivityCompat\nimport com.google.mlkit.vision.demo.R\n\n/** Demo app chooser which allows you pick from all available testing Activities. */\nclass ChooserActivity :\n  AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback, OnItemClickListener {\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    Log.d(TAG, \"onCreate\")\n    setContentView(R.layout.activity_chooser)\n\n    // Set up ListView and Adapter\n    val listView = findViewById<ListView>(R.id.test_activity_list_view)\n    val adapter = MyArrayAdapter(this, android.R.layout.simple_list_item_2, CLASSES)\n    adapter.setDescriptionIds(DESCRIPTION_IDS)\n    listView.adapter = adapter\n    listView.onItemClickListener = this\n  }\n\n  override fun onItemClick(parent: AdapterView<*>?, view: View, position: Int, id: Long) {\n    val clicked = CLASSES[position]\n    startActivity(Intent(this, clicked))\n  }\n\n  private class MyArrayAdapter(\n    private val ctx: Context,\n    resource: Int,\n    private val classes: Array<Class<*>>\n  ) : ArrayAdapter<Class<*>>(ctx, resource, classes) {\n    private var descriptionIds: IntArray? = null\n\n    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {\n      var view = convertView\n\n      if (convertView == null) {\n        val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater\n        view = inflater.inflate(android.R.layout.simple_list_item_2, null)\n      }\n\n      (view!!.findViewById<View>(android.R.id.text1) as TextView).text =\n        classes[position].simpleName\n      descriptionIds?.let {\n        (view.findViewById<View>(android.R.id.text2) as TextView).setText(it[position])\n      }\n\n      return view\n    }\n\n    fun setDescriptionIds(descriptionIds: IntArray) {\n      this.descriptionIds = descriptionIds\n    }\n  }\n\n  companion object {\n    private const val TAG = \"ChooserActivity\"\n    private val CLASSES =\n      if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)\n        arrayOf<Class<*>>(\n          LivePreviewActivity::class.java,\n          StillImageActivity::class.java,\n        )\n      else\n        arrayOf<Class<*>>(\n          LivePreviewActivity::class.java,\n          StillImageActivity::class.java,\n          CameraXLivePreviewActivity::class.java,\n          CameraXSourceDemoActivity::class.java\n        )\n    private val DESCRIPTION_IDS =\n      if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)\n        intArrayOf(\n          R.string.desc_camera_source_activity,\n          R.string.desc_still_image_activity,\n        )\n      else\n        intArrayOf(\n          R.string.desc_camera_source_activity,\n          R.string.desc_still_image_activity,\n          R.string.desc_camerax_live_preview_activity,\n          R.string.desc_cameraxsource_demo_activity\n        )\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/LivePreviewActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin\n\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.view.View\nimport android.widget.AdapterView\nimport android.widget.AdapterView.OnItemSelectedListener\nimport android.widget.ArrayAdapter\nimport android.widget.CompoundButton\nimport android.widget.ImageView\nimport android.widget.Spinner\nimport android.widget.Toast\nimport android.widget.ToggleButton\nimport com.google.android.gms.common.annotation.KeepName\nimport com.google.mlkit.common.model.LocalModel\nimport com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback\nimport com.google.mlkit.vision.demo.CameraSource\nimport com.google.mlkit.vision.demo.CameraSourcePreview\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.R\nimport com.google.mlkit.vision.demo.kotlin.barcodescanner.BarcodeScannerProcessor\nimport com.google.mlkit.vision.demo.kotlin.facedetector.FaceDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.facemeshdetector.FaceMeshDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.labeldetector.LabelDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.objectdetector.ObjectDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.posedetector.PoseDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.segmenter.SegmenterProcessor\nimport com.google.mlkit.vision.demo.kotlin.textdetector.TextRecognitionProcessor\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport com.google.mlkit.vision.demo.preference.SettingsActivity\nimport com.google.mlkit.vision.demo.preference.SettingsActivity.LaunchSource\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions\nimport com.google.mlkit.vision.label.defaults.ImageLabelerOptions\nimport com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions\nimport com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions\nimport com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions\nimport com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions\nimport java.io.IOException\n\n/** Live preview demo for ML Kit APIs. */\n@KeepName\nclass LivePreviewActivity :\n  AppCompatActivity(), OnItemSelectedListener, CompoundButton.OnCheckedChangeListener {\n\n  private var cameraSource: CameraSource? = null\n  private var preview: CameraSourcePreview? = null\n  private var graphicOverlay: GraphicOverlay? = null\n  private var selectedModel = OBJECT_DETECTION\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    Log.d(TAG, \"onCreate\")\n    setContentView(R.layout.activity_vision_live_preview)\n\n    preview = findViewById(R.id.preview_view)\n    if (preview == null) {\n      Log.d(TAG, \"Preview is null\")\n    }\n\n    graphicOverlay = findViewById(R.id.graphic_overlay)\n    if (graphicOverlay == null) {\n      Log.d(TAG, \"graphicOverlay is null\")\n    }\n\n    val spinner = findViewById<Spinner>(R.id.spinner)\n    val options: MutableList<String> = ArrayList()\n    options.add(OBJECT_DETECTION)\n    options.add(OBJECT_DETECTION_CUSTOM)\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION)\n    options.add(FACE_DETECTION)\n    options.add(BARCODE_SCANNING)\n    options.add(IMAGE_LABELING)\n    options.add(IMAGE_LABELING_CUSTOM)\n    options.add(CUSTOM_AUTOML_LABELING)\n    options.add(POSE_DETECTION)\n    options.add(SELFIE_SEGMENTATION)\n    options.add(TEXT_RECOGNITION_LATIN)\n    options.add(TEXT_RECOGNITION_CHINESE)\n    options.add(TEXT_RECOGNITION_DEVANAGARI)\n    options.add(TEXT_RECOGNITION_JAPANESE)\n    options.add(TEXT_RECOGNITION_KOREAN)\n    options.add(FACE_MESH_DETECTION)\n\n    // Creating adapter for spinner\n    val dataAdapter = ArrayAdapter(this, R.layout.spinner_style, options)\n\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n    // attaching data adapter to spinner\n    spinner.adapter = dataAdapter\n    spinner.onItemSelectedListener = this\n\n    val facingSwitch = findViewById<ToggleButton>(R.id.facing_switch)\n    facingSwitch.setOnCheckedChangeListener(this)\n\n    val settingsButton = findViewById<ImageView>(R.id.settings_button)\n    settingsButton.setOnClickListener {\n      val intent = Intent(applicationContext, SettingsActivity::class.java)\n      intent.putExtra(SettingsActivity.EXTRA_LAUNCH_SOURCE, LaunchSource.LIVE_PREVIEW)\n      startActivity(intent)\n    }\n\n    createCameraSource(selectedModel)\n  }\n\n  @Synchronized\n  override fun onItemSelected(parent: AdapterView<*>?, view: View?, pos: Int, id: Long) {\n    // An item was selected. You can retrieve the selected item using\n    // parent.getItemAtPosition(pos)\n    selectedModel = parent?.getItemAtPosition(pos).toString()\n    Log.d(TAG, \"Selected model: $selectedModel\")\n    preview?.stop()\n    createCameraSource(selectedModel)\n    startCameraSource()\n  }\n\n  override fun onNothingSelected(parent: AdapterView<*>?) {\n    // Do nothing.\n  }\n\n  override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {\n    Log.d(TAG, \"Set facing\")\n    if (cameraSource != null) {\n      if (isChecked) {\n        cameraSource?.setFacing(CameraSource.CAMERA_FACING_FRONT)\n      } else {\n        cameraSource?.setFacing(CameraSource.CAMERA_FACING_BACK)\n      }\n    }\n    preview?.stop()\n    startCameraSource()\n  }\n\n  private fun createCameraSource(model: String) {\n    // If there's no existing cameraSource, create one.\n    if (cameraSource == null) {\n      cameraSource = CameraSource(this, graphicOverlay)\n    }\n    try {\n      when (model) {\n        OBJECT_DETECTION -> {\n          Log.i(TAG, \"Using Object Detector Processor\")\n          val objectDetectorOptions = PreferenceUtils.getObjectDetectorOptionsForLivePreview(this)\n          cameraSource!!.setMachineLearningFrameProcessor(\n            ObjectDetectorProcessor(this, objectDetectorOptions)\n          )\n        }\n        OBJECT_DETECTION_CUSTOM -> {\n          Log.i(TAG, \"Using Custom Object Detector Processor\")\n          val localModel =\n            LocalModel.Builder().setAssetFilePath(\"custom_models/object_labeler.tflite\").build()\n          val customObjectDetectorOptions =\n            PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(this, localModel)\n          cameraSource!!.setMachineLearningFrameProcessor(\n            ObjectDetectorProcessor(this, customObjectDetectorOptions)\n          )\n        }\n        CUSTOM_AUTOML_OBJECT_DETECTION -> {\n          Log.i(TAG, \"Using Custom AutoML Object Detector Processor\")\n          val customAutoMLODTLocalModel =\n            LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build()\n          val customAutoMLODTOptions =\n            PreferenceUtils.getCustomObjectDetectorOptionsForLivePreview(\n              this,\n              customAutoMLODTLocalModel\n            )\n          cameraSource!!.setMachineLearningFrameProcessor(\n            ObjectDetectorProcessor(this, customAutoMLODTOptions)\n          )\n        }\n        TEXT_RECOGNITION_LATIN -> {\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Latin\")\n          cameraSource!!.setMachineLearningFrameProcessor(\n            TextRecognitionProcessor(this, TextRecognizerOptions.Builder().build())\n          )\n        }\n        TEXT_RECOGNITION_CHINESE -> {\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Chinese\")\n          cameraSource!!.setMachineLearningFrameProcessor(\n            TextRecognitionProcessor(this, ChineseTextRecognizerOptions.Builder().build())\n          )\n        }\n        TEXT_RECOGNITION_DEVANAGARI -> {\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Devanagari\")\n          cameraSource!!.setMachineLearningFrameProcessor(\n            TextRecognitionProcessor(this, DevanagariTextRecognizerOptions.Builder().build())\n          )\n        }\n        TEXT_RECOGNITION_JAPANESE -> {\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Japanese\")\n          cameraSource!!.setMachineLearningFrameProcessor(\n            TextRecognitionProcessor(this, JapaneseTextRecognizerOptions.Builder().build())\n          )\n        }\n        TEXT_RECOGNITION_KOREAN -> {\n          Log.i(TAG, \"Using on-device Text recognition Processor for Latin and Korean\")\n          cameraSource!!.setMachineLearningFrameProcessor(\n            TextRecognitionProcessor(this, KoreanTextRecognizerOptions.Builder().build())\n          )\n        }\n        FACE_DETECTION -> {\n          Log.i(TAG, \"Using Face Detector Processor\")\n          val faceDetectorOptions = PreferenceUtils.getFaceDetectorOptions(this)\n          cameraSource!!.setMachineLearningFrameProcessor(\n            FaceDetectorProcessor(this, faceDetectorOptions)\n          )\n        }\n        BARCODE_SCANNING -> {\n          Log.i(TAG, \"Using Barcode Detector Processor\")\n          var zoomCallback: ZoomCallback? = null\n          if (PreferenceUtils.shouldEnableAutoZoom(this)) {\n            zoomCallback = ZoomCallback { zoomLevel: Float -> cameraSource!!.setZoom(zoomLevel) }\n          }\n          cameraSource!!.setMachineLearningFrameProcessor(\n            BarcodeScannerProcessor(this, zoomCallback)\n          )\n        }\n        IMAGE_LABELING -> {\n          Log.i(TAG, \"Using Image Label Detector Processor\")\n          cameraSource!!.setMachineLearningFrameProcessor(\n            LabelDetectorProcessor(this, ImageLabelerOptions.DEFAULT_OPTIONS)\n          )\n        }\n        IMAGE_LABELING_CUSTOM -> {\n          Log.i(TAG, \"Using Custom Image Label Detector Processor\")\n          val localClassifier =\n            LocalModel.Builder().setAssetFilePath(\"custom_models/bird_classifier.tflite\").build()\n          val customImageLabelerOptions = CustomImageLabelerOptions.Builder(localClassifier).build()\n          cameraSource!!.setMachineLearningFrameProcessor(\n            LabelDetectorProcessor(this, customImageLabelerOptions)\n          )\n        }\n        CUSTOM_AUTOML_LABELING -> {\n          Log.i(TAG, \"Using Custom AutoML Image Label Detector Processor\")\n          val customAutoMLLabelLocalModel =\n            LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build()\n          val customAutoMLLabelOptions =\n            CustomImageLabelerOptions.Builder(customAutoMLLabelLocalModel)\n              .setConfidenceThreshold(0f)\n              .build()\n          cameraSource!!.setMachineLearningFrameProcessor(\n            LabelDetectorProcessor(this, customAutoMLLabelOptions)\n          )\n        }\n        POSE_DETECTION -> {\n          val poseDetectorOptions = PreferenceUtils.getPoseDetectorOptionsForLivePreview(this)\n          Log.i(TAG, \"Using Pose Detector with options $poseDetectorOptions\")\n          val shouldShowInFrameLikelihood =\n            PreferenceUtils.shouldShowPoseDetectionInFrameLikelihoodLivePreview(this)\n          val visualizeZ = PreferenceUtils.shouldPoseDetectionVisualizeZ(this)\n          val rescaleZ = PreferenceUtils.shouldPoseDetectionRescaleZForVisualization(this)\n          val runClassification = PreferenceUtils.shouldPoseDetectionRunClassification(this)\n          cameraSource!!.setMachineLearningFrameProcessor(\n            PoseDetectorProcessor(\n              this,\n              poseDetectorOptions,\n              shouldShowInFrameLikelihood,\n              visualizeZ,\n              rescaleZ,\n              runClassification,\n              /* isStreamMode = */ true\n            )\n          )\n        }\n        SELFIE_SEGMENTATION -> {\n          cameraSource!!.setMachineLearningFrameProcessor(SegmenterProcessor(this))\n        }\n        FACE_MESH_DETECTION -> {\n          cameraSource!!.setMachineLearningFrameProcessor(FaceMeshDetectorProcessor(this))\n        }\n        else -> Log.e(TAG, \"Unknown model: $model\")\n      }\n    } catch (e: Exception) {\n      Log.e(TAG, \"Can not create image processor: $model\", e)\n      Toast.makeText(\n          applicationContext,\n          \"Can not create image processor: \" + e.message,\n          Toast.LENGTH_LONG\n        )\n        .show()\n    }\n  }\n\n  /**\n   * Starts or restarts the camera source, if it exists. If the camera source doesn't exist yet\n   * (e.g., because onResume was called before the camera source was created), this will be called\n   * again when the camera source is created.\n   */\n  private fun startCameraSource() {\n    if (cameraSource != null) {\n      try {\n        if (preview == null) {\n          Log.d(TAG, \"resume: Preview is null\")\n        }\n        if (graphicOverlay == null) {\n          Log.d(TAG, \"resume: graphOverlay is null\")\n        }\n        preview!!.start(cameraSource, graphicOverlay)\n      } catch (e: IOException) {\n        Log.e(TAG, \"Unable to start camera source.\", e)\n        cameraSource!!.release()\n        cameraSource = null\n      }\n    }\n  }\n\n  public override fun onResume() {\n    super.onResume()\n    Log.d(TAG, \"onResume\")\n    createCameraSource(selectedModel)\n    startCameraSource()\n  }\n\n  /** Stops the camera. */\n  override fun onPause() {\n    super.onPause()\n    preview?.stop()\n  }\n\n  public override fun onDestroy() {\n    super.onDestroy()\n    if (cameraSource != null) {\n      cameraSource?.release()\n    }\n  }\n\n  companion object {\n    private const val OBJECT_DETECTION = \"Object Detection\"\n    private const val OBJECT_DETECTION_CUSTOM = \"Custom Object Detection\"\n    private const val CUSTOM_AUTOML_OBJECT_DETECTION = \"Custom AutoML Object Detection (Flower)\"\n    private const val FACE_DETECTION = \"Face Detection\"\n    private const val TEXT_RECOGNITION_LATIN = \"Text Recognition Latin\"\n    private const val TEXT_RECOGNITION_CHINESE = \"Text Recognition Chinese\"\n    private const val TEXT_RECOGNITION_DEVANAGARI = \"Text Recognition Devanagari\"\n    private const val TEXT_RECOGNITION_JAPANESE = \"Text Recognition Japanese\"\n    private const val TEXT_RECOGNITION_KOREAN = \"Text Recognition Korean\"\n    private const val BARCODE_SCANNING = \"Barcode Scanning\"\n    private const val IMAGE_LABELING = \"Image Labeling\"\n    private const val IMAGE_LABELING_CUSTOM = \"Custom Image Labeling (Birds)\"\n    private const val CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling (Flower)\"\n    private const val POSE_DETECTION = \"Pose Detection\"\n    private const val SELFIE_SEGMENTATION = \"Selfie Segmentation\"\n    private const val FACE_MESH_DETECTION = \"Face Mesh Detection (Beta)\"\n\n    private const val TAG = \"LivePreviewActivity\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/StillImageActivity.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin\n\nimport android.app.Activity\nimport android.content.ContentValues\nimport android.content.Intent\nimport android.content.res.Configuration\nimport android.graphics.Bitmap\nimport android.net.Uri\nimport android.os.Build\nimport android.os.Build.VERSION\nimport android.os.Bundle\nimport android.provider.MediaStore\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.util.Pair\nimport android.view.MenuItem\nimport android.view.View\nimport android.view.ViewTreeObserver\nimport android.widget.AdapterView\nimport android.widget.AdapterView.OnItemSelectedListener\nimport android.widget.ArrayAdapter\nimport android.widget.ImageView\nimport android.widget.PopupMenu\nimport android.widget.Spinner\nimport android.widget.Toast\nimport com.google.android.gms.common.annotation.KeepName\nimport com.google.mlkit.common.model.LocalModel\nimport com.google.mlkit.vision.demo.BitmapUtils\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.R\nimport com.google.mlkit.vision.demo.VisionImageProcessor\nimport com.google.mlkit.vision.demo.kotlin.barcodescanner.BarcodeScannerProcessor\nimport com.google.mlkit.vision.demo.kotlin.facedetector.FaceDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.facemeshdetector.FaceMeshDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.labeldetector.LabelDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.objectdetector.ObjectDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.posedetector.PoseDetectorProcessor\nimport com.google.mlkit.vision.demo.kotlin.segmenter.SegmenterProcessor\nimport com.google.mlkit.vision.demo.kotlin.subjectsegmenter.SubjectSegmenterProcessor\nimport com.google.mlkit.vision.demo.kotlin.textdetector.TextRecognitionProcessor\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport com.google.mlkit.vision.demo.preference.SettingsActivity\nimport com.google.mlkit.vision.demo.preference.SettingsActivity.LaunchSource\nimport com.google.mlkit.vision.label.custom.CustomImageLabelerOptions\nimport com.google.mlkit.vision.label.defaults.ImageLabelerOptions\nimport com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions\nimport com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions\nimport com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions\nimport com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions\nimport com.google.mlkit.vision.text.latin.TextRecognizerOptions\nimport java.io.IOException\nimport java.util.ArrayList\n\n/** Activity demonstrating different image detector features with a still image from camera. */\n@KeepName\nclass StillImageActivity : AppCompatActivity() {\n  private var preview: ImageView? = null\n  private var graphicOverlay: GraphicOverlay? = null\n  private var selectedMode = OBJECT_DETECTION\n  private var selectedSize: String? = SIZE_SCREEN\n  private var isLandScape = false\n  private var imageUri: Uri? = null\n  // Max width (portrait mode)\n  private var imageMaxWidth = 0\n  // Max height (portrait mode)\n  private var imageMaxHeight = 0\n  private var imageProcessor: VisionImageProcessor? = null\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_still_image)\n    findViewById<View>(R.id.select_image_button).setOnClickListener { view: View ->\n      // Menu for selecting either: a) take new photo b) select from existing\n      val popup = PopupMenu(this@StillImageActivity, view)\n      popup.setOnMenuItemClickListener { menuItem: MenuItem ->\n        val itemId = menuItem.itemId\n        if (itemId == R.id.select_images_from_local) {\n          startChooseImageIntentForResult()\n          return@setOnMenuItemClickListener true\n        } else if (itemId == R.id.take_photo_using_camera) {\n          startCameraIntentForResult()\n          return@setOnMenuItemClickListener true\n        }\n        false\n      }\n      val inflater = popup.menuInflater\n      inflater.inflate(R.menu.camera_button_menu, popup.menu)\n      popup.show()\n    }\n    preview = findViewById(R.id.preview)\n    graphicOverlay = findViewById(R.id.graphic_overlay)\n\n    populateFeatureSelector()\n    populateSizeSelector()\n    isLandScape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE\n    if (savedInstanceState != null) {\n      imageUri = savedInstanceState.getParcelable(KEY_IMAGE_URI)\n      imageMaxWidth = savedInstanceState.getInt(KEY_IMAGE_MAX_WIDTH)\n      imageMaxHeight = savedInstanceState.getInt(KEY_IMAGE_MAX_HEIGHT)\n      selectedSize = savedInstanceState.getString(KEY_SELECTED_SIZE)\n    }\n\n    val rootView = findViewById<View>(R.id.root)\n    rootView.viewTreeObserver.addOnGlobalLayoutListener(\n      object : ViewTreeObserver.OnGlobalLayoutListener {\n        override fun onGlobalLayout() {\n          rootView.viewTreeObserver.removeOnGlobalLayoutListener(this)\n          imageMaxWidth = rootView.width\n          imageMaxHeight = rootView.height - findViewById<View>(R.id.control).height\n          if (SIZE_SCREEN == selectedSize) {\n            tryReloadAndDetectInImage()\n          }\n        }\n      }\n    )\n\n    val settingsButton = findViewById<ImageView>(R.id.settings_button)\n    settingsButton.setOnClickListener {\n      val intent = Intent(applicationContext, SettingsActivity::class.java)\n      intent.putExtra(SettingsActivity.EXTRA_LAUNCH_SOURCE, LaunchSource.STILL_IMAGE)\n      startActivity(intent)\n    }\n  }\n\n  public override fun onResume() {\n    super.onResume()\n    Log.d(TAG, \"onResume\")\n    createImageProcessor()\n    tryReloadAndDetectInImage()\n  }\n\n  public override fun onPause() {\n    super.onPause()\n    imageProcessor?.run { this.stop() }\n  }\n\n  public override fun onDestroy() {\n    super.onDestroy()\n    imageProcessor?.run { this.stop() }\n  }\n\n  private fun populateFeatureSelector() {\n    val featureSpinner = findViewById<Spinner>(R.id.feature_selector)\n    val options: MutableList<String> = ArrayList()\n    options.add(OBJECT_DETECTION)\n    options.add(OBJECT_DETECTION_CUSTOM)\n    options.add(CUSTOM_AUTOML_OBJECT_DETECTION)\n    options.add(FACE_DETECTION)\n    options.add(BARCODE_SCANNING)\n    options.add(IMAGE_LABELING)\n    options.add(IMAGE_LABELING_CUSTOM)\n    options.add(CUSTOM_AUTOML_LABELING)\n    options.add(POSE_DETECTION)\n    options.add(SELFIE_SEGMENTATION)\n    options.add(TEXT_RECOGNITION_LATIN)\n    options.add(TEXT_RECOGNITION_CHINESE)\n    options.add(TEXT_RECOGNITION_DEVANAGARI)\n    options.add(TEXT_RECOGNITION_JAPANESE)\n    options.add(TEXT_RECOGNITION_KOREAN)\n    options.add(FACE_MESH_DETECTION)\n    if (VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n      options.add(SUBJECT_SEGMENTATION)\n    }\n\n    // Creating adapter for featureSpinner\n    val dataAdapter = ArrayAdapter(this, R.layout.spinner_style, options)\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n    // attaching data adapter to spinner\n    featureSpinner.adapter = dataAdapter\n    featureSpinner.onItemSelectedListener =\n      object : OnItemSelectedListener {\n        override fun onItemSelected(\n          parentView: AdapterView<*>,\n          selectedItemView: View?,\n          pos: Int,\n          id: Long\n        ) {\n          if (pos >= 0) {\n            selectedMode = parentView.getItemAtPosition(pos).toString()\n            createImageProcessor()\n            tryReloadAndDetectInImage()\n          }\n        }\n\n        override fun onNothingSelected(arg0: AdapterView<*>?) {}\n      }\n  }\n\n  private fun populateSizeSelector() {\n    val sizeSpinner = findViewById<Spinner>(R.id.size_selector)\n    val options: MutableList<String> = ArrayList()\n    options.add(SIZE_SCREEN)\n    options.add(SIZE_1024_768)\n    options.add(SIZE_640_480)\n    options.add(SIZE_ORIGINAL)\n    // Creating adapter for featureSpinner\n    val dataAdapter = ArrayAdapter(this, R.layout.spinner_style, options)\n    // Drop down layout style - list view with radio button\n    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)\n    // attaching data adapter to spinner\n    sizeSpinner.adapter = dataAdapter\n    sizeSpinner.onItemSelectedListener =\n      object : OnItemSelectedListener {\n        override fun onItemSelected(\n          parentView: AdapterView<*>,\n          selectedItemView: View?,\n          pos: Int,\n          id: Long\n        ) {\n          if (pos >= 0) {\n            selectedSize = parentView.getItemAtPosition(pos).toString()\n            tryReloadAndDetectInImage()\n          }\n        }\n\n        override fun onNothingSelected(arg0: AdapterView<*>?) {}\n      }\n  }\n\n  public override fun onSaveInstanceState(outState: Bundle) {\n    super.onSaveInstanceState(outState)\n    outState.putParcelable(KEY_IMAGE_URI, imageUri)\n    outState.putInt(KEY_IMAGE_MAX_WIDTH, imageMaxWidth)\n    outState.putInt(KEY_IMAGE_MAX_HEIGHT, imageMaxHeight)\n    outState.putString(KEY_SELECTED_SIZE, selectedSize)\n  }\n\n  private fun startCameraIntentForResult() { // Clean up last time's image\n    imageUri = null\n    preview!!.setImageBitmap(null)\n    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)\n    if (takePictureIntent.resolveActivity(packageManager) != null) {\n      val values = ContentValues()\n      values.put(MediaStore.Images.Media.TITLE, \"New Picture\")\n      values.put(MediaStore.Images.Media.DESCRIPTION, \"From Camera\")\n      imageUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)\n      takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)\n      startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)\n    }\n  }\n\n  private fun startChooseImageIntentForResult() {\n    val intent = Intent()\n    intent.type = \"image/*\"\n    intent.action = Intent.ACTION_GET_CONTENT\n    startActivityForResult(Intent.createChooser(intent, \"Select Picture\"), REQUEST_CHOOSE_IMAGE)\n  }\n\n  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {\n      tryReloadAndDetectInImage()\n    } else if (requestCode == REQUEST_CHOOSE_IMAGE && resultCode == Activity.RESULT_OK) {\n      // In this case, imageUri is returned by the chooser, save it.\n      imageUri = data!!.data\n      tryReloadAndDetectInImage()\n    } else {\n      super.onActivityResult(requestCode, resultCode, data)\n    }\n  }\n\n  private fun tryReloadAndDetectInImage() {\n    Log.d(TAG, \"Try reload and detect image\")\n    try {\n      if (imageUri == null) {\n        return\n      }\n\n      if (SIZE_SCREEN == selectedSize && imageMaxWidth == 0) {\n        // UI layout has not finished yet, will reload once it's ready.\n        return\n      }\n\n      val imageBitmap = BitmapUtils.getBitmapFromContentUri(contentResolver, imageUri) ?: return\n      // Clear the overlay first\n      graphicOverlay!!.clear()\n\n      val resizedBitmap: Bitmap\n      resizedBitmap =\n        if (selectedSize == SIZE_ORIGINAL) {\n          imageBitmap\n        } else {\n          // Get the dimensions of the image view\n          val targetedSize: Pair<Int, Int> = targetedWidthHeight\n\n          // Determine how much to scale down the image\n          val scaleFactor =\n            Math.max(\n              imageBitmap.width.toFloat() / targetedSize.first.toFloat(),\n              imageBitmap.height.toFloat() / targetedSize.second.toFloat()\n            )\n          Bitmap.createScaledBitmap(\n            imageBitmap,\n            (imageBitmap.width / scaleFactor).toInt(),\n            (imageBitmap.height / scaleFactor).toInt(),\n            true\n          )\n        }\n\n      preview!!.setImageBitmap(resizedBitmap)\n      if (imageProcessor != null) {\n        graphicOverlay!!.setImageSourceInfo(\n          resizedBitmap.width,\n          resizedBitmap.height,\n          /* isFlipped= */ false\n        )\n        imageProcessor!!.processBitmap(resizedBitmap, graphicOverlay)\n      } else {\n        Log.e(TAG, \"Null imageProcessor, please check adb logs for imageProcessor creation error\")\n      }\n    } catch (e: IOException) {\n      Log.e(TAG, \"Error retrieving saved image\")\n      imageUri = null\n    }\n  }\n\n  private val targetedWidthHeight: Pair<Int, Int>\n    get() {\n      val targetWidth: Int\n      val targetHeight: Int\n      when (selectedSize) {\n        SIZE_SCREEN -> {\n          targetWidth = imageMaxWidth\n          targetHeight = imageMaxHeight\n        }\n        SIZE_640_480 -> {\n          targetWidth = if (isLandScape) 640 else 480\n          targetHeight = if (isLandScape) 480 else 640\n        }\n        SIZE_1024_768 -> {\n          targetWidth = if (isLandScape) 1024 else 768\n          targetHeight = if (isLandScape) 768 else 1024\n        }\n        else -> throw IllegalStateException(\"Unknown size\")\n      }\n      return Pair(targetWidth, targetHeight)\n    }\n\n  private fun createImageProcessor() {\n    try {\n      when (selectedMode) {\n        OBJECT_DETECTION -> {\n          Log.i(TAG, \"Using Object Detector Processor\")\n          val objectDetectorOptions = PreferenceUtils.getObjectDetectorOptionsForStillImage(this)\n          imageProcessor = ObjectDetectorProcessor(this, objectDetectorOptions)\n        }\n        OBJECT_DETECTION_CUSTOM -> {\n          Log.i(TAG, \"Using Custom Object Detector Processor\")\n          val localModel =\n            LocalModel.Builder().setAssetFilePath(\"custom_models/object_labeler.tflite\").build()\n          val customObjectDetectorOptions =\n            PreferenceUtils.getCustomObjectDetectorOptionsForStillImage(this, localModel)\n          imageProcessor = ObjectDetectorProcessor(this, customObjectDetectorOptions)\n        }\n        CUSTOM_AUTOML_OBJECT_DETECTION -> {\n          Log.i(TAG, \"Using Custom AutoML Object Detector Processor\")\n          val customAutoMLODTLocalModel =\n            LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build()\n          val customAutoMLODTOptions =\n            PreferenceUtils.getCustomObjectDetectorOptionsForStillImage(\n              this,\n              customAutoMLODTLocalModel\n            )\n          imageProcessor = ObjectDetectorProcessor(this, customAutoMLODTOptions)\n        }\n        FACE_DETECTION -> {\n          Log.i(TAG, \"Using Face Detector Processor\")\n          val faceDetectorOptions = PreferenceUtils.getFaceDetectorOptions(this)\n          imageProcessor = FaceDetectorProcessor(this, faceDetectorOptions)\n        }\n        BARCODE_SCANNING -> imageProcessor = BarcodeScannerProcessor(this, zoomCallback = null)\n        TEXT_RECOGNITION_LATIN ->\n          imageProcessor = TextRecognitionProcessor(this, TextRecognizerOptions.Builder().build())\n        TEXT_RECOGNITION_CHINESE ->\n          imageProcessor =\n            TextRecognitionProcessor(this, ChineseTextRecognizerOptions.Builder().build())\n        TEXT_RECOGNITION_DEVANAGARI ->\n          imageProcessor =\n            TextRecognitionProcessor(this, DevanagariTextRecognizerOptions.Builder().build())\n        TEXT_RECOGNITION_JAPANESE ->\n          imageProcessor =\n            TextRecognitionProcessor(this, JapaneseTextRecognizerOptions.Builder().build())\n        TEXT_RECOGNITION_KOREAN ->\n          imageProcessor =\n            TextRecognitionProcessor(this, KoreanTextRecognizerOptions.Builder().build())\n        IMAGE_LABELING ->\n          imageProcessor = LabelDetectorProcessor(this, ImageLabelerOptions.DEFAULT_OPTIONS)\n        IMAGE_LABELING_CUSTOM -> {\n          Log.i(TAG, \"Using Custom Image Label Detector Processor\")\n          val localClassifier =\n            LocalModel.Builder().setAssetFilePath(\"custom_models/bird_classifier.tflite\").build()\n          val customImageLabelerOptions = CustomImageLabelerOptions.Builder(localClassifier).build()\n          imageProcessor = LabelDetectorProcessor(this, customImageLabelerOptions)\n        }\n        CUSTOM_AUTOML_LABELING -> {\n          Log.i(TAG, \"Using Custom AutoML Image Label Detector Processor\")\n          val customAutoMLLabelLocalModel =\n            LocalModel.Builder().setAssetManifestFilePath(\"automl/manifest.json\").build()\n          val customAutoMLLabelOptions =\n            CustomImageLabelerOptions.Builder(customAutoMLLabelLocalModel)\n              .setConfidenceThreshold(0f)\n              .build()\n          imageProcessor = LabelDetectorProcessor(this, customAutoMLLabelOptions)\n        }\n        POSE_DETECTION -> {\n          val poseDetectorOptions = PreferenceUtils.getPoseDetectorOptionsForStillImage(this)\n          Log.i(TAG, \"Using Pose Detector with options $poseDetectorOptions\")\n          val shouldShowInFrameLikelihood =\n            PreferenceUtils.shouldShowPoseDetectionInFrameLikelihoodStillImage(this)\n          val visualizeZ = PreferenceUtils.shouldPoseDetectionVisualizeZ(this)\n          val rescaleZ = PreferenceUtils.shouldPoseDetectionRescaleZForVisualization(this)\n          val runClassification = PreferenceUtils.shouldPoseDetectionRunClassification(this)\n          imageProcessor =\n            PoseDetectorProcessor(\n              this,\n              poseDetectorOptions,\n              shouldShowInFrameLikelihood,\n              visualizeZ,\n              rescaleZ,\n              runClassification,\n              isStreamMode = false\n            )\n        }\n        SELFIE_SEGMENTATION -> {\n          imageProcessor = SegmenterProcessor(this, isStreamMode = false)\n        }\n        FACE_MESH_DETECTION -> {\n          imageProcessor = FaceMeshDetectorProcessor(this)\n        }\n        SUBJECT_SEGMENTATION -> {\n          if (VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            imageProcessor = SubjectSegmenterProcessor(this)\n          }\n        }\n        else -> Log.e(TAG, \"Unknown selectedMode: $selectedMode\")\n      }\n    } catch (e: Exception) {\n      Log.e(TAG, \"Can not create image processor: $selectedMode\", e)\n      Toast.makeText(\n          applicationContext,\n          \"Can not create image processor: \" + e.message,\n          Toast.LENGTH_LONG\n        )\n        .show()\n    }\n  }\n\n  companion object {\n    private const val TAG = \"StillImageActivity\"\n    private const val OBJECT_DETECTION = \"Object Detection\"\n    private const val OBJECT_DETECTION_CUSTOM = \"Custom Object Detection\"\n    private const val CUSTOM_AUTOML_OBJECT_DETECTION = \"Custom AutoML Object Detection (Flower)\"\n    private const val FACE_DETECTION = \"Face Detection\"\n    private const val BARCODE_SCANNING = \"Barcode Scanning\"\n    private const val TEXT_RECOGNITION_LATIN = \"Text Recognition Latin\"\n    private const val TEXT_RECOGNITION_CHINESE = \"Text Recognition Chinese\"\n    private const val TEXT_RECOGNITION_DEVANAGARI = \"Text Recognition Devanagari\"\n    private const val TEXT_RECOGNITION_JAPANESE = \"Text Recognition Japanese\"\n    private const val TEXT_RECOGNITION_KOREAN = \"Text Recognition Korean\"\n    private const val IMAGE_LABELING = \"Image Labeling\"\n    private const val IMAGE_LABELING_CUSTOM = \"Custom Image Labeling (Birds)\"\n    private const val CUSTOM_AUTOML_LABELING = \"Custom AutoML Image Labeling (Flower)\"\n    private const val POSE_DETECTION = \"Pose Detection\"\n    private const val SELFIE_SEGMENTATION = \"Selfie Segmentation\"\n    private const val FACE_MESH_DETECTION = \"Face Mesh Detection (Beta)\"\n    private const val SUBJECT_SEGMENTATION = \"Subject Segmentation (Beta)\"\n\n    private const val SIZE_SCREEN = \"w:screen\" // Match screen width\n    private const val SIZE_1024_768 = \"w:1024\" // ~1024*768 in a normal ratio\n    private const val SIZE_640_480 = \"w:640\" // ~640*480 in a normal ratio\n    private const val SIZE_ORIGINAL = \"w:original\" // Original image size\n    private const val KEY_IMAGE_URI = \"com.google.mlkit.vision.demo.KEY_IMAGE_URI\"\n    private const val KEY_IMAGE_MAX_WIDTH = \"com.google.mlkit.vision.demo.KEY_IMAGE_MAX_WIDTH\"\n    private const val KEY_IMAGE_MAX_HEIGHT = \"com.google.mlkit.vision.demo.KEY_IMAGE_MAX_HEIGHT\"\n    private const val KEY_SELECTED_SIZE = \"com.google.mlkit.vision.demo.KEY_SELECTED_SIZE\"\n    private const val REQUEST_IMAGE_CAPTURE = 1001\n    private const val REQUEST_CHOOSE_IMAGE = 1002\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/TaskExt.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin\n\nimport com.google.android.gms.tasks.OnCanceledListener\nimport com.google.android.gms.tasks.OnCompleteListener\nimport com.google.android.gms.tasks.OnFailureListener\nimport com.google.android.gms.tasks.OnSuccessListener\nimport com.google.android.gms.tasks.Task\nimport java.util.concurrent.Executor\n\n/**\n * Quality-of-life helper to allow using trailing lambda syntax for adding a success listener to a\n * [Task].\n */\nfun <TResult> Task<TResult>.addOnSuccessListener(\n  executor: Executor,\n  listener: (TResult) -> Unit\n): Task<TResult> {\n  return addOnSuccessListener(executor, OnSuccessListener(listener))\n}\n\n/**\n * Quality-of-life helper to allow using trailing lambda syntax for adding a failure listener to a\n * [Task].\n */\nfun <TResult> Task<TResult>.addOnFailureListener(\n  executor: Executor,\n  listener: (Exception) -> Unit\n): Task<TResult> {\n  return addOnFailureListener(executor, OnFailureListener(listener))\n}\n\n/**\n * Quality-of-life helper to allow using trailing lambda syntax for adding a completion listener to\n * a [Task].\n */\nfun <TResult> Task<TResult>.addOnCompleteListener(\n  executor: Executor,\n  listener: (Task<TResult>) -> Unit\n): Task<TResult> {\n  return addOnCompleteListener(executor, OnCompleteListener(listener))\n}\n\n/**\n * Quality-of-life helper to allow using trailing lambda syntax for adding a cancellation listener\n * to a [Task].\n */\nfun <TResult> Task<TResult>.addOnCanceledListener(\n  executor: Executor,\n  listener: () -> Unit\n): Task<TResult> {\n  return addOnCanceledListener(executor, OnCanceledListener(listener))\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/VisionProcessorBase.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin\n\nimport android.app.ActivityManager\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.os.Build.VERSION_CODES\nimport android.os.SystemClock\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.annotation.GuardedBy\nimport androidx.annotation.RequiresApi\nimport androidx.camera.core.ExperimentalGetImage\nimport androidx.camera.core.ImageProxy\nimport com.google.android.gms.tasks.OnFailureListener\nimport com.google.android.gms.tasks.OnSuccessListener\nimport com.google.android.gms.tasks.Task\nimport com.google.android.gms.tasks.TaskExecutors\nimport com.google.android.gms.tasks.Tasks\nimport com.google.android.odml.image.BitmapMlImageBuilder\nimport com.google.android.odml.image.ByteBufferMlImageBuilder\nimport com.google.android.odml.image.MediaMlImageBuilder\nimport com.google.android.odml.image.MlImage\nimport com.google.mlkit.common.MlKitException\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.BitmapUtils\nimport com.google.mlkit.vision.demo.CameraImageGraphic\nimport com.google.mlkit.vision.demo.FrameMetadata\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.InferenceInfoGraphic\nimport com.google.mlkit.vision.demo.ScopedExecutor\nimport com.google.mlkit.vision.demo.VisionImageProcessor\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport java.lang.Math.max\nimport java.lang.Math.min\nimport java.nio.ByteBuffer\nimport java.util.Timer\nimport java.util.TimerTask\n\n/**\n * Abstract base class for ML Kit frame processors. Subclasses need to implement {@link\n * #onSuccess(T, FrameMetadata, GraphicOverlay)} to define what they want to with the detection\n * results and {@link #detectInImage(VisionImage)} to specify the detector object.\n *\n * @param <T> The type of the detected feature.\n */\nabstract class VisionProcessorBase<T>(context: Context) : VisionImageProcessor {\n\n  companion object {\n    const val MANUAL_TESTING_LOG = \"LogTagForTest\"\n    private const val TAG = \"VisionProcessorBase\"\n  }\n\n  private var activityManager: ActivityManager =\n    context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager\n  private val fpsTimer = Timer()\n  private val executor = ScopedExecutor(TaskExecutors.MAIN_THREAD)\n\n  // Whether this processor is already shut down\n  private var isShutdown = false\n\n  // Used to calculate latency, running in the same thread, no sync needed.\n  private var numRuns = 0\n  private var totalFrameMs = 0L\n  private var maxFrameMs = 0L\n  private var minFrameMs = Long.MAX_VALUE\n  private var totalDetectorMs = 0L\n  private var maxDetectorMs = 0L\n  private var minDetectorMs = Long.MAX_VALUE\n\n  // Frame count that have been processed so far in an one second interval to calculate FPS.\n  private var frameProcessedInOneSecondInterval = 0\n  private var framesPerSecond = 0\n\n  // To keep the latest images and its metadata.\n  @GuardedBy(\"this\") private var latestImage: ByteBuffer? = null\n  @GuardedBy(\"this\") private var latestImageMetaData: FrameMetadata? = null\n  // To keep the images and metadata in process.\n  @GuardedBy(\"this\") private var processingImage: ByteBuffer? = null\n  @GuardedBy(\"this\") private var processingMetaData: FrameMetadata? = null\n\n  init {\n    fpsTimer.scheduleAtFixedRate(\n      object : TimerTask() {\n        override fun run() {\n          framesPerSecond = frameProcessedInOneSecondInterval\n          frameProcessedInOneSecondInterval = 0\n        }\n      },\n      0,\n      1000\n    )\n  }\n\n  // -----------------Code for processing single still image----------------------------------------\n  override fun processBitmap(bitmap: Bitmap?, graphicOverlay: GraphicOverlay) {\n    val frameStartMs = SystemClock.elapsedRealtime()\n\n    if (isMlImageEnabled(graphicOverlay.context)) {\n      val mlImage = BitmapMlImageBuilder(bitmap!!).build()\n      requestDetectInImage(\n        mlImage,\n        graphicOverlay,\n        /* originalCameraImage= */ null,\n        /* shouldShowFps= */ false,\n        frameStartMs\n      )\n      mlImage.close()\n      return\n    }\n\n    requestDetectInImage(\n      InputImage.fromBitmap(bitmap!!, 0),\n      graphicOverlay,\n      /* originalCameraImage= */ null,\n      /* shouldShowFps= */ false,\n      frameStartMs\n    )\n  }\n\n  // -----------------Code for processing live preview frame from Camera1 API-----------------------\n  @Synchronized\n  override fun processByteBuffer(\n    data: ByteBuffer?,\n    frameMetadata: FrameMetadata?,\n    graphicOverlay: GraphicOverlay\n  ) {\n    latestImage = data\n    latestImageMetaData = frameMetadata\n    if (processingImage == null && processingMetaData == null) {\n      processLatestImage(graphicOverlay)\n    }\n  }\n\n  @Synchronized\n  private fun processLatestImage(graphicOverlay: GraphicOverlay) {\n    processingImage = latestImage\n    processingMetaData = latestImageMetaData\n    latestImage = null\n    latestImageMetaData = null\n    if (processingImage != null && processingMetaData != null && !isShutdown) {\n      processImage(processingImage!!, processingMetaData!!, graphicOverlay)\n    }\n  }\n\n  private fun processImage(\n    data: ByteBuffer,\n    frameMetadata: FrameMetadata,\n    graphicOverlay: GraphicOverlay\n  ) {\n    val frameStartMs = SystemClock.elapsedRealtime()\n    // If live viewport is on (that is the underneath surface view takes care of the camera preview\n    // drawing), skip the unnecessary bitmap creation that used for the manual preview drawing.\n    val bitmap =\n      if (PreferenceUtils.isCameraLiveViewportEnabled(graphicOverlay.context)) null\n      else BitmapUtils.getBitmap(data, frameMetadata)\n\n    if (isMlImageEnabled(graphicOverlay.context)) {\n      val mlImage =\n        ByteBufferMlImageBuilder(\n            data,\n            frameMetadata.width,\n            frameMetadata.height,\n            MlImage.IMAGE_FORMAT_NV21\n          )\n          .setRotation(frameMetadata.rotation)\n          .build()\n      requestDetectInImage(mlImage, graphicOverlay, bitmap, /* shouldShowFps= */ true, frameStartMs)\n        .addOnSuccessListener(executor) { processLatestImage(graphicOverlay) }\n\n      // This is optional. Java Garbage collection can also close it eventually.\n      mlImage.close()\n      return\n    }\n\n    requestDetectInImage(\n      InputImage.fromByteBuffer(\n        data,\n        frameMetadata.width,\n        frameMetadata.height,\n        frameMetadata.rotation,\n        InputImage.IMAGE_FORMAT_NV21\n      ),\n      graphicOverlay,\n      bitmap,\n      /* shouldShowFps= */ true,\n      frameStartMs\n    )\n      .addOnSuccessListener(executor) { processLatestImage(graphicOverlay) }\n  }\n\n  // -----------------Code for processing live preview frame from CameraX API-----------------------\n  @RequiresApi(VERSION_CODES.LOLLIPOP)\n  @ExperimentalGetImage\n  override fun processImageProxy(image: ImageProxy, graphicOverlay: GraphicOverlay) {\n    val frameStartMs = SystemClock.elapsedRealtime()\n    if (isShutdown) {\n      return\n    }\n    var bitmap: Bitmap? = null\n    if (!PreferenceUtils.isCameraLiveViewportEnabled(graphicOverlay.context)) {\n      bitmap = BitmapUtils.getBitmap(image)\n    }\n\n    if (isMlImageEnabled(graphicOverlay.context)) {\n      val mlImage =\n        MediaMlImageBuilder(image.image!!).setRotation(image.imageInfo.rotationDegrees).build()\n      requestDetectInImage(\n        mlImage,\n        graphicOverlay,\n        /* originalCameraImage= */ bitmap,\n        /* shouldShowFps= */ true,\n        frameStartMs\n      )\n        // When the image is from CameraX analysis use case, must call image.close() on received\n        // images when finished using them. Otherwise, new images may not be received or the camera\n        // may stall.\n        // Currently MlImage doesn't support ImageProxy directly, so we still need to call\n        // ImageProxy.close() here.\n        .addOnCompleteListener { image.close() }\n\n      return\n    }\n\n    requestDetectInImage(\n      InputImage.fromMediaImage(image.image!!, image.imageInfo.rotationDegrees),\n      graphicOverlay,\n      /* originalCameraImage= */ bitmap,\n      /* shouldShowFps= */ true,\n      frameStartMs\n    )\n      // When the image is from CameraX analysis use case, must call image.close() on received\n      // images when finished using them. Otherwise, new images may not be received or the camera\n      // may stall.\n      .addOnCompleteListener { image.close() }\n  }\n\n  // -----------------Common processing logic-------------------------------------------------------\n  private fun requestDetectInImage(\n    image: InputImage,\n    graphicOverlay: GraphicOverlay,\n    originalCameraImage: Bitmap?,\n    shouldShowFps: Boolean,\n    frameStartMs: Long\n  ): Task<T> {\n    return setUpListener(\n      detectInImage(image),\n      graphicOverlay,\n      originalCameraImage,\n      shouldShowFps,\n      frameStartMs\n    )\n  }\n\n  private fun requestDetectInImage(\n    image: MlImage,\n    graphicOverlay: GraphicOverlay,\n    originalCameraImage: Bitmap?,\n    shouldShowFps: Boolean,\n    frameStartMs: Long\n  ): Task<T> {\n    return setUpListener(\n      detectInImage(image),\n      graphicOverlay,\n      originalCameraImage,\n      shouldShowFps,\n      frameStartMs\n    )\n  }\n\n  private fun setUpListener(\n    task: Task<T>,\n    graphicOverlay: GraphicOverlay,\n    originalCameraImage: Bitmap?,\n    shouldShowFps: Boolean,\n    frameStartMs: Long\n  ): Task<T> {\n    val detectorStartMs = SystemClock.elapsedRealtime()\n    return task\n      .addOnSuccessListener(\n        executor,\n        OnSuccessListener { results: T ->\n          val endMs = SystemClock.elapsedRealtime()\n          val currentFrameLatencyMs = endMs - frameStartMs\n          val currentDetectorLatencyMs = endMs - detectorStartMs\n          if (numRuns >= 500) {\n            resetLatencyStats()\n          }\n          numRuns++\n          frameProcessedInOneSecondInterval++\n          totalFrameMs += currentFrameLatencyMs\n          maxFrameMs = max(currentFrameLatencyMs, maxFrameMs)\n          minFrameMs = min(currentFrameLatencyMs, minFrameMs)\n          totalDetectorMs += currentDetectorLatencyMs\n          maxDetectorMs = max(currentDetectorLatencyMs, maxDetectorMs)\n          minDetectorMs = min(currentDetectorLatencyMs, minDetectorMs)\n\n          // Only log inference info once per second. When frameProcessedInOneSecondInterval is\n          // equal to 1, it means this is the first frame processed during the current second.\n          if (frameProcessedInOneSecondInterval == 1) {\n            Log.d(TAG, \"Num of Runs: $numRuns\")\n            Log.d(\n              TAG,\n              \"Frame latency: max=\" +\n                maxFrameMs +\n                \", min=\" +\n                minFrameMs +\n                \", avg=\" +\n                totalFrameMs / numRuns\n            )\n            Log.d(\n              TAG,\n              \"Detector latency: max=\" +\n                maxDetectorMs +\n                \", min=\" +\n                minDetectorMs +\n                \", avg=\" +\n                totalDetectorMs / numRuns\n            )\n            val mi = ActivityManager.MemoryInfo()\n            activityManager.getMemoryInfo(mi)\n            val availableMegs: Long = mi.availMem / 0x100000L\n            Log.d(TAG, \"Memory available in system: $availableMegs MB\")\n          }\n          graphicOverlay.clear()\n          if (originalCameraImage != null) {\n            graphicOverlay.add(CameraImageGraphic(graphicOverlay, originalCameraImage))\n          }\n          this@VisionProcessorBase.onSuccess(results, graphicOverlay)\n          if (!PreferenceUtils.shouldHideDetectionInfo(graphicOverlay.context)) {\n            graphicOverlay.add(\n              InferenceInfoGraphic(\n                graphicOverlay,\n                currentFrameLatencyMs,\n                currentDetectorLatencyMs,\n                if (shouldShowFps) framesPerSecond else null\n              )\n            )\n          }\n          graphicOverlay.postInvalidate()\n        }\n      )\n      .addOnFailureListener(\n        executor,\n        OnFailureListener { e: Exception ->\n          graphicOverlay.clear()\n          graphicOverlay.postInvalidate()\n          val error = \"Failed to process. Error: \" + e.localizedMessage\n          Toast.makeText(\n              graphicOverlay.context,\n              \"\"\"\n          $error\n          Cause: ${e.cause}\n          \"\"\".trimIndent(),\n              Toast.LENGTH_SHORT\n            )\n            .show()\n          Log.d(TAG, error)\n          e.printStackTrace()\n          this@VisionProcessorBase.onFailure(e)\n        }\n      )\n  }\n\n  override fun stop() {\n    executor.shutdown()\n    isShutdown = true\n    resetLatencyStats()\n    fpsTimer.cancel()\n  }\n\n  private fun resetLatencyStats() {\n    numRuns = 0\n    totalFrameMs = 0\n    maxFrameMs = 0\n    minFrameMs = Long.MAX_VALUE\n    totalDetectorMs = 0\n    maxDetectorMs = 0\n    minDetectorMs = Long.MAX_VALUE\n  }\n\n  protected abstract fun detectInImage(image: InputImage): Task<T>\n\n  protected open fun detectInImage(image: MlImage): Task<T> {\n    return Tasks.forException(\n      MlKitException(\n        \"MlImage is currently not demonstrated for this feature\",\n        MlKitException.INVALID_ARGUMENT\n      )\n    )\n  }\n\n  protected abstract fun onSuccess(results: T, graphicOverlay: GraphicOverlay)\n\n  protected abstract fun onFailure(e: Exception)\n\n  protected open fun isMlImageEnabled(context: Context?): Boolean {\n    return false\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/barcodescanner/BarcodeGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.barcodescanner\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport android.graphics.RectF\nimport com.google.mlkit.vision.barcode.common.Barcode\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic\nimport kotlin.math.max\nimport kotlin.math.min\n\n/** Graphic instance for rendering Barcode position and content information in an overlay view. */\nclass BarcodeGraphic constructor(overlay: GraphicOverlay?, private val barcode: Barcode?) :\n  Graphic(overlay) {\n  private val rectPaint: Paint = Paint()\n  private val barcodePaint: Paint\n  private val labelPaint: Paint\n\n  init {\n    rectPaint.color = MARKER_COLOR\n    rectPaint.style = Paint.Style.STROKE\n    rectPaint.strokeWidth = STROKE_WIDTH\n    barcodePaint = Paint()\n    barcodePaint.color = TEXT_COLOR\n    barcodePaint.textSize = TEXT_SIZE\n    labelPaint = Paint()\n    labelPaint.color = MARKER_COLOR\n    labelPaint.style = Paint.Style.FILL\n  }\n\n  /**\n   * Draws the barcode block annotations for position, size, and raw value on the supplied canvas.\n   */\n  override fun draw(canvas: Canvas) {\n    checkNotNull(barcode) { \"Attempting to draw a null barcode.\" }\n    // Draws the bounding box around the BarcodeBlock.\n    val rect = RectF(barcode.boundingBox)\n    // If the image is flipped, the left will be translated to right, and the right to left.\n    val x0 = translateX(rect.left)\n    val x1 = translateX(rect.right)\n    rect.left = min(x0, x1)\n    rect.right = max(x0, x1)\n    rect.top = translateY(rect.top)\n    rect.bottom = translateY(rect.bottom)\n    canvas.drawRect(rect, rectPaint)\n    // Draws other object info.\n    val lineHeight = TEXT_SIZE + 2 * STROKE_WIDTH\n    val textWidth = barcodePaint.measureText(barcode.displayValue)\n    canvas.drawRect(\n      rect.left - STROKE_WIDTH,\n      rect.top - lineHeight,\n      rect.left + textWidth + 2 * STROKE_WIDTH,\n      rect.top,\n      labelPaint\n    )\n    // Renders the barcode at the bottom of the box.\n    canvas.drawText(barcode.displayValue!!, rect.left, rect.top - STROKE_WIDTH, barcodePaint)\n  }\n\n  companion object {\n    private const val TEXT_COLOR = Color.BLACK\n    private const val MARKER_COLOR = Color.WHITE\n    private const val TEXT_SIZE = 54.0f\n    private const val STROKE_WIDTH = 4.0f\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/barcodescanner/BarcodeScannerProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.barcodescanner\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.vision.barcode.BarcodeScanner\nimport com.google.mlkit.vision.barcode.BarcodeScannerOptions\nimport com.google.mlkit.vision.barcode.BarcodeScanning\nimport com.google.mlkit.vision.barcode.ZoomSuggestionOptions\nimport com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback\nimport com.google.mlkit.vision.barcode.common.Barcode\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\n\n/** Barcode Detector Demo. */\nclass BarcodeScannerProcessor(context: Context, zoomCallback: ZoomCallback?) :\n  VisionProcessorBase<List<Barcode>>(context) {\n\n  private var barcodeScanner: BarcodeScanner\n\n  init {\n    // Note that if you know which format of barcode your app is dealing with, detection will be\n    // faster to specify the supported barcode formats one by one, e.g.\n    // BarcodeScannerOptions.Builder()\n    //     .setBarcodeFormats(Barcode.FORMAT_QR_CODE)\n    //     .build();\n    barcodeScanner =\n      if (zoomCallback != null) {\n        val options =\n          BarcodeScannerOptions.Builder()\n            .setZoomSuggestionOptions(ZoomSuggestionOptions.Builder(zoomCallback).build())\n            .build()\n        BarcodeScanning.getClient(options)\n      } else {\n        BarcodeScanning.getClient()\n      }\n  }\n\n  override fun stop() {\n    super.stop()\n    barcodeScanner.close()\n  }\n\n  override fun detectInImage(image: InputImage): Task<List<Barcode>> {\n    return barcodeScanner.process(image)\n  }\n\n  override fun onSuccess(barcodes: List<Barcode>, graphicOverlay: GraphicOverlay) {\n    if (barcodes.isEmpty()) {\n      Log.v(MANUAL_TESTING_LOG, \"No barcode has been detected\")\n    }\n    for (i in barcodes.indices) {\n      val barcode = barcodes[i]\n      graphicOverlay.add(BarcodeGraphic(graphicOverlay, barcode))\n      logExtrasForTesting(barcode)\n    }\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.e(TAG, \"Barcode detection failed $e\")\n  }\n\n  companion object {\n    private const val TAG = \"BarcodeProcessor\"\n\n    private fun logExtrasForTesting(barcode: Barcode?) {\n      if (barcode != null) {\n        Log.v(\n          MANUAL_TESTING_LOG,\n          String.format(\n            \"Detected barcode's bounding box: %s\",\n            barcode.boundingBox!!.flattenToString()\n          )\n        )\n        Log.v(\n          MANUAL_TESTING_LOG,\n          String.format(\"Expected corner point size is 4, get %d\", barcode.cornerPoints!!.size)\n        )\n        for (point in barcode.cornerPoints!!) {\n          Log.v(\n            MANUAL_TESTING_LOG,\n            String.format(\"Corner point is located at: x = %d, y = %d\", point.x, point.y)\n          )\n        }\n        Log.v(MANUAL_TESTING_LOG, \"barcode display value: \" + barcode.displayValue)\n        Log.v(MANUAL_TESTING_LOG, \"barcode raw value: \" + barcode.rawValue)\n        val dl = barcode.driverLicense\n        if (dl != null) {\n          Log.v(MANUAL_TESTING_LOG, \"driver license city: \" + dl.addressCity)\n          Log.v(MANUAL_TESTING_LOG, \"driver license state: \" + dl.addressState)\n          Log.v(MANUAL_TESTING_LOG, \"driver license street: \" + dl.addressStreet)\n          Log.v(MANUAL_TESTING_LOG, \"driver license zip code: \" + dl.addressZip)\n          Log.v(MANUAL_TESTING_LOG, \"driver license birthday: \" + dl.birthDate)\n          Log.v(MANUAL_TESTING_LOG, \"driver license document type: \" + dl.documentType)\n          Log.v(MANUAL_TESTING_LOG, \"driver license expiry date: \" + dl.expiryDate)\n          Log.v(MANUAL_TESTING_LOG, \"driver license first name: \" + dl.firstName)\n          Log.v(MANUAL_TESTING_LOG, \"driver license middle name: \" + dl.middleName)\n          Log.v(MANUAL_TESTING_LOG, \"driver license last name: \" + dl.lastName)\n          Log.v(MANUAL_TESTING_LOG, \"driver license gender: \" + dl.gender)\n          Log.v(MANUAL_TESTING_LOG, \"driver license issue date: \" + dl.issueDate)\n          Log.v(MANUAL_TESTING_LOG, \"driver license issue country: \" + dl.issuingCountry)\n          Log.v(MANUAL_TESTING_LOG, \"driver license number: \" + dl.licenseNumber)\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/facedetector/FaceDetectorProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.facedetector\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\nimport com.google.mlkit.vision.face.Face\nimport com.google.mlkit.vision.face.FaceDetection\nimport com.google.mlkit.vision.face.FaceDetector\nimport com.google.mlkit.vision.face.FaceDetectorOptions\nimport com.google.mlkit.vision.face.FaceLandmark\nimport java.util.Locale\n\n/** Face Detector Demo.  */\nclass FaceDetectorProcessor(context: Context, detectorOptions: FaceDetectorOptions?) :\n  VisionProcessorBase<List<Face>>(context) {\n\n  private val detector: FaceDetector\n\n  init {\n    val options = detectorOptions\n      ?: FaceDetectorOptions.Builder()\n        .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)\n        .enableTracking()\n        .build()\n\n    detector = FaceDetection.getClient(options)\n\n    Log.v(MANUAL_TESTING_LOG, \"Face detector options: $options\")\n  }\n\n  override fun stop() {\n    super.stop()\n    detector.close()\n  }\n\n  override fun detectInImage(image: InputImage): Task<List<Face>> {\n    return detector.process(image)\n  }\n\n  override fun onSuccess(faces: List<Face>, graphicOverlay: GraphicOverlay) {\n    for (face in faces) {\n      graphicOverlay.add(FaceGraphic(graphicOverlay, face))\n      logExtrasForTesting(face)\n    }\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.e(TAG, \"Face detection failed $e\")\n  }\n\n  companion object {\n    private const val TAG = \"FaceDetectorProcessor\"\n    private fun logExtrasForTesting(face: Face?) {\n      if (face != null) {\n        Log.v(\n          MANUAL_TESTING_LOG,\n          \"face bounding box: \" + face.boundingBox.flattenToString()\n        )\n        Log.v(\n          MANUAL_TESTING_LOG,\n          \"face Euler Angle X: \" + face.headEulerAngleX\n        )\n        Log.v(\n          MANUAL_TESTING_LOG,\n          \"face Euler Angle Y: \" + face.headEulerAngleY\n        )\n        Log.v(\n          MANUAL_TESTING_LOG,\n          \"face Euler Angle Z: \" + face.headEulerAngleZ\n        )\n        // All landmarks\n        val landMarkTypes = intArrayOf(\n          FaceLandmark.MOUTH_BOTTOM,\n          FaceLandmark.MOUTH_RIGHT,\n          FaceLandmark.MOUTH_LEFT,\n          FaceLandmark.RIGHT_EYE,\n          FaceLandmark.LEFT_EYE,\n          FaceLandmark.RIGHT_EAR,\n          FaceLandmark.LEFT_EAR,\n          FaceLandmark.RIGHT_CHEEK,\n          FaceLandmark.LEFT_CHEEK,\n          FaceLandmark.NOSE_BASE\n        )\n        val landMarkTypesStrings = arrayOf(\n          \"MOUTH_BOTTOM\",\n          \"MOUTH_RIGHT\",\n          \"MOUTH_LEFT\",\n          \"RIGHT_EYE\",\n          \"LEFT_EYE\",\n          \"RIGHT_EAR\",\n          \"LEFT_EAR\",\n          \"RIGHT_CHEEK\",\n          \"LEFT_CHEEK\",\n          \"NOSE_BASE\"\n        )\n        for (i in landMarkTypes.indices) {\n          val landmark = face.getLandmark(landMarkTypes[i])\n          if (landmark == null) {\n            Log.v(\n              MANUAL_TESTING_LOG,\n              \"No landmark of type: \" + landMarkTypesStrings[i] + \" has been detected\"\n            )\n          } else {\n            val landmarkPosition = landmark.position\n            val landmarkPositionStr =\n              String.format(Locale.US, \"x: %f , y: %f\", landmarkPosition.x, landmarkPosition.y)\n            Log.v(\n              MANUAL_TESTING_LOG,\n              \"Position for face landmark: \" +\n                landMarkTypesStrings[i] +\n                \" is :\" +\n                landmarkPositionStr\n            )\n          }\n        }\n        Log.v(\n          MANUAL_TESTING_LOG,\n          \"face left eye open probability: \" + face.leftEyeOpenProbability\n        )\n        Log.v(\n          MANUAL_TESTING_LOG,\n          \"face right eye open probability: \" + face.rightEyeOpenProbability\n        )\n        Log.v(\n          MANUAL_TESTING_LOG,\n          \"face smiling probability: \" + face.smilingProbability\n        )\n        Log.v(\n          MANUAL_TESTING_LOG,\n          \"face tracking id: \" + face.trackingId\n        )\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/facedetector/FaceGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.facedetector\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic\nimport com.google.mlkit.vision.face.Face\nimport com.google.mlkit.vision.face.FaceLandmark\nimport com.google.mlkit.vision.face.FaceLandmark.LandmarkType\nimport java.util.Locale\nimport kotlin.math.abs\nimport kotlin.math.max\n\n/**\n * Graphic instance for rendering face position, contour, and landmarks within the associated\n * graphic overlay view.\n */\nclass FaceGraphic constructor(overlay: GraphicOverlay?, private val face: Face) : Graphic(overlay) {\n  private val facePositionPaint: Paint\n  private val numColors = COLORS.size\n  private val idPaints = Array(numColors) { Paint() }\n  private val boxPaints = Array(numColors) { Paint() }\n  private val labelPaints = Array(numColors) { Paint() }\n\n  init {\n    val selectedColor = Color.WHITE\n    facePositionPaint = Paint()\n    facePositionPaint.color = selectedColor\n    for (i in 0 until numColors) {\n      idPaints[i] = Paint()\n      idPaints[i].color = COLORS[i][0]\n      idPaints[i].textSize = ID_TEXT_SIZE\n      boxPaints[i] = Paint()\n      boxPaints[i].color = COLORS[i][1]\n      boxPaints[i].style = Paint.Style.STROKE\n      boxPaints[i].strokeWidth = BOX_STROKE_WIDTH\n      labelPaints[i] = Paint()\n      labelPaints[i].color = COLORS[i][1]\n      labelPaints[i].style = Paint.Style.FILL\n    }\n  }\n\n  /** Draws the face annotations for position on the supplied canvas. */\n  override fun draw(canvas: Canvas) {\n    // Draws a circle at the position of the detected face, with the face's track id below.\n\n    // Draws a circle at the position of the detected face, with the face's track id below.\n    val x = translateX(face.boundingBox.centerX().toFloat())\n    val y = translateY(face.boundingBox.centerY().toFloat())\n    canvas.drawCircle(x, y, FACE_POSITION_RADIUS, facePositionPaint)\n\n    // Calculate positions.\n    val left = x - scale(face.boundingBox.width() / 2.0f)\n    val top = y - scale(face.boundingBox.height() / 2.0f)\n    val right = x + scale(face.boundingBox.width() / 2.0f)\n    val bottom = y + scale(face.boundingBox.height() / 2.0f)\n    val lineHeight = ID_TEXT_SIZE + BOX_STROKE_WIDTH\n    var yLabelOffset: Float = if (face.trackingId == null) 0f else -lineHeight\n\n    // Decide color based on face ID\n    val colorID = if (face.trackingId == null) 0 else abs(face.trackingId!! % NUM_COLORS)\n\n    // Calculate width and height of label box\n    var textWidth = idPaints[colorID].measureText(\"ID: \" + face.trackingId)\n    if (face.smilingProbability != null) {\n      yLabelOffset -= lineHeight\n      textWidth =\n        max(\n          textWidth,\n          idPaints[colorID].measureText(\n            String.format(Locale.US, \"Happiness: %.2f\", face.smilingProbability)\n          )\n        )\n    }\n    if (face.leftEyeOpenProbability != null) {\n      yLabelOffset -= lineHeight\n      textWidth =\n        max(\n          textWidth,\n          idPaints[colorID].measureText(\n            String.format(Locale.US, \"Left eye open: %.2f\", face.leftEyeOpenProbability)\n          )\n        )\n    }\n    if (face.rightEyeOpenProbability != null) {\n      yLabelOffset -= lineHeight\n      textWidth =\n        max(\n          textWidth,\n          idPaints[colorID].measureText(\n            String.format(Locale.US, \"Right eye open: %.2f\", face.rightEyeOpenProbability)\n          )\n        )\n    }\n\n    yLabelOffset = yLabelOffset - 3 * lineHeight\n    textWidth =\n      Math.max(\n        textWidth,\n        idPaints[colorID].measureText(\n          String.format(Locale.US, \"EulerX: %.2f\", face.headEulerAngleX)\n        )\n      )\n    textWidth =\n      Math.max(\n        textWidth,\n        idPaints[colorID].measureText(\n          String.format(Locale.US, \"EulerY: %.2f\", face.headEulerAngleY)\n        )\n      )\n    textWidth =\n      Math.max(\n        textWidth,\n        idPaints[colorID].measureText(\n          String.format(Locale.US, \"EulerZ: %.2f\", face.headEulerAngleZ)\n        )\n      )\n\n    // Draw labels\n    canvas.drawRect(\n      left - BOX_STROKE_WIDTH,\n      top + yLabelOffset,\n      left + textWidth + 2 * BOX_STROKE_WIDTH,\n      top,\n      labelPaints[colorID]\n    )\n    yLabelOffset += ID_TEXT_SIZE\n    canvas.drawRect(left, top, right, bottom, boxPaints[colorID])\n    if (face.trackingId != null) {\n      canvas.drawText(\"ID: \" + face.trackingId, left, top + yLabelOffset, idPaints[colorID])\n      yLabelOffset += lineHeight\n    }\n\n    // Draws all face contours.\n    for (contour in face.allContours) {\n      for (point in contour.points) {\n        canvas.drawCircle(\n          translateX(point.x),\n          translateY(point.y),\n          FACE_POSITION_RADIUS,\n          facePositionPaint\n        )\n      }\n    }\n\n    // Draws smiling and left/right eye open probabilities.\n    if (face.smilingProbability != null) {\n      canvas.drawText(\n        \"Smiling: \" + String.format(Locale.US, \"%.2f\", face.smilingProbability),\n        left,\n        top + yLabelOffset,\n        idPaints[colorID]\n      )\n      yLabelOffset += lineHeight\n    }\n\n    val leftEye = face.getLandmark(FaceLandmark.LEFT_EYE)\n    if (face.leftEyeOpenProbability != null) {\n      canvas.drawText(\n        \"Left eye open: \" + String.format(Locale.US, \"%.2f\", face.leftEyeOpenProbability),\n        left,\n        top + yLabelOffset,\n        idPaints[colorID]\n      )\n      yLabelOffset += lineHeight\n    }\n    if (leftEye != null) {\n      val leftEyeLeft =\n        translateX(leftEye.position.x) - idPaints[colorID].measureText(\"Left Eye\") / 2.0f\n      canvas.drawRect(\n        leftEyeLeft - BOX_STROKE_WIDTH,\n        translateY(leftEye.position.y) + ID_Y_OFFSET - ID_TEXT_SIZE,\n        leftEyeLeft + idPaints[colorID].measureText(\"Left Eye\") + BOX_STROKE_WIDTH,\n        translateY(leftEye.position.y) + ID_Y_OFFSET + BOX_STROKE_WIDTH,\n        labelPaints[colorID]\n      )\n      canvas.drawText(\n        \"Left Eye\",\n        leftEyeLeft,\n        translateY(leftEye.position.y) + ID_Y_OFFSET,\n        idPaints[colorID]\n      )\n    }\n\n    val rightEye = face.getLandmark(FaceLandmark.RIGHT_EYE)\n    if (face.rightEyeOpenProbability != null) {\n      canvas.drawText(\n        \"Right eye open: \" + String.format(Locale.US, \"%.2f\", face.rightEyeOpenProbability),\n        left,\n        top + yLabelOffset,\n        idPaints[colorID]\n      )\n      yLabelOffset += lineHeight\n    }\n    if (rightEye != null) {\n      val rightEyeLeft =\n        translateX(rightEye.position.x) - idPaints[colorID].measureText(\"Right Eye\") / 2.0f\n      canvas.drawRect(\n        rightEyeLeft - BOX_STROKE_WIDTH,\n        translateY(rightEye.position.y) + ID_Y_OFFSET - ID_TEXT_SIZE,\n        rightEyeLeft + idPaints[colorID].measureText(\"Right Eye\") + BOX_STROKE_WIDTH,\n        translateY(rightEye.position.y) + ID_Y_OFFSET + BOX_STROKE_WIDTH,\n        labelPaints[colorID]\n      )\n      canvas.drawText(\n        \"Right Eye\",\n        rightEyeLeft,\n        translateY(rightEye.position.y) + ID_Y_OFFSET,\n        idPaints[colorID]\n      )\n    }\n\n    canvas.drawText(\"EulerX: \" + face.headEulerAngleX, left, top + yLabelOffset, idPaints[colorID])\n    yLabelOffset += lineHeight\n    canvas.drawText(\"EulerY: \" + face.headEulerAngleY, left, top + yLabelOffset, idPaints[colorID])\n    yLabelOffset += lineHeight\n    canvas.drawText(\"EulerZ: \" + face.headEulerAngleZ, left, top + yLabelOffset, idPaints[colorID])\n\n    // Draw facial landmarks\n    drawFaceLandmark(canvas, FaceLandmark.LEFT_EYE)\n    drawFaceLandmark(canvas, FaceLandmark.RIGHT_EYE)\n    drawFaceLandmark(canvas, FaceLandmark.LEFT_CHEEK)\n    drawFaceLandmark(canvas, FaceLandmark.RIGHT_CHEEK)\n  }\n\n  private fun drawFaceLandmark(canvas: Canvas, @LandmarkType landmarkType: Int) {\n    val faceLandmark = face.getLandmark(landmarkType)\n    if (faceLandmark != null) {\n      canvas.drawCircle(\n        translateX(faceLandmark.position.x),\n        translateY(faceLandmark.position.y),\n        FACE_POSITION_RADIUS,\n        facePositionPaint\n      )\n    }\n  }\n\n  companion object {\n    private const val FACE_POSITION_RADIUS = 8.0f\n    private const val ID_TEXT_SIZE = 30.0f\n    private const val ID_Y_OFFSET = 40.0f\n    private const val BOX_STROKE_WIDTH = 5.0f\n    private const val NUM_COLORS = 10\n    private val COLORS =\n      arrayOf(\n        intArrayOf(Color.BLACK, Color.WHITE),\n        intArrayOf(Color.WHITE, Color.MAGENTA),\n        intArrayOf(Color.BLACK, Color.LTGRAY),\n        intArrayOf(Color.WHITE, Color.RED),\n        intArrayOf(Color.WHITE, Color.BLUE),\n        intArrayOf(Color.WHITE, Color.DKGRAY),\n        intArrayOf(Color.BLACK, Color.CYAN),\n        intArrayOf(Color.BLACK, Color.YELLOW),\n        intArrayOf(Color.WHITE, Color.BLACK),\n        intArrayOf(Color.BLACK, Color.GREEN)\n      )\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/facemeshdetector/FaceMeshDetectorProcessor.kt",
    "content": "/*\n * Copyright 2022 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.vision.demo.kotlin.facemeshdetector\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.tasks.Task\nimport com.google.android.odml.image.MlImage\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport com.google.mlkit.vision.facemesh.FaceMesh\nimport com.google.mlkit.vision.facemesh.FaceMeshDetection\nimport com.google.mlkit.vision.facemesh.FaceMeshDetector\nimport com.google.mlkit.vision.facemesh.FaceMeshDetectorOptions\n\n/** Face Mesh Detector Demo. */\nclass FaceMeshDetectorProcessor(context: Context) :\n  VisionProcessorBase<List<FaceMesh>>(context) {\n\n  private val detector: FaceMeshDetector\n\n  init {\n    val optionsBuilder = FaceMeshDetectorOptions.Builder()\n    if (PreferenceUtils.getFaceMeshUseCase(context) == FaceMeshDetectorOptions.BOUNDING_BOX_ONLY) {\n      optionsBuilder.setUseCase(FaceMeshDetectorOptions.BOUNDING_BOX_ONLY)\n    }\n    detector = FaceMeshDetection.getClient(optionsBuilder.build())\n  }\n\n  override fun stop() {\n    super.stop()\n    detector.close()\n  }\n\n  override fun detectInImage(image: InputImage): Task<List<FaceMesh>> {\n    return detector.process(image)\n  }\n\n  override fun onSuccess(faces: List<FaceMesh>, graphicOverlay: GraphicOverlay) {\n    for (face in faces) {\n      graphicOverlay.add(FaceMeshGraphic(graphicOverlay, face))\n    }\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.e(TAG, \"Face detection failed $e\")\n  }\n\n  companion object {\n    private const val TAG = \"SelfieFaceProcessor\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/facemeshdetector/FaceMeshGraphic.kt",
    "content": "/*\n * Copyright 2022 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.google.mlkit.vision.demo.kotlin.facemeshdetector\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport android.graphics.RectF\nimport com.google.mlkit.vision.common.PointF3D\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport com.google.mlkit.vision.facemesh.FaceMesh\nimport com.google.mlkit.vision.facemesh.FaceMeshDetectorOptions\nimport com.google.mlkit.vision.facemesh.FaceMeshPoint\n\n/**\n * Graphic instance for rendering face position and mesh info within the associated graphic overlay\n * view.\n */\nclass FaceMeshGraphic(overlay: GraphicOverlay, private val faceMesh: FaceMesh) :\n  GraphicOverlay.Graphic(overlay) {\n\n  private val positionPaint: Paint\n  private val boxPaint: Paint\n  private val useCase: Int\n  private var zMin: Float\n  private var zMax: Float\n\n  @FaceMesh.ContourType\n  private val DISPLAY_CONTOURS =\n    intArrayOf(\n      FaceMesh.FACE_OVAL,\n      FaceMesh.LEFT_EYEBROW_TOP,\n      FaceMesh.LEFT_EYEBROW_BOTTOM,\n      FaceMesh.RIGHT_EYEBROW_TOP,\n      FaceMesh.RIGHT_EYEBROW_BOTTOM,\n      FaceMesh.LEFT_EYE,\n      FaceMesh.RIGHT_EYE,\n      FaceMesh.UPPER_LIP_TOP,\n      FaceMesh.UPPER_LIP_BOTTOM,\n      FaceMesh.LOWER_LIP_TOP,\n      FaceMesh.LOWER_LIP_BOTTOM,\n      FaceMesh.NOSE_BRIDGE\n    )\n\n  /** Draws the face annotations for position on the supplied canvas. */\n  override fun draw(canvas: Canvas) {\n\n    // Draws the bounding box.\n    val rect = RectF(faceMesh.boundingBox)\n    // If the image is flipped, the left will be translated to right, and the right to left.\n    val x0 = translateX(rect.left)\n    val x1 = translateX(rect.right)\n    rect.left = Math.min(x0, x1)\n    rect.right = Math.max(x0, x1)\n    rect.top = translateY(rect.top)\n    rect.bottom = translateY(rect.bottom)\n    canvas.drawRect(rect, boxPaint)\n\n    // Draw face mesh\n    val points =\n      if (useCase == USE_CASE_CONTOUR_ONLY) getContourPoints(faceMesh) else faceMesh.allPoints\n    val triangles = faceMesh.allTriangles\n\n    zMin = Float.MAX_VALUE\n    zMax = Float.MIN_VALUE\n    for (point in points) {\n      zMin = Math.min(zMin, point.position.z)\n      zMax = Math.max(zMax, point.position.z)\n    }\n\n    // Draw face mesh points\n    for (point in points) {\n      updatePaintColorByZValue(\n        positionPaint,\n        canvas,\n        /* visualizeZ= */true,\n        /* rescaleZForVisualization= */true,\n        point.position.z,\n        zMin,\n        zMax)\n      canvas.drawCircle(\n        translateX(point.position.x),\n        translateY(point.position.y),\n        FACE_POSITION_RADIUS,\n        positionPaint\n      )\n    }\n\n    if (useCase == FaceMeshDetectorOptions.FACE_MESH) {\n      // Draw face mesh triangles\n      for (triangle in triangles) {\n        val point1 = triangle.allPoints[0].position\n        val point2 = triangle.allPoints[1].position\n        val point3 = triangle.allPoints[2].position\n        drawLine(canvas, point1, point2)\n        drawLine(canvas, point1, point3)\n        drawLine(canvas, point2, point3)\n      }\n    }\n  }\n\n  private fun drawLine(canvas: Canvas, point1: PointF3D, point2: PointF3D) {\n    updatePaintColorByZValue(\n      positionPaint,\n      canvas,\n      /* visualizeZ= */true,\n      /* rescaleZForVisualization= */true,\n      (point1.z + point2.z) / 2,\n      zMin,\n      zMax)\n    canvas.drawLine(\n      translateX(point1.x),\n      translateY(point1.y),\n      translateX(point2.x),\n      translateY(point2.y),\n      positionPaint\n    )\n  }\n\n  private fun getContourPoints(faceMesh: FaceMesh): List<FaceMeshPoint> {\n    val contourPoints: MutableList<FaceMeshPoint> = ArrayList()\n    for (type in DISPLAY_CONTOURS) {\n      contourPoints.addAll(faceMesh.getPoints(type))\n    }\n    return contourPoints\n  }\n\n  companion object {\n    private const val USE_CASE_CONTOUR_ONLY = 999\n    private const val FACE_POSITION_RADIUS = 8.0f\n    private const val BOX_STROKE_WIDTH = 5.0f\n  }\n\n  init {\n    val selectedColor = Color.WHITE\n    positionPaint = Paint()\n    positionPaint.color = selectedColor\n\n    boxPaint = Paint()\n    boxPaint.color = selectedColor\n    boxPaint.style = Paint.Style.STROKE\n    boxPaint.strokeWidth = BOX_STROKE_WIDTH\n\n    useCase = PreferenceUtils.getFaceMeshUseCase(applicationContext)\n    zMin = java.lang.Float.MAX_VALUE\n    zMax = java.lang.Float.MIN_VALUE\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/labeldetector/LabelDetectorProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.labeldetector\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\nimport com.google.mlkit.vision.label.ImageLabel\nimport com.google.mlkit.vision.label.ImageLabeler\nimport com.google.mlkit.vision.label.ImageLabelerOptionsBase\nimport com.google.mlkit.vision.label.ImageLabeling\nimport java.io.IOException\n\n/** Custom InputImage Classifier Demo.  */\nclass LabelDetectorProcessor(context: Context, options: ImageLabelerOptionsBase) :\n  VisionProcessorBase<List<ImageLabel>>(context) {\n\n  private val imageLabeler: ImageLabeler = ImageLabeling.getClient(options)\n\n  override fun stop() {\n    super.stop()\n    try {\n      imageLabeler.close()\n    } catch (e: IOException) {\n      Log.e(\n        TAG,\n        \"Exception thrown while trying to close ImageLabelerClient: $e\"\n      )\n    }\n  }\n\n  override fun detectInImage(image: InputImage): Task<List<ImageLabel>> {\n    return imageLabeler.process(image)\n  }\n\n  override fun onSuccess(labels: List<ImageLabel>, graphicOverlay: GraphicOverlay) {\n    graphicOverlay.add(LabelGraphic(graphicOverlay, labels))\n    logExtrasForTesting(labels)\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.w(TAG, \"Label detection failed.$e\")\n  }\n\n  companion object {\n    private const val TAG = \"LabelDetectorProcessor\"\n\n    private fun logExtrasForTesting(labels: List<ImageLabel>?) {\n      if (labels == null) {\n        Log.v(MANUAL_TESTING_LOG, \"No labels detected\")\n      } else {\n        for (label in labels) {\n          Log.v(\n            MANUAL_TESTING_LOG,\n            String.format(\"Label %s, confidence %f\", label.text, label.confidence)\n          )\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/labeldetector/LabelGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.labeldetector\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic\nimport com.google.mlkit.vision.label.ImageLabel\nimport java.util.Locale\n\n/** Graphic instance for rendering a label within an associated graphic overlay view.  */\nclass LabelGraphic(\n  private val overlay: GraphicOverlay,\n  private val labels: List<ImageLabel>\n) : Graphic(overlay) {\n  private val textPaint: Paint = Paint()\n  private val labelPaint: Paint\n\n  init {\n    textPaint.color = Color.WHITE\n    textPaint.textSize = TEXT_SIZE\n    labelPaint = Paint()\n    labelPaint.color = Color.BLACK\n    labelPaint.style = Paint.Style.FILL\n    labelPaint.alpha = 200\n  }\n\n  @Synchronized\n  override fun draw(canvas: Canvas) {\n    // First try to find maxWidth and totalHeight in order to draw to the center of the screen.\n    var maxWidth = 0f\n    val totalHeight = labels.size * 2 * TEXT_SIZE\n    for (label in labels) {\n      val line1Width = textPaint.measureText(label.text)\n      val line2Width =\n        textPaint.measureText(\n          String.format(\n            Locale.US,\n            LABEL_FORMAT,\n            label.confidence * 100,\n            label.index\n          )\n        )\n\n      maxWidth = Math.max(maxWidth, Math.max(line1Width, line2Width))\n    }\n\n    val x = Math.max(0f, overlay.width / 2.0f - maxWidth / 2.0f)\n    var y = Math.max(200f, overlay.height / 2.0f - totalHeight / 2.0f)\n\n    if (!labels.isEmpty()) {\n      val padding = 20f\n      canvas.drawRect(\n        x - padding,\n        y - padding,\n        x + maxWidth + padding,\n        y + totalHeight + padding,\n        labelPaint\n      )\n    }\n\n    for (label in labels) {\n      if (y + TEXT_SIZE * 2 > overlay.height) {\n        break\n      }\n      canvas.drawText(label.text, x, y + TEXT_SIZE, textPaint)\n      y += TEXT_SIZE\n      canvas.drawText(\n        String.format(\n          Locale.US,\n          LABEL_FORMAT,\n          label.confidence * 100,\n          label.index\n        ),\n        x, y + TEXT_SIZE, textPaint\n      )\n      y += TEXT_SIZE\n    }\n  }\n\n  companion object {\n    private const val TEXT_SIZE = 70.0f\n    private const val LABEL_FORMAT = \"%.2f%% confidence (index: %d)\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/objectdetector/ObjectDetectorProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.objectdetector\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\nimport com.google.mlkit.vision.objects.DetectedObject\nimport com.google.mlkit.vision.objects.ObjectDetection\nimport com.google.mlkit.vision.objects.ObjectDetector\nimport com.google.mlkit.vision.objects.ObjectDetectorOptionsBase\nimport java.io.IOException\n\n/** A processor to run object detector.  */\nclass ObjectDetectorProcessor(context: Context, options: ObjectDetectorOptionsBase) :\n  VisionProcessorBase<List<DetectedObject>>(context) {\n\n  private val detector: ObjectDetector = ObjectDetection.getClient(options)\n\n  override fun stop() {\n    super.stop()\n    try {\n      detector.close()\n    } catch (e: IOException) {\n      Log.e(\n        TAG,\n        \"Exception thrown while trying to close object detector!\",\n        e\n      )\n    }\n  }\n\n  override fun detectInImage(image: InputImage): Task<List<DetectedObject>> {\n    return detector.process(image)\n  }\n\n  override fun onSuccess(results: List<DetectedObject>, graphicOverlay: GraphicOverlay) {\n    for (result in results) {\n      graphicOverlay.add(ObjectGraphic(graphicOverlay, result))\n    }\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.e(TAG, \"Object detection failed!\", e)\n  }\n\n  companion object {\n    private const val TAG = \"ObjectDetectorProcessor\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/objectdetector/ObjectGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.objectdetector\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport android.graphics.RectF\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic\nimport com.google.mlkit.vision.objects.DetectedObject\nimport java.util.Locale\nimport kotlin.math.abs\nimport kotlin.math.max\nimport kotlin.math.min\n\n/** Draw the detected object info in preview.  */\nclass ObjectGraphic constructor(\n  overlay: GraphicOverlay,\n  private val detectedObject: DetectedObject\n) : Graphic(overlay) {\n\n  private val numColors = COLORS.size\n\n  private val boxPaints = Array(numColors) { Paint() }\n  private val textPaints = Array(numColors) { Paint() }\n  private val labelPaints = Array(numColors) { Paint() }\n\n  init {\n    for (i in 0 until numColors) {\n      textPaints[i] = Paint()\n      textPaints[i].color = COLORS[i][0]\n      textPaints[i].textSize = TEXT_SIZE\n      boxPaints[i] = Paint()\n      boxPaints[i].color = COLORS[i][1]\n      boxPaints[i].style = Paint.Style.STROKE\n      boxPaints[i].strokeWidth = STROKE_WIDTH\n      labelPaints[i] = Paint()\n      labelPaints[i].color = COLORS[i][1]\n      labelPaints[i].style = Paint.Style.FILL\n    }\n  }\n\n  override fun draw(canvas: Canvas) {\n    // Decide color based on object tracking ID\n    val colorID =\n      if (detectedObject.trackingId == null) 0\n      else abs(detectedObject.trackingId!! % NUM_COLORS)\n    var textWidth =\n      textPaints[colorID].measureText(\"Tracking ID: \" + detectedObject.trackingId)\n    val lineHeight = TEXT_SIZE + STROKE_WIDTH\n    var yLabelOffset = -lineHeight\n\n    // Calculate width and height of label box\n    for (label in detectedObject.labels) {\n      textWidth =\n        max(textWidth, textPaints[colorID].measureText(label.text))\n      textWidth = max(\n        textWidth,\n        textPaints[colorID].measureText(\n          String.format(\n            Locale.US,\n            LABEL_FORMAT,\n            label.confidence * 100,\n            label.index\n          )\n        )\n      )\n      yLabelOffset -= 2 * lineHeight\n    }\n\n    // Draws the bounding box.\n    val rect = RectF(detectedObject.boundingBox)\n    val x0 = translateX(rect.left)\n    val x1 = translateX(rect.right)\n    rect.left = min(x0, x1)\n    rect.right = max(x0, x1)\n    rect.top = translateY(rect.top)\n    rect.bottom = translateY(rect.bottom)\n    canvas.drawRect(rect, boxPaints[colorID])\n\n    // Draws other object info.\n    canvas.drawRect(\n      rect.left - STROKE_WIDTH,\n      rect.top + yLabelOffset,\n      rect.left + textWidth + 2 * STROKE_WIDTH,\n      rect.top,\n      labelPaints[colorID]\n    )\n    yLabelOffset += TEXT_SIZE\n    canvas.drawText(\n      \"Tracking ID: \" + detectedObject.trackingId,\n      rect.left,\n      rect.top + yLabelOffset,\n      textPaints[colorID]\n    )\n    yLabelOffset += lineHeight\n    for (label in detectedObject.labels) {\n      canvas.drawText(\n        label.text + \" (index: \" + label.index + \")\",\n        rect.left,\n        rect.top + yLabelOffset,\n        textPaints[colorID]\n      )\n      yLabelOffset += lineHeight\n      canvas.drawText(\n        String.format(\n          Locale.US,\n          LABEL_FORMAT,\n          label.confidence * 100,\n          label.index\n        ),\n        rect.left,\n        rect.top + yLabelOffset,\n        textPaints[colorID]\n      )\n      yLabelOffset += lineHeight\n    }\n  }\n\n  companion object {\n    private const val TEXT_SIZE = 54.0f\n    private const val STROKE_WIDTH = 4.0f\n    private const val NUM_COLORS = 10\n    private val COLORS =\n      arrayOf(\n        intArrayOf(Color.BLACK, Color.WHITE),\n        intArrayOf(Color.WHITE, Color.MAGENTA),\n        intArrayOf(Color.BLACK, Color.LTGRAY),\n        intArrayOf(Color.WHITE, Color.RED),\n        intArrayOf(Color.WHITE, Color.BLUE),\n        intArrayOf(Color.WHITE, Color.DKGRAY),\n        intArrayOf(Color.BLACK, Color.CYAN),\n        intArrayOf(Color.BLACK, Color.YELLOW),\n        intArrayOf(Color.WHITE, Color.BLACK),\n        intArrayOf(Color.BLACK, Color.GREEN)\n      )\n    private const val LABEL_FORMAT = \"%.2f%% confidence (index: %d)\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/posedetector/PoseDetectorProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.posedetector\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.tasks.Task\nimport com.google.android.odml.image.MlImage\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.java.posedetector.classification.PoseClassifierProcessor\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\nimport com.google.mlkit.vision.pose.Pose\nimport com.google.mlkit.vision.pose.PoseDetection\nimport com.google.mlkit.vision.pose.PoseDetector\nimport com.google.mlkit.vision.pose.PoseDetectorOptionsBase\nimport java.util.ArrayList\nimport java.util.concurrent.Executor\nimport java.util.concurrent.Executors\n\n/** A processor to run pose detector. */\nclass PoseDetectorProcessor(\n  private val context: Context,\n  options: PoseDetectorOptionsBase,\n  private val showInFrameLikelihood: Boolean,\n  private val visualizeZ: Boolean,\n  private val rescaleZForVisualization: Boolean,\n  private val runClassification: Boolean,\n  private val isStreamMode: Boolean\n) : VisionProcessorBase<PoseDetectorProcessor.PoseWithClassification>(context) {\n\n  private val detector: PoseDetector\n  private val classificationExecutor: Executor\n\n  private var poseClassifierProcessor: PoseClassifierProcessor? = null\n\n  /** Internal class to hold Pose and classification results. */\n  class PoseWithClassification(val pose: Pose, val classificationResult: List<String>)\n\n  init {\n    detector = PoseDetection.getClient(options)\n    classificationExecutor = Executors.newSingleThreadExecutor()\n  }\n\n  override fun stop() {\n    super.stop()\n    detector.close()\n  }\n\n  override fun detectInImage(image: InputImage): Task<PoseWithClassification> {\n    return detector\n      .process(image)\n      .continueWith(\n        classificationExecutor,\n        { task ->\n          val pose = task.getResult()\n          var classificationResult: List<String> = ArrayList()\n          if (runClassification) {\n            if (poseClassifierProcessor == null) {\n              poseClassifierProcessor = PoseClassifierProcessor(context, isStreamMode)\n            }\n            classificationResult = poseClassifierProcessor!!.getPoseResult(pose)\n          }\n          PoseWithClassification(pose, classificationResult)\n        }\n      )\n  }\n\n  override fun detectInImage(image: MlImage): Task<PoseWithClassification> {\n    return detector\n      .process(image)\n      .continueWith(\n        classificationExecutor,\n        { task ->\n          val pose = task.getResult()\n          var classificationResult: List<String> = ArrayList()\n          if (runClassification) {\n            if (poseClassifierProcessor == null) {\n              poseClassifierProcessor = PoseClassifierProcessor(context, isStreamMode)\n            }\n            classificationResult = poseClassifierProcessor!!.getPoseResult(pose)\n          }\n          PoseWithClassification(pose, classificationResult)\n        }\n      )\n  }\n\n  override fun onSuccess(\n    poseWithClassification: PoseWithClassification,\n    graphicOverlay: GraphicOverlay\n  ) {\n    graphicOverlay.add(\n      PoseGraphic(\n        graphicOverlay,\n        poseWithClassification.pose,\n        showInFrameLikelihood,\n        visualizeZ,\n        rescaleZForVisualization,\n        poseWithClassification.classificationResult\n      )\n    )\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.e(TAG, \"Pose detection failed!\", e)\n  }\n\n  override fun isMlImageEnabled(context: Context?): Boolean {\n    // Use MlImage in Pose Detection by default, change it to OFF to switch to InputImage.\n    return true\n  }\n\n  companion object {\n    private val TAG = \"PoseDetectorProcessor\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/posedetector/PoseGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.posedetector\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic\nimport com.google.mlkit.vision.pose.Pose\nimport com.google.mlkit.vision.pose.PoseLandmark\nimport java.lang.Math.max\nimport java.lang.Math.min\nimport java.util.Locale\n\n/** Draw the detected pose in preview. */\nclass PoseGraphic\ninternal constructor(\n  overlay: GraphicOverlay,\n  private val pose: Pose,\n  private val showInFrameLikelihood: Boolean,\n  private val visualizeZ: Boolean,\n  private val rescaleZForVisualization: Boolean,\n  private val poseClassification: List<String>\n) : Graphic(overlay) {\n  private var zMin = java.lang.Float.MAX_VALUE\n  private var zMax = java.lang.Float.MIN_VALUE\n  private val classificationTextPaint: Paint\n  private val leftPaint: Paint\n  private val rightPaint: Paint\n  private val whitePaint: Paint\n\n  init {\n    classificationTextPaint = Paint()\n    classificationTextPaint.color = Color.WHITE\n    classificationTextPaint.textSize = POSE_CLASSIFICATION_TEXT_SIZE\n    classificationTextPaint.setShadowLayer(5.0f, 0f, 0f, Color.BLACK)\n\n    whitePaint = Paint()\n    whitePaint.strokeWidth = STROKE_WIDTH\n    whitePaint.color = Color.WHITE\n    whitePaint.textSize = IN_FRAME_LIKELIHOOD_TEXT_SIZE\n    leftPaint = Paint()\n    leftPaint.strokeWidth = STROKE_WIDTH\n    leftPaint.color = Color.GREEN\n    rightPaint = Paint()\n    rightPaint.strokeWidth = STROKE_WIDTH\n    rightPaint.color = Color.YELLOW\n  }\n\n  override fun draw(canvas: Canvas) {\n    val landmarks = pose.allPoseLandmarks\n    if (landmarks.isEmpty()) {\n      return\n    }\n\n    // Draw pose classification text.\n    val classificationX = POSE_CLASSIFICATION_TEXT_SIZE * 0.5f\n    for (i in poseClassification.indices) {\n      val classificationY =\n        canvas.height -\n          (POSE_CLASSIFICATION_TEXT_SIZE * 1.5f * (poseClassification.size - i).toFloat())\n      canvas.drawText(\n        poseClassification[i],\n        classificationX,\n        classificationY,\n        classificationTextPaint\n      )\n    }\n\n    // Draw all the points\n    for (landmark in landmarks) {\n      drawPoint(canvas, landmark, whitePaint)\n      if (visualizeZ && rescaleZForVisualization) {\n        zMin = min(zMin, landmark.position3D.z)\n        zMax = max(zMax, landmark.position3D.z)\n      }\n    }\n\n    val nose = pose.getPoseLandmark(PoseLandmark.NOSE)\n    val lefyEyeInner = pose.getPoseLandmark(PoseLandmark.LEFT_EYE_INNER)\n    val lefyEye = pose.getPoseLandmark(PoseLandmark.LEFT_EYE)\n    val leftEyeOuter = pose.getPoseLandmark(PoseLandmark.LEFT_EYE_OUTER)\n    val rightEyeInner = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE_INNER)\n    val rightEye = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE)\n    val rightEyeOuter = pose.getPoseLandmark(PoseLandmark.RIGHT_EYE_OUTER)\n    val leftEar = pose.getPoseLandmark(PoseLandmark.LEFT_EAR)\n    val rightEar = pose.getPoseLandmark(PoseLandmark.RIGHT_EAR)\n    val leftMouth = pose.getPoseLandmark(PoseLandmark.LEFT_MOUTH)\n    val rightMouth = pose.getPoseLandmark(PoseLandmark.RIGHT_MOUTH)\n\n    val leftShoulder = pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER)\n    val rightShoulder = pose.getPoseLandmark(PoseLandmark.RIGHT_SHOULDER)\n    val leftElbow = pose.getPoseLandmark(PoseLandmark.LEFT_ELBOW)\n    val rightElbow = pose.getPoseLandmark(PoseLandmark.RIGHT_ELBOW)\n    val leftWrist = pose.getPoseLandmark(PoseLandmark.LEFT_WRIST)\n    val rightWrist = pose.getPoseLandmark(PoseLandmark.RIGHT_WRIST)\n    val leftHip = pose.getPoseLandmark(PoseLandmark.LEFT_HIP)\n    val rightHip = pose.getPoseLandmark(PoseLandmark.RIGHT_HIP)\n    val leftKnee = pose.getPoseLandmark(PoseLandmark.LEFT_KNEE)\n    val rightKnee = pose.getPoseLandmark(PoseLandmark.RIGHT_KNEE)\n    val leftAnkle = pose.getPoseLandmark(PoseLandmark.LEFT_ANKLE)\n    val rightAnkle = pose.getPoseLandmark(PoseLandmark.RIGHT_ANKLE)\n\n    val leftPinky = pose.getPoseLandmark(PoseLandmark.LEFT_PINKY)\n    val rightPinky = pose.getPoseLandmark(PoseLandmark.RIGHT_PINKY)\n    val leftIndex = pose.getPoseLandmark(PoseLandmark.LEFT_INDEX)\n    val rightIndex = pose.getPoseLandmark(PoseLandmark.RIGHT_INDEX)\n    val leftThumb = pose.getPoseLandmark(PoseLandmark.LEFT_THUMB)\n    val rightThumb = pose.getPoseLandmark(PoseLandmark.RIGHT_THUMB)\n    val leftHeel = pose.getPoseLandmark(PoseLandmark.LEFT_HEEL)\n    val rightHeel = pose.getPoseLandmark(PoseLandmark.RIGHT_HEEL)\n    val leftFootIndex = pose.getPoseLandmark(PoseLandmark.LEFT_FOOT_INDEX)\n    val rightFootIndex = pose.getPoseLandmark(PoseLandmark.RIGHT_FOOT_INDEX)\n\n    // Face\n    drawLine(canvas, nose, lefyEyeInner, whitePaint)\n    drawLine(canvas, lefyEyeInner, lefyEye, whitePaint)\n    drawLine(canvas, lefyEye, leftEyeOuter, whitePaint)\n    drawLine(canvas, leftEyeOuter, leftEar, whitePaint)\n    drawLine(canvas, nose, rightEyeInner, whitePaint)\n    drawLine(canvas, rightEyeInner, rightEye, whitePaint)\n    drawLine(canvas, rightEye, rightEyeOuter, whitePaint)\n    drawLine(canvas, rightEyeOuter, rightEar, whitePaint)\n    drawLine(canvas, leftMouth, rightMouth, whitePaint)\n\n    drawLine(canvas, leftShoulder, rightShoulder, whitePaint)\n    drawLine(canvas, leftHip, rightHip, whitePaint)\n\n    // Left body\n    drawLine(canvas, leftShoulder, leftElbow, leftPaint)\n    drawLine(canvas, leftElbow, leftWrist, leftPaint)\n    drawLine(canvas, leftShoulder, leftHip, leftPaint)\n    drawLine(canvas, leftHip, leftKnee, leftPaint)\n    drawLine(canvas, leftKnee, leftAnkle, leftPaint)\n    drawLine(canvas, leftWrist, leftThumb, leftPaint)\n    drawLine(canvas, leftWrist, leftPinky, leftPaint)\n    drawLine(canvas, leftWrist, leftIndex, leftPaint)\n    drawLine(canvas, leftIndex, leftPinky, leftPaint)\n    drawLine(canvas, leftAnkle, leftHeel, leftPaint)\n    drawLine(canvas, leftHeel, leftFootIndex, leftPaint)\n\n    // Right body\n    drawLine(canvas, rightShoulder, rightElbow, rightPaint)\n    drawLine(canvas, rightElbow, rightWrist, rightPaint)\n    drawLine(canvas, rightShoulder, rightHip, rightPaint)\n    drawLine(canvas, rightHip, rightKnee, rightPaint)\n    drawLine(canvas, rightKnee, rightAnkle, rightPaint)\n    drawLine(canvas, rightWrist, rightThumb, rightPaint)\n    drawLine(canvas, rightWrist, rightPinky, rightPaint)\n    drawLine(canvas, rightWrist, rightIndex, rightPaint)\n    drawLine(canvas, rightIndex, rightPinky, rightPaint)\n    drawLine(canvas, rightAnkle, rightHeel, rightPaint)\n    drawLine(canvas, rightHeel, rightFootIndex, rightPaint)\n\n    // Draw inFrameLikelihood for all points\n    if (showInFrameLikelihood) {\n      for (landmark in landmarks) {\n        canvas.drawText(\n          String.format(Locale.US, \"%.2f\", landmark.inFrameLikelihood),\n          translateX(landmark.position.x),\n          translateY(landmark.position.y),\n          whitePaint\n        )\n      }\n    }\n  }\n\n  internal fun drawPoint(canvas: Canvas, landmark: PoseLandmark, paint: Paint) {\n    val point = landmark.position3D\n    updatePaintColorByZValue(\n      paint,\n      canvas,\n      visualizeZ,\n      rescaleZForVisualization,\n      point.z,\n      zMin,\n      zMax\n    )\n    canvas.drawCircle(translateX(point.x), translateY(point.y), DOT_RADIUS, paint)\n  }\n\n  internal fun drawLine(\n    canvas: Canvas,\n    startLandmark: PoseLandmark?,\n    endLandmark: PoseLandmark?,\n    paint: Paint\n  ) {\n    val start = startLandmark!!.position3D\n    val end = endLandmark!!.position3D\n\n    // Gets average z for the current body line\n    val avgZInImagePixel = (start.z + end.z) / 2\n    updatePaintColorByZValue(\n      paint,\n      canvas,\n      visualizeZ,\n      rescaleZForVisualization,\n      avgZInImagePixel,\n      zMin,\n      zMax\n    )\n\n    canvas.drawLine(\n      translateX(start.x),\n      translateY(start.y),\n      translateX(end.x),\n      translateY(end.y),\n      paint\n    )\n  }\n\n  companion object {\n\n    private val DOT_RADIUS = 8.0f\n    private val IN_FRAME_LIKELIHOOD_TEXT_SIZE = 30.0f\n    private val STROKE_WIDTH = 10.0f\n    private val POSE_CLASSIFICATION_TEXT_SIZE = 60.0f\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/segmenter/SegmentationGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.segmenter\n\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Matrix\nimport androidx.annotation.ColorInt\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.segmentation.SegmentationMask\nimport java.nio.ByteBuffer\n\n/** Draw the mask from SegmentationResult in preview.  */\nclass SegmentationGraphic(overlay: GraphicOverlay, segmentationMask: SegmentationMask) :\n  GraphicOverlay.Graphic(overlay) {\n  private val mask: ByteBuffer\n  private val maskWidth: Int\n  private val maskHeight: Int\n  private val isRawSizeMaskEnabled: Boolean\n  private val scaleX: Float\n  private val scaleY: Float\n\n  /** Draws the segmented background on the supplied canvas.  */\n  override fun draw(canvas: Canvas) {\n    val bitmap = Bitmap.createBitmap(\n      maskColorsFromByteBuffer(mask), maskWidth, maskHeight, Bitmap.Config.ARGB_8888\n    )\n    if (isRawSizeMaskEnabled) {\n      val matrix = Matrix(getTransformationMatrix())\n      matrix.preScale(scaleX, scaleY)\n      canvas.drawBitmap(bitmap, matrix, null)\n    } else {\n      canvas.drawBitmap(bitmap, getTransformationMatrix(), null)\n    }\n    bitmap.recycle()\n    // Reset byteBuffer pointer to beginning, so that the mask can be redrawn if screen is refreshed\n    mask.rewind()\n  }\n\n  /** Converts byteBuffer floats to ColorInt array that can be used as a mask.  */\n  @ColorInt\n  private fun maskColorsFromByteBuffer(byteBuffer: ByteBuffer): IntArray {\n    @ColorInt val colors =\n      IntArray(maskWidth * maskHeight)\n    for (i in 0 until maskWidth * maskHeight) {\n      val backgroundLikelihood = 1 - byteBuffer.float\n      if (backgroundLikelihood > 0.9) {\n        colors[i] = Color.argb(128, 255, 0, 255)\n      } else if (backgroundLikelihood > 0.2) {\n        // Linear interpolation to make sure when backgroundLikelihood is 0.2, the alpha is 0 and\n        // when backgroundLikelihood is 0.9, the alpha is 128.\n        // +0.5 to round the float value to the nearest int.\n        val alpha = (182.9 * backgroundLikelihood - 36.6 + 0.5).toInt()\n        colors[i] = Color.argb(alpha, 255, 0, 255)\n      }\n    }\n    return colors\n  }\n\n  init {\n    mask = segmentationMask.buffer\n    maskWidth = segmentationMask.width\n    maskHeight = segmentationMask.height\n    isRawSizeMaskEnabled =\n      maskWidth != overlay.getImageWidth() || maskHeight != overlay.getImageHeight()\n    scaleX = overlay.getImageWidth() * 1f / maskWidth\n    scaleY = overlay.getImageHeight() * 1f / maskHeight\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/segmenter/SegmenterProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.segmenter\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport com.google.mlkit.vision.segmentation.Segmentation\nimport com.google.mlkit.vision.segmentation.SegmentationMask\nimport com.google.mlkit.vision.segmentation.Segmenter\nimport com.google.mlkit.vision.segmentation.selfie.SelfieSegmenterOptions\n\n/** A processor to run Segmenter.  */\nclass SegmenterProcessor :\n  VisionProcessorBase<SegmentationMask> {\n  private val segmenter: Segmenter\n\n  constructor(context: Context) : this(context, /* isStreamMode= */ true)\n\n  constructor(\n    context: Context,\n    isStreamMode: Boolean\n  ) : super(\n    context\n  ) {\n    val optionsBuilder = SelfieSegmenterOptions.Builder()\n    optionsBuilder.setDetectorMode(\n      if(isStreamMode) SelfieSegmenterOptions.STREAM_MODE\n      else SelfieSegmenterOptions.SINGLE_IMAGE_MODE\n    )\n    if (PreferenceUtils.shouldSegmentationEnableRawSizeMask(context)) {\n      optionsBuilder.enableRawSizeMask()\n    }\n\n    val options = optionsBuilder.build()\n    segmenter = Segmentation.getClient(options)\n    Log.d(TAG, \"SegmenterProcessor created with option: \" + options)\n  }\n\n  override fun detectInImage(image: InputImage): Task<SegmentationMask> {\n    return segmenter.process(image)\n  }\n\n  override fun onSuccess(\n    segmentationMask: SegmentationMask,\n    graphicOverlay: GraphicOverlay\n  ) {\n    graphicOverlay.add(\n      SegmentationGraphic(\n        graphicOverlay,\n        segmentationMask\n      )\n    )\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.e(TAG, \"Segmentation failed: $e\")\n  }\n\n  companion object {\n    private const val TAG = \"SegmenterProcessor\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/subjectsegmenter/SubjectSegmentationGraphic.kt",
    "content": "/*\n * Copyright 2023 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.subjectsegmenter\n\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Matrix\nimport android.os.Build\nimport androidx.annotation.ColorInt\nimport androidx.annotation.RequiresApi\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.segmentation.subject.Subject\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmentationResult\nimport java.nio.FloatBuffer\nimport kotlin.collections.List\n\n/** Draw the mask from [SubjectSegmentationResult] in preview. */\n@RequiresApi(Build.VERSION_CODES.N)\nclass SubjectSegmentationGraphic(\n  overlay: GraphicOverlay,\n  segmentationResult: SubjectSegmentationResult,\n  imageWidth: Int,\n  imageHeight: Int\n) : GraphicOverlay.Graphic(overlay) {\n  private val subjects: List<Subject>\n  private val imageWidth: Int\n  private val imageHeight: Int\n  private val isRawSizeMaskEnabled: Boolean\n  private val scaleX: Float\n  private val scaleY: Float\n\n  /** Draws the segmented background on the supplied canvas. */\n  override fun draw(canvas: Canvas) {\n    val bitmap =\n      Bitmap.createBitmap(\n        maskColorsFromFloatBuffer(),\n        imageWidth,\n        imageHeight,\n        Bitmap.Config.ARGB_8888\n      )\n    if (isRawSizeMaskEnabled) {\n      val matrix = Matrix(getTransformationMatrix())\n      matrix.preScale(scaleX, scaleY)\n      canvas.drawBitmap(bitmap, matrix, null)\n    } else {\n      canvas.drawBitmap(bitmap, getTransformationMatrix(), null)\n    }\n    bitmap.recycle()\n  }\n\n  /**\n   * Converts [FloatBuffer] floats from all subjects to ColorInt array that can be used as a mask.\n   */\n  @ColorInt\n  private fun maskColorsFromFloatBuffer(): IntArray {\n    @ColorInt val colors = IntArray(imageWidth * imageHeight)\n    for (k in 0 until subjects.size) {\n      val subject = subjects[k]\n      val rgb = COLORS[k % COLORS.size]\n      val color = Color.argb(128, rgb[0], rgb[1], rgb[2])\n      val mask = subject.confidenceMask\n      for (j in 0 until subject.height) {\n        for (i in 0 until subject.width) {\n          if (mask!!.get() > 0.5) {\n            colors[(subject.startY + j) * imageWidth + subject.startX + i] = color\n          }\n        }\n      }\n      // Reset [FloatBuffer] pointer to beginning, so that the mask can be redrawn if screen is\n      // refreshed\n      mask!!.rewind()\n    }\n    return colors\n  }\n\n  init {\n    subjects = segmentationResult.subjects\n    this.imageWidth = imageWidth\n    this.imageHeight = imageHeight\n\n    isRawSizeMaskEnabled =\n      imageWidth != overlay.imageWidth || imageHeight != overlay.imageHeight\n    scaleX = overlay.imageWidth * 1f / imageWidth\n    scaleY = overlay.imageHeight * 1f / imageHeight\n  }\n\n  companion object {\n    private val COLORS =\n      arrayOf(\n        intArrayOf(255, 0, 255),\n        intArrayOf(0, 255, 255),\n        intArrayOf(255, 255, 0),\n        intArrayOf(255, 0, 0),\n        intArrayOf(0, 255, 0),\n        intArrayOf(0, 0, 255),\n        intArrayOf(128, 0, 128),\n        intArrayOf(0, 128, 128),\n        intArrayOf(128, 128, 0),\n        intArrayOf(128, 0, 0),\n        intArrayOf(0, 128, 0),\n        intArrayOf(0, 0, 128)\n      )\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/subjectsegmenter/SubjectSegmenterProcessor.kt",
    "content": "/*\n * Copyright 2023 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.subjectsegmenter\n\nimport android.content.Context\nimport android.os.Build\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmentation\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmentationResult\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmenter\nimport com.google.mlkit.vision.segmentation.subject.SubjectSegmenterOptions\n\n/** A processor to run Subject Segmenter. */\n@RequiresApi(Build.VERSION_CODES.N)\nclass SubjectSegmenterProcessor : VisionProcessorBase<SubjectSegmentationResult> {\n  private val subjectSegmenter: SubjectSegmenter\n  private var imageWidth: Int = 0\n  private var imageHeight: Int = 0\n\n  constructor(context: Context) : super(context) {\n    subjectSegmenter =\n      SubjectSegmentation.getClient(\n        SubjectSegmenterOptions.Builder()\n          .enableMultipleSubjects(\n            SubjectSegmenterOptions.SubjectResultOptions.Builder().enableConfidenceMask().build()\n          )\n          .build()\n      )\n\n    Log.d(TAG, \"SubjectSegmenterProcessor created\")\n  }\n\n  override fun detectInImage(image: InputImage): Task<SubjectSegmentationResult> {\n    this.imageWidth = image.width\n    this.imageHeight = image.height\n    return subjectSegmenter.process(image)\n  }\n\n  override fun onSuccess(\n    results: SubjectSegmentationResult,\n    graphicOverlay: GraphicOverlay\n  ) {\n    graphicOverlay.add(\n      SubjectSegmentationGraphic(graphicOverlay, results, imageWidth, imageHeight)\n    )\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.e(TAG, \"Segmentation failed: $e\")\n  }\n\n  companion object {\n    private const val TAG = \"SbjSegmenterProcessor\"\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/textdetector/TextGraphic.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.textdetector\n\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport android.graphics.RectF\nimport android.util.Log\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.GraphicOverlay.Graphic\nimport com.google.mlkit.vision.text.Text\nimport java.util.Arrays\nimport kotlin.math.max\nimport kotlin.math.min\n\n/**\n * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic\n * overlay view.\n */\nclass TextGraphic\nconstructor(\n  overlay: GraphicOverlay?,\n  private val text: Text,\n  private val shouldGroupTextInBlocks: Boolean,\n  private val showLanguageTag: Boolean,\n  private val showConfidence: Boolean\n) : Graphic(overlay) {\n\n  private val rectPaint: Paint = Paint()\n  private val textPaint: Paint\n  private val labelPaint: Paint\n\n  init {\n    rectPaint.color = MARKER_COLOR\n    rectPaint.style = Paint.Style.STROKE\n    rectPaint.strokeWidth = STROKE_WIDTH\n    textPaint = Paint()\n    textPaint.color = TEXT_COLOR\n    textPaint.textSize = TEXT_SIZE\n    labelPaint = Paint()\n    labelPaint.color = MARKER_COLOR\n    labelPaint.style = Paint.Style.FILL\n    // Redraw the overlay, as this graphic has been added.\n    postInvalidate()\n  }\n\n  /** Draws the text block annotations for position, size, and raw value on the supplied canvas. */\n  override fun draw(canvas: Canvas) {\n    Log.d(TAG, \"Text is: \" + text.text)\n    for (textBlock in text.textBlocks) { // Renders the text at the bottom of the box.\n      Log.d(TAG, \"TextBlock text is: \" + textBlock.text)\n      Log.d(TAG, \"TextBlock boundingbox is: \" + textBlock.boundingBox)\n      Log.d(TAG, \"TextBlock cornerpoint is: \" + Arrays.toString(textBlock.cornerPoints))\n      if (shouldGroupTextInBlocks) {\n        drawText(\n          getFormattedText(textBlock.text, textBlock.recognizedLanguage, confidence = null),\n          RectF(textBlock.boundingBox),\n          TEXT_SIZE * textBlock.lines.size + 2 * STROKE_WIDTH,\n          canvas\n        )\n      } else {\n        for (line in textBlock.lines) {\n          Log.d(TAG, \"Line text is: \" + line.text)\n          Log.d(TAG, \"Line boundingbox is: \" + line.boundingBox)\n          Log.d(TAG, \"Line cornerpoint is: \" + Arrays.toString(line.cornerPoints))\n          Log.d(TAG, \"Line confidence is: \" + line.confidence)\n          Log.d(TAG, \"Line angle is: \" + line.angle)\n          // Draws the bounding box around the TextBlock.\n          val rect = RectF(line.boundingBox)\n          drawText(\n            getFormattedText(line.text, line.recognizedLanguage, line.confidence),\n            rect,\n            TEXT_SIZE + 2 * STROKE_WIDTH,\n            canvas\n          )\n          for (element in line.elements) {\n            Log.d(TAG, \"Element text is: \" + element.text)\n            Log.d(TAG, \"Element boundingbox is: \" + element.boundingBox)\n            Log.d(TAG, \"Element cornerpoint is: \" + Arrays.toString(element.cornerPoints))\n            Log.d(TAG, \"Element language is: \" + element.recognizedLanguage)\n            Log.d(TAG, \"Element confidence is: \" + element.confidence)\n            Log.d(TAG, \"Element angle is: \" + element.angle)\n            for (symbol in element.symbols) {\n            Log.d(TAG, \"Symbol text is: \" + symbol.text)\n            Log.d(TAG, \"Symbol boundingbox is: \" + symbol.boundingBox)\n            Log.d(TAG, \"Symbol cornerpoint is: \" + Arrays.toString(symbol.cornerPoints))\n            Log.d(TAG, \"Symbol confidence is: \" + symbol.confidence)\n            Log.d(TAG, \"Symbol angle is: \" + symbol.angle)\n          }\n          }\n        }\n      }\n    }\n  }\n\n  private fun getFormattedText(text: String, languageTag: String, confidence: Float?): String {\n    val res =\n      if (showLanguageTag) String.format(TEXT_WITH_LANGUAGE_TAG_FORMAT, languageTag, text) else text\n    return if (showConfidence && confidence != null) String.format(\"%s (%.2f)\", res, confidence)\n    else res\n  }\n\n  private fun drawText(text: String, rect: RectF, textHeight: Float, canvas: Canvas) {\n    // If the image is flipped, the left will be translated to right, and the right to left.\n    val x0 = translateX(rect.left)\n    val x1 = translateX(rect.right)\n    rect.left = min(x0, x1)\n    rect.right = max(x0, x1)\n    rect.top = translateY(rect.top)\n    rect.bottom = translateY(rect.bottom)\n    canvas.drawRect(rect, rectPaint)\n    val textWidth = textPaint.measureText(text)\n    canvas.drawRect(\n      rect.left - STROKE_WIDTH,\n      rect.top - textHeight,\n      rect.left + textWidth + 2 * STROKE_WIDTH,\n      rect.top,\n      labelPaint\n    )\n    // Renders the text at the bottom of the box.\n    canvas.drawText(text, rect.left, rect.top - STROKE_WIDTH, textPaint)\n  }\n\n  companion object {\n    private const val TAG = \"TextGraphic\"\n    private const val TEXT_WITH_LANGUAGE_TAG_FORMAT = \"%s:%s\"\n    private const val TEXT_COLOR = Color.BLACK\n    private const val MARKER_COLOR = Color.WHITE\n    private const val TEXT_SIZE = 54.0f\n    private const val STROKE_WIDTH = 4.0f\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/kotlin/textdetector/TextRecognitionProcessor.kt",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.kotlin.textdetector\n\nimport android.content.Context\nimport android.util.Log\nimport com.google.android.gms.tasks.Task\nimport com.google.mlkit.vision.common.InputImage\nimport com.google.mlkit.vision.demo.GraphicOverlay\nimport com.google.mlkit.vision.demo.kotlin.VisionProcessorBase\nimport com.google.mlkit.vision.demo.preference.PreferenceUtils\nimport com.google.mlkit.vision.text.Text\nimport com.google.mlkit.vision.text.TextRecognition\nimport com.google.mlkit.vision.text.TextRecognizer\nimport com.google.mlkit.vision.text.TextRecognizerOptionsInterface\n\n/** Processor for the text detector demo. */\nclass TextRecognitionProcessor(\n  private val context: Context,\n  textRecognizerOptions: TextRecognizerOptionsInterface\n) : VisionProcessorBase<Text>(context) {\n  private val textRecognizer: TextRecognizer = TextRecognition.getClient(textRecognizerOptions)\n  private val shouldGroupRecognizedTextInBlocks: Boolean =\n    PreferenceUtils.shouldGroupRecognizedTextInBlocks(context)\n  private val showLanguageTag: Boolean = PreferenceUtils.showLanguageTag(context)\n  private val showConfidence: Boolean = PreferenceUtils.shouldShowTextConfidence(context)\n\n  override fun stop() {\n    super.stop()\n    textRecognizer.close()\n  }\n\n  override fun detectInImage(image: InputImage): Task<Text> {\n    return textRecognizer.process(image)\n  }\n\n  override fun onSuccess(text: Text, graphicOverlay: GraphicOverlay) {\n    Log.d(TAG, \"On-device Text detection successful\")\n    logExtrasForTesting(text)\n    graphicOverlay.add(\n      TextGraphic(\n        graphicOverlay,\n        text,\n        shouldGroupRecognizedTextInBlocks,\n        showLanguageTag,\n        showConfidence\n      )\n    )\n  }\n\n  override fun onFailure(e: Exception) {\n    Log.w(TAG, \"Text detection failed.$e\")\n  }\n\n  companion object {\n    private const val TAG = \"TextRecProcessor\"\n    private fun logExtrasForTesting(text: Text?) {\n      if (text != null) {\n        Log.v(MANUAL_TESTING_LOG, \"Detected text has : \" + text.textBlocks.size + \" blocks\")\n        for (i in text.textBlocks.indices) {\n          val lines = text.textBlocks[i].lines\n          Log.v(\n            MANUAL_TESTING_LOG,\n            String.format(\"Detected text block %d has %d lines\", i, lines.size)\n          )\n          for (j in lines.indices) {\n            val elements = lines[j].elements\n            Log.v(\n              MANUAL_TESTING_LOG,\n              String.format(\"Detected text line %d has %d elements\", j, elements.size)\n            )\n            for (k in elements.indices) {\n              val element = elements[k]\n              Log.v(\n                MANUAL_TESTING_LOG,\n                String.format(\"Detected text element %d says: %s\", k, element.text)\n              )\n              Log.v(\n                MANUAL_TESTING_LOG,\n                String.format(\n                  \"Detected text element %d has a bounding box: %s\",\n                  k,\n                  element.boundingBox!!.flattenToString()\n                )\n              )\n              Log.v(\n                MANUAL_TESTING_LOG,\n                String.format(\n                  \"Expected corner point size is 4, get %d\",\n                  element.cornerPoints!!.size\n                )\n              )\n              for (point in element.cornerPoints!!) {\n                Log.v(\n                  MANUAL_TESTING_LOG,\n                  String.format(\n                    \"Corner point for element %d is located at: x - %d, y = %d\",\n                    k,\n                    point.x,\n                    point.y\n                  )\n                )\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/preference/CameraXLivePreviewPreferenceFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.preference;\n\nimport android.content.Context;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.camera2.CameraAccessException;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.hardware.camera2.CameraManager;\nimport android.hardware.camera2.params.StreamConfigurationMap;\nimport android.os.Build.VERSION_CODES;\nimport android.preference.ListPreference;\nimport android.preference.PreferenceCategory;\nimport android.util.Size;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.StringRes;\nimport androidx.camera.core.CameraSelector;\nimport com.google.mlkit.vision.demo.R;\nimport java.util.Arrays;\nimport java.util.List;\n\n/** Configures CameraX live preview demo settings. */\n@RequiresApi(VERSION_CODES.LOLLIPOP)\npublic class CameraXLivePreviewPreferenceFragment extends LivePreviewPreferenceFragment {\n\n  @Override\n  void setUpCameraPreferences() {\n    PreferenceCategory cameraPreference =\n        (PreferenceCategory) findPreference(getString(R.string.pref_category_key_camera));\n\n    cameraPreference.removePreference(\n        findPreference(getString(R.string.pref_key_rear_camera_preview_size)));\n    cameraPreference.removePreference(\n        findPreference(getString(R.string.pref_key_front_camera_preview_size)));\n    setUpCameraXTargetAnalysisSizePreference(\n        R.string.pref_key_camerax_rear_camera_target_resolution, CameraSelector.LENS_FACING_BACK);\n    setUpCameraXTargetAnalysisSizePreference(\n        R.string.pref_key_camerax_front_camera_target_resolution, CameraSelector.LENS_FACING_FRONT);\n  }\n\n  private void setUpCameraXTargetAnalysisSizePreference(\n      @StringRes int previewSizePrefKeyId, int lensFacing) {\n    ListPreference pref = (ListPreference) findPreference(getString(previewSizePrefKeyId));\n    CameraCharacteristics cameraCharacteristics =\n        getCameraCharacteristics(getActivity(), lensFacing);\n    String[] entries;\n    if (cameraCharacteristics != null) {\n      StreamConfigurationMap map =\n          cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);\n      Size[] outputSizes = map.getOutputSizes(SurfaceTexture.class);\n      entries = new String[outputSizes.length];\n      for (int i = 0; i < outputSizes.length; i++) {\n        entries[i] = outputSizes[i].toString();\n      }\n    } else {\n      entries =\n          new String[] {\n            \"2000x2000\",\n            \"1600x1600\",\n            \"1200x1200\",\n            \"1000x1000\",\n            \"800x800\",\n            \"600x600\",\n            \"400x400\",\n            \"200x200\",\n            \"100x100\",\n          };\n    }\n    pref.setEntries(entries);\n    pref.setEntryValues(entries);\n    pref.setSummary(pref.getEntry() == null ? \"Default\" : pref.getEntry());\n    pref.setOnPreferenceChangeListener(\n        (preference, newValue) -> {\n          String newStringValue = (String) newValue;\n          pref.setSummary(newStringValue);\n          PreferenceUtils.saveString(getActivity(), previewSizePrefKeyId, newStringValue);\n          return true;\n        });\n  }\n\n  @Nullable\n  public static CameraCharacteristics getCameraCharacteristics(\n      Context context, Integer lensFacing) {\n    CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);\n    try {\n      List<String> cameraList = Arrays.asList(cameraManager.getCameraIdList());\n      for (String availableCameraId : cameraList) {\n        CameraCharacteristics availableCameraCharacteristics =\n            cameraManager.getCameraCharacteristics(availableCameraId);\n        Integer availableLensFacing =\n            availableCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);\n        if (availableLensFacing == null) {\n          continue;\n        }\n        if (availableLensFacing.equals(lensFacing)) {\n          return availableCameraCharacteristics;\n        }\n      }\n    } catch (CameraAccessException e) {\n      // Accessing camera ID info got error\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/preference/CameraXSourceDemoPreferenceFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.preference;\n\nimport android.os.Build.VERSION_CODES;\nimport android.os.Bundle;\nimport android.preference.PreferenceCategory;\nimport android.preference.PreferenceScreen;\nimport androidx.annotation.RequiresApi;\nimport com.google.mlkit.vision.demo.R;\n\n/** Configures CameraXSource live preview demo settings. */\n@RequiresApi(VERSION_CODES.LOLLIPOP)\npublic class CameraXSourceDemoPreferenceFragment extends CameraXLivePreviewPreferenceFragment {\n\n  @Override\n  public void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    PreferenceScreen preferenceScreen =\n        (PreferenceScreen) findPreference(getResources().getString(R.string.pref_screen));\n\n    PreferenceCategory preferenceCategory =\n        (PreferenceCategory) findPreference(getString(R.string.pref_category_key_camera));\n\n    preferenceCategory.removePreference(\n        findPreference(getString(R.string.pref_key_camera_live_viewport)));\n    // Remove the PreferenceCategories for hiding camera detection info.\n    preferenceScreen.removePreference(preferenceScreen.getPreference(1));\n\n    // Remove the last 3 PreferenceCategories\n    preferenceScreen.removePreference(preferenceScreen.getPreference(2));\n    preferenceScreen.removePreference(preferenceScreen.getPreference(2));\n    preferenceScreen.removePreference(preferenceScreen.getPreference(2));\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/preference/LivePreviewPreferenceFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.preference;\n\nimport android.hardware.Camera;\nimport android.os.Bundle;\nimport android.preference.EditTextPreference;\nimport android.preference.ListPreference;\nimport android.preference.PreferenceCategory;\nimport android.preference.PreferenceFragment;\nimport android.widget.Toast;\nimport androidx.annotation.StringRes;\nimport com.google.mlkit.vision.demo.CameraSource;\nimport com.google.mlkit.vision.demo.CameraSource.SizePair;\nimport com.google.mlkit.vision.demo.R;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/** Configures live preview demo settings. */\npublic class LivePreviewPreferenceFragment extends PreferenceFragment {\n\n  @Override\n  public void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    addPreferencesFromResource(R.xml.preference_live_preview_quickstart);\n    setUpCameraPreferences();\n    setUpFaceDetectionPreferencesForStreamMode();\n  }\n\n  void setUpCameraPreferences() {\n    PreferenceCategory cameraPreference =\n        (PreferenceCategory) findPreference(getString(R.string.pref_category_key_camera));\n    cameraPreference.removePreference(\n        findPreference(getString(R.string.pref_key_camerax_rear_camera_target_resolution)));\n    cameraPreference.removePreference(\n        findPreference(getString(R.string.pref_key_camerax_front_camera_target_resolution)));\n    setUpCameraPreviewSizePreference(\n        R.string.pref_key_rear_camera_preview_size,\n        R.string.pref_key_rear_camera_picture_size,\n        CameraSource.CAMERA_FACING_BACK);\n    setUpCameraPreviewSizePreference(\n        R.string.pref_key_front_camera_preview_size,\n        R.string.pref_key_front_camera_picture_size,\n        CameraSource.CAMERA_FACING_FRONT);\n  }\n\n  private void setUpCameraPreviewSizePreference(\n      @StringRes int previewSizePrefKeyId, @StringRes int pictureSizePrefKeyId, int cameraId) {\n    ListPreference previewSizePreference =\n        (ListPreference) findPreference(getString(previewSizePrefKeyId));\n\n    Camera camera = null;\n    try {\n      camera = Camera.open(cameraId);\n\n      List<SizePair> previewSizeList = CameraSource.generateValidPreviewSizeList(camera);\n      String[] previewSizeStringValues = new String[previewSizeList.size()];\n      Map<String, String> previewToPictureSizeStringMap = new HashMap<>();\n      for (int i = 0; i < previewSizeList.size(); i++) {\n        SizePair sizePair = previewSizeList.get(i);\n        previewSizeStringValues[i] = sizePair.preview.toString();\n        if (sizePair.picture != null) {\n          previewToPictureSizeStringMap.put(\n              sizePair.preview.toString(), sizePair.picture.toString());\n        }\n      }\n      previewSizePreference.setEntries(previewSizeStringValues);\n      previewSizePreference.setEntryValues(previewSizeStringValues);\n\n      if (previewSizePreference.getEntry() == null) {\n        // First time of opening the Settings page.\n        SizePair sizePair =\n            CameraSource.selectSizePair(\n                camera,\n                CameraSource.DEFAULT_REQUESTED_CAMERA_PREVIEW_WIDTH,\n                CameraSource.DEFAULT_REQUESTED_CAMERA_PREVIEW_HEIGHT);\n        String previewSizeString = sizePair.preview.toString();\n        previewSizePreference.setValue(previewSizeString);\n        previewSizePreference.setSummary(previewSizeString);\n        PreferenceUtils.saveString(\n            getActivity(),\n            pictureSizePrefKeyId,\n            sizePair.picture != null ? sizePair.picture.toString() : null);\n      } else {\n        previewSizePreference.setSummary(previewSizePreference.getEntry());\n      }\n\n      previewSizePreference.setOnPreferenceChangeListener(\n          (preference, newValue) -> {\n            String newPreviewSizeStringValue = (String) newValue;\n            previewSizePreference.setSummary(newPreviewSizeStringValue);\n            PreferenceUtils.saveString(\n                getActivity(),\n                pictureSizePrefKeyId,\n                previewToPictureSizeStringMap.get(newPreviewSizeStringValue));\n            return true;\n          });\n    } catch (RuntimeException e) {\n      // If there's no camera for the given camera id, hide the corresponding preference.\n      ((PreferenceCategory) findPreference(getString(R.string.pref_category_key_camera)))\n          .removePreference(previewSizePreference);\n    } finally {\n      if (camera != null) {\n        camera.release();\n      }\n    }\n  }\n\n  private void setUpFaceDetectionPreferencesForStreamMode() {\n    EditTextPreference minFaceSizePreference =\n        (EditTextPreference)\n            findPreference(getString(R.string.pref_key_live_preview_face_detection_min_face_size));\n    minFaceSizePreference.setSummary(minFaceSizePreference.getText());\n    minFaceSizePreference.setOnPreferenceChangeListener(\n        (preference, newValue) -> {\n          try {\n            float minFaceSize = Float.parseFloat((String) newValue);\n            if (minFaceSize >= 0.0f && minFaceSize <= 1.0f) {\n              minFaceSizePreference.setSummary((String) newValue);\n              return true;\n            }\n          } catch (NumberFormatException e) {\n            // Fall through intentionally.\n          }\n\n          Toast.makeText(\n                  this.getActivity(), R.string.pref_toast_invalid_min_face_size, Toast.LENGTH_LONG)\n              .show();\n          return false;\n        });\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/preference/PreferenceUtils.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.preference;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.os.Build.VERSION_CODES;\nimport android.preference.PreferenceManager;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.StringRes;\nimport androidx.camera.core.CameraSelector;\nimport com.google.android.gms.common.images.Size;\nimport com.google.common.base.Preconditions;\nimport com.google.mlkit.common.model.LocalModel;\nimport com.google.mlkit.vision.demo.CameraSource;\nimport com.google.mlkit.vision.demo.CameraSource.SizePair;\nimport com.google.mlkit.vision.demo.R;\nimport com.google.mlkit.vision.face.FaceDetectorOptions;\nimport com.google.mlkit.vision.facemesh.FaceMeshDetectorOptions;\nimport com.google.mlkit.vision.objects.ObjectDetectorOptionsBase.DetectorMode;\nimport com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;\nimport com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions;\nimport com.google.mlkit.vision.pose.PoseDetectorOptionsBase;\nimport com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions;\nimport com.google.mlkit.vision.pose.defaults.PoseDetectorOptions;\n\n/** Utility class to retrieve shared preferences. */\npublic class PreferenceUtils {\n\n  private static final int POSE_DETECTOR_PERFORMANCE_MODE_FAST = 1;\n\n  static void saveString(Context context, @StringRes int prefKeyId, @Nullable String value) {\n    PreferenceManager.getDefaultSharedPreferences(context)\n        .edit()\n        .putString(context.getString(prefKeyId), value)\n        .apply();\n  }\n\n  @Nullable\n  public static SizePair getCameraPreviewSizePair(Context context, int cameraId) {\n    Preconditions.checkArgument(\n        cameraId == CameraSource.CAMERA_FACING_BACK\n            || cameraId == CameraSource.CAMERA_FACING_FRONT);\n    String previewSizePrefKey;\n    String pictureSizePrefKey;\n    if (cameraId == CameraSource.CAMERA_FACING_BACK) {\n      previewSizePrefKey = context.getString(R.string.pref_key_rear_camera_preview_size);\n      pictureSizePrefKey = context.getString(R.string.pref_key_rear_camera_picture_size);\n    } else {\n      previewSizePrefKey = context.getString(R.string.pref_key_front_camera_preview_size);\n      pictureSizePrefKey = context.getString(R.string.pref_key_front_camera_picture_size);\n    }\n\n    try {\n      SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n      return new SizePair(\n          Size.parseSize(sharedPreferences.getString(previewSizePrefKey, null)),\n          Size.parseSize(sharedPreferences.getString(pictureSizePrefKey, null)));\n    } catch (Exception e) {\n      return null;\n    }\n  }\n\n  @RequiresApi(VERSION_CODES.LOLLIPOP)\n  @Nullable\n  public static android.util.Size getCameraXTargetResolution(Context context, int lensfacing) {\n    Preconditions.checkArgument(\n        lensfacing == CameraSelector.LENS_FACING_BACK\n            || lensfacing == CameraSelector.LENS_FACING_FRONT);\n    String prefKey =\n        lensfacing == CameraSelector.LENS_FACING_BACK\n            ? context.getString(R.string.pref_key_camerax_rear_camera_target_resolution)\n            : context.getString(R.string.pref_key_camerax_front_camera_target_resolution);\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    try {\n      return android.util.Size.parseSize(sharedPreferences.getString(prefKey, null));\n    } catch (Exception e) {\n      return null;\n    }\n  }\n\n  public static boolean shouldHideDetectionInfo(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_info_hide);\n    return sharedPreferences.getBoolean(prefKey, false);\n  }\n\n  public static ObjectDetectorOptions getObjectDetectorOptionsForStillImage(Context context) {\n    return getObjectDetectorOptions(\n        context,\n        R.string.pref_key_still_image_object_detector_enable_multiple_objects,\n        R.string.pref_key_still_image_object_detector_enable_classification,\n        ObjectDetectorOptions.SINGLE_IMAGE_MODE);\n  }\n\n  public static ObjectDetectorOptions getObjectDetectorOptionsForLivePreview(Context context) {\n    return getObjectDetectorOptions(\n        context,\n        R.string.pref_key_live_preview_object_detector_enable_multiple_objects,\n        R.string.pref_key_live_preview_object_detector_enable_classification,\n        ObjectDetectorOptions.STREAM_MODE);\n  }\n\n  private static ObjectDetectorOptions getObjectDetectorOptions(\n      Context context,\n      @StringRes int prefKeyForMultipleObjects,\n      @StringRes int prefKeyForClassification,\n      @DetectorMode int mode) {\n\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n\n    boolean enableMultipleObjects =\n        sharedPreferences.getBoolean(context.getString(prefKeyForMultipleObjects), false);\n    boolean enableClassification =\n        sharedPreferences.getBoolean(context.getString(prefKeyForClassification), true);\n\n    ObjectDetectorOptions.Builder builder =\n        new ObjectDetectorOptions.Builder().setDetectorMode(mode);\n    if (enableMultipleObjects) {\n      builder.enableMultipleObjects();\n    }\n    if (enableClassification) {\n      builder.enableClassification();\n    }\n    return builder.build();\n  }\n\n  public static CustomObjectDetectorOptions getCustomObjectDetectorOptionsForStillImage(\n      Context context, LocalModel localModel) {\n    return getCustomObjectDetectorOptions(\n        context,\n        localModel,\n        R.string.pref_key_still_image_object_detector_enable_multiple_objects,\n        R.string.pref_key_still_image_object_detector_enable_classification,\n        CustomObjectDetectorOptions.SINGLE_IMAGE_MODE);\n  }\n\n  public static CustomObjectDetectorOptions getCustomObjectDetectorOptionsForLivePreview(\n      Context context, LocalModel localModel) {\n    return getCustomObjectDetectorOptions(\n        context,\n        localModel,\n        R.string.pref_key_live_preview_object_detector_enable_multiple_objects,\n        R.string.pref_key_live_preview_object_detector_enable_classification,\n        CustomObjectDetectorOptions.STREAM_MODE);\n  }\n\n  private static CustomObjectDetectorOptions getCustomObjectDetectorOptions(\n      Context context,\n      LocalModel localModel,\n      @StringRes int prefKeyForMultipleObjects,\n      @StringRes int prefKeyForClassification,\n      @DetectorMode int mode) {\n\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n\n    boolean enableMultipleObjects =\n        sharedPreferences.getBoolean(context.getString(prefKeyForMultipleObjects), false);\n    boolean enableClassification =\n        sharedPreferences.getBoolean(context.getString(prefKeyForClassification), true);\n\n    CustomObjectDetectorOptions.Builder builder =\n        new CustomObjectDetectorOptions.Builder(localModel).setDetectorMode(mode);\n    if (enableMultipleObjects) {\n      builder.enableMultipleObjects();\n    }\n    if (enableClassification) {\n      builder.enableClassification().setMaxPerObjectLabelCount(1);\n    }\n    return builder.build();\n  }\n\n  public static FaceDetectorOptions getFaceDetectorOptions(Context context) {\n    int landmarkMode =\n        getModeTypePreferenceValue(\n            context,\n            R.string.pref_key_live_preview_face_detection_landmark_mode,\n            FaceDetectorOptions.LANDMARK_MODE_NONE);\n    int contourMode =\n        getModeTypePreferenceValue(\n            context,\n            R.string.pref_key_live_preview_face_detection_contour_mode,\n            FaceDetectorOptions.CONTOUR_MODE_ALL);\n    int classificationMode =\n        getModeTypePreferenceValue(\n            context,\n            R.string.pref_key_live_preview_face_detection_classification_mode,\n            FaceDetectorOptions.CLASSIFICATION_MODE_NONE);\n    int performanceMode =\n        getModeTypePreferenceValue(\n            context,\n            R.string.pref_key_live_preview_face_detection_performance_mode,\n            FaceDetectorOptions.PERFORMANCE_MODE_FAST);\n\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    boolean enableFaceTracking =\n        sharedPreferences.getBoolean(\n            context.getString(R.string.pref_key_live_preview_face_detection_face_tracking), false);\n    float minFaceSize =\n        Float.parseFloat(\n            sharedPreferences.getString(\n                context.getString(R.string.pref_key_live_preview_face_detection_min_face_size),\n                \"0.1\"));\n\n    FaceDetectorOptions.Builder optionsBuilder =\n        new FaceDetectorOptions.Builder()\n            .setLandmarkMode(landmarkMode)\n            .setContourMode(contourMode)\n            .setClassificationMode(classificationMode)\n            .setPerformanceMode(performanceMode)\n            .setMinFaceSize(minFaceSize);\n    if (enableFaceTracking) {\n      optionsBuilder.enableTracking();\n    }\n    return optionsBuilder.build();\n  }\n\n  public static PoseDetectorOptionsBase getPoseDetectorOptionsForLivePreview(Context context) {\n    int performanceMode =\n        getModeTypePreferenceValue(\n            context,\n            R.string.pref_key_live_preview_pose_detection_performance_mode,\n            POSE_DETECTOR_PERFORMANCE_MODE_FAST);\n    boolean preferGPU = preferGPUForPoseDetection(context);\n    if (performanceMode == POSE_DETECTOR_PERFORMANCE_MODE_FAST) {\n      PoseDetectorOptions.Builder builder =\n          new PoseDetectorOptions.Builder().setDetectorMode(PoseDetectorOptions.STREAM_MODE);\n      if (preferGPU) {\n        builder.setPreferredHardwareConfigs(PoseDetectorOptions.CPU_GPU);\n      }\n      return builder.build();\n    } else {\n      AccuratePoseDetectorOptions.Builder builder =\n          new AccuratePoseDetectorOptions.Builder()\n              .setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE);\n      if (preferGPU) {\n        builder.setPreferredHardwareConfigs(AccuratePoseDetectorOptions.CPU_GPU);\n      }\n      return builder.build();\n    }\n  }\n\n  public static PoseDetectorOptionsBase getPoseDetectorOptionsForStillImage(Context context) {\n    int performanceMode =\n        getModeTypePreferenceValue(\n            context,\n            R.string.pref_key_still_image_pose_detection_performance_mode,\n            POSE_DETECTOR_PERFORMANCE_MODE_FAST);\n    boolean preferGPU = preferGPUForPoseDetection(context);\n    if (performanceMode == POSE_DETECTOR_PERFORMANCE_MODE_FAST) {\n      PoseDetectorOptions.Builder builder =\n          new PoseDetectorOptions.Builder().setDetectorMode(PoseDetectorOptions.SINGLE_IMAGE_MODE);\n      if (preferGPU) {\n        builder.setPreferredHardwareConfigs(PoseDetectorOptions.CPU_GPU);\n      }\n      return builder.build();\n    } else {\n      AccuratePoseDetectorOptions.Builder builder =\n          new AccuratePoseDetectorOptions.Builder()\n              .setDetectorMode(AccuratePoseDetectorOptions.SINGLE_IMAGE_MODE);\n      if (preferGPU) {\n        builder.setPreferredHardwareConfigs(AccuratePoseDetectorOptions.CPU_GPU);\n      }\n      return builder.build();\n    }\n  }\n\n  public static boolean shouldEnableAutoZoom(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_enable_auto_zoom);\n    return sharedPreferences.getBoolean(prefKey, true);\n  }\n\n  public static boolean shouldGroupRecognizedTextInBlocks(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_group_recognized_text_in_blocks);\n    return sharedPreferences.getBoolean(prefKey, false);\n  }\n\n  public static boolean showLanguageTag(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_show_language_tag);\n    return sharedPreferences.getBoolean(prefKey, false);\n  }\n\n  public static boolean shouldShowTextConfidence(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_show_text_confidence);\n    return sharedPreferences.getBoolean(prefKey, false);\n  }\n\n  public static boolean preferGPUForPoseDetection(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_pose_detector_prefer_gpu);\n    return sharedPreferences.getBoolean(prefKey, true);\n  }\n\n  public static boolean shouldShowPoseDetectionInFrameLikelihoodLivePreview(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey =\n        context.getString(R.string.pref_key_live_preview_pose_detector_show_in_frame_likelihood);\n    return sharedPreferences.getBoolean(prefKey, true);\n  }\n\n  public static boolean shouldShowPoseDetectionInFrameLikelihoodStillImage(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey =\n        context.getString(R.string.pref_key_still_image_pose_detector_show_in_frame_likelihood);\n    return sharedPreferences.getBoolean(prefKey, true);\n  }\n\n  public static boolean shouldPoseDetectionVisualizeZ(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_pose_detector_visualize_z);\n    return sharedPreferences.getBoolean(prefKey, true);\n  }\n\n  public static boolean shouldPoseDetectionRescaleZForVisualization(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_pose_detector_rescale_z);\n    return sharedPreferences.getBoolean(prefKey, true);\n  }\n\n  public static boolean shouldPoseDetectionRunClassification(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_pose_detector_run_classification);\n    return sharedPreferences.getBoolean(prefKey, false);\n  }\n\n  public static boolean shouldSegmentationEnableRawSizeMask(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_segmentation_raw_size_mask);\n    return sharedPreferences.getBoolean(prefKey, false);\n  }\n\n  /**\n   * Mode type preference is backed by {@link android.preference.ListPreference} which only support\n   * storing its entry value as string type, so we need to retrieve as string and then convert to\n   * integer.\n   */\n  private static int getModeTypePreferenceValue(\n      Context context, @StringRes int prefKeyResId, int defaultValue) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(prefKeyResId);\n    return Integer.parseInt(sharedPreferences.getString(prefKey, String.valueOf(defaultValue)));\n  }\n\n  public static boolean isCameraLiveViewportEnabled(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_camera_live_viewport);\n    return sharedPreferences.getBoolean(prefKey, false);\n  }\n\n  public static int getFaceMeshUseCase(Context context) {\n    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);\n    String prefKey = context.getString(R.string.pref_key_face_mesh_use_case);\n    return Integer.parseInt(\n        sharedPreferences.getString(prefKey, String.valueOf(FaceMeshDetectorOptions.FACE_MESH)));\n  }\n\n  private PreferenceUtils() {}\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/preference/SettingsActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.preference;\n\nimport android.os.Bundle;\nimport android.preference.PreferenceFragment;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.app.AppCompatActivity;\nimport com.google.mlkit.vision.demo.R;\n\n/**\n * Hosts the preference fragment to configure settings for a demo activity that specified by the\n * {@link LaunchSource}.\n */\npublic class SettingsActivity extends AppCompatActivity {\n\n  public static final String EXTRA_LAUNCH_SOURCE = \"extra_launch_source\";\n\n  /** Specifies where this activity is launched from. */\n  @SuppressWarnings(\"NewApi\") // CameraX is only available on API 21+\n  public enum LaunchSource {\n    LIVE_PREVIEW(R.string.pref_screen_title_live_preview, LivePreviewPreferenceFragment.class),\n    STILL_IMAGE(R.string.pref_screen_title_still_image, StillImagePreferenceFragment.class),\n    CAMERAX_LIVE_PREVIEW(\n        R.string.pref_screen_title_camerax_live_preview,\n        CameraXLivePreviewPreferenceFragment.class),\n    CAMERAXSOURCE_DEMO(\n        R.string.pref_screen_title_cameraxsource_demo, CameraXSourceDemoPreferenceFragment.class);\n\n    private final int titleResId;\n    private final Class<? extends PreferenceFragment> prefFragmentClass;\n\n    LaunchSource(int titleResId, Class<? extends PreferenceFragment> prefFragmentClass) {\n      this.titleResId = titleResId;\n      this.prefFragmentClass = prefFragmentClass;\n    }\n  }\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    setContentView(R.layout.activity_settings);\n\n    LaunchSource launchSource =\n        (LaunchSource) getIntent().getSerializableExtra(EXTRA_LAUNCH_SOURCE);\n    ActionBar actionBar = getSupportActionBar();\n    if (actionBar != null) {\n      actionBar.setTitle(launchSource.titleResId);\n    }\n\n    try {\n      getFragmentManager()\n          .beginTransaction()\n          .replace(\n              R.id.settings_container,\n              launchSource.prefFragmentClass.getDeclaredConstructor().newInstance())\n          .commit();\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/preference/StillImagePreferenceFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.google.mlkit.vision.demo.preference;\n\nimport android.os.Bundle;\nimport android.preference.PreferenceFragment;\nimport com.google.mlkit.vision.demo.R;\n\n/** Configures still image demo settings. */\npublic class StillImagePreferenceFragment extends PreferenceFragment {\n\n  @Override\n  public void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    addPreferencesFromResource(R.xml.preference_still_image);\n  }\n}\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/drawable/list_item_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\" >\n    <stroke android:width=\"3dip\" android:color=\"@color/blue\"/>\n    <corners android:bottomRightRadius=\"16dp\"\n        android:bottomLeftRadius=\"16dp\"\n        android:topLeftRadius=\"16dp\"\n        android:topRightRadius=\"16dp\" />\n</shape>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/drawable/logo_mlkit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:ignore=\"NewApi\"\n    android:width=\"172dp\"\n    android:height=\"129dp\"\n    android:viewportWidth=\"172.43\"\n    android:viewportHeight=\"129.06\">\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M1.102,114.948l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M9.5,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#abccfc\"\n        android:pathData=\"M57.69,9.76h19v109.85h-19z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M67.19,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M58.779,114.962l57.68,-109.632l16.815,8.847l-57.68,109.632z\" />\n    <path\n        android:fillColor=\"#abccfc\"\n        android:pathData=\"M115.38,9.76h19v109.85h-19z\" />\n    <path\n        android:fillColor=\"#4285f4\"\n        android:pathData=\"M124.88,109.93h38.39v19h-38.39z\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M124.88,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M163.26,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M124.88,9.76m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n    <path\n        android:fillColor=\"#0d47a1\"\n        android:pathData=\"M67.19,119.43m-9.5,0a9.5,9.5 0,1 1,19 0a9.5,9.5 0,1 1,-19 0\" />\n</vector>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/drawable-hdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3.333333492dp\"\n    android:insetLeft=\"3.333333492dp\"\n    android:insetBottom=\"7.333333492dp\"\n    android:insetRight=\"3.333333492dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/drawable-mdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3dp\"\n    android:insetLeft=\"3dp\"\n    android:insetBottom=\"7dp\"\n    android:insetRight=\"3dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/drawable-xhdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3.5dp\"\n    android:insetLeft=\"3.5dp\"\n    android:insetBottom=\"7.5dp\"\n    android:insetRight=\"3.5dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/drawable-xxhdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3.666666746dp\"\n    android:insetLeft=\"3.666666746dp\"\n    android:insetBottom=\"7.666666985dp\"\n    android:insetRight=\"3.666666746dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/drawable-xxxhdpi/ic_switch_camera_white_48dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- This is an example InsetDrawable. It should be manually reviewed. -->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/ic_switch_camera_white_48dp_inset\"\n    android:insetTop=\"3.75dp\"\n    android:insetLeft=\"3.75dp\"\n    android:insetBottom=\"7.75dp\"\n    android:insetRight=\"3.75dp\"\n    android:visible=\"true\" />\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/activity_chooser.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:orientation=\"vertical\">\n\n  <ImageView\n      android:id=\"@+id/imageView\"\n      android:contentDescription=\"@string/app_name\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"50dp\"\n      android:layout_marginTop=\"32dp\"\n      app:srcCompat=\"@drawable/logo_mlkit\" />\n\n  <TextView\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:paddingTop=\"32dp\"\n      android:paddingBottom=\"32dp\"\n      android:fontFamily=\"google-sans\"\n      android:gravity=\"center_horizontal\"\n      android:text=\"@string/app_name\"\n      android:textColor=\"@color/white\"\n      android:textSize=\"18sp\"/>\n\n  <ListView\n      android:id=\"@+id/test_activity_list_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"/>\n</LinearLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/activity_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/settings_container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n</LinearLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/activity_still_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <ImageView\n      android:id=\"@+id/preview\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:adjustViewBounds=\"true\"\n      app:layout_constraintBottom_toTopOf=\"@+id/control\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintTop_toTopOf=\"parent\" />\n\n  <com.google.mlkit.vision.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintLeft_toLeftOf=\"@id/preview\"\n      app:layout_constraintRight_toRightOf=\"@id/preview\"\n      app:layout_constraintTop_toTopOf=\"@id/preview\"\n      app:layout_constraintBottom_toBottomOf=\"@id/preview\"/>\n\n  <LinearLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      android:background=\"#000\"\n      android:orientation=\"vertical\">\n\n    <Button\n        android:id=\"@+id/select_image_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_margin=\"12dp\"\n        android:text=\"@string/select_image\"/>\n\n    <LinearLayout\n        android:id=\"@+id/control2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        android:background=\"#000\"\n        android:orientation=\"horizontal\">\n\n      <Spinner\n          android:id=\"@+id/size_selector\"\n          android:layout_width=\"0dp\"\n          android:layout_weight=\"1\"\n          android:layout_height=\"wrap_content\"\n          android:layout_gravity=\"center\"/>\n\n      <Spinner\n          android:id=\"@+id/feature_selector\"\n          android:layout_width=\"0dp\"\n          android:layout_weight=\"1\"\n          android:layout_height=\"wrap_content\"\n          android:layout_gravity=\"center\"/>\n    </LinearLayout>\n  </LinearLayout>\n\n  <include\n      layout=\"@layout/settings_style\"\n      android:id=\"@+id/settings_button\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      app:layout_constraintRight_toRightOf=\"@id/root\"\n      app:layout_constraintTop_toTopOf=\"@id/root\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/activity_vision_camerax_live_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <androidx.camera.view.PreviewView\n      android:id=\"@+id/preview_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintTop_toTopOf=\"parent\"\n      app:layout_constraintBottom_toTopOf=\"@+id/control\"/>\n\n  <com.google.mlkit.vision.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintLeft_toLeftOf=\"@id/preview_view\"\n      app:layout_constraintRight_toRightOf=\"@id/preview_view\"\n      app:layout_constraintTop_toTopOf=\"@id/preview_view\"\n      app:layout_constraintBottom_toBottomOf=\"@id/preview_view\"/>\n\n  <include\n      android:id=\"@+id/settings_button\"\n      layout=\"@layout/settings_style\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      app:layout_constraintRight_toRightOf=\"@id/preview_view\"\n      app:layout_constraintTop_toTopOf=\"@id/preview_view\" />\n\n  <LinearLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"60dp\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      android:background=\"#000\"\n      android:orientation=\"horizontal\">\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"0dp\"\n        android:layout_weight=\"1\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"/>\n\n  </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/activity_vision_cameraxsource_demo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <androidx.camera.view.PreviewView\n      android:id=\"@+id/preview_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintTop_toTopOf=\"parent\"\n      app:layout_constraintBottom_toTopOf=\"@+id/control\"/>\n\n  <com.google.mlkit.vision.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintLeft_toLeftOf=\"@id/preview_view\"\n      app:layout_constraintRight_toRightOf=\"@id/preview_view\"\n      app:layout_constraintTop_toTopOf=\"@id/preview_view\"\n      app:layout_constraintBottom_toBottomOf=\"@id/preview_view\"/>\n\n  <include\n      android:id=\"@+id/settings_button\"\n      layout=\"@layout/settings_style\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      app:layout_constraintRight_toRightOf=\"@id/preview_view\"\n      app:layout_constraintTop_toTopOf=\"@id/preview_view\" />\n\n  <LinearLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"60dp\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      android:background=\"#000\"\n      android:orientation=\"horizontal\">\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <TextView\n        android:id=\"@+id/detector\"\n        android:layout_width=\"0dp\"\n        android:layout_weight=\"1\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center\"\n        android:maxLines=\"1\"\n        android:textStyle=\"bold\"\n        android:textColor=\"#FFF\"\n        android:textSize=\"16sp\"\n        android:text=\"@string/custom_object_detection\"/>\n  </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/activity_vision_entry_choice.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_gravity=\"center\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:background=\"@drawable/list_item_background\"\n        android:id=\"@+id/java_entry_point\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"@dimen/activity_vertical_margin\"\n        android:padding=\"20dp\"\n        android:text=\"@string/java_entry_title\"\n        android:textSize=\"26sp\" />\n\n    <TextView\n        android:background=\"@drawable/list_item_background\"\n        android:id=\"@+id/kotlin_entry_point\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"@dimen/activity_vertical_margin\"\n        android:padding=\"20dp\"\n        android:text=\"@string/kotlin_entry_title\"\n        android:textSize=\"26sp\" />\n</LinearLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/activity_vision_live_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <com.google.mlkit.vision.demo.CameraSourcePreview\n      android:id=\"@+id/preview_view\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintTop_toTopOf=\"parent\"\n      app:layout_constraintBottom_toTopOf=\"@+id/control\"/>\n\n  <com.google.mlkit.vision.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"0dp\"\n      app:layout_constraintLeft_toLeftOf=\"@id/preview_view\"\n      app:layout_constraintRight_toRightOf=\"@id/preview_view\"\n      app:layout_constraintTop_toTopOf=\"@id/preview_view\"\n      app:layout_constraintBottom_toBottomOf=\"@id/preview_view\"/>\n\n  <include\n      android:id=\"@+id/settings_button\"\n      layout=\"@layout/settings_style\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      app:layout_constraintRight_toRightOf=\"@id/preview_view\"\n      app:layout_constraintTop_toTopOf=\"@id/preview_view\" />\n\n  <LinearLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"60dp\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      android:background=\"#000\"\n      android:orientation=\"horizontal\">\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"0dp\"\n        android:layout_weight=\"1\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"/>\n\n  </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/settings_style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ImageView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"12dp\"\n    android:contentDescription=\"@string/menu_item_settings\"\n    android:src=\"@drawable/ic_settings_white_24dp\"/>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/spinner_style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TextView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:textStyle=\"bold\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"1dip\"\n    android:gravity=\"center\"\n    android:textColor=\"#FFF\"\n    android:textSize=\"16sp\"/>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout/toggle_style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item\n      android:drawable=\"@drawable/ic_switch_camera_white_48dp\"\n      android:state_checked=\"true\"/>\n  <item\n      android:drawable=\"@drawable/ic_switch_camera_white_48dp\"\n      android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout-land/activity_vision_camerax_live_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <androidx.camera.view.PreviewView\n      android:id=\"@+id/preview_view\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintEnd_toStartOf=\"@+id/control\"/>\n\n  <com.google.mlkit.vision.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toStartOf=\"@id/preview_view\"\n      app:layout_constraintEnd_toEndOf=\"@id/preview_view\" />\n\n  <FrameLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"220dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toEndOf=\"@id/preview_view\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      android:background=\"#000\">\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"top\"/>\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"bottom|start\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <ImageView\n        android:id=\"@+id/settings_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:padding=\"12dp\"\n        android:contentDescription=\"@string/menu_item_settings\"\n        android:src=\"@drawable/ic_settings_white_24dp\"/>\n  </FrameLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout-land/activity_vision_cameraxsource_demo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <androidx.camera.view.PreviewView\n      android:id=\"@+id/preview_view\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintEnd_toStartOf=\"@+id/control\"/>\n\n  <com.google.mlkit.vision.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toStartOf=\"@id/preview_view\"\n      app:layout_constraintEnd_toEndOf=\"@id/preview_view\" />\n\n  <FrameLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"220dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toEndOf=\"@id/preview_view\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      android:background=\"#000\">\n\n    <TextView\n        android:id=\"@+id/detector\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"top\"\n        android:gravity=\"center\"\n        android:maxLines=\"2\"\n        android:textStyle=\"bold\"\n        android:textColor=\"#FFF\"\n        android:textSize=\"16sp\"\n        android:text=\"@string/custom_object_detection\"/>\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"bottom|start\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <ImageView\n        android:id=\"@+id/settings_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:padding=\"12dp\"\n        android:contentDescription=\"@string/menu_item_settings\"\n        android:src=\"@drawable/ic_settings_white_24dp\"/>\n  </FrameLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/layout-land/activity_vision_live_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:keepScreenOn=\"true\">\n\n  <com.google.mlkit.vision.demo.CameraSourcePreview\n      android:id=\"@+id/preview_view\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintEnd_toStartOf=\"@+id/control\"/>\n\n  <com.google.mlkit.vision.demo.GraphicOverlay\n      android:id=\"@+id/graphic_overlay\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintStart_toStartOf=\"@id/preview_view\"\n      app:layout_constraintEnd_toEndOf=\"@id/preview_view\" />\n\n  <FrameLayout\n      android:id=\"@id/control\"\n      android:layout_width=\"220dp\"\n      android:layout_height=\"match_parent\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      android:background=\"#000\">\n\n    <Spinner\n        android:id=\"@+id/spinner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"top\"/>\n\n    <ToggleButton\n        android:id=\"@+id/facing_switch\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"bottom|start\"\n        android:background=\"@layout/toggle_style\"\n        android:checked=\"false\"\n        android:textOff=\"\"\n        android:textOn=\"\"/>\n\n    <ImageView\n        android:id=\"@+id/settings_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:padding=\"12dp\"\n        android:contentDescription=\"@string/menu_item_settings\"\n        android:src=\"@drawable/ic_settings_white_24dp\"/>\n  </FrameLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/menu/camera_button_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n  <item android:id=\"@+id/select_images_from_local\"\n      android:title=\"Select image from album\"\n      android:orderInCategory=\"100\"\n      app:showAsAction=\"never\" />\n  <item android:id=\"@+id/take_photo_using_camera\"\n      android:title=\"Take photo\"\n      android:orderInCategory=\"100\"\n      app:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/values/arrays.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n  <string-array name=\"pref_entries_face_detector_landmark_mode\">\n    <item>@string/pref_entries_face_detector_landmark_mode_no_landmarks</item>\n    <item>@string/pref_entries_face_detector_landmark_mode_all_landmarks</item>\n  </string-array>\n\n  <string-array name=\"pref_entry_values_face_detector_landmark_mode\">\n    <item>@string/pref_entry_values_face_detector_landmark_mode_no_landmarks</item>\n    <item>@string/pref_entry_values_face_detector_landmark_mode_all_landmarks</item>\n  </string-array>\n\n  <string-array name=\"pref_entries_face_detector_contour_mode\">\n    <item>@string/pref_entries_face_detector_contour_mode_no_contours</item>\n    <item>@string/pref_entries_face_detector_contour_mode_all_contours</item>\n  </string-array>\n\n  <string-array name=\"pref_entry_values_face_detector_contour_mode\">\n    <item>@string/pref_entry_values_face_detector_contour_mode_no_contours</item>\n    <item>@string/pref_entry_values_face_detector_contour_mode_all_contours</item>\n  </string-array>\n\n  <string-array name=\"pref_entries_face_detector_classification_mode\">\n    <item>@string/pref_entries_face_detector_classification_mode_no_classifications</item>\n    <item>@string/pref_entries_face_detector_classification_mode_all_classifications</item>\n  </string-array>\n\n  <string-array name=\"pref_entry_values_face_detector_classification_mode\">\n    <item>@string/pref_entry_values_face_detector_classification_mode_no_classifications</item>\n    <item>@string/pref_entry_values_face_detector_classification_mode_all_classifications</item>\n  </string-array>\n\n  <string-array name=\"pref_entries_face_detector_performance_mode\">\n    <item>@string/pref_entries_face_detector_performance_mode_fast</item>\n    <item>@string/pref_entries_face_detector_performance_mode_accurate</item>\n  </string-array>\n\n  <string-array name=\"pref_entry_values_face_detector_performance_mode\">\n    <item>@string/pref_entry_values_face_detector_performance_mode_fast</item>\n    <item>@string/pref_entry_values_face_detector_performance_mode_accurate</item>\n  </string-array>\n\n  <string-array name=\"pref_entries_values_pose_detector_performance_mode\">\n    <item>@string/pref_entries_pose_detector_performance_mode_fast</item>\n    <item>@string/pref_entries_pose_detector_performance_mode_accurate</item>\n  </string-array>\n\n  <string-array name=\"pref_entry_values_pose_detector_performance_mode\">\n    <item>@string/pref_entry_values_pose_detector_performance_mode_fast</item>\n    <item>@string/pref_entry_values_pose_detector_performance_mode_accurate</item>\n  </string-array>\n\n  <string-array name=\"pref_entry_titles_face_mesh_use_case\">\n    <item>Bounding Box Only</item>\n    <item>Face Mesh</item>\n    <item>Face Mesh(Simplified Contours only)</item>\n  </string-array>\n\n  <string-array name=\"pref_entry_values_face_mesh_use_case\">\n    <item>0</item>\n    <item>1</item>\n    <item>999</item>\n  </string-array>\n</resources>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#4CAF50</color>\n    <color name=\"colorPrimaryDark\">#388E3C</color>\n    <color name=\"colorAccent\">#7C4DFF</color>\n\n    <color name=\"blue_grey_400\">#78909C</color>\n    <color name=\"light_grey_400\">#E6E6E6</color>\n    <color name=\"light_green_700\">#689F38</color>\n    <color name=\"gray\">#BFBFBF</color>\n    <color name=\"white\">#FFFFFF</color>\n    <color name=\"blue\">#4286f4</color>\n    <color name=\"red\">#f44242</color>\n</resources>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"padding_standard\">10dp</dimen>\n</resources>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">MLKit-Vision</string>\n    <string name=\"java_entry_title\" translatable=\"false\">Run the ML Kit quickstart written in Java</string>\n    <string name=\"kotlin_entry_title\" translatable=\"false\">Run the ML Kit quickstart written in Kotlin</string>\n    <string name=\"ok\" translatable=\"false\">OK</string>\n    <string name=\"permission_camera_rationale\" translatable=\"false\">Access to the camera is needed for detection</string>\n    <string name=\"no_camera_permission\" translatable=\"false\">This application cannot run because it does not have the camera permission.  The application will now exit.</string>\n    <string name=\"low_storage_error\" translatable=\"false\">Face detector dependencies cannot be downloaded due to low device storage</string>\n    <string name=\"toggle_turn_on\" translatable=\"false\">Front</string>\n    <string name=\"toggle_turn_off\" translatable=\"false\">Back</string>\n    <string name=\"desc_camera_source_activity\" translatable=\"false\">Vision detectors demo with live camera preview</string>\n    <string name=\"desc_still_image_activity\" translatable=\"false\">Vision detectors demo with a still image</string>\n    <string name=\"desc_camerax_live_preview_activity\" translatable=\"false\">Vision detectors demo with live preview using CameraX. Note that CameraX is only supported on API 21+</string>\n    <string name=\"desc_cameraxsource_demo_activity\" translatable=\"false\">Object detection with custom classifier using ML Kit CameraXSource API. Note that CameraX is only supported on API 21+</string>\n    <string name=\"download_error\" translatable=\"false\">Download error</string>\n    <string name=\"start_over\" translatable=\"false\">Start over</string>\n    <string name=\"menu_item_settings\" translatable=\"false\">Settings</string>\n    <string name=\"select_image\" translatable=\"false\">Select image</string>\n    <string name=\"custom_object_detection\" translatable=\"false\">Custom Object Detector</string>\n\n    <!-- Settings related strings. -->\n    <string name=\"pref_screen\" translatable=\"false\">ps</string>\n    <string name=\"pref_screen_title_live_preview\" translatable=\"false\">Live preview settings</string>\n    <string name=\"pref_screen_title_still_image\" translatable=\"false\">Still image settings</string>\n    <string name=\"pref_screen_title_camerax_live_preview\" translatable=\"false\">CameraX live preview settings</string>\n    <string name=\"pref_screen_title_cameraxsource_demo\" translatable=\"false\">CameraXSource live preview settings</string>\n    <string name=\"pref_category_info\" translatable=\"false\">Detection Info</string>\n    <string name=\"pref_category_face_detection\" translatable=\"false\">Face Detection</string>\n    <string name=\"pref_category_object_detection\" translatable=\"false\">Object Detection / Custom Object Detection</string>\n    <string name=\"pref_category_automl\" translatable=\"false\">AutoML Image Labeling</string>\n    <string name=\"pref_category_pose_detection\" translatable=\"false\">Pose Detection</string>\n    <string name=\"pref_category_segmentation\" translatable=\"false\">Selfie Segmentation</string>\n    <string name=\"pref_category_text_recognition\" translatable=\"false\">Text Recognition</string>\n    <string name=\"pref_category_barcode_scanning\" translatable=\"false\">Barcode Scanning</string>\n\n    <!-- Strings for camera settings. -->\n    <string name=\"pref_category_key_camera\" translatable=\"false\">pckc</string>\n    <string name=\"pref_category_title_camera\" translatable=\"false\">Camera</string>\n    <string name=\"pref_key_rear_camera_preview_size\" translatable=\"false\">rcpvs</string>\n    <string name=\"pref_key_rear_camera_picture_size\" translatable=\"false\">rcpts</string>\n    <string name=\"pref_key_front_camera_preview_size\" translatable=\"false\">fcpvs</string>\n    <string name=\"pref_key_front_camera_picture_size\" translatable=\"false\">fcpts</string>\n    <string name=\"pref_key_camerax_rear_camera_target_resolution\" translatable=\"false\">crctas</string>\n    <string name=\"pref_key_camerax_front_camera_target_resolution\" translatable=\"false\">cfctas</string>\n    <string name=\"pref_key_camera_live_viewport\" translatable=\"false\">clv</string>\n    <string name=\"pref_title_rear_camera_preview_size\" translatable=\"false\">Rear camera preview size</string>\n    <string name=\"pref_title_front_camera_preview_size\" translatable=\"false\">Front camera preview size</string>\n    <string name=\"pref_title_camerax_rear_camera_target_resolution\" translatable=\"false\">CameraX rear camera target resolution</string>\n    <string name=\"pref_title_camerax_front_camera_target_resolution\" translatable=\"false\">CameraX front camera target resolution</string>\n    <string name=\"pref_title_camera_live_viewport\" translatable=\"false\">Enable live viewport</string>\n    <string name=\"pref_summary_camera_live_viewport\" translatable=\"false\">Do not block camera preview drawing on detection</string>\n\n    <!-- Strings for info preference. -->\n    <string name=\"pref_title_info_hide\" translatable=\"false\">Hide detection info</string>\n    <string name=\"pref_key_info_hide\" translatable=\"false\">ih</string>\n\n    <!-- Strings for barcode scanning preference. -->\n    <string name=\"pref_key_enable_auto_zoom\" translatable=\"false\">eaz</string>\n    <string name=\"pref_title_enable_auto_zoom\" translatable=\"false\">Enable auto zoom</string>\n\n    <!-- Strings for text recognition preference. -->\n    <string name=\"pref_title_group_recognized_text_in_blocks\" translatable=\"false\">Group recognized text in paragraphs</string>\n    <string name=\"pref_key_group_recognized_text_in_blocks\" translatable=\"false\">grtib</string>\n    <string name=\"pref_title_show_language_tag\" translatable=\"false\">Show language identified</string>\n    <string name=\"pref_key_show_language_tag\" translatable=\"false\">slt</string>\n    <string name=\"pref_title_show_text_confidence\" translatable=\"false\">Show confidence score</string>\n    <string name=\"pref_key_show_text_confidence\" translatable=\"false\">stc</string>\n\n    <!-- Strings for object detector enable multiple objects preference. -->\n    <string name=\"pref_title_object_detector_enable_multiple_objects\" translatable=\"false\">Enable multiple objects</string>\n    <string name=\"pref_key_live_preview_object_detector_enable_multiple_objects\" translatable=\"false\">lpodemo</string>\n    <string name=\"pref_key_still_image_object_detector_enable_multiple_objects\" translatable=\"false\">siodemo</string>\n\n    <!-- Strings for object detector enable classification preference. -->\n    <string name=\"pref_title_object_detector_enable_classification\" translatable=\"false\">Enable classification</string>\n    <string name=\"pref_key_live_preview_object_detector_enable_classification\" translatable=\"false\">lpodec</string>\n    <string name=\"pref_key_still_image_object_detector_enable_classification\" translatable=\"false\">siodec</string>\n\n    <!-- Strings for face detector landmark mode preference. -->\n    <string name=\"pref_title_face_detector_landmark_mode\" translatable=\"false\">Landmark mode</string>\n    <string name=\"pref_key_live_preview_face_detection_landmark_mode\" translatable=\"false\">lpfdlm</string>\n    <string name=\"pref_entries_face_detector_landmark_mode_no_landmarks\" translatable=\"false\">No landmarks</string>\n    <string name=\"pref_entries_face_detector_landmark_mode_all_landmarks\" translatable=\"false\">All landmarks</string>\n    <!-- The following entry values must match the ones in FaceDetectorOptions#LandmarkMode -->\n    <string name=\"pref_entry_values_face_detector_landmark_mode_no_landmarks\" translatable=\"false\">1</string>\n    <string name=\"pref_entry_values_face_detector_landmark_mode_all_landmarks\" translatable=\"false\">2</string>\n\n    <!-- Strings for face detector contour mode preference. -->\n    <string name=\"pref_title_face_detector_contour_mode\" translatable=\"false\">Contour mode</string>\n    <string name=\"pref_key_live_preview_face_detection_contour_mode\" translatable=\"false\">lpfdcm</string>\n    <string name=\"pref_entries_face_detector_contour_mode_no_contours\" translatable=\"false\">No contours</string>\n    <string name=\"pref_entries_face_detector_contour_mode_all_contours\" translatable=\"false\">All contours</string>\n    <!-- The following entry values must match the ones in FaceDetectorOptions#ContourMode -->\n    <string name=\"pref_entry_values_face_detector_contour_mode_no_contours\" translatable=\"false\">1</string>\n    <string name=\"pref_entry_values_face_detector_contour_mode_all_contours\" translatable=\"false\">2</string>\n\n    <!-- Strings for face detector classification mode preference. -->\n    <string name=\"pref_title_face_detector_classification_mode\" translatable=\"false\">Classification mode</string>\n    <string name=\"pref_key_live_preview_face_detection_classification_mode\" translatable=\"false\">lpfdcfm</string>\n    <string name=\"pref_entries_face_detector_classification_mode_no_classifications\" translatable=\"false\">No classifications</string>\n    <string name=\"pref_entries_face_detector_classification_mode_all_classifications\" translatable=\"false\">All classifications</string>\n    <!-- The following entry values must match the ones in FaceDetectorOptions#ClassificationMode -->\n    <string name=\"pref_entry_values_face_detector_classification_mode_no_classifications\" translatable=\"false\">1</string>\n    <string name=\"pref_entry_values_face_detector_classification_mode_all_classifications\" translatable=\"false\">2</string>\n\n    <!-- Strings for face detector performance mode preference. -->\n    <string name=\"pref_title_face_detector_performance_mode\" translatable=\"false\">Performance mode</string>\n    <string name=\"pref_key_live_preview_face_detection_performance_mode\" translatable=\"false\">lpfdpm</string>\n    <string name=\"pref_entries_face_detector_performance_mode_fast\" translatable=\"false\">Fast</string>\n    <string name=\"pref_entries_face_detector_performance_mode_accurate\" translatable=\"false\">Accurate</string>\n    <!-- The following entry values must match the ones in FaceDetectorOptions#PerformanceMode -->\n    <string name=\"pref_entry_values_face_detector_performance_mode_fast\" translatable=\"false\">1</string>\n    <string name=\"pref_entry_values_face_detector_performance_mode_accurate\" translatable=\"false\">2</string>\n\n    <!-- Strings for face detector face tracking preference. -->\n    <string name=\"pref_title_face_detector_face_tracking\" translatable=\"false\">Face tracking</string>\n    <string name=\"pref_key_live_preview_face_detection_face_tracking\" translatable=\"false\">lpfdft</string>\n\n    <!-- Strings for face detector min face size preference. -->\n    <string name=\"pref_title_face_detector_min_face_size\" translatable=\"false\">Minimum face size</string>\n    <string name=\"pref_key_live_preview_face_detection_min_face_size\" translatable=\"false\">lpfdmfs</string>\n    <string name=\"pref_dialog_message_face_detector_min_face_size\" translatable=\"false\">Proportion of the head width to the image width, and the valid value range is [0.0, 1.0]</string>\n    <string name=\"pref_toast_invalid_min_face_size\" translatable=\"false\">Minimum face size must be a float value and in the range [0.0, 1.0]</string>\n\n    <!-- Strings for pose detector performance mode preference. -->\n    <string name=\"pref_title_pose_detector_performance_mode\" translatable=\"false\">Performance mode</string>\n    <string name=\"pref_key_live_preview_pose_detection_performance_mode\" translatable=\"false\">lppdpm</string>\n    <string name=\"pref_key_still_image_pose_detection_performance_mode\" translatable=\"false\">sipdpm</string>\n    <string name=\"pref_entries_pose_detector_performance_mode_fast\" translatable=\"false\">Fast</string>\n    <string name=\"pref_entries_pose_detector_performance_mode_accurate\" translatable=\"false\">Accurate</string>\n    <string name=\"pref_entry_values_pose_detector_performance_mode_fast\" translatable=\"false\">1</string>\n    <string name=\"pref_entry_values_pose_detector_performance_mode_accurate\" translatable=\"false\">2</string>\n\n    <!-- Strings for pose detector prefer gpu preference. -->\n    <string name=\"pref_title_pose_detector_prefer_gpu\" translatable=\"false\">Prefer using GPU</string>\n    <string name=\"pref_key_pose_detector_prefer_gpu\" translatable=\"false\">pdpg</string>\n    <string name=\"pref_summary_pose_detector_prefer_gpu\" translatable=\"false\">If enabled, GPU will be used as long as it is available, stable and returns correct results. In this case, the detector will not check if GPU is really faster than CPU.</string>\n\n    <!-- Strings for pose detector showInFrameLikelihood preference. -->\n    <string name=\"pref_title_pose_detector_show_in_frame_likelihood\" translatable=\"false\">Show in-frame likelihood</string>\n    <string name=\"pref_key_live_preview_pose_detector_show_in_frame_likelihood\" translatable=\"false\">lppdsifl</string>\n    <string name=\"pref_key_still_image_pose_detector_show_in_frame_likelihood\" translatable=\"false\">sipdsifl</string>\n\n    <!-- Strings for pose detector z value visualization preference. -->\n    <string name=\"pref_title_pose_detector_visualize_z\" translatable=\"false\">Visualize z value</string>\n    <string name=\"pref_key_pose_detector_visualize_z\" translatable=\"false\">pdvz</string>\n    <string name=\"pref_title_pose_detector_rescale_z\" translatable=\"false\">Rescale z value for visualization</string>\n    <string name=\"pref_key_pose_detector_rescale_z\" translatable=\"false\">pdrz</string>\n\n    <!-- Strings for pose classification preference. -->\n    <string name=\"pref_title_pose_detector_run_classification\" translatable=\"false\">Run Classification</string>\n    <string name=\"pref_key_pose_detector_run_classification\" translatable=\"false\">pdrc</string>\n    <string name=\"pref_summary_pose_detector_run_classification\" translatable=\"false\">Classify squat and pushup poses. Count reps in streaming mode. To get the best classification results based on the current sample data, face the camera side way and make sure your full body is in the frame.</string>\n\n    <!-- Strings for segmentation preference. -->\n    <string name=\"pref_title_segmentation_raw_size_mask\" translatable=\"false\">Enable raw size mask</string>\n    <string name=\"pref_key_segmentation_raw_size_mask\" translatable=\"false\">srsm</string>\n\n    <string name=\"pref_group_title_face_mesh\" translatable=\"false\">Face Mesh Detection</string>\n    <string name=\"pref_title_face_mesh_use_case\" translatable=\"false\">Use Case</string>\n    <string name=\"pref_key_face_mesh_use_case\" translatable=\"false\">face_mesh_use_case</string>\n\n</resources>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/values/styles.xml",
    "content": "<resources>\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.NoActionBar\"/>\n</resources>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/xml/preference_live_preview_quickstart.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:key=\"@string/pref_screen\">\n\n  <PreferenceCategory\n      android:enabled=\"true\"\n      android:key=\"@string/pref_category_key_camera\"\n      android:title=\"@string/pref_category_title_camera\">\n\n    <ListPreference\n        android:key=\"@string/pref_key_rear_camera_preview_size\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_rear_camera_preview_size\"/>\n\n    <ListPreference\n        android:key=\"@string/pref_key_front_camera_preview_size\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_front_camera_preview_size\"/>\n\n    <ListPreference\n        android:key=\"@string/pref_key_camerax_rear_camera_target_resolution\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_camerax_rear_camera_target_resolution\"/>\n\n        <ListPreference\n        android:key=\"@string/pref_key_camerax_front_camera_target_resolution\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_camerax_front_camera_target_resolution\"/>\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_camera_live_viewport\"\n        android:persistent=\"true\"\n        android:summary=\"@string/pref_summary_camera_live_viewport\"\n        android:title=\"@string/pref_title_camera_live_viewport\"/>\n\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_info\">\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_info_hide\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_info_hide\"/>\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_barcode_scanning\">\n\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_enable_auto_zoom\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_enable_auto_zoom\"/>\n\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_text_recognition\">\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_group_recognized_text_in_blocks\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_group_recognized_text_in_blocks\"/>\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_show_language_tag\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_show_language_tag\"/>\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_show_text_confidence\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_show_text_confidence\"/>\n\n  </PreferenceCategory>\n\n  <PreferenceCategory\n      android:title=\"@string/pref_category_object_detection\">\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_live_preview_object_detector_enable_multiple_objects\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_object_detector_enable_multiple_objects\"/>\n\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_live_preview_object_detector_enable_classification\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_object_detector_enable_classification\"/>\n\n  </PreferenceCategory>\n\n  <PreferenceCategory\n      android:title=\"@string/pref_category_face_detection\">\n\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_face_detector_landmark_mode_no_landmarks\"\n        android:entries=\"@array/pref_entries_face_detector_landmark_mode\"\n        android:entryValues=\"@array/pref_entry_values_face_detector_landmark_mode\"\n        android:key=\"@string/pref_key_live_preview_face_detection_landmark_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_landmark_mode\"\n        android:summary=\"%s\"/>\n\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_face_detector_contour_mode_all_contours\"\n        android:entries=\"@array/pref_entries_face_detector_contour_mode\"\n        android:entryValues=\"@array/pref_entry_values_face_detector_contour_mode\"\n        android:key=\"@string/pref_key_live_preview_face_detection_contour_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_contour_mode\"\n        android:summary=\"%s\"/>\n\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_face_detector_classification_mode_no_classifications\"\n        android:entries=\"@array/pref_entries_face_detector_classification_mode\"\n        android:entryValues=\"@array/pref_entry_values_face_detector_classification_mode\"\n        android:key=\"@string/pref_key_live_preview_face_detection_classification_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_classification_mode\"\n        android:summary=\"%s\"/>\n\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_face_detector_performance_mode_fast\"\n        android:entries=\"@array/pref_entries_face_detector_performance_mode\"\n        android:entryValues=\"@array/pref_entry_values_face_detector_performance_mode\"\n        android:key=\"@string/pref_key_live_preview_face_detection_performance_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_performance_mode\"\n        android:summary=\"%s\"/>\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_live_preview_face_detection_face_tracking\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_face_tracking\"/>\n\n    <EditTextPreference\n        android:defaultValue=\"0.1\"\n        android:dialogMessage=\"@string/pref_dialog_message_face_detector_min_face_size\"\n        android:key=\"@string/pref_key_live_preview_face_detection_min_face_size\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_min_face_size\"/>\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_pose_detection\">\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_pose_detector_performance_mode_fast\"\n        android:entries=\"@array/pref_entries_values_pose_detector_performance_mode\"\n        android:entryValues=\"@array/pref_entry_values_pose_detector_performance_mode\"\n        android:key=\"@string/pref_key_live_preview_pose_detection_performance_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_performance_mode\"\n        android:summary=\"%s\"/>\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_pose_detector_prefer_gpu\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_prefer_gpu\"\n        android:summary=\"@string/pref_summary_pose_detector_prefer_gpu\"/>\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_live_preview_pose_detector_show_in_frame_likelihood\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_show_in_frame_likelihood\"/>\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_pose_detector_visualize_z\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_visualize_z\"/>\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_pose_detector_rescale_z\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_rescale_z\"/>\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_pose_detector_run_classification\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_run_classification\"\n        android:summary=\"@string/pref_summary_pose_detector_run_classification\"/>\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_segmentation\">\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_segmentation_raw_size_mask\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_segmentation_raw_size_mask\"/>\n  </PreferenceCategory>\n  <PreferenceCategory android:title=\"@string/pref_group_title_face_mesh\">\n    <ListPreference\n        android:key=\"@string/pref_key_face_mesh_use_case\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_mesh_use_case\"\n        android:defaultValue=\"1\"\n        android:entries=\"@array/pref_entry_titles_face_mesh_use_case\"\n        android:entryValues=\"@array/pref_entry_values_face_mesh_use_case\"\n        android:summary=\"%s\"/>\n  </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "android/vision-quickstart/app/src/main/res/xml/preference_still_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n  <PreferenceCategory android:title=\"@string/pref_category_info\">\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_info_hide\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_info_hide\"/>\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_text_recognition\">\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_group_recognized_text_in_blocks\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_group_recognized_text_in_blocks\"/>\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_show_language_tag\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_show_language_tag\"/>\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_show_text_confidence\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_show_text_confidence\"/>\n\n  </PreferenceCategory>\n\n  <PreferenceCategory\n      android:title=\"@string/pref_category_object_detection\">\n\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_still_image_object_detector_enable_multiple_objects\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_object_detector_enable_multiple_objects\"/>\n\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_still_image_object_detector_enable_classification\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_object_detector_enable_classification\"/>\n\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_pose_detection\">\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_pose_detector_performance_mode_fast\"\n        android:entries=\"@array/pref_entries_values_pose_detector_performance_mode\"\n        android:entryValues=\"@array/pref_entry_values_pose_detector_performance_mode\"\n        android:key=\"@string/pref_key_still_image_pose_detection_performance_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_performance_mode\"\n        android:summary=\"%s\"/>\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_pose_detector_prefer_gpu\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_prefer_gpu\"\n        android:summary=\"@string/pref_summary_pose_detector_prefer_gpu\"/>\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_still_image_pose_detector_show_in_frame_likelihood\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_show_in_frame_likelihood\"/>\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_pose_detector_visualize_z\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_visualize_z\"/>\n    <SwitchPreference\n        android:defaultValue=\"true\"\n        android:key=\"@string/pref_key_pose_detector_rescale_z\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_rescale_z\"/>\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_pose_detector_run_classification\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_pose_detector_run_classification\"/>\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_category_segmentation\">\n    <SwitchPreference\n        android:defaultValue=\"false\"\n        android:key=\"@string/pref_key_segmentation_raw_size_mask\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_segmentation_raw_size_mask\"/>\n  </PreferenceCategory>\n\n  <PreferenceCategory\n      android:title=\"@string/pref_category_face_detection\">\n\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_face_detector_landmark_mode_no_landmarks\"\n        android:entries=\"@array/pref_entries_face_detector_landmark_mode\"\n        android:entryValues=\"@array/pref_entry_values_face_detector_landmark_mode\"\n        android:key=\"@string/pref_key_live_preview_face_detection_landmark_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_landmark_mode\"\n        android:summary=\"%s\"/>\n\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_face_detector_contour_mode_all_contours\"\n        android:entries=\"@array/pref_entries_face_detector_contour_mode\"\n        android:entryValues=\"@array/pref_entry_values_face_detector_contour_mode\"\n        android:key=\"@string/pref_key_live_preview_face_detection_contour_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_contour_mode\"\n        android:summary=\"%s\"/>\n\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_face_detector_classification_mode_no_classifications\"\n        android:entries=\"@array/pref_entries_face_detector_classification_mode\"\n        android:entryValues=\"@array/pref_entry_values_face_detector_classification_mode\"\n        android:key=\"@string/pref_key_live_preview_face_detection_classification_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_classification_mode\"\n        android:summary=\"%s\"/>\n\n    <ListPreference\n        android:defaultValue=\"@string/pref_entry_values_face_detector_performance_mode_fast\"\n        android:entries=\"@array/pref_entries_face_detector_performance_mode\"\n        android:entryValues=\"@array/pref_entry_values_face_detector_performance_mode\"\n        android:key=\"@string/pref_key_live_preview_face_detection_performance_mode\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_detector_performance_mode\"\n        android:summary=\"%s\"/>\n  </PreferenceCategory>\n\n  <PreferenceCategory android:title=\"@string/pref_group_title_face_mesh\">\n    <ListPreference\n        android:key=\"@string/pref_key_face_mesh_use_case\"\n        android:persistent=\"true\"\n        android:title=\"@string/pref_title_face_mesh_use_case\"\n        android:defaultValue=\"1\"\n        android:entries=\"@array/pref_entry_titles_face_mesh_use_case\"\n        android:entryValues=\"@array/pref_entry_values_face_mesh_use_case\"\n        android:summary=\"%s\"/>\n  </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "android/vision-quickstart/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = \"1.9.0\"\n\n    repositories {\n        mavenCentral()\n        mavenLocal()\n        google()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.3.1'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        mavenCentral()\n        mavenLocal()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android/vision-quickstart/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Jan 06 14:48:40 PST 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.5-bin.zip\n"
  },
  {
    "path": "android/vision-quickstart/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# Uses one worker to build. This helps resolve build OOM issue.\norg.gradle.workers.max=1\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n"
  },
  {
    "path": "android/vision-quickstart/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android/vision-quickstart/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android/vision-quickstart/settings.gradle",
    "content": "rootProject.name='ML Kit Vision Quickstart'\ninclude ':app'\n"
  },
  {
    "path": "ios/ios-snippets/Podfile",
    "content": "# Uncomment the next line to define a global platform for your project\n# platform :ios, '9.0'\n\nsource 'sso://cpdc-test/mlkit'\nsource 'https://github.com/CocoaPods/Specs.git'\n\ntarget 'objc-snippets' do\n  # Comment the next line if you don't want to use dynamic frameworks\n  use_frameworks!\n\n  # Pods for objc-snippets\n  pod 'MLKitCommon'\n  pod 'MLKitImageClassificationAutoML'\n  pod 'MLKitVision'\nend\n\ntarget 'swift-snippets' do\n  # Comment the next line if you don't want to use dynamic frameworks\n  use_frameworks!\n\n  # Pods for swift-snippets\n  pod 'MLKitCommon'\n  pod 'MLKitImageClassificationAutoML'\n  pod 'MLKitVision'\nend\n"
  },
  {
    "path": "ios/ios-snippets/mlkit-snippets.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t42170C9222986F6500B22418 /* AutoMLVision.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42170C9122986F6500B22418 /* AutoMLVision.swift */; };\n\t\t4264664422A862B200B5B7B5 /* ImagePreparation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4264664322A862B200B5B7B5 /* ImagePreparation.swift */; };\n\t\t4264664622A865C500B5B7B5 /* ImagePreparation.m in Sources */ = {isa = PBXBuildFile; fileRef = 4264664522A865C500B5B7B5 /* ImagePreparation.m */; };\n\t\t42825ACE22987089003A4469 /* ModelManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42825ACD22987089003A4469 /* ModelManagement.swift */; };\n\t\t42825AD022987134003A4469 /* AutoMLVision.m in Sources */ = {isa = PBXBuildFile; fileRef = 42825ACF22987134003A4469 /* AutoMLVision.m */; };\n\t\t42B043EB229DAB0E00ABAB63 /* ModelManagement.m in Sources */ = {isa = PBXBuildFile; fileRef = 42B043EA229DAB0E00ABAB63 /* ModelManagement.m */; };\n\t\t42B9833122986A18008AE4FF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42B9833022986A18008AE4FF /* AppDelegate.swift */; };\n\t\t42B9833322986A18008AE4FF /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42B9833222986A18008AE4FF /* ViewController.swift */; };\n\t\t42B9833622986A18008AE4FF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42B9833422986A18008AE4FF /* Main.storyboard */; };\n\t\t42B9833822986A19008AE4FF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42B9833722986A19008AE4FF /* Assets.xcassets */; };\n\t\t42B9833B22986A19008AE4FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42B9833922986A19008AE4FF /* LaunchScreen.storyboard */; };\n\t\t42B9834822986AC7008AE4FF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 42B9834722986AC7008AE4FF /* AppDelegate.m */; };\n\t\t42B9834B22986AC7008AE4FF /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 42B9834A22986AC7008AE4FF /* ViewController.m */; };\n\t\t42B9834E22986AC7008AE4FF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42B9834C22986AC7008AE4FF /* Main.storyboard */; };\n\t\t42B9835022986AC8008AE4FF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42B9834F22986AC8008AE4FF /* Assets.xcassets */; };\n\t\t42B9835322986AC8008AE4FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42B9835122986AC8008AE4FF /* LaunchScreen.storyboard */; };\n\t\t42B9835622986AC8008AE4FF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 42B9835522986AC8008AE4FF /* main.m */; };\n\t\tA87A0364EA8B57F695617CFD /* Pods_objc_snippets.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4873791D661430B0B0FB66B0 /* Pods_objc_snippets.framework */; };\n\t\tD1BC67399F5B39401ABB2FDF /* Pods_swift_snippets.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E72B4E6FF6BEA59CA6F1FF8D /* Pods_swift_snippets.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0114DD6801AD76446B4062A7 /* Pods-swift-snippets.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-swift-snippets.release.xcconfig\"; path = \"Target Support Files/Pods-swift-snippets/Pods-swift-snippets.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t3C5BD28ADB5263B9BE70FDF1 /* Pods-objc-snippets.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-objc-snippets.release.xcconfig\"; path = \"Target Support Files/Pods-objc-snippets/Pods-objc-snippets.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t42170C9122986F6500B22418 /* AutoMLVision.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoMLVision.swift; sourceTree = \"<group>\"; };\n\t\t4264664322A862B200B5B7B5 /* ImagePreparation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePreparation.swift; sourceTree = \"<group>\"; };\n\t\t4264664522A865C500B5B7B5 /* ImagePreparation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImagePreparation.m; sourceTree = \"<group>\"; };\n\t\t42825ACD22987089003A4469 /* ModelManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelManagement.swift; sourceTree = \"<group>\"; };\n\t\t42825ACF22987134003A4469 /* AutoMLVision.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AutoMLVision.m; sourceTree = \"<group>\"; };\n\t\t42B043EA229DAB0E00ABAB63 /* ModelManagement.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ModelManagement.m; sourceTree = \"<group>\"; };\n\t\t42B9832D22986A18008AE4FF /* swift-snippets.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"swift-snippets.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t42B9833022986A18008AE4FF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t42B9833222986A18008AE4FF /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\t42B9833522986A18008AE4FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t42B9833722986A19008AE4FF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t42B9833A22986A19008AE4FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t42B9833C22986A19008AE4FF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t42B9834422986AC7008AE4FF /* objc-snippets.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"objc-snippets.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t42B9834622986AC7008AE4FF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t42B9834722986AC7008AE4FF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t42B9834922986AC7008AE4FF /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\t42B9834A22986AC7008AE4FF /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\t42B9834D22986AC7008AE4FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t42B9834F22986AC8008AE4FF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t42B9835222986AC8008AE4FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t42B9835422986AC8008AE4FF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t42B9835522986AC8008AE4FF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t4873791D661430B0B0FB66B0 /* Pods_objc_snippets.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_objc_snippets.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t5480D0FE786A5C17362D8A56 /* Pods-swift-snippets.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-swift-snippets.debug.xcconfig\"; path = \"Target Support Files/Pods-swift-snippets/Pods-swift-snippets.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tB9A153CB3E937915C45D800B /* Pods-objc-snippets.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-objc-snippets.debug.xcconfig\"; path = \"Target Support Files/Pods-objc-snippets/Pods-objc-snippets.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tE72B4E6FF6BEA59CA6F1FF8D /* Pods_swift_snippets.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_swift_snippets.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t42B9832A22986A18008AE4FF /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tD1BC67399F5B39401ABB2FDF /* Pods_swift_snippets.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t42B9834122986AC7008AE4FF /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA87A0364EA8B57F695617CFD /* Pods_objc_snippets.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t42B98322229869E0008AE4FF = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t42B9832F22986A18008AE4FF /* swift-snippets */,\n\t\t\t\t42B9834522986AC7008AE4FF /* objc-snippets */,\n\t\t\t\t42B9832E22986A18008AE4FF /* Products */,\n\t\t\t\tC8A899ADE5B89620197E0F35 /* Pods */,\n\t\t\t\t56392CAB235A4ABC2AA4D2CD /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t42B9832E22986A18008AE4FF /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t42B9832D22986A18008AE4FF /* swift-snippets.app */,\n\t\t\t\t42B9834422986AC7008AE4FF /* objc-snippets.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t42B9832F22986A18008AE4FF /* swift-snippets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t42B9833022986A18008AE4FF /* AppDelegate.swift */,\n\t\t\t\t42B9833222986A18008AE4FF /* ViewController.swift */,\n\t\t\t\t42B9833422986A18008AE4FF /* Main.storyboard */,\n\t\t\t\t42B9833722986A19008AE4FF /* Assets.xcassets */,\n\t\t\t\t42B9833922986A19008AE4FF /* LaunchScreen.storyboard */,\n\t\t\t\t42B9833C22986A19008AE4FF /* Info.plist */,\n\t\t\t\t42170C9122986F6500B22418 /* AutoMLVision.swift */,\n\t\t\t\t42825ACD22987089003A4469 /* ModelManagement.swift */,\n\t\t\t\t4264664322A862B200B5B7B5 /* ImagePreparation.swift */,\n\t\t\t);\n\t\t\tpath = \"swift-snippets\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t42B9834522986AC7008AE4FF /* objc-snippets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t42B9834622986AC7008AE4FF /* AppDelegate.h */,\n\t\t\t\t42B9834722986AC7008AE4FF /* AppDelegate.m */,\n\t\t\t\t42B9834922986AC7008AE4FF /* ViewController.h */,\n\t\t\t\t42B9834A22986AC7008AE4FF /* ViewController.m */,\n\t\t\t\t42B9834C22986AC7008AE4FF /* Main.storyboard */,\n\t\t\t\t42B9834F22986AC8008AE4FF /* Assets.xcassets */,\n\t\t\t\t42B9835122986AC8008AE4FF /* LaunchScreen.storyboard */,\n\t\t\t\t42B9835422986AC8008AE4FF /* Info.plist */,\n\t\t\t\t42B9835522986AC8008AE4FF /* main.m */,\n\t\t\t\t42825ACF22987134003A4469 /* AutoMLVision.m */,\n\t\t\t\t42B043EA229DAB0E00ABAB63 /* ModelManagement.m */,\n\t\t\t\t4264664522A865C500B5B7B5 /* ImagePreparation.m */,\n\t\t\t);\n\t\t\tpath = \"objc-snippets\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t56392CAB235A4ABC2AA4D2CD /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4873791D661430B0B0FB66B0 /* Pods_objc_snippets.framework */,\n\t\t\t\tE72B4E6FF6BEA59CA6F1FF8D /* Pods_swift_snippets.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC8A899ADE5B89620197E0F35 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB9A153CB3E937915C45D800B /* Pods-objc-snippets.debug.xcconfig */,\n\t\t\t\t3C5BD28ADB5263B9BE70FDF1 /* Pods-objc-snippets.release.xcconfig */,\n\t\t\t\t5480D0FE786A5C17362D8A56 /* Pods-swift-snippets.debug.xcconfig */,\n\t\t\t\t0114DD6801AD76446B4062A7 /* Pods-swift-snippets.release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t42B9832C22986A18008AE4FF /* swift-snippets */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 42B9833D22986A19008AE4FF /* Build configuration list for PBXNativeTarget \"swift-snippets\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tDA84B68AAC84D6607087955D /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t42B9832922986A18008AE4FF /* Sources */,\n\t\t\t\t42B9832A22986A18008AE4FF /* Frameworks */,\n\t\t\t\t42B9832B22986A18008AE4FF /* Resources */,\n\t\t\t\t396F2C4305BAC90FCDDDF44D /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"swift-snippets\";\n\t\t\tproductName = \"swift-snippets\";\n\t\t\tproductReference = 42B9832D22986A18008AE4FF /* swift-snippets.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t42B9834322986AC7008AE4FF /* objc-snippets */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 42B9835722986AC8008AE4FF /* Build configuration list for PBXNativeTarget \"objc-snippets\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4773E1E2AEA26A38AC237415 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t42B9834022986AC7008AE4FF /* Sources */,\n\t\t\t\t42B9834122986AC7008AE4FF /* Frameworks */,\n\t\t\t\t42B9834222986AC7008AE4FF /* Resources */,\n\t\t\t\t60E04FC7063814BE1BB56824 /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"objc-snippets\";\n\t\t\tproductName = \"objc-snippets\";\n\t\t\tproductReference = 42B9834422986AC7008AE4FF /* objc-snippets.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t42B98323229869E0008AE4FF /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1010;\n\t\t\t\tLastUpgradeCheck = 1010;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t42B9832C22986A18008AE4FF = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t};\n\t\t\t\t\t42B9834322986AC7008AE4FF = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 42B98326229869E0008AE4FF /* Build configuration list for PBXProject \"mlkit-snippets\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 42B98322229869E0008AE4FF;\n\t\t\tproductRefGroup = 42B9832E22986A18008AE4FF /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t42B9832C22986A18008AE4FF /* swift-snippets */,\n\t\t\t\t42B9834322986AC7008AE4FF /* objc-snippets */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t42B9832B22986A18008AE4FF /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t42B9833B22986A19008AE4FF /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t42B9833822986A19008AE4FF /* Assets.xcassets in Resources */,\n\t\t\t\t42B9833622986A18008AE4FF /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t42B9834222986AC7008AE4FF /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t42B9835322986AC8008AE4FF /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t42B9835022986AC8008AE4FF /* Assets.xcassets in Resources */,\n\t\t\t\t42B9834E22986AC7008AE4FF /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t396F2C4305BAC90FCDDDF44D /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-swift-snippets/Pods-swift-snippets-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-swift-snippets/Pods-swift-snippets-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-swift-snippets/Pods-swift-snippets-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t4773E1E2AEA26A38AC237415 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-objc-snippets-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t60E04FC7063814BE1BB56824 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-objc-snippets/Pods-objc-snippets-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-objc-snippets/Pods-objc-snippets-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-objc-snippets/Pods-objc-snippets-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tDA84B68AAC84D6607087955D /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-swift-snippets-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t42B9832922986A18008AE4FF /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t42825ACE22987089003A4469 /* ModelManagement.swift in Sources */,\n\t\t\t\t42170C9222986F6500B22418 /* AutoMLVision.swift in Sources */,\n\t\t\t\t42B9833322986A18008AE4FF /* ViewController.swift in Sources */,\n\t\t\t\t4264664422A862B200B5B7B5 /* ImagePreparation.swift in Sources */,\n\t\t\t\t42B9833122986A18008AE4FF /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t42B9834022986AC7008AE4FF /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t42B043EB229DAB0E00ABAB63 /* ModelManagement.m in Sources */,\n\t\t\t\t4264664622A865C500B5B7B5 /* ImagePreparation.m in Sources */,\n\t\t\t\t42B9834B22986AC7008AE4FF /* ViewController.m in Sources */,\n\t\t\t\t42B9835622986AC8008AE4FF /* main.m in Sources */,\n\t\t\t\t42B9834822986AC7008AE4FF /* AppDelegate.m in Sources */,\n\t\t\t\t42825AD022987134003A4469 /* AutoMLVision.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t42B9833422986A18008AE4FF /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t42B9833522986A18008AE4FF /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t42B9833922986A19008AE4FF /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t42B9833A22986A19008AE4FF /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t42B9834C22986AC7008AE4FF /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t42B9834D22986AC7008AE4FF /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t42B9835122986AC8008AE4FF /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t42B9835222986AC8008AE4FF /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t42B98327229869E0008AE4FF /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t42B98328229869E0008AE4FF /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t42B9833E22986A19008AE4FF /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 5480D0FE786A5C17362D8A56 /* Pods-swift-snippets.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINFOPLIST_FILE = \"swift-snippets/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.swift-snippets\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t42B9833F22986A19008AE4FF /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 0114DD6801AD76446B4062A7 /* Pods-swift-snippets.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINFOPLIST_FILE = \"swift-snippets/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.swift-snippets\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t42B9835822986AC8008AE4FF /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B9A153CB3E937915C45D800B /* Pods-objc-snippets.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINFOPLIST_FILE = \"objc-snippets/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.objc-snippets\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t42B9835922986AC8008AE4FF /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3C5BD28ADB5263B9BE70FDF1 /* Pods-objc-snippets.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINFOPLIST_FILE = \"objc-snippets/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.example.objc-snippets\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t42B98326229869E0008AE4FF /* Build configuration list for PBXProject \"mlkit-snippets\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t42B98327229869E0008AE4FF /* Debug */,\n\t\t\t\t42B98328229869E0008AE4FF /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t42B9833D22986A19008AE4FF /* Build configuration list for PBXNativeTarget \"swift-snippets\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t42B9833E22986A19008AE4FF /* Debug */,\n\t\t\t\t42B9833F22986A19008AE4FF /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t42B9835722986AC8008AE4FF /* Build configuration list for PBXNativeTarget \"objc-snippets\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t42B9835822986AC8008AE4FF /* Debug */,\n\t\t\t\t42B9835922986AC8008AE4FF /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 42B98323229869E0008AE4FF /* Project object */;\n}\n"
  },
  {
    "path": "ios/ios-snippets/mlkit-snippets.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "ios/ios-snippets/mlkit-snippets.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/ios-snippets/mlkit-snippets.xcodeproj/xcuserdata/dfurlong.xcuserdatad/xcschemes/xcschememanagement.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>SchemeUserState</key>\n\t<dict>\n\t\t<key>objc-snippets.xcscheme_^#shared#^_</key>\n\t\t<dict>\n\t\t\t<key>orderHint</key>\n\t\t\t<integer>16</integer>\n\t\t</dict>\n\t\t<key>swift-snippets.xcscheme_^#shared#^_</key>\n\t\t<dict>\n\t\t\t<key>orderHint</key>\n\t\t\t<integer>15</integer>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/ios-snippets/mlkit-snippets.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:mlkit-snippets.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "ios/ios-snippets/mlkit-snippets.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/ios-snippets/mlkit-snippets.xcworkspace/xcuserdata/dfurlong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n   uuid = \"0FB9B27A-640F-43D8-816E-9CDDF50A3618\"\n   type = \"0\"\n   version = \"2.0\">\n</Bucket>\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/AppDelegate.h",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n\n\n@end\n\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/AppDelegate.m",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\n#import \"AppDelegate.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Override point for customization after application launch.\n    return YES;\n}\n\n\n- (void)applicationWillResignActive:(UIApplication *)application {\n    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.\n}\n\n\n- (void)applicationDidEnterBackground:(UIApplication *)application {\n    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n}\n\n\n- (void)applicationWillEnterForeground:(UIApplication *)application {\n    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.\n}\n\n\n- (void)applicationDidBecomeActive:(UIApplication *)application {\n    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n}\n\n\n- (void)applicationWillTerminate:(UIApplication *)application {\n    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n}\n\n\n@end\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/AutoMLVision.m",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <Foundation/Foundation.h>\n@import MLKitImageClassificationAutoML;\n\n@interface AutoMLVision : NSObject\n\n- (void)classifyImage:(MLKVisionImage *)image;\n\n@end\n\n@implementation AutoMLVision\n\n- (void)classifyImage:(MLKVisionImage *)image {\n  // [START get_classifier]\n  NSBundle *bundle = [NSBundle bundleForClass:[self class]];\n  NSString *manifestPath = [bundle pathForResource:@\"manifest\" ofType:@\"json\"];\n  MLKAutoMLLocalModel *localModel = [[MLKAutoMLLocalModel alloc] initWithManifestPath:manifestPath];\n  MLKAutoMLImageClassifierOptions *classifierOptions =\n      [[MLKAutoMLImageClassifierOptions alloc]\n          initWithLocalModel:localModel];\n  classifierOptions.confidenceThreshold = 0;  // Evaluate your model in the Firebase console\n                                           // to determine an appropriate value.\n  MLKImageClassifier *classifier =\n      [MLKImageClassifier autoMLImageClassifierWithOptions:classifierOptions];\n  // [END get_classifier]\n\n  // [START process_image]\n\n  [classifier\n      processImage:image\n   completion:^(NSArray<MLKImageClassification *> *_Nullable classifications, NSError *_Nullable error) {\n    if (error != nil || classifications == nil) {\n      return;\n    }\n    // Task succeeded.\n    // [START_EXCLUDE]\n    // [START get_classfications]\n    for (MLKImageClassification *classification in classifications) {\n      NSString *classificationText = classification.text;\n      float confidence = classification.confidence;\n    }\n    // [END get_classfications]\n    // [END_EXCLUDE]\n  }];\n}\n\n@end\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/ImagePreparation.m",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <Foundation/Foundation.h>\n@import AVFoundation;\n@import MLKitVision;\n\n@interface ImagePreparation : NSObject\n\n- (MLKVisionImage *)createImageWithUIImage:(UIImage *)uiImage;\n- (MLKVisionImageOrientation)\n    imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation\n                           cameraPosition:(AVCaptureDevicePosition)cameraPosition;\n- (MLKVisionImage *)createImageWithBuffer:(CMSampleBufferRef)sampleBuffer;\n\n@end\n\n@implementation ImagePreparation\n\n- (MLKVisionImage *)createImageWithUIImage:(UIImage *)uiImage {\n  // [START create_image_with_uiimage]\n  MLKVisionImage *image = [[MLKVisionImage alloc] initWithImage:uiImage];\n  // [END create_image_with_uiimage]\n  return image;\n}\n\n// [START image_orientation_from_device_orientation]\n- (MLKVisionImageOrientation)\n    imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation\n                           cameraPosition:(AVCaptureDevicePosition)cameraPosition {\n  switch (deviceOrientation) {\n    case UIDeviceOrientationPortrait:\n      if (cameraPosition == AVCaptureDevicePositionFront) {\n        return MLKVisionImageOrientationLeftTop;\n      } else {\n        return MLKVisionImageOrientationRightTop;\n      }\n    case UIDeviceOrientationLandscapeLeft:\n      if (cameraPosition == AVCaptureDevicePositionFront) {\n        return MLKVisionImageOrientationBottomLeft;\n      } else {\n        return MLKVisionImageOrientationTopLeft;\n      }\n    case UIDeviceOrientationPortraitUpsideDown:\n      if (cameraPosition == AVCaptureDevicePositionFront) {\n        return MLKVisionImageOrientationRightBottom;\n      } else {\n        return MLKVisionImageOrientationLeftBottom;\n      }\n    case UIDeviceOrientationLandscapeRight:\n      if (cameraPosition == AVCaptureDevicePositionFront) {\n        return MLKVisionImageOrientationTopRight;\n      } else {\n        return MLKVisionImageOrientationBottomRight;\n      }\n    default:\n      return MLKVisionImageOrientationTopLeft;\n  }\n}\n// [END image_orientation_from_device_orientation]\n\n- (MLKVisionImage *)createImageWithBuffer:(CMSampleBufferRef)sampleBuffer {\n  // [START create_image_metadata]\n  MLKVisionImageMetadata *metadata = [[MLKVisionImageMetadata alloc] init];\n  AVCaptureDevicePosition cameraPosition =\n      AVCaptureDevicePositionBack;  // Set to the capture device you used.\n  metadata.orientation =\n      [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation\n                                   cameraPosition:cameraPosition];\n  // [END create_image_metadata]\n\n  // [START create_image_with_buffer]\n  MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];\n  image.metadata = metadata;\n  // [END create_image_with_buffer]\n\n  return image;\n}\n\n@end\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/ModelManagement.m",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <Foundation/Foundation.h>\n@import MLKitImageClassificationAutoML;\n@import MLKitCommon;\n\n@interface ModelManagementSnippets : NSObject\n\n- (void)setUpRemoteModel;\n- (void)setUpModelDownloadNotifications;\n- (void)setUpLocalModel;\n\n@end\n\n@implementation ModelManagementSnippets\n\n- (void)setUpRemoteModel {\n  // [START setup_remote_model]\n  MLKModelDownloadConditions *downloadConditions =\n      [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES\n                                           allowsBackgroundDownloading:YES];\n  // Instantiate a concrete subclass of MLKRemoteModel.\n  MLKRemoteModel *remoteModel =\n      [[MLKAutoMLRemoteModel alloc] initWithName:@\"your_remote_model\"];  // The name you assigned in the console.\n  // [END setup_remote_model]\n\n  // [START start_download]\n  NSProgress *downloadProgress = [[MLKModelManager modelManager] downloadModel:remoteModel\n                                                                    conditions:downloadConditions];\n\n  // ...\n\n  if (downloadProgress.isFinished) {\n    // The model is available on the device\n  }\n  // [END start_download]\n}\n\n- (void)setUpModelDownloadNotifications {\n  // [START setup_notifications]\n  __weak typeof(self) weakSelf = self;\n\n  [NSNotificationCenter.defaultCenter\n      addObserverForName:MLKModelDownloadDidSucceedNotification\n                  object:nil\n                   queue:nil\n              usingBlock:^(NSNotification *_Nonnull note) {\n                if (weakSelf == nil | note.userInfo == nil) {\n                  return;\n                }\n                __strong typeof(self) strongSelf = weakSelf;\n\n                MLKRemoteModel *model = note.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];\n                if ([model.name isEqualToString:@\"your_remote_model\"]) {\n                  // The model was downloaded and is available on the device\n                }\n              }];\n\n  [NSNotificationCenter.defaultCenter\n      addObserverForName:MLKModelDownloadDidFailNotification\n                  object:nil\n                   queue:nil\n              usingBlock:^(NSNotification *_Nonnull note) {\n                if (weakSelf == nil | note.userInfo == nil) {\n                  return;\n                }\n                __strong typeof(self) strongSelf = weakSelf;\n\n                NSError *error = note.userInfo[MLKModelDownloadUserInfoKeyError];\n              }];\n  // [END setup_notifications]\n}\n\n- (void)setUpLocalModel {\n  // [START setup_local_model]\n  NSString *manifestPath = [NSBundle.mainBundle pathForResource:@\"manifest\"\n                                                         ofType:@\"json\"\n                                                    inDirectory:@\"my_model\"];\n  // Instantiate a concrete subclass of MLKLocalModel.\n  MLKLocalModel *localModel = [[MLKAutoMLLocalModel alloc]\n                               initWithManifestPath:manifestPath];\n  // [END setup_local_model]\n}\n\n@end\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/ViewController.h",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/ViewController.m",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\n#import \"ViewController.h\"\n\n@interface ViewController ()\n\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view, typically from a nib.\n}\n\n\n@end\n"
  },
  {
    "path": "ios/ios-snippets/objc-snippets/main.m",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n    }\n}\n"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/AppDelegate.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n    }\n\n\n}\n\n"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/AutoMLVision.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport MLKitVision\nimport MLKitImageClassificationAutoML\n\nclass AutoMLVision {\n    func label(image: VisionImage) {\n        // [START get_labeler]\n        let bundle = Bundle(for: type(of: self))\n        guard let manifestPath = bundle.path(forResource: \"manifest\", ofType: \"json\") else { return }\n        let localModel = AutoMLLocalModel(manifestPath: manifestPath)\n        let labelerOptions = AutoMLImageClassifierOptions(localModel: localModel)\n        labelerOptions.confidenceThreshold = 0 // Evaluate your model in the Firebase console\n                                               // to determine an appropriate value.\n        let labeler = ImageClassifier.imageClassifier(options: labelerOptions)\n        // [END get_labeler]\n\n        // [START process_image]\n        labeler.process(image) { labels, error in\n            guard error == nil, let labels = labels else { return }\n\n            // Task succeeded.\n            // [START_EXCLUDE]\n            // [START get_labels]\n            for label in labels {\n                let labelText = label.text\n                let confidence = label.confidence\n            }\n            // [END get_labels]\n            // [END_EXCLUDE]\n        }\n        // [END process_image]\n    }\n}\n"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/ImagePreparation.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\nimport Foundation\nimport AVFoundation\nimport MLKitVision\n\nclass ImagePreparation {\n    func createImage(uiImage: UIImage) -> VisionImage {\n        // [START create_image_with_uiimage]\n        let image = VisionImage(image: uiImage)\n        // [END create_image_with_uiimage]\n        return image\n    }\n\n    // [START image_orientation_from_device_orientation]\n    func imageOrientation(\n        deviceOrientation: UIDeviceOrientation,\n        cameraPosition: AVCaptureDevice.Position\n        ) -> VisionImageOrientation {\n        switch deviceOrientation {\n        case .portrait:\n            return cameraPosition == .front ? .leftTop : .rightTop\n        case .landscapeLeft:\n            return cameraPosition == .front ? .bottomLeft : .topLeft\n        case .portraitUpsideDown:\n            return cameraPosition == .front ? .rightBottom : .leftBottom\n        case .landscapeRight:\n            return cameraPosition == .front ? .topRight : .bottomRight\n        case .faceDown, .faceUp, .unknown:\n            return .leftTop\n        }\n    }\n    // [END image_orientation_from_device_orientation]\n\n    func createImage(sampleBuffer: CMSampleBuffer) -> VisionImage {\n        // [START create_image_metadata]\n        let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.\n        let metadata = VisionImageMetadata()\n        metadata.orientation = imageOrientation(\n            deviceOrientation: UIDevice.current.orientation,\n            cameraPosition: cameraPosition\n        )\n        // [END create_image_metadata]\n\n        // [START create_image_with_buffer]\n        let image = VisionImage(buffer: sampleBuffer)\n        image.metadata = metadata\n        // [END create_image_with_buffer]\n\n        return image\n    }\n}\n"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/ModelManagement.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport MLKitCommon\nimport MLKitImageClassificationAutoML\n\nclass ModelManagementSnippets {\n    func setupRemoteModel() {\n        // [START setup_remote_model]\n        let downloadConditions = ModelDownloadConditions(allowsCellularAccess: true,\n                                                         allowsBackgroundDownloading: true)\n        // Instantiate a concrete subclass of RemoteModel.\n        let remoteModel = AutoMLRemoteModel(name: \"your_remote_model\" // The name you assigned in the console.\n        )\n        // [END setup_remote_model]\n\n        // [START start_download]\n        let downloadProgress = ModelManager.modelManager().download(remoteModel, conditions: downloadConditions)\n\n        // ...\n\n        if downloadProgress.isFinished {\n            // The model is available on the device\n        }\n        // [END start_download]\n    }\n\n    func setupModelDownloadNotifications() {\n        // [START setup_notifications]\n        NotificationCenter.default.addObserver(\n            forName: .mlkitModelDownloadDidSucceed,\n            object: nil,\n            queue: nil\n        ) { [weak self] notification in\n            guard let strongSelf = self,\n                let userInfo = notification.userInfo,\n                let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]\n                    as? RemoteModel,\n                model.name == \"your_remote_model\"\n                else { return }\n            // The model was downloaded and is available on the device\n        }\n\n        NotificationCenter.default.addObserver(\n            forName: .mlkitModelDownloadDidFail,\n            object: nil,\n            queue: nil\n        ) { [weak self] notification in\n            guard let strongSelf = self,\n                let userInfo = notification.userInfo,\n                let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]\n                    as? RemoteModel\n                else { return }\n            let error = userInfo[ModelDownloadUserInfoKey.error.rawValue]\n            // ...\n        }\n        // [END setup_notifications]\n    }\n\n    func setupLocalModel() {\n        // [START setup_local_model]\n        guard let manifestPath = Bundle.main.path(forResource: \"manifest\",\n                                                  ofType: \"json\",\n                                                  inDirectory: \"my_model\") else { return }\n        // Instantiate a concrete subclass of LocalModel.\n        let localModel = AutoMLLocalModel(manifestPath: manifestPath)\n        // [END setup_local_model]\n    }\n}\n"
  },
  {
    "path": "ios/ios-snippets/swift-snippets/ViewController.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n\nimport UIKit\n\nclass ViewController: UIViewController {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        // Do any additional setup after loading the view, typically from a nib.\n    }\n\n\n}\n\n"
  },
  {
    "path": "ios/quickstarts/automl/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/Assets.xcassets/cloud_download.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"cloud_download_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"cloud_download_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/automl/Assets.xcassets/delete.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_delete_black_36pt_1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_delete_black_36pt_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_delete_black_36pt_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/automl/Assets.xcassets/photo_camera.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"photo_camera_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"photo_camera_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/automl/Assets.xcassets/photo_library.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"photo_library_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"photo_library_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/automl/Assets.xcassets/switch_camera.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"switch_camera_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"switch_camera_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/Assets.xcassets/video_camera.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"video_camera_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"video_camera_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample/AppDelegate.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\nimport FirebaseCore\n\n@UIApplicationMain\nfinal class AppDelegate: UIResponder, UIApplicationDelegate {\n\n  /// The main window of the app.\n  var window: UIWindow?\n\n  func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil\n  ) -> Bool {\n    FirebaseApp.configure()\n    return true\n  }\n}\n\n// MARK: - Extensions\n\n#if !swift(>=4.2)\n  extension UIApplication {\n    typealias LaunchOptionsKey = UIApplicationLaunchOptionsKey\n  }\n#endif  // !swift(>=4.2)\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"16097.2\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"0Q6-lG-sCk\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"16087\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Navigation Controller-->\n        <scene sceneID=\"rAH-gT-x68\">\n            <objects>\n                <navigationController id=\"0Q6-lG-sCk\" sceneMemberID=\"viewController\">\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"JoS-YE-9OV\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </navigationBar>\n                    <connections>\n                        <segue destination=\"BYZ-38-t0r\" kind=\"relationship\" relationship=\"rootViewController\" id=\"fdA-VU-1vi\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"6gn-Xt-3Nz\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-607\" y=\"134\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController storyboardIdentifier=\"viewController\" id=\"BYZ-38-t0r\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"LHw-b6-B2a\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"Ydg-C1-MLG\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <pickerView contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Xs4-mo-RjW\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"488\" width=\"375\" height=\"180\"/>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"180\" id=\"f3t-1V-izd\"/>\n                                </constraints>\n                                <edgeInsets key=\"layoutMargins\" top=\"8\" left=\"8\" bottom=\"8\" right=\"8\"/>\n                            </pickerView>\n                            <toolbar opaque=\"NO\" clearsContextBeforeDrawing=\"NO\" contentMode=\"center\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"POq-8j-gOJ\" userLabel=\"Top Toolbar\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"56\" width=\"375\" height=\"44\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"44\" id=\"it0-iL-OwQ\"/>\n                                </constraints>\n                                <items>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"Ntc-CQ-liM\"/>\n                                    <barButtonItem image=\"photo_library\" id=\"cQ8-BV-rH6\" userLabel=\"Photo Library Button\">\n                                        <connections>\n                                            <action selector=\"openPhotoLibrary:\" destination=\"BYZ-38-t0r\" id=\"1Jr-zi-I6V\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"eph-cT-Zvt\"/>\n                                    <barButtonItem image=\"photo_camera\" id=\"jD4-E9-bbj\" userLabel=\"Photo Camera Button\">\n                                        <connections>\n                                            <action selector=\"openCamera:\" destination=\"BYZ-38-t0r\" id=\"3cs-Py-gWB\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"v2M-Hr-v21\"/>\n                                    <barButtonItem enabled=\"NO\" image=\"video_camera\" id=\"M1D-Qg-lKI\" userLabel=\"Video Camera Button\">\n                                        <connections>\n                                            <segue destination=\"YXl-5B-mBF\" kind=\"show\" identifier=\"showCameraViewController\" id=\"M0h-0G-c32\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"aEw-JJ-oRD\"/>\n                                    <barButtonItem image=\"cloud_download\" style=\"plain\" id=\"dpl-CD-O71\" userLabel=\"Download Model Button\">\n                                        <connections>\n                                            <action selector=\"downloadOrDeleteModel:\" destination=\"BYZ-38-t0r\" id=\"Snl-c4-XyJ\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"1ha-dt-VEM\"/>\n                                </items>\n                            </toolbar>\n                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cCp-tA-gDT\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"106\" width=\"375\" height=\"344\"/>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                            </imageView>\n                            <progressView hidden=\"YES\" opaque=\"NO\" contentMode=\"scaleToFill\" verticalHuggingPriority=\"750\" progress=\"0.5\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xaG-Fk-Kew\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"100\" width=\"375\" height=\"6\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"6\" id=\"ENY-EP-7u6\"/>\n                                </constraints>\n                            </progressView>\n                            <toolbar opaque=\"NO\" clearsContextBeforeDrawing=\"NO\" contentMode=\"center\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yof-fW-vlO\" userLabel=\"Bottom Toolbar\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"450\" width=\"375\" height=\"44\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"44\" id=\"74h-Pf-w4T\"/>\n                                </constraints>\n                                <items>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"RLv-lI-aQm\"/>\n                                    <barButtonItem title=\"Detect\" id=\"Dwb-uQ-3dE\" userLabel=\"Detect Button\">\n                                        <connections>\n                                            <action selector=\"detect:\" destination=\"BYZ-38-t0r\" id=\"oTX-fI-9ty\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem title=\"Next image\" id=\"Glk-GE-iCa\">\n                                        <connections>\n                                            <action selector=\"changeImage:\" destination=\"BYZ-38-t0r\" id=\"wi9-lu-Oqs\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"cR0-7i-Xm8\"/>\n                                </items>\n                            </toolbar>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"xaG-Fk-Kew\" firstAttribute=\"width\" secondItem=\"POq-8j-gOJ\" secondAttribute=\"width\" id=\"0A9-hi-nSv\"/>\n                            <constraint firstItem=\"cCp-tA-gDT\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"45c-Cz-uBY\"/>\n                            <constraint firstItem=\"POq-8j-gOJ\" firstAttribute=\"top\" secondItem=\"LHw-b6-B2a\" secondAttribute=\"bottom\" constant=\"12\" id=\"7wp-P3-gcC\"/>\n                            <constraint firstItem=\"Xs4-mo-RjW\" firstAttribute=\"top\" secondItem=\"yof-fW-vlO\" secondAttribute=\"bottom\" constant=\"-6\" id=\"Eqz-89-OCh\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"POq-8j-gOJ\" secondAttribute=\"trailing\" id=\"I0X-8i-nPT\"/>\n                            <constraint firstItem=\"xaG-Fk-Kew\" firstAttribute=\"leading\" secondItem=\"POq-8j-gOJ\" secondAttribute=\"leading\" id=\"J0C-6D-Ifi\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"cCp-tA-gDT\" secondAttribute=\"trailing\" id=\"UKP-ZW-thL\"/>\n                            <constraint firstItem=\"yof-fW-vlO\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"Wki-fU-blU\"/>\n                            <constraint firstItem=\"POq-8j-gOJ\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"cho-7Z-rGg\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"yof-fW-vlO\" secondAttribute=\"trailing\" id=\"etE-tG-0CW\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"Xs4-mo-RjW\" secondAttribute=\"trailing\" id=\"gvn-CW-6Xx\"/>\n                            <constraint firstItem=\"xaG-Fk-Kew\" firstAttribute=\"top\" secondItem=\"POq-8j-gOJ\" secondAttribute=\"bottom\" id=\"hSN-NL-d34\"/>\n                            <constraint firstItem=\"yof-fW-vlO\" firstAttribute=\"top\" secondItem=\"cCp-tA-gDT\" secondAttribute=\"bottom\" id=\"oQg-Ks-4Jj\"/>\n                            <constraint firstItem=\"Ydg-C1-MLG\" firstAttribute=\"top\" secondItem=\"Xs4-mo-RjW\" secondAttribute=\"bottom\" constant=\"-1\" id=\"rWN-Im-hnc\"/>\n                            <constraint firstItem=\"Xs4-mo-RjW\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"uNU-KO-ASb\"/>\n                            <constraint firstItem=\"cCp-tA-gDT\" firstAttribute=\"top\" secondItem=\"xaG-Fk-Kew\" secondAttribute=\"bottom\" id=\"v4h-9Q-PbG\"/>\n                        </constraints>\n                    </view>\n                    <navigationItem key=\"navigationItem\" id=\"xYg-VP-pps\">\n                        <barButtonItem key=\"backBarButtonItem\" title=\" \" id=\"QLp-QO-2R9\"/>\n                    </navigationItem>\n                    <connections>\n                        <outlet property=\"detectButton\" destination=\"Dwb-uQ-3dE\" id=\"8Hn-BT-3m1\"/>\n                        <outlet property=\"detectorPicker\" destination=\"Xs4-mo-RjW\" id=\"kFH-5K-Mcc\"/>\n                        <outlet property=\"downloadOrDeleteModelButton\" destination=\"dpl-CD-O71\" id=\"JKy-Vj-6MP\"/>\n                        <outlet property=\"downloadProgressView\" destination=\"xaG-Fk-Kew\" id=\"h0c-hg-58T\"/>\n                        <outlet property=\"imageView\" destination=\"cCp-tA-gDT\" id=\"FIt-va-neE\"/>\n                        <outlet property=\"photoCameraButton\" destination=\"jD4-E9-bbj\" id=\"cf0-4Q-UL8\"/>\n                        <outlet property=\"videoCameraButton\" destination=\"M1D-Qg-lKI\" id=\"3Cr-4e-JCG\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"125.59999999999999\" y=\"133.5832083958021\"/>\n        </scene>\n        <!--Camera View Controller-->\n        <scene sceneID=\"kPU-gK-lh6\">\n            <objects>\n                <viewController id=\"YXl-5B-mBF\" customClass=\"CameraViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"qO2-JB-Jc4\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"7NG-lt-hPa\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"bWY-Sx-TCF\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vwd-Qp-BMC\" userLabel=\"Camera View\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"50\" width=\"375\" height=\"617\"/>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                            </view>\n                            <progressView hidden=\"YES\" opaque=\"NO\" contentMode=\"scaleToFill\" verticalHuggingPriority=\"750\" progress=\"0.5\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mn2-dQ-YNu\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"44\" width=\"375\" height=\"6\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"6\" id=\"xIK-Vd-Y6R\"/>\n                                </constraints>\n                            </progressView>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"mn2-dQ-YNu\" secondAttribute=\"trailing\" id=\"EB2-tA-kM2\"/>\n                            <constraint firstItem=\"mn2-dQ-YNu\" firstAttribute=\"top\" secondItem=\"qO2-JB-Jc4\" secondAttribute=\"bottom\" id=\"Ldx-Kl-J3W\"/>\n                            <constraint firstItem=\"Vwd-Qp-BMC\" firstAttribute=\"leading\" secondItem=\"bWY-Sx-TCF\" secondAttribute=\"leading\" id=\"bTr-O6-WSG\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"Vwd-Qp-BMC\" secondAttribute=\"trailing\" id=\"cN6-F5-qVY\"/>\n                            <constraint firstItem=\"Vwd-Qp-BMC\" firstAttribute=\"top\" secondItem=\"mn2-dQ-YNu\" secondAttribute=\"bottom\" id=\"fhZ-Tc-nRJ\"/>\n                            <constraint firstItem=\"Vwd-Qp-BMC\" firstAttribute=\"bottom\" secondItem=\"7NG-lt-hPa\" secondAttribute=\"top\" id=\"ja0-Ki-fxw\"/>\n                            <constraint firstItem=\"mn2-dQ-YNu\" firstAttribute=\"leading\" secondItem=\"bWY-Sx-TCF\" secondAttribute=\"leading\" id=\"qK3-Jn-xfl\"/>\n                        </constraints>\n                    </view>\n                    <navigationItem key=\"navigationItem\" id=\"8dJ-Hr-2St\">\n                        <nil key=\"title\"/>\n                        <rightBarButtonItems>\n                            <barButtonItem image=\"switch_camera\" id=\"kXj-bT-GY0\" userLabel=\"Switch Camera Button\">\n                                <connections>\n                                    <action selector=\"switchCamera:\" destination=\"YXl-5B-mBF\" id=\"sFo-ar-LIv\"/>\n                                </connections>\n                            </barButtonItem>\n                            <barButtonItem title=\"Detectors\" id=\"gQ9-nz-4p5\" userLabel=\"Detectors Button\">\n                                <connections>\n                                    <action selector=\"selectDetector:\" destination=\"YXl-5B-mBF\" id=\"KmV-U7-Qxb\"/>\n                                </connections>\n                            </barButtonItem>\n                        </rightBarButtonItems>\n                    </navigationItem>\n                    <connections>\n                        <outlet property=\"cameraView\" destination=\"Vwd-Qp-BMC\" id=\"yRq-e8-30h\"/>\n                        <outlet property=\"downloadProgressView\" destination=\"mn2-dQ-YNu\" id=\"lNZ-Xz-0FT\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Tub-Fx-HUo\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"853.60000000000002\" y=\"133.5832083958021\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"cloud_download\" width=\"16\" height=\"16\"/>\n        <image name=\"photo_camera\" width=\"72\" height=\"72\"/>\n        <image name=\"photo_library\" width=\"72\" height=\"72\"/>\n        <image name=\"switch_camera\" width=\"72\" height=\"72\"/>\n        <image name=\"video_camera\" width=\"72\" height=\"72\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample/CameraViewController.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport AVFoundation\nimport CoreVideo\nimport MLKit\nimport UIKit\n\n@objc(CameraViewController)\nclass CameraViewController: UIViewController {\n  private let detectors: [DetectorType] = [\n    .detectorImageLabels,\n    .detectorObjectsSingleNoClassifier,\n    .detectorObjectsSingleWithClassifier,\n    .detectorObjectsMultipleNoClassifier,\n    .detectorObjectsMultipleWithClassifier,\n  ]\n\n  private var currentDetector: DetectorType = .detectorImageLabels\n  private var isUsingFrontCamera = true\n  private var previewLayer: AVCaptureVideoPreviewLayer!\n  private lazy var captureSession = AVCaptureSession()\n  private lazy var sessionQueue = DispatchQueue(label: Constants.sessionQueueLabel)\n  private var lastFrame: CMSampleBuffer?\n  private lazy var modelManager = ModelManager.modelManager()\n  @IBOutlet var downloadProgressView: UIProgressView!\n\n  private lazy var previewOverlayView: UIImageView = {\n    precondition(isViewLoaded)\n    let previewOverlayView = UIImageView(frame: .zero)\n    previewOverlayView.contentMode = UIView.ContentMode.scaleAspectFill\n    previewOverlayView.translatesAutoresizingMaskIntoConstraints = false\n    return previewOverlayView\n  }()\n\n  private lazy var annotationOverlayView: UIView = {\n    precondition(isViewLoaded)\n    let annotationOverlayView = UIView(frame: .zero)\n    annotationOverlayView.translatesAutoresizingMaskIntoConstraints = false\n    return annotationOverlayView\n  }()\n\n  // MARK: - IBOutlets\n\n  @IBOutlet private weak var cameraView: UIView!\n\n  // MARK: - UIViewController\n\n  override func viewDidLoad() {\n    super.viewDidLoad()\n\n    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)\n    setUpPreviewOverlayView()\n    setUpAnnotationOverlayView()\n    setUpCaptureSessionOutput()\n    setUpCaptureSessionInput()\n  }\n\n  override func viewDidAppear(_ animated: Bool) {\n    super.viewDidAppear(animated)\n\n    NotificationCenter.default.addObserver(\n      self,\n      selector: #selector(remoteModelDownloadDidSucceed(_:)),\n      name: .mlkitModelDownloadDidSucceed,\n      object: nil\n    )\n    NotificationCenter.default.addObserver(\n      self,\n      selector: #selector(remoteModelDownloadDidFail(_:)),\n      name: .mlkitModelDownloadDidFail,\n      object: nil\n    )\n    startSession()\n  }\n\n  override func viewDidDisappear(_ animated: Bool) {\n    super.viewDidDisappear(animated)\n\n    // We wouldn't have needed to remove the observers if iOS 9.0+ had cleaned up the observer \"the\n    // next time it would have posted to it\" as documented here:\n    // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver\n    NotificationCenter.default.removeObserver(\n      self,\n      name: .mlkitModelDownloadDidSucceed,\n      object: nil)\n    NotificationCenter.default.removeObserver(self, name: .mlkitModelDownloadDidFail, object: nil)\n    stopSession()\n  }\n\n  override func viewDidLayoutSubviews() {\n    super.viewDidLayoutSubviews()\n\n    previewLayer.frame = cameraView.frame\n  }\n\n  // MARK: - IBActions\n\n  @IBAction func switchCamera(_ sender: Any) {\n    isUsingFrontCamera = !isUsingFrontCamera\n    removeDetectionAnnotations()\n    setUpCaptureSessionInput()\n  }\n\n  @IBAction func selectDetector(_ sender: Any) {\n    presentDetectorsAlertController()\n  }\n\n  // MARK: - AutoML Detections\n\n  func detectObjects(\n    in visionImage: VisionImage,\n    width: CGFloat,\n    height: CGFloat,\n    shouldEnableClassification: Bool,\n    shouldEnableMultipleObjects: Bool\n  ) {\n    requestAutoMLRemoteModelIfNeeded()\n\n    let remoteModel = self.remoteModel()\n    var options: CustomObjectDetectorOptions!\n    if modelManager.isModelDownloaded(remoteModel) {\n      print(\"Use AutoML remote model.\")\n      options = CustomObjectDetectorOptions(remoteModel: remoteModel as! CustomRemoteModel)\n    } else {\n      print(\"Use AutoML local model.\")\n      guard\n        let localModelFilePath = Bundle.main.path(\n          forResource: Constants.localModelManifestFileName,\n          ofType: Constants.autoMLManifestFileType\n        )\n      else {\n        print(\n          \"Failed to find AutoML local model manifest file: \\(Constants.localModelManifestFileName)\"\n        )\n        return\n      }\n      guard let localModel = LocalModel(manifestPath: localModelFilePath) else { return }\n      options = CustomObjectDetectorOptions(localModel: localModel)\n    }\n    options.shouldEnableClassification = shouldEnableClassification\n    options.shouldEnableMultipleObjects = shouldEnableMultipleObjects\n    // Due to the UI space, We will only display one label per detected object.\n    options.maxPerObjectLabelCount = 1\n    options.detectorMode = .stream\n\n    let objectDetector = ObjectDetector.objectDetector(options: options)\n    var objects: [Object]\n    do {\n      objects = try objectDetector.results(in: visionImage)\n    } catch let error {\n      print(\"Failed to detect objects with error: \\(error.localizedDescription).\")\n      return\n    }\n    weak var weakSelf = self\n    DispatchQueue.main.sync {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.updatePreviewOverlayView()\n      strongSelf.removeDetectionAnnotations()\n    }\n    guard !objects.isEmpty else {\n      print(\"Object detector returned no results.\")\n      return\n    }\n\n    DispatchQueue.main.sync {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      for object in objects {\n        let normalizedRect = CGRect(\n          x: object.frame.origin.x / width,\n          y: object.frame.origin.y / height,\n          width: object.frame.size.width / width,\n          height: object.frame.size.height / height\n        )\n        let standardizedRect = strongSelf.previewLayer.layerRectConverted(\n          fromMetadataOutputRect: normalizedRect\n        ).standardized\n        UIUtilities.addRectangle(\n          standardizedRect,\n          to: strongSelf.annotationOverlayView,\n          color: UIColor.green\n        )\n        let label = UILabel(frame: standardizedRect)\n        var description = \"\"\n        if let trackingID = object.trackingID {\n          description += \"Object ID: \" + trackingID.stringValue + \"\\n\"\n        }\n        description += object.labels.enumerated().map { (index, label) in\n          \"Label \\(index): \\(label.text), \\(label.confidence), \\(label.index)\"\n        }.joined(separator: \"\\n\")\n\n        label.text = description\n        label.numberOfLines = 0\n        label.adjustsFontSizeToFitWidth = true\n        strongSelf.annotationOverlayView.addSubview(label)\n      }\n    }\n  }\n\n  private func detectImageLabels(\n    in visionImage: VisionImage,\n    width: CGFloat,\n    height: CGFloat\n  ) {\n    requestAutoMLRemoteModelIfNeeded()\n\n    let remoteModel = self.remoteModel()\n    guard\n      let localModelFilePath = Bundle.main.path(\n        forResource: Constants.localModelManifestFileName,\n        ofType: Constants.autoMLManifestFileType\n      )\n    else {\n      print(\"Failed to find AutoML local model manifest file.\")\n      return\n    }\n    let isModelDownloaded = modelManager.isModelDownloaded(remoteModel)\n    var options: CommonImageLabelerOptions!\n    guard let localModel = LocalModel(manifestPath: localModelFilePath) else { return }\n    options =\n      isModelDownloaded\n      ? CustomImageLabelerOptions(remoteModel: remoteModel as! CustomRemoteModel)\n      : CustomImageLabelerOptions(localModel: localModel)\n    print(\"Use AutoML \\(isModelDownloaded ? \"remote\" : \"local\") model.\")\n    options.confidenceThreshold = NSNumber(value: Constants.labelConfidenceThreshold)\n    let autoMLImageLabeler = ImageLabeler.imageLabeler(options: options)\n    print(\"labeler: \\(autoMLImageLabeler)\\n\")\n\n    let group = DispatchGroup()\n    group.enter()\n\n    weak var weakSelf = self\n    autoMLImageLabeler.process(visionImage) { detectedLabels, error in\n      defer { group.leave() }\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.updatePreviewOverlayView()\n      strongSelf.removeDetectionAnnotations()\n\n      if let error = error {\n        print(\"Failed to detect labels with error: \\(error.localizedDescription).\")\n        return\n      }\n\n      guard let labels = detectedLabels, !labels.isEmpty else {\n        return\n      }\n\n      let annotationFrame = strongSelf.annotationOverlayView.frame\n      let resultsRect = CGRect(\n        x: annotationFrame.origin.x + Constants.padding,\n        y: annotationFrame.size.height - Constants.padding - Constants.resultsLabelHeight,\n        width: annotationFrame.width - 2 * Constants.padding,\n        height: Constants.resultsLabelHeight\n      )\n      let resultsLabel = UILabel(frame: resultsRect)\n      resultsLabel.textColor = .yellow\n      resultsLabel.text = labels.map { label -> String in\n        return \"Label: \\(label.text), Confidence: \\(label.confidence)\"\n      }.joined(separator: \"\\n\")\n      resultsLabel.adjustsFontSizeToFitWidth = true\n      resultsLabel.numberOfLines = Constants.resultsLabelLines\n      strongSelf.annotationOverlayView.addSubview(resultsLabel)\n    }\n\n    group.wait()\n  }\n\n  private func requestAutoMLRemoteModelIfNeeded() {\n    let remoteModel = self.remoteModel()\n    if modelManager.isModelDownloaded(remoteModel) {\n      return\n    }\n    weak var weakSelf = self\n    DispatchQueue.main.async {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.downloadProgressView.isHidden = false\n      let conditions = ModelDownloadConditions(\n        allowsCellularAccess: true,\n        allowsBackgroundDownloading: true)\n      strongSelf.downloadProgressView.observedProgress = strongSelf.modelManager.download(\n        remoteModel,\n        conditions: conditions)\n    }\n\n    print(\"Start downloading AutoML remote model\")\n  }\n\n  // MARK: - Notifications\n\n  @objc\n  private func remoteModelDownloadDidSucceed(_ notification: Notification) {\n    weak var weakSelf = self\n    let notificationHandler = {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.downloadProgressView.isHidden = true\n      guard let userInfo = notification.userInfo,\n        let remoteModel = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? RemoteModel\n      else {\n        print(\n          \"MLKitModelDownloadDidSucceed notification posted without a RemoteModel instance.\")\n        return\n      }\n      print(\n        \"Successfully downloaded the remote model with name: \\(remoteModel.name). The model \"\n          + \"is ready for detection.\")\n    }\n    if Thread.isMainThread {\n      notificationHandler()\n      return\n    }\n    DispatchQueue.main.async { notificationHandler() }\n  }\n\n  @objc\n  private func remoteModelDownloadDidFail(_ notification: Notification) {\n    weak var weakSelf = self\n    let notificationHandler = {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.downloadProgressView.isHidden = true\n      guard let userInfo = notification.userInfo,\n        let remoteModel = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? RemoteModel,\n        let error = userInfo[ModelDownloadUserInfoKey.error.rawValue] as? NSError\n      else {\n        print(\n          \"MLKitModelDownloadDidFail notification posted without a RemoteModel instance or error.\"\n        )\n        return\n      }\n      print(\"Failed to download the remote model with name: \\(remoteModel.name), error: \\(error).\")\n    }\n    if Thread.isMainThread {\n      notificationHandler()\n      return\n    }\n    DispatchQueue.main.async { notificationHandler() }\n  }\n\n  // MARK: - Private\n\n  private func remoteModel() -> RemoteModel {\n    let firebaseModelSource = FirebaseModelSource(name: Constants.remoteAutoMLModelName)\n    return CustomRemoteModel(remoteModelSource: firebaseModelSource)\n  }\n\n  private func setUpCaptureSessionOutput() {\n    weak var weakSelf = self\n    sessionQueue.async {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.captureSession.beginConfiguration()\n      // When performing latency tests to determine ideal capture settings,\n      // run the app in 'release' mode to get accurate performance metrics\n      strongSelf.captureSession.sessionPreset = AVCaptureSession.Preset.medium\n\n      let output = AVCaptureVideoDataOutput()\n      output.videoSettings = [\n        (kCVPixelBufferPixelFormatTypeKey as String): kCVPixelFormatType_32BGRA\n      ]\n      let outputQueue = DispatchQueue(label: Constants.videoDataOutputQueueLabel)\n      output.setSampleBufferDelegate(self, queue: outputQueue)\n      guard strongSelf.captureSession.canAddOutput(output) else {\n        print(\"Failed to add capture session output.\")\n        return\n      }\n      strongSelf.captureSession.addOutput(output)\n      strongSelf.captureSession.commitConfiguration()\n    }\n  }\n\n  private func setUpCaptureSessionInput() {\n    weak var weakSelf = self\n    sessionQueue.async {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      let cameraPosition: AVCaptureDevice.Position = strongSelf.isUsingFrontCamera ? .front : .back\n      guard let device = strongSelf.captureDevice(forPosition: cameraPosition) else {\n        print(\"Failed to get capture device for camera position: \\(cameraPosition)\")\n        return\n      }\n      do {\n        strongSelf.captureSession.beginConfiguration()\n        let currentInputs = strongSelf.captureSession.inputs\n        for input in currentInputs {\n          strongSelf.captureSession.removeInput(input)\n        }\n\n        let input = try AVCaptureDeviceInput(device: device)\n        guard strongSelf.captureSession.canAddInput(input) else {\n          print(\"Failed to add capture session input.\")\n          return\n        }\n        strongSelf.captureSession.addInput(input)\n        strongSelf.captureSession.commitConfiguration()\n      } catch {\n        print(\"Failed to create capture device input: \\(error.localizedDescription)\")\n      }\n    }\n  }\n\n  private func startSession() {\n    weak var weakSelf = self\n    sessionQueue.async {\n      weakSelf?.captureSession.startRunning()\n    }\n  }\n\n  private func stopSession() {\n    weak var weakSelf = self\n    sessionQueue.async {\n      weakSelf?.captureSession.stopRunning()\n    }\n  }\n\n  private func setUpPreviewOverlayView() {\n    cameraView.addSubview(previewOverlayView)\n    NSLayoutConstraint.activate([\n      previewOverlayView.centerXAnchor.constraint(equalTo: cameraView.centerXAnchor),\n      previewOverlayView.centerYAnchor.constraint(equalTo: cameraView.centerYAnchor),\n      previewOverlayView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor),\n      previewOverlayView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor),\n\n    ])\n  }\n\n  private func setUpAnnotationOverlayView() {\n    cameraView.addSubview(annotationOverlayView)\n    NSLayoutConstraint.activate([\n      annotationOverlayView.topAnchor.constraint(equalTo: cameraView.topAnchor),\n      annotationOverlayView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor),\n      annotationOverlayView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor),\n      annotationOverlayView.bottomAnchor.constraint(equalTo: cameraView.bottomAnchor),\n    ])\n  }\n\n  private func captureDevice(forPosition position: AVCaptureDevice.Position) -> AVCaptureDevice? {\n    if #available(iOS 10.0, *) {\n      let discoverySession = AVCaptureDevice.DiscoverySession(\n        deviceTypes: [.builtInWideAngleCamera],\n        mediaType: .video,\n        position: .unspecified\n      )\n      return discoverySession.devices.first { $0.position == position }\n    }\n    return nil\n  }\n\n  private func presentDetectorsAlertController() {\n    let alertController = UIAlertController(\n      title: Constants.alertControllerTitle,\n      message: Constants.alertControllerMessage,\n      preferredStyle: .alert\n    )\n    detectors.forEach { detectorType in\n      let action = UIAlertAction(title: detectorType.rawValue, style: .default) {\n        [weak self] (action) in\n        guard let value = action.title else { return }\n        guard let detector = DetectorType(rawValue: value) else { return }\n        guard let strongSelf = self else {\n          print(\"Self is nil!\")\n          return\n        }\n        strongSelf.currentDetector = detector\n        strongSelf.removeDetectionAnnotations()\n      }\n      if detectorType.rawValue == self.currentDetector.rawValue { action.isEnabled = false }\n      alertController.addAction(action)\n    }\n    alertController.addAction(UIAlertAction(title: Constants.cancelActionTitleText, style: .cancel))\n    present(alertController, animated: true)\n  }\n\n  private func removeDetectionAnnotations() {\n    for annotationView in annotationOverlayView.subviews {\n      annotationView.removeFromSuperview()\n    }\n  }\n\n  private func updatePreviewOverlayView() {\n    guard let lastFrame = lastFrame,\n      let imageBuffer = CMSampleBufferGetImageBuffer(lastFrame)\n    else {\n      return\n    }\n    let ciImage = CIImage(cvPixelBuffer: imageBuffer)\n    let context = CIContext(options: nil)\n    guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {\n      return\n    }\n    let rotatedImage = UIImage(\n      cgImage: cgImage, scale: Constants.originalScale, orientation: .right)\n    if isUsingFrontCamera {\n      guard let rotatedCGImage = rotatedImage.cgImage else {\n        return\n      }\n      let mirroredImage = UIImage(\n        cgImage: rotatedCGImage, scale: Constants.originalScale, orientation: .leftMirrored)\n      previewOverlayView.image = mirroredImage\n    } else {\n      previewOverlayView.image = rotatedImage\n    }\n  }\n}\n\n// MARK: AVCaptureVideoDataOutputSampleBufferDelegate\n\nextension CameraViewController: AVCaptureVideoDataOutputSampleBufferDelegate {\n\n  func captureOutput(\n    _ output: AVCaptureOutput,\n    didOutput sampleBuffer: CMSampleBuffer,\n    from connection: AVCaptureConnection\n  ) {\n    guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {\n      print(\"Failed to get image buffer from sample buffer.\")\n      return\n    }\n    // Evaluate `self.currentDetector` once to ensure consistency throughout this method since it\n    // can be concurrently modified from the main thread.\n    let activeDetector = self.currentDetector\n\n    lastFrame = sampleBuffer\n    let visionImage = VisionImage(buffer: sampleBuffer)\n    let orientation = UIUtilities.imageOrientation(\n      fromDevicePosition: isUsingFrontCamera ? .front : .back\n    )\n    visionImage.orientation = orientation\n    let imageWidth = CGFloat(CVPixelBufferGetWidth(imageBuffer))\n    let imageHeight = CGFloat(CVPixelBufferGetHeight(imageBuffer))\n\n    let shouldEnableClassification =\n      activeDetector == .detectorObjectsSingleWithClassifier\n      || activeDetector == .detectorObjectsMultipleWithClassifier\n    let shouldEnableMultipleObjects =\n      activeDetector == .detectorObjectsMultipleNoClassifier\n      || activeDetector == .detectorObjectsMultipleWithClassifier\n\n    switch activeDetector {\n    case .detectorImageLabels:\n      detectImageLabels(in: visionImage, width: imageWidth, height: imageHeight)\n    case .detectorObjectsSingleNoClassifier, .detectorObjectsSingleWithClassifier,\n      .detectorObjectsMultipleNoClassifier, .detectorObjectsMultipleWithClassifier:\n      detectObjects(\n        in: visionImage, width: imageWidth, height: imageHeight,\n        shouldEnableClassification: shouldEnableClassification,\n        shouldEnableMultipleObjects: shouldEnableMultipleObjects)\n    }\n  }\n}\n\n// MARK: - Constants\n\nprivate enum DetectorType: String {\n  case detectorImageLabels = \"AutoML Image Labeling\"\n  case detectorObjectsSingleNoClassifier = \"AutoML ODT, single, no labeling\"\n  case detectorObjectsSingleWithClassifier = \"AutoML ODT, single, labeling\"\n  case detectorObjectsMultipleNoClassifier = \"AutoML ODT, multiple, no labeling\"\n  case detectorObjectsMultipleWithClassifier = \"AutoML ODT, multiple, labeling\"\n}\n\nprivate enum Constants {\n  static let alertControllerTitle = \"AutoML Detectors\"\n  static let alertControllerMessage = \"Select a detector\"\n  static let cancelActionTitleText = \"Cancel\"\n  static let videoDataOutputQueueLabel = \"com.google.mlkit.automl.VideoDataOutputQueue\"\n  static let sessionQueueLabel = \"com.google.mlkit.automl.SessionQueue\"\n  static let noResultsMessage = \"No Results\"\n  static let remoteAutoMLModelName = \"remote_automl_model\"\n  static let localModelManifestFileName = \"automl_labeler_manifest\"\n  static let autoMLManifestFileType = \"json\"\n  static let labelConfidenceThreshold: Float = 0.75\n  static let smallDotRadius: CGFloat = 4.0\n  static let originalScale: CGFloat = 1.0\n  static let padding: CGFloat = 10.0\n  static let resultsLabelHeight: CGFloat = 200.0\n  static let resultsLabelLines = 5\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string>We use the data from the camera for the image recognition.</string>\n\t<key>NSPhotoLibraryUsageDescription</key>\n\t<string>We use the data from the photo library for the image recognition.</string>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample/MLKitExtensions.swift",
    "content": "import CoreGraphics\nimport UIKit\n\n// MARK: - UIImage\n\nextension UIImage {\n\n  /// Creates and returns a new image scaled to the given size. The image preserves its original PNG\n  /// or JPEG bitmap info.\n  ///\n  /// - Parameter size: The size to scale the image to.\n  /// - Returns: The scaled image or `nil` if image could not be resized.\n  public func scaledImage(with size: CGSize) -> UIImage? {\n    UIGraphicsBeginImageContextWithOptions(size, false, scale)\n    defer { UIGraphicsEndImageContext() }\n    draw(in: CGRect(origin: .zero, size: size))\n    return UIGraphicsGetImageFromCurrentImageContext()?.data.flatMap(UIImage.init)\n  }\n\n  // MARK: - Private\n\n  /// The PNG or JPEG data representation of the image or `nil` if the conversion failed.\n  private var data: Data? {\n    #if swift(>=4.2)\n      return self.pngData() ?? self.jpegData(compressionQuality: Constants.jpegCompressionQuality)\n    #else\n      return self.pngData() ?? self.jpegData(compressionQuality: Constants.jpegCompressionQuality)\n    #endif  // swift(>=4.2)\n  }\n}\n\n// MARK: - Constants\n\nprivate enum Constants {\n  static let jpegCompressionQuality: CGFloat = 0.8\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample/UIUtilities.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport AVFoundation\nimport MLKitVision\nimport UIKit\n\n/// Defines UI-related utilitiy methods for vision detection.\npublic class UIUtilities {\n\n  // MARK: - Public\n\n  public static func addCircle(\n    atPoint point: CGPoint,\n    to view: UIView,\n    color: UIColor,\n    radius: CGFloat\n  ) {\n    let divisor: CGFloat = 2.0\n    let xCoord = point.x - radius / divisor\n    let yCoord = point.y - radius / divisor\n    let circleRect = CGRect(x: xCoord, y: yCoord, width: radius, height: radius)\n    let circleView = UIView(frame: circleRect)\n    circleView.layer.cornerRadius = radius / divisor\n    circleView.alpha = Constants.circleViewAlpha\n    circleView.backgroundColor = color\n    view.addSubview(circleView)\n  }\n\n  public static func addRectangle(_ rectangle: CGRect, to view: UIView, color: UIColor) {\n    let rectangleView = UIView(frame: rectangle)\n    rectangleView.layer.cornerRadius = Constants.rectangleViewCornerRadius\n    rectangleView.alpha = Constants.rectangleViewAlpha\n    rectangleView.backgroundColor = color\n    rectangleView.accessibilityIdentifier = \"MLKit Rectangle View\"\n    view.addSubview(rectangleView)\n  }\n\n  public static func addShape(withPoints points: [NSValue]?, to view: UIView, color: UIColor) {\n    guard let points = points else { return }\n    let path = UIBezierPath()\n    for (index, value) in points.enumerated() {\n      let point = value.cgPointValue\n      if index == 0 {\n        path.move(to: point)\n      } else {\n        path.addLine(to: point)\n      }\n      if index == points.count - 1 {\n        path.close()\n      }\n    }\n    let shapeLayer = CAShapeLayer()\n    shapeLayer.path = path.cgPath\n    shapeLayer.fillColor = color.cgColor\n    let rect = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)\n    let shapeView = UIView(frame: rect)\n    shapeView.alpha = Constants.shapeViewAlpha\n    shapeView.layer.addSublayer(shapeLayer)\n    view.addSubview(shapeView)\n  }\n\n  public static func imageOrientation(\n    fromDevicePosition devicePosition: AVCaptureDevice.Position = .back\n  ) -> UIImage.Orientation {\n    var deviceOrientation = UIDevice.current.orientation\n    if deviceOrientation == .faceDown || deviceOrientation == .faceUp\n      || deviceOrientation\n        == .unknown\n    {\n      deviceOrientation = currentUIOrientation()\n    }\n    switch deviceOrientation {\n    case .portrait:\n      return devicePosition == .front ? .leftMirrored : .right\n    case .landscapeLeft:\n      return devicePosition == .front ? .downMirrored : .up\n    case .portraitUpsideDown:\n      return devicePosition == .front ? .rightMirrored : .left\n    case .landscapeRight:\n      return devicePosition == .front ? .upMirrored : .down\n    case .faceDown, .faceUp, .unknown:\n      return .up\n    }\n  }\n\n  // MARK: - Private\n\n  private static func currentUIOrientation() -> UIDeviceOrientation {\n    let deviceOrientation = { () -> UIDeviceOrientation in\n      switch UIApplication.shared.statusBarOrientation {\n      case .landscapeLeft:\n        return .landscapeRight\n      case .landscapeRight:\n        return .landscapeLeft\n      case .portraitUpsideDown:\n        return .portraitUpsideDown\n      case .portrait, .unknown:\n        return .portrait\n      }\n    }\n    guard Thread.isMainThread else {\n      var currentOrientation: UIDeviceOrientation = .portrait\n      DispatchQueue.main.sync {\n        currentOrientation = deviceOrientation()\n      }\n      return currentOrientation\n    }\n    return deviceOrientation()\n  }\n}\n\n// MARK: - Constants\n\nprivate enum Constants {\n  static let circleViewAlpha: CGFloat = 0.7\n  static let rectangleViewAlpha: CGFloat = 0.3\n  static let shapeViewAlpha: CGFloat = 0.3\n  static let rectangleViewCornerRadius: CGFloat = 10.0\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample/ViewController.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport MLKit\nimport UIKit\n\n/// Main view controller class.\n@objc(ViewController)\nclass ViewController: UIViewController, UINavigationControllerDelegate {\n\n  /// Manager for local and remote models.\n  lazy var modelManager = ModelManager.modelManager()\n\n  /// A string holding current results from detection.\n  var resultsText = \"\"\n\n  /// An overlay view that displays detection annotations.\n  private lazy var annotationOverlayView: UIView = {\n    precondition(isViewLoaded)\n    let annotationOverlayView = UIView(frame: .zero)\n    annotationOverlayView.translatesAutoresizingMaskIntoConstraints = false\n    return annotationOverlayView\n  }()\n\n  /// An image picker for accessing the photo library or camera.\n  var imagePicker = UIImagePickerController()\n\n  // Image counter.\n  var currentImage = 0\n\n  // MARK: - IBOutlets\n\n  @IBOutlet fileprivate weak var detectorPicker: UIPickerView!\n\n  @IBOutlet fileprivate weak var imageView: UIImageView!\n  @IBOutlet fileprivate weak var photoCameraButton: UIBarButtonItem!\n  @IBOutlet fileprivate weak var videoCameraButton: UIBarButtonItem!\n  @IBOutlet fileprivate weak var downloadOrDeleteModelButton: UIBarButtonItem!\n  @IBOutlet weak var detectButton: UIBarButtonItem!\n  @IBOutlet var downloadProgressView: UIProgressView!\n\n  // MARK: - UIViewController\n\n  override func viewDidLoad() {\n    super.viewDidLoad()\n\n    downloadOrDeleteModelButton.image =\n      modelManager.isModelDownloaded(remoteModel())\n      ? #imageLiteral(resourceName: \"delete\") : #imageLiteral(resourceName: \"cloud_download\")\n    imageView.image = UIImage(named: Constants.images[currentImage])\n    imageView.addSubview(annotationOverlayView)\n    NSLayoutConstraint.activate([\n      annotationOverlayView.topAnchor.constraint(equalTo: imageView.topAnchor),\n      annotationOverlayView.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),\n      annotationOverlayView.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),\n      annotationOverlayView.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),\n    ])\n\n    imagePicker.delegate = self\n    imagePicker.sourceType = .photoLibrary\n\n    detectorPicker.delegate = self\n    detectorPicker.dataSource = self\n\n    let isCameraAvailable =\n      UIImagePickerController.isCameraDeviceAvailable(.front)\n      || UIImagePickerController.isCameraDeviceAvailable(.rear)\n    if isCameraAvailable {\n      // `CameraViewController` uses `AVCaptureDevice.DiscoverySession` which is only supported for\n      // iOS 10 or newer.\n      if #available(iOS 10.0, *) {\n        videoCameraButton.isEnabled = true\n      }\n    } else {\n      photoCameraButton.isEnabled = false\n    }\n\n    let defaultRow = (DetectorPickerRow.rowsCount / 2) - 1\n    detectorPicker.selectRow(defaultRow, inComponent: 0, animated: false)\n  }\n\n  override func viewWillAppear(_ animated: Bool) {\n    super.viewWillAppear(animated)\n\n    navigationController?.navigationBar.isHidden = true\n    NotificationCenter.default.addObserver(\n      self,\n      selector: #selector(remoteModelDownloadDidSucceed(_:)),\n      name: .mlkitModelDownloadDidSucceed,\n      object: nil\n    )\n    NotificationCenter.default.addObserver(\n      self,\n      selector: #selector(remoteModelDownloadDidFail(_:)),\n      name: .mlkitModelDownloadDidFail,\n      object: nil\n    )\n  }\n\n  override func viewWillDisappear(_ animated: Bool) {\n    super.viewWillDisappear(animated)\n\n    navigationController?.navigationBar.isHidden = false\n    // We wouldn't have needed to remove the observers if iOS 9.0+ had cleaned up the observer \"the\n    // next time it would have posted to it\" as documented here:\n    // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver\n    NotificationCenter.default.removeObserver(\n      self,\n      name: .mlkitModelDownloadDidSucceed,\n      object: nil)\n    NotificationCenter.default.removeObserver(self, name: .mlkitModelDownloadDidFail, object: nil)\n  }\n\n  // MARK: - IBActions\n\n  @IBAction func detect(_ sender: Any) {\n    clearResults()\n    let row = detectorPicker.selectedRow(inComponent: 0)\n    let shouldEnableClassification =\n      row == DetectorPickerRow.detectorObjectsSingleWithClassifier.rawValue\n      || row == DetectorPickerRow.detectorObjectsMultipleWithClassifier.rawValue\n    let shouldEnableMultipleObjects =\n      row == DetectorPickerRow.detectorObjectsMultipleNoClassifier.rawValue\n      || row == DetectorPickerRow.detectorObjectsMultipleWithClassifier.rawValue\n\n    if let rowIndex = DetectorPickerRow(rawValue: row) {\n      switch rowIndex {\n      case .detectorImageLabels: detectImageLabels(image: imageView.image)\n      case .detectorObjectsSingleNoClassifier, .detectorObjectsSingleWithClassifier,\n        .detectorObjectsMultipleNoClassifier, .detectorObjectsMultipleWithClassifier:\n        detectObjects(\n          image: imageView.image, shouldEnableClassification: shouldEnableClassification,\n          shouldEnableMultipleObjects: shouldEnableMultipleObjects)\n      }\n    } else {\n      print(\"No such item at row \\(row) in detector picker.\")\n    }\n  }\n\n  @IBAction func openPhotoLibrary(_ sender: Any) {\n    imagePicker.sourceType = .photoLibrary\n    present(imagePicker, animated: true)\n  }\n\n  @IBAction func openCamera(_ sender: Any) {\n    guard\n      UIImagePickerController.isCameraDeviceAvailable(.front)\n        || UIImagePickerController\n          .isCameraDeviceAvailable(.rear)\n    else {\n      return\n    }\n    imagePicker.sourceType = .camera\n    present(imagePicker, animated: true)\n  }\n\n  @IBAction func changeImage(_ sender: Any) {\n    clearResults()\n    currentImage = (currentImage + 1) % Constants.images.count\n    imageView.image = UIImage(named: Constants.images[currentImage])\n  }\n\n  @IBAction func downloadOrDeleteModel(_ sender: Any) {\n    clearResults()\n    let remoteModel = self.remoteModel()\n    if modelManager.isModelDownloaded(remoteModel) {\n      weak var weakSelf = self\n      modelManager.deleteDownloadedModel(remoteModel) { error in\n        guard error == nil else { preconditionFailure(\"Failed to delete the AutoML model.\") }\n        print(\"The downloaded remote model has been successfully deleted.\\n\")\n        weakSelf?.downloadOrDeleteModelButton.image = #imageLiteral(resourceName: \"cloud_download\")\n      }\n    } else {\n      downloadAutoMLRemoteModel(remoteModel)\n    }\n  }\n\n  // MARK: - Private\n\n  private func remoteModel() -> RemoteModel {\n    let firebaseModelSource = FirebaseModelSource(name: Constants.remoteAutoMLModelName)\n    return CustomRemoteModel(remoteModelSource: firebaseModelSource)\n  }\n\n  /// Removes the detection annotations from the annotation overlay view.\n  private func removeDetectionAnnotations() {\n    for annotationView in annotationOverlayView.subviews {\n      annotationView.removeFromSuperview()\n    }\n  }\n\n  /// Clears the results text view and removes any frames that are visible.\n  private func clearResults() {\n    removeDetectionAnnotations()\n    self.resultsText = \"\"\n  }\n\n  private func showResults() {\n    let resultsAlertController = UIAlertController(\n      title: \"Detection Results\",\n      message: nil,\n      preferredStyle: .actionSheet\n    )\n    resultsAlertController.addAction(\n      UIAlertAction(title: \"OK\", style: .destructive) { _ in\n        resultsAlertController.dismiss(animated: true, completion: nil)\n      }\n    )\n    resultsAlertController.message = resultsText\n    resultsAlertController.popoverPresentationController?.barButtonItem = detectButton\n    resultsAlertController.popoverPresentationController?.sourceView = self.view\n    present(resultsAlertController, animated: true, completion: nil)\n    print(resultsText)\n  }\n\n  /// Updates the image view with a scaled version of the given image.\n  private func updateImageView(with image: UIImage) {\n    let orientation = UIApplication.shared.statusBarOrientation\n    var scaledImageWidth: CGFloat = 0.0\n    var scaledImageHeight: CGFloat = 0.0\n    switch orientation {\n    case .portrait, .portraitUpsideDown, .unknown:\n      scaledImageWidth = imageView.bounds.size.width\n      scaledImageHeight = image.size.height * scaledImageWidth / image.size.width\n    case .landscapeLeft, .landscapeRight:\n      scaledImageWidth = image.size.width * scaledImageHeight / image.size.height\n      scaledImageHeight = imageView.bounds.size.height\n    }\n    DispatchQueue.global(qos: .userInitiated).async {\n      // Scale image while maintaining aspect ratio so it displays better in the UIImageView.\n      var scaledImage = image.scaledImage(\n        with: CGSize(width: scaledImageWidth, height: scaledImageHeight)\n      )\n      scaledImage = scaledImage ?? image\n      guard let finalImage = scaledImage else { return }\n      weak var weakSelf = self\n      DispatchQueue.main.async {\n        weakSelf?.imageView.image = finalImage\n      }\n    }\n  }\n\n  private func transformMatrix() -> CGAffineTransform {\n    guard let image = imageView.image else { return CGAffineTransform() }\n    let imageViewWidth = imageView.frame.size.width\n    let imageViewHeight = imageView.frame.size.height\n    let imageWidth = image.size.width\n    let imageHeight = image.size.height\n\n    let imageViewAspectRatio = imageViewWidth / imageViewHeight\n    let imageAspectRatio = imageWidth / imageHeight\n    let scale =\n      (imageViewAspectRatio > imageAspectRatio)\n      ? imageViewHeight / imageHeight : imageViewWidth / imageWidth\n\n    // Image view's `contentMode` is `scaleAspectFit`, which scales the image to fit the size of the\n    // image view by maintaining the aspect ratio. Multiple by `scale` to get image's original size.\n    let scaledImageWidth = imageWidth * scale\n    let scaledImageHeight = imageHeight * scale\n    let xValue = (imageViewWidth - scaledImageWidth) / CGFloat(2.0)\n    let yValue = (imageViewHeight - scaledImageHeight) / CGFloat(2.0)\n\n    var transform = CGAffineTransform.identity.translatedBy(x: xValue, y: yValue)\n    transform = transform.scaledBy(x: scale, y: scale)\n    return transform\n  }\n\n  private func requestAutoMLRemoteModelIfNeeded() {\n    let remoteModel = self.remoteModel()\n    if modelManager.isModelDownloaded(remoteModel) {\n      return\n    }\n    downloadAutoMLRemoteModel(remoteModel)\n  }\n\n  private func downloadAutoMLRemoteModel(_ remoteModel: RemoteModel) {\n    downloadProgressView.isHidden = false\n    let conditions = ModelDownloadConditions(\n      allowsCellularAccess: true,\n      allowsBackgroundDownloading: true)\n    downloadProgressView.observedProgress = modelManager.download(\n      remoteModel,\n      conditions: conditions)\n    print(\"Start downloading AutoML remote model\")\n  }\n\n  // MARK: - Notifications\n\n  @objc\n  private func remoteModelDownloadDidSucceed(_ notification: Notification) {\n    weak var weakSelf = self\n    let notificationHandler = {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.downloadProgressView.isHidden = true\n      strongSelf.downloadOrDeleteModelButton.image = #imageLiteral(resourceName: \"delete\")\n      guard let userInfo = notification.userInfo,\n        let remoteModel = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? RemoteModel\n      else {\n        strongSelf.resultsText +=\n          \"MLKitModelDownloadDidSucceed notification posted without a RemoteModel instance.\"\n        return\n      }\n      strongSelf.resultsText +=\n        \"Successfully downloaded the remote model with name: \\(remoteModel.name).\"\n      strongSelf.resultsText += \"The model is ready for detection.\"\n      print(\"Sucessfully downloaded AutoML remote model.\")\n    }\n    if Thread.isMainThread {\n      notificationHandler()\n      return\n    }\n    DispatchQueue.main.async { notificationHandler() }\n  }\n\n  @objc\n  private func remoteModelDownloadDidFail(_ notification: Notification) {\n    weak var weakSelf = self\n    let notificationHandler = {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.downloadProgressView.isHidden = true\n      guard let userInfo = notification.userInfo,\n        let remoteModel = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? RemoteModel,\n        let error = userInfo[ModelDownloadUserInfoKey.error.rawValue] as? NSError\n      else {\n        strongSelf.resultsText +=\n          \"MLKitModelDownloadDidFail notification posted without a RemoteModel instance or error.\"\n        return\n      }\n      strongSelf.resultsText +=\n        \"Failed to download the remote model with name: \\(remoteModel.name), error: \\(error).\"\n      print(\"Failed to download AutoML remote model.\")\n    }\n    if Thread.isMainThread {\n      notificationHandler()\n      return\n    }\n    DispatchQueue.main.async { notificationHandler() }\n  }\n}\n\nextension ViewController: UIPickerViewDataSource, UIPickerViewDelegate {\n\n  // MARK: - UIPickerViewDataSource\n\n  func numberOfComponents(in pickerView: UIPickerView) -> Int {\n    return DetectorPickerRow.componentsCount\n  }\n\n  func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {\n    return DetectorPickerRow.rowsCount\n  }\n\n  // MARK: - UIPickerViewDelegate\n\n  func pickerView(\n    _ pickerView: UIPickerView,\n    titleForRow row: Int,\n    forComponent component: Int\n  ) -> String? {\n    return DetectorPickerRow(rawValue: row)?.description\n  }\n\n  func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {\n    clearResults()\n  }\n}\n\n// MARK: - UIImagePickerControllerDelegate\n\nextension ViewController: UIImagePickerControllerDelegate {\n\n  func imagePickerController(\n    _ picker: UIImagePickerController,\n    didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]\n  ) {\n    // Local variable inserted by Swift 4.2 migrator.\n    let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)\n\n    clearResults()\n    if let pickedImage =\n      info[\n        convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.originalImage)]\n      as? UIImage\n    {\n      updateImageView(with: pickedImage)\n    }\n    dismiss(animated: true)\n  }\n}\n\n/// Extension of ViewController for AutoML image labeling.\nextension ViewController {\n\n  // MARK: - AutoML Image Labeling\n\n  /// Detects labels on the specified image using AutoML Image Labeling API.\n  ///\n  /// - Parameter image: The image.\n  func detectImageLabels(image: UIImage?) {\n    guard let image = image else { return }\n    requestAutoMLRemoteModelIfNeeded()\n\n    // [START config_automl_label]\n    let remoteModel = self.remoteModel()\n    guard\n      let localModelFilePath = Bundle.main.path(\n        forResource: Constants.localModelManifestFileName,\n        ofType: Constants.autoMLManifestFileType\n      )\n    else {\n      print(\"Failed to find AutoML local model manifest file.\")\n      return\n    }\n    let isModelDownloaded = modelManager.isModelDownloaded(remoteModel)\n    var options: CommonImageLabelerOptions!\n    guard let localModel = LocalModel(manifestPath: localModelFilePath) else { return }\n    options =\n      isModelDownloaded\n      ? CustomImageLabelerOptions(remoteModel: remoteModel as! CustomRemoteModel)\n      : CustomImageLabelerOptions(localModel: localModel)\n    print(\"Use AutoML \\(isModelDownloaded ? \"remote\" : \"local\") in detector picker.\")\n    options.confidenceThreshold = NSNumber(value: Constants.labelConfidenceThreshold)\n    // [END config_automl_label]\n\n    // [START init_automl_label]\n    let autoMLImageLabeler = ImageLabeler.imageLabeler(options: options)\n    // [END init_automl_label]\n\n    // Initialize a VisionImage object with the given UIImage.\n    let visionImage = VisionImage(image: image)\n    visionImage.orientation = image.imageOrientation\n\n    // [START detect_automl_label]\n    weak var weakSelf = self\n    autoMLImageLabeler.process(visionImage) { labels, error in\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      guard error == nil, let labels = labels, !labels.isEmpty else {\n        // [START_EXCLUDE]\n        let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n        strongSelf.resultsText = \"AutoML image labeling failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        // [END_EXCLUDE]\n        return\n      }\n\n      // [START_EXCLUDE]\n      strongSelf.resultsText = labels.map { label -> String in\n        return \"Label: \\(label.text), Confidence: \\(label.confidence)\"\n      }.joined(separator: \"\\n\")\n      strongSelf.showResults()\n      // [END_EXCLUDE]\n    }\n    // [END detect_automl_label]\n  }\n\n  /// Detects objects on the specified image using image classification models trained by AutoML\n  /// via Custom Object Detection API.\n  ///\n  /// - Parameter image: The image.\n  /// - Parameter shouldEnableClassification: Whether image classification should be enabled.\n  /// - Parameter shouldEnableMultipleObjects: Whether multi-object detection should be enabled.\n  func detectObjects(\n    image: UIImage?, shouldEnableClassification: Bool, shouldEnableMultipleObjects: Bool\n  ) {\n    guard let image = image else { return }\n    requestAutoMLRemoteModelIfNeeded()\n\n    let remoteModel = self.remoteModel()\n    var options: CustomObjectDetectorOptions!\n    if modelManager.isModelDownloaded(remoteModel) {\n      print(\"Use AutoML remote model.\")\n      options = CustomObjectDetectorOptions(remoteModel: remoteModel as! CustomRemoteModel)\n    } else {\n      print(\"Use AutoML local model.\")\n      guard\n        let localModelFilePath = Bundle.main.path(\n          forResource: Constants.localModelManifestFileName,\n          ofType: Constants.autoMLManifestFileType\n        )\n      else {\n        print(\n          \"Failed to find AutoML local model manifest file: \\(Constants.localModelManifestFileName)\"\n        )\n        return\n      }\n      guard let localModel = LocalModel(manifestPath: localModelFilePath) else { return }\n      options = CustomObjectDetectorOptions(localModel: localModel)\n    }\n    options.shouldEnableClassification = shouldEnableClassification\n    options.shouldEnableMultipleObjects = shouldEnableMultipleObjects\n    options.detectorMode = .singleImage\n\n    let autoMLObjectDetector = ObjectDetector.objectDetector(options: options)\n\n    // Initialize a VisionImage object with the given UIImage.\n    let visionImage = VisionImage(image: image)\n    visionImage.orientation = image.imageOrientation\n\n    weak var weakSelf = self\n    autoMLObjectDetector.process(visionImage) { objects, error in\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      guard error == nil, let objects = objects, !objects.isEmpty else {\n        let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n        strongSelf.resultsText = \"AutoML object detection failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        return\n      }\n\n      strongSelf.resultsText = objects.map { object -> String in\n        let transform = strongSelf.transformMatrix()\n        let transformedRect = object.frame.applying(transform)\n        UIUtilities.addRectangle(\n          transformedRect, to: strongSelf.annotationOverlayView, color: .green)\n        let labels = object.labels.enumerated().map { (index, label) -> String in\n          return \"Label \\(index): \\(label.text), \\(label.confidence), \\(label.index)\"\n        }.joined(separator: \"\\n\")\n        return\n          \"Frame: \\(object.frame)\\nObject ID: \\(String(describing: object.trackingID))\\nLabels:\\(labels)\"\n      }.joined(separator: \"\\n\")\n      strongSelf.showResults()\n    }\n  }\n}\n\n// MARK: - Enums\n\nprivate enum DetectorPickerRow: Int {\n  // AutoML image label detector.\n  case detectorImageLabels\n  // AutoML object detector, single, only tracking.\n  case detectorObjectsSingleNoClassifier\n  // AutoML object detector, single, with classification.\n  case detectorObjectsSingleWithClassifier\n  // AutoML object detector, multiple, only tracking.\n  case detectorObjectsMultipleNoClassifier\n  // AutoML object detector, multiple, with classification.\n  case detectorObjectsMultipleWithClassifier\n\n  static let rowsCount = 5\n  static let componentsCount = 1\n\n  public var description: String {\n    switch self {\n    case .detectorImageLabels:\n      return \"AutoML Image Labeling\"\n    case .detectorObjectsSingleNoClassifier:\n      return \"AutoML ODT, single, no labeling\"\n    case .detectorObjectsSingleWithClassifier:\n      return \"AutoML ODT, single, labeling\"\n    case .detectorObjectsMultipleNoClassifier:\n      return \"AutoML ODT, multiple, no labeling\"\n    case .detectorObjectsMultipleWithClassifier:\n      return \"AutoML ODT, multiple, labeling\"\n    }\n  }\n}\n\nprivate enum Constants {\n  static let images = [\n    \"dandelion.jpg\", \"sunflower.jpg\", \"tulips.jpeg\", \"daisy.jpeg\", \"roses.jpeg\",\n  ]\n\n  static let modelExtension = \"tflite\"\n  static let localModelName = \"mobilenet\"\n  static let quantizedModelFilename = \"mobilenet_quant_v1_224\"\n\n  static let detectionNoResultsMessage = \"No results returned.\"\n  static let sparseTextModelName = \"Sparse\"\n  static let denseTextModelName = \"Dense\"\n\n  static let remoteAutoMLModelName = \"remote_automl_model\"\n  static let localModelManifestFileName = \"automl_labeler_manifest\"\n  static let autoMLManifestFileType = \"json\"\n\n  static let labelConfidenceThreshold: Float = 0.75\n  static let smallDotRadius: CGFloat = 5.0\n  static let largeDotRadius: CGFloat = 10.0\n  static let lineColor = UIColor.yellow.cgColor\n  static let fillColor = UIColor.clear.cgColor\n}\n\n// Helper function inserted by Swift 4.2 migrator.\nprivate func convertFromUIImagePickerControllerInfoKeyDictionary(\n  _ input: [UIImagePickerController.InfoKey: Any]\n) -> [String: Any] {\n  return Dictionary(uniqueKeysWithValues: input.map { key, value in (key.rawValue, value) })\n}\n\n// Helper function inserted by Swift 4.2 migrator.\nprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey)\n  -> String\n{\n  return input.rawValue\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 48;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1001E6F720CEE0DD00445CB3 /* UIUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */; };\n\t\t1001E6F920CF021E00445CB3 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1001E6F820CF021E00445CB3 /* CameraViewController.swift */; };\n\t\t1001E6FD20CF0C8F00445CB3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */; };\n\t\t100D2A50222F37DB00DF5C02 /* automl_labeler_labels.txt in Resources */ = {isa = PBXBuildFile; fileRef = B217D4A8220D24C9001CE5AA /* automl_labeler_labels.txt */; };\n\t\t100D2A51222F37DE00DF5C02 /* automl_labeler_manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = B217D4A9220D24CA001CE5AA /* automl_labeler_manifest.json */; };\n\t\t100D2A52222F37E100DF5C02 /* automl_labeler_model.tflite in Resources */ = {isa = PBXBuildFile; fileRef = B217D4AA220D24CA001CE5AA /* automl_labeler_model.tflite */; };\n\t\t10224B582087E43100A77316 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10224B572087E43100A77316 /* ViewController.swift */; };\n\t\t10224B5E2087E49F00A77316 /* MLKitExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10224B5B2087E49F00A77316 /* MLKitExtensions.swift */; };\n\t\t10B3184F22EB9C5E00E834FF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 10B3184D22EB9C5E00E834FF /* GoogleService-Info.plist */; };\n\t\t10E114E420E5CBAA0013E4A4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E114E320E5CBAA0013E4A4 /* AppDelegate.m */; };\n\t\t10E114E720E5CBAA0013E4A4 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E114E620E5CBAA0013E4A4 /* ViewController.m */; };\n\t\t10E114F220E5CBAE0013E4A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E114F120E5CBAE0013E4A4 /* main.m */; };\n\t\t10E1151420EBF5EB0013E4A4 /* UIUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E1151320EBF5EB0013E4A4 /* UIUtilities.m */; };\n\t\t10E1151720EBF6220013E4A4 /* CameraViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E1151620EBF6220013E4A4 /* CameraViewController.m */; };\n\t\t10E1151A20EBF7E10013E4A4 /* UIImage+VisionDetection.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E1151920EBF7E10013E4A4 /* UIImage+VisionDetection.m */; };\n\t\t10E1152120F3D5F60013E4A4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB287B3C20729CE90069707A /* Main.storyboard */; };\n\t\t10E1152520F3DFE20013E4A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */; };\n\t\t1B76D8DA23C7ACAB00EBF6FC /* sunflower.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D523C7ACA900EBF6FC /* sunflower.jpg */; };\n\t\t1B76D8DB23C7ACAB00EBF6FC /* tulips.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D623C7ACAA00EBF6FC /* tulips.jpeg */; };\n\t\t1B76D8DC23C7ACAB00EBF6FC /* daisy.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D723C7ACAA00EBF6FC /* daisy.jpeg */; };\n\t\t1B76D8DD23C7ACAB00EBF6FC /* roses.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D823C7ACAA00EBF6FC /* roses.jpeg */; };\n\t\t1B76D8DE23C7ACAB00EBF6FC /* dandelion.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D923C7ACAB00EBF6FC /* dandelion.jpg */; };\n\t\t1B76D8DF23C7B01F00EBF6FC /* daisy.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D723C7ACAA00EBF6FC /* daisy.jpeg */; };\n\t\t1B76D8E023C7B01F00EBF6FC /* dandelion.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D923C7ACAB00EBF6FC /* dandelion.jpg */; };\n\t\t1B76D8E123C7B01F00EBF6FC /* roses.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D823C7ACAA00EBF6FC /* roses.jpeg */; };\n\t\t1B76D8E223C7B01F00EBF6FC /* sunflower.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D523C7ACA900EBF6FC /* sunflower.jpg */; };\n\t\t1B76D8E323C7B01F00EBF6FC /* tulips.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 1B76D8D623C7ACAA00EBF6FC /* tulips.jpeg */; };\n\t\tA4581F0224C2473B005237E0 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 10B3184D22EB9C5E00E834FF /* GoogleService-Info.plist */; };\n\t\tB217D4AB220D24CA001CE5AA /* automl_labeler_labels.txt in Resources */ = {isa = PBXBuildFile; fileRef = B217D4A8220D24C9001CE5AA /* automl_labeler_labels.txt */; };\n\t\tB217D4AC220D24CA001CE5AA /* automl_labeler_manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = B217D4A9220D24CA001CE5AA /* automl_labeler_manifest.json */; };\n\t\tB217D4AD220D24CA001CE5AA /* automl_labeler_model.tflite in Resources */ = {isa = PBXBuildFile; fileRef = B217D4AA220D24CA001CE5AA /* automl_labeler_model.tflite */; };\n\t\tBB287B3920729CE90069707A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB287B3820729CE90069707A /* AppDelegate.swift */; };\n\t\tBB287B3E20729CE90069707A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB287B3C20729CE90069707A /* Main.storyboard */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIUtilities.swift; sourceTree = \"<group>\"; };\n\t\t1001E6F820CF021E00445CB3 /* CameraViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = \"<group>\"; };\n\t\t1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t10224B572087E43100A77316 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\t10224B5B2087E49F00A77316 /* MLKitExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MLKitExtensions.swift; sourceTree = \"<group>\"; };\n\t\t10B3184D22EB9C5E00E834FF /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = \"GoogleService-Info.plist\"; path = \"AutoMLExample/GoogleService-Info.plist\"; sourceTree = \"<group>\"; };\n\t\t10E114E020E5CBAA0013E4A4 /* AutoMLExampleObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoMLExampleObjC.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t10E114E220E5CBAA0013E4A4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t10E114E320E5CBAA0013E4A4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t10E114E520E5CBAA0013E4A4 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\t10E114E620E5CBAA0013E4A4 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\t10E114F120E5CBAE0013E4A4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t10E1151220EBF5EB0013E4A4 /* UIUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIUtilities.h; sourceTree = \"<group>\"; };\n\t\t10E1151320EBF5EB0013E4A4 /* UIUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIUtilities.m; sourceTree = \"<group>\"; };\n\t\t10E1151520EBF6220013E4A4 /* CameraViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CameraViewController.h; sourceTree = \"<group>\"; };\n\t\t10E1151620EBF6220013E4A4 /* CameraViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraViewController.m; sourceTree = \"<group>\"; };\n\t\t10E1151820EBF7E10013E4A4 /* UIImage+VisionDetection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"UIImage+VisionDetection.h\"; sourceTree = \"<group>\"; };\n\t\t10E1151920EBF7E10013E4A4 /* UIImage+VisionDetection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = \"UIImage+VisionDetection.m\"; sourceTree = \"<group>\"; };\n\t\t1B76D8D523C7ACA900EBF6FC /* sunflower.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = sunflower.jpg; path = Resources/sunflower.jpg; sourceTree = \"<group>\"; };\n\t\t1B76D8D623C7ACAA00EBF6FC /* tulips.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = tulips.jpeg; path = Resources/tulips.jpeg; sourceTree = \"<group>\"; };\n\t\t1B76D8D723C7ACAA00EBF6FC /* daisy.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = daisy.jpeg; path = Resources/daisy.jpeg; sourceTree = \"<group>\"; };\n\t\t1B76D8D823C7ACAA00EBF6FC /* roses.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = roses.jpeg; path = Resources/roses.jpeg; sourceTree = \"<group>\"; };\n\t\t1B76D8D923C7ACAB00EBF6FC /* dandelion.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = dandelion.jpg; path = Resources/dandelion.jpg; sourceTree = \"<group>\"; };\n\t\tB217D4A8220D24C9001CE5AA /* automl_labeler_labels.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = automl_labeler_labels.txt; path = Resources/automl_labeler_labels.txt; sourceTree = \"<group>\"; };\n\t\tB217D4A9220D24CA001CE5AA /* automl_labeler_manifest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = automl_labeler_manifest.json; path = Resources/automl_labeler_manifest.json; sourceTree = \"<group>\"; };\n\t\tB217D4AA220D24CA001CE5AA /* automl_labeler_model.tflite */ = {isa = PBXFileReference; lastKnownFileType = file; name = automl_labeler_model.tflite; path = Resources/automl_labeler_model.tflite; sourceTree = \"<group>\"; };\n\t\tBB287B3520729CE90069707A /* AutoMLExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoMLExample.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tBB287B3820729CE90069707A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tBB287B3D20729CE90069707A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tBB287B4420729CE90069707A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t10E114DD20E5CBAA0013E4A4 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3220729CE90069707A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t10224B642087E52600A77316 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1B76D8D723C7ACAA00EBF6FC /* daisy.jpeg */,\n\t\t\t\t1B76D8D923C7ACAB00EBF6FC /* dandelion.jpg */,\n\t\t\t\t1B76D8D823C7ACAA00EBF6FC /* roses.jpeg */,\n\t\t\t\t1B76D8D523C7ACA900EBF6FC /* sunflower.jpg */,\n\t\t\t\t1B76D8D623C7ACAA00EBF6FC /* tulips.jpeg */,\n\t\t\t\tB217D4A8220D24C9001CE5AA /* automl_labeler_labels.txt */,\n\t\t\t\tB217D4A9220D24CA001CE5AA /* automl_labeler_manifest.json */,\n\t\t\t\tB217D4AA220D24CA001CE5AA /* automl_labeler_model.tflite */,\n\t\t\t);\n\t\t\tname = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t10E114E120E5CBAA0013E4A4 /* AutoMLExampleObjC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t10E114E220E5CBAA0013E4A4 /* AppDelegate.h */,\n\t\t\t\t10E114E320E5CBAA0013E4A4 /* AppDelegate.m */,\n\t\t\t\t10E114E520E5CBAA0013E4A4 /* ViewController.h */,\n\t\t\t\t10E114E620E5CBAA0013E4A4 /* ViewController.m */,\n\t\t\t\t10E114F120E5CBAE0013E4A4 /* main.m */,\n\t\t\t\t10E1151220EBF5EB0013E4A4 /* UIUtilities.h */,\n\t\t\t\t10E1151320EBF5EB0013E4A4 /* UIUtilities.m */,\n\t\t\t\t10E1151520EBF6220013E4A4 /* CameraViewController.h */,\n\t\t\t\t10E1151620EBF6220013E4A4 /* CameraViewController.m */,\n\t\t\t\t10E1151820EBF7E10013E4A4 /* UIImage+VisionDetection.h */,\n\t\t\t\t10E1151920EBF7E10013E4A4 /* UIImage+VisionDetection.m */,\n\t\t\t);\n\t\t\tpath = AutoMLExampleObjC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B2C20729CE90069707A = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t10B3184D22EB9C5E00E834FF /* GoogleService-Info.plist */,\n\t\t\t\t1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */,\n\t\t\t\t10224B642087E52600A77316 /* Resources */,\n\t\t\t\tBB287B3720729CE90069707A /* AutoMLExample */,\n\t\t\t\t10E114E120E5CBAA0013E4A4 /* AutoMLExampleObjC */,\n\t\t\t\tBB287B3620729CE90069707A /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B3620729CE90069707A /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3520729CE90069707A /* AutoMLExample.app */,\n\t\t\t\t10E114E020E5CBAA0013E4A4 /* AutoMLExampleObjC.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B3720729CE90069707A /* AutoMLExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3820729CE90069707A /* AppDelegate.swift */,\n\t\t\t\t10224B572087E43100A77316 /* ViewController.swift */,\n\t\t\t\t10224B5B2087E49F00A77316 /* MLKitExtensions.swift */,\n\t\t\t\t1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */,\n\t\t\t\t1001E6F820CF021E00445CB3 /* CameraViewController.swift */,\n\t\t\t\tBB287B4A2072A0200069707A /* Supporting Files */,\n\t\t\t\tBB287B4420729CE90069707A /* Info.plist */,\n\t\t\t);\n\t\t\tpath = AutoMLExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B4A2072A0200069707A /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3C20729CE90069707A /* Main.storyboard */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t10E114DF20E5CBAA0013E4A4 /* AutoMLExampleObjC */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 10E1150F20E5CBAE0013E4A4 /* Build configuration list for PBXNativeTarget \"AutoMLExampleObjC\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t10E114DC20E5CBAA0013E4A4 /* Sources */,\n\t\t\t\t10E114DD20E5CBAA0013E4A4 /* Frameworks */,\n\t\t\t\t10E114DE20E5CBAA0013E4A4 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AutoMLExampleObjC;\n\t\t\tproductName = AutoMLExampleObjC;\n\t\t\tproductReference = 10E114E020E5CBAA0013E4A4 /* AutoMLExampleObjC.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tBB287B3420729CE90069707A /* AutoMLExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = BB287B4720729CE90069707A /* Build configuration list for PBXNativeTarget \"AutoMLExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tBB287B3120729CE90069707A /* Sources */,\n\t\t\t\tBB287B3220729CE90069707A /* Frameworks */,\n\t\t\t\tBB287B3320729CE90069707A /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = AutoMLExample;\n\t\t\tproductName = \"ml-kit-sampler\";\n\t\t\tproductReference = BB287B3520729CE90069707A /* AutoMLExample.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tBB287B2D20729CE90069707A /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1340;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = \"Google Inc.\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t10E114DF20E5CBAA0013E4A4 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.4;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\tBB287B3420729CE90069707A = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = BB287B3020729CE90069707A /* Build configuration list for PBXProject \"AutoMLExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = BB287B2C20729CE90069707A;\n\t\t\tproductRefGroup = BB287B3620729CE90069707A /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tBB287B3420729CE90069707A /* AutoMLExample */,\n\t\t\t\t10E114DF20E5CBAA0013E4A4 /* AutoMLExampleObjC */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t10E114DE20E5CBAA0013E4A4 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1B76D8DF23C7B01F00EBF6FC /* daisy.jpeg in Resources */,\n\t\t\t\t1B76D8E323C7B01F00EBF6FC /* tulips.jpeg in Resources */,\n\t\t\t\t10E1152120F3D5F60013E4A4 /* Main.storyboard in Resources */,\n\t\t\t\t1B76D8E123C7B01F00EBF6FC /* roses.jpeg in Resources */,\n\t\t\t\t1B76D8E223C7B01F00EBF6FC /* sunflower.jpg in Resources */,\n\t\t\t\t1B76D8E023C7B01F00EBF6FC /* dandelion.jpg in Resources */,\n\t\t\t\t10E1152520F3DFE20013E4A4 /* Assets.xcassets in Resources */,\n\t\t\t\tB217D4AD220D24CA001CE5AA /* automl_labeler_model.tflite in Resources */,\n\t\t\t\t10B3184F22EB9C5E00E834FF /* GoogleService-Info.plist in Resources */,\n\t\t\t\tB217D4AB220D24CA001CE5AA /* automl_labeler_labels.txt in Resources */,\n\t\t\t\tB217D4AC220D24CA001CE5AA /* automl_labeler_manifest.json in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3320729CE90069707A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1B76D8DA23C7ACAB00EBF6FC /* sunflower.jpg in Resources */,\n\t\t\t\t100D2A51222F37DE00DF5C02 /* automl_labeler_manifest.json in Resources */,\n\t\t\t\t1B76D8DB23C7ACAB00EBF6FC /* tulips.jpeg in Resources */,\n\t\t\t\t100D2A52222F37E100DF5C02 /* automl_labeler_model.tflite in Resources */,\n\t\t\t\t1B76D8DE23C7ACAB00EBF6FC /* dandelion.jpg in Resources */,\n\t\t\t\t1B76D8DC23C7ACAB00EBF6FC /* daisy.jpeg in Resources */,\n\t\t\t\t1B76D8DD23C7ACAB00EBF6FC /* roses.jpeg in Resources */,\n\t\t\t\tBB287B3E20729CE90069707A /* Main.storyboard in Resources */,\n\t\t\t\tA4581F0224C2473B005237E0 /* GoogleService-Info.plist in Resources */,\n\t\t\t\t100D2A50222F37DB00DF5C02 /* automl_labeler_labels.txt in Resources */,\n\t\t\t\t1001E6FD20CF0C8F00445CB3 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t10E114DC20E5CBAA0013E4A4 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t10E1151720EBF6220013E4A4 /* CameraViewController.m in Sources */,\n\t\t\t\t10E1151A20EBF7E10013E4A4 /* UIImage+VisionDetection.m in Sources */,\n\t\t\t\t10E114E720E5CBAA0013E4A4 /* ViewController.m in Sources */,\n\t\t\t\t10E114F220E5CBAE0013E4A4 /* main.m in Sources */,\n\t\t\t\t10E1151420EBF5EB0013E4A4 /* UIUtilities.m in Sources */,\n\t\t\t\t10E114E420E5CBAA0013E4A4 /* AppDelegate.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3120729CE90069707A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t10224B582087E43100A77316 /* ViewController.swift in Sources */,\n\t\t\t\t1001E6F920CF021E00445CB3 /* CameraViewController.swift in Sources */,\n\t\t\t\tBB287B3920729CE90069707A /* AppDelegate.swift in Sources */,\n\t\t\t\t10224B5E2087E49F00A77316 /* MLKitExtensions.swift in Sources */,\n\t\t\t\t1001E6F720CEE0DD00445CB3 /* UIUtilities.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tBB287B3C20729CE90069707A /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3D20729CE90069707A /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t10E1150920E5CBAE0013E4A4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/AutoMLExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.AutoMLExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t10E1150A20E5CBAE0013E4A4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/AutoMLExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.AutoMLExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBB287B4520729CE90069707A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tEXCLUDED_ARCHS = \"\";\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = arm64;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"COCOAPODS DEBUG\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBB287B4620729CE90069707A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tEXCLUDED_ARCHS = \"\";\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = arm64;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = COCOAPODS;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBB287B4820729CE90069707A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = arm64;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstanceID\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleAPIClientForREST\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransportCCTSupport\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilitiesComponents\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf\\\"\",\n\t\t\t\t\t\"\\\"${PODS_CONFIGURATION_BUILD_DIR}/nanopb\\\"\",\n\t\t\t\t\t\"\\\"${PODS_ROOT}/MLKitCommon/Frameworks\\\"\",\n\t\t\t\t\t\"\\\"${PODS_ROOT}/MLKitImageClassificationAutoML/Frameworks\\\"\",\n\t\t\t\t\t\"\\\"${PODS_ROOT}/MLKitLinkFirebase/Frameworks\\\"\",\n\t\t\t\t\t\"\\\"${PODS_ROOT}/MLKitVision/Frameworks\\\"\",\n\t\t\t\t\t\"\\\"${PODS_ROOT}/TensorFlowLiteC/Frameworks\\\"\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/AutoMLExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.AutoMLExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBB287B4920729CE90069707A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = arm64;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/AutoMLExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.AutoMLExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t10E1150F20E5CBAE0013E4A4 /* Build configuration list for PBXNativeTarget \"AutoMLExampleObjC\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t10E1150920E5CBAE0013E4A4 /* Debug */,\n\t\t\t\t10E1150A20E5CBAE0013E4A4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBB287B3020729CE90069707A /* Build configuration list for PBXProject \"AutoMLExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBB287B4520729CE90069707A /* Debug */,\n\t\t\t\tBB287B4620729CE90069707A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBB287B4720729CE90069707A /* Build configuration list for PBXNativeTarget \"AutoMLExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBB287B4820729CE90069707A /* Debug */,\n\t\t\t\tBB287B4920729CE90069707A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = BB287B2D20729CE90069707A /* Project object */;\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/AppDelegate.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property(nonatomic, strong) UIWindow *window;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/AppDelegate.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"AppDelegate.h\"\n\n@import FirebaseCore;\n\n@interface AppDelegate ()\n@end\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application\n    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n  [FIRApp configure];\n  return YES;\n}\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/CameraViewController.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface CameraViewController : UIViewController\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/CameraViewController.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"CameraViewController.h\"\n#import <AVFoundation/AVFoundation.h>\n#import <CoreImage/CoreImage.h>\n#import <CoreVideo/CoreVideo.h>\n#import \"UIUtilities.h\"\n\n@import MLKit;\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic NSString *const alertControllerTitle = @\"Vision Detectors\";\nstatic NSString *const alertControllerMessage = @\"Select a detector\";\nstatic NSString *const cancelActionTitleText = @\"Cancel\";\nstatic NSString *const videoDataOutputQueueLabel = @\"com.google.mlkit.automl.VideoDataOutputQueue\";\nstatic NSString *const sessionQueueLabel = @\"com.google.mlkit.automl.SessionQueue\";\nstatic NSString *const noResultsMessage = @\"No Results\";\n\n/** Name of the remote AutoML model. */\nstatic NSString *const MLKRemoteAutoMLModelName = @\"remote_automl_model\";\n\n/** Filename of AutoML local model manifest in the main resource bundle. */\nstatic NSString *const MLKAutoMLLocalModelManifestFilename = @\"automl_labeler_manifest\";\n\n/** File type of AutoML local model manifest in the main resource bundle. */\nstatic NSString *const MLKAutoMLManifestFileType = @\"json\";\n\nstatic const float kLabelConfidenceThreshold = 0.75f;\nstatic const CGFloat kImageScale = 1.0;\nstatic const CGFloat kLayoutPadding = 10.0;\nstatic const CGFloat kResultsLabelHeight = 200.0;\nstatic const int kResultsLabelLines = 5;\n\n@interface CameraViewController () <AVCaptureVideoDataOutputSampleBufferDelegate>\n\ntypedef NS_ENUM(NSInteger, Detector) {\n  /** AutoML image label detector. */\n  DetectorImageLabelsAutoML,\n  /** AutoML object detector, single, only tracking. */\n  DetectorObjectsAutoMLSingleNoClassifier,\n  /** AutoML object detector, single, with classification. */\n  DetectorObjectsAutoMLSingleWithClassifier,\n  /** AutoML object detector, multiple, only tracking. */\n  DetectorObjectsAutoMLMultipleNoClassifier,\n  /** AutoML object detector, multiple, with classification. */\n  DetectorObjectsAutoMLMultipleWithClassifier,\n};\n\n@property(nonatomic) NSArray *detectors;\n@property(nonatomic) Detector currentDetector;\n@property(nonatomic) bool isUsingFrontCamera;\n@property(nonatomic, nonnull) AVCaptureVideoPreviewLayer *previewLayer;\n@property(nonatomic) AVCaptureSession *captureSession;\n@property(nonatomic) dispatch_queue_t sessionQueue;\n@property(nonatomic) UIView *annotationOverlayView;\n@property(nonatomic) UIImageView *previewOverlayView;\n@property(weak, nonatomic) IBOutlet UIView *cameraView;\n@property(nonatomic) CMSampleBufferRef lastFrame;\n@property(nonatomic) MLKModelManager *modelManager;\n\n@property(strong, nonatomic) IBOutlet UIProgressView *downloadProgressView;\n\n@end\n\n@implementation CameraViewController\n\n- (NSString *)stringForDetector:(Detector)detector {\n  switch (detector) {\n    case DetectorImageLabelsAutoML:\n      return @\"AutoML Image Labeling\";\n    case DetectorObjectsAutoMLSingleNoClassifier:\n      return @\"AutoML ODT, single, no labeling\";\n    case DetectorObjectsAutoMLSingleWithClassifier:\n      return @\"AutoML ODT, single, labeling\";\n    case DetectorObjectsAutoMLMultipleNoClassifier:\n      return @\"AutoML ODT, multiple, no labeling\";\n    case DetectorObjectsAutoMLMultipleWithClassifier:\n      return @\"AutoML ODT, multiple, labeling\";\n  }\n}\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  self.detectors = @[\n    @(DetectorImageLabelsAutoML),\n    @(DetectorObjectsAutoMLSingleNoClassifier),\n    @(DetectorObjectsAutoMLSingleWithClassifier),\n    @(DetectorObjectsAutoMLMultipleNoClassifier),\n    @(DetectorObjectsAutoMLMultipleWithClassifier),\n  ];\n  self.currentDetector = DetectorImageLabelsAutoML;\n  self.isUsingFrontCamera = YES;\n  self.captureSession = [[AVCaptureSession alloc] init];\n  self.sessionQueue = dispatch_queue_create(sessionQueueLabel.UTF8String, nil);\n  self.modelManager = [MLKModelManager modelManager];\n  self.previewOverlayView = [[UIImageView alloc] initWithFrame:CGRectZero];\n  self.previewOverlayView.contentMode = UIViewContentModeScaleAspectFill;\n  self.previewOverlayView.translatesAutoresizingMaskIntoConstraints = NO;\n  self.annotationOverlayView = [[UIView alloc] initWithFrame:CGRectZero];\n  self.annotationOverlayView.translatesAutoresizingMaskIntoConstraints = NO;\n\n  self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];\n  [self setUpPreviewOverlayView];\n  [self setUpAnnotationOverlayView];\n  [self setUpCaptureSessionOutput];\n  [self setUpCaptureSessionInput];\n}\n\n- (void)viewDidAppear:(BOOL)animated {\n  [super viewDidAppear:animated];\n  [self startSession];\n  [NSNotificationCenter.defaultCenter addObserver:self\n                                         selector:@selector(remoteModelDownloadDidSucceed:)\n                                             name:MLKModelDownloadDidSucceedNotification\n                                           object:nil];\n  [NSNotificationCenter.defaultCenter addObserver:self\n                                         selector:@selector(remoteModelDownloadDidFail:)\n                                             name:MLKModelDownloadDidFailNotification\n                                           object:nil];\n}\n\n- (void)viewDidDisappear:(BOOL)animated {\n  [super viewDidDisappear:animated];\n  [self stopSession];\n  // We wouldn't have needed to remove the observers if iOS 9.0+ had cleaned up the observer \"the\n  // next time it would have posted to it\" as documented here:\n  // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver\n  [NSNotificationCenter.defaultCenter removeObserver:self\n                                                name:MLKModelDownloadDidSucceedNotification\n                                              object:nil];\n  [NSNotificationCenter.defaultCenter removeObserver:self\n                                                name:MLKModelDownloadDidFailNotification\n                                              object:nil];\n}\n\n- (void)viewDidLayoutSubviews {\n  [super viewDidLayoutSubviews];\n  self.previewLayer.frame = self.cameraView.frame;\n}\n\n- (IBAction)selectDetector:(id)sender {\n  [self presentDetectorsAlertController];\n}\n\n- (IBAction)switchCamera:(id)sender {\n  self.isUsingFrontCamera = !self.isUsingFrontCamera;\n  [self removeDetectionAnnotations];\n  [self setUpCaptureSessionInput];\n}\n\n#pragma mark - AutoML Image Labeling\n\n/**\n * Detects labels on the specified image using AutoML-trained models via Custom Image Labeling API.\n *\n * @param image The input image.\n */\n- (void)detectImageLabelsInImage:(MLKVisionImage *)image {\n  [self requestAutoMLRemoteModelIfNeeded];\n\n  // [START config_automl_label]\n  MLKCommonImageLabelerOptions *options;\n  MLKCustomRemoteModel *remoteModel = (MLKCustomRemoteModel *)[self remoteModel];\n  if ([self.modelManager isModelDownloaded:remoteModel]) {\n    NSLog(@\"Use AutoML remote model.\");\n    options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];\n  } else {\n    NSLog(@\"Use AutoML local model.\");\n    NSString *localModelFilePath =\n        [[NSBundle mainBundle] pathForResource:MLKAutoMLLocalModelManifestFilename\n                                        ofType:MLKAutoMLManifestFileType];\n    if (localModelFilePath == nil) {\n      NSLog(@\"Failed to find AutoML local model manifest file: %@\",\n            MLKAutoMLLocalModelManifestFilename);\n      return;\n    }\n    MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithManifestPath:localModelFilePath];\n    options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];\n  }\n  options.confidenceThreshold = @(kLabelConfidenceThreshold);\n  // [END config_automl_label]\n\n  // [START init_automl_label]\n  MLKImageLabeler *autoMLImageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];\n  // [END init_automl_label]\n\n  // [START detect_automl_label]\n  NSError *error;\n  NSArray<MLKImageLabel *> *labels = [autoMLImageLabeler resultsInImage:image error:&error];\n\n  // [START_EXCLUDE]\n  __weak typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf updatePreviewOverlayView];\n    [strongSelf removeDetectionAnnotations];\n    // [END_EXCLUDE]\n    if (error != nil) {\n      // [START_EXCLUDE]\n      NSLog(@\"Failed to detect labels with error: %@.\", error.localizedDescription);\n      // [END_EXCLUDE]\n      return;\n    }\n\n    if (labels.count == 0) {\n      return;\n    }\n\n    // [START_EXCLUDE]\n    CGRect annotationFrame = strongSelf.annotationOverlayView.frame;\n    CGRect resultsRect =\n        CGRectMake(annotationFrame.origin.x + kLayoutPadding,\n                   annotationFrame.size.height - kLayoutPadding - kResultsLabelHeight,\n                   annotationFrame.size.width - 2 * kLayoutPadding, kResultsLabelHeight);\n    UILabel *resultsLabel = [[UILabel alloc] initWithFrame:resultsRect];\n    resultsLabel.textColor = UIColor.yellowColor;\n    NSMutableArray *labelStrings = [NSMutableArray arrayWithCapacity:labels.count];\n    for (MLKImageLabel *label in labels) {\n      [labelStrings addObject:[NSString stringWithFormat:@\"Label: %@, Confidence: %f\", label.text,\n                                                         label.confidence]];\n    }\n    resultsLabel.text = [labelStrings componentsJoinedByString:@\"\\n\"];\n    resultsLabel.adjustsFontSizeToFitWidth = YES;\n    resultsLabel.numberOfLines = kResultsLabelLines;\n    [strongSelf.annotationOverlayView addSubview:resultsLabel];\n  });\n  // [END_EXCLUDE]\n  // [END detect_automl_label]\n}\n\n- (void)detectObjectsInImage:(MLKVisionImage *)image\n                          width:(CGFloat)width\n                         height:(CGFloat)height\n     shouldEnableClassification:(BOOL)shouldEnableClassification\n    shouldEnableMultipleObjects:(BOOL)shouldEnableMultipleObjects {\n  [self requestAutoMLRemoteModelIfNeeded];\n\n  MLKCustomRemoteModel *remoteModel = (MLKCustomRemoteModel *)[self remoteModel];\n  MLKCustomObjectDetectorOptions *options;\n\n  if ([self.modelManager isModelDownloaded:remoteModel]) {\n    NSLog(@\"Use AutoML remote model.\");\n    options = [[MLKCustomObjectDetectorOptions alloc] initWithRemoteModel:remoteModel];\n  } else {\n    NSLog(@\"Use AutoML local model.\");\n    NSString *localModelFilePath =\n        [[NSBundle mainBundle] pathForResource:MLKAutoMLLocalModelManifestFilename\n                                        ofType:MLKAutoMLManifestFileType];\n    if (localModelFilePath == nil) {\n      NSLog(@\"Failed to find AutoML local model manifest file: %@\",\n            MLKAutoMLLocalModelManifestFilename);\n      return;\n    }\n    MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithManifestPath:localModelFilePath];\n    options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];\n  }\n\n  options.shouldEnableClassification = shouldEnableClassification;\n  options.shouldEnableMultipleObjects = shouldEnableMultipleObjects;\n  options.detectorMode = MLKObjectDetectorModeStream;\n  // Due to the UI space, We will only display one label per detected object.\n  options.maxPerObjectLabelCount = 1;\n\n  MLKObjectDetector *autoMLObjectDetector = [MLKObjectDetector objectDetectorWithOptions:options];\n  NSError *error;\n  NSArray<MLKObject *> *objects = [autoMLObjectDetector resultsInImage:image error:&error];\n  __weak typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf updatePreviewOverlayView];\n    [strongSelf removeDetectionAnnotations];\n    if (error != nil) {\n      NSLog(@\"Failed to detect object with error: %@\", error.localizedDescription);\n      return;\n    }\n    if (objects.count == 0) {\n      NSLog(@\"Object detector returned no results.\");\n      return;\n    }\n    for (MLKObject *object in objects) {\n      NSMutableString *description = [[NSMutableString alloc] init];\n      CGRect normalizedRect =\n          CGRectMake(object.frame.origin.x / width, object.frame.origin.y / height,\n                     object.frame.size.width / width, object.frame.size.height / height);\n      CGRect standardizedRect = CGRectStandardize(\n          [strongSelf.previewLayer rectForMetadataOutputRectOfInterest:normalizedRect]);\n      [UIUtilities addRectangle:standardizedRect\n                         toView:strongSelf.annotationOverlayView\n                          color:UIColor.greenColor];\n      UILabel *label = [[UILabel alloc] initWithFrame:standardizedRect];\n      if (object.trackingID != nil) {\n        [description appendFormat:@\"Object ID: %@\\n\", object.trackingID];\n      }\n\n      [description appendString:@\"Labels:\\n\"];\n      int i = 0;\n      for (MLKObjectLabel *l in object.labels) {\n        NSString *labelString = [NSString stringWithFormat:@\"Label %d: %@, %f, %lu\\n\", i++, l.text,\n                                                           l.confidence, (unsigned long)l.index];\n        [description appendString:labelString];\n      }\n      label.text = description;\n      label.numberOfLines = 0;\n      label.adjustsFontSizeToFitWidth = YES;\n      [strongSelf.annotationOverlayView addSubview:label];\n    }\n  });\n}\n\n- (void)requestAutoMLRemoteModelIfNeeded {\n  MLKRemoteModel *remoteModel = [self remoteModel];\n  if ([self.modelManager isModelDownloaded:remoteModel]) {\n    return;\n  }\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    strongSelf.downloadProgressView.hidden = NO;\n    MLKModelDownloadConditions *conditions =\n        [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES\n                                             allowsBackgroundDownloading:YES];\n    strongSelf.downloadProgressView.observedProgress =\n        [strongSelf.modelManager downloadModel:remoteModel conditions:conditions];\n    NSLog(@\"Start downloading AutoML remote model.\");\n  });\n}\n\n#pragma mark - Notifications\n\n- (void)remoteModelDownloadDidSucceed:(NSNotification *)notification {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    strongSelf.downloadProgressView.hidden = YES;\n    MLKRemoteModel *remotemodel = notification.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];\n    if (remotemodel == nil) {\n      NSLog(@\"MLKitModelDownloadDidSucceed notification posted without a RemoteModel instance.\");\n      return;\n    }\n    NSLog(@\"Successfully downloaded the remote model with name: %@. The model is ready for \"\n          @\"detection.\",\n          remotemodel.name);\n  });\n}\n\n- (void)remoteModelDownloadDidFail:(NSNotification *)notification {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    strongSelf.downloadProgressView.hidden = YES;\n    MLKRemoteModel *remoteModel = notification.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];\n    NSError *error = notification.userInfo[MLKModelDownloadUserInfoKeyError];\n    if (error == nil) {\n      NSLog(@\"MLKitModelDownloadDidFail notification posted without a RemoteModel instance or \"\n            @\"error.\");\n      return;\n    }\n    NSLog(@\"Failed to download the remote model with name: %@, error: %@.\", remoteModel,\n          error.localizedDescription);\n  });\n}\n\n#pragma mark - Private\n\n- (MLKRemoteModel *)remoteModel {\n  MLKFirebaseModelSource *firebaseModelSource =\n      [[MLKFirebaseModelSource alloc] initWithName:MLKRemoteAutoMLModelName];\n  return [[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];\n}\n\n- (void)setUpCaptureSessionOutput {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(self.sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf.captureSession beginConfiguration];\n    // When performing latency tests to determine ideal capture settings,\n    // run the app in 'release' mode to get accurate performance metrics\n    strongSelf.captureSession.sessionPreset = AVCaptureSessionPresetMedium;\n\n    AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];\n    output.videoSettings = @{\n      (id)\n      kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]\n    };\n    dispatch_queue_t outputQueue = dispatch_queue_create(videoDataOutputQueueLabel.UTF8String, nil);\n    [output setSampleBufferDelegate:strongSelf queue:outputQueue];\n    if ([strongSelf.captureSession canAddOutput:output]) {\n      [strongSelf.captureSession addOutput:output];\n      [strongSelf.captureSession commitConfiguration];\n    } else {\n      NSLog(@\"%@\", @\"Failed to add capture session output.\");\n    }\n  });\n}\n\n- (void)setUpCaptureSessionInput {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(self.sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    AVCaptureDevicePosition cameraPosition =\n        strongSelf.isUsingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;\n    AVCaptureDevice *device = [strongSelf captureDeviceForPosition:cameraPosition];\n    if (device) {\n      [strongSelf.captureSession beginConfiguration];\n      NSArray<AVCaptureInput *> *currentInputs = strongSelf.captureSession.inputs;\n      for (AVCaptureInput *input in currentInputs) {\n        [strongSelf.captureSession removeInput:input];\n      }\n      NSError *error;\n      AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device\n                                                                          error:&error];\n      if (error) {\n        NSLog(@\"Failed to create capture device input: %@\", error.localizedDescription);\n        return;\n      } else {\n        if ([strongSelf.captureSession canAddInput:input]) {\n          [strongSelf.captureSession addInput:input];\n        } else {\n          NSLog(@\"%@\", @\"Failed to add capture session input.\");\n        }\n      }\n      [strongSelf.captureSession commitConfiguration];\n    } else {\n      NSLog(@\"Failed to get capture device for camera position: %ld\", cameraPosition);\n    }\n  });\n}\n\n- (void)startSession {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(self.sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf.captureSession startRunning];\n  });\n}\n\n- (void)stopSession {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(self.sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf.captureSession stopRunning];\n  });\n}\n\n- (void)setUpPreviewOverlayView {\n  [self.cameraView addSubview:self.previewOverlayView];\n  [NSLayoutConstraint activateConstraints:@[\n    [self.previewOverlayView.centerYAnchor constraintEqualToAnchor:self.cameraView.centerYAnchor],\n    [self.previewOverlayView.centerXAnchor constraintEqualToAnchor:self.cameraView.centerXAnchor],\n    [self.previewOverlayView.leadingAnchor constraintEqualToAnchor:self.cameraView.leadingAnchor],\n    [self.previewOverlayView.trailingAnchor constraintEqualToAnchor:self.cameraView.trailingAnchor]\n  ]];\n}\n- (void)setUpAnnotationOverlayView {\n  [self.cameraView addSubview:self.annotationOverlayView];\n  [NSLayoutConstraint activateConstraints:@[\n    [self.annotationOverlayView.topAnchor constraintEqualToAnchor:self.cameraView.topAnchor],\n    [self.annotationOverlayView.leadingAnchor\n        constraintEqualToAnchor:self.cameraView.leadingAnchor],\n    [self.annotationOverlayView.trailingAnchor\n        constraintEqualToAnchor:self.cameraView.trailingAnchor],\n    [self.annotationOverlayView.bottomAnchor constraintEqualToAnchor:self.cameraView.bottomAnchor]\n  ]];\n}\n\n- (AVCaptureDevice *)captureDeviceForPosition:(AVCaptureDevicePosition)position {\n  if (@available(iOS 10, *)) {\n    AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession\n        discoverySessionWithDeviceTypes:@[ AVCaptureDeviceTypeBuiltInWideAngleCamera ]\n                              mediaType:AVMediaTypeVideo\n                               position:AVCaptureDevicePositionUnspecified];\n    for (AVCaptureDevice *device in discoverySession.devices) {\n      if (device.position == position) {\n        return device;\n      }\n    }\n  }\n  return nil;\n}\n\n- (void)presentDetectorsAlertController {\n  UIAlertController *alertController =\n      [UIAlertController alertControllerWithTitle:alertControllerTitle\n                                          message:alertControllerMessage\n                                   preferredStyle:UIAlertControllerStyleAlert];\n  for (NSNumber *detectorType in self.detectors) {\n    NSInteger detector = detectorType.integerValue;\n    __weak typeof(self) weakSelf = self;\n    UIAlertAction *action = [UIAlertAction actionWithTitle:[self stringForDetector:detector]\n                                                     style:UIAlertActionStyleDefault\n                                                   handler:^(UIAlertAction *_Nonnull action) {\n                                                     __strong typeof(weakSelf) strongSelf =\n                                                         weakSelf;\n                                                     strongSelf.currentDetector = detector;\n                                                     [strongSelf removeDetectionAnnotations];\n                                                   }];\n    if (detector == self.currentDetector) {\n      [action setEnabled:NO];\n    }\n    [alertController addAction:action];\n  }\n  [alertController addAction:[UIAlertAction actionWithTitle:cancelActionTitleText\n                                                      style:UIAlertActionStyleCancel\n                                                    handler:nil]];\n  [self presentViewController:alertController animated:YES completion:nil];\n}\n\n- (void)removeDetectionAnnotations {\n  for (UIView *annotationView in self.annotationOverlayView.subviews) {\n    [annotationView removeFromSuperview];\n  }\n}\n\n- (void)updatePreviewOverlayView {\n  CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(self.lastFrame);\n  if (imageBuffer == nil) {\n    return;\n  }\n  CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer];\n  CIContext *context = [[CIContext alloc] initWithOptions:nil];\n  CGImageRef cgImage = [context createCGImage:ciImage fromRect:ciImage.extent];\n  if (cgImage == nil) {\n    return;\n  }\n  UIImage *rotatedImage = [UIImage imageWithCGImage:cgImage\n                                              scale:kImageScale\n                                        orientation:UIImageOrientationRight];\n  if (self.isUsingFrontCamera) {\n    CGImageRef rotatedCGImage = rotatedImage.CGImage;\n    if (rotatedCGImage == nil) {\n      return;\n    }\n    UIImage *mirroredImage = [UIImage imageWithCGImage:rotatedCGImage\n                                                 scale:kImageScale\n                                           orientation:UIImageOrientationLeftMirrored];\n    self.previewOverlayView.image = mirroredImage;\n  } else {\n    self.previewOverlayView.image = rotatedImage;\n  }\n  CGImageRelease(cgImage);\n}\n\n- (NSArray<NSValue *> *)convertedPointsFromPoints:(NSArray<NSValue *> *)points\n                                            width:(CGFloat)width\n                                           height:(CGFloat)height {\n  NSMutableArray *result = [NSMutableArray arrayWithCapacity:points.count];\n  for (NSValue *point in points) {\n    CGPoint cgPointValue = point.CGPointValue;\n    CGPoint normalizedPoint = CGPointMake(cgPointValue.x / width, cgPointValue.y / height);\n    CGPoint cgPoint = [self.previewLayer pointForCaptureDevicePointOfInterest:normalizedPoint];\n    [result addObject:[NSValue valueWithCGPoint:cgPoint]];\n  }\n  return result;\n}\n\n#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate\n\n- (void)captureOutput:(AVCaptureOutput *)output\n    didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer\n           fromConnection:(AVCaptureConnection *)connection {\n  CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);\n  if (imageBuffer == nil) {\n    NSLog(@\"%@\", @\"Failed to get image buffer from sample buffer.\");\n    return;\n  }\n\n  // Evaluate `self.currentDetector` once to ensure consistency throughout this method since it\n  // can be concurrently modified from the main thread.\n  Detector activeDetector = self.currentDetector;\n  self.lastFrame = sampleBuffer;\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];\n  UIImageOrientation orientation = [UIUtilities\n      imageOrientationFromDevicePosition:self.isUsingFrontCamera ? AVCaptureDevicePositionFront\n                                                                 : AVCaptureDevicePositionBack];\n\n  visionImage.orientation = orientation;\n  CGFloat imageWidth = CVPixelBufferGetWidth(imageBuffer);\n  CGFloat imageHeight = CVPixelBufferGetHeight(imageBuffer);\n\n  BOOL shouldEnableClassification = NO;\n  BOOL shouldEnableMultipleObjects = NO;\n  switch (activeDetector) {\n    case DetectorObjectsAutoMLSingleWithClassifier:\n    case DetectorObjectsAutoMLMultipleWithClassifier:\n      shouldEnableClassification = YES;\n    default:\n      break;\n  }\n  switch (activeDetector) {\n    case DetectorObjectsAutoMLMultipleNoClassifier:\n    case DetectorObjectsAutoMLMultipleWithClassifier:\n      shouldEnableMultipleObjects = YES;\n    default:\n      break;\n  }\n\n  switch (activeDetector) {\n    case DetectorImageLabelsAutoML:\n      [self detectImageLabelsInImage:visionImage];\n      break;\n    case DetectorObjectsAutoMLSingleNoClassifier:\n    case DetectorObjectsAutoMLSingleWithClassifier:\n    case DetectorObjectsAutoMLMultipleNoClassifier:\n    case DetectorObjectsAutoMLMultipleWithClassifier:\n      [self detectObjectsInImage:visionImage\n                                width:imageWidth\n                               height:imageHeight\n           shouldEnableClassification:shouldEnableClassification\n          shouldEnableMultipleObjects:shouldEnableMultipleObjects];\n      break;\n  }\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/UIImage+VisionDetection.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** A `UIImage` category used for vision detection. */\n@interface UIImage (VisionDetection)\n\n- (UIImage *)scaledImageWithSize:(CGSize)size;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/UIImage+VisionDetection.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"UIImage+VisionDetection.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation UIImage (VisionDetection)\n\n/**\n * Returns a scaled image to the given size.\n *\n * @param size Maximum size of the returned image.\n * @return Image scaled according to the give size or `nil` if resizing image failed.\n */\n- (UIImage *)scaledImageWithSize:(CGSize)size {\n  UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);\n  [self drawInRect:CGRectMake(0, 0, size.width, size.height)];\n  UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();\n  UIGraphicsEndImageContext();\n\n  // Attempt to convert the scaled image to PNG or JPEG data to preserve the bitmap info.\n  if (!scaledImage) {\n    return nil;\n  }\n  NSData *imageData = UIImagePNGRepresentation(scaledImage);\n  if (!imageData) {\n    imageData = UIImageJPEGRepresentation(scaledImage, 0.8);\n  }\n  return [UIImage imageWithData:imageData];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/UIUtilities.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <AVFoundation/AVFoundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface UIUtilities : NSObject\n\n+ (void)addCircleAtPoint:(CGPoint)point\n                  toView:(UIView *)view\n                   color:(UIColor *)color\n                  radius:(CGFloat)radius;\n\n+ (void)addRectangle:(CGRect)rectangle toView:(UIView *)view color:(UIColor *)color;\n+ (void)addShapeWithPoints:(NSArray<NSValue *> *)points\n                    toView:(UIView *)view\n                     color:(UIColor *)color;\n+ (UIImageOrientation)imageOrientation;\n+ (UIImageOrientation)imageOrientationFromDevicePosition:(AVCaptureDevicePosition)devicePosition;\n+ (UIDeviceOrientation)currentUIOrientation;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/UIUtilities.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"UIUtilities.h\"\n\nstatic CGFloat const circleViewAlpha = 0.7;\nstatic CGFloat const rectangleViewAlpha = 0.3;\nstatic CGFloat const shapeViewAlpha = 0.3;\nstatic CGFloat const rectangleViewCornerRadius = 10.0;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation UIUtilities\n\n+ (void)addCircleAtPoint:(CGPoint)point\n                  toView:(UIView *)view\n                   color:(UIColor *)color\n                  radius:(CGFloat)radius {\n  CGFloat divisor = 2.0;\n  CGFloat xCoord = point.x - radius / divisor;\n  CGFloat yCoord = point.y - radius / divisor;\n  CGRect circleRect = CGRectMake(xCoord, yCoord, radius, radius);\n  UIView *circleView = [[UIView alloc] initWithFrame:circleRect];\n  circleView.layer.cornerRadius = radius / divisor;\n  circleView.alpha = circleViewAlpha;\n  circleView.backgroundColor = color;\n  [view addSubview:circleView];\n}\n\n+ (void)addRectangle:(CGRect)rectangle toView:(UIView *)view color:(UIColor *)color {\n  UIView *rectangleView = [[UIView alloc] initWithFrame:rectangle];\n  rectangleView.layer.cornerRadius = rectangleViewCornerRadius;\n  rectangleView.alpha = rectangleViewAlpha;\n  rectangleView.backgroundColor = color;\n  rectangleView.accessibilityIdentifier = @\"MLKit Rectangle View\";\n  [view addSubview:rectangleView];\n}\n\n+ (void)addShapeWithPoints:(NSArray<NSValue *> *)points\n                    toView:(UIView *)view\n                     color:(UIColor *)color {\n  UIBezierPath *path = [UIBezierPath new];\n  for (int i = 0; i < [points count]; i++) {\n    CGPoint point = points[i].CGPointValue;\n    if (i == 0) {\n      [path moveToPoint:point];\n    } else {\n      [path addLineToPoint:point];\n    }\n    if (i == points.count - 1) {\n      [path closePath];\n    }\n  }\n  CAShapeLayer *shapeLayer = [CAShapeLayer new];\n  shapeLayer.path = path.CGPath;\n  shapeLayer.fillColor = color.CGColor;\n  CGRect rect = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height);\n  UIView *shapeView = [[UIView alloc] initWithFrame:rect];\n  shapeView.alpha = shapeViewAlpha;\n  [shapeView.layer addSublayer:shapeLayer];\n  [view addSubview:shapeView];\n}\n\n+ (UIImageOrientation)imageOrientation {\n  return [self imageOrientationFromDevicePosition:AVCaptureDevicePositionBack];\n}\n\n+ (UIImageOrientation)imageOrientationFromDevicePosition:(AVCaptureDevicePosition)devicePosition {\n  UIDeviceOrientation deviceOrientation = UIDevice.currentDevice.orientation;\n  if (deviceOrientation == UIDeviceOrientationFaceDown ||\n      deviceOrientation == UIDeviceOrientationFaceUp ||\n      deviceOrientation == UIDeviceOrientationUnknown) {\n    deviceOrientation = [self currentUIOrientation];\n  }\n  switch (deviceOrientation) {\n    case UIDeviceOrientationPortrait:\n      return devicePosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored\n                                                            : UIImageOrientationRight;\n    case UIDeviceOrientationLandscapeLeft:\n      return devicePosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored\n                                                            : UIImageOrientationUp;\n    case UIDeviceOrientationPortraitUpsideDown:\n      return devicePosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored\n                                                            : UIImageOrientationLeft;\n    case UIDeviceOrientationLandscapeRight:\n      return devicePosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored\n                                                            : UIImageOrientationDown;\n    case UIDeviceOrientationFaceDown:\n    case UIDeviceOrientationFaceUp:\n    case UIDeviceOrientationUnknown:\n      return UIImageOrientationUp;\n  }\n}\n\n+ (UIDeviceOrientation)currentUIOrientation {\n  UIDeviceOrientation (^deviceOrientation)(void) = ^UIDeviceOrientation(void) {\n    switch (UIApplication.sharedApplication.statusBarOrientation) {\n      case UIInterfaceOrientationLandscapeLeft:\n        return UIDeviceOrientationLandscapeRight;\n      case UIInterfaceOrientationLandscapeRight:\n        return UIDeviceOrientationLandscapeLeft;\n      case UIInterfaceOrientationPortraitUpsideDown:\n        return UIDeviceOrientationPortraitUpsideDown;\n      case UIInterfaceOrientationPortrait:\n      case UIInterfaceOrientationUnknown:\n        return UIDeviceOrientationPortrait;\n    }\n  };\n\n  if (NSThread.isMainThread) {\n    return deviceOrientation();\n  } else {\n    __block UIDeviceOrientation currentOrientation = UIDeviceOrientationPortrait;\n    dispatch_sync(dispatch_get_main_queue(), ^{\n      currentOrientation = deviceOrientation();\n    });\n    return currentOrientation;\n  }\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/ViewController.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ViewController : UIViewController\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/ViewController.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"ViewController.h\"\n#import \"UIImage+VisionDetection.h\"\n#import \"UIUtilities.h\"\n\n@import MLKit;\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic NSArray *images;\nstatic NSString *const ModelExtension = @\"tflite\";\nstatic NSString *const quantizedModelFilename = @\"mobilenet_quant_v1_224\";\n\nstatic NSString *const detectionNoResultsMessage = @\"No results returned.\";\n\n/** Name of the local AutoML model. */\nstatic NSString *const MLKLocalAutoMLModelName = @\"local_automl_model\";\n\n/** Name of the remote AutoML model. */\nstatic NSString *const MLKRemoteAutoMLModelName = @\"remote_automl_model\";\n\n/** Filename of AutoML local model manifest in the main resource bundle. */\nstatic NSString *const MLKAutoMLLocalModelManifestFilename = @\"automl_labeler_manifest\";\n\n/** File type of AutoML local model manifest in the main resource bundle. */\nstatic NSString *const MLKAutoMLManifestFileType = @\"json\";\n\nstatic float const labelConfidenceThreshold = 0.75f;\nstatic CGColorRef lineColor;\nstatic CGColorRef fillColor;\n\nstatic int const rowsCount = 5;\nstatic int const componentsCount = 1;\n\n/**\n * @enum DetectorPickerRow\n * Defines the MLKit detector types.\n */\ntypedef NS_ENUM(NSInteger, DetectorPickerRow) {\n  /** AutoML image label detector. */\n  DetectorPickerRowDetectImageLabelsAutoML,\n  /** AutoML object detector, single, only tracking. */\n  DetectorPickerRowDetectObjectsAutoMLSingleNoClassifier,\n  /** AutoML object detector, single, with classification. */\n  DetectorPickerRowDetectObjectsAutoMLSingleWithClassifier,\n  /** AutoML object detector, multiple, only tracking. */\n  DetectorPickerRowDetectObjectsAutoMLMultipleNoClassifier,\n  /** AutoML object detector, multiple, with classification. */\n  DetectorPickerRowDetectObjectsAutoMLMultipleWithClassifier,\n};\n\n@interface ViewController () <UINavigationControllerDelegate,\n                              UIPickerViewDelegate,\n                              UIPickerViewDataSource,\n                              UIImagePickerControllerDelegate>\n\n@property(nonatomic) MLKModelManager *modelManager;\n\n/** A string holding current results from detection. */\n@property(nonatomic) NSMutableString *resultsText;\n\n/** An overlay view that displays detection annotations. */\n@property(nonatomic) UIView *annotationOverlayView;\n\n/** An image picker for accessing the photo library or camera. */\n@property(nonatomic) UIImagePickerController *imagePicker;\n@property(weak, nonatomic) IBOutlet UIBarButtonItem *detectButton;\n@property(strong, nonatomic) IBOutlet UIProgressView *downloadProgressView;\n\n// Image counter.\n@property(nonatomic) NSUInteger currentImage;\n\n@property(weak, nonatomic) IBOutlet UIPickerView *detectorPicker;\n@property(weak, nonatomic) IBOutlet UIImageView *imageView;\n@property(weak, nonatomic) IBOutlet UIBarButtonItem *photoCameraButton;\n@property(weak, nonatomic) IBOutlet UIBarButtonItem *videoCameraButton;\n@property(weak, nonatomic) IBOutlet UIBarButtonItem *downloadOrDeleteModelButton;\n\n@end\n\n@implementation ViewController\n\n- (NSString *)stringForDetectorPickerRow:(DetectorPickerRow)detectorPickerRow {\n  switch (detectorPickerRow) {\n    case DetectorPickerRowDetectImageLabelsAutoML:\n      return @\"AutoML Image Labeling\";\n    case DetectorPickerRowDetectObjectsAutoMLSingleNoClassifier:\n      return @\"AutoML ODT, single, no labeling\";\n    case DetectorPickerRowDetectObjectsAutoMLSingleWithClassifier:\n      return @\"AutoML ODT, single, labeling\";\n    case DetectorPickerRowDetectObjectsAutoMLMultipleNoClassifier:\n      return @\"AutoML ODT, multiple, no labeling\";\n    case DetectorPickerRowDetectObjectsAutoMLMultipleWithClassifier:\n      return @\"AutoML ODT, multiple, labeling\";\n  }\n}\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n\n  images = @[\n    @\"dandelion.jpg\",\n    @\"sunflower.jpg\",\n    @\"tulips.jpeg\",\n    @\"daisy.jpeg\",\n    @\"roses.jpeg\",\n  ];\n  lineColor = UIColor.yellowColor.CGColor;\n  fillColor = UIColor.clearColor.CGColor;\n\n  self.modelManager = [MLKModelManager modelManager];\n  MLKRemoteModel *remoteModel = [self remoteModel];\n  NSString *buttonImage =\n      [self.modelManager isModelDownloaded:remoteModel] ? @\"delete\" : @\"cloud_download\";\n  self.downloadOrDeleteModelButton.image = [UIImage imageNamed:buttonImage];\n\n  self.imagePicker = [UIImagePickerController new];\n  self.resultsText = [NSMutableString new];\n  self.currentImage = 0;\n  self.imageView.image = [UIImage imageNamed:images[self.currentImage]];\n  self.annotationOverlayView = [[UIView alloc] initWithFrame:CGRectZero];\n  self.annotationOverlayView.translatesAutoresizingMaskIntoConstraints = NO;\n  [self.imageView addSubview:self.annotationOverlayView];\n  [NSLayoutConstraint activateConstraints:@[\n    [self.annotationOverlayView.topAnchor constraintEqualToAnchor:self.imageView.topAnchor],\n    [self.annotationOverlayView.leadingAnchor constraintEqualToAnchor:self.imageView.leadingAnchor],\n    [self.annotationOverlayView.trailingAnchor\n        constraintEqualToAnchor:self.imageView.trailingAnchor],\n    [self.annotationOverlayView.bottomAnchor constraintEqualToAnchor:self.imageView.bottomAnchor]\n  ]];\n  self.imagePicker.delegate = self;\n  self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;\n\n  self.detectorPicker.delegate = self;\n  self.detectorPicker.dataSource = self;\n\n  BOOL isCameraAvailable =\n      [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront] ||\n      [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear];\n  if (isCameraAvailable) {\n    // `CameraViewController` uses `AVCaptureDeviceDiscoverySession` which is only supported for\n    // iOS 10 or newer.\n    if (@available(iOS 10, *)) {\n      [self.videoCameraButton setEnabled:YES];\n    }\n  } else {\n    [self.photoCameraButton setEnabled:NO];\n  }\n  [self.detectorPicker selectRow:0 inComponent:0 animated:NO];\n}\n\n- (void)viewWillAppear:(BOOL)animated {\n  [super viewWillAppear:animated];\n  [self.navigationController.navigationBar setHidden:YES];\n  [NSNotificationCenter.defaultCenter addObserver:self\n                                         selector:@selector(remoteModelDownloadDidSucceed:)\n                                             name:MLKModelDownloadDidSucceedNotification\n                                           object:nil];\n  [NSNotificationCenter.defaultCenter addObserver:self\n                                         selector:@selector(remoteModelDownloadDidFail:)\n                                             name:MLKModelDownloadDidFailNotification\n                                           object:nil];\n}\n\n- (void)viewWillDisappear:(BOOL)animated {\n  [super viewWillDisappear:animated];\n  [self.navigationController.navigationBar setHidden:NO];\n  // We wouldn't have needed to remove the observers if iOS 9.0+ had cleaned up the observer \"the\n  // next time it would have posted to it\" as documented here:\n  // https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver\n  [NSNotificationCenter.defaultCenter removeObserver:self\n                                                name:MLKModelDownloadDidSucceedNotification\n                                              object:nil];\n  [NSNotificationCenter.defaultCenter removeObserver:self\n                                                name:MLKModelDownloadDidFailNotification\n                                              object:nil];\n}\n\n- (IBAction)detect:(id)sender {\n  [self clearResults];\n  NSInteger rowIndex = [self.detectorPicker selectedRowInComponent:0];\n  BOOL shouldEnableClassification =\n      rowIndex == DetectorPickerRowDetectObjectsAutoMLSingleWithClassifier ||\n      rowIndex == DetectorPickerRowDetectObjectsAutoMLMultipleWithClassifier;\n  BOOL shouldEnableMultipleObjects =\n      rowIndex == DetectorPickerRowDetectObjectsAutoMLMultipleNoClassifier ||\n      rowIndex == DetectorPickerRowDetectObjectsAutoMLMultipleWithClassifier;\n  switch (rowIndex) {\n    case DetectorPickerRowDetectImageLabelsAutoML:\n      [self detectImageLabelsInImage:self.imageView.image];\n      break;\n    case DetectorPickerRowDetectObjectsAutoMLSingleNoClassifier:\n    case DetectorPickerRowDetectObjectsAutoMLSingleWithClassifier:\n    case DetectorPickerRowDetectObjectsAutoMLMultipleNoClassifier:\n    case DetectorPickerRowDetectObjectsAutoMLMultipleWithClassifier:\n      [self detectObjectsInImage:self.imageView.image\n           shouldEnableClassification:shouldEnableClassification\n          shouldEnableMultipleObjects:shouldEnableMultipleObjects];\n      break;\n  }\n}\n\n- (IBAction)openPhotoLibrary:(id)sender {\n  self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;\n  [self presentViewController:self.imagePicker animated:YES completion:nil];\n}\n\n- (IBAction)openCamera:(id)sender {\n  if (![UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront] &&\n      ![UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]) {\n    return;\n  }\n  self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;\n  [self presentViewController:self.imagePicker animated:YES completion:nil];\n}\n\n- (IBAction)changeImage:(id)sender {\n  [self clearResults];\n  self.currentImage = (self.currentImage + 1) % images.count;\n  self.imageView.image = [UIImage imageNamed:images[self.currentImage]];\n}\n\n- (IBAction)downloadOrDeleteModel:(id)sender {\n  [self clearResults];\n  MLKRemoteModel *remoteModel = [self remoteModel];\n  if ([self.modelManager isModelDownloaded:remoteModel]) {\n    __weak typeof(self) weakSelf = self;\n    [self.modelManager\n        deleteDownloadedModel:remoteModel\n                   completion:^(NSError *_Nullable error) {\n                     if (error) {\n                       NSLog(@\"Failed to delete the AutoML model.\");\n                       return;\n                     }\n                     __strong typeof(weakSelf) strongSelf = weakSelf;\n                     NSLog(@\"The downloaded remote model has been successfully deleted.\");\n                     strongSelf.downloadOrDeleteModelButton.image =\n                         [UIImage imageNamed:@\"cloud_download\"];\n                   }];\n  } else {\n    [self requestAutoMLRemoteModelIfNeeded];\n  }\n}\n\n#pragma mark - Private\n\n- (MLKRemoteModel *)remoteModel {\n  MLKFirebaseModelSource *firebaseModelSource =\n      [[MLKFirebaseModelSource alloc] initWithName:MLKRemoteAutoMLModelName];\n  return [[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];\n}\n\n/** Removes the detection annotations from the annotation overlay view. */\n- (void)removeDetectionAnnotations {\n  for (UIView *annotationView in self.annotationOverlayView.subviews) {\n    [annotationView removeFromSuperview];\n  }\n}\n\n/** Clears the results text view and removes any frames that are visible. */\n- (void)clearResults {\n  [self removeDetectionAnnotations];\n  self.resultsText = [NSMutableString new];\n}\n\n- (void)showResults {\n  UIAlertController *resultsAlertController =\n      [UIAlertController alertControllerWithTitle:@\"Detection Results\"\n                                          message:nil\n                                   preferredStyle:UIAlertControllerStyleActionSheet];\n  [resultsAlertController\n      addAction:[UIAlertAction actionWithTitle:@\"OK\"\n                                         style:UIAlertActionStyleDestructive\n                                       handler:^(UIAlertAction *_Nonnull action) {\n                                         [resultsAlertController dismissViewControllerAnimated:YES\n                                                                                    completion:nil];\n                                       }]];\n  resultsAlertController.message = self.resultsText;\n  resultsAlertController.popoverPresentationController.barButtonItem = self.detectButton;\n  resultsAlertController.popoverPresentationController.sourceView = self.view;\n  [self presentViewController:resultsAlertController animated:YES completion:nil];\n  NSLog(@\"%@\", self.resultsText);\n}\n\n/**\n * Updates the image view with a scaled version of the given image.\n *\n * @param image The image to scale and use for updating the image view.\n */\n- (void)updateImageViewWithImage:(UIImage *)image {\n  CGFloat scaledImageWidth = 0.0;\n  CGFloat scaledImageHeight = 0.0;\n  switch (UIApplication.sharedApplication.statusBarOrientation) {\n    case UIInterfaceOrientationPortrait:\n    case UIInterfaceOrientationPortraitUpsideDown:\n    case UIInterfaceOrientationUnknown:\n      scaledImageWidth = self.imageView.bounds.size.width;\n      scaledImageHeight = image.size.height * scaledImageWidth / image.size.width;\n      break;\n    case UIInterfaceOrientationLandscapeLeft:\n    case UIInterfaceOrientationLandscapeRight:\n      scaledImageWidth = image.size.width * scaledImageHeight / image.size.height;\n      scaledImageHeight = self.imageView.bounds.size.height;\n      break;\n  }\n\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{\n    // Scale image while maintaining aspect ratio so it displays better in the UIImageView.\n    UIImage *scaledImage =\n        [image scaledImageWithSize:CGSizeMake(scaledImageWidth, scaledImageHeight)];\n    if (!scaledImage) {\n      scaledImage = image;\n    }\n    if (!scaledImage) {\n      return;\n    }\n    dispatch_async(dispatch_get_main_queue(), ^{\n      __strong typeof(weakSelf) strongSelf = weakSelf;\n      strongSelf.imageView.image = scaledImage;\n    });\n  });\n}\n\n#pragma mark - UIPickerViewDataSource\n\n- (NSInteger)numberOfComponentsInPickerView:(nonnull UIPickerView *)pickerView {\n  return componentsCount;\n}\n\n- (NSInteger)pickerView:(nonnull UIPickerView *)pickerView\n    numberOfRowsInComponent:(NSInteger)component {\n  return rowsCount;\n}\n\n#pragma mark - UIPickerViewDelegate\n\n- (nullable NSString *)pickerView:(UIPickerView *)pickerView\n                      titleForRow:(NSInteger)row\n                     forComponent:(NSInteger)component {\n  return [self stringForDetectorPickerRow:row];\n}\n\n- (void)pickerView:(UIPickerView *)pickerView\n      didSelectRow:(NSInteger)row\n       inComponent:(NSInteger)component {\n  [self clearResults];\n}\n\n#pragma mark - UIImagePickerControllerDelegate\n\n- (void)imagePickerController:(UIImagePickerController *)picker\n    didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info {\n  [self clearResults];\n  UIImage *pickedImage = info[UIImagePickerControllerOriginalImage];\n  if (pickedImage) {\n    [self updateImageViewWithImage:pickedImage];\n  }\n  [self dismissViewControllerAnimated:YES completion:nil];\n}\n\n#pragma mark - AutoML Detections\n\n/**\n * Detects labels on the specified image using image classification models trained by AutoML via\n * Custom Image Labeling API.\n *\n * @param image The input image.\n */\n- (void)detectImageLabelsInImage:(UIImage *)image {\n  if (!image) {\n    return;\n  }\n  [self requestAutoMLRemoteModelIfNeeded];\n\n  // [START config_automl_label]\n  MLKCommonImageLabelerOptions *options;\n  MLKCustomRemoteModel *remoteModel = (MLKCustomRemoteModel *)[self remoteModel];\n\n  if ([self.modelManager isModelDownloaded:remoteModel]) {\n    NSLog(@\"Use AutoML remote model.\");\n    options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];\n  } else {\n    NSLog(@\"Use AutoML local model.\");\n    NSString *localModelFilePath =\n        [[NSBundle mainBundle] pathForResource:MLKAutoMLLocalModelManifestFilename\n                                        ofType:MLKAutoMLManifestFileType];\n    if (localModelFilePath == nil) {\n      self.resultsText =\n          [NSMutableString stringWithFormat:@\"Failed to find AutoML local model manifest file: %@\",\n                                            MLKAutoMLLocalModelManifestFilename];\n      [self showResults];\n      return;\n    }\n    MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithManifestPath:localModelFilePath];\n    options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];\n  }\n  options.confidenceThreshold = @(labelConfidenceThreshold);\n  // [END config_automl_label]\n\n  // [START init_automl_label]\n  MLKImageLabeler *autoMLImageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];\n  // [END init_automl_label]\n\n  // Initialize a VisionImage object with the given UIImage.\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];\n  visionImage.orientation = image.imageOrientation;\n\n  // [START detect_automl_label]\n  __weak typeof(self) weakSelf = self;\n  [autoMLImageLabeler\n      processImage:visionImage\n        completion:^(NSArray<MLKImageLabel *> *_Nullable labels, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (!labels || labels.count == 0) {\n            // [START_EXCLUDE]\n            NSString *errorString = error ? error.localizedDescription : detectionNoResultsMessage;\n            [strongSelf.resultsText\n                appendFormat:@\"AutoML image labeling failed with error: %@\", errorString];\n            [strongSelf showResults];\n            // [END_EXCLUDE]\n            return;\n          }\n\n          // [START_EXCLUDE]\n          [strongSelf.resultsText setString:@\"\"];\n          for (MLKImageLabel *label in labels) {\n            [strongSelf.resultsText\n                appendFormat:@\"Label: %@, Confidence: %f\\n\", label.text, label.confidence];\n          }\n          [strongSelf showResults];\n          // [END_EXCLUDE]\n        }];\n  // [END detect_automl_label]\n}\n\n/**\n * Detects objects on the specified image using image classification models trained by AutoML via\n * Custom Object Detection API.\n *\n * @param image The input image.\n * @param shouldEnableClassification Whether image classification should be enabled.\n * @param shouldEnableMultipleObjects Whether multi-object detection should be enabled.\n */\n- (void)detectObjectsInImage:(UIImage *)image\n     shouldEnableClassification:(BOOL)shouldEnableClassification\n    shouldEnableMultipleObjects:(BOOL)shouldEnableMultipleObjects {\n  if (!image) {\n    return;\n  }\n  [self requestAutoMLRemoteModelIfNeeded];\n\n  MLKCustomRemoteModel *remoteModel = (MLKCustomRemoteModel *)[self remoteModel];\n  MLKCustomObjectDetectorOptions *options;\n\n  if ([self.modelManager isModelDownloaded:remoteModel]) {\n    NSLog(@\"Use AutoML remote model.\");\n    options = [[MLKCustomObjectDetectorOptions alloc] initWithRemoteModel:remoteModel];\n  } else {\n    NSLog(@\"Use AutoML local model.\");\n    NSString *localModelFilePath =\n        [[NSBundle mainBundle] pathForResource:MLKAutoMLLocalModelManifestFilename\n                                        ofType:MLKAutoMLManifestFileType];\n    if (localModelFilePath == nil) {\n      self.resultsText =\n          [NSMutableString stringWithFormat:@\"Failed to find AutoML local model manifest file: %@\",\n                                            MLKAutoMLLocalModelManifestFilename];\n      [self showResults];\n      return;\n    }\n    MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithManifestPath:localModelFilePath];\n    options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];\n  }\n  options.shouldEnableClassification = shouldEnableClassification;\n  options.shouldEnableMultipleObjects = shouldEnableMultipleObjects;\n  options.detectorMode = MLKObjectDetectorModeSingleImage;\n\n  MLKObjectDetector *autoMLObjectDetector = [MLKObjectDetector objectDetectorWithOptions:options];\n\n  // Initialize a VisionImage object with the given UIImage.\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];\n  visionImage.orientation = image.imageOrientation;\n\n  __weak typeof(self) weakSelf = self;\n  [autoMLObjectDetector\n      processImage:visionImage\n        completion:^(NSArray<MLKObject *> *_Nullable objects, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (!objects || objects.count == 0) {\n            NSString *errorString = error ? error.localizedDescription : detectionNoResultsMessage;\n            [strongSelf.resultsText\n                appendFormat:@\"AutoML object detection failed with error: %@\", errorString];\n            [strongSelf showResults];\n            return;\n          }\n\n          [strongSelf.resultsText setString:@\"\"];\n          for (MLKObject *object in objects) {\n            CGAffineTransform transform = [self transformMatrix];\n            CGRect transformedRect = CGRectApplyAffineTransform(object.frame, transform);\n            [UIUtilities addRectangle:transformedRect\n                               toView:self.annotationOverlayView\n                                color:UIColor.greenColor];\n            [strongSelf.resultsText appendFormat:@\"Frame: %@\\nObject ID: %@\\nLabels:\\n\",\n                                                 NSStringFromCGRect(object.frame),\n                                                 object.trackingID];\n            int i = 0;\n            for (MLKObjectLabel *l in object.labels) {\n              NSString *labelString =\n                  [NSString stringWithFormat:@\"Label %d: %@, %f, %lu\\n\", i++, l.text, l.confidence,\n                                             (unsigned long)l.index];\n              [strongSelf.resultsText appendString:labelString];\n            }\n          }\n          [strongSelf showResults];\n        }];\n}\n\n- (CGAffineTransform)transformMatrix {\n  UIImage *image = self.imageView.image;\n  if (!image) {\n    return CGAffineTransformMake(0, 0, 0, 0, 0, 0);\n  }\n  CGFloat imageViewWidth = self.imageView.frame.size.width;\n  CGFloat imageViewHeight = self.imageView.frame.size.height;\n  CGFloat imageWidth = image.size.width;\n  CGFloat imageHeight = image.size.height;\n\n  CGFloat imageViewAspectRatio = imageViewWidth / imageViewHeight;\n  CGFloat imageAspectRatio = imageWidth / imageHeight;\n  CGFloat scale = (imageViewAspectRatio > imageAspectRatio) ? imageViewHeight / imageHeight\n                                                            : imageViewWidth / imageWidth;\n\n  // Image view's `contentMode` is `scaleAspectFit`, which scales the image to fit the size of the\n  // image view by maintaining the aspect ratio. Multiple by `scale` to get image's original size.\n  CGFloat scaledImageWidth = imageWidth * scale;\n  CGFloat scaledImageHeight = imageHeight * scale;\n  CGFloat xValue = (imageViewWidth - scaledImageWidth) / 2.0;\n  CGFloat yValue = (imageViewHeight - scaledImageHeight) / 2.0;\n\n  CGAffineTransform transform =\n      CGAffineTransformTranslate(CGAffineTransformIdentity, xValue, yValue);\n  return CGAffineTransformScale(transform, scale, scale);\n}\n\n- (void)requestAutoMLRemoteModelIfNeeded {\n  MLKRemoteModel *remoteModel = [self remoteModel];\n  if ([self.modelManager isModelDownloaded:remoteModel]) {\n    return;\n  }\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    strongSelf.downloadProgressView.hidden = NO;\n    MLKModelDownloadConditions *conditions =\n        [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES\n                                             allowsBackgroundDownloading:YES];\n    strongSelf.downloadProgressView.observedProgress =\n        [strongSelf.modelManager downloadModel:remoteModel conditions:conditions];\n    NSLog(@\"Start downloading AutoML remote model.\");\n  });\n}\n\n#pragma mark - Notifications\n\n- (void)remoteModelDownloadDidSucceed:(NSNotification *)notification {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    strongSelf.downloadProgressView.hidden = YES;\n    strongSelf.downloadOrDeleteModelButton.image = [UIImage imageNamed:@\"delete\"];\n    MLKRemoteModel *remotemodel = notification.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];\n    if (remotemodel == nil) {\n      [strongSelf.resultsText appendString:@\"MLKitModelDownloadDidSucceed notification posted \"\n                                           @\"without a RemoteModel instance.\"];\n      return;\n    }\n    [strongSelf.resultsText\n        appendFormat:@\"Successfully downloaded the remote model with name: %@. The \"\n                     @\"model is ready for detection.\",\n                     remotemodel.name];\n    NSLog(@\"Successfully downloaded AutoML remote model.\");\n  });\n}\n\n- (void)remoteModelDownloadDidFail:(NSNotification *)notification {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    strongSelf.downloadProgressView.hidden = YES;\n    MLKRemoteModel *remoteModel = notification.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];\n    NSError *error = notification.userInfo[MLKModelDownloadUserInfoKeyError];\n    if (error == nil) {\n      [strongSelf.resultsText appendString:@\"MLKitModelDownloadDidFail notification posted without \"\n                                           @\"a RemoteModel instance or error.\"];\n      return;\n    }\n    [strongSelf.resultsText\n        appendFormat:@\"Failed to download the remote model with name: %@, error: %@.\", remoteModel,\n                     error.localizedDescription];\n    NSLog(@\"Failed to download AutoML remote model.\");\n  });\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/automl/AutoMLExampleObjC/main.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char* argv[]) {\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/automl/Podfile",
    "content": "platform :ios, '15.5'\nuse_frameworks!\n\nproject 'AutoMLExample.xcodeproj'\n\npod 'GoogleMLKit/Common', '9.0.0'\npod 'GoogleMLKit/ImageLabelingCustom', '9.0.0'\npod 'GoogleMLKit/LinkFirebase', '9.0.0'\npod 'GoogleMLKit/ObjectDetectionCustom', '9.0.0'\npod 'GoogleMLKit/Vision', '9.0.0'\n\ntarget 'AutoMLExample' do\nend\n\ntarget 'AutoMLExampleObjC' do\nend\n\npost_install do |installer|\n  installer.aggregate_targets.each do |target|\n    target.xcconfigs.each do |variant, xcconfig|\n      xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)\n      IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n    end\n  end\n  installer.generated_projects.each do |project|\n    project.targets.each do |target|\n        target.build_configurations.each do |config|\n            config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'\n            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'\n         end\n    end\n  end\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference\n        xcconfig_path = config.base_configuration_reference.real_path\n        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n      end\n    end\n  end\nend"
  },
  {
    "path": "ios/quickstarts/automl/README.md",
    "content": "# ML Kit AutoML Remote Model Quickstart Sample App\n\n* [Read more about training an image classification model using AutoML Vision Edge model](https://firebase.google.com/docs/ml/automl-image-labeling)\n* [Read more about hosting models with Firebase Model deployment](https://firebase.google.com/docs/ml/manage-hosted-models)\n\n## Introduction\n\nThis ML Kit AutoML iOS Quickstart app demonstrates how to label images with an\nAutoML Vision Edge trained model, and also how to download models that are\nhosted with Firebase.\n\n## Feature List\nFeatures that are included in this demo app:\n\n* [AutoML Image labeling](https://developers.google.com/ml-kit/vision/image-labeling/automl/ios) - Label images using an AutoML VisionEdge trained model\n\n<img src=\"../../screenshots/auto_ml_1.jpeg\" width=\"256\"/> <img src=\"../../screenshots/auto_ml_2.jpeg\" width=\"256\"/>\n\n## Getting Started\n\n- [Add Firebase to your iOS Project](https://firebase.google.com/docs/ios/setup).\n- Run the sample on your iOS device or simulator.\n- Choose Photo Library, Photo Camera, or Video Camera to see a demo of labeling\n  images using a model trained by AutoML\n\n## How to use the app\n\nThis app supports two usage scenarios: Live Camera mode and Static Image mode.\n\n### Live Camera Scenario\nThis mode uses the camera preview as input and allows you to label images using\na remotely downloaded AutoML Vision Edge model.\n\n### Static Image Scenario\nThe static image scenario is identical to the live camera scenario, but instead\nrelies on images fed into the app through the camera roll.\n\n\n## Support\n\n- [Stack Overflow for ML Kit](https://stackoverflow.com/questions/tagged/google-mlkit)\n\nLicense\n-------\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "ios/quickstarts/automl/Resources/automl_labeler_labels.txt",
    "content": "daisy\ndandelion\nroses\nsunflowers\ntulips\n"
  },
  {
    "path": "ios/quickstarts/automl/Resources/automl_labeler_manifest.json",
    "content": "{\n  \"modelType\": \"IMAGE_LABELING\",\n  \"modelFile\": \"automl_labeler_model.tflite\",\n  \"labelsFile\": \"automl_labeler_labels.txt\",\n}\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExample/AppDelegate.swift",
    "content": "import UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n  var window: UIWindow?\n\n  func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    // Override point for customization after application launch.\n    return true\n  }\n\n  // MARK: UISceneSession Lifecycle\n\n  @available(iOS 13.0, *)\n  func application(\n    _ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession,\n    options: UIScene.ConnectionOptions\n  ) -> UISceneConfiguration {\n    // Called when a new scene session is being created.\n    // Use this method to select a configuration to create the new scene with.\n    return UISceneConfiguration(\n      name: \"Default Configuration\", sessionRole: connectingSceneSession.role)\n  }\n\n  @available(iOS 13.0, *)\n  func application(\n    _ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>\n  ) {\n    // Called when the user discards a scene session. If any sessions were discarded while the \n    // application was not running, this will be called shortly after\n    // application:didFinishLaunchingWithOptions. Use this method to release any resources\n    // that were specific to the discarded scenes, as they will not return.\n  }\n\n}\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExample/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>SceneDelegate</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key>\n\t\t\t\t\t<string>Main</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExample/RecognizedInk.swift",
    "content": "import Foundation\n\nimport MLKit\n\nclass RecognizedInk: NSObject {\n\n  /** Ink, displayed to the user. */\n  var ink: Ink\n  /** Top recognition result candidate for the ink, displayed to the user. */\n  var text: String? = nil\n\n  /**\n   * Creates a `RecognizedInk` with the given `Ink` once it is sent for recognition. Text is initially\n   * empty.\n   * @param ink The ink to be stored in the `RecognizedInk` object.\n   * @return the initialized `RecognizedInk` object.\n   */\n  init(ink: Ink) {\n    self.ink = ink\n  }\n\n}\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExample/SceneDelegate.swift",
    "content": "import UIKit\n\n@available(iOS 13.0, *)\n@objc(SceneDelegate)\nclass SceneDelegate: UIResponder, UIWindowSceneDelegate {\n\n  var window: UIWindow?\n\n  func scene(\n    _ scene: UIScene, willConnectTo session: UISceneSession,\n    options connectionOptions: UIScene.ConnectionOptions\n  ) {\n    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n    guard let _ = (scene as? UIWindowScene) else { return }\n  }\n\n  func sceneDidDisconnect(_ scene: UIScene) {\n    // Called as the scene is being released by the system.\n    // This occurs shortly after the scene enters the background, or when its session is discarded.\n    // Release any resources associated with this scene that can be re-created the next time the scene connects.\n    // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).\n  }\n\n  func sceneDidBecomeActive(_ scene: UIScene) {\n    // Called when the scene has moved from an inactive state to an active state.\n    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n  }\n\n  func sceneWillResignActive(_ scene: UIScene) {\n    // Called when the scene will move from an active state to an inactive state.\n    // This may occur due to temporary interruptions (ex. an incoming phone call).\n  }\n\n  func sceneWillEnterForeground(_ scene: UIScene) {\n    // Called as the scene transitions from the background to the foreground.\n    // Use this method to undo the changes made on entering the background.\n  }\n\n  func sceneDidEnterBackground(_ scene: UIScene) {\n    // Called as the scene transitions from the foreground to the background.\n    // Use this method to save data, release shared resources, and store enough scene-specific state information\n    // to restore the scene back to its current state.\n  }\n\n}\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExample/StrokeManager.swift",
    "content": "import Foundation\nimport UIKit\n\nimport MLKit\n\n/// Protocol used by the `StrokeManager` to send requests back to the `ViewController` to update the\n/// display.\nprotocol StrokeManagerDelegate: class {\n  /** Clears any temporary ink managed by the caller. */\n  func clearInk()\n  /** Redraws the ink and recognition results. */\n  func redraw()\n  /** Display the given message to the user. */\n  func displayMessage(message: String)\n}\n\n/// The `StrokeManager` object is responsible for storing the ink and recognition results, and\n/// managing the interaction with the recognizer. It receives the touch points as the user is drawing\n/// from the `ViewController` (which takes care of rendering the ink), and stores them into an array\n/// of `Stroke`s. When the user taps \"recognize\", the strokes are collected together into an `Ink`\n/// object, and passed to the recognizer. The `StrokeManagerDelegate` protocol is used to inform the\n/// `ViewController` when the display needs to be updated.\n///\n/// The `StrokeManager` provides additional methods to handle other buttons in the UI, including\n/// selecting a recognition language, downloading or deleting the recognition model, or clearing the\n/// ink.\nclass StrokeManager {\n\n  /**\n   * Array of `RecognizedInk`s that have been sent to the recognizer along with any recognition\n   * results.\n   */\n  var recognizedInks: [RecognizedInk]\n\n  /**\n  * Conversion factor between `TimeInterval` and milliseconds, which is the unit used by the\n  * recognizer.\n  */\n  private var kMillisecondsPerTimeInterval = 1000.0\n\n  /** Arrays used to keep the piece of ink that is currently being drawn. */\n  private var strokes: [Stroke] = []\n  private var points: [StrokePoint] = []\n\n  /** The recognizer that will translate the ink into text. */\n  private var recognizer: DigitalInkRecognizer! = nil\n\n  /** The view that handles UI stuff. */\n  private weak var delegate: StrokeManagerDelegate?\n\n  /** Properties to track and manage the selected language and recognition model. */\n  private var model: DigitalInkRecognitionModel?\n  private var modelManager: ModelManager\n\n  /**\n   * Initialization of internal variables as well as creating the model manager and setting up\n   * observers of the recognition model downloading status.\n   */\n  init(delegate: StrokeManagerDelegate) {\n    self.delegate = delegate\n    modelManager = ModelManager.modelManager()\n    recognizedInks = []\n\n    // Add observers for download notifications, and reflect the status back to the user.\n    NotificationCenter.default.addObserver(\n      forName: NSNotification.Name.mlkitModelDownloadDidSucceed, object: nil,\n      queue: OperationQueue.main,\n      using: {\n        [unowned self]\n        (notification) in\n        if notification.userInfo![ModelDownloadUserInfoKey.remoteModel.rawValue]\n          as? DigitalInkRecognitionModel == self.model\n        {\n          self.delegate?.displayMessage(message: \"Model download succeeded\")\n        }\n      })\n    NotificationCenter.default.addObserver(\n      forName: NSNotification.Name.mlkitModelDownloadDidFail, object: nil,\n      queue: OperationQueue.main,\n      using: {\n        [unowned self]\n        (notification) in\n        if notification.userInfo![ModelDownloadUserInfoKey.remoteModel.rawValue]\n          as? DigitalInkRecognitionModel == self.model\n        {\n          self.delegate?.displayMessage(message: \"Model download failed\")\n        }\n      })\n  }\n\n  /**\n   * Check whether the model for the given language tag is downloaded.\n   */\n  func isLanguageDownloaded(languageTag: String) -> Bool {\n    let identifier = DigitalInkRecognitionModelIdentifier(forLanguageTag: languageTag)\n    let model = DigitalInkRecognitionModel.init(modelIdentifier: identifier!)\n    return modelManager.isModelDownloaded(model)\n  }\n\n  /**\n   * Given a language tag, looks up the cooresponding model identifier and initializes the model. Note\n   * that this doesn't actually download the model, which is triggered manually by the user for the\n   * purposes of this demo app.\n   */\n  func selectLanguage(languageTag: String) {\n    let identifier = DigitalInkRecognitionModelIdentifier(forLanguageTag: languageTag)\n    model = DigitalInkRecognitionModel.init(modelIdentifier: identifier!)\n    recognizer = nil\n    self.delegate?.displayMessage(message: \"Selected language with tag \\(languageTag)\")\n  }\n\n  /**\n   * Actually downloads the model. This happens asynchronously with the user being shown status messages\n   * when the download completes or fails.\n   */\n  func downloadModel() {\n    if modelManager.isModelDownloaded(model!) {\n      self.delegate?.displayMessage(message: \"Model is already downloaded\")\n      return\n    }\n    self.delegate?.displayMessage(message: \"Starting download\")\n    // The Progress object returned by `downloadModel` currently only takes on the values 0% or 100%\n    // so is not very useful. Instead we'll rely on the outcome listeners in the initializer to\n    // inform the user if a download succeeds or fails.\n    modelManager.download(\n      model!,\n      conditions: ModelDownloadConditions.init(\n        allowsCellularAccess: true, allowsBackgroundDownloading: true)\n    )\n  }\n\n  /** Deletes the currently selected model. */\n  func deleteModel() {\n    if !modelManager.isModelDownloaded(model!) {\n      self.delegate?.displayMessage(message: \"Model not downloaded, nothing to delete\")\n      return\n    }\n    modelManager.deleteDownloadedModel(\n      model!,\n      completion: {\n        [unowned self] _ in\n        self.delegate?.displayMessage(message: \"Model deleted\")\n      })\n  }\n\n  /**\n   * Actually carries out the recognition. The recognition may happen asynchronously so there's a\n   * callback that handles the results when they are ready.\n   */\n  func recognizeInk() {\n    if strokes.isEmpty {\n      delegate?.displayMessage(message: \"No ink to recognize\")\n      return\n    }\n    if !modelManager.isModelDownloaded(model!) {\n      delegate?.displayMessage(message: \"Recognizer model not downloaded\")\n      return\n    }\n    if recognizer == nil {\n      self.delegate?.displayMessage(message: \"Initializing recognizer\")\n      let options: DigitalInkRecognizerOptions = DigitalInkRecognizerOptions.init(model: model!)\n      recognizer = DigitalInkRecognizer.digitalInkRecognizer(options: options)\n      delegate?.displayMessage(message: \"Initialized recognizer\")\n    }\n\n    // Turn the list of strokes into an `Ink`, and add this ink to the `recognizedInks` array.\n    let ink = Ink.init(strokes: strokes)\n    let recognizedInk = RecognizedInk.init(ink: ink)\n    recognizedInks.append(recognizedInk)\n    // Clear the currently being drawn ink, and display the ink from `recognizedInks` (which results\n    // in it changing color).\n    delegate?.redraw()\n    delegate?.clearInk()\n    strokes = []\n    // Start the recognizer. Callback function will store the recognized text and tell the\n    // `ViewController` to redraw the screen to show it.\n    recognizer.recognize(\n      ink: ink,\n      completion: {\n        [unowned self, recognizedInk]\n        (result: DigitalInkRecognitionResult?, error: Error?) in\n        if let result = result, let candidate = result.candidates.first {\n          recognizedInk.text = candidate.text\n          var message = \"Recognized: \\(candidate.text)\"\n          if candidate.score != nil {\n            message += \" score \\(candidate.score!.floatValue)\"\n          }\n          self.delegate?.displayMessage(message: message)\n        } else {\n          recognizedInk.text = \"error\"\n          self.delegate?.displayMessage(message: \"Recognition error \" + String(describing: error))\n        }\n        self.delegate?.redraw()\n      })\n  }\n\n  /** Clear out all the ink and other state. */\n  func clear() {\n    recognizedInks = []\n    strokes = []\n    points = []\n  }\n\n  /** Begins a new stroke when the user touches the screen. */\n  func startStrokeAtPoint(point: CGPoint, t: TimeInterval) {\n    points = [\n      StrokePoint.init(\n        x: Float(point.x), y: Float(point.y), t: Int(t * kMillisecondsPerTimeInterval))\n    ]\n  }\n\n  /** Adds an additional point to the stroke when the user moves their finger. */\n  func continueStrokeAtPoint(point: CGPoint, t: TimeInterval) {\n    points.append(\n      StrokePoint.init(\n        x: Float(point.x), y: Float(point.y),\n        t: Int(t * kMillisecondsPerTimeInterval)))\n  }\n\n  /** Completes a stroke when the user lifts their finger. */\n  func endStrokeAtPoint(point: CGPoint, t: TimeInterval) {\n    points.append(\n      StrokePoint.init(\n        x: Float(point.x), y: Float(point.y),\n        t: Int(t * kMillisecondsPerTimeInterval)))\n    // Create an array of strokes if it doesn't exist already, and add this stroke to it.\n    strokes.append(Stroke.init(points: points))\n    points = []\n  }\n\n}\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExample/ViewController.swift",
    "content": "import UIKit\n\nimport MLKit\n\n/// The `ViewController` manages the display seen by the user. The drawing canvas is actually two\n/// overlapping image views. The top one contains the ink that the user is drawing before it is sent\n/// to the recognizer. It can be thought of as a temporary buffer for ink in progress. When the user\n/// presses the \"Recognize\" button, the ink is transferred to the other canvas, which displays a\n/// grayed out version of the ink together with the recognition result.\n///\n/// The management of the interaction with the recognizer happens in `StrokeManager`.\n/// `ViewController` just takes care of receiving user events, rendering the temporary ink, and\n/// handles redraw requests from the `StrokeManager` when the ink is recognized. This latter request\n/// comes through the `StrokeManagerDelegate` protocol.\n///\n/// The `ViewController` provides a number of buttons for controlling the `StrokeManager` which allow\n/// for selecting the recognition language, downloading or deleting the recognition model, triggering\n/// recognition, and clearing the ink.\n@objc(ViewController)\nclass ViewController: UIViewController, StrokeManagerDelegate, UIPickerViewDelegate,\n  UIPickerViewDataSource\n{\n\n  /** Constant defining how to render strokes. */\n  private var kBrushWidth: CGFloat = 2.0\n\n  /** All possible language tags supported by the digital ink recognition API. */\n  private var allLanguageTags: [String] = []\n\n  /** Mapping between the langugae tags and their display names. */\n  private var languageTagDisplayNames: [String: String] = [:]\n\n  /** Default language selected when demo app starts up. */\n  private var defaultLanguage: String = \"\"\n\n  /**\n   * Object that takes care of the logic of saving the ink, sending ink to the recognizer after a\n   * long enough pause, and storing the recognition results.\n   */\n  private var strokeManager: StrokeManager!\n\n  /** Coordinates of the previous touch point as the user is drawing ink. */\n  private var lastPoint: CGPoint!\n\n  /** This view displays all the ink that has been sent for recognition, and recognition results. */\n  @IBOutlet private var recognizedImage: UIImageView!\n\n  /** This view shows only the ink that is currently being drawn, before sending for recognition. */\n  @IBOutlet private var drawnImage: UIImageView!\n\n  /**\n   * Input field showing the currently selected language; when tapped brings up the `languagePicker`.\n   */\n  @IBOutlet private var selectedLanguageField: UITextField!\n\n  /** Text region used to display status messages to the user about the results of their actions. */\n  @IBOutlet private var messageLabel: UILabel!\n\n  /** Clear button clears the canvases and also tells the `StrokeManager` to delete everything. */\n  @IBAction func didPressClear() {\n    recognizedImage.image = nil\n    drawnImage.image = nil\n    strokeManager!.clear()\n    displayMessage(message: \"\")\n  }\n\n  /** Relays the download model command to the `StrokeManager`. */\n  @IBAction func didPressDownload() {\n    strokeManager!.downloadModel()\n  }\n\n  /** Relays the delete model command to the `StrokeManager`. */\n  @IBAction func didPressDelete() {\n    strokeManager!.deleteModel()\n  }\n\n  /** Relays the recognize ink command to the `StrokeManager`. */\n  @IBAction func didPressRecognize() {\n    strokeManager!.recognizeInk()\n  }\n\n  /** Initializes the view, in turn creating the StrokeManager and recognizer. */\n  override func viewDidLoad() {\n    super.viewDidLoad()\n    // Create a `StrokeManager` to store the drawn ink. This also creates the recognizer object.\n    strokeManager = StrokeManager.init(delegate: self)\n\n    // Create the language picker which will be brought up when the user taps the selected language\n    // field.\n    let languagePicker = UIPickerView.init()\n    languagePicker.delegate = self\n    languagePicker.dataSource = self\n\n    // Toolbar on top of the picker which will be used to finalize the selection.\n    let toolbar = UIToolbar.init(\n      frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 44))\n    let leftSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)\n    let done = UIBarButtonItem.init(\n      title: \"Select Language\",\n      style: .done,\n      target: selectedLanguageField,\n      action: #selector(selectedLanguageField!.resignFirstResponder))\n    let rightSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)\n    toolbar.setItems([leftSpace, done, rightSpace], animated: false)\n\n    // Associate the above two UI elements with the selected language input field.\n    selectedLanguageField!.inputView = languagePicker\n    selectedLanguageField!.inputAccessoryView = toolbar\n\n    // Find the language most closely associated with the preferred language, falling back to English\n    // if we can't find a match.\n    let defaultLanguageIdentifier: DigitalInkRecognitionModelIdentifier =\n      NSLocale.preferredLanguages.lazy.compactMap {\n        try? DigitalInkRecognitionModelIdentifier.from(languageTag: $0)\n      }.first ?? (try! DigitalInkRecognitionModelIdentifier.from(languageTag: \"en\"))\n    defaultLanguage = defaultLanguageIdentifier.languageTag\n\n    strokeManager!.selectLanguage(languageTag: defaultLanguageIdentifier.languageTag)\n\n    // Initialize the language picker and scroll it to have the above language selected.\n    computeAllLanguageTags()\n    languagePicker.reloadAllComponents()\n    languagePicker.selectRow(\n      allLanguageTags.firstIndex(of: defaultLanguage)!,\n      inComponent: 0,\n      animated: false)\n\n    // This has to happen after calling computeAllLanguageTags() which also sets up the\n    // display names mapping.\n    selectedLanguageField!.text = languageTagDisplayNames[defaultLanguage]\n  }\n\n  /** Handle start of stroke: Draw the point, and pass it along to the `StrokeManager`. */\n  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {\n    let touch = touches.first\n    // Since this is a new stroke, make last point the same as the current point.\n    lastPoint = touch!.location(in: drawnImage)\n    let time = touch!.timestamp\n    drawLineSegment(touch: touch)\n    strokeManager!.startStrokeAtPoint(point: lastPoint!, t: time)\n  }\n\n  /** Handle continuing a stroke: Draw the line segment, and pass along to the `StrokeManager`. */\n  override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {\n    let touch = touches.first\n    drawLineSegment(touch: touch)\n    strokeManager!.continueStrokeAtPoint(point: lastPoint!, t: touch!.timestamp)\n  }\n\n  /** Handle end of stroke: Draw the line segment, and pass along to the `StrokeManager`. */\n  override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {\n    let touch = touches.first\n    drawLineSegment(touch: touch)\n    strokeManager!.endStrokeAtPoint(point: lastPoint!, t: touch!.timestamp)\n  }\n\n  /** Displays a status message from the `StrokeManager` to the user. */\n  func displayMessage(message: String) {\n    messageLabel!.text = message\n  }\n\n  /**\n   * Clear temporary ink in progress. This is invoked by the `StrokeManager` when the temporary ink is\n   * sent to the recognizer.\n   */\n  func clearInk() {\n    drawnImage.image = nil\n  }\n\n  /**\n   * Iterate through all the saved ink/recognition results in the `StrokeManager` and render them.\n   * This is invoked by the `StrokeManager` when an ink is sent to the recognizer, and when a\n   * recognition result is returned.\n   */\n  func redraw() {\n    recognizedImage.image = nil\n    let recognizedInks = strokeManager!.recognizedInks\n    for recognizedInk in recognizedInks {\n      drawInk(ink: recognizedInk.ink)\n      if recognizedInk.text != nil {\n        drawText(recognizedInk: recognizedInk)\n      }\n    }\n  }\n\n  /**\n   * Invoked by the language picker when the user scrolls to a particular position in either\n   * component. In the left component, the language subtag is selected, so the right component needs\n   * to be updated with corresponding list of full language codes and the first one is selected by\n   * default; also the `StrokeManager` is informed.\n   */\n  func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {\n    let tag: String = allLanguageTags[row]\n    selectedLanguageField.text = languageTagDisplayNames[tag]\n    strokeManager!.selectLanguage(languageTag: tag)\n  }\n\n  /**\n * Invoked by the language picker to get the contents of each row. If the model for the language\n * is already downloaded, prepend the title with the string \"[D]\".\n */\n  func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int)\n    -> String?\n  {\n    let tag = allLanguageTags[row]\n    let title = languageTagDisplayNames[tag]!\n    if strokeManager.isLanguageDownloaded(languageTag: tag) {\n      return \"[D] \\(title)\"\n    } else {\n      return title\n    }\n  }\n\n  /** Invoked by the language picker to find out how many entries are in each component. */\n  func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: NSInteger)\n    -> NSInteger\n  {\n    return allLanguageTags.count\n  }\n\n  /** Invoked by the language picker to get the number of components. */\n  func numberOfComponents(in pickerView: UIPickerView) -> Int {\n    return 1\n  }\n\n  /**\n   * Draws a line segment from `self.lastPoint` to the current touch point given in the argument\n   * to the temporary ink canvas.\n   */\n  func drawLineSegment(touch: UITouch!) {\n    let currentPoint = touch.location(in: drawnImage)\n\n    UIGraphicsBeginImageContext(drawnImage.frame.size)\n    drawnImage.image?.draw(\n      in: CGRect(\n        x: 0, y: 0, width: drawnImage.frame.size.width, height: drawnImage.frame.size.height))\n    let ctx: CGContext! = UIGraphicsGetCurrentContext()\n    ctx.move(to: lastPoint!)\n    ctx.addLine(to: currentPoint)\n    ctx.setLineCap(CGLineCap.round)\n    ctx.setLineWidth(kBrushWidth)\n    // Unrecognized strokes are drawn in blue.\n    ctx.setStrokeColor(red: 0, green: 0, blue: 1, alpha: 1)\n    ctx.setBlendMode(CGBlendMode.normal)\n    ctx.strokePath()\n    ctx.flush()\n    drawnImage.image = UIGraphicsGetImageFromCurrentImageContext()\n    UIGraphicsEndImageContext()\n    lastPoint = currentPoint\n  }\n\n  /**\n  * Goes through all language tags supported by the library, and attempt to create human readable names for\n  * each of them (although the library supports more languages than iOS's NSLocale library knows about).\n  * Ordered the languages alphabetically by their display names, but places the default language and the non-text\n  * recognizers (emoji, autodraw, and shapes) at the top of the list.\n  */\n  func computeAllLanguageTags() {\n    let all = DigitalInkRecognitionModelIdentifier.allModelIdentifiers()\n    let locale: Locale = NSLocale.current\n    var nonText: [String] = []\n    var allTags: [String] = []\n    for identifier in all {\n      let tag = identifier.languageTag\n      var displayName: String!\n      if tag.hasPrefix(\"zxx-\") {\n        nonText.append(tag)\n        displayName = tag.components(separatedBy: \"-x-\").last\n      } else {\n        displayName = locale.localizedString(forIdentifier: tag)\n      }\n      if displayName == nil {\n        displayName = identifier.languageSubtag\n        if identifier.regionSubtag != nil {\n          displayName += \" (\\(identifier.regionSubtag!))\"\n        }\n        if identifier.scriptSubtag != nil {\n          displayName += \" \\(identifier.scriptSubtag!) Script\"\n        }\n      }\n      languageTagDisplayNames[tag] = displayName\n      allTags.append(tag)\n    }\n    allLanguageTags = allTags.sorted(by: {\n      var priorityA = 2\n      if $0 == defaultLanguage {\n        priorityA = 0\n      } else if nonText.firstIndex(of: $0) != nil {\n        priorityA = 1\n      }\n      var priorityB = 2\n      if $1 == self.defaultLanguage {\n        priorityB = 0\n      } else if nonText.firstIndex(of: $1) != nil {\n        priorityB = 1\n      }\n      if priorityA < priorityB {\n        return true\n      }\n      if priorityA > priorityB {\n        return false\n      }\n      return languageTagDisplayNames[$0]!.compare(\n        languageTagDisplayNames[$1]!, options: NSString.CompareOptions.caseInsensitive)\n        == ComparisonResult.orderedAscending\n    })\n  }\n\n  /** Given an `Ink`, draw it into the `recognizedImage` canvas in gray. */\n  func drawInk(ink: Ink) {\n    UIGraphicsBeginImageContext(drawnImage.frame.size)\n    recognizedImage.image?.draw(\n      in: CGRect(\n        x: 0, y: 0, width: drawnImage.frame.size.width, height: drawnImage.frame.size.height))\n    let ctx: CGContext! = UIGraphicsGetCurrentContext()\n    for stroke in ink.strokes {\n      if stroke.points.isEmpty {\n        continue\n      }\n      let point = CGPoint.init(x: Double(stroke.points[0].x), y: Double(stroke.points[0].y))\n      ctx.move(to: point)\n      ctx.addLine(to: point)\n      for point in stroke.points {\n        ctx.addLine(to: CGPoint.init(x: Double(point.x), y: Double(point.y)))\n      }\n    }\n    ctx.setLineCap(CGLineCap.round)\n    ctx.setLineWidth(kBrushWidth)\n    // Recognized strokes are drawn in gray.\n    ctx.setStrokeColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1)\n    ctx.setBlendMode(CGBlendMode.normal)\n    ctx.strokePath()\n    ctx.flush()\n    recognizedImage.image = UIGraphicsGetImageFromCurrentImageContext()\n    UIGraphicsEndImageContext()\n  }\n\n  /** Given an `Ink`, returned the bounding box of the ink. */\n  func getInkRect(ink: Ink) -> CGRect {\n    var rect = CGRect.null\n    if ink.strokes.count == 0 {\n      return rect\n    }\n    for stroke in ink.strokes {\n      for point in stroke.points {\n        rect = rect.union(CGRect(x: Double(point.x), y: Double(point.y), width: 0, height: 0))\n      }\n    }\n    // Make the minimum size 10x10 pixels.\n    rect = rect.union(\n      CGRect(\n        x: rect.midX - 5,\n        y: rect.midY - 5,\n        width: 10,\n        height: 10))\n    return rect\n  }\n\n  /**\n   * Given a `recognizedInk`, compute the bounding box of the ink that it contains, and render the\n   * text at roughly the same size as the bounding box.\n   */\n  func drawText(recognizedInk: RecognizedInk) {\n    let rect = getInkRect(ink: recognizedInk.ink)\n    UIGraphicsBeginImageContext(drawnImage.frame.size)\n    recognizedImage.image?.draw(\n      in: CGRect(\n        x: 0, y: 0, width: drawnImage.frame.size.width, height: drawnImage.frame.size.height))\n    let ctx: CGContext! = UIGraphicsGetCurrentContext()\n    ctx.setBlendMode(CGBlendMode.normal)\n\n    let arbitrarySize: CGFloat = 20\n    let font = UIFont.systemFont(ofSize: arbitrarySize)\n    let attributes = [\n      NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: UIColor.green,\n    ]\n    var size = recognizedInk.text!.size(withAttributes: attributes)\n    if size.width <= 0 {\n      size.width = 1\n    }\n    if size.height <= 0 {\n      size.height = 1\n    }\n    ctx.translateBy(x: rect.origin.x, y: rect.origin.y)\n    ctx.scaleBy(x: ceil(rect.size.width) / size.width, y: ceil(rect.size.height) / size.height)\n    recognizedInk.text!.draw(at: CGPoint.init(x: 0, y: 0), withAttributes: attributes)\n    ctx.flush()\n    recognizedImage.image = UIGraphicsGetImageFromCurrentImageContext()\n    UIGraphicsEndImageContext()\n  }\n\n}\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t06B702967D07DFBE8B611A65 /* Pods_DigitalInkRecognitionExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43C581A52410A68C001DDCD7 /* Pods_DigitalInkRecognitionExample.framework */; };\n\t\t4316679E23E3C9B600320D07 /* StrokeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4316679D23E3C9B500320D07 /* StrokeManager.m */; };\n\t\t431667A123E79EC200320D07 /* RecognizedInk.m in Sources */ = {isa = PBXBuildFile; fileRef = 431667A023E79EC200320D07 /* RecognizedInk.m */; };\n\t\t437C575823ECB138007755CF /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 437C575723ECB138007755CF /* SceneDelegate.m */; };\n\t\t43941DD62491F2AE0003EF8E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43941DD52491F2AE0003EF8E /* AppDelegate.swift */; };\n\t\t43941DD82491F2AE0003EF8E /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43941DD72491F2AE0003EF8E /* SceneDelegate.swift */; };\n\t\t43941DDA2491F2AE0003EF8E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43941DD92491F2AE0003EF8E /* ViewController.swift */; };\n\t\t43941DE72491F2D90003EF8E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43A74FD723D9502C003CD995 /* Main.storyboard */; };\n\t\t43941DE82491F2DC0003EF8E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43A74FDA23D9502D003CD995 /* Assets.xcassets */; };\n\t\t43941DE92491F2DF0003EF8E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43A74FDC23D9502D003CD995 /* LaunchScreen.storyboard */; };\n\t\t43941DEC2491FF520003EF8E /* RecognizedInk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43941DEB2491FF520003EF8E /* RecognizedInk.swift */; };\n\t\t43941DEE2491FF660003EF8E /* StrokeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43941DED2491FF660003EF8E /* StrokeManager.swift */; };\n\t\t43A74FD023D9502C003CD995 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A74FCF23D9502C003CD995 /* AppDelegate.m */; };\n\t\t43A74FD623D9502C003CD995 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A74FD523D9502C003CD995 /* ViewController.m */; };\n\t\t43A74FD923D9502C003CD995 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43A74FD723D9502C003CD995 /* Main.storyboard */; };\n\t\t43A74FDB23D9502D003CD995 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43A74FDA23D9502D003CD995 /* Assets.xcassets */; };\n\t\t43A74FDE23D9502D003CD995 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43A74FDC23D9502D003CD995 /* LaunchScreen.storyboard */; };\n\t\t43A74FE123D9502D003CD995 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A74FE023D9502D003CD995 /* main.m */; };\n\t\tBDC0E56B3269ACD32101DEC2 /* Pods_DigitalInkRecognitionExampleObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A22BB43CB8C0FDB75229DD /* Pods_DigitalInkRecognitionExampleObjC.framework */; };\n\t\tDB5FEFEEC8CADB42FA3F1F4A /* Pods_DigitalInkRecognitionExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4F00C43D4D2F0B9368E3DBA /* Pods_DigitalInkRecognitionExample.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t43C581A82410A68D001DDCD7 /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t22A22BB43CB8C0FDB75229DD /* Pods_DigitalInkRecognitionExampleObjC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DigitalInkRecognitionExampleObjC.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t2FA139D9122F19DE977BD81B /* Pods-DigitalInkRecognitionExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-DigitalInkRecognitionExample.debug.xcconfig\"; path = \"Target Support Files/Pods-DigitalInkRecognitionExample/Pods-DigitalInkRecognitionExample.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4316679D23E3C9B500320D07 /* StrokeManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StrokeManager.m; sourceTree = \"<group>\"; };\n\t\t4316679F23E3C9E200320D07 /* StrokeManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StrokeManager.h; sourceTree = \"<group>\"; };\n\t\t431667A023E79EC200320D07 /* RecognizedInk.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RecognizedInk.m; sourceTree = \"<group>\"; };\n\t\t431667A223E79EE600320D07 /* RecognizedInk.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RecognizedInk.h; sourceTree = \"<group>\"; };\n\t\t437C575623ECB137007755CF /* SceneDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = \"<group>\"; };\n\t\t437C575723ECB138007755CF /* SceneDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = \"<group>\"; };\n\t\t43941DD32491F2AE0003EF8E /* DigitalInkRecognitionExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DigitalInkRecognitionExample.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t43941DD52491F2AE0003EF8E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t43941DD72491F2AE0003EF8E /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = \"<group>\"; };\n\t\t43941DD92491F2AE0003EF8E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\t43941DEB2491FF520003EF8E /* RecognizedInk.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecognizedInk.swift; sourceTree = \"<group>\"; };\n\t\t43941DED2491FF660003EF8E /* StrokeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StrokeManager.swift; sourceTree = \"<group>\"; };\n\t\t43A74FCB23D9502C003CD995 /* DigitalInkRecognitionExampleObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DigitalInkRecognitionExampleObjC.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t43A74FCE23D9502C003CD995 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t43A74FCF23D9502C003CD995 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t43A74FD423D9502C003CD995 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\t43A74FD523D9502C003CD995 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\t43A74FD823D9502C003CD995 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t43A74FDA23D9502D003CD995 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t43A74FDD23D9502D003CD995 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t43A74FDF23D9502D003CD995 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t43A74FE023D9502D003CD995 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t43C581A52410A68C001DDCD7 /* Pods_DigitalInkRecognitionExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_DigitalInkRecognitionExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t43C581A92410A6F1001DDCD7 /* MLKitDigitalInkRecognition_resource.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = MLKitDigitalInkRecognition_resource.bundle; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t8EDBFCAB26C99F32DBC3BB47 /* Pods-DigitalInkRecognitionExampleObjC.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-DigitalInkRecognitionExampleObjC.release.xcconfig\"; path = \"Target Support Files/Pods-DigitalInkRecognitionExampleObjC/Pods-DigitalInkRecognitionExampleObjC.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tA4F00C43D4D2F0B9368E3DBA /* Pods_DigitalInkRecognitionExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DigitalInkRecognitionExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tAFA1E264236E71DB7382FA5E /* Pods-DigitalInkRecognitionExampleObjC.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-DigitalInkRecognitionExampleObjC.debug.xcconfig\"; path = \"Target Support Files/Pods-DigitalInkRecognitionExampleObjC/Pods-DigitalInkRecognitionExampleObjC.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tE1DF0DA0323C1E13E5250180 /* Pods-DigitalInkRecognitionExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-DigitalInkRecognitionExample.release.xcconfig\"; path = \"Target Support Files/Pods-DigitalInkRecognitionExample/Pods-DigitalInkRecognitionExample.release.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t43941DD02491F2AE0003EF8E /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t06B702967D07DFBE8B611A65 /* Pods_DigitalInkRecognitionExample.framework in Frameworks */,\n\t\t\t\tDB5FEFEEC8CADB42FA3F1F4A /* Pods_DigitalInkRecognitionExample.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t43A74FC823D9502C003CD995 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tBDC0E56B3269ACD32101DEC2 /* Pods_DigitalInkRecognitionExampleObjC.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t20CD2168EC1B2C7E1B64CE02 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t43C581A92410A6F1001DDCD7 /* MLKitDigitalInkRecognition_resource.bundle */,\n\t\t\t\t22A22BB43CB8C0FDB75229DD /* Pods_DigitalInkRecognitionExampleObjC.framework */,\n\t\t\t\tA4F00C43D4D2F0B9368E3DBA /* Pods_DigitalInkRecognitionExample.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t43941DD42491F2AE0003EF8E /* DigitalInkRecognitionExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t43A74FDF23D9502D003CD995 /* Info.plist */,\n\t\t\t\t43941DD52491F2AE0003EF8E /* AppDelegate.swift */,\n\t\t\t\t43941DD72491F2AE0003EF8E /* SceneDelegate.swift */,\n\t\t\t\t43941DD92491F2AE0003EF8E /* ViewController.swift */,\n\t\t\t\t43941DEB2491FF520003EF8E /* RecognizedInk.swift */,\n\t\t\t\t43941DED2491FF660003EF8E /* StrokeManager.swift */,\n\t\t\t);\n\t\t\tpath = DigitalInkRecognitionExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t43941DEA2491F4A80003EF8E /* Recovered References */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t43C581A52410A68C001DDCD7 /* Pods_DigitalInkRecognitionExample.framework */,\n\t\t\t);\n\t\t\tname = \"Recovered References\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t43A74FC223D9502C003CD995 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t43A74FCD23D9502C003CD995 /* DigitalInkRecognitionExampleObjC */,\n\t\t\t\t43941DD42491F2AE0003EF8E /* DigitalInkRecognitionExample */,\n\t\t\t\t43A74FCC23D9502C003CD995 /* Products */,\n\t\t\t\t7EE461C10C1CFC1BEB2001DD /* Pods */,\n\t\t\t\t20CD2168EC1B2C7E1B64CE02 /* Frameworks */,\n\t\t\t\t43941DEA2491F4A80003EF8E /* Recovered References */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t43A74FCC23D9502C003CD995 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t43A74FCB23D9502C003CD995 /* DigitalInkRecognitionExampleObjC.app */,\n\t\t\t\t43941DD32491F2AE0003EF8E /* DigitalInkRecognitionExample.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t43A74FCD23D9502C003CD995 /* DigitalInkRecognitionExampleObjC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t437C575623ECB137007755CF /* SceneDelegate.h */,\n\t\t\t\t437C575723ECB138007755CF /* SceneDelegate.m */,\n\t\t\t\t43A74FCE23D9502C003CD995 /* AppDelegate.h */,\n\t\t\t\t43A74FCF23D9502C003CD995 /* AppDelegate.m */,\n\t\t\t\t43A74FD423D9502C003CD995 /* ViewController.h */,\n\t\t\t\t43A74FD523D9502C003CD995 /* ViewController.m */,\n\t\t\t\t4316679F23E3C9E200320D07 /* StrokeManager.h */,\n\t\t\t\t4316679D23E3C9B500320D07 /* StrokeManager.m */,\n\t\t\t\t43A74FD723D9502C003CD995 /* Main.storyboard */,\n\t\t\t\t43A74FDA23D9502D003CD995 /* Assets.xcassets */,\n\t\t\t\t43A74FDC23D9502D003CD995 /* LaunchScreen.storyboard */,\n\t\t\t\t43A74FE023D9502D003CD995 /* main.m */,\n\t\t\t\t431667A023E79EC200320D07 /* RecognizedInk.m */,\n\t\t\t\t431667A223E79EE600320D07 /* RecognizedInk.h */,\n\t\t\t);\n\t\t\tpath = DigitalInkRecognitionExampleObjC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7EE461C10C1CFC1BEB2001DD /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2FA139D9122F19DE977BD81B /* Pods-DigitalInkRecognitionExample.debug.xcconfig */,\n\t\t\t\tE1DF0DA0323C1E13E5250180 /* Pods-DigitalInkRecognitionExample.release.xcconfig */,\n\t\t\t\tAFA1E264236E71DB7382FA5E /* Pods-DigitalInkRecognitionExampleObjC.debug.xcconfig */,\n\t\t\t\t8EDBFCAB26C99F32DBC3BB47 /* Pods-DigitalInkRecognitionExampleObjC.release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t43941DD22491F2AE0003EF8E /* DigitalInkRecognitionExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 43941DE42491F2B00003EF8E /* Build configuration list for PBXNativeTarget \"DigitalInkRecognitionExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t349051F548B767D9E6444D3A /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t43941DCF2491F2AE0003EF8E /* Sources */,\n\t\t\t\t43941DD02491F2AE0003EF8E /* Frameworks */,\n\t\t\t\t43941DD12491F2AE0003EF8E /* Resources */,\n\t\t\t\tF3BFDE80257CA33EFABF9D3A /* [CP] Embed Pods Frameworks */,\n\t\t\t\tF50F853499C8DF375ECCF48B /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = DigitalInkRecognitionExample;\n\t\t\tproductName = DigitalInkRecognitionExample;\n\t\t\tproductReference = 43941DD32491F2AE0003EF8E /* DigitalInkRecognitionExample.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t43A74FCA23D9502C003CD995 /* DigitalInkRecognitionExampleObjC */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 43A74FFA23D9502D003CD995 /* Build configuration list for PBXNativeTarget \"DigitalInkRecognitionExampleObjC\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t41730B736DDDA270BEB1DE14 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t43A74FC723D9502C003CD995 /* Sources */,\n\t\t\t\t43A74FC823D9502C003CD995 /* Frameworks */,\n\t\t\t\t43A74FC923D9502C003CD995 /* Resources */,\n\t\t\t\tC1BAD7E585DB7C7F50315AB7 /* [CP] Embed Pods Frameworks */,\n\t\t\t\t82C89EC12BC1D0E9062AFAD4 /* [CP] Copy Pods Resources */,\n\t\t\t\t43C581A82410A68D001DDCD7 /* Embed Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = DigitalInkRecognitionExampleObjC;\n\t\t\tproductName = DigitalInkRecognitionExample;\n\t\t\tproductReference = 43A74FCB23D9502C003CD995 /* DigitalInkRecognitionExampleObjC.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t43A74FC323D9502C003CD995 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1150;\n\t\t\t\tLastUpgradeCheck = 1150;\n\t\t\t\tORGANIZATIONNAME = \"\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t43941DD22491F2AE0003EF8E = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.5;\n\t\t\t\t\t};\n\t\t\t\t\t43A74FCA23D9502C003CD995 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.3;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 43A74FC623D9502C003CD995 /* Build configuration list for PBXProject \"DigitalInkRecognitionExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 43A74FC223D9502C003CD995;\n\t\t\tproductRefGroup = 43A74FCC23D9502C003CD995 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t43A74FCA23D9502C003CD995 /* DigitalInkRecognitionExampleObjC */,\n\t\t\t\t43941DD22491F2AE0003EF8E /* DigitalInkRecognitionExample */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t43941DD12491F2AE0003EF8E /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t43941DE92491F2DF0003EF8E /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t43941DE82491F2DC0003EF8E /* Assets.xcassets in Resources */,\n\t\t\t\t43941DE72491F2D90003EF8E /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t43A74FC923D9502C003CD995 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t43A74FDE23D9502D003CD995 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t43A74FDB23D9502D003CD995 /* Assets.xcassets in Resources */,\n\t\t\t\t43A74FD923D9502C003CD995 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t349051F548B767D9E6444D3A /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-DigitalInkRecognitionExample-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t41730B736DDDA270BEB1DE14 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-DigitalInkRecognitionExampleObjC-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t82C89EC12BC1D0E9062AFAD4 /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExampleObjC/Pods-DigitalInkRecognitionExampleObjC-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExampleObjC/Pods-DigitalInkRecognitionExampleObjC-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExampleObjC/Pods-DigitalInkRecognitionExampleObjC-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tC1BAD7E585DB7C7F50315AB7 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExampleObjC/Pods-DigitalInkRecognitionExampleObjC-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExampleObjC/Pods-DigitalInkRecognitionExampleObjC-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExampleObjC/Pods-DigitalInkRecognitionExampleObjC-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tF3BFDE80257CA33EFABF9D3A /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExample/Pods-DigitalInkRecognitionExample-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExample/Pods-DigitalInkRecognitionExample-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExample/Pods-DigitalInkRecognitionExample-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tF50F853499C8DF375ECCF48B /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExample/Pods-DigitalInkRecognitionExample-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExample/Pods-DigitalInkRecognitionExample-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-DigitalInkRecognitionExample/Pods-DigitalInkRecognitionExample-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t43941DCF2491F2AE0003EF8E /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t43941DDA2491F2AE0003EF8E /* ViewController.swift in Sources */,\n\t\t\t\t43941DD62491F2AE0003EF8E /* AppDelegate.swift in Sources */,\n\t\t\t\t43941DEE2491FF660003EF8E /* StrokeManager.swift in Sources */,\n\t\t\t\t43941DEC2491FF520003EF8E /* RecognizedInk.swift in Sources */,\n\t\t\t\t43941DD82491F2AE0003EF8E /* SceneDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t43A74FC723D9502C003CD995 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t431667A123E79EC200320D07 /* RecognizedInk.m in Sources */,\n\t\t\t\t437C575823ECB138007755CF /* SceneDelegate.m in Sources */,\n\t\t\t\t43A74FD623D9502C003CD995 /* ViewController.m in Sources */,\n\t\t\t\t43A74FD023D9502C003CD995 /* AppDelegate.m in Sources */,\n\t\t\t\t4316679E23E3C9B600320D07 /* StrokeManager.m in Sources */,\n\t\t\t\t43A74FE123D9502D003CD995 /* main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t43A74FD723D9502C003CD995 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t43A74FD823D9502C003CD995 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t43A74FDC23D9502D003CD995 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t43A74FDD23D9502D003CD995 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t43941DE52491F2B00003EF8E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 2FA139D9122F19DE977BD81B /* Pods-DigitalInkRecognitionExample.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = DigitalInkRecognitionExample/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-D COCOAPODS\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.DigitalInkRecognitionExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t43941DE62491F2B00003EF8E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = E1DF0DA0323C1E13E5250180 /* Pods-DigitalInkRecognitionExample.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = DigitalInkRecognitionExample/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-D COCOAPODS\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.DigitalInkRecognitionExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t43A74FF823D9502D003CD995 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t43A74FF923D9502D003CD995 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t43A74FFB23D9502D003CD995 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = AFA1E264236E71DB7382FA5E /* Pods-DigitalInkRecognitionExampleObjC.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = DigitalInkRecognitionExample/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"\";\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-l\\\"c++\\\"\",\n\t\t\t\t\t\"-l\\\"sqlite3\\\"\",\n\t\t\t\t\t\"-l\\\"z\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"Foundation\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"GTMSessionFetcher\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"GoogleDataTransport\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"GoogleToolboxForMac\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"GoogleUtilities\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"LocalAuthentication\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"MLKitCommon\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"MLKitDigitalInkRecognition\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"Security\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"nanopb\\\"\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.DigitalInkRecognitionExampleObjC;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t43A74FFC23D9502D003CD995 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 8EDBFCAB26C99F32DBC3BB47 /* Pods-DigitalInkRecognitionExampleObjC.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = DigitalInkRecognitionExample/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"\";\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-l\\\"c++\\\"\",\n\t\t\t\t\t\"-l\\\"sqlite3\\\"\",\n\t\t\t\t\t\"-l\\\"z\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"Foundation\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"GTMSessionFetcher\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"GoogleDataTransport\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"GoogleToolboxForMac\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"GoogleUtilities\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"LocalAuthentication\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"MLKitCommon\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"MLKitDigitalInkRecognition\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"Security\\\"\",\n\t\t\t\t\t\"-framework\",\n\t\t\t\t\t\"\\\"nanopb\\\"\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.DigitalInkRecognitionExampleObjC;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t43941DE42491F2B00003EF8E /* Build configuration list for PBXNativeTarget \"DigitalInkRecognitionExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t43941DE52491F2B00003EF8E /* Debug */,\n\t\t\t\t43941DE62491F2B00003EF8E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t43A74FC623D9502C003CD995 /* Build configuration list for PBXProject \"DigitalInkRecognitionExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t43A74FF823D9502D003CD995 /* Debug */,\n\t\t\t\t43A74FF923D9502D003CD995 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t43A74FFA23D9502D003CD995 /* Build configuration list for PBXNativeTarget \"DigitalInkRecognitionExampleObjC\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t43A74FFB23D9502D003CD995 /* Debug */,\n\t\t\t\t43A74FFC23D9502D003CD995 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 43A74FC323D9502C003CD995 /* Project object */;\n}\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/AppDelegate.h",
    "content": "#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property(strong, nonatomic) UIWindow *window;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/AppDelegate.m",
    "content": "#import \"AppDelegate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application\n    didFinishLaunchingWithOptions:\n        (nullable NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {\n  // Override point for customization after application launch.\n  return YES;\n}\n\n#pragma mark - UISceneSession lifecycle\n\n- (UISceneConfiguration *)application:(UIApplication *)application\n    configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession\n                                   options:(UISceneConnectionOptions *)options\n    API_AVAILABLE(ios(13.0)) {\n  // Called when a new scene session is being created.\n  // Use this method to select a configuration to create the new scene with.\n  return [[UISceneConfiguration alloc] initWithName:@\"Default Configuration\"\n                                        sessionRole:connectingSceneSession.role];\n}\n\n- (void)application:(UIApplication *)application\n    didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions API_AVAILABLE(ios(13.0)) {\n  // Called when the user discards a scene session.\n  // If any sessions were discarded while the application was not running, this will be called\n  // shortly after application:didFinishLaunchingWithOptions. Use this method to release any\n  // resources that were specific to the discarded scenes, as they will not return.\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" xcode11CocoaTouchSystemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"16097\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina6_5\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"16087\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Stack View standard spacing\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"414\" height=\"896\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" tag=\"1\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" verticalCompressionResistancePriority=\"250\" insetsLayoutMarginsFromSafeArea=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z03-vP-65t\" userLabel=\"recognizedImage\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"44\" width=\"414\" height=\"720\"/>\n                            </imageView>\n                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" tag=\"1\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" verticalCompressionResistancePriority=\"250\" insetsLayoutMarginsFromSafeArea=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Xgt-Hs-cjx\" userLabel=\"drawnImage\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"44\" width=\"414\" height=\"720\"/>\n                            </imageView>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" verticalCompressionResistancePriority=\"1000\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yMa-Tg-tkJ\" userLabel=\"All Controls\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"764\" width=\"414\" height=\"98\"/>\n                                <subviews>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"center\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" verticalCompressionResistancePriority=\"1000\" text=\"\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sZY-jL-V5N\" userLabel=\"Message\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"414\" height=\"34\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"34\" id=\"PTc-he-IKD\"/>\n                                        </constraints>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"15\"/>\n                                        <nil key=\"textColor\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" spacingType=\"standard\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZAH-Gw-jA6\" userLabel=\"Language Controls\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"34\" width=\"414\" height=\"34\"/>\n                                        <subviews>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Language:\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CbP-21-1fH\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"72\" height=\"34\"/>\n                                                <color key=\"tintColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"15\"/>\n                                                <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <textField opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"left\" contentVerticalAlignment=\"center\" borderStyle=\"roundedRect\" textAlignment=\"natural\" minimumFontSize=\"17\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"l2s-aw-qOa\">\n                                                <rect key=\"frame\" x=\"80\" y=\"0.0\" width=\"334\" height=\"34\"/>\n                                                <color key=\"tintColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"15\"/>\n                                                <textInputTraits key=\"textInputTraits\"/>\n                                            </textField>\n                                        </subviews>\n                                    </stackView>\n                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" distribution=\"fillEqually\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tKw-MT-gsT\" userLabel=\"Buttons\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"68\" width=\"414\" height=\"30\"/>\n                                        <subviews>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3vg-og-fQ2\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"103.66666666666667\" height=\"30\"/>\n                                                <state key=\"normal\" title=\"Download\"/>\n                                                <connections>\n                                                    <action selector=\"didPressDownload\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"6kA-rr-rob\"/>\n                                                </connections>\n                                            </button>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OEf-cP-CgV\">\n                                                <rect key=\"frame\" x=\"103.66666666666669\" y=\"0.0\" width=\"103.33333333333331\" height=\"30\"/>\n                                                <state key=\"normal\" title=\"Delete\"/>\n                                                <connections>\n                                                    <action selector=\"didPressDelete\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"UbF-np-4rB\"/>\n                                                </connections>\n                                            </button>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CVF-Ff-gBp\">\n                                                <rect key=\"frame\" x=\"206.99999999999997\" y=\"0.0\" width=\"103.66666666666666\" height=\"30\"/>\n                                                <state key=\"normal\" title=\"Recognize\"/>\n                                                <connections>\n                                                    <action selector=\"didPressRecognize\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"Jru-Aa-hm9\"/>\n                                                </connections>\n                                            </button>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vwy-Wy-bcU\">\n                                                <rect key=\"frame\" x=\"310.66666666666669\" y=\"0.0\" width=\"103.33333333333331\" height=\"30\"/>\n                                                <state key=\"normal\" title=\"Clear\"/>\n                                                <connections>\n                                                    <action selector=\"didPressClear\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"3Eb-3P-Jvu\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                    </stackView>\n                                </subviews>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"yMa-Tg-tkJ\" secondAttribute=\"trailing\" id=\"3XU-P3-quG\"/>\n                            <constraint firstItem=\"yMa-Tg-tkJ\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" id=\"3lX-cc-kRk\"/>\n                            <constraint firstItem=\"Z03-vP-65t\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" id=\"KdI-ba-QzL\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"top\" secondItem=\"Z03-vP-65t\" secondAttribute=\"top\" id=\"ZHa-rc-I27\"/>\n                            <constraint firstItem=\"Xgt-Hs-cjx\" firstAttribute=\"top\" secondItem=\"Z03-vP-65t\" secondAttribute=\"top\" id=\"emc-ZZ-wXt\"/>\n                            <constraint firstItem=\"yMa-Tg-tkJ\" firstAttribute=\"top\" secondItem=\"Z03-vP-65t\" secondAttribute=\"bottom\" id=\"fm2-Mt-1WT\" userLabel=\"All Controls.top = recognizedImage.bottom\"/>\n                            <constraint firstItem=\"Xgt-Hs-cjx\" firstAttribute=\"trailing\" secondItem=\"Z03-vP-65t\" secondAttribute=\"trailing\" id=\"h1h-0Z-zw1\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"bottom\" secondItem=\"yMa-Tg-tkJ\" secondAttribute=\"bottom\" id=\"o0l-zs-rVA\"/>\n                            <constraint firstItem=\"Xgt-Hs-cjx\" firstAttribute=\"leading\" secondItem=\"Z03-vP-65t\" secondAttribute=\"leading\" id=\"oh7-ZU-GfR\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"Z03-vP-65t\" secondAttribute=\"trailing\" id=\"wcl-ft-pZc\"/>\n                            <constraint firstItem=\"Xgt-Hs-cjx\" firstAttribute=\"bottom\" secondItem=\"Z03-vP-65t\" secondAttribute=\"bottom\" id=\"yTx-bs-PN8\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                    <connections>\n                        <outlet property=\"drawnImage\" destination=\"Xgt-Hs-cjx\" id=\"vta-4X-NbX\"/>\n                        <outlet property=\"messageLabel\" destination=\"sZY-jL-V5N\" id=\"vRn-Bm-p5P\"/>\n                        <outlet property=\"recognizedImage\" destination=\"Z03-vP-65t\" id=\"7Jj-2f-yPu\"/>\n                        <outlet property=\"selectedLanguageField\" destination=\"l2s-aw-qOa\" id=\"gOp-cn-32W\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"136.875\" y=\"118.30985915492958\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/RecognizedInk.h",
    "content": "#ifndef RecognizedInk_h\n#define RecognizedInk_h\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class MLKInk;\n\n/**\n * Stores a piece of ink that has been sent to the recognizer, along with the recognition result\n * when it is returned. An array of these is used to represent the ink and results on the screen.\n */\n@interface RecognizedInk : NSObject\n\n/** Ink, displayed to the user. */\n@property(nonatomic) MLKInk *ink;\n/** Top recognition result candidate for the ink, displayed to the user. */\n@property(copy, nullable, nonatomic) NSString *text;\n\n/**\n * Creates a `RecognizedInk` with the given `Ink` once it is sent for recognition. Text is initially\n * empty.\n * @param ink The ink to be stored in the `RecognizedInk` object.\n * @return the initialized `RecognizedInk` object.\n */\n- (nullable instancetype)initWithInk:(MLKInk *)ink NS_DESIGNATED_INITIALIZER;\n\n- (nullable instancetype)init NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n\n#endif /* RecognizedInk_h */\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/RecognizedInk.m",
    "content": "#import \"RecognizedInk.h\"\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n@import MLKit;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation RecognizedInk : NSObject\n\n- (nullable instancetype)initWithInk:(MLKInk *)ink {\n  self = [super init];\n  if (self != nil) {\n    _ink = ink;\n  }\n  return self;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/SceneDelegate.h",
    "content": "#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>\n\n@property(strong, nonatomic) UIWindow* window;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/SceneDelegate.m",
    "content": "#import \"SceneDelegate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface SceneDelegate ()\n\n@end\n\n@implementation SceneDelegate\n\n- (void)scene:(UIScene *)scene\n    willConnectToSession:(UISceneSession *)session\n                 options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)) {\n  // Use this method to optionally configure and attach the UIWindow `window` to the provided\n  // UIWindowScene `scene`. If using a storyboard, the `window` property will automatically be\n  // initialized and attached to the scene. This delegate does not imply the connecting scene or\n  // session are new (see `application:configurationForConnectingSceneSession` instead).\n}\n\n- (void)sceneDidDisconnect:(UIScene *)scene API_AVAILABLE(ios(13.0)) {\n  // Called as the scene is being released by the system.\n  // This occurs shortly after the scene enters the background, or when its session is discarded.\n  // Release any resources associated with this scene that can be re-created the next time the scene\n  // connects. The scene may re-connect later, as its session was not necessarily discarded (see\n  // `application:didDiscardSceneSessions` instead).\n}\n\n- (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0)) {\n  // Called when the scene has moved from an inactive state to an active state.\n  // Use this method to restart any tasks that were paused (or not yet started) when the scene was\n  // inactive.\n}\n\n- (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0)) {\n  // Called when the scene will move from an active state to an inactive state.\n  // This may occur due to temporary interruptions (ex. an incoming phone call).\n}\n\n- (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0)) {\n  // Called as the scene transitions from the background to the foreground.\n  // Use this method to undo the changes made on entering the background.\n}\n\n- (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0)) {\n  // Called as the scene transitions from the foreground to the background.\n  // Use this method to save data, release shared resources, and store enough scene-specific state\n  // information to restore the scene back to its current state.\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/StrokeManager.h",
    "content": "#ifndef StrokeManager_h\n#define StrokeManager_h\n\n#import <UIKit/UIKit.h>\n\n#import \"RecognizedInk.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n * Protocol used by the `StrokeManager` to send requests back to the `ViewController` to update the\n * display.\n */\n@protocol StrokeManagerDelegate <NSObject>\n/** Clears any temporary ink managed by the caller. */\n- (void)clearInk;\n/** Redraws the ink and recognition results. */\n- (void)redraw;\n/** Display the given message to the user. */\n- (void)displayMessage:(NSString *)message;\n@end\n\n/**\n * The `StrokeManager` object is responsible for storing the ink and recognition results, and\n * managing the interaction with the recognizer. It receives the touch points as the user is drawing\n * from the `ViewController` (which takes care of rendering the ink), and stores them into an array\n * of `Stroke`s. When the user taps \"recognize\", the strokes are collected together into an `Ink`\n * object, and passed to the recognizer. The `StrokeManagerDelegate` protocol is used to inform the\n * `ViewController` when the display needs to be updated.\n *\n * The `StrokeManager` provides additional methods to handle other buttons in the UI, including\n * selecting a recognition language, downloading or deleting the recognition model, or clearing the\n * ink.\n */\n@interface StrokeManager : NSObject\n\n/**\n * Array of `RecognizedInk`s that have been sent to the recognizer along with any recognition\n * results.\n */\n@property(readonly, nonatomic) NSArray<RecognizedInk *> *recognizedInks;\n\n/**\n * Initializes internal state and stores a pointer to the view to allow for redrawing when ink is\n * sent to the recognizer or recognition results come back.\n */\n- (nullable instancetype)initWithDelegate:(nullable id<StrokeManagerDelegate>)delegate\n    NS_DESIGNATED_INITIALIZER;\n- (nullable instancetype)init NS_UNAVAILABLE;\n\n/** Function called by the `ViewController` to create the first point of a stroke. */\n- (void)startStrokeAtPoint:(CGPoint)point time:(NSTimeInterval)t;\n\n/** Function called by the `ViewController` to add a point to a stroke. */\n- (void)continueStrokeAtPoint:(CGPoint)point time:(NSTimeInterval)t;\n\n/** Function called by the `ViewController` to end a stroke. */\n- (void)endStrokeAtPoint:(CGPoint)point time:(NSTimeInterval)t;\n\n/** Clears all ink. */\n- (void)clear;\n\n/** Informs the `StrokeManager` of which recognizer to use for subsequent recognitions. */\n- (void)selectLanguage:(NSString *)languageTag;\n\n/**\n * Asks the `StrokeManager` to start downloading the recognition model indicated by\n * `selectLanguage:`.\n */\n- (void)downloadModel;\n\n/**\n * Check whether the model for the given language tag is already downloaded.\n */\n- (BOOL)isLanguageDownloaded:(NSString *)languageTag;\n\n/** Asks the `StrokeManager` to delete the reocngition model indicated by `selectLanguage:`. */\n- (void)deleteModel;\n\n/**\n * Asks the `StrokeManager` to recognize the unrecognized ink using the recognition model indicated\n * by `selectLanguage:`.\n */\n- (void)recognizeInk;\n\n@end\n\n#endif /* StrokeManager_h */\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/StrokeManager.m",
    "content": "#import \"StrokeManager.h\"\n\n#import <Foundation/Foundation.h>\n\n@import MLKit;\n\n#import \"ViewController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n * Conversion factor between `NSTimeInterval` and milliseconds, which is the unit used by the\n * recognizer.\n */\nstatic const double kMillisecondsPerTimeInterval = 1000.0;\n\n@interface StrokeManager ()\n/** Arrays used to keep the piece of ink that is currently being drawn. */\n@property(nullable, nonatomic) NSMutableArray<MLKStroke *> *strokes;\n@property(nullable, nonatomic) NSMutableArray<MLKStrokePoint *> *points;\n\n/** The recognizer that will translate the ink into text. */\n@property(nullable, nonatomic) MLKDigitalInkRecognizer *recognizer;\n\n/** The view that handles UI stuff. */\n@property(weak, nullable, nonatomic) id<StrokeManagerDelegate> delegate;\n\n/** Redeclared as `readwrite`. */\n@property(nonatomic) NSMutableArray<RecognizedInk *> *recognizedInks;\n\n/** Properties to track and manage the selected language and recognition model. */\n@property(nonatomic) MLKDigitalInkRecognitionModel *model;\n@property(nonatomic) MLKModelManager *modelManager;\n@end\n\n@implementation StrokeManager\n\n#pragma mark - Public\n\n/**\n * Initialization of internal variables as well as creating the model manager and setting up\n * observers of the recognition model downloading status.\n */\n- (nullable instancetype)initWithDelegate:(nullable id<StrokeManagerDelegate>)delegate {\n  self = [super init];\n  if (self != nil) {\n    _modelManager = [MLKModelManager modelManager];\n    _delegate = delegate;\n    _recognizedInks = [NSMutableArray array];\n\n    // Add observers for download notifications, and reflect the status back to the user.\n    __weak typeof(self) weakSelf = self;\n    [NSNotificationCenter.defaultCenter\n        addObserverForName:MLKModelDownloadDidSucceedNotification\n                    object:nil\n                     queue:NSOperationQueue.mainQueue\n                usingBlock:^(NSNotification *notification) {\n                  typeof(self) strongSelf = weakSelf;\n                  if (strongSelf == nil) {\n                    NSLog(@\"self == nil handling download success notification\");\n                    return;\n                  }\n                  if ([notification.userInfo[MLKModelDownloadUserInfoKeyRemoteModel]\n                          isEqual:strongSelf.model]) {\n                    [strongSelf.delegate displayMessage:@\"Model download succeeded\"];\n                  }\n                }];\n    [NSNotificationCenter.defaultCenter\n        addObserverForName:MLKModelDownloadDidFailNotification\n                    object:nil\n                     queue:NSOperationQueue.mainQueue\n                usingBlock:^(NSNotification *notification) {\n                  typeof(self) strongSelf = weakSelf;\n                  if (strongSelf == nil) {\n                    NSLog(@\"self == nil handling download fail notification\");\n                    return;\n                  }\n                  if ([notification.userInfo[MLKModelDownloadUserInfoKeyRemoteModel]\n                          isEqual:strongSelf.model]) {\n                    [strongSelf.delegate displayMessage:@\"Model download failed\"];\n                  }\n                }];\n  }\n  return self;\n}\n\n/**\n * Given a language tag, looks up the cooresponding model identifier and initializes the model. Note\n * that this doesn't actually download the model, which is triggered manually by the user for the\n * purposes of this demo app.\n */\n- (void)selectLanguage:(NSString *)languageTag {\n  MLKDigitalInkRecognitionModelIdentifier *identifier =\n      [MLKDigitalInkRecognitionModelIdentifier modelIdentifierForLanguageTag:languageTag];\n  self.model = [[MLKDigitalInkRecognitionModel alloc] initWithModelIdentifier:identifier];\n  self.recognizer = nil;\n  [self.delegate\n      displayMessage:[NSString stringWithFormat:@\"Selected language with tag %@\", languageTag]];\n}\n\n/**\n * Check whether the model for the given language tag is already downloaded.\n */\n- (BOOL)isLanguageDownloaded:(NSString *)languageTag {\n  MLKDigitalInkRecognitionModelIdentifier *identifier =\n      [MLKDigitalInkRecognitionModelIdentifier modelIdentifierForLanguageTag:languageTag];\n  MLKDigitalInkRecognitionModel *model =\n      [[MLKDigitalInkRecognitionModel alloc] initWithModelIdentifier:identifier];\n  return [self.modelManager isModelDownloaded:model];\n}\n\n/**\n * Actually downloads the model. This happens asynchronously with the user being shown status\n * messages when the download completes or fails.\n */\n- (void)downloadModel {\n  if ([self.modelManager isModelDownloaded:self.model]) {\n    [self.delegate displayMessage:@\"Model is already downloaded\"];\n    return;\n  }\n\n  [self.delegate displayMessage:@\"Starting download\"];\n  // The NSProgress object returned by downloadModel: currently only takes on the values 0% or 100%\n  // so is not very useful. Instead we'll rely on the outcome listeners in the initializer to\n  // inform the user if a download succeeds or fails.\n  [self.modelManager\n      downloadModel:self.model\n         conditions:[[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES\n                                                         allowsBackgroundDownloading:YES]];\n}\n\n/** Deletes the currently selected model. */\n- (void)deleteModel {\n  if (![self.modelManager isModelDownloaded:self.model]) {\n    [self.delegate displayMessage:@\"Model not downloaded, nothing to delete\"];\n    return;\n  }\n  __weak typeof(self) weakSelf = self;\n  [self.modelManager deleteDownloadedModel:self.model\n                                completion:^(NSError *_Nullable error) {\n                                  typeof(self) strongSelf = weakSelf;\n                                  if (strongSelf == nil) {\n                                    NSLog(@\"self == nil handling model download completion\");\n                                    return;\n                                  }\n                                  [strongSelf.delegate displayMessage:@\"Model deleted\"];\n                                }];\n}\n\n/**\n * Actually carries out the recognition. The recognition may happen asynchronously so there's a\n * callback that handles the results when they are ready.\n */\n- (void)recognizeInk {\n  if (self.strokes.count == 0) {\n    [self.delegate displayMessage:@\"No ink to recognize\"];\n    return;\n  }\n  if (![self.modelManager isModelDownloaded:self.model]) {\n    [self.delegate displayMessage:@\"Recognizer model not downloaded\"];\n    return;\n  }\n  if (self.recognizer == nil) {\n    [self.delegate displayMessage:@\"Initializing recognizer\"];\n    MLKDigitalInkRecognizerOptions *options =\n        [[MLKDigitalInkRecognizerOptions alloc] initWithModel:self.model];\n    self.recognizer = [MLKDigitalInkRecognizer digitalInkRecognizerWithOptions:options];\n    if (self.recognizer == nil) {\n      [self.delegate displayMessage:@\"Could not initialize recognizer\"];\n      return;\n    } else {\n      [self.delegate displayMessage:@\"Initialized recognizer\"];\n    }\n  }\n\n  // Turn the list of strokes into an `Ink`, and add this ink to the `recognizedInks` array.\n  MLKInk *ink = [[MLKInk alloc] initWithStrokes:self.strokes];\n  RecognizedInk *recognizedInk = [[RecognizedInk alloc] initWithInk:ink];\n  [_recognizedInks addObject:recognizedInk];\n  // Clear the currently being drawn ink, and display the ink from `recognizedInks` (which results\n  // in it changing color).\n  [self.delegate redraw];\n  [self.delegate clearInk];\n  self.strokes = nil;\n  // Start the recognizer. Callback function will store the recognized text and tell the\n  // `ViewController` to redraw the screen to show it.\n  __weak typeof(self) weakSelf = self;\n  [self.recognizer\n      recognizeInk:ink\n        completion:^(MLKDigitalInkRecognitionResult *_Nullable result, NSError *_Nullable error) {\n          typeof(self) strongSelf = weakSelf;\n          if (strongSelf == nil) {\n            NSLog(@\"self == nil handling recognition completion\");\n            return;\n          }\n          if (result.candidates.count > 0) {\n            recognizedInk.text = result.candidates[0].text;\n            NSString *message = [@\"Recognized: \" stringByAppendingString:result.candidates[0].text];\n            if (result.candidates[0].score != nil) {\n              message = [message\n                  stringByAppendingFormat:@\" score %f\", result.candidates[0].score.floatValue];\n            }\n            [strongSelf.delegate displayMessage:message];\n          } else {\n            recognizedInk.text = @\"error\";\n            [strongSelf.delegate displayMessage:@\"Recognition error\"];\n          }\n          [strongSelf.delegate redraw];\n        }];\n}\n\n/** Clear out all the ink and other state. */\n- (void)clear {\n  self.recognizedInks = [NSMutableArray array];\n  self.strokes = nil;\n}\n\n/** Begins a new stroke when the user touches the screen. */\n- (void)startStrokeAtPoint:(CGPoint)point time:(NSTimeInterval)t {\n  self.points = [NSMutableArray array];\n  [self.points addObject:[[MLKStrokePoint alloc] initWithX:point.x\n                                                         y:point.y\n                                                         t:t * kMillisecondsPerTimeInterval]];\n}\n\n/** Adds an additional point to the stroke when the user moves their finger. */\n- (void)continueStrokeAtPoint:(CGPoint)point time:(NSTimeInterval)t {\n  [self.points addObject:[[MLKStrokePoint alloc] initWithX:point.x\n                                                         y:point.y\n                                                         t:t * kMillisecondsPerTimeInterval]];\n}\n\n/** Completes a stroke when the user lifts their finger. */\n- (void)endStrokeAtPoint:(CGPoint)point time:(NSTimeInterval)t {\n  [self.points addObject:[[MLKStrokePoint alloc] initWithX:point.x\n                                                         y:point.y\n                                                         t:t * kMillisecondsPerTimeInterval]];\n  // Create an array of strokes if it doesn't exist already, and add this stroke to it.\n  if (self.strokes == nil) {\n    self.strokes = [NSMutableArray array];\n  }\n  [self.strokes addObject:[[MLKStroke alloc] initWithPoints:self.points]];\n  self.points = nil;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/ViewController.h",
    "content": "#import <UIKit/UIKit.h>\n\n#import \"RecognizedInk.h\"\n#import \"StrokeManager.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n * The `ViewController` manages the display seen by the user. The drawing canvas is actually two\n * overlapping image views. The top one contains the ink that the user is drawing before it is sent\n * to the recognizer. It can be thought of as a temporary buffer for ink in progress. When the user\n * presses the \"Recognize\" button, the ink is transferred to the other canvas, which displays a\n * grayed out version of the ink together with the recognition result.\n *\n * The management of the interaction with the recognizer happens in `StrokeManager`.\n * `ViewController` just takes care of receiving user events, rendering the temporary ink, and\n * handles redraw requests from the `StrokeManager` when the ink is recognized. This latter request\n * comes through the `StrokeManagerDelegate` protocol.\n *\n * The `ViewController` provides a number of buttons for controlling the `StrokeManager` which allow\n * for selecting the recognition language, downloading or deleting the recognition model, triggering\n * recognition, and clearing the ink.\n */\n@interface ViewController\n    : UIViewController <StrokeManagerDelegate, UIPickerViewDelegate, UIPickerViewDataSource>\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/ViewController.m",
    "content": "#import \"ViewController.h\"\n\n#import \"StrokeManager.h\"\n\n@import MLKit;\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Constant defining how to render strokes. */\nstatic const CGFloat kBrushWidth = 2.0;\n\n@interface ViewController ()\n\n/** Languager selected by default based on the system locale settings. */\n@property(nonatomic) NSString *defaultLanguage;\n\n/** All possible language tags supported by the digital ink recognition API, ordered as they are\n * shown in the UI. */\n@property(nonatomic) NSArray<NSString *> *allLanguageTags;\n\n/** Mapping between the language tag and the display name of the language. */\n@property(nonatomic) NSMutableDictionary<NSString *, NSString *> *languageTagDisplayNames;\n\n/**\n * Object that takes care of the logic of saving the ink, sending ink to the recognizer after a\n * long enough pause, and storing the recognition results.\n */\n@property(nonatomic) StrokeManager *strokeManager;\n\n/** Coordinates of the previous touch point as the user is drawing ink. */\n@property(nonatomic) CGPoint lastPoint;\n\n/** This view displays all the ink that has been sent for recognition, and recognition results. */\n@property(weak, nonatomic) IBOutlet UIImageView *recognizedImage;\n\n/** This view shows only the ink that is currently being drawn, before sending for recognition. */\n@property(weak, nonatomic) IBOutlet UIImageView *drawnImage;\n\n/**\n * Input field showing the currently selected language; when tapped brings up the `languagePicker`.\n */\n@property(weak, nonatomic) IBOutlet UITextField *selectedLanguageField;\n\n/** Text region used to display status messages to the user about the results of their actions. */\n@property(weak, nonatomic) IBOutlet UILabel *messageLabel;\n\n@end\n\n@implementation ViewController\n\n#pragma mark - IBAction\n\n/** Clear button clears the canvases and also tells the `StrokeManager` to delete everything. */\n- (IBAction)didPressClear {\n  self.recognizedImage.image = nil;\n  self.drawnImage.image = nil;\n  [self.strokeManager clear];\n  [self displayMessage:@\"\"];\n}\n\n/** Relays the download model command to the `StrokeManager`. */\n- (IBAction)didPressDownload {\n  [self.strokeManager downloadModel];\n}\n\n/** Relays the delete model command to the `StrokeManager`. */\n- (IBAction)didPressDelete {\n  [self.strokeManager deleteModel];\n}\n\n/** Relays the recognize ink command to the `StrokeManager`. */\n- (IBAction)didPressRecognize {\n  [self.strokeManager recognizeInk];\n}\n\n#pragma mark - UIViewController\n\n/** Initializes the view, in turn creating the StrokeManager and recognizer. */\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  // Create a `StrokeManager` to store the drawn ink. This also creates the recognizer object.\n  self.strokeManager = [[StrokeManager alloc] initWithDelegate:self];\n\n  // Create the language picker which will be brought up when the user taps the selected language\n  // field.\n  UIPickerView *languagePicker = [[UIPickerView alloc] init];\n  languagePicker.delegate = self;\n  languagePicker.dataSource = self;\n\n  // Toolbar on top of the picker which will be used to finalize the selection.\n  UIToolbar *toolbar =\n      [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];\n  UIBarButtonItem *leftSpace =\n      [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace\n                                                    target:nil\n                                                    action:nil];\n  UIBarButtonItem *done = [[UIBarButtonItem alloc] initWithTitle:@\"Select Language\"\n                                                           style:UIBarButtonItemStyleDone\n                                                          target:self.selectedLanguageField\n                                                          action:@selector(resignFirstResponder)];\n  UIBarButtonItem *rightSpace =\n      [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace\n                                                    target:nil\n                                                    action:nil];\n  [toolbar setItems:@[ leftSpace, done, rightSpace ]];\n\n  // Associate the above two UI elements with the selected language input field.\n  self.selectedLanguageField.inputView = languagePicker;\n  self.selectedLanguageField.inputAccessoryView = toolbar;\n\n  // Find the language most closely associated with the preferred language, falling back to English\n  // if we can't find a match.\n  NSString *language = [[NSLocale preferredLanguages] firstObject];\n  MLKDigitalInkRecognitionModelIdentifier *identifier =\n      [MLKDigitalInkRecognitionModelIdentifier modelIdentifierFromLanguageTag:language error:nil];\n  if (identifier == nil) {\n    identifier = [MLKDigitalInkRecognitionModelIdentifier modelIdentifierFromLanguageTag:@\"en\"\n                                                                                   error:nil];\n  }\n  [self.strokeManager selectLanguage:identifier.languageTag];\n  self.defaultLanguage = identifier.languageTag;\n\n  // Initialize the language picker and scroll it to have the above language selected.\n  [self computeAllLanguageTags];\n  [languagePicker reloadAllComponents];\n  [languagePicker selectRow:[self.allLanguageTags indexOfObject:identifier.languageTag]\n                inComponent:0\n                   animated:NO];\n\n  // This has to happen after computeAllLanguageTags as that function also sets up the display\n  // names mapping.\n  self.selectedLanguageField.text = self.languageTagDisplayNames[identifier.languageTag];\n}\n\n/** Handle start of stroke: Draw the point, and pass it along to the `StrokeManager`. */\n- (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event {\n  UITouch *touch = [touches anyObject];\n  // Since this is a new stroke, make last point the same as the current point.\n  self.lastPoint = [touch locationInView:self.drawnImage];\n  NSTimeInterval time = [touch timestamp];\n  [self drawLineSegment:touch];\n  [self.strokeManager startStrokeAtPoint:self.lastPoint time:time];\n}\n\n/** Handle continuing a stroke: Draw the line segment, and pass along to the `StrokeManager`. */\n- (void)touchesMoved:(NSSet *)touches withEvent:(nullable UIEvent *)event {\n  UITouch *touch = [touches anyObject];\n  [self drawLineSegment:touch];\n  NSTimeInterval time = [touch timestamp];\n  [self.strokeManager continueStrokeAtPoint:self.lastPoint time:time];\n}\n\n/** Handle end of stroke: Draw the line segment, and pass along to the `StrokeManager`. */\n- (void)touchesEnded:(NSSet *)touches withEvent:(nullable UIEvent *)event {\n  UITouch *touch = [touches anyObject];\n  [self drawLineSegment:touch];\n  NSTimeInterval time = [touch timestamp];\n  [self.strokeManager endStrokeAtPoint:self.lastPoint time:time];\n}\n\n#pragma mark - StrokeManagerDelegate\n\n/** Displays a status message from the `StrokeManager` to the user. */\n- (void)displayMessage:(NSString *)message {\n  self.messageLabel.text = message;\n}\n\n/**\n * Clear temporary ink in progress. This is invoked by the `StrokeManager` when the temporary ink is\n * sent to the recognizer.\n */\n- (void)clearInk {\n  self.drawnImage.image = nil;\n}\n\n/**\n * Iterate through all the saved ink/recognition results in the `StrokeManager` and render them.\n * This is invoked by the `StrokeManager` when an ink is sent to the recognizer, and when a\n * recognition result is returned.\n */\n- (void)redraw {\n  self.recognizedImage.image = nil;\n  NSArray<RecognizedInk *> *recognizedInks = [self.strokeManager recognizedInks];\n  for (NSUInteger i = 0; i < [recognizedInks count]; i++) {\n    [self drawInk:recognizedInks[i].ink];\n    if (recognizedInks[i].text != nil) {\n      [self drawText:recognizedInks[i]];\n    }\n  }\n}\n\n#pragma mark - UIPickerViewDelegate\n\n/**\n * Invoked by the language picker when the user scrolls to a particular position in either\n * component. In the left component, the language subtag is selected, so the right component needs\n * to be updated with corresponding list of full language codes and the first one is selected by\n * default; also the `StrokeManager` is informed.\n */\n- (void)pickerView:(UIPickerView *)pickerView\n      didSelectRow:(NSInteger)row\n       inComponent:(NSInteger)component {\n  if (component == 0) {\n    self.selectedLanguageField.text = self.languageTagDisplayNames[self.allLanguageTags[row]];\n    [self.strokeManager selectLanguage:self.allLanguageTags[row]];\n  }\n}\n\n/**\n * Invoked by the language picker to get the contents of each row. If the model for the language\n * is already downloaded, prepend the title with the string \"[D]\".\n */\n- (nullable NSString *)pickerView:(UIPickerView *)pickerView\n                      titleForRow:(NSInteger)row\n                     forComponent:(NSInteger)component {\n  NSString *tag = self.allLanguageTags[row];\n  NSString *title = self.languageTagDisplayNames[tag];\n  if ([self.strokeManager isLanguageDownloaded:tag]) {\n    return [@\"[D] \" stringByAppendingString:title];\n  } else {\n    return title;\n  }\n}\n\n#pragma mark - UIPickerViewDataSource\n\n/** Invoked by the language picker to find out how many entries are in each component. */\n- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {\n  return self.allLanguageTags.count;\n}\n\n/** Invoked by the language picker to get the number of components. */\n- (NSInteger)numberOfComponentsInPickerView:(nonnull UIPickerView *)pickerView {\n  return 1;\n}\n\n#pragma mark - Private\n\n/**\n * Draws a line segment from `self.lastPoint` to the current touch point given in the argument\n * to the temporary ink canvas.\n */\n- (void)drawLineSegment:(UITouch *)touch {\n  CGPoint currentPoint = [touch locationInView:self.drawnImage];\n\n  UIGraphicsBeginImageContext(self.drawnImage.frame.size);\n  [self.drawnImage.image drawInRect:CGRectMake(0, 0, self.drawnImage.frame.size.width,\n                                               self.drawnImage.frame.size.height)];\n  CGContextMoveToPoint(UIGraphicsGetCurrentContext(), self.lastPoint.x, self.lastPoint.y);\n  CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);\n  CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);\n  CGContextSetLineWidth(UIGraphicsGetCurrentContext(), kBrushWidth);\n  // Unrecognized strokes are drawn in blue.\n  CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0, 0, 1, 1);\n  CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeNormal);\n  CGContextStrokePath(UIGraphicsGetCurrentContext());\n  CGContextFlush(UIGraphicsGetCurrentContext());\n  self.drawnImage.image = UIGraphicsGetImageFromCurrentImageContext();\n  UIGraphicsEndImageContext();\n\n  self.lastPoint = currentPoint;\n}\n\n/**\n * Goes through all language tags supported by the library, and attempt to create human readable\n * names for each of them (although the library supports more languages than iOS's NSLocale library\n * knows about). Ordered the languages alphabetically by their display names, but places the default\n * language and the non-text recognizers (emoji, autodraw, and shapes) at the top of the list.\n */\n- (void)computeAllLanguageTags {\n  NSSet<MLKDigitalInkRecognitionModelIdentifier *> *allModelIdentifiers =\n      [MLKDigitalInkRecognitionModelIdentifier allModelIdentifiers];\n  self.languageTagDisplayNames = [NSMutableDictionary<NSString *, NSString *> dictionary];\n  NSLocale *locale = [NSLocale currentLocale];\n  NSMutableArray<NSString *> *nonText = [NSMutableArray<NSString *> array];\n  NSMutableArray<NSString *> *allTags = [NSMutableArray<NSString *> array];\n  [allModelIdentifiers enumerateObjectsUsingBlock:^(\n                           MLKDigitalInkRecognitionModelIdentifier *identifier, BOOL *stop) {\n    NSString *tag = identifier.languageTag;\n    NSString *displayName;\n    if ([tag hasPrefix:@\"zxx-\"]) {\n      [nonText addObject:tag];\n      displayName = [[tag componentsSeparatedByString:@\"-x-\"] lastObject];\n    } else {\n      displayName = [locale localizedStringForLocaleIdentifier:tag];\n    }\n    if (displayName == nil) {\n      displayName = identifier.languageSubtag;\n      if (identifier.regionSubtag != nil) {\n        displayName = [displayName stringByAppendingFormat:@\" (%@)\", identifier.regionSubtag];\n      }\n      if (identifier.scriptSubtag != nil) {\n        displayName = [displayName stringByAppendingFormat:@\" %@ Script\", identifier.scriptSubtag];\n      }\n    }\n    self.languageTagDisplayNames[tag] = displayName;\n    [allTags addObject:tag];\n  }];\n  self.allLanguageTags = [allTags sortedArrayUsingComparator:^(NSString *a, NSString *b) {\n    int priorityA = 2;\n    if (a == self.defaultLanguage) {\n      priorityA = 0;\n    } else if ([nonText indexOfObject:a] != NSNotFound) {\n      priorityA = 1;\n    }\n    int priorityB = 2;\n    if (b == self.defaultLanguage) {\n      priorityB = 0;\n    } else if ([nonText indexOfObject:b] != NSNotFound) {\n      priorityB = 1;\n    }\n    if (priorityA < priorityB) {\n      return NSOrderedAscending;\n    }\n    if (priorityA > priorityB) {\n      return NSOrderedDescending;\n    }\n    return [self.languageTagDisplayNames[a] caseInsensitiveCompare:self.languageTagDisplayNames[b]];\n  }];\n}\n\n/** Given an `Ink`, draw it into the `recognizedImage` canvas in gray. */\n- (void)drawInk:(MLKInk *)ink {\n  UIGraphicsBeginImageContext(self.drawnImage.frame.size);\n  [self.recognizedImage.image drawInRect:CGRectMake(0, 0, self.drawnImage.frame.size.width,\n                                                    self.drawnImage.frame.size.height)];\n  for (MLKStroke *stroke in ink.strokes) {\n    if (stroke.points.count == 0) {\n      continue;\n    }\n    MLKStrokePoint *point = stroke.points[0];\n    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), point.x, point.y);\n    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), point.x, point.y);\n    for (MLKStrokePoint *point in stroke.points) {\n      CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), point.x, point.y);\n    }\n  }\n  CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);\n  CGContextSetLineWidth(UIGraphicsGetCurrentContext(), kBrushWidth);\n  // Recognized strokes are drawn in gray.\n  CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.7, 0.7, 0.7, 1.0);\n  CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeNormal);\n  CGContextStrokePath(UIGraphicsGetCurrentContext());\n  CGContextFlush(UIGraphicsGetCurrentContext());\n  self.recognizedImage.image = UIGraphicsGetImageFromCurrentImageContext();\n  UIGraphicsEndImageContext();\n}\n\n/** Given an `Ink`, returned the bounding box of the ink. */\n- (CGRect)getInkRect:(MLKInk *)ink {\n  CGRect rect = CGRectNull;\n  if ([ink.strokes count] == 0) {\n    return rect;\n  }\n\n  for (MLKStroke *stroke in ink.strokes) {\n    for (MLKStrokePoint *point in stroke.points) {\n      rect = CGRectUnion(rect, CGRectMake(point.x, point.y, 0, 0));\n    }\n  }\n  // Make the minimum size 10x10 pixels.\n  rect = CGRectUnion(rect, CGRectMake(rect.origin.x + rect.size.width / 2 - 5,\n                                      rect.origin.y + rect.size.height / 2 - 5, 10, 10));\n  return rect;\n}\n\n/**\n * Given a `recognizedInk`, compute the bounding box of the ink that it contains, and render the\n * text at roughly the same size as the bounding box.\n */\n- (void)drawText:(RecognizedInk *)recognizedInk {\n  CGRect rect = [self getInkRect:recognizedInk.ink];\n  UIGraphicsBeginImageContext(self.drawnImage.frame.size);\n  [self.recognizedImage.image drawInRect:CGRectMake(0, 0, self.drawnImage.frame.size.width,\n                                                    self.drawnImage.frame.size.height)];\n  CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeNormal);\n\n  CGFloat arbitrarySize = 20;\n  UIFont *font = [UIFont systemFontOfSize:arbitrarySize];\n  NSDictionary<NSAttributedStringKey, id> *attributes =\n      @{NSFontAttributeName : font, NSForegroundColorAttributeName : [UIColor greenColor]};\n  CGSize size = [recognizedInk.text sizeWithAttributes:attributes];\n  if (size.width <= 0) {\n    size.width = 1;\n  }\n  if (size.height <= 0) {\n    size.height = 1;\n  }\n  CGContextTranslateCTM(UIGraphicsGetCurrentContext(), floor(rect.origin.x), floor(rect.origin.y));\n  CGContextScaleCTM(UIGraphicsGetCurrentContext(), ceil(rect.size.width) / size.width,\n                    ceil(rect.size.height) / size.height);\n  [recognizedInk.text drawAtPoint:CGPointMake(0, 0) withAttributes:attributes];\n\n  CGContextFlush(UIGraphicsGetCurrentContext());\n  self.recognizedImage.image = UIGraphicsGetImageFromCurrentImageContext();\n  UIGraphicsEndImageContext();\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/DigitalInkRecognitionExampleObjC/main.m",
    "content": "#import <UIKit/UIKit.h>\n\n#import \"AppDelegate.h\"\n\nint main(int argc, char* argv[]) {\n  NSString* appDelegateClassName;\n  @autoreleasepool {\n    // Setup code that might create autoreleased objects goes here.\n    appDelegateClassName = NSStringFromClass([AppDelegate class]);\n  }\n  return UIApplicationMain(argc, argv, nil, appDelegateClassName);\n}\n"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/Podfile",
    "content": "platform :ios, '15.5'\nuse_frameworks!\n\nproject 'DigitalInkRecognitionExample.xcodeproj'\n\npod 'GoogleMLKit/DigitalInkRecognition', '9.0.0'\n\ntarget 'DigitalInkRecognitionExample' do\nend\n\ntarget 'DigitalInkRecognitionExampleObjC' do\nend\n\npost_install do |installer|\n  installer.aggregate_targets.each do |target|\n    target.xcconfigs.each do |variant, xcconfig|\n      xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)\n      IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n    end\n  end\n  installer.generated_projects.each do |project|\n    project.targets.each do |target|\n        target.build_configurations.each do |config|\n            config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'\n            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'\n         end\n    end\n  end\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference\n        xcconfig_path = config.base_configuration_reference.real_path\n        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n      end\n    end\n  end\nend"
  },
  {
    "path": "ios/quickstarts/digitalinkrecognition/README.md",
    "content": "ML Kit Digital Ink Recognition Quickstart\n=======================\n\n- [Read more about ML Kit Digital Ink Recognition](https://developers.google.com/ml-kit/vision/digital-ink-recognition/ios)\n\nIntroduction\n------------\n\nThe ML Kit Digital Ink Recognition iOS Quickstart app demonstrates how to use\nthe Digital Ink Recognition feature of ML Kit to perform digital ink recognition\nin your application.\n\nGetting Started\n---------------\n\n- Run the sample on your iOS device or simulator.\n- Draw on the screen and see your handwriting recognized and turned into text.\n\nSupport\n-------\n\n- [Stack Overflow](https://stackoverflow.com/questions/tagged/google-mlkit)\n\nLicense\n-------\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/Assets.xcassets/cloud_download_24pt.imageset/Contents.json",
    "content": "{\n    \"images\": [\n        {\n            \"filename\": \"cloud_download_24pt_1x.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"filename\": \"cloud_download_24pt_2x.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"filename\": \"cloud_download_24pt_3x.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"3x\"\n        }\n    ],\n    \"info\": {\n        \"author\": \"xcode\",\n        \"template-rendering-intent\": \"template\",\n        \"version\": 1\n    }\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/Assets.xcassets/delete_24pt.imageset/Contents.json",
    "content": "{\n    \"images\": [\n        {\n            \"filename\": \"delete_24pt_1x.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"filename\": \"delete_24pt_2x.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"filename\": \"delete_24pt_3x.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"3x\"\n        }\n    ],\n    \"info\": {\n        \"author\": \"xcode\",\n        \"template-rendering-intent\": \"template\",\n        \"version\": 1\n    }\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExample/AppDelegate.swift",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n  var window: UIWindow?\n\n  func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    return true\n  }\n}\n\n#if !swift(>=4.2)\n  extension UIApplication {\n    typealias LaunchOptionsKey = UIApplicationLaunchOptionsKey\n  }\n#endif  // !swift(>=4.2)\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExample/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExample/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"19455\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"OvN-fm-fpv\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"19454\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Models-->\n        <scene sceneID=\"iTE-pF-zfs\">\n            <objects>\n                <tableViewController id=\"lti-iO-OpS\" customClass=\"ModelManagementViewController\" sceneMemberID=\"viewController\">\n                    <tableView key=\"view\" clipsSubviews=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" dataMode=\"prototypes\" style=\"plain\" separatorStyle=\"default\" rowHeight=\"-1\" estimatedRowHeight=\"-1\" sectionHeaderHeight=\"28\" sectionFooterHeight=\"28\" id=\"zDI-qD-beG\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <connections>\n                            <outlet property=\"dataSource\" destination=\"lti-iO-OpS\" id=\"eL8-Qg-oN0\"/>\n                            <outlet property=\"delegate\" destination=\"lti-iO-OpS\" id=\"5uA-T6-xXD\"/>\n                        </connections>\n                    </tableView>\n                    <tabBarItem key=\"tabBarItem\" title=\"Models\" image=\"square.and.arrow.down.on.square\" catalog=\"system\" landscapeImage=\"square.and.arrow.down.on.square\" id=\"FMl-Pi-ZGR\"/>\n                    <simulatedTabBarMetrics key=\"simulatedBottomBarMetrics\"/>\n                </tableViewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"P0K-Ol-wtt\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-905\" y=\"-725\"/>\n        </scene>\n        <!--Entity Extraction View-->\n        <scene sceneID=\"vgt-Nu-7zB\">\n            <objects>\n                <viewController title=\"Entity Extraction View\" id=\"mOJ-Ji-nr9\" customClass=\"EntityViewController\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" autoresizesSubviews=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2S1-xQ-hsT\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"618\"/>\n                        <subviews>\n                            <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" text=\"Write here e.g. Let's meet at 1:30pm at Maggies tomorrow. Call me at 917-000-0000.\" textAlignment=\"natural\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CU6-Hv-afs\" userLabel=\"Input Text View\">\n                                <rect key=\"frame\" x=\"10\" y=\"5\" width=\"355\" height=\"200\"/>\n                                <color key=\"backgroundColor\" systemColor=\"groupTableViewBackgroundColor\"/>\n                                <color key=\"textColor\" systemColor=\"labelColor\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\" autocorrectionType=\"no\"/>\n                            </textView>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" misplaced=\"YES\" text=\"Overall language\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4a3-sa-Vl0\" userLabel=\"Language Label\">\n                                <rect key=\"frame\" x=\"10\" y=\"214\" width=\"349\" height=\"21\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <nil key=\"textColor\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <pickerView contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"13G-zM-sBK\">\n                                <rect key=\"frame\" x=\"10\" y=\"234\" width=\"355\" height=\"150\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"150\" id=\"O3G-WY-Hvc\"/>\n                                </constraints>\n                            </pickerView>\n                            <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" editable=\"NO\" textAlignment=\"natural\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dxc-dV-fix\" userLabel=\"Output Text View\">\n                                <rect key=\"frame\" x=\"10\" y=\"392\" width=\"355\" height=\"221\"/>\n                                <color key=\"backgroundColor\" systemColor=\"groupTableViewBackgroundColor\"/>\n                                <color key=\"textColor\" systemColor=\"labelColor\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\"/>\n                            </textView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"0kN-5k-7zN\"/>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"Dxc-dV-fix\" firstAttribute=\"bottom\" secondItem=\"0kN-5k-7zN\" secondAttribute=\"bottom\" constant=\"-5\" id=\"0KU-Ju-0LQ\"/>\n                            <constraint firstItem=\"CU6-Hv-afs\" firstAttribute=\"top\" secondItem=\"0kN-5k-7zN\" secondAttribute=\"top\" constant=\"5\" id=\"9g8-hP-5XR\"/>\n                            <constraint firstItem=\"13G-zM-sBK\" firstAttribute=\"trailing\" secondItem=\"4a3-sa-Vl0\" secondAttribute=\"trailing\" id=\"AJ8-7e-7Ln\"/>\n                            <constraint firstItem=\"CU6-Hv-afs\" firstAttribute=\"leading\" secondItem=\"2S1-xQ-hsT\" secondAttribute=\"leading\" constant=\"10\" id=\"BID-N1-6HE\"/>\n                            <constraint firstItem=\"CU6-Hv-afs\" firstAttribute=\"trailing\" secondItem=\"2S1-xQ-hsT\" secondAttribute=\"trailing\" constant=\"-10\" id=\"FvQ-Kl-bGj\"/>\n                            <constraint firstItem=\"CU6-Hv-afs\" firstAttribute=\"bottom\" secondItem=\"4a3-sa-Vl0\" secondAttribute=\"top\" constant=\"-8\" id=\"GHL-pP-0cX\"/>\n                            <constraint firstItem=\"Dxc-dV-fix\" firstAttribute=\"trailing\" secondItem=\"2S1-xQ-hsT\" secondAttribute=\"trailing\" constant=\"-10\" id=\"GPK-NP-iex\"/>\n                            <constraint firstItem=\"13G-zM-sBK\" firstAttribute=\"centerY\" secondItem=\"2S1-xQ-hsT\" secondAttribute=\"centerY\" id=\"KhG-k6-G5q\"/>\n                            <constraint firstItem=\"Dxc-dV-fix\" firstAttribute=\"leading\" secondItem=\"2S1-xQ-hsT\" secondAttribute=\"leading\" constant=\"10\" id=\"LSd-4b-PPO\"/>\n                            <constraint firstItem=\"Dxc-dV-fix\" firstAttribute=\"top\" secondItem=\"13G-zM-sBK\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"OYa-WE-jN3\"/>\n                            <constraint firstItem=\"4a3-sa-Vl0\" firstAttribute=\"trailing\" secondItem=\"0kN-5k-7zN\" secondAttribute=\"trailing\" constant=\"-10\" id=\"RDt-fn-hRr\"/>\n                            <constraint firstItem=\"4a3-sa-Vl0\" firstAttribute=\"leading\" secondItem=\"0kN-5k-7zN\" secondAttribute=\"leading\" constant=\"10\" id=\"jBE-1A-72J\"/>\n                            <constraint firstItem=\"13G-zM-sBK\" firstAttribute=\"leading\" secondItem=\"4a3-sa-Vl0\" secondAttribute=\"leading\" id=\"ybp-P5-00w\"/>\n                            <constraint firstItem=\"13G-zM-sBK\" firstAttribute=\"top\" secondItem=\"4a3-sa-Vl0\" secondAttribute=\"bottom\" id=\"zr8-ab-Bay\"/>\n                        </constraints>\n                    </view>\n                    <extendedEdge key=\"edgesForExtendedLayout\"/>\n                    <tabBarItem key=\"tabBarItem\" title=\"Entities\" image=\"square.and.pencil\" catalog=\"system\" landscapeImage=\"square.and.pencil\" id=\"qjO-sW-sCl\"/>\n                    <connections>\n                        <outlet property=\"inputTextView\" destination=\"CU6-Hv-afs\" id=\"udx-za-8ly\"/>\n                        <outlet property=\"languagePicker\" destination=\"13G-zM-sBK\" id=\"wwv-MD-KTk\"/>\n                        <outlet property=\"outputTextView\" destination=\"Dxc-dV-fix\" id=\"EQH-g2-ac0\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"GbO-IV-EL5\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"719.20000000000005\" y=\"1.3493253373313345\"/>\n        </scene>\n        <!--Tab Bar Controller-->\n        <scene sceneID=\"jin-q2-PEG\">\n            <objects>\n                <tabBarController id=\"OvN-fm-fpv\" sceneMemberID=\"viewController\">\n                    <tabBar key=\"tabBar\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"dX2-Ey-zCU\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"414\" height=\"49\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                    </tabBar>\n                    <connections>\n                        <segue destination=\"mOJ-Ji-nr9\" kind=\"relationship\" relationship=\"viewControllers\" id=\"b3k-T4-066\"/>\n                        <segue destination=\"lti-iO-OpS\" kind=\"relationship\" relationship=\"viewControllers\" id=\"fTk-5h-vXh\"/>\n                    </connections>\n                </tabBarController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"wHU-As-h9G\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-1601\" y=\"2\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"square.and.arrow.down.on.square\" catalog=\"system\" width=\"122\" height=\"128\"/>\n        <image name=\"square.and.pencil\" catalog=\"system\" width=\"128\" height=\"115\"/>\n        <systemColor name=\"groupTableViewBackgroundColor\">\n            <color red=\"0.94901960784313721\" green=\"0.94901960784313721\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </systemColor>\n        <systemColor name=\"labelColor\">\n            <color white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExample/EntityExtractionModelIdentifierExtensions.swift",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\nimport MLKitEntityExtraction\n\nextension EntityExtractionModelIdentifier {\n  static func allModelIdentifiersSorted() -> [EntityExtractionModelIdentifier] {\n    let locale = Locale.current\n    return EntityExtractionModelIdentifier.allModelIdentifiers().sorted {\n      return locale.localizedString(forLanguageCode: $0.toLanguageTag())! < locale.localizedString(\n        forLanguageCode: $1.toLanguageTag())!\n    }\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExample/EntityViewController.swift",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\nimport MLKitEntityExtraction\n\n@objc(EntityViewController)\nclass EntityViewController: UIViewController, UITextViewDelegate, UIPickerViewDataSource,\n  UIPickerViewDelegate\n{\n  @IBOutlet var inputTextView: UITextView!\n  @IBOutlet var outputTextView: UITextView!\n  @IBOutlet var languagePicker: UIPickerView!\n  @IBOutlet var localePicker: UIPickerView!\n\n  var modelForExtractor = EntityExtractionModelIdentifier.english\n  var entityExtractor = EntityExtractor.entityExtractor(\n    options: EntityExtractorOptions(modelIdentifier: EntityExtractionModelIdentifier.english))\n  let colorPalette: [UIColor]! = EntityViewController.simplePalette()\n  let languages = EntityExtractionModelIdentifier.allModelIdentifiersSorted()\n  var outputTextAttributes: [NSAttributedString.Key: Any] {\n    if #available(iOS 13.0, *) {\n      // Support Dark Mode\n      return [\n        NSAttributedString.Key.font: self.outputTextView.font as Any,\n        NSAttributedString.Key.foregroundColor: UIColor.label,\n      ]\n    } else {\n      return [NSAttributedString.Key.font: self.outputTextView.font as Any]\n    }\n  }\n\n  class func simplePalette() -> [UIColor]! {\n    return [\n      UIColor.blue.withAlphaComponent(0.25),\n      UIColor.red.withAlphaComponent(0.25),\n      UIColor.green.withAlphaComponent(0.25),\n      UIColor.cyan.withAlphaComponent(0.25),\n      UIColor.magenta.withAlphaComponent(0.25),\n      UIColor.yellow.withAlphaComponent(0.25),\n    ]\n  }\n\n  override func viewDidLoad() {\n    inputTextView.delegate = self\n    inputTextView.returnKeyType = .done\n    inputTextView.accessibilityIdentifier = \"Input Box\"\n    outputTextView.accessibilityIdentifier = \"Result View\"\n    languagePicker.delegate = self\n    languagePicker.dataSource = self\n    languagePicker.accessibilityIdentifier = \"Language Picker\"\n\n    let languageRow = languages.firstIndex(of: EntityExtractionModelIdentifier.english)!\n    languagePicker.selectRow(languageRow, inComponent: 0, animated: false)\n    downloadModelAndAnnotate()\n  }\n\n  func downloadModelAndAnnotate() {\n    let model = languages[languagePicker.selectedRow(inComponent: 0)]\n    let locale = Locale.current  // Use system locale or a locale of your choice.\n    if model != modelForExtractor {\n      modelForExtractor = model\n      let options = EntityExtractorOptions(modelIdentifier: model)\n      entityExtractor = EntityExtractor.entityExtractor(options: options)\n    }\n    let extractor = entityExtractor\n    let text = inputTextView.attributedText!\n    extractor.downloadModelIfNeeded(completion: {\n      [weak self]\n      error in\n      guard let self = self else { return }\n      guard error == nil else {\n        self.outputTextView.text = \"Failed to download model with error \\(error!)\"\n        return\n      }\n      self.annotateText(text: text, extractor: extractor, locale: locale)\n    })\n  }\n\n  func textView(\n    _ textView: UITextView, shouldChangeTextIn range: NSRange,\n    replacementText text: String\n  ) -> Bool {\n    // Hide the keyboard when \"Done\" is pressed.\n    // See: https://stackoverflow.com/questions/26600359/dismiss-keyboard-with-a-uitextview\n    if text == \"\\n\" {\n      textView.resignFirstResponder()\n      return false\n    }\n    return true\n  }\n\n  // Make all text selected when the text view is activated for editing, so that the newly\n  // input context will override the existing content.\n  func textViewDidBeginEditing(_ textView: UITextView) {\n    textView.selectedTextRange = textView.textRange(\n      from: textView.beginningOfDocument, to: textView.endOfDocument)\n  }\n\n  func textViewDidChange(_ textView: UITextView) {\n    self.downloadModelAndAnnotate()\n  }\n\n  class func stringFromPaymentCardNetwork(_ network: PaymentCardNetwork) -> String {\n    switch network {\n    case PaymentCardNetwork.unknown:\n      return \"unknown\"\n    case PaymentCardNetwork.amex:\n      return \"Amex\"\n    case PaymentCardNetwork.dinersClub:\n      return \"DinersClub\"\n    case PaymentCardNetwork.discover:\n      return \"Discover\"\n    case PaymentCardNetwork.interPayment:\n      return \"InterPayment\"\n    case PaymentCardNetwork.JCB:\n      return \"JCB\"\n    case PaymentCardNetwork.maestro:\n      return \"Maestro\"\n    case PaymentCardNetwork.mastercard:\n      return \"Mastercard\"\n    case PaymentCardNetwork.mir:\n      return \"Mir\"\n    case PaymentCardNetwork.troy:\n      return \"Troy\"\n    case PaymentCardNetwork.unionpay:\n      return \"Unionpay\"\n    case PaymentCardNetwork.visa:\n      return \"Visa\"\n    }\n  }\n\n  class func stringFromGranularity(_ granularity: DateTimeGranularity) -> String {\n    switch granularity {\n    case DateTimeGranularity.year:\n      return \"year\"\n    case DateTimeGranularity.month:\n      return \"month\"\n    case DateTimeGranularity.week:\n      return \"week\"\n    case DateTimeGranularity.day:\n      return \"day\"\n    case DateTimeGranularity.hour:\n      return \"hour\"\n    case DateTimeGranularity.minute:\n      return \"minute\"\n    case DateTimeGranularity.second:\n      return \"second\"\n    case DateTimeGranularity.unknown:\n      return \"unknown\"\n    }\n  }\n\n  class func stringFromCarrier(_ carrier: ParcelTrackingCarrier) -> String {\n    switch carrier {\n    case ParcelTrackingCarrier.unknown:\n      return \"unknown\"\n    case ParcelTrackingCarrier.fedEx:\n      return \"FedEx\"\n    case ParcelTrackingCarrier.UPS:\n      return \"UPS\"\n    case ParcelTrackingCarrier.DHL:\n      return \"DHL\"\n    case ParcelTrackingCarrier.USPS:\n      return \"USPS\"\n    case ParcelTrackingCarrier.ontrac:\n      return \"Ontrac\"\n    case ParcelTrackingCarrier.lasership:\n      return \"Lasership\"\n    case ParcelTrackingCarrier.israelPost:\n      return \"IsraelPost\"\n    case ParcelTrackingCarrier.swissPost:\n      return \"SwissPost\"\n    case ParcelTrackingCarrier.MSC:\n      return \"MSC\"\n    case ParcelTrackingCarrier.amazon:\n      return \"Amazon\"\n    case ParcelTrackingCarrier.iParcel:\n      return \"IParcel\"\n    }\n  }\n\n  class func stringFromAnnotation(annotation: EntityAnnotation) -> String {\n    var outputs: [String] = []\n    for entity in annotation.entities {\n      var output = \"\"\n      if entity.entityType == EntityType.address {\n        // Identifies a physical address.\n        // No structured data available.\n        output = \"address\"\n      } else if entity.entityType == EntityType.dateTime {\n        // Identifies a date and time reference that may include a specific time. May be absolute\n        // such as \"01/01/2000 5:30pm\" or relative like \"tomorrow at 5:30pm\".\n        output = \"datetime: \"\n        let formatter = DateFormatter()\n        formatter.timeZone = TimeZone.current\n        formatter.dateFormat = \"yyyy-MM-dd HH:mm:ss\"\n        output.append(formatter.string(from: entity.dateTimeEntity!.dateTime))\n        output.append(\" (granularity \")\n        output.append(\n          EntityViewController.stringFromGranularity(entity.dateTimeEntity!.dateTimeGranularity))\n        output.append(\")\")\n      } else if entity.entityType == EntityType.email {\n        // Identifies an e-mail address.\n        // No structured data available.\n        output = \"email\"\n      } else if entity.entityType == EntityType.flightNumber {\n        // Identifies a flight number in IATA format.\n        output = \"flight: \"\n        output.append(entity.flightNumberEntity!.airlineCode)\n        output.append(\" \")\n        output.append(entity.flightNumberEntity!.flightNumber)\n      } else if entity.entityType == EntityType.IBAN {\n        // Identifies an International Bank Account Number (IBAN).\n        output = \"iban: \"\n        output.append(entity.ibanEntity!.countryCode)\n        output.append(\" \")\n        output.append(entity.ibanEntity!.iban)\n      } else if entity.entityType == EntityType.ISBN {\n        // Identifies an International Standard Book Number (ISBN).\n        output = \"isbn: \"\n        output.append(entity.isbnEntity!.isbn)\n      } else if entity.entityType == EntityType.paymentCard {\n        // Identifies a payment card.\n        output = \"Payment card: \"\n        output.append(\n          EntityViewController.stringFromPaymentCardNetwork(\n            entity.paymentCardEntity!.paymentCardNetwork))\n        output.append(\" \")\n        output.append(entity.paymentCardEntity!.paymentCardNumber)\n      } else if entity.entityType == EntityType.phone {\n        // Identifies a phone number.\n        // No structured data available.\n        output = \"phone\"\n      } else if entity.entityType == EntityType.trackingNumber {\n        // Identifies a shipment tracking number.\n        output = \"tracking_number: \"\n        output.append(\n          EntityViewController.stringFromCarrier(entity.trackingNumberEntity!.parcelCarrier))\n        output.append(\" \")\n        output.append(entity.trackingNumberEntity!.parcelTrackingNumber)\n      } else if entity.entityType == EntityType.URL {\n        // Identifies a URL.\n        // No structured data available.\n        output = \"url\"\n      } else if entity.entityType == EntityType.money {\n        // Identifies currencies.\n        output = \"money: \"\n        output.append(entity.moneyEntity!.description)\n      }\n      outputs.append(output)\n    }\n    return \"[\" + outputs.joined(separator: \", \") + \"]\\n\"\n  }\n\n  func annotateText(text: NSAttributedString!, extractor: EntityExtractor!, locale: Locale!) {\n    extractor.annotateText(\n      text.string,\n      completion: {\n        [weak self]\n        result, error in\n\n        guard let self = self else { return }\n        let outputAttributes = self.outputTextAttributes\n        let output = NSMutableAttributedString()\n        let input = text.mutableCopy() as! NSMutableAttributedString\n        input.removeAttribute(\n          NSAttributedString.Key.backgroundColor, range: NSMakeRange(0, input.string.count))\n        if error != nil {\n          output.append(\n            NSMutableAttributedString.init(\n              string: \"Entity Extractor failed with error \\(error!)\", attributes: outputAttributes))\n        }\n        guard let result = result else {\n          print(\"Result is nil.\")\n          return\n        }\n        if result.count == 0 {\n          output.append(\n            NSMutableAttributedString.init(\n              string: \"No results returned.\", attributes: outputAttributes))\n        } else {\n          var i = 0\n          for annotation in result {\n            let color = self.colorPalette[i % self.colorPalette.count]\n            i += 1\n            input.addAttributes(\n              [NSAttributedString.Key.backgroundColor: color], range: annotation.range)\n            let annotationString = EntityViewController.stringFromAnnotation(annotation: annotation)\n            let annotationAttributesString = NSMutableAttributedString.init(\n              string: annotationString, attributes: outputAttributes)\n            annotationAttributesString.addAttributes(\n              [NSAttributedString.Key.backgroundColor: color],\n              range: NSMakeRange(0, annotationString.count))\n            output.append(annotationAttributesString)\n          }\n        }\n        self.outputTextView.attributedText = output\n        self.inputTextView.attributedText = input\n      })\n  }\n\n  func numberOfComponents(in pickerView: UIPickerView) -> Int {\n    return 1\n  }\n\n  func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {\n    return languages.count\n  }\n\n  func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int)\n    -> String?\n  {\n    let code = languages[row].toLanguageTag()\n    return Locale.current.localizedString(forLanguageCode: code)\n  }\n\n  func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {\n    downloadModelAndAnnotate()\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExample/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>Entity Extraction Sample</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>0.0.1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExample/ModelManagementViewController.swift",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\nimport MLKitCommon\nimport MLKitEntityExtraction\n\n@objc(ModelManagementViewController)\nclass ModelManagementViewController: UITableViewController {\n  let languages = EntityExtractionModelIdentifier.allModelIdentifiersSorted()\n  let modelManager = ModelManager.modelManager()\n  var downloadedLanguages: Set<EntityExtractionModelIdentifier> = []\n\n  override func viewDidLoad() {\n    NotificationCenter.default.addObserver(\n      self, selector: #selector(receiveModelLoadingDidCompleteNotification(notification:)),\n      name: .mlkitModelDownloadDidSucceed, object: nil)\n    NotificationCenter.default.addObserver(\n      self, selector: #selector(receiveModelLoadingDidCompleteNotification(notification:)),\n      name: .mlkitModelDownloadDidFail, object: nil)\n    refresh()\n  }\n\n  func refresh() {\n    self.downloadedLanguages = Set(\n      modelManager.downloadedEntityExtractionModels.map { $0.modelIdentifier })\n    self.tableView.reloadData()\n  }\n\n  override func numberOfSections(in tableView: UITableView) -> Int {\n    return 1\n  }\n\n  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {\n    return languages.count\n  }\n\n  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)\n    -> UITableViewCell\n  {\n    let cellIdentifier = \"language\"\n    let cell =\n      tableView.dequeueReusableCell(withIdentifier: cellIdentifier)\n      ?? UITableViewCell.init(\n        style: UITableViewCell.CellStyle.default, reuseIdentifier: cellIdentifier)\n    let language = languages[indexPath.row]\n    let code = language.toLanguageTag()\n    cell.textLabel!.text = Locale.current.localizedString(forLanguageCode: code)\n    if downloadedLanguages.contains(language) {\n      cell.imageView!.image = UIImage.init(named: \"delete_24pt\")\n    } else {\n      cell.imageView!.image = UIImage.init(named: \"cloud_download_24pt\")\n    }\n    return cell\n  }\n\n  func showError(title: String, message: String) {\n    let alert = UIAlertController.init(\n      title: title, message: message,\n      preferredStyle: UIAlertController.Style.alert)\n    let action = UIAlertAction.init(\n      title: \"OK\", style: UIAlertAction.Style.default,\n      handler: {\n        action in\n      })\n    alert.addAction(action)\n    self.present(alert, animated: false, completion: nil)\n  }\n\n  override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {\n    let language = languages[indexPath.row]\n    let model = EntityExtractorRemoteModel.entityExtractorRemoteModel(identifier: language)\n    if downloadedLanguages.contains(language) {\n      weak var weakSelf = self\n      modelManager.deleteDownloadedModel(model) {\n        error in\n        guard let strongSelf = weakSelf else {\n          print(\"Self is nil!\")\n          return\n        }\n        if error != nil {\n          strongSelf.showError(title: \"Deleting model failed\", message: error!.localizedDescription)\n        }\n        strongSelf.refresh()\n      }\n    } else {\n      let conditions = ModelDownloadConditions(\n        allowsCellularAccess: true,\n        allowsBackgroundDownloading: true\n      )\n      modelManager.download(model, conditions: conditions)\n    }\n  }\n\n  @objc\n  func receiveModelLoadingDidCompleteNotification(notification: NSNotification!) {\n    weak var weakSelf = self\n    if notification.name == NSNotification.Name.mlkitModelDownloadDidFail {\n      let userInfo = notification.userInfo!\n      let error = userInfo[ModelDownloadUserInfoKey.error.rawValue] as! NSError\n      DispatchQueue.main.async {\n        weakSelf?.showError(title: \"Downloading model failed\", message: error.localizedDescription)\n      }\n    }\n    DispatchQueue.main.async { weakSelf?.refresh() }\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t108489A5224415A1004D37A8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 108489A4224415A1004D37A8 /* AppDelegate.m */; };\n\t\t108489A8224415A1004D37A8 /* EntityViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 108489A7224415A1004D37A8 /* EntityViewController.m */; };\n\t\t108489B3224415A4004D37A8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 108489B2224415A4004D37A8 /* main.m */; };\n\t\t108489F8224531B9004D37A8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDC822259E3400536A5C /* Main.storyboard */; };\n\t\t108489F9224531BF004D37A8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDCD22259E3500536A5C /* LaunchScreen.storyboard */; };\n\t\t408FD251248AB72A00CA5C9D /* EntityExtractionModelIdentifierExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 408FD250248AB72A00CA5C9D /* EntityExtractionModelIdentifierExtensions.swift */; };\n\t\t408FD254248AB84300CA5C9D /* MLKEntityExtractionModelIdentifier+Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 408FD253248AB84300CA5C9D /* MLKEntityExtractionModelIdentifier+Extensions.m */; };\n\t\t6191C8FE2471A84200E09CDE /* ModelManagementViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6191C8FC2471A84200E09CDE /* ModelManagementViewController.m */; };\n\t\t61B47298247FC34B00923C2C /* ModelManagementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61B47297247FC34A00923C2C /* ModelManagementViewController.swift */; };\n\t\tC18E1D3722410D0E00B5F51C /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C18E1D3622410D0E00B5F51C /* libc++.tbd */; };\n\t\tC1E8DDC522259E3400536A5C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E8DDC422259E3400536A5C /* AppDelegate.swift */; };\n\t\tC1E8DDC722259E3400536A5C /* EntityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E8DDC622259E3400536A5C /* EntityViewController.swift */; };\n\t\tC1E8DDCA22259E3400536A5C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDC822259E3400536A5C /* Main.storyboard */; };\n\t\tC1E8DDCF22259E3500536A5C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDCD22259E3500536A5C /* LaunchScreen.storyboard */; };\n\t\tEC1278572748201D00863E4A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC1278562748201D00863E4A /* Assets.xcassets */; };\n\t\tEC1278582748201D00863E4A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC1278562748201D00863E4A /* Assets.xcassets */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t108489A1224415A1004D37A8 /* EntityExtractionExampleObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EntityExtractionExampleObjC.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t108489A3224415A1004D37A8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t108489A4224415A1004D37A8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t108489A6224415A1004D37A8 /* EntityViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EntityViewController.h; sourceTree = \"<group>\"; };\n\t\t108489A7224415A1004D37A8 /* EntityViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EntityViewController.m; sourceTree = \"<group>\"; };\n\t\t108489B2224415A4004D37A8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t408FD250248AB72A00CA5C9D /* EntityExtractionModelIdentifierExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityExtractionModelIdentifierExtensions.swift; sourceTree = \"<group>\"; };\n\t\t408FD252248AB84300CA5C9D /* MLKEntityExtractionModelIdentifier+Extensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"MLKEntityExtractionModelIdentifier+Extensions.h\"; sourceTree = \"<group>\"; };\n\t\t408FD253248AB84300CA5C9D /* MLKEntityExtractionModelIdentifier+Extensions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = \"MLKEntityExtractionModelIdentifier+Extensions.m\"; sourceTree = \"<group>\"; };\n\t\t6191C8FC2471A84200E09CDE /* ModelManagementViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModelManagementViewController.m; sourceTree = \"<group>\"; };\n\t\t6191C8FD2471A84200E09CDE /* ModelManagementViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModelManagementViewController.h; sourceTree = \"<group>\"; };\n\t\t61B47297247FC34A00923C2C /* ModelManagementViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModelManagementViewController.swift; sourceTree = \"<group>\"; };\n\t\tC18E1D3622410D0E00B5F51C /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = \"libc++.tbd\"; path = \"usr/lib/libc++.tbd\"; sourceTree = SDKROOT; };\n\t\tC1E8DDC122259E3400536A5C /* EntityExtractionExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EntityExtractionExample.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC1E8DDC422259E3400536A5C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tC1E8DDC622259E3400536A5C /* EntityViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityViewController.swift; sourceTree = \"<group>\"; };\n\t\tC1E8DDC922259E3400536A5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tC1E8DDCE22259E3500536A5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tC1E8DDD022259E3500536A5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tEC1278562748201D00863E4A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t1084899E224415A1004D37A8 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1E8DDBE22259E3400536A5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC18E1D3722410D0E00B5F51C /* libc++.tbd in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t108489A2224415A1004D37A8 /* EntityExtractionExampleObjC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6191C8FD2471A84200E09CDE /* ModelManagementViewController.h */,\n\t\t\t\t6191C8FC2471A84200E09CDE /* ModelManagementViewController.m */,\n\t\t\t\t108489A3224415A1004D37A8 /* AppDelegate.h */,\n\t\t\t\t108489A4224415A1004D37A8 /* AppDelegate.m */,\n\t\t\t\t108489A6224415A1004D37A8 /* EntityViewController.h */,\n\t\t\t\t108489A7224415A1004D37A8 /* EntityViewController.m */,\n\t\t\t\t108489B2224415A4004D37A8 /* main.m */,\n\t\t\t\t408FD252248AB84300CA5C9D /* MLKEntityExtractionModelIdentifier+Extensions.h */,\n\t\t\t\t408FD253248AB84300CA5C9D /* MLKEntityExtractionModelIdentifier+Extensions.m */,\n\t\t\t);\n\t\t\tpath = EntityExtractionExampleObjC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65AC6D81F1B268042A1E4A79 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC18E1D3622410D0E00B5F51C /* libc++.tbd */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1E8DDB822259E3400536A5C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tEC1278562748201D00863E4A /* Assets.xcassets */,\n\t\t\t\tC1E8DDC322259E3400536A5C /* EntityExtractionExample */,\n\t\t\t\t108489A2224415A1004D37A8 /* EntityExtractionExampleObjC */,\n\t\t\t\tC1E8DDC222259E3400536A5C /* Products */,\n\t\t\t\t65AC6D81F1B268042A1E4A79 /* Frameworks */,\n\t\t\t\tE7C45F3A2FC5CB6A04E2E3FF /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1E8DDC222259E3400536A5C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC1E8DDC122259E3400536A5C /* EntityExtractionExample.app */,\n\t\t\t\t108489A1224415A1004D37A8 /* EntityExtractionExampleObjC.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1E8DDC322259E3400536A5C /* EntityExtractionExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t61B47297247FC34A00923C2C /* ModelManagementViewController.swift */,\n\t\t\t\tC1E8DDC422259E3400536A5C /* AppDelegate.swift */,\n\t\t\t\tC1E8DDC622259E3400536A5C /* EntityViewController.swift */,\n\t\t\t\tC1E8DDC822259E3400536A5C /* Main.storyboard */,\n\t\t\t\tC1E8DDCD22259E3500536A5C /* LaunchScreen.storyboard */,\n\t\t\t\tC1E8DDD022259E3500536A5C /* Info.plist */,\n\t\t\t\t408FD250248AB72A00CA5C9D /* EntityExtractionModelIdentifierExtensions.swift */,\n\t\t\t);\n\t\t\tpath = EntityExtractionExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE7C45F3A2FC5CB6A04E2E3FF /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t108489A0224415A1004D37A8 /* EntityExtractionExampleObjC */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 108489D0224415A5004D37A8 /* Build configuration list for PBXNativeTarget \"EntityExtractionExampleObjC\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t1084899D224415A1004D37A8 /* Sources */,\n\t\t\t\t1084899E224415A1004D37A8 /* Frameworks */,\n\t\t\t\t1084899F224415A1004D37A8 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = EntityExtractionExampleObjC;\n\t\t\tproductName = EntityExtractionExampleObjC;\n\t\t\tproductReference = 108489A1224415A1004D37A8 /* EntityExtractionExampleObjC.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tC1E8DDC022259E3400536A5C /* EntityExtractionExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C1E8DDD322259E3500536A5C /* Build configuration list for PBXNativeTarget \"EntityExtractionExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tC1E8DDBD22259E3400536A5C /* Sources */,\n\t\t\t\tC1E8DDBE22259E3400536A5C /* Frameworks */,\n\t\t\t\tC1E8DDBF22259E3400536A5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = EntityExtractionExample;\n\t\t\tproductName = EntityExtractionApp;\n\t\t\tproductReference = C1E8DDC122259E3400536A5C /* EntityExtractionExample.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tC1E8DDB922259E3400536A5C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1340;\n\t\t\t\tLastUpgradeCheck = 1010;\n\t\t\t\tORGANIZATIONNAME = \"Google LLC\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t108489A0224415A1004D37A8 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t};\n\t\t\t\t\tC1E8DDC022259E3400536A5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = C1E8DDBC22259E3400536A5C /* Build configuration list for PBXProject \"EntityExtractionExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = C1E8DDB822259E3400536A5C;\n\t\t\tproductRefGroup = C1E8DDC222259E3400536A5C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tC1E8DDC022259E3400536A5C /* EntityExtractionExample */,\n\t\t\t\t108489A0224415A1004D37A8 /* EntityExtractionExampleObjC */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t1084899F224415A1004D37A8 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t108489F8224531B9004D37A8 /* Main.storyboard in Resources */,\n\t\t\t\tEC1278582748201D00863E4A /* Assets.xcassets in Resources */,\n\t\t\t\t108489F9224531BF004D37A8 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1E8DDBF22259E3400536A5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC1E8DDCF22259E3500536A5C /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tEC1278572748201D00863E4A /* Assets.xcassets in Resources */,\n\t\t\t\tC1E8DDCA22259E3400536A5C /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t1084899D224415A1004D37A8 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t108489A8224415A1004D37A8 /* EntityViewController.m in Sources */,\n\t\t\t\t108489B3224415A4004D37A8 /* main.m in Sources */,\n\t\t\t\t408FD254248AB84300CA5C9D /* MLKEntityExtractionModelIdentifier+Extensions.m in Sources */,\n\t\t\t\t6191C8FE2471A84200E09CDE /* ModelManagementViewController.m in Sources */,\n\t\t\t\t108489A5224415A1004D37A8 /* AppDelegate.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1E8DDBD22259E3400536A5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t408FD251248AB72A00CA5C9D /* EntityExtractionModelIdentifierExtensions.swift in Sources */,\n\t\t\t\tC1E8DDC722259E3400536A5C /* EntityViewController.swift in Sources */,\n\t\t\t\tC1E8DDC522259E3400536A5C /* AppDelegate.swift in Sources */,\n\t\t\t\t61B47298247FC34B00923C2C /* ModelManagementViewController.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tC1E8DDC822259E3400536A5C /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tC1E8DDC922259E3400536A5C /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1E8DDCD22259E3500536A5C /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tC1E8DDCE22259E3500536A5C /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t108489CA224415A5004D37A8 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/EntityExtractionExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkitml.sampleapp.entityextraction;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t108489CB224415A5004D37A8 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/EntityExtractionExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkitml.sampleapp.entityextraction;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC1E8DDD122259E3500536A5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC1E8DDD222259E3500536A5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC1E8DDD422259E3500536A5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/EntityExtractionExample/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\t\"OTHER_SWIFT_FLAGS[arch=*]\" = \"-D COCOAPODS\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.sampleapp.entityextraction;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC1E8DDD522259E3500536A5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/EntityExtractionExample/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\t\"OTHER_SWIFT_FLAGS[arch=*]\" = \"-D COCOAPODS\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.sampleapp.entityextraction;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t108489D0224415A5004D37A8 /* Build configuration list for PBXNativeTarget \"EntityExtractionExampleObjC\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t108489CA224415A5004D37A8 /* Debug */,\n\t\t\t\t108489CB224415A5004D37A8 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC1E8DDBC22259E3400536A5C /* Build configuration list for PBXProject \"EntityExtractionExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC1E8DDD122259E3500536A5C /* Debug */,\n\t\t\t\tC1E8DDD222259E3500536A5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC1E8DDD322259E3500536A5C /* Build configuration list for PBXNativeTarget \"EntityExtractionExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC1E8DDD422259E3500536A5C /* Debug */,\n\t\t\t\tC1E8DDD522259E3500536A5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = C1E8DDB922259E3400536A5C /* Project object */;\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/AppDelegate.h",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property(strong, nonatomic) UIWindow *window;\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/AppDelegate.m",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"AppDelegate.h\"\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application\n    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n  return YES;\n}\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/EntityViewController.h",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface EntityViewController\n    : UIViewController <UITextViewDelegate, UIPickerViewDataSource, UIPickerViewDelegate>\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/EntityViewController.m",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"EntityViewController.h\"\n#import \"MLKEntityExtractionModelIdentifier+Extensions.h\"\n\n@import MLKitCommon;\n@import MLKitEntityExtraction;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface EntityViewController ()\n\n@property(weak, nonatomic) IBOutlet UITextView *inputTextView;\n@property(weak, nonatomic) IBOutlet UITextView *outputTextView;\n@property(weak, nonatomic) IBOutlet UIPickerView *languagePicker;\n\n@property(nonatomic, strong) MLKEntityExtractor *entityExtractor;\n@property(nonatomic, strong) MLKEntityExtractionModelIdentifier modelForExtractor;\n@property(nonatomic, strong) NSArray<UIColor *> *colorPalette;\n@property(nonatomic, strong) NSArray<MLKEntityExtractionModelIdentifier> *languages;\n\n@end\n\n@implementation EntityViewController\n\n+ (NSArray<UIColor *> *)simplePalette {\n  NSMutableArray<UIColor *> *palette = [NSMutableArray array];\n  [palette addObject:[[UIColor cyanColor] colorWithAlphaComponent:0.25]];\n  [palette addObject:[[UIColor orangeColor] colorWithAlphaComponent:0.25]];\n  [palette addObject:[[UIColor greenColor] colorWithAlphaComponent:0.25]];\n  [palette addObject:[[UIColor cyanColor] colorWithAlphaComponent:0.25]];\n  [palette addObject:[[UIColor magentaColor] colorWithAlphaComponent:0.25]];\n  [palette addObject:[[UIColor yellowColor] colorWithAlphaComponent:0.25]];\n  return palette;\n}\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  self.languages = MLKEntityExtractionAllModelIdentifiersSorted();\n  self.colorPalette = [self.class simplePalette];\n  self.modelForExtractor = @\"\";\n\n  self.inputTextView.delegate = self;\n  self.inputTextView.returnKeyType = UIReturnKeyDone;\n  self.inputTextView.accessibilityIdentifier = @\"Input Box\";\n  self.inputTextView.delegate = self;\n  self.outputTextView.accessibilityIdentifier = @\"Result View\";\n  self.languagePicker.delegate = self;\n  self.languagePicker.dataSource = self;\n  self.languagePicker.accessibilityIdentifier = @\"Language Picker\";\n\n  NSUInteger languageRow = [self.languages indexOfObject:MLKEntityExtractionModelIdentifierEnglish];\n  [self.languagePicker selectRow:languageRow inComponent:0 animated:NO];\n\n  [self downloadModelAndAnnotate];\n}\n\n- (void)downloadModelAndAnnotate {\n  MLKEntityExtractionModelIdentifier model =\n      self.languages[[self.languagePicker selectedRowInComponent:0]];\n\n  NSLocale *locale = [NSLocale currentLocale];  // Use system locale or use a locale of your choice.\n  if (![model isEqualToString:self.modelForExtractor]) {\n    self.modelForExtractor = model;\n    self.entityExtractor =\n        [MLKEntityExtractor entityExtractorWithOptions:[[MLKEntityExtractorOptions alloc]\n                                                           initWithModelIdentifier:model]];\n  }\n  MLKEntityExtractor *extractor = self.entityExtractor;\n  NSAttributedString *text = [self.inputTextView.attributedText copy];\n  __weak typeof(self) weakSelf = self;\n  [extractor downloadModelIfNeededWithCompletion:^(NSError *_Nullable error) {\n    typeof(self) strongSelf = weakSelf;\n    if (strongSelf == nil) return;\n    if (error != nil) {\n      strongSelf.outputTextView.text = [NSString\n          stringWithFormat:@\"Model downloading failed with error: %@\", error.localizedDescription];\n    } else {\n      [strongSelf annotateText:text withExtractor:extractor locale:locale];\n    }\n  }];\n}\n\n+ (NSString *)stringFromPaymentCardNetwork:(MLKPaymentCardNetwork)network {\n  switch (network) {\n    case MLKPaymentCardNetworkUnknown:\n      return @\"unknown\";\n    case MLKPaymentCardNetworkAmex:\n      return @\"Amex\";\n    case MLKPaymentCardNetworkDinersClub:\n      return @\"DinersClub\";\n    case MLKPaymentCardNetworkDiscover:\n      return @\"Discover\";\n    case MLKPaymentCardNetworkInterPayment:\n      return @\"InterPayment\";\n    case MLKPaymentCardNetworkJCB:\n      return @\"JCB\";\n    case MLKPaymentCardNetworkMaestro:\n      return @\"Maestro\";\n    case MLKPaymentCardNetworkMastercard:\n      return @\"Mastercard\";\n    case MLKPaymentCardNetworkMir:\n      return @\"Mir\";\n    case MLKPaymentCardNetworkTroy:\n      return @\"Troy\";\n    case MLKPaymentCardNetworkUnionpay:\n      return @\"Unionpay\";\n    case MLKPaymentCardNetworkVisa:\n      return @\"Visa\";\n  }\n  return @\"unknown\";\n}\n\n+ (NSString *)stringFromGranularity:(MLKDateTimeGranularity)granularity {\n  switch (granularity) {\n    case MLKDateTimeGranularityUnknown:\n      return @\"unknown\";\n    case MLKDateTimeGranularityYear:\n      return @\"year\";\n    case MLKDateTimeGranularityMonth:\n      return @\"month\";\n    case MLKDateTimeGranularityWeek:\n      return @\"week\";\n    case MLKDateTimeGranularityDay:\n      return @\"day\";\n    case MLKDateTimeGranularityHour:\n      return @\"hour\";\n    case MLKDateTimeGranularityMinute:\n      return @\"minute\";\n    case MLKDateTimeGranularitySecond:\n      return @\"second\";\n  }\n}\n\n+ (NSString *)stringFromCarrier:(MLKParcelTrackingCarrier)carrier {\n  switch (carrier) {\n    case MLKParcelTrackingCarrierUnknown:\n      return @\"unknown\";\n    case MLKParcelTrackingCarrierFedEx:\n      return @\"FedEx\";\n    case MLKParcelTrackingCarrierUPS:\n      return @\"UPS\";\n    case MLKParcelTrackingCarrierDHL:\n      return @\"DHL\";\n    case MLKParcelTrackingCarrierUSPS:\n      return @\"USPS\";\n    case MLKParcelTrackingCarrierOntrac:\n      return @\"Ontrac\";\n    case MLKParcelTrackingCarrierLasership:\n      return @\"Lasership\";\n    case MLKParcelTrackingCarrierIsraelPost:\n      return @\"IsraelPost\";\n    case MLKParcelTrackingCarrierSwissPost:\n      return @\"SwissPost\";\n    case MLKParcelTrackingCarrierMSC:\n      return @\"MSC\";\n    case MLKParcelTrackingCarrierAmazon:\n      return @\"Amazon\";\n    case MLKParcelTrackingCarrierIParcel:\n      return @\"IParcel\";\n  }\n  return @\"unknown\";\n}\n\n+ (NSString *)stringFromAnnotation:(MLKEntityAnnotation *)annotation {\n  NSMutableArray *outputs = [NSMutableArray array];\n  for (MLKEntity *entity in annotation.entities) {\n    NSMutableString *output = [entity.entityType mutableCopy];\n    if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeAddress]) {\n      // Identifies a physical address.\n      // No structured data available.\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeDateTime]) {\n      // Identifies a date and time reference that may include a specific time. May be absolute such\n      // as \"01/01/2000 5:30pm\" or relative like \"tomorrow at 5:30pm\".\n      NSDateFormatter *formatter = [[NSDateFormatter alloc] init];\n      NSTimeZone *timeZone = [NSTimeZone localTimeZone];\n      [formatter setTimeZone:timeZone];\n      [formatter setDateFormat:@\"yyyy-MM-dd HH:mm:ss\"];\n      [output appendFormat:@\": %@ (granularity %@)\",\n                           [formatter stringFromDate:entity.dateTimeEntity.dateTime],\n                           [self stringFromGranularity:entity.dateTimeEntity.dateTimeGranularity]];\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeEmail]) {\n      // Identifies an e-mail address.\n      // No structured data available.\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeFlightNumber]) {\n      // Identifies a flight number in IATA format.\n      [output appendFormat:@\": %@ %@\", entity.flightNumberEntity.airlineCode,\n                           entity.flightNumberEntity.flightNumber];\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeIBAN]) {\n      // Identifies an International Bank Account Number (IBAN).\n      [output appendFormat:@\": %@ %@\", entity.IBANEntity.countryCode, entity.IBANEntity.IBAN];\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeISBN]) {\n      // Identifies an International Standard Book Number (ISBN).\n      [output appendFormat:@\": %@\", entity.ISBNEntity.ISBN];\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypePaymentCard]) {\n      // Identifies a payment card.\n      [output appendFormat:@\": %@ %@\",\n                           [self stringFromPaymentCardNetwork:entity.paymentCardEntity\n                                                                  .paymentCardNetwork],\n                           entity.paymentCardEntity.paymentCardNumber];\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypePhone]) {\n      // Identifies a phone number.\n      // No structured data available.\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeTrackingNumber]) {\n      // Identifies a shipment tracking number.\n      [output appendFormat:@\": %@ %@\",\n                           [self stringFromCarrier:entity.trackingNumberEntity.parcelCarrier],\n                           entity.trackingNumberEntity.parcelTrackingNumber];\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeURL]) {\n      // Identifies a URL.\n      // No structured data available.\n    } else if ([entity.entityType isEqualToString:MLKEntityExtractionEntityTypeMoney]) {\n      // Identifies currency.\n      [output appendFormat:@\": %@\", entity.moneyEntity];\n    }\n    [outputs addObject:output];\n  }\n\n  return [NSString stringWithFormat:@\"[%@]\\n\", [outputs componentsJoinedByString:@\", \"]];\n}\n\n- (NSDictionary *)outputTextAttributes {\n  if (@available(iOS 13.0, *)) {\n    // Support Dark Mode\n    return @{\n      NSFontAttributeName : self.outputTextView.font,\n      NSForegroundColorAttributeName : UIColor.labelColor\n    };\n  } else {\n    return @{NSFontAttributeName : self.outputTextView.font};\n  }\n}\n\n- (void)annotateText:(NSAttributedString *)text\n       withExtractor:(MLKEntityExtractor *)extractor\n              locale:(NSLocale *)locale {\n  __weak typeof(self) weakSelf = self;\n  MLKEntityExtractionParams *params = [[MLKEntityExtractionParams alloc] init];\n  params.preferredLocale = locale;\n  [extractor\n      annotateText:text.string\n        withParams:params\n        completion:^(NSArray<MLKEntityAnnotation *> *_Nullable result, NSError *_Nullable error) {\n          typeof(self) strongSelf = weakSelf;\n          if (strongSelf == nil) return;\n          NSDictionary *outputAttributes = [self outputTextAttributes];\n          NSMutableAttributedString *output = [[NSMutableAttributedString alloc] init];\n          NSMutableAttributedString *input = [text mutableCopy];\n          [input removeAttribute:NSBackgroundColorAttributeName\n                           range:NSMakeRange(0, input.string.length)];\n          NSUInteger i = 0;\n          if (error != nil) {\n            NSString *message =\n                [NSString stringWithFormat:@\"Entity Extractor failed with error: %@\",\n                                           error.localizedDescription];\n            strongSelf.outputTextView.attributedText =\n                [[NSAttributedString alloc] initWithString:message attributes:outputAttributes];\n          }\n          if (result.count == 0) {\n            [output appendAttributedString:[[NSAttributedString alloc]\n                                               initWithString:@\"No results returned.\"\n                                                   attributes:outputAttributes]];\n          } else {\n            for (MLKEntityAnnotation *annotation in result) {\n              UIColor *color =\n                  [strongSelf.colorPalette objectAtIndex:(i++ % strongSelf.colorPalette.count)];\n              [input addAttributes:@{NSBackgroundColorAttributeName : color}\n                             range:annotation.range];\n              NSString *annotationString = [strongSelf.class stringFromAnnotation:annotation];\n              NSMutableAttributedString *annotationAttributedString =\n                  [[NSMutableAttributedString alloc] initWithString:annotationString\n                                                         attributes:outputAttributes];\n              [annotationAttributedString addAttributes:@{NSBackgroundColorAttributeName : color}\n                                                  range:NSMakeRange(0, annotationString.length)];\n              [output appendAttributedString:annotationAttributedString];\n            }\n          }\n          strongSelf.outputTextView.attributedText = output;\n          strongSelf.inputTextView.attributedText = input;\n        }];\n}\n\n- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {\n  return 1;\n}\n\n- (nullable NSString *)pickerView:(UIPickerView *)pickerView\n                      titleForRow:(NSInteger)row\n                     forComponent:(NSInteger)component {\n  if (pickerView == self.languagePicker) {\n    NSString *code = MLKEntityExtractionLanguageTagForModelIdentifier(self.languages[row]);\n    return [NSLocale.currentLocale localizedStringForLanguageCode:code];\n  }\n  return @\"\";\n}\n\n- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {\n  if (pickerView == self.languagePicker) {\n    return self.languages.count;\n  }\n  return 0;\n}\n\n- (void)pickerView:(UIPickerView *)pickerView\n      didSelectRow:(NSInteger)row\n       inComponent:(NSInteger)component {\n  [self downloadModelAndAnnotate];\n}\n\n#pragma mark - UITextViewDelegate\n\n- (BOOL)textView:(UITextView *)textView\n    shouldChangeTextInRange:(NSRange)range\n            replacementText:(NSString *)text {\n  if ([text isEqualToString:@\"\\n\"]) {\n    [textView resignFirstResponder];\n    return NO;\n  }\n  return YES;\n}\n\n/**\n * Make all text selected when the text view is activated for editing, so that the newly input\n * context will override the existing content.\n */\n- (void)textViewDidBeginEditing:(UITextView *)textView {\n  textView.selectedTextRange = [textView textRangeFromPosition:textView.beginningOfDocument\n                                                    toPosition:textView.endOfDocument];\n}\n\n- (void)textViewDidChange:(UITextView *)textView {\n  [self downloadModelAndAnnotate];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/MLKEntityExtractionModelIdentifier+Extensions.h",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <Foundation/Foundation.h>\n\n@import MLKitEntityExtraction;\n\nNSArray<MLKEntityExtractionModelIdentifier> *MLKEntityExtractionAllModelIdentifiersSorted(void);\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/MLKEntityExtractionModelIdentifier+Extensions.m",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"MLKEntityExtractionModelIdentifier+Extensions.h\"\n\nNSArray<MLKEntityExtractionModelIdentifier> *MLKEntityExtractionAllModelIdentifiersSorted(void) {\n  NSLocale *currentLocale = NSLocale.currentLocale;\n  return [MLKEntityExtractionAllModelIdentifiers()\n                        .allObjects sortedArrayUsingComparator:^NSComparisonResult(\n                                        NSString *_Nonnull model1, NSString *_Nonnull model2) {\n    return [[currentLocale\n        localizedStringForLanguageCode:MLKEntityExtractionLanguageTagForModelIdentifier(model1)]\n        compare:[currentLocale\n                    localizedStringForLanguageCode:MLKEntityExtractionLanguageTagForModelIdentifier(\n                                                       model2)]];\n  }];\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/ModelManagementViewController.h",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ModelManagementViewController : UITableViewController <UITableViewDataSource>\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/ModelManagementViewController.m",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"ModelManagementViewController.h\"\n#import \"MLKEntityExtractionModelIdentifier+Extensions.h\"\n\n@import MLKitCommon;\n@import MLKitEntityExtraction;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ModelManagementViewController ()\n\n@property(nonatomic, strong) NSArray<MLKEntityExtractionModelIdentifier> *languages;\n@property(nonatomic, strong) MLKModelManager *modelManager;\n@property(nonatomic, strong) NSSet<MLKEntityExtractionModelIdentifier> *downloadedLanguages;\n\n@end\n\n@implementation ModelManagementViewController\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  self.languages = MLKEntityExtractionAllModelIdentifiersSorted();\n  self.modelManager = [MLKModelManager modelManager];\n  [self refresh];\n\n  [NSNotificationCenter.defaultCenter\n      addObserver:self\n         selector:@selector(receiveModelLoadingDidCompleteNotification:)\n             name:MLKModelDownloadDidSucceedNotification\n           object:nil];\n  [NSNotificationCenter.defaultCenter\n      addObserver:self\n         selector:@selector(receiveModelLoadingDidCompleteNotification:)\n             name:MLKModelDownloadDidFailNotification\n           object:nil];\n}\n\n- (void)refresh {\n  NSSet<MLKEntityExtractionRemoteModel *> *downloadedModels =\n      [self.modelManager downloadedEntityExtractionModels];\n  NSMutableSet<MLKEntityExtractionModelIdentifier> *languages = [[NSMutableSet alloc] init];\n  for (MLKEntityExtractionRemoteModel *model in downloadedModels) {\n    [languages addObject:model.modelIdentifier];\n  }\n  self.downloadedLanguages = languages;\n  [self.tableView reloadData];\n}\n\n- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {\n  return 1;\n}\n\n- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {\n  return self.languages.count;\n}\n\n- (UITableViewCell *)tableView:(UITableView *)tableView\n         cellForRowAtIndexPath:(NSIndexPath *)indexPath {\n  static NSString *cellIdentifier = @\"language\";\n\n  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];\n  if (cell == nil) {\n    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault\n                                  reuseIdentifier:cellIdentifier];\n  }\n\n  MLKEntityExtractionModelIdentifier language = self.languages[indexPath.row];\n  NSString *code = MLKEntityExtractionLanguageTagForModelIdentifier(language);\n  cell.textLabel.text = [NSLocale.currentLocale localizedStringForLanguageCode:code];\n  if ([self.downloadedLanguages containsObject:language]) {\n    cell.imageView.image = [UIImage imageNamed:@\"delete_24pt\"];\n  } else {\n    cell.imageView.image = [UIImage imageNamed:@\"cloud_download_24pt\"];\n  }\n  return cell;\n}\n\n- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {\n  MLKEntityExtractionModelIdentifier language = self.languages[indexPath.row];\n  MLKEntityExtractionRemoteModel *model =\n      [MLKEntityExtractionRemoteModel entityExtractorRemoteModelWithIdentifier:language];\n  if ([self.downloadedLanguages containsObject:language]) {\n    [self.modelManager deleteDownloadedModel:model\n                                  completion:^(NSError *_Nullable error) {\n                                    [self refresh];\n                                  }];\n  } else {\n    MLKModelDownloadConditions *conditions =\n        [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES\n                                             allowsBackgroundDownloading:YES];\n    [self.modelManager downloadModel:model conditions:conditions];\n  }\n}\n\n- (void)receiveModelLoadingDidCompleteNotification:(NSNotification *)notification {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    [weakSelf refresh];\n  });\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/EntityExtractionExampleObjC/main.m",
    "content": "//\n// Copyright (c) 2020 Google LLC.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char* argv[]) {\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/entityextraction/Podfile",
    "content": "platform :ios, '15.5'\nuse_frameworks!\n\nproject 'EntityExtractionExample.xcodeproj'\n\npod 'GoogleMLKit/EntityExtraction', '9.0.0'\n\ntarget 'EntityExtractionExample' do\nend\n\ntarget 'EntityExtractionExampleObjC' do\nend\n\npost_install do |installer|\n  installer.aggregate_targets.each do |target|\n    target.xcconfigs.each do |variant, xcconfig|\n      xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)\n      IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n    end\n  end\n  installer.generated_projects.each do |project|\n    project.targets.each do |target|\n        target.build_configurations.each do |config|\n            config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'\n            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'\n         end\n    end\n  end\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference\n        xcconfig_path = config.base_configuration_reference.real_path\n        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n      end\n    end\n  end\nend"
  },
  {
    "path": "ios/quickstarts/entityextraction/README.md",
    "content": "# ML Kit Entity Extraction Quickstart\n\n* [Read more about ML Kit Entity Extraction API](https://developers.google.com/ml-kit/language/entity-extraction)\n\n## Introduction\n\nThe ML Kit Entity Extraction iOS Quickstart app demonstrates how to use the ML\nKit Entity Extraction feature to recognize structured data in text.\n\nThis app requires network connectivity in order to download the corresponding\nlanguage model.\n\n## Getting Started\n\n-   Run the sample on your iOS device or simulator.\n-   Type input text and change languages to see entity extraction in action.\n\n## How to use the app\n\n-   Enter text in the input box and hit \"done\" on your keyboard.\n-   If any entities are found in the text, they will show up on the bottom half\nof the screen.\n-   Click the \"Models\" button in the bottom right corner to ensure the correct\nlanguage model has been downloaded.\n\n### Examples\n\n<table>\n<tr><th>Input text</th><th>Detected entities</th></tr>\n\n<tr><td>You can contact the test team <b>tomorrow</b> at <b>info@google.com</b>\nto determine the best timeline.</td>\n<td>Entity 1 type: Date-Time<br>\nEntity 1 text: = \"2020-12-09 00:00:00\"<br><br>\n\nEntity 2 type: Email address<br>\nEntity 2 text: info@google.com</td></tr>\n\n<tr><td>Your order has shipped from Google. To follow the progress of your\ndelivery please use this tracking number: <b>9612804152073070474837</b></td>\n<td>Entity type: Tracking number<br>\nEntity text: \"FedEx 9612804152073070474837\"</td></tr>\n\n<tr><td>Call the restaurant at <b>555-555-1234</b> to pay for dinner. My card\nnumber is <b>4111 1111 1111 1111</b>.</td>\n<td>Entity 1 type: Phone number<br>\nEntity 1 text: \"555-555-1234\"<br><br>\n\nEntity 2 type: Payment card<br>\nEntity 2 text: \"Visa 4111 1111 1111 1111\"</td></tr>\n\n</table>\n\n## Support\n\n-   [Stack Overflow](https://stackoverflow.com/questions/tagged/google-mlkit)\n\n## License\n\nCopyright 2020 Google LLC.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements. See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership. The ASF licenses this file\nto you under the Apache License, Version 2.0 (the \"License\"); you may not use\nthis file except in compliance with the License. You may obtain a copy of the\nLicense at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExample/AppDelegate.swift",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n  var window: UIWindow?\n\n  func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    return true\n  }\n}\n\n#if !swift(>=4.2)\n  extension UIApplication {\n    typealias LaunchOptionsKey = UIApplicationLaunchOptionsKey\n  }\n#endif  // !swift(>=4.2)\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExample/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExample/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExample/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExample/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14460.31\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14460.20\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" textAlignment=\"natural\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FQT-28-NVR\" userLabel=\"Input Text View\">\n                                <rect key=\"frame\" x=\"16\" y=\"40\" width=\"343\" height=\"160\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"160\" id=\"3BR-MP-SCa\"/>\n                                </constraints>\n                                <string key=\"text\">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\"/>\n                            </textView>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" distribution=\"fillEqually\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0wH-X0-wXh\" userLabel=\"Toolbar\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"200\" width=\"375\" height=\"60\"/>\n                                <subviews>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uLh-z9-rXq\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"187.5\" height=\"60\"/>\n                                        <color key=\"backgroundColor\" red=\"0.23579712561276311\" green=\"0.6301872307327272\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"displayP3\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                        <state key=\"normal\" title=\"Identify Language\">\n                                            <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        </state>\n                                        <connections>\n                                            <action selector=\"identifyLanguage:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"V14-jA-TXm\"/>\n                                        </connections>\n                                    </button>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"wordWrap\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"peZ-pd-Uys\">\n                                        <rect key=\"frame\" x=\"187.5\" y=\"0.0\" width=\"187.5\" height=\"60\"/>\n                                        <color key=\"backgroundColor\" red=\"0.23579712561276311\" green=\"0.6301872307327272\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"displayP3\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                        <state key=\"normal\" title=\"Identify Possible Languages\">\n                                            <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        </state>\n                                        <connections>\n                                            <action selector=\"identifyPossibleLanguages:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"jyx-0A-bDl\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"60\" id=\"J6s-qD-zU4\"/>\n                                </constraints>\n                            </stackView>\n                            <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" editable=\"NO\" textAlignment=\"natural\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SNu-r4-GMJ\" userLabel=\"Output Text View\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"260\" width=\"375\" height=\"407\"/>\n                                <color key=\"backgroundColor\" red=\"0.23579712561276311\" green=\"0.6301872307327272\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"displayP3\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\"/>\n                            </textView>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"SNu-r4-GMJ\" firstAttribute=\"top\" secondItem=\"0wH-X0-wXh\" secondAttribute=\"bottom\" id=\"N0t-lx-kx6\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"bottom\" secondItem=\"SNu-r4-GMJ\" secondAttribute=\"bottom\" id=\"Pgm-ZX-PXo\"/>\n                            <constraint firstItem=\"0wH-X0-wXh\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" id=\"QTJ-af-08m\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"FQT-28-NVR\" secondAttribute=\"trailing\" constant=\"16\" id=\"Qr5-GG-5vc\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"0wH-X0-wXh\" secondAttribute=\"trailing\" id=\"STK-32-7z1\"/>\n                            <constraint firstItem=\"0wH-X0-wXh\" firstAttribute=\"top\" secondItem=\"FQT-28-NVR\" secondAttribute=\"bottom\" id=\"VaP-k0-PIn\"/>\n                            <constraint firstItem=\"SNu-r4-GMJ\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" id=\"bWE-Be-djL\"/>\n                            <constraint firstItem=\"FQT-28-NVR\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" constant=\"16\" id=\"lzo-mv-fSL\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"SNu-r4-GMJ\" secondAttribute=\"trailing\" id=\"pI0-j8-Zk7\"/>\n                            <constraint firstItem=\"FQT-28-NVR\" firstAttribute=\"top\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"top\" constant=\"20\" id=\"uwJ-zR-NzI\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                    <connections>\n                        <outlet property=\"inputTextView\" destination=\"FQT-28-NVR\" id=\"1wY-Py-4iI\"/>\n                        <outlet property=\"outputTextView\" destination=\"SNu-r4-GMJ\" id=\"KDF-TM-BQI\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"136.80000000000001\" y=\"132.68365817091455\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExample/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>0.0.1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExample/ViewController.swift",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\nimport MLKit\n\n@objc(ViewController)\nfinal class ViewController: UIViewController, UITextViewDelegate {\n  @IBOutlet weak var inputTextView: UITextView!\n  @IBOutlet weak var outputTextView: UITextView!\n\n  lazy var languageId = LanguageIdentification.languageIdentification()\n\n  override func viewDidLoad() {\n    super.viewDidLoad()\n    inputTextView.text = \"Type here\"\n    inputTextView.delegate = self\n    inputTextView.accessibilityIdentifier = \"inputTextView\"\n    outputTextView.accessibilityIdentifier = \"outputTextView\"\n  }\n\n  func displayName(for languageTag: String) -> String {\n    if languageTag == IdentifiedLanguage.undetermined {\n      return \"Undetermined Language\"\n    }\n    return Locale.current.localizedString(forLanguageCode: languageTag)!\n  }\n\n  @IBAction func identifyLanguage(_ sender: Any) {\n    languageId.identifyLanguage(for: inputTextView.text) { (languageTag, error) in\n      if let error = error {\n        self.outputTextView.text = \"Failed with error: \\(error)\"\n        return\n      }\n\n      self.outputTextView.text = \"Identified Language: \\(self.displayName(for:languageTag!))\"\n    }\n  }\n\n  @IBAction func identifyPossibleLanguages(_ sender: Any) {\n    languageId.identifyPossibleLanguages(for: inputTextView.text) { (identifiedLanguages, error) in\n      if let error = error {\n        self.outputTextView.text = \"Failed with error: \\(error)\"\n        return\n      }\n\n      self.outputTextView.text =\n        \"Identified Languages:\\n\"\n        + identifiedLanguages!.map {\n          String(format: \"(%@, %.2f)\", self.displayName(for: $0.languageTag), $0.confidence)\n        }.joined(separator: \"\\n\")\n    }\n  }\n\n  /// Pragma mark - UITextViewDelegate\n\n  // Make all text selected when the text view is activated for editing, so that the newly\n  // input context will override the existing content.\n  func textViewDidBeginEditing(_ textView: UITextView) {\n    textView.selectedTextRange = textView.textRange(\n      from: textView.beginningOfDocument, to: textView.endOfDocument)\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t10F9324721B997E9008B6C9D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 10F9324621B997E9008B6C9D /* AppDelegate.m */; };\n\t\t10F9324A21B997E9008B6C9D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 10F9324921B997E9008B6C9D /* ViewController.m */; };\n\t\t10F9325521B997E9008B6C9D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 10F9325421B997E9008B6C9D /* main.m */; };\n\t\t10F9325A21B9AE2C008B6C9D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1C9170C21AD98F000DD171F /* LaunchScreen.storyboard */; };\n\t\t10F9325B21B9AE32008B6C9D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1085F3721AEB545007C8D86 /* Main.storyboard */; };\n\t\t10F9325C21B9AE38008B6C9D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C1C9170A21AD98EF00DD171F /* Assets.xcassets */; };\n\t\tC1085F3921AEB546007C8D86 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1085F3721AEB545007C8D86 /* Main.storyboard */; };\n\t\tC1C9170421AD98EE00DD171F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C9170321AD98EE00DD171F /* AppDelegate.swift */; };\n\t\tC1C9170621AD98EE00DD171F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C9170521AD98EE00DD171F /* ViewController.swift */; };\n\t\tC1C9170B21AD98EF00DD171F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C1C9170A21AD98EF00DD171F /* Assets.xcassets */; };\n\t\tC1C9170E21AD98F000DD171F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1C9170C21AD98F000DD171F /* LaunchScreen.storyboard */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t10F9324321B997E8008B6C9D /* LanguageIDExampleObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LanguageIDExampleObjC.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t10F9324521B997E9008B6C9D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t10F9324621B997E9008B6C9D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t10F9324821B997E9008B6C9D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\t10F9324921B997E9008B6C9D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\t10F9325421B997E9008B6C9D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tC1085F3821AEB545007C8D86 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tC1C9170021AD98EE00DD171F /* LanguageIDExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LanguageIDExample.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC1C9170321AD98EE00DD171F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tC1C9170521AD98EE00DD171F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tC1C9170A21AD98EF00DD171F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tC1C9170D21AD98F000DD171F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tC1C9170F21AD98F000DD171F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t10F9324021B997E8008B6C9D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1C916FD21AD98EE00DD171F /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t10F9324421B997E8008B6C9D /* LanguageIDExampleObjC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t10F9324521B997E9008B6C9D /* AppDelegate.h */,\n\t\t\t\t10F9324621B997E9008B6C9D /* AppDelegate.m */,\n\t\t\t\t10F9324821B997E9008B6C9D /* ViewController.h */,\n\t\t\t\t10F9324921B997E9008B6C9D /* ViewController.m */,\n\t\t\t\t10F9325421B997E9008B6C9D /* main.m */,\n\t\t\t);\n\t\t\tpath = LanguageIDExampleObjC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1C916F721AD98EE00DD171F = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC1C9170221AD98EE00DD171F /* LanguageIDExample */,\n\t\t\t\t10F9324421B997E8008B6C9D /* LanguageIDExampleObjC */,\n\t\t\t\tC1C9170121AD98EE00DD171F /* Products */,\n\t\t\t\tE0CD026E0409A559B9676047 /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1C9170121AD98EE00DD171F /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC1C9170021AD98EE00DD171F /* LanguageIDExample.app */,\n\t\t\t\t10F9324321B997E8008B6C9D /* LanguageIDExampleObjC.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1C9170221AD98EE00DD171F /* LanguageIDExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC1085F3721AEB545007C8D86 /* Main.storyboard */,\n\t\t\t\tC1C9170321AD98EE00DD171F /* AppDelegate.swift */,\n\t\t\t\tC1C9170521AD98EE00DD171F /* ViewController.swift */,\n\t\t\t\tC1C9170A21AD98EF00DD171F /* Assets.xcassets */,\n\t\t\t\tC1C9170C21AD98F000DD171F /* LaunchScreen.storyboard */,\n\t\t\t\tC1C9170F21AD98F000DD171F /* Info.plist */,\n\t\t\t);\n\t\t\tpath = LanguageIDExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE0CD026E0409A559B9676047 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t10F9324221B997E8008B6C9D /* LanguageIDExampleObjC */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 10F9325821B997E9008B6C9D /* Build configuration list for PBXNativeTarget \"LanguageIDExampleObjC\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t10F9323F21B997E8008B6C9D /* Sources */,\n\t\t\t\t10F9324021B997E8008B6C9D /* Frameworks */,\n\t\t\t\t10F9324121B997E8008B6C9D /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = LanguageIDExampleObjC;\n\t\t\tproductName = LanguageIDExampleObjC;\n\t\t\tproductReference = 10F9324321B997E8008B6C9D /* LanguageIDExampleObjC.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tC1C916FF21AD98EE00DD171F /* LanguageIDExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C1C9172821AD98F100DD171F /* Build configuration list for PBXNativeTarget \"LanguageIDExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tC1C916FC21AD98EE00DD171F /* Sources */,\n\t\t\t\tC1C916FD21AD98EE00DD171F /* Frameworks */,\n\t\t\t\tC1C916FE21AD98EE00DD171F /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = LanguageIDExample;\n\t\t\tproductName = LanguageIDApp;\n\t\t\tproductReference = C1C9170021AD98EE00DD171F /* LanguageIDExample.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tC1C916F821AD98EE00DD171F /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1010;\n\t\t\t\tLastUpgradeCheck = 1010;\n\t\t\t\tORGANIZATIONNAME = \"Google Inc\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t10F9324221B997E8008B6C9D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t};\n\t\t\t\t\tC1C916FF21AD98EE00DD171F = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = C1C916FB21AD98EE00DD171F /* Build configuration list for PBXProject \"LanguageIDExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = C1C916F721AD98EE00DD171F;\n\t\t\tproductRefGroup = C1C9170121AD98EE00DD171F /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tC1C916FF21AD98EE00DD171F /* LanguageIDExample */,\n\t\t\t\t10F9324221B997E8008B6C9D /* LanguageIDExampleObjC */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t10F9324121B997E8008B6C9D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t10F9325B21B9AE32008B6C9D /* Main.storyboard in Resources */,\n\t\t\t\t10F9325C21B9AE38008B6C9D /* Assets.xcassets in Resources */,\n\t\t\t\t10F9325A21B9AE2C008B6C9D /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1C916FE21AD98EE00DD171F /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC1C9170E21AD98F000DD171F /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tC1C9170B21AD98EF00DD171F /* Assets.xcassets in Resources */,\n\t\t\t\tC1085F3921AEB546007C8D86 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t10F9323F21B997E8008B6C9D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t10F9324A21B997E9008B6C9D /* ViewController.m in Sources */,\n\t\t\t\t10F9325521B997E9008B6C9D /* main.m in Sources */,\n\t\t\t\t10F9324721B997E9008B6C9D /* AppDelegate.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1C916FC21AD98EE00DD171F /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC1C9170621AD98EE00DD171F /* ViewController.swift in Sources */,\n\t\t\t\tC1C9170421AD98EE00DD171F /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tC1085F3721AEB545007C8D86 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tC1085F3821AEB545007C8D86 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1C9170C21AD98F000DD171F /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tC1C9170D21AD98F000DD171F /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t10F9325621B997E9008B6C9D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/LanguageIDExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.LanguageIDExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"Google Development\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t10F9325721B997E9008B6C9D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/LanguageIDExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.LanguageIDExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"Google Development\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC1C9172621AD98F100DD171F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC1C9172721AD98F100DD171F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC1C9172921AD98F100DD171F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/LanguageIDExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\t\"OTHER_SWIFT_FLAGS[arch=*]\" = \"$(inherited) -D COCOAPODS\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.LanguageIDExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC1C9172A21AD98F100DD171F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/LanguageIDExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.sampleapp.langid;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t10F9325821B997E9008B6C9D /* Build configuration list for PBXNativeTarget \"LanguageIDExampleObjC\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t10F9325621B997E9008B6C9D /* Debug */,\n\t\t\t\t10F9325721B997E9008B6C9D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC1C916FB21AD98EE00DD171F /* Build configuration list for PBXProject \"LanguageIDExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC1C9172621AD98F100DD171F /* Debug */,\n\t\t\t\tC1C9172721AD98F100DD171F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC1C9172821AD98F100DD171F /* Build configuration list for PBXNativeTarget \"LanguageIDExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC1C9172921AD98F100DD171F /* Debug */,\n\t\t\t\tC1C9172A21AD98F100DD171F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = C1C916F821AD98EE00DD171F /* Project object */;\n}\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExampleObjC/AppDelegate.h",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n\n\n@end\n\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExampleObjC/AppDelegate.m",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"AppDelegate.h\"\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n  return YES;\n}\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExampleObjC/ViewController.h",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController <UITextViewDelegate>\n\n@end\n\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExampleObjC/ViewController.m",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"ViewController.h\"\n\n@import MLKit;\n\n@interface ViewController ()\n@property (weak, nonatomic) IBOutlet UITextView *inputTextView;\n@property (weak, nonatomic) IBOutlet UITextView *outputTextView;\n@property(nonatomic, strong) MLKLanguageIdentification *languageId;\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  self.languageId = [MLKLanguageIdentification languageIdentification];\n  _inputTextView.text = @\"Type here\";\n  _inputTextView.delegate = self;\n  _inputTextView.accessibilityIdentifier = @\"inputTextView\";\n  _outputTextView.accessibilityIdentifier = @\"outputTextView\";\n}\n\n- (NSString *)displayNameForLanguageTag:(NSString *)languageTag {\n  if ([languageTag isEqual:MLKUndeterminedLanguageTag]) {\n    return @\"Undetermined Language\";\n  }\n  return [NSLocale.currentLocale localizedStringForLanguageCode:languageTag];\n}\n\n- (IBAction)identifyLanguage:(id)sender {\n  [_languageId\n      identifyLanguageForText:_inputTextView.text\n                   completion:^(NSString *_Nullable languageTag, NSError *_Nullable error) {\n                     if (error != nil) {\n                       self.outputTextView.text = [NSString\n                           stringWithFormat:@\"Failed with error: %@\", error.localizedDescription];\n                       return;\n                     }\n                     self.outputTextView.text =\n                         [NSString stringWithFormat:@\"Identified Language: %@\",\n                                                    [self displayNameForLanguageTag:languageTag]];\n                   }];\n}\n\n- (IBAction)identifyPossibleLanguages:(id)sender {\n  [_languageId\n      identifyPossibleLanguagesForText:_inputTextView.text\n                            completion:^(\n                                NSArray<MLKIdentifiedLanguage *> *_Nonnull identifiedLanguages,\n                                NSError *_Nullable error) {\n                              if (error != nil) {\n                                self.outputTextView.text =\n                                    [NSString stringWithFormat:@\"Failed with error: %@\",\n                                                               error.localizedDescription];\n                                return;\n                              }\n                              NSMutableString *outputText =\n                                  [NSMutableString stringWithFormat:@\"Identified Languages:\"];\n                              for (MLKIdentifiedLanguage *language in identifiedLanguages) {\n                                [outputText\n                                    appendFormat:@\"\\n(%@, %.2f)\",\n                                                 [self displayNameForLanguageTag:language\n                                                                                     .languageTag],\n                                                 language.confidence];\n                              }\n                              self.outputTextView.text = outputText;\n                            }];\n}\n\n#pragma mark - TextEditView delegate\n\n/**\n * Make all text selected when the text view is activated for editing, so that the newly input\n * context will override the existing content.\n */\n- (void)textViewDidBeginEditing:(UITextView *)textView {\n  textView.selectedTextRange = [textView textRangeFromPosition:textView.beginningOfDocument\n                                                    toPosition:textView.endOfDocument];\n}\n\n/** Hide the keyboard when \"Done\" is pressed. */\n- (BOOL)textView:(UITextView *)textView\n    shouldChangeTextInRange:(NSRange)range\n            replacementText:(NSString *)text {\n  if ([text isEqualToString:@\"\\n\"]) {\n    [textView resignFirstResponder];\n    return NO;\n  }\n  return YES;\n}\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/languageid/LanguageIDExampleObjC/main.m",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n  @autoreleasepool {\n      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/languageid/Podfile",
    "content": "use_frameworks!\nplatform :ios, '15.5'\n\nproject 'LanguageIDExample.xcodeproj'\n\npod 'GoogleMLKit/LanguageID', '9.0.0'\n\ntarget 'LanguageIDExample' do\nend\n\ntarget 'LanguageIDExampleObjC' do\nend\n\npost_install do |installer|\n  installer.aggregate_targets.each do |target|\n    target.xcconfigs.each do |variant, xcconfig|\n      xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)\n      IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n    end\n  end\n  installer.generated_projects.each do |project|\n    project.targets.each do |target|\n        target.build_configurations.each do |config|\n            config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'\n            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'\n         end\n    end\n  end\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference\n        xcconfig_path = config.base_configuration_reference.real_path\n        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n      end\n    end\n  end\nend"
  },
  {
    "path": "ios/quickstarts/languageid/README.md",
    "content": "# ML Kit Language ID Quickstart Sample App\n\n* [Read more about ML Kit LanguageID](https://developers.google.com/ml-kit/language/identification)\n\n## Introduction\n\nThe ML Kit Language ID iOS Quickstart app demonstrates how to use the Language\nID feature of ML Kit to identify the language of entered text in your application.\n\n## Feature List\n\nFeatures that are included in this demo app:\n\n* [Language Identification](https://developers.google.com/ml-kit/language/identification/ios) - Identify the language of text with ML Kit on iOS\n\n<img src=\"../../screenshots/langid.jpg\" width=\"256\"/>\n\n## Getting Started\n\n- Run the sample on your iOS device or simulator.\n\n## Support\n\n- [Stack Overflow](https://stackoverflow.com/questions/tagged/google-mlkit)\n\nLicense\n-------\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "ios/quickstarts/smartreply/Podfile",
    "content": "use_frameworks!\nplatform :ios, '15.5'\n\nproject 'SmartReplyExample.xcodeproj'\n\npod 'GoogleMLKit/SmartReply', '9.0.0'\n\npod 'MaterialComponents'\npod 'SwiftLint'\n\ntarget 'SmartReplyExampleObjC' do\nend\ntarget 'SmartReplyExample' do\nend\n\npost_install do |installer|\n  installer.aggregate_targets.each do |target|\n    target.xcconfigs.each do |variant, xcconfig|\n      xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)\n      IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n    end\n  end\n  installer.generated_projects.each do |project|\n    project.targets.each do |target|\n        target.build_configurations.each do |config|\n            config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'\n            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'\n         end\n    end\n  end\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference\n        xcconfig_path = config.base_configuration_reference.real_path\n        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n      end\n    end\n  end\nend"
  },
  {
    "path": "ios/quickstarts/smartreply/README.md",
    "content": "# ML Kit Smart Reply Quickstart Sample App\n\n* [Read more about ML Kit Smart Reply](https://developers.google.com/ml-kit/language/smart-reply)\n\n## Introduction\n\nThe ML Kit Smart Reply iOS Quickstart app demonstrates how to use the Smart\nReply feature of ML Kit to automatically generate replies to conversation\nthreads in your application.\n\n## Feature List\n\nFeatures that are included in this demo app:\n\n* [Smart Reply](https://developers.google.com/ml-kit/language/smart-reply/ios) - Generate smart replies with ML Kit on iOS\n\n<img src=\"../../screenshots/smart_reply.jpg\" width=\"256\"/>\n\n## Getting Started\n\n* Run the sample on your iOS device or simulator.\n* Type message text and press “Switch” button to generate smart replies.\n\n## Support\n\n- [Stack Overflow](https://stackoverflow.com/questions/tagged/google-mlkit)\n\nLicense\n-------\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExample/AppDelegate.swift",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\n@UIApplicationMain\n// [START signin_delegate]\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n  // [END signin_delegate]\n\n  var window: UIWindow?\n\n  func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    return true\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExample/DateExtension.swift",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\n\nextension Date {\n\n  func timeAgo() -> String {\n\n    let interval = Calendar.current.dateComponents(\n      [.year, .day, .hour, .minute, .second], from: self, to: Date())\n\n    if let year = interval.year, year > 0 {\n      return DateFormatter.localizedString(from: self, dateStyle: .long, timeStyle: .none)\n    } else if let day = interval.day, day > 6 {\n      let format = DateFormatter.dateFormat(\n        fromTemplate: \"MMMMd\", options: 0, locale: NSLocale.current)\n      let formatter = DateFormatter()\n      formatter.dateFormat = format\n      return formatter.string(from: self)\n    } else if let day = interval.day, day > 0 {\n      return day == 1 ? \"\\(day) day ago\" : \"\\(day) days ago\"\n    } else if let hour = interval.hour, hour > 0 {\n      return hour == 1 ? \"\\(hour) hour ago\" : \"\\(hour) hours ago\"\n    } else if let minute = interval.minute, minute > 0 {\n      return minute == 1 ? \"\\(minute) minute ago\" : \"\\(minute) minutes ago\"\n    } else if let second = interval.second, second > 0 {\n      return second == 1 ? \"\\(second) second ago\" : \"\\(second) seconds ago\"\n    } else {\n      return \"just now\"\n    }\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExample/MainViewController.swift",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, eitheimputVir express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport MLKit\nimport MaterialComponents\n\n@objc(MainViewController)\nclass MainViewController: UICollectionViewController, UITextViewDelegate {\n  private lazy var messages = [TextMessage]()\n  private var isLocalUser = true\n\n  private var bottomConstraint: NSLayoutConstraint!\n  private var heightConstraint: NSLayoutConstraint!\n  private var inputBottomConstraint: NSLayoutConstraint!\n  private var sendBottomConstraint: NSLayoutConstraint!\n  private var isKeyboardShown = false\n  private let messageInputContainerView: UIView = {\n    let view = UIView()\n    if #available(iOS 13.0, *) {\n      // Support dark mode\n      view.backgroundColor = .systemBackground\n    } else {\n      view.backgroundColor = .white\n    }\n    return view\n  }()\n\n  lazy var smartReply = SmartReply.smartReply()\n\n  var bottomAreaInset: CGFloat = 0\n\n  let inputTextView: UITextView = {\n    let textView = UITextView(placeholder: \"Write a message\")\n    textView.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.callout)\n    textView.isScrollEnabled = false\n    textView.accessibilityIdentifier = \"Input Box\"\n    return textView\n  }()\n\n  let smartReplyView: UIStackView = {\n    let view = UIStackView()\n    view.distribution = .equalSpacing\n    for index in 0..<3 {\n      let chipView = MDCChipView()\n      chipView.isHidden = true\n      chipView.setTitleColor(UIColor.red, for: .selected)\n      chipView.accessibilityIdentifier = \"Smart Reply Suggestion\"\n      let widthConstraint = chipView.widthAnchor.constraint(equalToConstant: 0)\n      widthConstraint.identifier = \"width\"\n      widthConstraint.isActive = true\n      chipView.addTarget(self, action: #selector(replySelected(reply:)), for: .touchUpInside)\n      view.addArrangedSubview(chipView)\n    }\n    return view\n  }()\n\n  let sendButton: MDCFloatingButton = {\n    let button = MDCFloatingButton(shape: .mini)\n    button.setImage(#imageLiteral(resourceName: \"ic_send\"), for: .normal)\n    button.tintColor = .blue\n    button.backgroundColor = .white\n    button.accessibilityLabel = \"Send\"\n    button.isEnabled = false\n    button.addTarget(self, action: #selector(enterPressed), for: .touchUpInside)\n    return button\n  }()\n\n  lazy var moreAlert: UIAlertController = {\n    let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)\n    alert.addAction(\n      UIAlertAction(title: \"Generate basic history\", style: .default) { _ in\n        self.generateChatHistoryBasic()\n      })\n    alert.addAction(\n      UIAlertAction(\n        title: \"Generate history with sensitive content\",\n        style: .default\n      ) { _ in\n        self.generateChatHistoryWithSensitiveContent()\n      })\n    alert.addAction(\n      UIAlertAction(title: \"Clear chat history\", style: .destructive) { _ in\n        self.messages = []\n        self.updateReplies()\n        self.collectionView.reloadData()\n        self.collectionView.collectionViewLayout.invalidateLayout()\n      })\n    alert.addAction(UIAlertAction(title: \"Cancel\", style: .cancel, handler: nil))\n    return alert\n  }()\n\n  override func viewDidLoad() {\n    super.viewDidLoad()\n    updateNavigationBar(.blue)\n\n    guard let collectionView = collectionView else {\n      return\n    }\n\n    // registering the cell\n    collectionView.register(MDCSelfSizingStereoCell.self, forCellWithReuseIdentifier: \"cell\")\n\n    if #available(iOS 11.0, *) {\n      bottomAreaInset = UIApplication.shared.keyWindow!.safeAreaInsets.bottom\n    }\n\n    inputTextView.delegate = self\n\n    NotificationCenter.default.addObserver(\n      self, selector: #selector(handleKeyboardNotification),\n      name: UIResponder.keyboardWillShowNotification, object: nil)\n    NotificationCenter.default.addObserver(\n      self, selector: #selector(handleKeyboardNotification),\n      name: UIResponder.keyboardWillHideNotification, object: nil)\n\n    guard let col = collectionViewLayout as? UICollectionViewFlowLayout else { return }\n    col.estimatedItemSize = CGSize.init(width: collectionView.bounds.width, height: 52)\n\n    view.addSubview(messageInputContainerView)\n\n    view.addConstraintsWithFormat(format: \"H:|[v0]|\", views: messageInputContainerView)\n\n    heightConstraint = messageInputContainerView.heightAnchor.constraint(\n      equalToConstant: 88 + bottomAreaInset)\n\n    bottomConstraint = NSLayoutConstraint(\n      item: messageInputContainerView, attribute: .bottom, relatedBy: .equal,\n      toItem: view, attribute: .bottom, multiplier: 1, constant: 0)\n    view.addConstraint(bottomConstraint)\n    view.addConstraint(heightConstraint)\n    setupInputComponents()\n  }\n\n  private func updateNavigationBar(_ color: UIColor) {\n    guard let navigationBar = navigationController?.navigationBar else { return }\n    if #available(iOS 13.0, *) {\n      // In iOS 15, `scrollEdgeAppearance` applies to all navigtion bars. If the value of\n      // `scrollEdgeAppearance` is `nil`, UIKit uses the setting in `standardAppearance` and\n      // modify it to use a transparent background. To avoid this, we have the `UINavigationBar`\n      // use the same appearance for both standard and edge states.\n      navigationBar.standardAppearance.backgroundColor = color\n      navigationBar.standardAppearance.titleTextAttributes = [\n        .foregroundColor: UIColor.white\n      ]\n      navigationBar.scrollEdgeAppearance =\n        navigationBar.standardAppearance\n    } else {\n      navigationBar.barTintColor = color\n    }\n  }\n\n  private func setupInputComponents() {\n    let topBorderView = UIView()\n    topBorderView.backgroundColor = UIColor(white: 0.5, alpha: 0.5)\n    messageInputContainerView.addSubview(inputTextView)\n    messageInputContainerView.addSubview(sendButton)\n    messageInputContainerView.addSubview(topBorderView)\n    messageInputContainerView.addSubview(smartReplyView)\n\n    messageInputContainerView.addConstraintsWithFormat(\n      format: \"H:|-8-[v0][v1(40)]-16-|\",\n      views: inputTextView, sendButton)\n    messageInputContainerView.addConstraintsWithFormat(format: \"H:|[v0]|\", views: topBorderView)\n    messageInputContainerView.addConstraintsWithFormat(\n      format: \"H:|-16-[v0]-16-|\", views: smartReplyView)\n\n    smartReplyView.topAnchor.constraint(equalTo: messageInputContainerView.topAnchor, constant: 6)\n      .isActive = true\n    smartReplyView.bottomAnchor.constraint(equalTo: inputTextView.topAnchor, constant: -6).isActive =\n      true\n\n    inputBottomConstraint = messageInputContainerView.bottomAnchor.constraint(\n      equalTo: inputTextView.bottomAnchor,\n      constant: bottomAreaInset)\n    inputBottomConstraint.isActive = true\n\n    sendBottomConstraint = messageInputContainerView.bottomAnchor.constraint(\n      equalTo: sendButton.bottomAnchor,\n      constant: bottomAreaInset + 6)\n    sendBottomConstraint.isActive = true\n\n    messageInputContainerView.addConstraintsWithFormat(format: \"V:|[v0(0.5)]\", views: topBorderView)\n  }\n\n  override func viewWillAppear(_ animated: Bool) {\n    super.viewWillAppear(animated)\n    inputTextView.becomeFirstResponder()\n  }\n\n  override func viewWillDisappear(_ animated: Bool) {\n    inputTextView.endEditing(true)\n    super.viewWillDisappear(animated)\n  }\n\n  override func viewDidLayoutSubviews() {\n    super.viewDidLayoutSubviews()\n    inputTextView.resizePlaceholder()\n  }\n\n  @objc func replySelected(reply: MDCChipView) {\n    guard let title = reply.titleLabel.text else { return }\n    inputTextView.insertText(title)\n  }\n\n  @IBAction func switchUser(_ sender: Any) {\n    isLocalUser.toggle()\n    let color: UIColor = isLocalUser ? .blue : .red\n    sendButton.tintColor = color\n    updateNavigationBar(color)\n    updateReplies()\n  }\n\n  private func generateChatHistoryBasic() {\n    guard let date = Calendar.current.date(byAdding: .day, value: -1, to: Date()) else { return }\n    guard\n      let dateAfter = Calendar.current.date(\n        byAdding: .minute,\n        value: 10, to: date)?.timeIntervalSince1970\n    else { return }\n    messages = [\n      TextMessage(\n        text: \"Hello\", timestamp: date.timeIntervalSince1970, userID: \"\", isLocalUser: true),\n      TextMessage(text: \"Hey\", timestamp: dateAfter, userID: \"\", isLocalUser: false),\n    ]\n    self.updateReplies()\n    self.collectionView.reloadData()\n    self.collectionView.collectionViewLayout.invalidateLayout()\n  }\n\n  private func generateChatHistoryWithSensitiveContent() {\n    guard let date = Calendar.current.date(byAdding: .day, value: -1, to: Date()) else { return }\n    guard\n      let dateAfter = Calendar.current.date(\n        byAdding: .minute,\n        value: 10, to: date)?.timeIntervalSince1970\n    else { return }\n    guard\n      let dateAfterAfter = Calendar.current.date(\n        byAdding: .minute,\n        value: 20, to: date)?.timeIntervalSince1970\n    else { return }\n    messages = [\n      TextMessage(\n        text: \"Hi\", timestamp: date.timeIntervalSince1970, userID: \"\", isLocalUser: false),\n      TextMessage(text: \"How are you?\", timestamp: dateAfter, userID: \"\", isLocalUser: true),\n      TextMessage(text: \"My cat died\", timestamp: dateAfterAfter, userID: \"\", isLocalUser: false),\n    ]\n    self.updateReplies()\n    self.collectionView.reloadData()\n    self.collectionView.collectionViewLayout.invalidateLayout()\n  }\n\n  func textViewDidEndEditing(_ textView: UITextView) {\n    sendButton.isEnabled = false\n    heightConstraint.constant = 88 + bottomAreaInset\n  }\n\n  func textViewDidChange(_ textView: UITextView) {\n    sendButton.isEnabled = !textView.text.isEmpty\n    let size = CGSize(width: view.frame.width - 60, height: .infinity)\n    let estimatedSize = textView.sizeThatFits(size)\n    heightConstraint.constant =\n      estimatedSize.height + 54 + (self.isKeyboardShown ? 0 : bottomAreaInset)\n  }\n\n  @IBAction func didTapMore(_ sender: UIBarButtonItem) {\n    moreAlert.popoverPresentationController?.barButtonItem = sender\n    present(moreAlert, animated: true, completion: nil)\n  }\n\n  @objc func enterPressed() {\n    inputTextView.endEditing(true)\n    guard let text = inputTextView.text, !text.isEmpty else { return }\n    let message = TextMessage(\n      text: text, timestamp: Date().timeIntervalSince1970,\n      userID: \"\", isLocalUser: isLocalUser)\n    messages.append(message)\n    collectionView.insertItems(at: [IndexPath(item: messages.count - 1, section: 0)])\n    inputTextView.text = nil\n    inputTextView.textViewDidChange(inputTextView)\n    self.smartReplyView.arrangedSubviews.compactMap { $0 as? MDCChipView }.forEach {\n      $0.isHidden = true\n    }\n  }\n\n  private func updateReplies() {\n    // SmartReply for users' own messages is a non-use-case.\n    guard let lastMessage = messages.last, lastMessage.isLocalUser != isLocalUser else {\n      self.smartReplyView.subviews.compactMap { $0 as? MDCChipView }.forEach { $0.isHidden = true }\n      return\n    }\n    var chat = messages\n\n    // Revert isLocalUser field in text messages to simulate the remote user for the sample.\n    if !isLocalUser {\n      chat = []\n      for textMessage in messages.suffix(10) {\n        chat.append(\n          TextMessage(\n            text: textMessage.text, timestamp: textMessage.timestamp,\n            userID: textMessage.userID, isLocalUser: !textMessage.isLocalUser))\n      }\n    }\n\n    smartReply.suggestReplies(for: chat) { result, error in\n      let suggestionChips = self.smartReplyView.subviews.compactMap { $0 as? MDCChipView }\n      guard error == nil, let suggestions = result?.suggestions, !suggestions.isEmpty else {\n        suggestionChips.forEach { $0.isHidden = true }\n        return\n      }\n      zip(suggestionChips, suggestions).forEach { chip, suggestion in\n        chip.isHidden = false\n        chip.titleLabel.text = suggestion.text\n        chip.sizeToFit()\n        chip.constraints.first { $0.identifier == \"width\" }?.constant = chip.bounds.width\n      }\n    }\n  }\n\n  @objc func handleKeyboardNotification(notification: NSNotification) {\n    guard\n      let keyboardSize =\n        (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey]\n        as? NSValue)?.cgRectValue\n    else { return }\n    let isKeyboardShowing = notification.name == UIResponder.keyboardWillShowNotification\n    guard self.isKeyboardShown != isKeyboardShowing else {\n      bottomConstraint?.constant = isKeyboardShowing ? -keyboardSize.height : 0\n      if !self.messages.isEmpty {\n        let indexPath = IndexPath(item: self.messages.count - 1, section: 0)\n        self.collectionView?.scrollToItem(at: indexPath, at: .top, animated: false)\n      }\n      return\n    }\n    self.isKeyboardShown = isKeyboardShowing\n    bottomConstraint?.constant = isKeyboardShowing ? -keyboardSize.height : 0\n    let inset = isKeyboardShowing ? -bottomAreaInset : bottomAreaInset\n    heightConstraint?.constant += inset\n    inputBottomConstraint?.constant = isKeyboardShowing ? 0 : bottomAreaInset\n    sendBottomConstraint?.constant = isKeyboardShowing ? 6 : (6 + bottomAreaInset)\n    if let animationDuration =\n      notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as? Double\n    {\n      UIView.animate(\n        withDuration: animationDuration, delay: 0, options: .curveEaseOut,\n        animations: {\n          self.view.layoutIfNeeded()\n        },\n        completion: { _ in\n          if !self.messages.isEmpty {\n            let indexPath = IndexPath(item: self.messages.count - 1, section: 0)\n            self.collectionView?.scrollToItem(at: indexPath, at: .top, animated: false)\n          }\n        })\n    }\n  }\n\n  func textViewDidBeginEditing(_ textView: UITextView) {\n    textViewDidChange(textView)\n  }\n\n  override func numberOfSections(in collectionView: UICollectionView) -> Int {\n    return 1\n  }\n\n  override func collectionView(\n    _ collectionView: UICollectionView, numberOfItemsInSection section: Int\n  ) -> Int {\n    return messages.count\n  }\n\n  override func collectionView(\n    _ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath\n  ) {\n    inputTextView.endEditing(true)\n  }\n\n  override func collectionView(\n    _ collectionView: UICollectionView,\n    cellForItemAt indexPath: IndexPath\n  ) -> UICollectionViewCell {\n    guard\n      let cell = collectionView.dequeueReusableCell(\n        withReuseIdentifier: \"cell\",\n        for: indexPath) as? MDCSelfSizingStereoCell\n    else {\n      return UICollectionViewCell()\n    }\n    let item = messages[indexPath.item]\n    cell.leadingImageView.image = #imageLiteral(resourceName: \"ic_account_circle_36pt\")\n    cell.leadingImageView.tintColor = item.isLocalUser ? .blue : .red\n    cell.titleLabel.text = item.text\n    cell.detailLabel.text = Date(timeIntervalSince1970: item.timestamp).timeAgo()\n    if #available(iOS 13.0, *) {\n      // Support dark mode\n      cell.titleLabel.textColor = .label\n      cell.detailLabel.textColor = .label\n    }\n    return cell\n  }\n}\n\nextension UIView {\n  func addConstraintsWithFormat(format: String, views: UIView...) {\n    var viewsDictionary = [String: UIView]()\n    for (index, view) in views.enumerated() {\n      let key = \"v\\(index)\"\n      view.translatesAutoresizingMaskIntoConstraints = false\n      viewsDictionary[key] = view\n    }\n    addConstraints(\n      NSLayoutConstraint.constraints(\n        withVisualFormat: format, options: NSLayoutConstraint.FormatOptions(),\n        metrics: nil, views: viewsDictionary))\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExample/UITextViewPlaceholder.swift",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\n/// Extend UITextView and implemented UITextViewDelegate to listen for changes\nextension UITextView {\n\n  public convenience init(placeholder: String) {\n    self.init()\n    self.placeholder = placeholder\n    NotificationCenter.default.addObserver(\n      self,\n      selector: #selector(textViewDidChange),\n      name: UITextView.textDidChangeNotification,\n      object: nil)\n  }\n\n  /// Resize the placeholder when the UITextView bounds change\n  override open var bounds: CGRect {\n    didSet {\n      self.resizePlaceholder()\n    }\n  }\n\n  /// The UITextView placeholder text\n  public var placeholder: String? {\n    get {\n      var placeholderText: String?\n\n      if let placeholderLabel = self.viewWithTag(100) as? UILabel {\n        placeholderText = placeholderLabel.text\n      }\n\n      return placeholderText\n    }\n    set {\n      if let placeholderLabel = self.viewWithTag(100) as? UILabel {\n        placeholderLabel.text = newValue\n        placeholderLabel.sizeToFit()\n      } else {\n        self.addPlaceholder(newValue!)\n      }\n    }\n  }\n\n  /// When the UITextView did change, show or hide the label based on if the UITextView is empty or not\n  ///\n  /// - Parameter textView: The UITextView that got updated\n  @objc public func textViewDidChange(_ textView: UITextView) {\n    if let placeholderLabel = self.viewWithTag(100) as? UILabel {\n      placeholderLabel.isHidden = !self.text.isEmpty\n    }\n  }\n\n  /// Resize the placeholder UILabel to make sure it's in the same position as the UITextView text\n  func resizePlaceholder() {\n    if let placeholderLabel = self.viewWithTag(100) as? UILabel {\n      let labelX = self.textContainer.lineFragmentPadding\n      let labelY = self.textContainerInset.top - 2\n      let labelWidth = self.frame.width - (labelX * 2)\n      let labelHeight = placeholderLabel.frame.height\n\n      placeholderLabel.frame = CGRect(x: labelX, y: labelY, width: labelWidth, height: labelHeight)\n    }\n  }\n\n  /// Adds a placeholder UILabel to this UITextView\n  private func addPlaceholder(_ placeholderText: String) {\n    let placeholderLabel = UILabel()\n\n    placeholderLabel.text = placeholderText\n    placeholderLabel.sizeToFit()\n\n    placeholderLabel.font = UIFont.preferredFont(forTextStyle: .callout)\n    placeholderLabel.textColor = UIColor.lightGray\n    placeholderLabel.tag = 100\n\n    placeholderLabel.isHidden = !self.text.isEmpty\n\n    self.addSubview(placeholderLabel)\n    self.resizePlaceholder()\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 47;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1091729C22066E9D0059D03D /* UITextView+Placeholder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1091729B22066E9D0059D03D /* UITextView+Placeholder.m */; };\n\t\t1091729F2206767C0059D03D /* NSDate+Format.m in Sources */ = {isa = PBXBuildFile; fileRef = 1091729E2206767C0059D03D /* NSDate+Format.m */; };\n\t\t109172A022067F750059D03D /* UITextViewPlaceholder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 106C558821F7958B00908FF7 /* UITextViewPlaceholder.swift */; };\n\t\t109172A122067F7A0059D03D /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 108F913D21FB8F1A0069ADDA /* DateExtension.swift */; };\n\t\t10B054031C6A3C630061077D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 10B054011C6A3C630061077D /* Main.storyboard */; };\n\t\t40B95AC224616FAD007AED02 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 40B95AC124616FAD007AED02 /* LaunchScreen.xib */; };\n\t\t40B95AC324616FAD007AED02 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 40B95AC124616FAD007AED02 /* LaunchScreen.xib */; };\n\t\t40B95AC5246179AA007AED02 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 40B95AC4246179A9007AED02 /* Assets.xcassets */; };\n\t\t40B95AC62461821E007AED02 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 40B95AC4246179A9007AED02 /* Assets.xcassets */; };\n\t\t5F5A53521ADE670C00F81DF0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F5A53511ADE670C00F81DF0 /* main.m */; };\n\t\t5F5A53551ADE670C00F81DF0 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F5A53541ADE670C00F81DF0 /* AppDelegate.m */; };\n\t\t5F5A537E1ADE67D500F81DF0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5A537D1ADE67D500F81DF0 /* AppDelegate.swift */; };\n\t\tEF4857041C752B7700649485 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 10B054011C6A3C630061077D /* Main.storyboard */; };\n\t\tEF6DB4CD1CDD60F700319C08 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF6DB4CA1CDD60F700319C08 /* MainViewController.swift */; };\n\t\tEF6DB4D61CDD610200319C08 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EF6DB4D01CDD610200319C08 /* MainViewController.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t1036DA102087CA25003253C9 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 5F5A53441ADE670C00F81DF0 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 5F5A534B1ADE670C00F81DF0;\n\t\t\tremoteInfo = SmartReplyExampleObjC;\n\t\t};\n\t\t1036DA1E2087CA66003253C9 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 5F5A53441ADE670C00F81DF0 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 5F5A53781ADE67D500F81DF0;\n\t\t\tremoteInfo = SmartReplyExample;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t106C558821F7958B00908FF7 /* UITextViewPlaceholder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITextViewPlaceholder.swift; sourceTree = \"<group>\"; };\n\t\t108F913D21FB8F1A0069ADDA /* DateExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = \"<group>\"; };\n\t\t1091729A22066E9D0059D03D /* UITextView+Placeholder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"UITextView+Placeholder.h\"; sourceTree = \"<group>\"; };\n\t\t1091729B22066E9D0059D03D /* UITextView+Placeholder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = \"UITextView+Placeholder.m\"; sourceTree = \"<group>\"; };\n\t\t1091729D2206767C0059D03D /* NSDate+Format.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"NSDate+Format.h\"; sourceTree = \"<group>\"; };\n\t\t1091729E2206767C0059D03D /* NSDate+Format.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = \"NSDate+Format.m\"; sourceTree = \"<group>\"; };\n\t\t10B054021C6A3C630061077D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t40B95AC124616FAD007AED02 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = LaunchScreen.xib; path = SmartReplyExampleObjC/LaunchScreen.xib; sourceTree = SOURCE_ROOT; };\n\t\t40B95AC4246179A9007AED02 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = SmartReplyExampleObjC/Assets.xcassets; sourceTree = SOURCE_ROOT; };\n\t\t5F5A534C1ADE670C00F81DF0 /* SmartReplyExampleObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SmartReplyExampleObjC.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t5F5A53501ADE670C00F81DF0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t5F5A53511ADE670C00F81DF0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t5F5A53531ADE670C00F81DF0 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t5F5A53541ADE670C00F81DF0 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t5F5A53791ADE67D500F81DF0 /* SmartReplyExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SmartReplyExample.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t5F5A537D1ADE67D500F81DF0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tEF6DB4CA1CDD60F700319C08 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = \"<group>\"; };\n\t\tEF6DB4D01CDD610200319C08 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = \"<group>\"; };\n\t\tEF6DB4D31CDD610200319C08 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t1036DA082087CA25003253C9 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t1036DA162087CA66003253C9 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5F5A53491ADE670C00F81DF0 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5F5A53761ADE67D500F81DF0 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t5F5A53431ADE670C00F81DF0 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5F5A534E1ADE670C00F81DF0 /* SmartReplyExampleObjC */,\n\t\t\t\t5F5A537A1ADE67D500F81DF0 /* SmartReplyExample */,\n\t\t\t\t5F5A534D1ADE670C00F81DF0 /* Products */,\n\t\t\t\t84AF1DBB4C2C1A28DF953D03 /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t\twrapsLines = 0;\n\t\t};\n\t\t5F5A534D1ADE670C00F81DF0 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5F5A534C1ADE670C00F81DF0 /* SmartReplyExampleObjC.app */,\n\t\t\t\t5F5A53791ADE67D500F81DF0 /* SmartReplyExample.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5F5A534E1ADE670C00F81DF0 /* SmartReplyExampleObjC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tEF6DB4D31CDD610200319C08 /* MainViewController.h */,\n\t\t\t\tEF6DB4D01CDD610200319C08 /* MainViewController.m */,\n\t\t\t\t5F5A53531ADE670C00F81DF0 /* AppDelegate.h */,\n\t\t\t\t5F5A53541ADE670C00F81DF0 /* AppDelegate.m */,\n\t\t\t\t1091729A22066E9D0059D03D /* UITextView+Placeholder.h */,\n\t\t\t\t1091729B22066E9D0059D03D /* UITextView+Placeholder.m */,\n\t\t\t\t1091729D2206767C0059D03D /* NSDate+Format.h */,\n\t\t\t\t1091729E2206767C0059D03D /* NSDate+Format.m */,\n\t\t\t\t5F5A534F1ADE670C00F81DF0 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = SmartReplyExampleObjC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5F5A534F1ADE670C00F81DF0 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t40B95AC4246179A9007AED02 /* Assets.xcassets */,\n\t\t\t\t40B95AC124616FAD007AED02 /* LaunchScreen.xib */,\n\t\t\t\t10B054011C6A3C630061077D /* Main.storyboard */,\n\t\t\t\t5F5A53501ADE670C00F81DF0 /* Info.plist */,\n\t\t\t\t5F5A53511ADE670C00F81DF0 /* main.m */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5F5A537A1ADE67D500F81DF0 /* SmartReplyExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t108F913D21FB8F1A0069ADDA /* DateExtension.swift */,\n\t\t\t\tEF6DB4CA1CDD60F700319C08 /* MainViewController.swift */,\n\t\t\t\t5F5A537D1ADE67D500F81DF0 /* AppDelegate.swift */,\n\t\t\t\t106C558821F7958B00908FF7 /* UITextViewPlaceholder.swift */,\n\t\t\t);\n\t\t\tpath = SmartReplyExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t84AF1DBB4C2C1A28DF953D03 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t5F5A534B1ADE670C00F81DF0 /* SmartReplyExampleObjC */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 5F5A536F1ADE670C00F81DF0 /* Build configuration list for PBXNativeTarget \"SmartReplyExampleObjC\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t5F5A53481ADE670C00F81DF0 /* Sources */,\n\t\t\t\t5F5A53491ADE670C00F81DF0 /* Frameworks */,\n\t\t\t\t5F5A534A1ADE670C00F81DF0 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SmartReplyExampleObjC;\n\t\t\tproductName = UserManagementExample;\n\t\t\tproductReference = 5F5A534C1ADE670C00F81DF0 /* SmartReplyExampleObjC.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t5F5A53781ADE67D500F81DF0 /* SmartReplyExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 5F5A53991ADE67D500F81DF0 /* Build configuration list for PBXNativeTarget \"SmartReplyExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t5F5A53751ADE67D500F81DF0 /* Sources */,\n\t\t\t\t5F5A53761ADE67D500F81DF0 /* Frameworks */,\n\t\t\t\t5F5A53771ADE67D500F81DF0 /* Resources */,\n\t\t\t\t10111604221B796200F5BF7E /* ShellScript */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SmartReplyExample;\n\t\t\tproductName = UserManagementExampleSwift;\n\t\t\tproductReference = 5F5A53791ADE67D500F81DF0 /* SmartReplyExample.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t5F5A53441ADE670C00F81DF0 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0930;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = \"Google Inc.\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t5F5A534B1ADE670C00F81DF0 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.3;\n\t\t\t\t\t\tLastSwiftMigration = 0920;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.Keychain = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tcom.apple.SafariKeychain = {\n\t\t\t\t\t\t\t\tenabled = 0;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t\t5F5A53781ADE67D500F81DF0 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.3;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.Keychain = {\n\t\t\t\t\t\t\t\tenabled = 0;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tcom.apple.SafariKeychain = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 5F5A53471ADE670C00F81DF0 /* Build configuration list for PBXProject \"SmartReplyExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 6.3\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 5F5A53431ADE670C00F81DF0;\n\t\t\tproductRefGroup = 5F5A534D1ADE670C00F81DF0 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t5F5A534B1ADE670C00F81DF0 /* SmartReplyExampleObjC */,\n\t\t\t\t5F5A53781ADE67D500F81DF0 /* SmartReplyExample */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t1036DA092087CA25003253C9 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t1036DA172087CA66003253C9 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5F5A534A1ADE670C00F81DF0 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t40B95AC224616FAD007AED02 /* LaunchScreen.xib in Resources */,\n\t\t\t\t40B95AC5246179AA007AED02 /* Assets.xcassets in Resources */,\n\t\t\t\t10B054031C6A3C630061077D /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5F5A53771ADE67D500F81DF0 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tEF4857041C752B7700649485 /* Main.storyboard in Resources */,\n\t\t\t\t40B95AC62461821E007AED02 /* Assets.xcassets in Resources */,\n\t\t\t\t40B95AC324616FAD007AED02 /* LaunchScreen.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t10111604221B796200F5BF7E /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"${PODS_ROOT}/SwiftLint/swiftlint\\n\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t1036DA072087CA25003253C9 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t1036DA152087CA66003253C9 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5F5A53481ADE670C00F81DF0 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tEF6DB4D61CDD610200319C08 /* MainViewController.m in Sources */,\n\t\t\t\t1091729C22066E9D0059D03D /* UITextView+Placeholder.m in Sources */,\n\t\t\t\t5F5A53551ADE670C00F81DF0 /* AppDelegate.m in Sources */,\n\t\t\t\t1091729F2206767C0059D03D /* NSDate+Format.m in Sources */,\n\t\t\t\t5F5A53521ADE670C00F81DF0 /* main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5F5A53751ADE67D500F81DF0 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t109172A022067F750059D03D /* UITextViewPlaceholder.swift in Sources */,\n\t\t\t\t109172A122067F7A0059D03D /* DateExtension.swift in Sources */,\n\t\t\t\t5F5A537E1ADE67D500F81DF0 /* AppDelegate.swift in Sources */,\n\t\t\t\tEF6DB4CD1CDD60F700319C08 /* MainViewController.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t10B054011C6A3C630061077D /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t10B054021C6A3C630061077D /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t5F5A536D1ADE670C00F81DF0 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t5F5A536E1ADE670C00F81DF0 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t5F5A53701ADE670C00F81DF0 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/SmartReplyExampleObjC/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.sampleapp.smartreply;\n\t\t\t\tPRODUCT_NAME = SmartReplyExampleObjC;\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t5F5A53711ADE670C00F81DF0 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/SmartReplyExampleObjC/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.SmartReplyExampleObjC;\n\t\t\t\tPRODUCT_NAME = SmartReplyExampleObjC;\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 3.0;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t5F5A53951ADE67D500F81DF0 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/SmartReplyExampleObjC/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\t\"OTHER_SWIFT_FLAGS[arch=*]\" = \"-D COCOAPODS\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.SmartReplyExampleObjC;\n\t\t\t\tPRODUCT_NAME = SmartReplyExample;\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t5F5A53961ADE67D500F81DF0 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/SmartReplyExampleObjC/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\t\"OTHER_SWIFT_FLAGS[arch=*]\" = \"-D COCOAPODS\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.SmartReplyExampleObjC;\n\t\t\t\tPRODUCT_NAME = SmartReplyExample;\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t5F5A53471ADE670C00F81DF0 /* Build configuration list for PBXProject \"SmartReplyExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t5F5A536D1ADE670C00F81DF0 /* Debug */,\n\t\t\t\t5F5A536E1ADE670C00F81DF0 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t5F5A536F1ADE670C00F81DF0 /* Build configuration list for PBXNativeTarget \"SmartReplyExampleObjC\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t5F5A53701ADE670C00F81DF0 /* Debug */,\n\t\t\t\t5F5A53711ADE670C00F81DF0 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t5F5A53991ADE67D500F81DF0 /* Build configuration list for PBXNativeTarget \"SmartReplyExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t5F5A53951ADE67D500F81DF0 /* Debug */,\n\t\t\t\t5F5A53961ADE67D500F81DF0 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 5F5A53441ADE670C00F81DF0 /* Project object */;\n}\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/AppDelegate.h",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property(nonatomic, strong) UIWindow *window;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/AppDelegate.m",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"AppDelegate.h\"\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application\n    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n  return YES;\n}\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/Assets.xcassets/LaunchImage.launchimage/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"8.0\",\n      \"subtype\" : \"736h\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"8.0\",\n      \"subtype\" : \"736h\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"8.0\",\n      \"subtype\" : \"667h\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"subtype\" : \"retina4\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"extent\" : \"full-screen\",\n      \"subtype\" : \"retina4\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/Assets.xcassets/ic_account_circle_36pt.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_account_circle_36pt.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_account_circle_36pt_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_account_circle_36pt_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/Assets.xcassets/ic_more_vert_white.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_more_vert_white.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_more_vert_white_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_more_vert_white_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/Assets.xcassets/ic_send.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_send.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_send_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_send_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14460.31\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"Tjv-AT-FJM\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14460.20\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Navigation Controller-->\n        <scene sceneID=\"2p8-Fw-pMr\">\n            <objects>\n                <navigationController id=\"Tjv-AT-FJM\" sceneMemberID=\"viewController\">\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" id=\"o3e-Ch-GOB\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"20\" width=\"375\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <color key=\"barTintColor\" red=\"0.01176470588\" green=\"0.60784313729999995\" blue=\"0.8980392157\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <textAttributes key=\"titleTextAttributes\">\n                            <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        </textAttributes>\n                        <textAttributes key=\"largeTitleTextAttributes\">\n                            <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"0.0\"/>\n                        </textAttributes>\n                    </navigationBar>\n                    <connections>\n                        <segue destination=\"N42-xk-ULx\" kind=\"relationship\" relationship=\"rootViewController\" id=\"Mbp-lQ-nMH\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"yGI-yy-bTd\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"476\" y=\"-1541\"/>\n        </scene>\n        <!--ML Kit Smart Reply-->\n        <scene sceneID=\"aF9-42-xn7\">\n            <objects>\n                <collectionViewController id=\"N42-xk-ULx\" customClass=\"MainViewController\" sceneMemberID=\"viewController\">\n                    <collectionView key=\"view\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" id=\"dGk-f3-io8\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        <collectionViewFlowLayout key=\"collectionViewLayout\" minimumLineSpacing=\"0.0\" minimumInteritemSpacing=\"0.0\" id=\"nhC-Fh-pBJ\">\n                            <size key=\"itemSize\" width=\"281\" height=\"55\"/>\n                            <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                            <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                            <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"88\"/>\n                        </collectionViewFlowLayout>\n                        <cells/>\n                        <connections>\n                            <outlet property=\"dataSource\" destination=\"N42-xk-ULx\" id=\"Ucy-Ov-ZP6\"/>\n                            <outlet property=\"delegate\" destination=\"N42-xk-ULx\" id=\"w5n-81-Ccm\"/>\n                        </connections>\n                    </collectionView>\n                    <navigationItem key=\"navigationItem\" title=\"ML Kit Smart Reply\" id=\"gMd-wJ-N4F\">\n                        <barButtonItem key=\"leftBarButtonItem\" title=\"SWITCH\" id=\"x9v-rC-HaP\">\n                            <color key=\"tintColor\" red=\"0.99942404029999998\" green=\"0.98555368190000003\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                            <connections>\n                                <action selector=\"switchUser:\" destination=\"N42-xk-ULx\" id=\"Oz2-Ho-enL\"/>\n                            </connections>\n                        </barButtonItem>\n                        <barButtonItem key=\"rightBarButtonItem\" title=\"more\" image=\"ic_more_vert_white\" id=\"QIP-vr-CNA\">\n                            <connections>\n                                <action selector=\"didTapMore:\" destination=\"N42-xk-ULx\" id=\"Gk8-HG-dg9\"/>\n                            </connections>\n                        </barButtonItem>\n                    </navigationItem>\n                </collectionViewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"acA-xV-gBv\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"1212\" y=\"-1541.3793103448277\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"ic_more_vert_white\" width=\"48\" height=\"48\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIcons</key>\n\t<dict/>\n\t<key>CFBundleIcons~ipad</key>\n\t<dict/>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/LaunchScreen.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"14109\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14088\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"480\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"Logo\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0ia-61-qSP\">\n                    <rect key=\"frame\" x=\"70\" y=\"69\" width=\"341\" height=\"341\"/>\n                </imageView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"0ia-61-qSP\" firstAttribute=\"centerY\" secondItem=\"iN0-l3-epB\" secondAttribute=\"centerY\" id=\"CWF-TQ-nYT\"/>\n                <constraint firstItem=\"0ia-61-qSP\" firstAttribute=\"centerX\" secondItem=\"iN0-l3-epB\" secondAttribute=\"centerX\" id=\"rb3-GK-Eaf\"/>\n            </constraints>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"404\" y=\"445\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"Logo\" width=\"341\" height=\"341\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/MainViewController.h",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface MainViewController : UICollectionViewController <UITextViewDelegate>\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/MainViewController.m",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"MainViewController.h\"\n#import \"NSDate+Format.h\"\n#import \"UITextView+Placeholder.h\"\n\n@import MLKit;\n@import MaterialComponents;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface UIView (Constraints)\n- (void)addConstraintsWithFormat:(NSString *)format views:(NSArray<UIView *> *)views;\n@end\n\n@implementation UIView (Constraints)\n- (void)addConstraintsWithFormat:(NSString *)format views:(NSArray<UIView *> *)views {\n  NSMutableDictionary *viewsDictionary = [[NSMutableDictionary alloc] initWithCapacity:views.count];\n  for (int i = 0; i < views.count; i++) {\n    UIView *view = views[i];\n    NSString *key = [NSString stringWithFormat:@\"v%d\", i];\n    view.translatesAutoresizingMaskIntoConstraints = false;\n    viewsDictionary[key] = view;\n  }\n  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:format\n                                                               options:0\n                                                               metrics:nil\n                                                                 views:viewsDictionary]];\n}\n@end\n\n@interface MainViewController ()\n@property(strong, nonatomic) NSMutableArray<MLKTextMessage *> *messages;\n@property(nonatomic) BOOL isLocalUser;\n@property(strong, nonatomic) NSLayoutConstraint *bottomConstraint;\n@property(strong, nonatomic) NSLayoutConstraint *heightConstraint;\n@property(strong, nonatomic) NSLayoutConstraint *inputBottomConstraint;\n@property(strong, nonatomic) NSLayoutConstraint *sendBottomConstraint;\n@property(nonatomic) BOOL isKeyboardShown;\n@property(strong, nonatomic) UIView *messageInputContainerView;\n\n@property(strong, nonatomic) MLKSmartReply *smartReply;\n\n@property(nonatomic) CGFloat bottomAreaInset;\n\n@property(strong, nonatomic) UITextView *inputTextView;\n@property(strong, nonatomic) UIStackView *smartReplyView;\n@property(strong, nonatomic) UILabel *updatedLabel;\n@property(strong, nonatomic) MDCFloatingButton *sendButton;\n@property(nonatomic, strong) UIAlertController *moreAlert;\n@end\n\n@implementation MainViewController\n\n- (UIAlertController *)moreAlert {\n  if (_moreAlert == nil) {\n    _moreAlert = [UIAlertController alertControllerWithTitle:nil\n                                                     message:nil\n                                              preferredStyle:UIAlertControllerStyleActionSheet];\n    [_moreAlert addAction:[UIAlertAction actionWithTitle:@\"Generate basic history\"\n                                                   style:UIAlertActionStyleDefault\n                                                 handler:^(UIAlertAction *action) {\n                                                   [self generateChatHistoryBasic];\n                                                 }]];\n    [_moreAlert addAction:[UIAlertAction actionWithTitle:@\"Generate history with sensitive content\"\n                                                   style:UIAlertActionStyleDefault\n                                                 handler:^(UIAlertAction *action) {\n                                                   [self generateChatHistoryWithSensitiveContent];\n                                                 }]];\n    [_moreAlert addAction:[UIAlertAction\n                              actionWithTitle:@\"Clear chat history\"\n                                        style:UIAlertActionStyleDestructive\n                                      handler:^(UIAlertAction *action) {\n                                        self.messages = [NSMutableArray new];\n                                        [self updateReplies];\n                                        [self.collectionView reloadData];\n                                        [self.collectionView.collectionViewLayout invalidateLayout];\n                                      }]];\n    [_moreAlert addAction:[UIAlertAction actionWithTitle:@\"Cancel\"\n                                                   style:UIAlertActionStyleCancel\n                                                 handler:nil]];\n  }\n  return _moreAlert;\n}\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  self.messages = [NSMutableArray new];\n  self.isLocalUser = YES;\n  self.messageInputContainerView = [UIView new];\n  if (@available(iOS 13.0, *)) {\n    // Support dark mode\n    _messageInputContainerView.backgroundColor = UIColor.systemBackgroundColor;\n  } else {\n    _messageInputContainerView.backgroundColor = UIColor.whiteColor;\n  }\n  self.smartReply = [MLKSmartReply smartReply];\n  self.bottomAreaInset = 0;\n  self.inputTextView = [[UITextView alloc] initWithPlaceholder:@\"Write a message\"];\n  _inputTextView.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCallout];\n  _inputTextView.scrollEnabled = NO;\n  _inputTextView.accessibilityIdentifier = @\"Input Box\";\n  self.smartReplyView = [UIStackView new];\n  _smartReplyView.distribution = UIStackViewDistributionEqualSpacing;\n\n  for (int i = 0; i < 3; i++) {\n    MDCChipView *chipView = [MDCChipView new];\n    chipView.hidden = YES;\n    [chipView setTitleColor:UIColor.redColor forState:UIControlStateSelected];\n    NSLayoutConstraint *widthConstraint = [chipView.widthAnchor constraintEqualToConstant:0];\n    widthConstraint.identifier = @\"width\";\n    widthConstraint.active = YES;\n    [chipView addTarget:self\n                  action:@selector(replySelected:)\n        forControlEvents:UIControlEventTouchUpInside];\n    [_smartReplyView addArrangedSubview:chipView];\n  }\n\n  self.sendButton = [[MDCFloatingButton alloc] initWithFrame:CGRectNull\n                                                       shape:MDCFloatingButtonShapeMini];\n  [_sendButton setImage:[UIImage imageNamed:@\"ic_send\"] forState:UIControlStateNormal];\n  _sendButton.tintColor = UIColor.blueColor;\n  _sendButton.backgroundColor = UIColor.whiteColor;\n  _sendButton.accessibilityLabel = @\"Send\";\n  _sendButton.enabled = NO;\n  [_sendButton addTarget:self\n                  action:@selector(enterPressed)\n        forControlEvents:UIControlEventTouchUpInside];\n\n  [self updateNavigationBarWithColor:UIColor.blueColor];\n  [self.collectionView registerClass:MDCSelfSizingStereoCell.class\n          forCellWithReuseIdentifier:@\"cell\"];\n  if (@available(iOS 11, *)) {\n    _bottomAreaInset = UIApplication.sharedApplication.keyWindow.safeAreaInsets.bottom;\n  }\n  self.isKeyboardShown = NO;\n\n  _inputTextView.delegate = self;\n  [NSNotificationCenter.defaultCenter addObserver:self\n                                         selector:@selector(handleKeyboardNotification:)\n                                             name:UIKeyboardWillShowNotification\n                                           object:nil];\n  [NSNotificationCenter.defaultCenter addObserver:self\n                                         selector:@selector(handleKeyboardNotification:)\n                                             name:UIKeyboardWillHideNotification\n                                           object:nil];\n  ((UICollectionViewFlowLayout *)self.collectionViewLayout).estimatedItemSize =\n      CGSizeMake(self.collectionView.bounds.size.width, 52);\n  [self.view addSubview:_messageInputContainerView];\n  [self.view addConstraintsWithFormat:@\"H:|[v0]|\" views:@[ _messageInputContainerView ]];\n  self.heightConstraint =\n      [_messageInputContainerView.heightAnchor constraintEqualToConstant:88 + _bottomAreaInset];\n  self.bottomConstraint = [NSLayoutConstraint constraintWithItem:_messageInputContainerView\n                                                       attribute:NSLayoutAttributeBottom\n                                                       relatedBy:NSLayoutRelationEqual\n                                                          toItem:self.view\n                                                       attribute:NSLayoutAttributeBottom\n                                                      multiplier:1\n                                                        constant:0];\n  [self.view addConstraint:_bottomConstraint];\n  [self.view addConstraint:_heightConstraint];\n  [self setupInputComponents];\n}\n\n- (void)updateNavigationBarWithColor:(UIColor *)color {\n  if (@available(iOS 13.0, *)) {\n    // In iOS 15, `scrollEdgeAppearance` applies to all navigtion bars. If the value of\n    // `scrollEdgeAppearance` is `nil`, UIKit uses the setting in `standardAppearance` and\n    // modify it to use a transparent background. To avoid this, we have the `UINavigationBar`\n    // use the same appearance for both standard and edge states.\n    self.navigationController.navigationBar.standardAppearance.backgroundColor = color;\n    self.navigationController.navigationBar.standardAppearance.titleTextAttributes =\n        @{NSForegroundColorAttributeName : [UIColor whiteColor]};\n    self.navigationController.navigationBar.scrollEdgeAppearance =\n        self.navigationController.navigationBar.standardAppearance;\n\n  } else {\n    self.navigationController.navigationBar.barTintColor = color;\n  }\n}\n\n- (void)setupInputComponents {\n  UIView *topBorderView = [UIView new];\n  topBorderView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.5];\n  [_messageInputContainerView addSubview:_inputTextView];\n  [_messageInputContainerView addSubview:_sendButton];\n  [_messageInputContainerView addSubview:topBorderView];\n  [_messageInputContainerView addSubview:_smartReplyView];\n\n  [_messageInputContainerView addConstraintsWithFormat:@\"H:|-8-[v0][v1(40)]-16-|\"\n                                                 views:@[ _inputTextView, _sendButton ]];\n  [_messageInputContainerView addConstraintsWithFormat:@\"H:|[v0]|\" views:@[ topBorderView ]];\n  [_messageInputContainerView addConstraintsWithFormat:@\"H:|-16-[v0]-16-|\"\n                                                 views:@[ _smartReplyView ]];\n\n  [_smartReplyView.topAnchor constraintEqualToAnchor:_messageInputContainerView.topAnchor\n                                            constant:6]\n      .active = YES;\n  [_smartReplyView.bottomAnchor constraintEqualToAnchor:_inputTextView.topAnchor constant:-6]\n      .active = YES;\n\n  self.inputBottomConstraint =\n      [_messageInputContainerView.bottomAnchor constraintEqualToAnchor:_inputTextView.bottomAnchor\n                                                              constant:_bottomAreaInset];\n  _inputBottomConstraint.active = YES;\n\n  self.sendBottomConstraint =\n      [_messageInputContainerView.bottomAnchor constraintEqualToAnchor:_sendButton.bottomAnchor\n                                                              constant:_bottomAreaInset + 6];\n  _sendBottomConstraint.active = YES;\n\n  [_messageInputContainerView addConstraintsWithFormat:@\"V:|[v0(0.5)]\" views:@[ topBorderView ]];\n}\n\n- (void)viewWillAppear:(BOOL)animated {\n  [super viewWillAppear:animated];\n  [_inputTextView becomeFirstResponder];\n}\n\n- (void)viewWillDisappear:(BOOL)animated {\n  [_inputTextView endEditing:YES];\n  [super viewWillDisappear:animated];\n}\n\n- (void)viewDidLayoutSubviews {\n  [super viewDidLayoutSubviews];\n  [_inputTextView resizePlaceholder];\n}\n\n- (void)enterPressed {\n  NSString *text = _inputTextView.text;\n  if (text.length > 0) {\n    MLKTextMessage *message =\n        [[MLKTextMessage alloc] initWithText:text\n                                   timestamp:[NSDate date].timeIntervalSince1970\n                                      userID:@\"\"\n                                 isLocalUser:_isLocalUser];\n    [_messages addObject:message];\n    [self.collectionView\n        insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:_messages.count - 1\n                                                       inSection:0] ]];\n    _inputTextView.text = nil;\n    [_inputTextView textViewDidChange:_inputTextView];\n    [self clearChips];\n  }\n  [_inputTextView endEditing:YES];\n}\n\n- (IBAction)didTapMore:(UIBarButtonItem *)sender {\n  self.moreAlert.popoverPresentationController.barButtonItem = sender;\n  [self presentViewController:self.moreAlert animated:YES completion:nil];\n}\n\n- (void)clearChips {\n  for (UIView *view in self.smartReplyView.arrangedSubviews) {\n    view.hidden = YES;\n  }\n}\n\n- (void)updateReplies {\n  // SmartReply for users' own messages is a non-use-case.\n  MLKTextMessage *lastMessage = _messages.lastObject;\n  if (lastMessage == nil || lastMessage.isLocalUser == _isLocalUser) {\n    [self clearChips];\n    return;\n  }\n\n  NSMutableArray<MLKTextMessage *> *chat = _messages;\n\n  // Revert isLocalUser field in text messages to simulate the remote user for the sample.\n  if (!_isLocalUser) {\n    chat = [[NSMutableArray alloc] initWithCapacity:10];\n    for (int i = (_messages.count <= 10 ? 0 : _messages.count - 10); i < _messages.count; i++) {\n      MLKTextMessage *textMessage = _messages[i];\n      textMessage = [[MLKTextMessage alloc] initWithText:textMessage.text\n                                               timestamp:textMessage.timestamp\n                                                  userID:textMessage.userID\n                                             isLocalUser:!textMessage.isLocalUser];\n      [chat addObject:textMessage];\n    }\n  }\n\n  [_smartReply\n      suggestRepliesForMessages:chat\n                     completion:^(MLKSmartReplySuggestionResult *_Nullable result,\n                                  NSError *_Nullable error) {\n                       if (error != nil || result == nil || result.suggestions.count == 0) {\n                         [self clearChips];\n                         return;\n                       }\n                       for (int i = 0; i < 3; i++) {\n                         MDCChipView *chip = self.smartReplyView.arrangedSubviews[i];\n                         chip.titleLabel.text = result.suggestions[i].text;\n                         chip.accessibilityIdentifier = @\"Smart Reply Suggestion\";\n                         [chip sizeToFit];\n                         chip.hidden = NO;\n                         for (NSLayoutConstraint *constraint in chip.constraints) {\n                           if ([constraint.identifier isEqualToString:@\"width\"]) {\n                             constraint.constant = chip.bounds.size.width;\n                             break;\n                           }\n                         }\n                       }\n                     }];\n}\n\n- (void)handleKeyboardNotification:(NSNotification *)notification {\n  CGRect keyboardSize =\n      ((NSValue *)notification.userInfo[UIKeyboardFrameEndUserInfoKey]).CGRectValue;\n  BOOL isKeyboardShowing = notification.name == UIKeyboardWillShowNotification;\n  if (_isKeyboardShown == isKeyboardShowing) {\n    _bottomConstraint.constant = isKeyboardShowing ? -keyboardSize.size.height : 0;\n    if (self.messages.count > 0) {\n      NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.messages.count - 1 inSection:0];\n      [self.collectionView scrollToItemAtIndexPath:indexPath\n                                  atScrollPosition:UICollectionViewScrollPositionTop\n                                          animated:YES];\n    }\n    return;\n  }\n  _isKeyboardShown = isKeyboardShowing;\n  _bottomConstraint.constant = isKeyboardShowing ? -keyboardSize.size.height : 0;\n  double inset = isKeyboardShowing ? -_bottomAreaInset : _bottomAreaInset;\n  _heightConstraint.constant += inset;\n  _inputBottomConstraint.constant = isKeyboardShowing ? 0 : _bottomAreaInset;\n  _sendBottomConstraint.constant = isKeyboardShowing ? 6 : (6 + _bottomAreaInset);\n  NSTimeInterval animationDuration =\n      ((NSNumber *)notification.userInfo[UIKeyboardAnimationDurationUserInfoKey]).doubleValue;\n  [UIView animateWithDuration:animationDuration\n      delay:0\n      options:UIViewAnimationOptionCurveEaseOut\n      animations:^{\n        [self.view layoutIfNeeded];\n      }\n      completion:^(BOOL finished) {\n        if (self.messages.count > 0) {\n          NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.messages.count - 1\n                                                       inSection:0];\n          [self.collectionView scrollToItemAtIndexPath:indexPath\n                                      atScrollPosition:UICollectionViewScrollPositionTop\n                                              animated:YES];\n        }\n      }];\n}\n\n- (void)textViewDidBeginEditing:(UITextView *)textView {\n  [self textViewDidChange:textView];\n}\n\n- (void)collectionView:(UICollectionView *)collectionView\n    didSelectItemAtIndexPath:(NSIndexPath *)indexPath {\n  [_inputTextView endEditing:YES];\n}\n\n- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView\n                  cellForItemAtIndexPath:(NSIndexPath *)indexPath {\n  MDCSelfSizingStereoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@\"cell\"\n                                                                            forIndexPath:indexPath];\n  MLKTextMessage *item = _messages[indexPath.item];\n  cell.leadingImageView.image = [UIImage imageNamed:@\"ic_account_circle_36pt\"];\n  cell.leadingImageView.tintColor = item.isLocalUser ? UIColor.blueColor : UIColor.redColor;\n  cell.titleLabel.text = item.text;\n  cell.detailLabel.text = [[NSDate dateWithTimeIntervalSince1970:item.timestamp] timeAgo];\n  if (@available(iOS 13.0, *)) {\n    // Support dark mode\n    cell.titleLabel.textColor = UIColor.labelColor;\n    cell.detailLabel.textColor = UIColor.labelColor;\n  }\n  return cell;\n}\n\n- (void)replySelected:(MDCChipView *)reply {\n  [_inputTextView insertText:reply.titleLabel.text];\n}\n\n- (IBAction)switchUser:(id)sender {\n  self.isLocalUser = !_isLocalUser;\n  UIColor *color = _isLocalUser ? UIColor.blueColor : UIColor.redColor;\n  _sendButton.tintColor = color;\n  [self updateNavigationBarWithColor:color];\n  [self updateReplies];\n}\n\n- (void)generateChatHistoryBasic {\n  NSDate *date = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitDay\n                                                        value:-1\n                                                       toDate:[NSDate date]\n                                                      options:0];\n  NSTimeInterval dateAfter = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitMinute\n                                                                    value:10\n                                                                   toDate:date\n                                                                  options:0]\n                                 .timeIntervalSince1970;\n  _messages =\n      @[\n        [[MLKTextMessage alloc] initWithText:@\"Hello\"\n                                   timestamp:date.timeIntervalSince1970\n                                      userID:@\"\"\n                                 isLocalUser:YES],\n        [[MLKTextMessage alloc] initWithText:@\"Hey\" timestamp:dateAfter userID:@\"\" isLocalUser:NO]\n      ]\n          .mutableCopy;\n  [self updateReplies];\n  [self.collectionView reloadData];\n  [self.collectionView.collectionViewLayout invalidateLayout];\n}\n\n- (void)generateChatHistoryWithSensitiveContent {\n  NSDate *date = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitDay\n                                                        value:-1\n                                                       toDate:[NSDate date]\n                                                      options:0];\n  NSTimeInterval dateAfter = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitMinute\n                                                                    value:10\n                                                                   toDate:date\n                                                                  options:0]\n                                 .timeIntervalSince1970;\n  NSTimeInterval dateAfterAfter = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitMinute\n                                                                         value:20\n                                                                        toDate:date\n                                                                       options:0]\n                                      .timeIntervalSince1970;\n  _messages =\n      @[\n        [[MLKTextMessage alloc] initWithText:@\"Hi\"\n                                   timestamp:date.timeIntervalSince1970\n                                      userID:@\"\"\n                                 isLocalUser:NO],\n        [[MLKTextMessage alloc] initWithText:@\"How are you?\"\n                                   timestamp:dateAfter\n                                      userID:@\"\"\n                                 isLocalUser:YES],\n        [[MLKTextMessage alloc] initWithText:@\"My cat died\"\n                                   timestamp:dateAfterAfter\n                                      userID:@\"\"\n                                 isLocalUser:NO]\n      ]\n          .mutableCopy;\n  [self updateReplies];\n  [self.collectionView reloadData];\n  [self.collectionView.collectionViewLayout invalidateLayout];\n}\n\n- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {\n  return 1;\n}\n\n- (void)textViewDidEndEditing:(UITextView *)textView {\n  _sendButton.enabled = NO;\n  _heightConstraint.constant = 88 + _bottomAreaInset;\n}\n\n- (void)textViewDidChange:(UITextView *)textView {\n  _sendButton.enabled = textView.text.length != 0;\n  CGSize size = CGSizeMake(self.view.frame.size.width - 60, INFINITY);\n  CGSize estimatedSize = [textView sizeThatFits:size];\n  _heightConstraint.constant =\n      estimatedSize.height + 54 + (self.isKeyboardShown ? 0 : _bottomAreaInset);\n}\n\n- (NSInteger)collectionView:(UICollectionView *)collectionView\n     numberOfItemsInSection:(NSInteger)section {\n  return _messages.count;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/NSDate+Format.h",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface NSDate (Format)\n- (NSString *)timeAgo;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/NSDate+Format.m",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"NSDate+Format.h\"\n\n@implementation NSDate (Format)\n- (NSString *)timeAgo {\n  NSCalendarUnit components = NSCalendarUnitYear | NSCalendarUnitDay | NSCalendarUnitHour |\n                              NSCalendarUnitMinute | NSCalendarUnitSecond;\n  NSDateComponents *interval = [NSCalendar.currentCalendar components:components\n                                                             fromDate:self\n                                                               toDate:[NSDate new]\n                                                              options:0];\n\n  if (interval.year > 0) {\n    return [NSDateFormatter localizedStringFromDate:self\n                                          dateStyle:NSDateFormatterLongStyle\n                                          timeStyle:NSDateFormatterNoStyle];\n  } else if (interval.day > 6) {\n    NSString *format = [NSDateFormatter dateFormatFromTemplate:@\"MMMMd\"\n                                                       options:0\n                                                        locale:NSLocale.currentLocale];\n    NSDateFormatter *formatter = [NSDateFormatter new];\n    formatter.dateFormat = format;\n    return [formatter stringFromDate:self];\n  } else if (interval.day > 0) {\n    NSString *format = interval.day == 1 ? @\"%d day ago\" : @\"%d days ago\";\n    return [NSString stringWithFormat:format, interval.day];\n  } else if (interval.hour > 0) {\n    NSString *format = interval.hour == 1 ? @\"%d hour ago\" : @\"%d hours ago\";\n    return [NSString stringWithFormat:format, interval.hour];\n  } else if (interval.minute > 0) {\n    NSString *format = interval.minute == 1 ? @\"%d minute ago\" : @\"%d minutes ago\";\n    return [NSString stringWithFormat:format, interval.minute];\n  } else if (interval.second > 0) {\n    NSString *format = interval.second == 1 ? @\"%d second ago\" : @\"%d seconds ago\";\n    return [NSString stringWithFormat:format, interval.second];\n  } else {\n    return @\"just now\";\n  }\n}\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/UITextView+Placeholder.h",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface UITextView (Placeholder)\n- (instancetype)initWithPlaceholder:(NSString *)placeholder;\n- (void)textViewDidChange:(UITextView *)textView;\n- (void)resizePlaceholder;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/UITextView+Placeholder.m",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"UITextView+Placeholder.h\"\n\n/// Extend UITextView and implemented UITextViewDelegate to listen for changes\n@implementation UITextView (Placeholder)\n- (instancetype)initWithPlaceholder:(NSString *)placeholder {\n  self = [self init];\n  if (self) {\n    self.placeholder = placeholder;\n    [NSNotificationCenter.defaultCenter addObserver:self\n                                           selector:@selector(textViewDidChange:)\n                                               name:UITextViewTextDidChangeNotification\n                                             object:nil];\n  }\n  return self;\n}\n\n/// Resize the placeholder when the UITextView bounds change\n- (void)setBounds:(CGRect)bounds {\n  [super setBounds:bounds];\n  [self resizePlaceholder];\n}\n\n- (void)setPlaceholder:(NSString *)placeholder {\n  UILabel *placeholderLabel = [self viewWithTag:100];\n  if (placeholderLabel == nil) {\n    [self addPlaceholder:placeholder];\n  } else {\n    placeholderLabel.text = placeholder;\n    [placeholderLabel sizeToFit];\n  }\n}\n\n- (nullable NSString *)getPlaceholder {\n  UILabel *placeholderLabel = [self viewWithTag:100];\n  if (placeholderLabel == nil) {\n    return nil;\n  }\n  return placeholderLabel.text;\n}\n\n/// When the UITextView did change, show or hide the label based on if the UITextView is empty or\n/// not\n///\n/// - Parameter textView: The UITextView that got updated\n- (void)textViewDidChange:(UITextView *)textView {\n  UILabel *placeholderLabel = [self viewWithTag:100];\n  placeholderLabel.hidden = self.text.length != 0;\n}\n\n/// Resize the placeholder UILabel to make sure it's in the same position as the UITextView text\n- (void)resizePlaceholder {\n  UILabel *placeholderLabel = [self viewWithTag:100];\n  CGFloat labelX = self.textContainer.lineFragmentPadding;\n  CGFloat labelY = self.textContainerInset.top - 2;\n  CGFloat labelWidth = self.frame.size.width - (labelX * 2);\n  CGFloat labelHeight = placeholderLabel.frame.size.height;\n\n  placeholderLabel.frame = CGRectMake(labelX, labelY, labelWidth, labelHeight);\n}\n\n/// Adds a placeholder UILabel to this UITextView\n- (void)addPlaceholder:(NSString *)placeholderText {\n  UILabel *placeholderLabel = [UILabel new];\n\n  placeholderLabel.text = placeholderText;\n  [placeholderLabel sizeToFit];\n\n  placeholderLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCallout];\n  placeholderLabel.textColor = UIColor.lightGrayColor;\n  placeholderLabel.tag = 100;\n\n  placeholderLabel.hidden = self.text.length != 0;\n\n  [self addSubview:placeholderLabel];\n  [self resizePlaceholder];\n}\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/smartreply/SmartReplyExampleObjC/main.m",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char* argv[]) {\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/translate/Podfile",
    "content": "use_frameworks!\n\nplatform :ios, '15.5'\n\nproject 'TranslateExample.xcodeproj'\n\npod 'GoogleMLKit/Translate', '9.0.0'\n\ntarget 'TranslateExample' do\nend\n\ntarget 'TranslateExampleObjC' do\nend\n\npost_install do |installer|\n  installer.aggregate_targets.each do |target|\n    target.xcconfigs.each do |variant, xcconfig|\n      xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)\n      IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n    end\n  end\n  installer.generated_projects.each do |project|\n    project.targets.each do |target|\n        target.build_configurations.each do |config|\n            config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'\n            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'\n         end\n    end\n  end\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference\n        xcconfig_path = config.base_configuration_reference.real_path\n        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n      end\n    end\n  end\nend"
  },
  {
    "path": "ios/quickstarts/translate/README.md",
    "content": "# ML Kit Translate Quickstart Sample App\n\n* [Read more about ML Kit Translate](https://developers.google.com/ml-kit/language/translation)\n\n## Introduction\n\nThe ML Kit Translate iOS Quickstart app demonstrates how to use the Translate\nfeature of ML Kit to translate text in your application.\n\n## Feature List\n\nFeatures that are included in this demo app:\n\n* [Translate](https://developers.google.com/ml-kit/language/translation/ios) - Translate Text with ML Kit on iOS\n\n<img src=\"../../screenshots/translate.jpg\" width=\"256\"/>\n\n## Getting Started\n\n* Run the sample on your iOS device or simulator.\n* Type input text and change languages to see translation in action.\n\n## Support\n\n- [Stack Overflow](https://stackoverflow.com/questions/tagged/google-mlkit)\n\nLicense\n-------\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample/AppDelegate.swift",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n  var window: UIWindow?\n\n  func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    return true\n  }\n}\n\n#if !swift(>=4.2)\n  extension UIApplication {\n    typealias LaunchOptionsKey = UIApplicationLaunchOptionsKey\n  }\n#endif  // !swift(>=4.2)\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample/Assets.xcassets/baseline_swap_horiz_black_48pt.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_swap_horiz_black_48pt_1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_swap_horiz_black_48pt_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_swap_horiz_black_48pt_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14113\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14088\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" distribution=\"fillEqually\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tJl-Ki-q2A\" userLabel=\"Pickers and switcher\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"262\" width=\"375\" height=\"120\"/>\n                                <subviews>\n                                    <pickerView contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"deb-nW-4ea\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"125\" height=\"120\"/>\n                                    </pickerView>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qgM-C6-S7q\">\n                                        <rect key=\"frame\" x=\"125\" y=\"0.0\" width=\"125\" height=\"120\"/>\n                                        <state key=\"normal\" image=\"baseline_swap_horiz_black_48pt\">\n                                            <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        </state>\n                                        <connections>\n                                            <action selector=\"didTapSwap\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"afb-rl-YFK\"/>\n                                        </connections>\n                                    </button>\n                                    <pickerView contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Lxi-1Q-WcD\">\n                                        <rect key=\"frame\" x=\"250\" y=\"0.0\" width=\"125\" height=\"120\"/>\n                                    </pickerView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"120\" id=\"gL3-u3-tQp\"/>\n                                </constraints>\n                            </stackView>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" distribution=\"equalSpacing\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rZB-Li-zoY\" userLabel=\"Management buttons\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"382\" width=\"375\" height=\"30\"/>\n                                <subviews>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CnX-ZD-9E6\" userLabel=\"DL/Delete source\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"69\" height=\"30\"/>\n                                        <state key=\"normal\" title=\"DL/Delete\"/>\n                                        <connections>\n                                            <action selector=\"didTapDownloadDeleteSourceLanguage\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"jcY-e2-GZP\"/>\n                                        </connections>\n                                    </button>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9jF-qT-v3L\" userLabel=\"List available\">\n                                        <rect key=\"frame\" x=\"131\" y=\"0.0\" width=\"113\" height=\"30\"/>\n                                        <state key=\"normal\" title=\"List downloaded\"/>\n                                        <connections>\n                                            <action selector=\"listDownloadedModels\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"1Up-US-OQS\"/>\n                                        </connections>\n                                    </button>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5Iq-V8-hQM\" userLabel=\"DL/Delete target\">\n                                        <rect key=\"frame\" x=\"306\" y=\"0.0\" width=\"69\" height=\"30\"/>\n                                        <state key=\"normal\" title=\"DL/Delete\"/>\n                                        <connections>\n                                            <action selector=\"didTapDownloadDeleteTargetLanguage\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"qcq-Dy-vlN\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"30\" id=\"bGq-ts-jLa\"/>\n                                </constraints>\n                            </stackView>\n                            <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" editable=\"NO\" textAlignment=\"natural\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dxc-dV-fix\" userLabel=\"Output Text View\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"412\" width=\"375\" height=\"151\"/>\n                                <color key=\"backgroundColor\" cocoaTouchSystemColor=\"groupTableViewBackgroundColor\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\"/>\n                            </textView>\n                            <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" editable=\"NO\" textAlignment=\"natural\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SUn-0F-Wz1\" userLabel=\"Status Text View\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"563\" width=\"375\" height=\"60\"/>\n                                <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"60\" id=\"HxJ-ng-LlW\"/>\n                                </constraints>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\"/>\n                            </textView>\n                            <textView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" text=\"Write here\" textAlignment=\"natural\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CU6-Hv-afs\" userLabel=\"Input Text View\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"249\"/>\n                                <color key=\"textColor\" systemColor=\"labelColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\"/>\n                            </textView>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"Dxc-dV-fix\" firstAttribute=\"top\" secondItem=\"rZB-Li-zoY\" secondAttribute=\"bottom\" id=\"0Kz-j5-vap\"/>\n                            <constraint firstItem=\"tJl-Ki-q2A\" firstAttribute=\"leading\" secondItem=\"CU6-Hv-afs\" secondAttribute=\"leading\" id=\"37n-TZ-O2X\"/>\n                            <constraint firstItem=\"CU6-Hv-afs\" firstAttribute=\"top\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"top\" id=\"3sC-yM-U8N\"/>\n                            <constraint firstItem=\"SUn-0F-Wz1\" firstAttribute=\"leading\" secondItem=\"CU6-Hv-afs\" secondAttribute=\"leading\" id=\"7Hb-RI-qal\"/>\n                            <constraint firstItem=\"SUn-0F-Wz1\" firstAttribute=\"bottom\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"bottom\" id=\"AhD-k1-rlD\"/>\n                            <constraint firstItem=\"CU6-Hv-afs\" firstAttribute=\"bottom\" secondItem=\"tJl-Ki-q2A\" secondAttribute=\"top\" id=\"FEF-Xx-aBK\"/>\n                            <constraint firstItem=\"rZB-Li-zoY\" firstAttribute=\"trailing\" secondItem=\"CU6-Hv-afs\" secondAttribute=\"trailing\" id=\"IaO-9E-wG9\"/>\n                            <constraint firstItem=\"rZB-Li-zoY\" firstAttribute=\"leading\" secondItem=\"CU6-Hv-afs\" secondAttribute=\"leading\" id=\"MrB-mq-AW5\"/>\n                            <constraint firstItem=\"SUn-0F-Wz1\" firstAttribute=\"trailing\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"trailing\" id=\"RQG-sU-8ht\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"CU6-Hv-afs\" secondAttribute=\"trailing\" id=\"S2t-RE-SmI\"/>\n                            <constraint firstItem=\"Dxc-dV-fix\" firstAttribute=\"bottom\" secondItem=\"SUn-0F-Wz1\" secondAttribute=\"top\" id=\"Y5y-IM-Aag\"/>\n                            <constraint firstItem=\"Dxc-dV-fix\" firstAttribute=\"trailing\" secondItem=\"CU6-Hv-afs\" secondAttribute=\"trailing\" id=\"cOb-R0-OPW\"/>\n                            <constraint firstItem=\"tJl-Ki-q2A\" firstAttribute=\"trailing\" secondItem=\"CU6-Hv-afs\" secondAttribute=\"trailing\" id=\"ec0-jZ-Msg\"/>\n                            <constraint firstItem=\"tJl-Ki-q2A\" firstAttribute=\"centerY\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"centerY\" id=\"fG4-Ax-iBw\"/>\n                            <constraint firstItem=\"Dxc-dV-fix\" firstAttribute=\"leading\" secondItem=\"CU6-Hv-afs\" secondAttribute=\"leading\" id=\"hLb-K6-tdx\"/>\n                            <constraint firstItem=\"CU6-Hv-afs\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"j8j-kp-xLB\"/>\n                            <constraint firstItem=\"rZB-Li-zoY\" firstAttribute=\"top\" secondItem=\"tJl-Ki-q2A\" secondAttribute=\"bottom\" id=\"ybX-cB-13C\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                    <toolbarItems/>\n                    <simulatedToolbarMetrics key=\"simulatedBottomBarMetrics\"/>\n                    <connections>\n                        <outlet property=\"inputPicker\" destination=\"deb-nW-4ea\" id=\"Nvn-Dx-8FK\"/>\n                        <outlet property=\"inputTextView\" destination=\"CU6-Hv-afs\" id=\"paw-Vb-1sH\"/>\n                        <outlet property=\"outputPicker\" destination=\"Lxi-1Q-WcD\" id=\"NUe-yr-eFx\"/>\n                        <outlet property=\"outputTextView\" destination=\"Dxc-dV-fix\" id=\"aCN-hT-iNc\"/>\n                        <outlet property=\"sourceDownloadDeleteButton\" destination=\"CnX-ZD-9E6\" id=\"ceX-HU-tm9\"/>\n                        <outlet property=\"statusTextView\" destination=\"SUn-0F-Wz1\" id=\"Ksi-uF-pDJ\"/>\n                        <outlet property=\"targetDownloadDeleteButton\" destination=\"5Iq-V8-hQM\" id=\"Iub-Sd-rVu\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53.600000000000001\" y=\"27.436281859070466\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"baseline_swap_horiz_black_48pt\" width=\"96\" height=\"96\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>TranslateExample</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>0.0.1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample/ViewController.swift",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\nimport MLKit\n\n@objc(ViewController)\nclass ViewController: UIViewController, UITextViewDelegate, UIPickerViewDataSource,\n  UIPickerViewDelegate\n{\n\n  @IBOutlet var inputTextView: UITextView!\n  @IBOutlet var outputTextView: UITextView!\n  @IBOutlet var statusTextView: UITextView!\n  @IBOutlet var inputPicker: UIPickerView!\n  @IBOutlet var outputPicker: UIPickerView!\n  @IBOutlet var sourceDownloadDeleteButton: UIButton!\n  @IBOutlet var targetDownloadDeleteButton: UIButton!\n\n  var translator: Translator!\n  let locale = Locale.current\n  lazy var allLanguages = TranslateLanguage.allLanguages().sorted {\n    return locale.localizedString(forLanguageCode: $0.rawValue)!\n      < locale.localizedString(forLanguageCode: $1.rawValue)!\n  }\n\n  override func viewDidLoad() {\n    inputPicker.dataSource = self\n    outputPicker.dataSource = self\n    inputPicker.selectRow(\n      allLanguages.firstIndex(of: TranslateLanguage.english) ?? 0, inComponent: 0, animated: false)\n    outputPicker.selectRow(\n      allLanguages.firstIndex(of: TranslateLanguage.spanish) ?? 0, inComponent: 0, animated: false)\n    inputPicker.delegate = self\n    outputPicker.delegate = self\n    inputTextView.delegate = self\n    inputTextView.accessibilityIdentifier = \"inputTextView\"\n    inputTextView.returnKeyType = .done\n    pickerView(inputPicker, didSelectRow: 0, inComponent: 0)\n    setDownloadDeleteButtonLabels()\n\n    outputTextView.accessibilityIdentifier = \"outputTextView\"\n    sourceDownloadDeleteButton.accessibilityIdentifier = \"InputModelButton\"\n    statusTextView.accessibilityIdentifier = \"statusTextView\"\n\n    NotificationCenter.default.addObserver(\n      self, selector: #selector(remoteModelDownloadDidComplete(notification:)),\n      name: .mlkitModelDownloadDidSucceed, object: nil)\n    NotificationCenter.default.addObserver(\n      self, selector: #selector(remoteModelDownloadDidComplete(notification:)),\n      name: .mlkitModelDownloadDidFail, object: nil)\n  }\n\n  func numberOfComponents(in pickerView: UIPickerView) -> Int {\n    return 1\n  }\n\n  func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int)\n    -> String?\n  {\n    return Locale.current.localizedString(forLanguageCode: allLanguages[row].rawValue)\n  }\n\n  func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {\n    return allLanguages.count\n  }\n\n  func textView(\n    _ textView: UITextView, shouldChangeTextIn range: NSRange,\n    replacementText text: String\n  ) -> Bool {\n    // Hide the keyboard when \"Done\" is pressed.\n    // See: https://stackoverflow.com/questions/26600359/dismiss-keyboard-with-a-uitextview\n    if text == \"\\n\" {\n      textView.resignFirstResponder()\n      return false\n    }\n    return true\n  }\n\n  func textViewDidChange(_ textView: UITextView) {\n    translate()\n  }\n\n  // Make all text selected when the text view is activated for editing, so that the newly\n  // input context will override the existing content.\n  func textViewDidBeginEditing(_ textView: UITextView) {\n    textView.selectedTextRange = textView.textRange(\n      from: textView.beginningOfDocument, to: textView.endOfDocument)\n  }\n\n  @IBAction func didTapSwap() {\n    let inputSelectedRow = inputPicker.selectedRow(inComponent: 0)\n    inputPicker.selectRow(outputPicker.selectedRow(inComponent: 0), inComponent: 0, animated: false)\n    outputPicker.selectRow(inputSelectedRow, inComponent: 0, animated: false)\n    inputTextView.text = outputTextView.text\n    pickerView(inputPicker, didSelectRow: 0, inComponent: 0)\n    self.setDownloadDeleteButtonLabels()\n  }\n\n  func model(forLanguage: TranslateLanguage) -> TranslateRemoteModel {\n    return TranslateRemoteModel.translateRemoteModel(language: forLanguage)\n  }\n\n  func isLanguageDownloaded(_ language: TranslateLanguage) -> Bool {\n    let model = self.model(forLanguage: language)\n    let modelManager = ModelManager.modelManager()\n    return modelManager.isModelDownloaded(model)\n  }\n\n  func handleDownloadDelete(picker: UIPickerView, button: UIButton) {\n    let language = allLanguages[picker.selectedRow(inComponent: 0)]\n    if language == .english {\n      return\n    }\n    button.setTitle(\"working...\", for: .normal)\n    let model = self.model(forLanguage: language)\n    let modelManager = ModelManager.modelManager()\n    let languageName = Locale.current.localizedString(forLanguageCode: language.rawValue)!\n    if modelManager.isModelDownloaded(model) {\n      self.statusTextView.text = \"Deleting \\(languageName)\"\n      modelManager.deleteDownloadedModel(model) { error in\n        self.statusTextView.text = \"Deleted \\(languageName)\"\n        self.setDownloadDeleteButtonLabels()\n      }\n    } else {\n      self.statusTextView.text = \"Downloading \\(languageName)\"\n      let conditions = ModelDownloadConditions(\n        allowsCellularAccess: true,\n        allowsBackgroundDownloading: true\n      )\n      modelManager.download(model, conditions: conditions)\n    }\n  }\n\n  @IBAction func didTapDownloadDeleteSourceLanguage() {\n    self.handleDownloadDelete(picker: inputPicker, button: self.sourceDownloadDeleteButton)\n  }\n\n  @IBAction func didTapDownloadDeleteTargetLanguage() {\n    self.handleDownloadDelete(picker: outputPicker, button: self.targetDownloadDeleteButton)\n  }\n\n  @IBAction func listDownloadedModels() {\n    let msg =\n      \"Downloaded models: \"\n      + ModelManager.modelManager()\n      .downloadedTranslateModels\n      .map { model in Locale.current.localizedString(forLanguageCode: model.language.rawValue)! }\n      .joined(separator: \", \")\n    self.statusTextView.text = msg\n  }\n\n  @objc\n  func remoteModelDownloadDidComplete(notification: NSNotification) {\n    let userInfo = notification.userInfo!\n    guard\n      let remoteModel =\n        userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? TranslateRemoteModel\n    else {\n      return\n    }\n    weak var weakSelf = self\n    DispatchQueue.main.async {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      let languageName = Locale.current.localizedString(\n        forLanguageCode: remoteModel.language.rawValue)!\n      if notification.name == .mlkitModelDownloadDidSucceed {\n        strongSelf.statusTextView.text =\n          \"Download succeeded for \\(languageName)\"\n      } else {\n        strongSelf.statusTextView.text =\n          \"Download failed for \\(languageName)\"\n      }\n      strongSelf.setDownloadDeleteButtonLabels()\n    }\n  }\n\n  func setDownloadDeleteButtonLabels() {\n    let inputLanguage = allLanguages[inputPicker.selectedRow(inComponent: 0)]\n    let outputLanguage = allLanguages[outputPicker.selectedRow(inComponent: 0)]\n    if self.isLanguageDownloaded(inputLanguage) {\n      self.sourceDownloadDeleteButton.setTitle(\"Delete Model\", for: .normal)\n    } else {\n      self.sourceDownloadDeleteButton.setTitle(\"Download Model\", for: .normal)\n    }\n    self.sourceDownloadDeleteButton.isHidden = inputLanguage == .english\n    if self.isLanguageDownloaded(outputLanguage) {\n      self.targetDownloadDeleteButton.setTitle(\"Delete Model\", for: .normal)\n    } else {\n      self.targetDownloadDeleteButton.setTitle(\"Download Model\", for: .normal)\n    }\n    self.targetDownloadDeleteButton.isHidden = outputLanguage == .english\n  }\n\n  func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {\n    let inputLanguage = allLanguages[inputPicker.selectedRow(inComponent: 0)]\n    let outputLanguage = allLanguages[outputPicker.selectedRow(inComponent: 0)]\n    self.setDownloadDeleteButtonLabels()\n    let options = TranslatorOptions(sourceLanguage: inputLanguage, targetLanguage: outputLanguage)\n    translator = Translator.translator(options: options)\n    translate()\n  }\n\n  func translate() {\n    let translatorForDownloading = self.translator!\n\n    translatorForDownloading.downloadModelIfNeeded { error in\n      guard error == nil else {\n        self.outputTextView.text = \"Failed to ensure model downloaded with error \\(error!)\"\n        return\n      }\n      self.setDownloadDeleteButtonLabels()\n      if translatorForDownloading == self.translator {\n        translatorForDownloading.translate(self.inputTextView.text ?? \"\") { result, error in\n          guard error == nil else {\n            self.outputTextView.text = \"Failed with error \\(error!)\"\n            return\n          }\n          if translatorForDownloading == self.translator {\n            self.outputTextView.text = result\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t108489A5224415A1004D37A8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 108489A4224415A1004D37A8 /* AppDelegate.m */; };\n\t\t108489A8224415A1004D37A8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 108489A7224415A1004D37A8 /* ViewController.m */; };\n\t\t108489B3224415A4004D37A8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 108489B2224415A4004D37A8 /* main.m */; };\n\t\t108489F7224531B6004D37A8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDCB22259E3500536A5C /* Assets.xcassets */; };\n\t\t108489F8224531B9004D37A8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDC822259E3400536A5C /* Main.storyboard */; };\n\t\t108489F9224531BF004D37A8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDCD22259E3500536A5C /* LaunchScreen.storyboard */; };\n\t\tC18E1D3722410D0E00B5F51C /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C18E1D3622410D0E00B5F51C /* libc++.tbd */; };\n\t\tC1E8DDC522259E3400536A5C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E8DDC422259E3400536A5C /* AppDelegate.swift */; };\n\t\tC1E8DDC722259E3400536A5C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E8DDC622259E3400536A5C /* ViewController.swift */; };\n\t\tC1E8DDCA22259E3400536A5C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDC822259E3400536A5C /* Main.storyboard */; };\n\t\tC1E8DDCC22259E3500536A5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDCB22259E3500536A5C /* Assets.xcassets */; };\n\t\tC1E8DDCF22259E3500536A5C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1E8DDCD22259E3500536A5C /* LaunchScreen.storyboard */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t108489A1224415A1004D37A8 /* TranslateExampleObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TranslateExampleObjC.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t108489A3224415A1004D37A8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t108489A4224415A1004D37A8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t108489A6224415A1004D37A8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\t108489A7224415A1004D37A8 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\t108489B2224415A4004D37A8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tC18E1D3622410D0E00B5F51C /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = \"libc++.tbd\"; path = \"usr/lib/libc++.tbd\"; sourceTree = SDKROOT; };\n\t\tC1E8DDC122259E3400536A5C /* TranslateExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TranslateExample.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC1E8DDC422259E3400536A5C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tC1E8DDC622259E3400536A5C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tC1E8DDC922259E3400536A5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tC1E8DDCB22259E3500536A5C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tC1E8DDCE22259E3500536A5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tC1E8DDD022259E3500536A5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t1084899E224415A1004D37A8 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1E8DDBE22259E3400536A5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC18E1D3722410D0E00B5F51C /* libc++.tbd in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t108489A2224415A1004D37A8 /* TranslateExampleObjC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t108489A3224415A1004D37A8 /* AppDelegate.h */,\n\t\t\t\t108489A4224415A1004D37A8 /* AppDelegate.m */,\n\t\t\t\t108489A6224415A1004D37A8 /* ViewController.h */,\n\t\t\t\t108489A7224415A1004D37A8 /* ViewController.m */,\n\t\t\t\t108489B2224415A4004D37A8 /* main.m */,\n\t\t\t);\n\t\t\tpath = TranslateExampleObjC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65AC6D81F1B268042A1E4A79 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC18E1D3622410D0E00B5F51C /* libc++.tbd */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1E8DDB822259E3400536A5C = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC1E8DDC322259E3400536A5C /* TranslateExample */,\n\t\t\t\t108489A2224415A1004D37A8 /* TranslateExampleObjC */,\n\t\t\t\tC1E8DDC222259E3400536A5C /* Products */,\n\t\t\t\t65AC6D81F1B268042A1E4A79 /* Frameworks */,\n\t\t\t\tE7C45F3A2FC5CB6A04E2E3FF /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1E8DDC222259E3400536A5C /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC1E8DDC122259E3400536A5C /* TranslateExample.app */,\n\t\t\t\t108489A1224415A1004D37A8 /* TranslateExampleObjC.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1E8DDC322259E3400536A5C /* TranslateExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC1E8DDC422259E3400536A5C /* AppDelegate.swift */,\n\t\t\t\tC1E8DDC622259E3400536A5C /* ViewController.swift */,\n\t\t\t\tC1E8DDC822259E3400536A5C /* Main.storyboard */,\n\t\t\t\tC1E8DDCB22259E3500536A5C /* Assets.xcassets */,\n\t\t\t\tC1E8DDCD22259E3500536A5C /* LaunchScreen.storyboard */,\n\t\t\t\tC1E8DDD022259E3500536A5C /* Info.plist */,\n\t\t\t);\n\t\t\tpath = TranslateExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE7C45F3A2FC5CB6A04E2E3FF /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t108489A0224415A1004D37A8 /* TranslateExampleObjC */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 108489D0224415A5004D37A8 /* Build configuration list for PBXNativeTarget \"TranslateExampleObjC\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t1084899D224415A1004D37A8 /* Sources */,\n\t\t\t\t1084899E224415A1004D37A8 /* Frameworks */,\n\t\t\t\t1084899F224415A1004D37A8 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = TranslateExampleObjC;\n\t\t\tproductName = TranslateExampleObjC;\n\t\t\tproductReference = 108489A1224415A1004D37A8 /* TranslateExampleObjC.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tC1E8DDC022259E3400536A5C /* TranslateExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C1E8DDD322259E3500536A5C /* Build configuration list for PBXNativeTarget \"TranslateExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tC1E8DDBD22259E3400536A5C /* Sources */,\n\t\t\t\tC1E8DDBE22259E3400536A5C /* Frameworks */,\n\t\t\t\tC1E8DDBF22259E3400536A5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = TranslateExample;\n\t\t\tproductName = TranslateApp;\n\t\t\tproductReference = C1E8DDC122259E3400536A5C /* TranslateExample.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tC1E8DDB922259E3400536A5C /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1010;\n\t\t\t\tLastUpgradeCheck = 1010;\n\t\t\t\tORGANIZATIONNAME = \"Google Inc\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t108489A0224415A1004D37A8 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t};\n\t\t\t\t\tC1E8DDC022259E3400536A5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = C1E8DDBC22259E3400536A5C /* Build configuration list for PBXProject \"TranslateExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = C1E8DDB822259E3400536A5C;\n\t\t\tproductRefGroup = C1E8DDC222259E3400536A5C /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tC1E8DDC022259E3400536A5C /* TranslateExample */,\n\t\t\t\t108489A0224415A1004D37A8 /* TranslateExampleObjC */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t1084899F224415A1004D37A8 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t108489F8224531B9004D37A8 /* Main.storyboard in Resources */,\n\t\t\t\t108489F9224531BF004D37A8 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t108489F7224531B6004D37A8 /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1E8DDBF22259E3400536A5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC1E8DDCF22259E3500536A5C /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tC1E8DDCC22259E3500536A5C /* Assets.xcassets in Resources */,\n\t\t\t\tC1E8DDCA22259E3400536A5C /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t1084899D224415A1004D37A8 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t108489A8224415A1004D37A8 /* ViewController.m in Sources */,\n\t\t\t\t108489B3224415A4004D37A8 /* main.m in Sources */,\n\t\t\t\t108489A5224415A1004D37A8 /* AppDelegate.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC1E8DDBD22259E3400536A5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC1E8DDC722259E3400536A5C /* ViewController.swift in Sources */,\n\t\t\t\tC1E8DDC522259E3400536A5C /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tC1E8DDC822259E3400536A5C /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tC1E8DDC922259E3400536A5C /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC1E8DDCD22259E3500536A5C /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tC1E8DDCE22259E3500536A5C /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t108489CA224415A5004D37A8 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/TranslateExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkitml.sampleapp.translate;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t108489CB224415A5004D37A8 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/TranslateExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkitml.sampleapp.translate;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC1E8DDD122259E3500536A5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC1E8DDD222259E3500536A5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC1E8DDD422259E3500536A5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/TranslateExample/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\t\"OTHER_SWIFT_FLAGS[arch=*]\" = \"-D COCOAPODS\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.sampleapp.translate;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC1E8DDD522259E3500536A5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/TranslateExample/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.sampleapp.translate;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t108489D0224415A5004D37A8 /* Build configuration list for PBXNativeTarget \"TranslateExampleObjC\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t108489CA224415A5004D37A8 /* Debug */,\n\t\t\t\t108489CB224415A5004D37A8 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC1E8DDBC22259E3400536A5C /* Build configuration list for PBXProject \"TranslateExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC1E8DDD122259E3500536A5C /* Debug */,\n\t\t\t\tC1E8DDD222259E3500536A5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC1E8DDD322259E3500536A5C /* Build configuration list for PBXNativeTarget \"TranslateExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC1E8DDD422259E3500536A5C /* Debug */,\n\t\t\t\tC1E8DDD522259E3500536A5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = C1E8DDB922259E3400536A5C /* Project object */;\n}\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExampleObjC/AppDelegate.h",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property(strong, nonatomic) UIWindow *window;\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExampleObjC/AppDelegate.m",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"AppDelegate.h\"\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application\n    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n  return YES;\n}\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExampleObjC/ViewController.h",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController <UITextViewDelegate, UIPickerViewDataSource, UIPickerViewDelegate>\n\n@end\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExampleObjC/ViewController.m",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"ViewController.h\"\n\n@import MLKit;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ViewController ()\n\n@property(weak, nonatomic) IBOutlet UITextView *inputTextView;\n@property(weak, nonatomic) IBOutlet UITextView *outputTextView;\n@property(weak, nonatomic) IBOutlet UITextView *statusTextView;\n@property(weak, nonatomic) IBOutlet UIPickerView *inputPicker;\n@property(weak, nonatomic) IBOutlet UIPickerView *outputPicker;\n@property(weak, nonatomic) IBOutlet UIButton *sourceDownloadDeleteButton;\n@property(weak, nonatomic) IBOutlet UIButton *targetDownloadDeleteButton;\n\n@property(nonatomic, strong) MLKTranslator *translator;\n@property(nonatomic, strong) NSArray<MLKTranslateLanguage> *allLanguages;\n\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  NSLocale *currentLocale = NSLocale.currentLocale;\n  self.allLanguages = [MLKTranslateAllLanguages().allObjects\n      sortedArrayUsingComparator:^NSComparisonResult(NSString *_Nonnull lang1,\n                                                     NSString *_Nonnull lang2) {\n        return [[currentLocale localizedStringForLanguageCode:lang1]\n            compare:[currentLocale localizedStringForLanguageCode:lang2]];\n      }];\n  self.inputPicker.dataSource = self;\n  self.outputPicker.dataSource = self;\n  [self.inputPicker selectRow:[self.allLanguages indexOfObject:MLKTranslateLanguageEnglish]\n                  inComponent:0\n                     animated:NO];\n  [self.outputPicker selectRow:[self.allLanguages indexOfObject:MLKTranslateLanguageSpanish]\n                   inComponent:0\n                      animated:NO];\n  self.inputPicker.delegate = self;\n  self.outputPicker.delegate = self;\n  self.inputTextView.delegate = self;\n  self.inputTextView.accessibilityIdentifier = @\"inputTextView\";\n  self.inputTextView.returnKeyType = UIReturnKeyDone;\n  self.statusTextView.accessibilityIdentifier = @\"statusTextView\";\n  self.outputTextView.accessibilityIdentifier = @\"outputTextView\";\n  self.sourceDownloadDeleteButton.accessibilityIdentifier = @\"InputModelButton\";\n  [self pickerView:self.inputPicker didSelectRow:0 inComponent:0];\n  [self updateDownloadDeleteButtonLabels];\n\n  [NSNotificationCenter.defaultCenter\n      addObserver:self\n         selector:@selector(modelDownloadDidCompleteWithNotification:)\n             name:MLKModelDownloadDidSucceedNotification\n           object:nil];\n  [NSNotificationCenter.defaultCenter\n      addObserver:self\n         selector:@selector(modelDownloadDidCompleteWithNotification:)\n             name:MLKModelDownloadDidFailNotification\n           object:nil];\n}\n\n- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {\n  return 1;\n}\n\n- (nullable NSString *)pickerView:(UIPickerView *)pickerView\n                      titleForRow:(NSInteger)row\n                     forComponent:(NSInteger)component {\n  return [NSLocale.currentLocale localizedStringForLanguageCode:self.allLanguages[row]];\n}\n\n- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {\n  return self.allLanguages.count;\n}\n\n- (void)textViewDidChange:(UITextView *)textView {\n  [self translate];\n}\n\n/**\n * Make all text selected when the text view is activated for editing, so that the newly input\n * context will override the existing content.\n */\n- (void)textViewDidBeginEditing:(UITextView *)textView {\n  textView.selectedTextRange = [textView textRangeFromPosition:textView.beginningOfDocument\n                                                    toPosition:textView.endOfDocument];\n}\n\n- (BOOL)textView:(UITextView *)textView\n    shouldChangeTextInRange:(NSRange)range\n            replacementText:(NSString *)text {\n  // Hide the keyboard when \"Done\" is pressed.\n  // See: https://stackoverflow.com/questions/26600359/dismiss-keyboard-with-a-uitextview\n  if ([text isEqualToString:@\"\\n\"]) {\n    [textView resignFirstResponder];\n    return NO;\n  }\n  return YES;\n}\n\n- (IBAction)didTapSwap {\n  NSInteger inputSelectedRow = [self.inputPicker selectedRowInComponent:0];\n  [self.inputPicker selectRow:[self.outputPicker selectedRowInComponent:0]\n                  inComponent:0\n                     animated:NO];\n  [self.outputPicker selectRow:inputSelectedRow inComponent:0 animated:NO];\n  self.inputTextView.text = self.outputTextView.text;\n  [self pickerView:self.inputPicker didSelectRow:0 inComponent:0];\n}\n\n- (void)pickerView:(UIPickerView *)pickerView\n      didSelectRow:(NSInteger)row\n       inComponent:(NSInteger)component {\n  MLKTranslatorOptions *options = [[MLKTranslatorOptions alloc]\n      initWithSourceLanguage:self.allLanguages[[self.inputPicker selectedRowInComponent:0]]\n              targetLanguage:self.allLanguages[[self.outputPicker selectedRowInComponent:0]]];\n  [self updateDownloadDeleteButtonLabels];\n  self.translator = [MLKTranslator translatorWithOptions:options];\n  [self translate];\n}\n\n- (void)translate {\n  MLKTranslator *translatorForDownload = self.translator;\n  __weak typeof(self) weakSelf = self;\n  [self.translator downloadModelIfNeededWithCompletion:^(NSError *_Nullable error) {\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    if (error != nil) {\n      strongSelf.outputTextView.text =\n          [NSString stringWithFormat:@\"Failed to ensure model downloaded with error %@\",\n                                     error.localizedDescription];\n      return;\n    }\n    [strongSelf updateDownloadDeleteButtonLabels];\n    NSString *text = strongSelf.inputTextView.text;\n    if (text == nil) {\n      text = @\"\";\n    }\n    strongSelf.outputTextView.text = @\"\";\n    if (translatorForDownload != self.translator) {\n      return;\n    }\n    [strongSelf.translator\n        translateText:text\n           completion:^(NSString *_Nullable result, NSError *_Nullable error) {\n             __strong typeof(weakSelf) strongSelf2 = weakSelf;\n             if (error != nil) {\n               strongSelf2.outputTextView.text =\n                   [NSString stringWithFormat:@\"Failed to ensure model downloaded with error %@\",\n                                              error.localizedDescription];\n               return;\n             }\n             if (translatorForDownload != strongSelf2.translator) {\n               return;\n             }\n             strongSelf2.outputTextView.text = result;\n           }];\n  }];\n}\n\n- (void)handleDownloadDeleteWithPicker:(UIPickerView *)picker button:(UIButton *)button {\n  MLKTranslateLanguage language = self.allLanguages[[picker selectedRowInComponent:0]];\n  if (language == MLKTranslateLanguageEnglish) {\n    return;\n  }\n  NSString *languageName = [NSLocale.currentLocale localizedStringForLanguageCode:language];\n\n  [button setTitle:@\"Working...\" forState:UIControlStateNormal];\n  MLKTranslateRemoteModel *model = [self modelForLanguage:language];\n  MLKModelManager *modelManager = [MLKModelManager modelManager];\n\n  if ([modelManager isModelDownloaded:model]) {\n    self.statusTextView.text = [NSString stringWithFormat:@\"Deleting %@\", languageName];\n    [modelManager deleteDownloadedModel:model\n                             completion:^(NSError *_Nullable error) {\n                               [self updateDownloadDeleteButtonLabels];\n                               self.statusTextView.text =\n                                   [NSString stringWithFormat:@\"Deleted %@\", languageName];\n                             }];\n  } else {\n    self.statusTextView.text = [NSString stringWithFormat:@\"Downloading %@\", languageName];\n    MLKModelDownloadConditions *conditions =\n        [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES\n                                             allowsBackgroundDownloading:YES];\n    [modelManager downloadModel:model conditions:conditions];\n  }\n}\n\n- (void)updateDownloadDeleteButtonLabels {\n  MLKTranslateLanguage inputLanguage =\n      self.allLanguages[[self.inputPicker selectedRowInComponent:0]];\n  MLKTranslateLanguage outputLanguage =\n      self.allLanguages[[self.outputPicker selectedRowInComponent:0]];\n\n  if ([self isLanguageDownloaded:inputLanguage]) {\n    [self.sourceDownloadDeleteButton setTitle:@\"Delete Model\" forState:UIControlStateNormal];\n  } else {\n    [self.sourceDownloadDeleteButton setTitle:@\"Download Model\" forState:UIControlStateNormal];\n  }\n  self.sourceDownloadDeleteButton.hidden = inputLanguage == MLKTranslateLanguageEnglish;\n  if ([self isLanguageDownloaded:outputLanguage]) {\n    [self.targetDownloadDeleteButton setTitle:@\"Delete Model\" forState:UIControlStateNormal];\n  } else {\n    [self.targetDownloadDeleteButton setTitle:@\"Download Model\" forState:UIControlStateNormal];\n  }\n  self.targetDownloadDeleteButton.hidden = outputLanguage == MLKTranslateLanguageEnglish;\n}\n\n- (BOOL)isLanguageDownloaded:(MLKTranslateLanguage)language {\n  MLKTranslateRemoteModel *model = [self modelForLanguage:language];\n  MLKModelManager *modelManager = [MLKModelManager modelManager];\n  return [modelManager isModelDownloaded:model];\n}\n\n- (IBAction)listDownloadedModels {\n  MLKModelManager *modelManager = [MLKModelManager modelManager];\n  NSMutableString *listOfLanguages = [NSMutableString string];\n  for (MLKTranslateRemoteModel *model in modelManager.downloadedTranslateModels) {\n    if (listOfLanguages.length > 0) {\n      [listOfLanguages appendString:@\", \"];\n    }\n\n    [listOfLanguages\n        appendString:[NSLocale.currentLocale localizedStringForLanguageCode:model.language]];\n  }\n  self.statusTextView.text = [NSString stringWithFormat:@\"Downloaded models: %@\", listOfLanguages];\n}\n\n- (IBAction)didTapDownloadDeleteSourceLanguage {\n  [self handleDownloadDeleteWithPicker:self.inputPicker button:self.sourceDownloadDeleteButton];\n}\n\n- (IBAction)didTapDownloadDeleteTargetLanguage {\n  [self handleDownloadDeleteWithPicker:self.outputPicker button:self.targetDownloadDeleteButton];\n}\n\n- (MLKTranslateRemoteModel *)modelForLanguage:(MLKTranslateLanguage)language {\n  return [MLKTranslateRemoteModel translateRemoteModelWithLanguage:language];\n}\n\n- (void)modelDownloadDidCompleteWithNotification:(NSNotification *)notification {\n  MLKTranslateRemoteModel *model = notification.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];\n  if (![model isKindOfClass:MLKTranslateRemoteModel.class]) {\n    return;\n  }\n  NSString *languageName = [NSLocale.currentLocale localizedStringForLanguageCode:model.language];\n\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    if (notification.name == MLKModelDownloadDidSucceedNotification) {\n      strongSelf.statusTextView.text =\n          [NSString stringWithFormat:@\"Download succeeded for %@\", languageName];\n    } else {\n      strongSelf.statusTextView.text =\n          [NSString stringWithFormat:@\"Download failed for%@\", languageName];\n    }\n    [strongSelf updateDownloadDeleteButtonLabels];\n  });\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/translate/TranslateExampleObjC/main.m",
    "content": "//\n// Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char* argv[]) {\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/Assets.xcassets/photo_camera.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"photo_camera_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"photo_camera_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/vision/Assets.xcassets/photo_library.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"photo_library_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"photo_library_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/vision/Assets.xcassets/switch_camera.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"switch_camera_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"switch_camera_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/Assets.xcassets/video_camera.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"video_camera_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"video_camera_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/quickstarts/vision/Podfile",
    "content": "platform :ios, '15.5'\nuse_frameworks!\n\nproject 'VisionExample.xcodeproj'\n\npod 'GoogleMLKit/BarcodeScanning', '9.0.0'\npod 'GoogleMLKit/FaceDetection', '9.0.0'\npod 'GoogleMLKit/ImageLabeling', '9.0.0'\npod 'GoogleMLKit/ImageLabelingCustom', '9.0.0'\npod 'GoogleMLKit/ObjectDetection', '9.0.0'\npod 'GoogleMLKit/ObjectDetectionCustom', '9.0.0'\npod 'GoogleMLKit/PoseDetection', '9.0.0'\npod 'GoogleMLKit/PoseDetectionAccurate', '9.0.0'\npod 'GoogleMLKit/SegmentationSelfie', '9.0.0'\npod 'GoogleMLKit/TextRecognition', '9.0.0'\npod 'GoogleMLKit/TextRecognitionChinese', '9.0.0'\npod 'GoogleMLKit/TextRecognitionDevanagari', '9.0.0'\npod 'GoogleMLKit/TextRecognitionJapanese', '9.0.0'\npod 'GoogleMLKit/TextRecognitionKorean', '9.0.0'\n\ntarget 'VisionExample' do\nend\n\ntarget 'VisionExampleObjC' do\nend\n\npost_install do |installer|\n  installer.aggregate_targets.each do |target|\n    target.xcconfigs.each do |variant, xcconfig|\n      xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)\n      IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n    end\n  end\n  installer.generated_projects.each do |project|\n    project.targets.each do |target|\n        target.build_configurations.each do |config|\n            config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'\n            config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'\n         end\n    end\n  end\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference\n        xcconfig_path = config.base_configuration_reference.real_path\n        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n      end\n    end\n  end\nend"
  },
  {
    "path": "ios/quickstarts/vision/README.md",
    "content": "# ML Kit Vision Quickstart Sample App\n\n## Introduction\n\nThis ML Kit Vision iOS Quickstart app demonstrates how to use and integrate various vision based ML Kit features into your app.\n\n## Feature List\n\nFeatures that are included in this demo app:\n* [Object Detection](https://developers.google.com/ml-kit/vision/object-detection/ios) - Detect, track, and classify objects in real time and static images\n* [Custom Object Detection (Birds)](https://developers.google.com/ml-kit/vision/object-detection/custom-models/ios) - Detect, track, and classify birds with a custom TensorFlow Lite model\n* [Face Detection](https://developers.google.com/ml-kit/vision/face-detection/ios) - Detect faces in real time and static images\n* [Text Recognition](https://developers.google.com/ml-kit/vision/text-recognition/v2/ios) - Recognize text in real time and static images\n* [Barcode Scanning ](https://developers.google.com/ml-kit/vision/barcode-scanning/ios)- Scan barcodes in real time and static images\n* [Image Labeling](https://developers.google.com/ml-kit/vision/image-labeling/ios) - Label images in real time and static images\n* [Custom Image Labeling (Birds)](https://developers.google.com/ml-kit/vision/image-labeling/custom-models/ios) - Label images of birds with a custom TensorFlow Lite model\n* [Pose Detection](https://developers.google.com/ml-kit/vision/pose-detection/ios) - Detect the position of the human body in real time.\n* [Selfie Segmentation](https://developers.google.com/ml-kit/vision/selfie-segmentation/ios) - Segment people from the background in real time.\n\n## Getting Started\n\n* Run the sample code on your iOS device or simulator\n* Try extending the code to add new features and functionality\n\n## How to use the app\n\nThis app supports two usage scenarios: Live Camera mode and Static Image mode.\n\n### Static Image Scenario\nWhen the app is first opened, you will begin in Static Image mode. Use the carousel to select a specific API and hit “detect” to exercise the API on the preloaded images. In order to add your own images from the camera roll, select the camera roll icon on the top of the screen.\n\n### Live Camera Scenario\nThis mode uses the camera preview as input instead of static images. In order to enter this mode, select the video camera icon in the top right corner of the screen.\n\n## Support\n-------\n\n- [Stack Overflow](https://stackoverflow.com/questions/tagged/google-mlkit)\n\nLicense\n-------\n\nCopyright 2020 Google, Inc.\n\nLicensed to the Apache Software Foundation (ASF) under one or more contributor\nlicense agreements.  See the NOTICE file distributed with this work for\nadditional information regarding copyright ownership.  The ASF licenses this\nfile to you under the Apache License, Version 2.0 (the \"License\"); you may not\nuse this file except in compliance with the License.  You may obtain a copy of\nthe License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\nLicense for the specific language governing permissions and limitations under\nthe License.\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample/AppDelegate.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n  var window: UIWindow?\n\n  func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    return true\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14868\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"0Q6-lG-sCk\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14824\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Navigation Controller-->\n        <scene sceneID=\"rAH-gT-x68\">\n            <objects>\n                <navigationController id=\"0Q6-lG-sCk\" sceneMemberID=\"viewController\">\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"JoS-YE-9OV\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </navigationBar>\n                    <connections>\n                        <segue destination=\"BYZ-38-t0r\" kind=\"relationship\" relationship=\"rootViewController\" id=\"fdA-VU-1vi\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"6gn-Xt-3Nz\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-607\" y=\"134\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController storyboardIdentifier=\"viewController\" id=\"BYZ-38-t0r\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"LHw-b6-B2a\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"Ydg-C1-MLG\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <pickerView contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Xs4-mo-RjW\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"488\" width=\"375\" height=\"180\"/>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"180\" id=\"f3t-1V-izd\"/>\n                                </constraints>\n                                <edgeInsets key=\"layoutMargins\" top=\"8\" left=\"8\" bottom=\"8\" right=\"8\"/>\n                            </pickerView>\n                            <toolbar opaque=\"NO\" clearsContextBeforeDrawing=\"NO\" contentMode=\"center\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"POq-8j-gOJ\" userLabel=\"Top Toolbar\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"56\" width=\"375\" height=\"44\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"44\" id=\"it0-iL-OwQ\"/>\n                                </constraints>\n                                <items>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"Ntc-CQ-liM\"/>\n                                    <barButtonItem image=\"photo_library\" id=\"cQ8-BV-rH6\" userLabel=\"Photo Library Button\">\n                                        <connections>\n                                            <action selector=\"openPhotoLibrary:\" destination=\"BYZ-38-t0r\" id=\"1Jr-zi-I6V\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"eph-cT-Zvt\"/>\n                                    <barButtonItem image=\"photo_camera\" id=\"jD4-E9-bbj\" userLabel=\"Photo Camera Button\">\n                                        <connections>\n                                            <action selector=\"openCamera:\" destination=\"BYZ-38-t0r\" id=\"3cs-Py-gWB\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"v2M-Hr-v21\"/>\n                                    <barButtonItem enabled=\"NO\" image=\"video_camera\" id=\"M1D-Qg-lKI\" userLabel=\"Video Camera Button\">\n                                        <connections>\n                                            <segue destination=\"YXl-5B-mBF\" kind=\"show\" identifier=\"showCameraViewController\" id=\"M0h-0G-c32\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"1ha-dt-VEM\"/>\n                                </items>\n                            </toolbar>\n                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cCp-tA-gDT\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"100\" width=\"375\" height=\"350\"/>\n                            </imageView>\n                            <toolbar opaque=\"NO\" clearsContextBeforeDrawing=\"NO\" contentMode=\"center\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yof-fW-vlO\" userLabel=\"Bottom Toolbar\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"450\" width=\"375\" height=\"44\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"44\" id=\"74h-Pf-w4T\"/>\n                                </constraints>\n                                <items>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"RLv-lI-aQm\"/>\n                                    <barButtonItem title=\"Detect\" id=\"Dwb-uQ-3dE\" userLabel=\"Detect Button\">\n                                        <connections>\n                                            <action selector=\"detect:\" destination=\"BYZ-38-t0r\" id=\"oTX-fI-9ty\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem title=\"Next image\" id=\"Glk-GE-iCa\">\n                                        <connections>\n                                            <action selector=\"changeImage:\" destination=\"BYZ-38-t0r\" id=\"wi9-lu-Oqs\"/>\n                                        </connections>\n                                    </barButtonItem>\n                                    <barButtonItem style=\"plain\" systemItem=\"flexibleSpace\" id=\"cR0-7i-Xm8\"/>\n                                </items>\n                            </toolbar>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"cCp-tA-gDT\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"45c-Cz-uBY\"/>\n                            <constraint firstItem=\"POq-8j-gOJ\" firstAttribute=\"top\" secondItem=\"LHw-b6-B2a\" secondAttribute=\"bottom\" constant=\"12\" id=\"7wp-P3-gcC\"/>\n                            <constraint firstItem=\"Xs4-mo-RjW\" firstAttribute=\"top\" secondItem=\"yof-fW-vlO\" secondAttribute=\"bottom\" constant=\"-6\" id=\"Eqz-89-OCh\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"POq-8j-gOJ\" secondAttribute=\"trailing\" id=\"I0X-8i-nPT\"/>\n                            <constraint firstItem=\"cCp-tA-gDT\" firstAttribute=\"top\" secondItem=\"POq-8j-gOJ\" secondAttribute=\"bottom\" id=\"Tv4-sH-Gef\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"cCp-tA-gDT\" secondAttribute=\"trailing\" id=\"UKP-ZW-thL\"/>\n                            <constraint firstItem=\"yof-fW-vlO\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"Wki-fU-blU\"/>\n                            <constraint firstItem=\"POq-8j-gOJ\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"cho-7Z-rGg\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"yof-fW-vlO\" secondAttribute=\"trailing\" id=\"etE-tG-0CW\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"Xs4-mo-RjW\" secondAttribute=\"trailing\" id=\"gvn-CW-6Xx\"/>\n                            <constraint firstItem=\"yof-fW-vlO\" firstAttribute=\"top\" secondItem=\"cCp-tA-gDT\" secondAttribute=\"bottom\" id=\"oQg-Ks-4Jj\"/>\n                            <constraint firstItem=\"Ydg-C1-MLG\" firstAttribute=\"top\" secondItem=\"Xs4-mo-RjW\" secondAttribute=\"bottom\" constant=\"-1\" id=\"rWN-Im-hnc\"/>\n                            <constraint firstItem=\"Xs4-mo-RjW\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"uNU-KO-ASb\"/>\n                        </constraints>\n                    </view>\n                    <navigationItem key=\"navigationItem\" id=\"xYg-VP-pps\">\n                        <barButtonItem key=\"backBarButtonItem\" title=\" \" id=\"QLp-QO-2R9\"/>\n                    </navigationItem>\n                    <connections>\n                        <outlet property=\"detectButton\" destination=\"Dwb-uQ-3dE\" id=\"8Hn-BT-3m1\"/>\n                        <outlet property=\"detectorPicker\" destination=\"Xs4-mo-RjW\" id=\"kFH-5K-Mcc\"/>\n                        <outlet property=\"imageView\" destination=\"cCp-tA-gDT\" id=\"FIt-va-neE\"/>\n                        <outlet property=\"photoCameraButton\" destination=\"jD4-E9-bbj\" id=\"cf0-4Q-UL8\"/>\n                        <outlet property=\"videoCameraButton\" destination=\"M1D-Qg-lKI\" id=\"3Cr-4e-JCG\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"125.59999999999999\" y=\"133.5832083958021\"/>\n        </scene>\n        <!--Camera View Controller-->\n        <scene sceneID=\"kPU-gK-lh6\">\n            <objects>\n                <viewController id=\"YXl-5B-mBF\" customClass=\"CameraViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"qO2-JB-Jc4\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"7NG-lt-hPa\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"bWY-Sx-TCF\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vwd-Qp-BMC\" userLabel=\"Camera View\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"44\" width=\"375\" height=\"623\"/>\n                                <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                            </view>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"Vwd-Qp-BMC\" firstAttribute=\"top\" secondItem=\"bWY-Sx-TCF\" secondAttribute=\"topMargin\" id=\"GtM-D5-MQE\"/>\n                            <constraint firstItem=\"Vwd-Qp-BMC\" firstAttribute=\"leading\" secondItem=\"bWY-Sx-TCF\" secondAttribute=\"leading\" id=\"bTr-O6-WSG\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"Vwd-Qp-BMC\" secondAttribute=\"trailing\" id=\"cN6-F5-qVY\"/>\n                            <constraint firstItem=\"Vwd-Qp-BMC\" firstAttribute=\"bottom\" secondItem=\"7NG-lt-hPa\" secondAttribute=\"top\" id=\"ja0-Ki-fxw\"/>\n                        </constraints>\n                    </view>\n                    <navigationItem key=\"navigationItem\" id=\"8dJ-Hr-2St\">\n                        <nil key=\"title\"/>\n                        <rightBarButtonItems>\n                            <barButtonItem image=\"switch_camera\" id=\"kXj-bT-GY0\" userLabel=\"Switch Camera Button\">\n                                <connections>\n                                    <action selector=\"switchCamera:\" destination=\"YXl-5B-mBF\" id=\"sFo-ar-LIv\"/>\n                                </connections>\n                            </barButtonItem>\n                            <barButtonItem title=\"Detectors\" id=\"jrI-gv-coB\" userLabel=\"Detectors Button\">\n                                <connections>\n                                    <action selector=\"selectDetector:\" destination=\"YXl-5B-mBF\" id=\"AjI-Jr-07c\"/>\n                                </connections>\n                            </barButtonItem>\n                        </rightBarButtonItems>\n                    </navigationItem>\n                    <connections>\n                        <outlet property=\"cameraView\" destination=\"Vwd-Qp-BMC\" id=\"yRq-e8-30h\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Tub-Fx-HUo\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"853.60000000000002\" y=\"133.5832083958021\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"photo_camera\" width=\"36\" height=\"36\"/>\n        <image name=\"photo_library\" width=\"36\" height=\"36\"/>\n        <image name=\"switch_camera\" width=\"36\" height=\"36\"/>\n        <image name=\"video_camera\" width=\"36\" height=\"36\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample/CameraViewController.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport AVFoundation\nimport CoreVideo\nimport MLImage\nimport MLKit\n\n@objc(CameraViewController)\nclass CameraViewController: UIViewController {\n  private let detectors: [Detector] = [\n    .onDeviceFace,\n    .onDeviceText,\n    .onDeviceTextChinese,\n    .onDeviceTextDevanagari,\n    .onDeviceTextJapanese,\n    .onDeviceTextKorean,\n    .onDeviceBarcode,\n    .onDeviceImageLabel,\n    .onDeviceImageLabelsCustom,\n    .onDeviceObjectProminentNoClassifier,\n    .onDeviceObjectProminentWithClassifier,\n    .onDeviceObjectMultipleNoClassifier,\n    .onDeviceObjectMultipleWithClassifier,\n    .onDeviceObjectCustomProminentNoClassifier,\n    .onDeviceObjectCustomProminentWithClassifier,\n    .onDeviceObjectCustomMultipleNoClassifier,\n    .onDeviceObjectCustomMultipleWithClassifier,\n    .pose,\n    .poseAccurate,\n    .segmentationSelfie,\n  ]\n\n  private var currentDetector: Detector = .onDeviceFace\n  private var isUsingFrontCamera = true\n  private var previewLayer: AVCaptureVideoPreviewLayer!\n  private lazy var captureSession = AVCaptureSession()\n  private lazy var sessionQueue = DispatchQueue(label: Constant.sessionQueueLabel)\n  private var lastFrame: CMSampleBuffer?\n\n  private lazy var previewOverlayView: UIImageView = {\n\n    precondition(isViewLoaded)\n    let previewOverlayView = UIImageView(frame: .zero)\n    previewOverlayView.contentMode = UIView.ContentMode.scaleAspectFill\n    previewOverlayView.translatesAutoresizingMaskIntoConstraints = false\n    return previewOverlayView\n  }()\n\n  private lazy var annotationOverlayView: UIView = {\n    precondition(isViewLoaded)\n    let annotationOverlayView = UIView(frame: .zero)\n    annotationOverlayView.translatesAutoresizingMaskIntoConstraints = false\n    return annotationOverlayView\n  }()\n\n  /// Initialized when one of the pose detector rows are chosen. Reset to `nil` when neither are.\n  private var poseDetector: PoseDetector? = nil\n\n  /// Initialized when a segmentation row is chosen. Reset to `nil` otherwise.\n  private var segmenter: Segmenter? = nil\n\n  /// The detector mode with which detection was most recently run. Only used on the video output\n  /// queue. Useful for inferring when to reset detector instances which use a conventional\n  /// lifecyle paradigm.\n  private var lastDetector: Detector?\n\n  // MARK: - IBOutlets\n\n  @IBOutlet private weak var cameraView: UIView!\n\n  // MARK: - UIViewController\n\n  override func viewDidLoad() {\n    super.viewDidLoad()\n\n    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)\n    setUpPreviewOverlayView()\n    setUpAnnotationOverlayView()\n    setUpCaptureSessionOutput()\n    setUpCaptureSessionInput()\n  }\n\n  override func viewDidAppear(_ animated: Bool) {\n    super.viewDidAppear(animated)\n\n    startSession()\n  }\n\n  override func viewDidDisappear(_ animated: Bool) {\n    super.viewDidDisappear(animated)\n\n    stopSession()\n  }\n\n  override func viewDidLayoutSubviews() {\n    super.viewDidLayoutSubviews()\n\n    previewLayer.frame = cameraView.frame\n  }\n\n  // MARK: - IBActions\n\n  @IBAction func selectDetector(_ sender: Any) {\n    presentDetectorsAlertController()\n  }\n\n  @IBAction func switchCamera(_ sender: Any) {\n    isUsingFrontCamera = !isUsingFrontCamera\n    removeDetectionAnnotations()\n    setUpCaptureSessionInput()\n  }\n\n  // MARK: On-Device Detections\n\n  private func scanBarcodesOnDevice(in image: VisionImage, width: CGFloat, height: CGFloat) {\n    // Define the options for a barcode detector.\n    let format = BarcodeFormat.all\n    let barcodeOptions = BarcodeScannerOptions(formats: format)\n\n    // Create a barcode scanner.\n    let barcodeScanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)\n    var barcodes: [Barcode] = []\n    var scanningError: Error?\n    do {\n      barcodes = try barcodeScanner.results(in: image)\n    } catch let error {\n      scanningError = error\n    }\n    weak var weakSelf = self\n    DispatchQueue.main.sync {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.updatePreviewOverlayViewWithLastFrame()\n\n      if let scanningError = scanningError {\n        print(\"Failed to scan barcodes with error: \\(scanningError.localizedDescription).\")\n        return\n      }\n      guard !barcodes.isEmpty else {\n        print(\"Barcode scanner returrned no results.\")\n        return\n      }\n      for barcode in barcodes {\n        let normalizedRect = CGRect(\n          x: barcode.frame.origin.x / width,\n          y: barcode.frame.origin.y / height,\n          width: barcode.frame.size.width / width,\n          height: barcode.frame.size.height / height\n        )\n        let convertedRect = strongSelf.previewLayer.layerRectConverted(\n          fromMetadataOutputRect: normalizedRect\n        )\n        UIUtilities.addRectangle(\n          convertedRect,\n          to: strongSelf.annotationOverlayView,\n          color: UIColor.green\n        )\n        let label = UILabel(frame: convertedRect)\n        label.text = barcode.displayValue\n        label.adjustsFontSizeToFitWidth = true\n        strongSelf.rotate(label, orientation: image.orientation)\n        strongSelf.annotationOverlayView.addSubview(label)\n      }\n    }\n  }\n\n  private func detectFacesOnDevice(in image: VisionImage, width: CGFloat, height: CGFloat) {\n    // When performing latency tests to determine ideal detection settings, run the app in 'release'\n    // mode to get accurate performance metrics.\n    let options = FaceDetectorOptions()\n    options.landmarkMode = .none\n    options.contourMode = .all\n    options.classificationMode = .none\n    options.performanceMode = .fast\n    let faceDetector = FaceDetector.faceDetector(options: options)\n    var faces: [Face] = []\n    var detectionError: Error?\n    do {\n      faces = try faceDetector.results(in: image)\n    } catch let error {\n      detectionError = error\n    }\n    weak var weakSelf = self\n    DispatchQueue.main.sync {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.updatePreviewOverlayViewWithLastFrame()\n      if let detectionError = detectionError {\n        print(\"Failed to detect faces with error: \\(detectionError.localizedDescription).\")\n        return\n      }\n      guard !faces.isEmpty else {\n        print(\"On-Device face detector returned no results.\")\n        return\n      }\n\n      for face in faces {\n        let normalizedRect = CGRect(\n          x: face.frame.origin.x / width,\n          y: face.frame.origin.y / height,\n          width: face.frame.size.width / width,\n          height: face.frame.size.height / height\n        )\n        let standardizedRect = strongSelf.previewLayer.layerRectConverted(\n          fromMetadataOutputRect: normalizedRect\n        ).standardized\n        UIUtilities.addRectangle(\n          standardizedRect,\n          to: strongSelf.annotationOverlayView,\n          color: UIColor.green\n        )\n        strongSelf.addContours(for: face, width: width, height: height)\n      }\n    }\n  }\n\n  private func detectPose(in image: MLImage, width: CGFloat, height: CGFloat) {\n    if let poseDetector = self.poseDetector {\n      var poses: [Pose] = []\n      var detectionError: Error?\n      do {\n        poses = try poseDetector.results(in: image)\n      } catch let error {\n        detectionError = error\n      }\n      weak var weakSelf = self\n      DispatchQueue.main.sync {\n        guard let strongSelf = weakSelf else {\n          print(\"Self is nil!\")\n          return\n        }\n        strongSelf.updatePreviewOverlayViewWithLastFrame()\n        if let detectionError = detectionError {\n          print(\"Failed to detect poses with error: \\(detectionError.localizedDescription).\")\n          return\n        }\n        guard !poses.isEmpty else {\n          print(\"Pose detector returned no results.\")\n          return\n        }\n\n        // Pose detected. Currently, only single person detection is supported.\n        poses.forEach { pose in\n          let poseOverlayView = UIUtilities.createPoseOverlayView(\n            forPose: pose,\n            inViewWithBounds: strongSelf.annotationOverlayView.bounds,\n            lineWidth: Constant.lineWidth,\n            dotRadius: Constant.smallDotRadius,\n            positionTransformationClosure: { (position) -> CGPoint in\n              return strongSelf.normalizedPoint(\n                fromVisionPoint: position, width: width, height: height)\n            }\n          )\n          strongSelf.annotationOverlayView.addSubview(poseOverlayView)\n        }\n      }\n    }\n  }\n\n  private func detectSegmentationMask(in image: VisionImage, sampleBuffer: CMSampleBuffer) {\n    guard let segmenter = self.segmenter else {\n      return\n    }\n    var mask: SegmentationMask? = nil\n    var segmentationError: Error?\n    do {\n      mask = try segmenter.results(in: image)\n    } catch let error {\n      segmentationError = error\n    }\n    weak var weakSelf = self\n    DispatchQueue.main.sync {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.removeDetectionAnnotations()\n\n      if let segmentationError = segmentationError {\n        print(\n          \"Failed to perform segmentation with error: \\(segmentationError.localizedDescription).\")\n        return\n      }\n      guard let mask = mask else {\n        print(\"Segmenter returned empty mask.\")\n        return\n      }\n      guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {\n        print(\"Failed to get image buffer from sample buffer.\")\n        return\n      }\n\n      UIUtilities.applySegmentationMask(\n        mask: mask, to: imageBuffer,\n        backgroundColor: UIColor.purple.withAlphaComponent(Constant.segmentationMaskAlpha),\n        foregroundColor: nil)\n      strongSelf.updatePreviewOverlayViewWithImageBuffer(imageBuffer)\n    }\n  }\n\n  private func recognizeTextOnDevice(\n    in image: VisionImage, width: CGFloat, height: CGFloat, detectorType: Detector\n  ) {\n    var options: CommonTextRecognizerOptions\n    if detectorType == .onDeviceTextChinese {\n      options = ChineseTextRecognizerOptions.init()\n    } else if detectorType == .onDeviceTextDevanagari {\n      options = DevanagariTextRecognizerOptions.init()\n    } else if detectorType == .onDeviceTextJapanese {\n      options = JapaneseTextRecognizerOptions.init()\n    } else if detectorType == .onDeviceTextKorean {\n      options = KoreanTextRecognizerOptions.init()\n    } else {\n      options = TextRecognizerOptions.init()\n    }\n\n    var recognizedText: Text?\n    var detectionError: Error?\n    do {\n      recognizedText = try TextRecognizer.textRecognizer(options: options)\n        .results(in: image)\n    } catch let error {\n      detectionError = error\n    }\n    weak var weakSelf = self\n    DispatchQueue.main.sync {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.updatePreviewOverlayViewWithLastFrame()\n      if let detectionError = detectionError {\n        print(\"Failed to recognize text with error: \\(detectionError.localizedDescription).\")\n        return\n      }\n      guard let recognizedText = recognizedText else {\n        print(\"Text recognition returned no results.\")\n        return\n      }\n\n      // Blocks.\n      for block in recognizedText.blocks {\n        let points = strongSelf.convertedPoints(\n          from: block.cornerPoints, width: width, height: height)\n        UIUtilities.addShape(\n          withPoints: points,\n          to: strongSelf.annotationOverlayView,\n          color: UIColor.purple\n        )\n\n        // Lines.\n        for line in block.lines {\n          let points = strongSelf.convertedPoints(\n            from: line.cornerPoints, width: width, height: height)\n          UIUtilities.addShape(\n            withPoints: points,\n            to: strongSelf.annotationOverlayView,\n            color: UIColor.orange\n          )\n\n          // Elements.\n          for element in line.elements {\n            let normalizedRect = CGRect(\n              x: element.frame.origin.x / width,\n              y: element.frame.origin.y / height,\n              width: element.frame.size.width / width,\n              height: element.frame.size.height / height\n            )\n            let convertedRect = strongSelf.previewLayer.layerRectConverted(\n              fromMetadataOutputRect: normalizedRect\n            )\n            UIUtilities.addRectangle(\n              convertedRect,\n              to: strongSelf.annotationOverlayView,\n              color: UIColor.green\n            )\n            let label = UILabel(frame: convertedRect)\n            label.text = element.text\n            label.adjustsFontSizeToFitWidth = true\n            strongSelf.rotate(label, orientation: image.orientation)\n            strongSelf.annotationOverlayView.addSubview(label)\n          }\n        }\n      }\n    }\n  }\n\n  private func detectLabels(\n    in visionImage: VisionImage,\n    width: CGFloat,\n    height: CGFloat,\n    shouldUseCustomModel: Bool\n  ) {\n    var options: CommonImageLabelerOptions!\n    if shouldUseCustomModel {\n      guard\n        let localModelFilePath = Bundle.main.path(\n          forResource: Constant.localModelFile.name,\n          ofType: Constant.localModelFile.type\n        )\n      else {\n        print(\"On-Device label detection failed because custom model was not found.\")\n        return\n      }\n      let localModel = LocalModel(path: localModelFilePath)\n      options = CustomImageLabelerOptions(localModel: localModel)\n    } else {\n      options = ImageLabelerOptions()\n    }\n    options.confidenceThreshold = NSNumber(floatLiteral: Constant.labelConfidenceThreshold)\n    let onDeviceLabeler = ImageLabeler.imageLabeler(options: options)\n    let labels: [ImageLabel]\n    var labelingError: Error?\n    var resultsText: String? = nil\n    do {\n      labels = try onDeviceLabeler.results(in: visionImage)\n      resultsText = labels.map { label -> String in\n        return \"Label: \\(label.text), Confidence: \\(label.confidence), Index: \\(label.index)\"\n      }.joined(separator: \"\\n\")\n\n    } catch let error {\n      labelingError = error\n    }\n    weak var weakSelf = self\n    DispatchQueue.main.sync {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.updatePreviewOverlayViewWithLastFrame()\n      if let labelingError = labelingError {\n        print(\"Image labeling failed with error: \\(labelingError.localizedDescription)\")\n        return\n      }\n      guard let resultsText = resultsText else { return }\n      guard resultsText.count > 0 else { return }\n\n      let normalizedRect = CGRect(\n        x: Constant.imageLabelResultFrameX,\n        y: Constant.imageLabelResultFrameY,\n        width: Constant.imageLabelResultFrameWidth,\n        height: Constant.imageLabelResultFrameHeight\n      )\n      let standardizedRect = strongSelf.previewLayer.layerRectConverted(\n        fromMetadataOutputRect: normalizedRect\n      ).standardized\n      UIUtilities.addRectangle(\n        standardizedRect,\n        to: strongSelf.annotationOverlayView,\n        color: UIColor.gray\n      )\n      let uiLabel = UILabel(frame: standardizedRect)\n      uiLabel.text = resultsText\n      uiLabel.numberOfLines = 0\n      uiLabel.adjustsFontSizeToFitWidth = true\n      strongSelf.rotate(uiLabel, orientation: visionImage.orientation)\n      strongSelf.annotationOverlayView.addSubview(uiLabel)\n    }\n  }\n\n  private func detectObjectsOnDevice(\n    in image: VisionImage,\n    width: CGFloat,\n    height: CGFloat,\n    options: CommonObjectDetectorOptions\n  ) {\n    let detector = ObjectDetector.objectDetector(options: options)\n    var objects: [Object] = []\n    var detectionError: Error? = nil\n    do {\n      objects = try detector.results(in: image)\n    } catch let error {\n      detectionError = error\n    }\n\n    weak var weakSelf = self\n    DispatchQueue.main.sync {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.self.updatePreviewOverlayViewWithLastFrame()\n      if let detectionError = detectionError {\n        print(\"Failed to detect objects with error: \\(detectionError.localizedDescription).\")\n        return\n\n      }\n      guard !objects.isEmpty else {\n        print(\"On-Device object detector returned no results.\")\n        return\n      }\n      for object in objects {\n        let normalizedRect = CGRect(\n          x: object.frame.origin.x / width,\n          y: object.frame.origin.y / height,\n          width: object.frame.size.width / width,\n          height: object.frame.size.height / height\n        )\n        let standardizedRect = strongSelf.previewLayer.layerRectConverted(\n          fromMetadataOutputRect: normalizedRect\n        ).standardized\n        UIUtilities.addRectangle(\n          standardizedRect,\n          to: strongSelf.annotationOverlayView,\n          color: UIColor.green\n        )\n        let label = UILabel(frame: standardizedRect)\n        var description = \"\"\n        if let trackingID = object.trackingID {\n          description += \"Object ID: \" + trackingID.stringValue + \"\\n\"\n        }\n        description += object.labels.enumerated().map { (index, label) in\n          \"Label \\(index): \\(label.text), \\(label.confidence), \\(label.index)\"\n        }.joined(separator: \"\\n\")\n\n        label.text = description\n        label.numberOfLines = 0\n        label.adjustsFontSizeToFitWidth = true\n        strongSelf.rotate(label, orientation: image.orientation)\n        strongSelf.annotationOverlayView.addSubview(label)\n      }\n    }\n  }\n\n  // MARK: - Private\n\n  private func setUpCaptureSessionOutput() {\n    weak var weakSelf = self\n    sessionQueue.async {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.captureSession.beginConfiguration()\n      // When performing latency tests to determine ideal capture settings,\n      // run the app in 'release' mode to get accurate performance metrics\n      strongSelf.captureSession.sessionPreset = AVCaptureSession.Preset.medium\n\n      let output = AVCaptureVideoDataOutput()\n      output.videoSettings = [\n        (kCVPixelBufferPixelFormatTypeKey as String): kCVPixelFormatType_32BGRA\n      ]\n      output.alwaysDiscardsLateVideoFrames = true\n      let outputQueue = DispatchQueue(label: Constant.videoDataOutputQueueLabel)\n      output.setSampleBufferDelegate(strongSelf, queue: outputQueue)\n      guard strongSelf.captureSession.canAddOutput(output) else {\n        print(\"Failed to add capture session output.\")\n        return\n      }\n      strongSelf.captureSession.addOutput(output)\n      strongSelf.captureSession.commitConfiguration()\n    }\n  }\n\n  private func setUpCaptureSessionInput() {\n    weak var weakSelf = self\n    sessionQueue.async {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      let cameraPosition: AVCaptureDevice.Position = strongSelf.isUsingFrontCamera ? .front : .back\n      guard let device = strongSelf.captureDevice(forPosition: cameraPosition) else {\n        print(\"Failed to get capture device for camera position: \\(cameraPosition)\")\n        return\n      }\n      do {\n        strongSelf.captureSession.beginConfiguration()\n        let currentInputs = strongSelf.captureSession.inputs\n        for input in currentInputs {\n          strongSelf.captureSession.removeInput(input)\n        }\n\n        let input = try AVCaptureDeviceInput(device: device)\n        guard strongSelf.captureSession.canAddInput(input) else {\n          print(\"Failed to add capture session input.\")\n          return\n        }\n        strongSelf.captureSession.addInput(input)\n        strongSelf.captureSession.commitConfiguration()\n      } catch {\n        print(\"Failed to create capture device input: \\(error.localizedDescription)\")\n      }\n    }\n  }\n\n  private func startSession() {\n    weak var weakSelf = self\n    sessionQueue.async {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.captureSession.startRunning()\n    }\n  }\n\n  private func stopSession() {\n    weak var weakSelf = self\n    sessionQueue.async {\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      strongSelf.captureSession.stopRunning()\n    }\n  }\n\n  private func setUpPreviewOverlayView() {\n    cameraView.addSubview(previewOverlayView)\n    NSLayoutConstraint.activate([\n      previewOverlayView.centerXAnchor.constraint(equalTo: cameraView.centerXAnchor),\n      previewOverlayView.centerYAnchor.constraint(equalTo: cameraView.centerYAnchor),\n      previewOverlayView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor),\n      previewOverlayView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor),\n\n    ])\n  }\n\n  private func setUpAnnotationOverlayView() {\n    cameraView.addSubview(annotationOverlayView)\n    NSLayoutConstraint.activate([\n      annotationOverlayView.topAnchor.constraint(equalTo: cameraView.topAnchor),\n      annotationOverlayView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor),\n      annotationOverlayView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor),\n      annotationOverlayView.bottomAnchor.constraint(equalTo: cameraView.bottomAnchor),\n    ])\n  }\n\n  private func captureDevice(forPosition position: AVCaptureDevice.Position) -> AVCaptureDevice? {\n    if #available(iOS 10.0, *) {\n      let discoverySession = AVCaptureDevice.DiscoverySession(\n        deviceTypes: [.builtInWideAngleCamera],\n        mediaType: .video,\n        position: .unspecified\n      )\n      return discoverySession.devices.first { $0.position == position }\n    }\n    return nil\n  }\n\n  private func presentDetectorsAlertController() {\n    let alertController = UIAlertController(\n      title: Constant.alertControllerTitle,\n      message: Constant.alertControllerMessage,\n      preferredStyle: .alert\n    )\n    weak var weakSelf = self\n    detectors.forEach { detectorType in\n      let action = UIAlertAction(title: detectorType.rawValue, style: .default) {\n        [unowned self] (action) in\n        guard let value = action.title else { return }\n        guard let detector = Detector(rawValue: value) else { return }\n        guard let strongSelf = weakSelf else {\n          print(\"Self is nil!\")\n          return\n        }\n        strongSelf.currentDetector = detector\n        strongSelf.removeDetectionAnnotations()\n      }\n      if detectorType.rawValue == self.currentDetector.rawValue { action.isEnabled = false }\n      alertController.addAction(action)\n    }\n    alertController.addAction(UIAlertAction(title: Constant.cancelActionTitleText, style: .cancel))\n    present(alertController, animated: true)\n  }\n\n  private func removeDetectionAnnotations() {\n    for annotationView in annotationOverlayView.subviews {\n      annotationView.removeFromSuperview()\n    }\n  }\n\n  private func updatePreviewOverlayViewWithLastFrame() {\n    guard let lastFrame = lastFrame,\n      let imageBuffer = CMSampleBufferGetImageBuffer(lastFrame)\n    else {\n      return\n    }\n    self.updatePreviewOverlayViewWithImageBuffer(imageBuffer)\n    self.removeDetectionAnnotations()\n  }\n\n  private func updatePreviewOverlayViewWithImageBuffer(_ imageBuffer: CVImageBuffer?) {\n    guard let imageBuffer = imageBuffer else {\n      return\n    }\n    let orientation: UIImage.Orientation = isUsingFrontCamera ? .leftMirrored : .right\n    let image = UIUtilities.createUIImage(from: imageBuffer, orientation: orientation)\n    previewOverlayView.image = image\n  }\n\n  private func convertedPoints(\n    from points: [NSValue]?,\n    width: CGFloat,\n    height: CGFloat\n  ) -> [NSValue]? {\n    return points?.map {\n      let cgPointValue = $0.cgPointValue\n      let normalizedPoint = CGPoint(x: cgPointValue.x / width, y: cgPointValue.y / height)\n      let cgPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: normalizedPoint)\n      let value = NSValue(cgPoint: cgPoint)\n      return value\n    }\n  }\n\n  private func normalizedPoint(\n    fromVisionPoint point: VisionPoint,\n    width: CGFloat,\n    height: CGFloat\n  ) -> CGPoint {\n    let cgPoint = CGPoint(x: point.x, y: point.y)\n    var normalizedPoint = CGPoint(x: cgPoint.x / width, y: cgPoint.y / height)\n    normalizedPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: normalizedPoint)\n    return normalizedPoint\n  }\n\n  private func addContours(for face: Face, width: CGFloat, height: CGFloat) {\n    // Face\n    if let faceContour = face.contour(ofType: .face) {\n      for point in faceContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.blue,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n\n    // Eyebrows\n    if let topLeftEyebrowContour = face.contour(ofType: .leftEyebrowTop) {\n      for point in topLeftEyebrowContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.orange,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n    if let bottomLeftEyebrowContour = face.contour(ofType: .leftEyebrowBottom) {\n      for point in bottomLeftEyebrowContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.orange,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n    if let topRightEyebrowContour = face.contour(ofType: .rightEyebrowTop) {\n      for point in topRightEyebrowContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.orange,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n    if let bottomRightEyebrowContour = face.contour(ofType: .rightEyebrowBottom) {\n      for point in bottomRightEyebrowContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.orange,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n\n    // Eyes\n    if let leftEyeContour = face.contour(ofType: .leftEye) {\n      for point in leftEyeContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.cyan,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n    if let rightEyeContour = face.contour(ofType: .rightEye) {\n      for point in rightEyeContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.cyan,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n\n    // Lips\n    if let topUpperLipContour = face.contour(ofType: .upperLipTop) {\n      for point in topUpperLipContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.red,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n    if let bottomUpperLipContour = face.contour(ofType: .upperLipBottom) {\n      for point in bottomUpperLipContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.red,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n    if let topLowerLipContour = face.contour(ofType: .lowerLipTop) {\n      for point in topLowerLipContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.red,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n    if let bottomLowerLipContour = face.contour(ofType: .lowerLipBottom) {\n      for point in bottomLowerLipContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.red,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n\n    // Nose\n    if let noseBridgeContour = face.contour(ofType: .noseBridge) {\n      for point in noseBridgeContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n    if let noseBottomContour = face.contour(ofType: .noseBottom) {\n      for point in noseBottomContour.points {\n        let cgPoint = normalizedPoint(fromVisionPoint: point, width: width, height: height)\n        UIUtilities.addCircle(\n          atPoint: cgPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constant.smallDotRadius\n        )\n      }\n    }\n  }\n\n  /// Resets any detector instances which use a conventional lifecycle paradigm. This method is\n  /// expected to be invoked on the AVCaptureOutput queue - the same queue on which detection is\n  /// run.\n  private func resetManagedLifecycleDetectors(activeDetector: Detector) {\n    if activeDetector == self.lastDetector {\n      // Same row as before, no need to reset any detectors.\n      return\n    }\n    // Clear the old detector, if applicable.\n    switch self.lastDetector {\n    case .pose, .poseAccurate:\n      self.poseDetector = nil\n      break\n    case .segmentationSelfie:\n      self.segmenter = nil\n      break\n    default:\n      break\n    }\n    // Initialize the new detector, if applicable.\n    switch activeDetector {\n    case .pose, .poseAccurate:\n      // The `options.detectorMode` defaults to `.stream`\n      let options = activeDetector == .pose ? PoseDetectorOptions() : AccuratePoseDetectorOptions()\n      self.poseDetector = PoseDetector.poseDetector(options: options)\n      break\n    case .segmentationSelfie:\n      // The `options.segmenterMode` defaults to `.stream`\n      let options = SelfieSegmenterOptions()\n      self.segmenter = Segmenter.segmenter(options: options)\n      break\n    default:\n      break\n    }\n    self.lastDetector = activeDetector\n  }\n\n  private func rotate(_ view: UIView, orientation: UIImage.Orientation) {\n    var degree: CGFloat = 0.0\n    switch orientation {\n    case .up, .upMirrored:\n      degree = 90.0\n    case .rightMirrored, .left:\n      degree = 180.0\n    case .down, .downMirrored:\n      degree = 270.0\n    case .leftMirrored, .right:\n      degree = 0.0\n    }\n    view.transform = CGAffineTransform.init(rotationAngle: degree * 3.141592654 / 180)\n  }\n}\n\n// MARK: AVCaptureVideoDataOutputSampleBufferDelegate\n\nextension CameraViewController: AVCaptureVideoDataOutputSampleBufferDelegate {\n\n  func captureOutput(\n    _ output: AVCaptureOutput,\n    didOutput sampleBuffer: CMSampleBuffer,\n    from connection: AVCaptureConnection\n  ) {\n    guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {\n      print(\"Failed to get image buffer from sample buffer.\")\n      return\n    }\n    // Evaluate `self.currentDetector` once to ensure consistency throughout this method since it\n    // can be concurrently modified from the main thread.\n    let activeDetector = self.currentDetector\n    resetManagedLifecycleDetectors(activeDetector: activeDetector)\n\n    lastFrame = sampleBuffer\n    let visionImage = VisionImage(buffer: sampleBuffer)\n    let orientation = UIUtilities.imageOrientation(\n      fromDevicePosition: isUsingFrontCamera ? .front : .back\n    )\n    visionImage.orientation = orientation\n\n    guard let inputImage = MLImage(sampleBuffer: sampleBuffer) else {\n      print(\"Failed to create MLImage from sample buffer.\")\n      return\n    }\n    inputImage.orientation = orientation\n\n    let imageWidth = CGFloat(CVPixelBufferGetWidth(imageBuffer))\n    let imageHeight = CGFloat(CVPixelBufferGetHeight(imageBuffer))\n    var shouldEnableClassification = false\n    var shouldEnableMultipleObjects = false\n    switch activeDetector {\n    case .onDeviceObjectProminentWithClassifier, .onDeviceObjectMultipleWithClassifier,\n      .onDeviceObjectCustomProminentWithClassifier, .onDeviceObjectCustomMultipleWithClassifier:\n      shouldEnableClassification = true\n    default:\n      break\n    }\n    switch activeDetector {\n    case .onDeviceObjectMultipleNoClassifier, .onDeviceObjectMultipleWithClassifier,\n      .onDeviceObjectCustomMultipleNoClassifier, .onDeviceObjectCustomMultipleWithClassifier:\n      shouldEnableMultipleObjects = true\n    default:\n      break\n    }\n\n    switch activeDetector {\n    case .onDeviceBarcode:\n      scanBarcodesOnDevice(in: visionImage, width: imageWidth, height: imageHeight)\n    case .onDeviceFace:\n      detectFacesOnDevice(in: visionImage, width: imageWidth, height: imageHeight)\n    case .onDeviceText, .onDeviceTextChinese, .onDeviceTextDevanagari, .onDeviceTextJapanese,\n      .onDeviceTextKorean:\n      recognizeTextOnDevice(\n        in: visionImage, width: imageWidth, height: imageHeight, detectorType: activeDetector)\n    case .onDeviceImageLabel:\n      detectLabels(\n        in: visionImage, width: imageWidth, height: imageHeight, shouldUseCustomModel: false)\n    case .onDeviceImageLabelsCustom:\n      detectLabels(\n        in: visionImage, width: imageWidth, height: imageHeight, shouldUseCustomModel: true)\n    case .onDeviceObjectProminentNoClassifier, .onDeviceObjectProminentWithClassifier,\n      .onDeviceObjectMultipleNoClassifier, .onDeviceObjectMultipleWithClassifier:\n      // The `options.detectorMode` defaults to `.stream`\n      let options = ObjectDetectorOptions()\n      options.shouldEnableClassification = shouldEnableClassification\n      options.shouldEnableMultipleObjects = shouldEnableMultipleObjects\n      detectObjectsOnDevice(\n        in: visionImage,\n        width: imageWidth,\n        height: imageHeight,\n        options: options)\n    case .onDeviceObjectCustomProminentNoClassifier, .onDeviceObjectCustomProminentWithClassifier,\n      .onDeviceObjectCustomMultipleNoClassifier, .onDeviceObjectCustomMultipleWithClassifier:\n      guard\n        let localModelFilePath = Bundle.main.path(\n          forResource: Constant.localModelFile.name,\n          ofType: Constant.localModelFile.type\n        )\n      else {\n        print(\"Failed to find custom local model file.\")\n        return\n      }\n      let localModel = LocalModel(path: localModelFilePath)\n      // The `options.detectorMode` defaults to `.stream`\n      let options = CustomObjectDetectorOptions(localModel: localModel)\n      options.shouldEnableClassification = shouldEnableClassification\n      options.shouldEnableMultipleObjects = shouldEnableMultipleObjects\n      detectObjectsOnDevice(\n        in: visionImage,\n        width: imageWidth,\n        height: imageHeight,\n        options: options)\n\n    case .pose, .poseAccurate:\n      detectPose(in: inputImage, width: imageWidth, height: imageHeight)\n    case .segmentationSelfie:\n      detectSegmentationMask(in: visionImage, sampleBuffer: sampleBuffer)\n    }\n  }\n}\n\n// MARK: - Constants\n\npublic enum Detector: String {\n  case onDeviceBarcode = \"Barcode Scanning\"\n  case onDeviceFace = \"Face Detection\"\n  case onDeviceText = \"Text Recognition\"\n  case onDeviceTextChinese = \"Text Recognition Chinese\"\n  case onDeviceTextDevanagari = \"Text Recognition Devanagari\"\n  case onDeviceTextJapanese = \"Text Recognition Japanese\"\n  case onDeviceTextKorean = \"Text Recognition Korean\"\n  case onDeviceImageLabel = \"Image Labeling\"\n  case onDeviceImageLabelsCustom = \"Image Labeling Custom\"\n  case onDeviceObjectProminentNoClassifier = \"ODT, single, no labeling\"\n  case onDeviceObjectProminentWithClassifier = \"ODT, single, labeling\"\n  case onDeviceObjectMultipleNoClassifier = \"ODT, multiple, no labeling\"\n  case onDeviceObjectMultipleWithClassifier = \"ODT, multiple, labeling\"\n  case onDeviceObjectCustomProminentNoClassifier = \"ODT, custom, single, no labeling\"\n  case onDeviceObjectCustomProminentWithClassifier = \"ODT, custom, single, labeling\"\n  case onDeviceObjectCustomMultipleNoClassifier = \"ODT, custom, multiple, no labeling\"\n  case onDeviceObjectCustomMultipleWithClassifier = \"ODT, custom, multiple, labeling\"\n  case pose = \"Pose Detection\"\n  case poseAccurate = \"Pose Detection, accurate\"\n  case segmentationSelfie = \"Selfie Segmentation\"\n}\n\nprivate enum Constant {\n  static let alertControllerTitle = \"Vision Detectors\"\n  static let alertControllerMessage = \"Select a detector\"\n  static let cancelActionTitleText = \"Cancel\"\n  static let videoDataOutputQueueLabel = \"com.google.mlkit.visiondetector.VideoDataOutputQueue\"\n  static let sessionQueueLabel = \"com.google.mlkit.visiondetector.SessionQueue\"\n  static let noResultsMessage = \"No Results\"\n  static let localModelFile = (name: \"bird\", type: \"tflite\")\n  static let labelConfidenceThreshold = 0.75\n  static let smallDotRadius: CGFloat = 4.0\n  static let lineWidth: CGFloat = 3.0\n  static let originalScale: CGFloat = 1.0\n  static let padding: CGFloat = 10.0\n  static let resultsLabelHeight: CGFloat = 200.0\n  static let resultsLabelLines = 5\n  static let imageLabelResultFrameX = 0.4\n  static let imageLabelResultFrameY = 0.1\n  static let imageLabelResultFrameWidth = 0.5\n  static let imageLabelResultFrameHeight = 0.8\n  static let segmentationMaskAlpha: CGFloat = 0.5\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string>We use the data from the camera for the image recognition.</string>\n\t<key>NSPhotoLibraryUsageDescription</key>\n\t<string>We use the data from the photo library for the image recognition.</string>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample/MLKitExtensions.swift",
    "content": "import CoreGraphics\nimport UIKit\n\n// MARK: - UIImage\n\nextension UIImage {\n\n  /// Creates and returns a new image scaled to the given size. The image preserves its original PNG\n  /// or JPEG bitmap info.\n  ///\n  /// - Parameter size: The size to scale the image to.\n  /// - Returns: The scaled image or `nil` if image could not be resized.\n  public func scaledImage(with size: CGSize) -> UIImage? {\n    UIGraphicsBeginImageContextWithOptions(size, false, scale)\n    defer { UIGraphicsEndImageContext() }\n    draw(in: CGRect(origin: .zero, size: size))\n    return UIGraphicsGetImageFromCurrentImageContext()?.data.flatMap(UIImage.init)\n  }\n\n  // MARK: - Private\n\n  /// The PNG or JPEG data representation of the image or `nil` if the conversion failed.\n  private var data: Data? {\n    #if swift(>=4.2)\n      return self.pngData() ?? self.jpegData(compressionQuality: Constant.jpegCompressionQuality)\n    #else\n      return self.pngData() ?? self.jpegData(compressionQuality: Constant.jpegCompressionQuality)\n    #endif  // swift(>=4.2)\n  }\n}\n\n// MARK: - Constants\n\nprivate enum Constant {\n  static let jpegCompressionQuality: CGFloat = 0.8\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample/UIUtilities.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport AVFoundation\nimport CoreVideo\nimport MLKit\nimport UIKit\n\n/// Defines UI-related utilitiy methods for vision detection.\npublic class UIUtilities {\n\n  // MARK: - Public\n\n  public static func addCircle(\n    atPoint point: CGPoint,\n    to view: UIView,\n    color: UIColor,\n    radius: CGFloat\n  ) {\n    let divisor: CGFloat = 2.0\n    let xCoord = point.x - radius / divisor\n    let yCoord = point.y - radius / divisor\n    let circleRect = CGRect(x: xCoord, y: yCoord, width: radius, height: radius)\n    guard circleRect.isValid() else { return }\n    let circleView = UIView(frame: circleRect)\n    circleView.layer.cornerRadius = radius / divisor\n    circleView.alpha = Constants.circleViewAlpha\n    circleView.backgroundColor = color\n    circleView.isAccessibilityElement = true\n    circleView.accessibilityIdentifier = Constants.circleViewIdentifier\n    view.addSubview(circleView)\n  }\n\n  public static func addLineSegment(\n    fromPoint: CGPoint, toPoint: CGPoint, inView: UIView, color: UIColor, width: CGFloat\n  ) {\n    let path = UIBezierPath()\n    path.move(to: fromPoint)\n    path.addLine(to: toPoint)\n    let lineLayer = CAShapeLayer()\n    lineLayer.path = path.cgPath\n    lineLayer.strokeColor = color.cgColor\n    lineLayer.fillColor = nil\n    lineLayer.opacity = 1.0\n    lineLayer.lineWidth = width\n    let lineView = UIView()\n    lineView.layer.addSublayer(lineLayer)\n    lineView.isAccessibilityElement = true\n    lineView.accessibilityIdentifier = Constants.lineViewIdentifier\n    inView.addSubview(lineView)\n  }\n\n  public static func addRectangle(_ rectangle: CGRect, to view: UIView, color: UIColor) {\n    guard rectangle.isValid() else { return }\n    let rectangleView = UIView(frame: rectangle)\n    rectangleView.layer.cornerRadius = Constants.rectangleViewCornerRadius\n    rectangleView.alpha = Constants.rectangleViewAlpha\n    rectangleView.backgroundColor = color\n    rectangleView.isAccessibilityElement = true\n    rectangleView.accessibilityIdentifier = Constants.rectangleViewIdentifier\n    view.addSubview(rectangleView)\n  }\n\n  public static func addShape(withPoints points: [NSValue]?, to view: UIView, color: UIColor) {\n    guard let points = points else { return }\n    let path = UIBezierPath()\n    for (index, value) in points.enumerated() {\n      let point = value.cgPointValue\n      if index == 0 {\n        path.move(to: point)\n      } else {\n        path.addLine(to: point)\n      }\n      if index == points.count - 1 {\n        path.close()\n      }\n    }\n    let shapeLayer = CAShapeLayer()\n    shapeLayer.path = path.cgPath\n    shapeLayer.fillColor = color.cgColor\n    let rect = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)\n    let shapeView = UIView(frame: rect)\n    shapeView.alpha = Constants.shapeViewAlpha\n    shapeView.layer.addSublayer(shapeLayer)\n    view.addSubview(shapeView)\n  }\n\n  public static func imageOrientation(\n    fromDevicePosition devicePosition: AVCaptureDevice.Position = .back\n  ) -> UIImage.Orientation {\n    var deviceOrientation = UIDevice.current.orientation\n    if deviceOrientation == .faceDown || deviceOrientation == .faceUp\n      || deviceOrientation\n        == .unknown\n    {\n      deviceOrientation = currentUIOrientation()\n    }\n    switch deviceOrientation {\n    case .portrait:\n      return devicePosition == .front ? .leftMirrored : .right\n    case .landscapeLeft:\n      return devicePosition == .front ? .downMirrored : .up\n    case .portraitUpsideDown:\n      return devicePosition == .front ? .rightMirrored : .left\n    case .landscapeRight:\n      return devicePosition == .front ? .upMirrored : .down\n    case .faceDown, .faceUp, .unknown:\n      return .up\n    @unknown default:\n      fatalError()\n    }\n  }\n\n  /// Applies a segmentation mask to an image buffer by replacing colors in the segmented regions.\n  ///\n  /// @param The mask output from a segmentation operation.\n  /// @param imageBuffer The image buffer on which segmentation was performed. Must have pixel\n  ///     format type `kCVPixelFormatType_32BGRA`.\n  /// @param backgroundColor Optional color to render into the background region (i.e. outside of\n  ///    the segmented region of interest).\n  /// @param foregroundColor Optional color to render into the foreground region (i.e. inside the\n  ///     segmented region of interest).\n  public static func applySegmentationMask(\n    mask: SegmentationMask, to imageBuffer: CVImageBuffer,\n    backgroundColor: UIColor?, foregroundColor: UIColor?\n  ) {\n    assert(\n      CVPixelBufferGetPixelFormatType(imageBuffer) == kCVPixelFormatType_32BGRA,\n      \"Image buffer must have 32BGRA pixel format type\")\n\n    let width = CVPixelBufferGetWidth(mask.buffer)\n    let height = CVPixelBufferGetHeight(mask.buffer)\n    assert(CVPixelBufferGetWidth(imageBuffer) == width, \"Width must match\")\n    assert(CVPixelBufferGetHeight(imageBuffer) == height, \"Height must match\")\n\n    if backgroundColor == nil && foregroundColor == nil {\n      return\n    }\n\n    let writeFlags = CVPixelBufferLockFlags(rawValue: 0)\n    CVPixelBufferLockBaseAddress(imageBuffer, writeFlags)\n    CVPixelBufferLockBaseAddress(mask.buffer, CVPixelBufferLockFlags.readOnly)\n\n    let maskBytesPerRow = CVPixelBufferGetBytesPerRow(mask.buffer)\n    var maskAddress =\n      CVPixelBufferGetBaseAddress(mask.buffer)!.bindMemory(\n        to: Float32.self, capacity: maskBytesPerRow * height)\n\n    let imageBytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)\n    var imageAddress = CVPixelBufferGetBaseAddress(imageBuffer)!.bindMemory(\n      to: UInt8.self, capacity: imageBytesPerRow * height)\n\n    var redFG: CGFloat = 0.0\n    var greenFG: CGFloat = 0.0\n    var blueFG: CGFloat = 0.0\n    var alphaFG: CGFloat = 0.0\n    var redBG: CGFloat = 0.0\n    var greenBG: CGFloat = 0.0\n    var blueBG: CGFloat = 0.0\n    var alphaBG: CGFloat = 0.0\n\n    let backgroundColor = backgroundColor != nil ? backgroundColor : .clear\n    let foregroundColor = foregroundColor != nil ? foregroundColor : .clear\n    backgroundColor!.getRed(&redBG, green: &greenBG, blue: &blueBG, alpha: &alphaBG)\n    foregroundColor!.getRed(&redFG, green: &greenFG, blue: &blueFG, alpha: &alphaFG)\n\n    for _ in 0...(height - 1) {\n      for col in 0...(width - 1) {\n        let pixelOffset = col * Constants.bgraBytesPerPixel\n        let blueOffset = pixelOffset\n        let greenOffset = pixelOffset + 1\n        let redOffset = pixelOffset + 2\n        let alphaOffset = pixelOffset + 3\n\n        let maskValue: CGFloat = CGFloat(maskAddress[col])\n        let backgroundRegionRatio: CGFloat = 1.0 - maskValue\n        let foregroundRegionRatio = maskValue\n\n        let originalPixelRed: CGFloat =\n          CGFloat(imageAddress[redOffset]) / Constants.maxColorComponentValue\n        let originalPixelGreen: CGFloat =\n          CGFloat(imageAddress[greenOffset]) / Constants.maxColorComponentValue\n        let originalPixelBlue: CGFloat =\n          CGFloat(imageAddress[blueOffset]) / Constants.maxColorComponentValue\n        let originalPixelAlpha: CGFloat =\n          CGFloat(imageAddress[alphaOffset]) / Constants.maxColorComponentValue\n\n        let redOverlay = redBG * backgroundRegionRatio + redFG * foregroundRegionRatio\n        let greenOverlay = greenBG * backgroundRegionRatio + greenFG * foregroundRegionRatio\n        let blueOverlay = blueBG * backgroundRegionRatio + blueFG * foregroundRegionRatio\n        let alphaOverlay = alphaBG * backgroundRegionRatio + alphaFG * foregroundRegionRatio\n\n        // Calculate composite color component values.\n        // Derived from https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending\n        let compositeAlpha: CGFloat = ((1.0 - alphaOverlay) * originalPixelAlpha) + alphaOverlay\n        var compositeRed: CGFloat = 0.0\n        var compositeGreen: CGFloat = 0.0\n        var compositeBlue: CGFloat = 0.0\n        // Only perform rgb blending calculations if the output alpha is > 0. A zero-value alpha\n        // means none of the color channels actually matter, and would introduce division by 0.\n        if abs(compositeAlpha) > CGFloat(Float.ulpOfOne) {\n          compositeRed =\n            (((1.0 - alphaOverlay) * originalPixelAlpha * originalPixelRed)\n              + (alphaOverlay * redOverlay)) / compositeAlpha\n          compositeGreen =\n            (((1.0 - alphaOverlay) * originalPixelAlpha * originalPixelGreen)\n              + (alphaOverlay * greenOverlay)) / compositeAlpha\n          compositeBlue =\n            (((1.0 - alphaOverlay) * originalPixelAlpha * originalPixelBlue)\n              + (alphaOverlay * blueOverlay)) / compositeAlpha\n        }\n\n        imageAddress[redOffset] = UInt8(compositeRed * Constants.maxColorComponentValue)\n        imageAddress[greenOffset] = UInt8(compositeGreen * Constants.maxColorComponentValue)\n        imageAddress[blueOffset] = UInt8(compositeBlue * Constants.maxColorComponentValue)\n      }\n\n      imageAddress += imageBytesPerRow / MemoryLayout<UInt8>.size\n      maskAddress += maskBytesPerRow / MemoryLayout<Float32>.size\n    }\n\n    CVPixelBufferUnlockBaseAddress(imageBuffer, writeFlags)\n    CVPixelBufferUnlockBaseAddress(mask.buffer, CVPixelBufferLockFlags.readOnly)\n  }\n\n  /// Converts an image buffer to a `UIImage`.\n  ///\n  /// @param imageBuffer The image buffer which should be converted.\n  /// @param orientation The orientation already applied to the image.\n  /// @return A new `UIImage` instance.\n  public static func createUIImage(\n    from imageBuffer: CVImageBuffer,\n    orientation: UIImage.Orientation\n  ) -> UIImage? {\n    let ciImage = CIImage(cvPixelBuffer: imageBuffer)\n    let context = CIContext(options: nil)\n    guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else { return nil }\n    return UIImage(cgImage: cgImage, scale: Constants.originalScale, orientation: orientation)\n  }\n\n  /// Converts a `UIImage` to an image buffer.\n  ///\n  /// @param image The `UIImage` which should be converted.\n  /// @return The image buffer. Callers own the returned buffer and are responsible for releasing it\n  ///     when it is no longer needed. Additionally, the image orientation will not be accounted for\n  ///     in the returned buffer, so callers must keep track of the orientation separately.\n  public static func createImageBuffer(from image: UIImage) -> CVImageBuffer? {\n    guard let cgImage = image.cgImage else { return nil }\n    let width = cgImage.width\n    let height = cgImage.height\n\n    var buffer: CVPixelBuffer? = nil\n    CVPixelBufferCreate(\n      kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, nil,\n      &buffer)\n    guard let imageBuffer = buffer else { return nil }\n\n    let flags = CVPixelBufferLockFlags(rawValue: 0)\n    CVPixelBufferLockBaseAddress(imageBuffer, flags)\n    let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer)\n    let colorSpace = CGColorSpaceCreateDeviceRGB()\n    let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)\n    let context = CGContext(\n      data: baseAddress, width: width, height: height, bitsPerComponent: 8,\n      bytesPerRow: bytesPerRow, space: colorSpace,\n      bitmapInfo: (CGImageAlphaInfo.premultipliedFirst.rawValue\n        | CGBitmapInfo.byteOrder32Little.rawValue))\n\n    if let context = context {\n      let rect = CGRect.init(x: 0, y: 0, width: width, height: height)\n      context.draw(cgImage, in: rect)\n      CVPixelBufferUnlockBaseAddress(imageBuffer, flags)\n      return imageBuffer\n    } else {\n      CVPixelBufferUnlockBaseAddress(imageBuffer, flags)\n      return nil\n    }\n  }\n\n  /// Creates a pose overlay view for visualizing a given `pose`.\n  ///\n  /// - Parameters:\n  ///   - pose: The pose which will be visualized.\n  ///   - bounds: The bounds of the view to which this overlay will be added. The overlay view's\n  ///         bounds will match this value.\n  ///   - lineWidth: The width of the lines connecting the landmark dots.\n  ///   - dotRadius: The radius of the landmark dots.\n  ///   - positionTransformationClosure: Closure which transforms a landmark `position` to the\n  ///         `UIView` `CGPoint` coordinate where it should be shown on-screen.\n  /// - Returns: The pose overlay view.\n  public static func createPoseOverlayView(\n    forPose pose: Pose, inViewWithBounds bounds: CGRect, lineWidth: CGFloat, dotRadius: CGFloat,\n    positionTransformationClosure: (VisionPoint) -> CGPoint\n  ) -> UIView {\n    let overlayView = UIView(frame: bounds)\n\n    let lowerBodyHeight: CGFloat =\n      UIUtilities.distance(\n        fromPoint: pose.landmark(ofType: PoseLandmarkType.leftAnkle).position,\n        toPoint: pose.landmark(ofType: PoseLandmarkType.leftKnee).position)\n      + UIUtilities.distance(\n        fromPoint: pose.landmark(ofType: PoseLandmarkType.leftKnee).position,\n        toPoint: pose.landmark(ofType: PoseLandmarkType.leftHip).position)\n\n    // Pick arbitrary z extents to form a range of z values mapped to our colors. Red = close, blue\n    // = far. Assume that the z values will roughly follow physical extents of the human body, but\n    // apply an adjustment ratio to increase this color-coded z-range because this is not always the\n    // case.\n    let adjustmentRatio: CGFloat = 1.2\n    let nearZExtent: CGFloat = -lowerBodyHeight * adjustmentRatio\n    let farZExtent: CGFloat = lowerBodyHeight * adjustmentRatio\n    let zColorRange: CGFloat = farZExtent - nearZExtent\n    let nearZColor = UIColor.red\n    let farZColor = UIColor.blue\n\n    for (startLandmarkType, endLandmarkTypesArray) in UIUtilities.poseConnections() {\n      let startLandmark = pose.landmark(ofType: startLandmarkType)\n      for endLandmarkType in endLandmarkTypesArray {\n        let endLandmark = pose.landmark(ofType: endLandmarkType)\n        let startLandmarkPoint = positionTransformationClosure(startLandmark.position)\n        let endLandmarkPoint = positionTransformationClosure(endLandmark.position)\n\n        let landmarkZRatio = (startLandmark.position.z - nearZExtent) / zColorRange\n        let connectedLandmarkZRatio = (endLandmark.position.z - nearZExtent) / zColorRange\n\n        let startColor = UIUtilities.interpolatedColor(\n          fromColor: nearZColor, toColor: farZColor, ratio: landmarkZRatio)\n        let endColor = UIUtilities.interpolatedColor(\n          fromColor: nearZColor, toColor: farZColor, ratio: connectedLandmarkZRatio)\n\n        UIUtilities.addLineSegment(\n          fromPoint: startLandmarkPoint,\n          toPoint: endLandmarkPoint,\n          inView: overlayView,\n          colors: [startColor, endColor],\n          width: lineWidth)\n      }\n    }\n    for landmark in pose.landmarks {\n      let landmarkPoint = positionTransformationClosure(landmark.position)\n      UIUtilities.addCircle(\n        atPoint: landmarkPoint,\n        to: overlayView,\n        color: UIColor.blue,\n        radius: dotRadius\n      )\n    }\n    return overlayView\n  }\n\n  /// Adds a gradient-colored line segment subview in a given `view`.\n  ///\n  /// - Parameters:\n  ///   - fromPoint: The starting point of the line, in the view's coordinate space.\n  ///   - toPoint: The end point of the line, in the view's coordinate space.\n  ///   - inView: The view to which the line should be added as a subview.\n  ///   - colors: The colors that the gradient should traverse over. Must be non-empty.\n  ///   - width: The width of the line segment.\n  private static func addLineSegment(\n    fromPoint: CGPoint, toPoint: CGPoint, inView: UIView, colors: [UIColor], width: CGFloat\n  ) {\n    let viewWidth = inView.bounds.width\n    let viewHeight = inView.bounds.height\n    if viewWidth == 0.0 || viewHeight == 0.0 {\n      return\n    }\n    let path = UIBezierPath()\n    path.move(to: fromPoint)\n    path.addLine(to: toPoint)\n    let lineMaskLayer = CAShapeLayer()\n    lineMaskLayer.path = path.cgPath\n    lineMaskLayer.strokeColor = UIColor.black.cgColor\n    lineMaskLayer.fillColor = nil\n    lineMaskLayer.opacity = 1.0\n    lineMaskLayer.lineWidth = width\n\n    let gradientLayer = CAGradientLayer()\n    gradientLayer.startPoint = CGPoint(x: fromPoint.x / viewWidth, y: fromPoint.y / viewHeight)\n    gradientLayer.endPoint = CGPoint(x: toPoint.x / viewWidth, y: toPoint.y / viewHeight)\n    gradientLayer.frame = inView.bounds\n    var CGColors = [CGColor]()\n    for color in colors {\n      CGColors.append(color.cgColor)\n    }\n    if CGColors.count == 1 {\n      // Single-colored lines must still supply a start and end color for the gradient layer to\n      // render anything. Just add the single color to the colors list again to fulfill this\n      // requirement.\n      CGColors.append(colors[0].cgColor)\n    }\n    gradientLayer.colors = CGColors\n    gradientLayer.mask = lineMaskLayer\n\n    let lineView = UIView(frame: inView.bounds)\n    lineView.layer.addSublayer(gradientLayer)\n    lineView.isAccessibilityElement = true\n    lineView.accessibilityIdentifier = Constants.lineViewIdentifier\n    inView.addSubview(lineView)\n  }\n\n  /// Returns a color interpolated between to other colors.\n  ///\n  /// - Parameters:\n  ///   - fromColor: The start color of the interpolation.\n  ///   - toColor: The end color of the interpolation.\n  ///   - ratio: The ratio in range [0, 1] by which the colors should be interpolated. Passing 0\n  ///         results in `fromColor` and passing 1 results in `toColor`, whereas passing 0.5 results\n  ///         in a color that is half-way between `fromColor` and `startColor`. Values are clamped\n  ///         between 0 and 1.\n  /// - Returns: The interpolated color.\n  private static func interpolatedColor(\n    fromColor: UIColor, toColor: UIColor, ratio: CGFloat\n  ) -> UIColor {\n    var fromR: CGFloat = 0\n    var fromG: CGFloat = 0\n    var fromB: CGFloat = 0\n    var fromA: CGFloat = 0\n    fromColor.getRed(&fromR, green: &fromG, blue: &fromB, alpha: &fromA)\n\n    var toR: CGFloat = 0\n    var toG: CGFloat = 0\n    var toB: CGFloat = 0\n    var toA: CGFloat = 0\n    toColor.getRed(&toR, green: &toG, blue: &toB, alpha: &toA)\n\n    let clampedRatio = max(0.0, min(ratio, 1.0))\n\n    let interpolatedR = fromR + (toR - fromR) * clampedRatio\n    let interpolatedG = fromG + (toG - fromG) * clampedRatio\n    let interpolatedB = fromB + (toB - fromB) * clampedRatio\n    let interpolatedA = fromA + (toA - fromA) * clampedRatio\n\n    return UIColor(\n      red: interpolatedR, green: interpolatedG, blue: interpolatedB, alpha: interpolatedA)\n  }\n\n  /// Returns the distance between two 3D points.\n  ///\n  /// - Parameters:\n  ///   - fromPoint: The starting point.\n  ///   - toPoint: The end point.\n  /// - Returns: The distance.\n  private static func distance(fromPoint: Vision3DPoint, toPoint: Vision3DPoint) -> CGFloat {\n    let xDiff = fromPoint.x - toPoint.x\n    let yDiff = fromPoint.y - toPoint.y\n    let zDiff = fromPoint.z - toPoint.z\n    return CGFloat(sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff))\n  }\n\n  // MARK: - Private\n\n  /// Returns the minimum subset of all connected pose landmarks. Each key represents a start\n  /// landmark, and each value in the key's value array represents an end landmark which is\n  /// connected to the start landmark. These connections may be used for visualizing the landmark\n  /// positions on a pose object.\n  private static func poseConnections() -> [PoseLandmarkType: [PoseLandmarkType]] {\n    struct PoseConnectionsHolder {\n      static var connections: [PoseLandmarkType: [PoseLandmarkType]] = [\n        PoseLandmarkType.leftEar: [PoseLandmarkType.leftEyeOuter],\n        PoseLandmarkType.leftEyeOuter: [PoseLandmarkType.leftEye],\n        PoseLandmarkType.leftEye: [PoseLandmarkType.leftEyeInner],\n        PoseLandmarkType.leftEyeInner: [PoseLandmarkType.nose],\n        PoseLandmarkType.nose: [PoseLandmarkType.rightEyeInner],\n        PoseLandmarkType.rightEyeInner: [PoseLandmarkType.rightEye],\n        PoseLandmarkType.rightEye: [PoseLandmarkType.rightEyeOuter],\n        PoseLandmarkType.rightEyeOuter: [PoseLandmarkType.rightEar],\n        PoseLandmarkType.mouthLeft: [PoseLandmarkType.mouthRight],\n        PoseLandmarkType.leftShoulder: [\n          PoseLandmarkType.rightShoulder,\n          PoseLandmarkType.leftHip,\n        ],\n        PoseLandmarkType.rightShoulder: [\n          PoseLandmarkType.rightHip,\n          PoseLandmarkType.rightElbow,\n        ],\n        PoseLandmarkType.rightWrist: [\n          PoseLandmarkType.rightElbow,\n          PoseLandmarkType.rightThumb,\n          PoseLandmarkType.rightIndexFinger,\n          PoseLandmarkType.rightPinkyFinger,\n        ],\n        PoseLandmarkType.leftHip: [PoseLandmarkType.rightHip, PoseLandmarkType.leftKnee],\n        PoseLandmarkType.rightHip: [PoseLandmarkType.rightKnee],\n        PoseLandmarkType.rightKnee: [PoseLandmarkType.rightAnkle],\n        PoseLandmarkType.leftKnee: [PoseLandmarkType.leftAnkle],\n        PoseLandmarkType.leftElbow: [PoseLandmarkType.leftShoulder],\n        PoseLandmarkType.leftWrist: [\n          PoseLandmarkType.leftElbow, PoseLandmarkType.leftThumb,\n          PoseLandmarkType.leftIndexFinger,\n          PoseLandmarkType.leftPinkyFinger,\n        ],\n        PoseLandmarkType.leftAnkle: [PoseLandmarkType.leftHeel, PoseLandmarkType.leftToe],\n        PoseLandmarkType.rightAnkle: [PoseLandmarkType.rightHeel, PoseLandmarkType.rightToe],\n        PoseLandmarkType.rightHeel: [PoseLandmarkType.rightToe],\n        PoseLandmarkType.leftHeel: [PoseLandmarkType.leftToe],\n        PoseLandmarkType.rightIndexFinger: [PoseLandmarkType.rightPinkyFinger],\n        PoseLandmarkType.leftIndexFinger: [PoseLandmarkType.leftPinkyFinger],\n      ]\n    }\n    return PoseConnectionsHolder.connections\n  }\n\n  private static func currentUIOrientation() -> UIDeviceOrientation {\n    let deviceOrientation = { () -> UIDeviceOrientation in\n      switch UIApplication.shared.statusBarOrientation {\n      case .landscapeLeft:\n        return .landscapeRight\n      case .landscapeRight:\n        return .landscapeLeft\n      case .portraitUpsideDown:\n        return .portraitUpsideDown\n      case .portrait, .unknown:\n        return .portrait\n      @unknown default:\n        fatalError()\n      }\n    }\n    guard Thread.isMainThread else {\n      var currentOrientation: UIDeviceOrientation = .portrait\n      DispatchQueue.main.sync {\n        currentOrientation = deviceOrientation()\n      }\n      return currentOrientation\n    }\n    return deviceOrientation()\n  }\n}\n\n// MARK: - Constants\n\nprivate enum Constants {\n  static let circleViewAlpha: CGFloat = 0.7\n  static let rectangleViewAlpha: CGFloat = 0.3\n  static let shapeViewAlpha: CGFloat = 0.3\n  static let rectangleViewCornerRadius: CGFloat = 10.0\n  static let maxColorComponentValue: CGFloat = 255.0\n  static let originalScale: CGFloat = 1.0\n  static let bgraBytesPerPixel = 4\n  static let circleViewIdentifier = \"MLKit Circle View\"\n  static let lineViewIdentifier = \"MLKit Line View\"\n  static let rectangleViewIdentifier = \"MLKit Rectangle View\"\n}\n\n// MARK: - Extension\n\nextension CGRect {\n  /// Returns a `Bool` indicating whether the rectangle's values are valid`.\n  func isValid() -> Bool {\n    return\n      !(origin.x.isNaN || origin.y.isNaN || width.isNaN || height.isNaN || width < 0 || height < 0)\n  }\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample/ViewController.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport MLImage\nimport MLKit\nimport UIKit\n\n/// Main view controller class.\n@objc(ViewController)\nclass ViewController: UIViewController, UINavigationControllerDelegate {\n\n  /// A string holding current results from detection.\n  var resultsText = \"\"\n\n  /// An overlay view that displays detection annotations.\n  private lazy var annotationOverlayView: UIView = {\n    precondition(isViewLoaded)\n    let annotationOverlayView = UIView(frame: .zero)\n    annotationOverlayView.translatesAutoresizingMaskIntoConstraints = false\n    annotationOverlayView.clipsToBounds = true\n    return annotationOverlayView\n  }()\n\n  /// An image picker for accessing the photo library or camera.\n  var imagePicker = UIImagePickerController()\n\n  // Image counter.\n  var currentImage = 0\n\n  /// Initialized when one of the pose detector rows are chosen. Reset to `nil` when neither are.\n  private var poseDetector: PoseDetector? = nil\n\n  /// Initialized when a segmentation row is chosen. Reset to `nil` otherwise.\n  private var segmenter: Segmenter? = nil\n\n  /// The detector row with which detection was most recently run. Useful for inferring when to\n  /// reset detector instances which use a conventional lifecyle paradigm.\n  private var lastDetectorRow: DetectorPickerRow?\n\n  // MARK: - IBOutlets\n\n  @IBOutlet fileprivate weak var detectorPicker: UIPickerView!\n\n  @IBOutlet fileprivate weak var imageView: UIImageView!\n  @IBOutlet fileprivate weak var photoCameraButton: UIBarButtonItem!\n  @IBOutlet fileprivate weak var videoCameraButton: UIBarButtonItem!\n  @IBOutlet weak var detectButton: UIBarButtonItem!\n\n  // MARK: - UIViewController\n\n  override func viewDidLoad() {\n    super.viewDidLoad()\n\n    imageView.image = UIImage(named: Constants.images[currentImage])\n    imageView.addSubview(annotationOverlayView)\n    NSLayoutConstraint.activate([\n      annotationOverlayView.topAnchor.constraint(equalTo: imageView.topAnchor),\n      annotationOverlayView.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),\n      annotationOverlayView.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),\n      annotationOverlayView.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),\n    ])\n\n    imagePicker.delegate = self\n    imagePicker.sourceType = .photoLibrary\n\n    detectorPicker.delegate = self\n    detectorPicker.dataSource = self\n\n    let isCameraAvailable =\n      UIImagePickerController.isCameraDeviceAvailable(.front)\n      || UIImagePickerController.isCameraDeviceAvailable(.rear)\n    if isCameraAvailable {\n      // `CameraViewController` uses `AVCaptureDevice.DiscoverySession` which is only supported for\n      // iOS 10 or newer.\n      if #available(iOS 10.0, *) {\n        videoCameraButton.isEnabled = true\n      }\n    } else {\n      photoCameraButton.isEnabled = false\n    }\n\n    let defaultRow = (DetectorPickerRow.rowsCount / 2) - 1\n    detectorPicker.selectRow(defaultRow, inComponent: 0, animated: false)\n  }\n\n  override func viewWillAppear(_ animated: Bool) {\n    super.viewWillAppear(animated)\n\n    navigationController?.navigationBar.isHidden = true\n  }\n\n  override func viewWillDisappear(_ animated: Bool) {\n    super.viewWillDisappear(animated)\n\n    navigationController?.navigationBar.isHidden = false\n  }\n\n  // MARK: - IBActions\n\n  @IBAction func detect(_ sender: Any) {\n    clearResults()\n    let row = detectorPicker.selectedRow(inComponent: 0)\n    if let rowIndex = DetectorPickerRow(rawValue: row) {\n      resetManagedLifecycleDetectors(activeDetectorRow: rowIndex)\n\n      let shouldEnableClassification =\n        (rowIndex == .detectObjectsProminentWithClassifier)\n        || (rowIndex == .detectObjectsMultipleWithClassifier)\n        || (rowIndex == .detectObjectsCustomProminentWithClassifier)\n        || (rowIndex == .detectObjectsCustomMultipleWithClassifier)\n      let shouldEnableMultipleObjects =\n        (rowIndex == .detectObjectsMultipleWithClassifier)\n        || (rowIndex == .detectObjectsMultipleNoClassifier)\n        || (rowIndex == .detectObjectsCustomMultipleWithClassifier)\n        || (rowIndex == .detectObjectsCustomMultipleNoClassifier)\n      switch rowIndex {\n      case .detectFaceOnDevice:\n        detectFaces(image: imageView.image)\n      case .detectTextOnDevice, .detectTextChineseOnDevice, .detectTextDevanagariOnDevice,\n        .detectTextJapaneseOnDevice, .detectTextKoreanOnDevice:\n        detectTextOnDevice(\n          image: imageView.image, detectorType: rowIndex)\n      case .detectBarcodeOnDevice:\n        detectBarcodes(image: imageView.image)\n      case .detectImageLabelsOnDevice:\n        detectLabels(image: imageView.image, shouldUseCustomModel: false)\n      case .detectImageLabelsCustomOnDevice:\n        detectLabels(image: imageView.image, shouldUseCustomModel: true)\n      case .detectObjectsProminentNoClassifier, .detectObjectsProminentWithClassifier,\n        .detectObjectsMultipleNoClassifier, .detectObjectsMultipleWithClassifier:\n        let options = ObjectDetectorOptions()\n        options.shouldEnableClassification = shouldEnableClassification\n        options.shouldEnableMultipleObjects = shouldEnableMultipleObjects\n        options.detectorMode = .singleImage\n        detectObjectsOnDevice(in: imageView.image, options: options)\n      case .detectObjectsCustomProminentNoClassifier, .detectObjectsCustomProminentWithClassifier,\n        .detectObjectsCustomMultipleNoClassifier, .detectObjectsCustomMultipleWithClassifier:\n        guard\n          let localModelFilePath = Bundle.main.path(\n            forResource: Constants.localModelFile.name,\n            ofType: Constants.localModelFile.type\n          )\n        else {\n          print(\"Failed to find custom local model file.\")\n          return\n        }\n        let localModel = LocalModel(path: localModelFilePath)\n        let options = CustomObjectDetectorOptions(localModel: localModel)\n        options.shouldEnableClassification = shouldEnableClassification\n        options.shouldEnableMultipleObjects = shouldEnableMultipleObjects\n        options.detectorMode = .singleImage\n        detectObjectsOnDevice(in: imageView.image, options: options)\n      case .detectPose, .detectPoseAccurate:\n        detectPose(image: imageView.image)\n      case .detectSegmentationMaskSelfie:\n        detectSegmentationMask(image: imageView.image)\n      }\n    } else {\n      print(\"No such item at row \\(row) in detector picker.\")\n    }\n  }\n\n  @IBAction func openPhotoLibrary(_ sender: Any) {\n    imagePicker.sourceType = .photoLibrary\n    present(imagePicker, animated: true)\n  }\n\n  @IBAction func openCamera(_ sender: Any) {\n    guard\n      UIImagePickerController.isCameraDeviceAvailable(.front)\n        || UIImagePickerController\n          .isCameraDeviceAvailable(.rear)\n    else {\n      return\n    }\n    imagePicker.sourceType = .camera\n    present(imagePicker, animated: true)\n  }\n\n  @IBAction func changeImage(_ sender: Any) {\n    clearResults()\n    currentImage = (currentImage + 1) % Constants.images.count\n    imageView.image = UIImage(named: Constants.images[currentImage])\n  }\n\n  @IBAction func downloadOrDeleteModel(_ sender: Any) {\n    clearResults()\n  }\n\n  // MARK: - Private\n\n  /// Removes the detection annotations from the annotation overlay view.\n  private func removeDetectionAnnotations() {\n    for annotationView in annotationOverlayView.subviews {\n      annotationView.removeFromSuperview()\n    }\n  }\n\n  /// Clears the results text view and removes any frames that are visible.\n  private func clearResults() {\n    removeDetectionAnnotations()\n    self.resultsText = \"\"\n  }\n\n  private func showResults() {\n    let resultsAlertController = UIAlertController(\n      title: \"Detection Results\",\n      message: nil,\n      preferredStyle: .actionSheet\n    )\n    resultsAlertController.addAction(\n      UIAlertAction(title: \"OK\", style: .destructive) { _ in\n        resultsAlertController.dismiss(animated: true, completion: nil)\n      }\n    )\n    resultsAlertController.message = resultsText\n    resultsAlertController.popoverPresentationController?.barButtonItem = detectButton\n    resultsAlertController.popoverPresentationController?.sourceView = self.view\n    present(resultsAlertController, animated: true, completion: nil)\n    print(resultsText)\n  }\n\n  /// Updates the image view with a scaled version of the given image.\n  private func updateImageView(with image: UIImage) {\n    let orientation = UIApplication.shared.statusBarOrientation\n    var scaledImageWidth: CGFloat = 0.0\n    var scaledImageHeight: CGFloat = 0.0\n    switch orientation {\n    case .portrait, .portraitUpsideDown, .unknown:\n      scaledImageWidth = imageView.bounds.size.width\n      scaledImageHeight = image.size.height * scaledImageWidth / image.size.width\n    case .landscapeLeft, .landscapeRight:\n      scaledImageWidth = image.size.width * scaledImageHeight / image.size.height\n      scaledImageHeight = imageView.bounds.size.height\n    @unknown default:\n      fatalError()\n    }\n    weak var weakSelf = self\n    DispatchQueue.global(qos: .userInitiated).async {\n      // Scale image while maintaining aspect ratio so it displays better in the UIImageView.\n      var scaledImage = image.scaledImage(\n        with: CGSize(width: scaledImageWidth, height: scaledImageHeight)\n      )\n      scaledImage = scaledImage ?? image\n      guard let finalImage = scaledImage else { return }\n      DispatchQueue.main.async {\n        weakSelf?.imageView.image = finalImage\n      }\n    }\n  }\n\n  private func transformMatrix() -> CGAffineTransform {\n    guard let image = imageView.image else { return CGAffineTransform() }\n    let imageViewWidth = imageView.frame.size.width\n    let imageViewHeight = imageView.frame.size.height\n    let imageWidth = image.size.width\n    let imageHeight = image.size.height\n\n    let imageViewAspectRatio = imageViewWidth / imageViewHeight\n    let imageAspectRatio = imageWidth / imageHeight\n    let scale =\n      (imageViewAspectRatio > imageAspectRatio)\n      ? imageViewHeight / imageHeight : imageViewWidth / imageWidth\n\n    // Image view's `contentMode` is `scaleAspectFit`, which scales the image to fit the size of the\n    // image view by maintaining the aspect ratio. Multiple by `scale` to get image's original size.\n    let scaledImageWidth = imageWidth * scale\n    let scaledImageHeight = imageHeight * scale\n    let xValue = (imageViewWidth - scaledImageWidth) / CGFloat(2.0)\n    let yValue = (imageViewHeight - scaledImageHeight) / CGFloat(2.0)\n\n    var transform = CGAffineTransform.identity.translatedBy(x: xValue, y: yValue)\n    transform = transform.scaledBy(x: scale, y: scale)\n    return transform\n  }\n\n  private func pointFrom(_ visionPoint: VisionPoint) -> CGPoint {\n    return CGPoint(x: visionPoint.x, y: visionPoint.y)\n  }\n\n  private func addContours(forFace face: Face, transform: CGAffineTransform) {\n    // Face\n    if let faceContour = face.contour(ofType: .face) {\n      for point in faceContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n\n    // Eyebrows\n    if let topLeftEyebrowContour = face.contour(ofType: .leftEyebrowTop) {\n      for point in topLeftEyebrowContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n    if let bottomLeftEyebrowContour = face.contour(ofType: .leftEyebrowBottom) {\n      for point in bottomLeftEyebrowContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n    if let topRightEyebrowContour = face.contour(ofType: .rightEyebrowTop) {\n      for point in topRightEyebrowContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n    if let bottomRightEyebrowContour = face.contour(ofType: .rightEyebrowBottom) {\n      for point in bottomRightEyebrowContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n\n    // Eyes\n    if let leftEyeContour = face.contour(ofType: .leftEye) {\n      for point in leftEyeContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius)\n      }\n    }\n    if let rightEyeContour = face.contour(ofType: .rightEye) {\n      for point in rightEyeContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n\n    // Lips\n    if let topUpperLipContour = face.contour(ofType: .upperLipTop) {\n      for point in topUpperLipContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n    if let bottomUpperLipContour = face.contour(ofType: .upperLipBottom) {\n      for point in bottomUpperLipContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n    if let topLowerLipContour = face.contour(ofType: .lowerLipTop) {\n      for point in topLowerLipContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n    if let bottomLowerLipContour = face.contour(ofType: .lowerLipBottom) {\n      for point in bottomLowerLipContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n\n    // Nose\n    if let noseBridgeContour = face.contour(ofType: .noseBridge) {\n      for point in noseBridgeContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n    if let noseBottomContour = face.contour(ofType: .noseBottom) {\n      for point in noseBottomContour.points {\n        let transformedPoint = pointFrom(point).applying(transform)\n        UIUtilities.addCircle(\n          atPoint: transformedPoint,\n          to: annotationOverlayView,\n          color: UIColor.yellow,\n          radius: Constants.smallDotRadius\n        )\n      }\n    }\n  }\n\n  private func addLandmarks(forFace face: Face, transform: CGAffineTransform) {\n    // Mouth\n    if let bottomMouthLandmark = face.landmark(ofType: .mouthBottom) {\n      let point = pointFrom(bottomMouthLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.red,\n        radius: Constants.largeDotRadius\n      )\n    }\n    if let leftMouthLandmark = face.landmark(ofType: .mouthLeft) {\n      let point = pointFrom(leftMouthLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.red,\n        radius: Constants.largeDotRadius\n      )\n    }\n    if let rightMouthLandmark = face.landmark(ofType: .mouthRight) {\n      let point = pointFrom(rightMouthLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.red,\n        radius: Constants.largeDotRadius\n      )\n    }\n\n    // Nose\n    if let noseBaseLandmark = face.landmark(ofType: .noseBase) {\n      let point = pointFrom(noseBaseLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.yellow,\n        radius: Constants.largeDotRadius\n      )\n    }\n\n    // Eyes\n    if let leftEyeLandmark = face.landmark(ofType: .leftEye) {\n      let point = pointFrom(leftEyeLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.cyan,\n        radius: Constants.largeDotRadius\n      )\n    }\n    if let rightEyeLandmark = face.landmark(ofType: .rightEye) {\n      let point = pointFrom(rightEyeLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.cyan,\n        radius: Constants.largeDotRadius\n      )\n    }\n\n    // Ears\n    if let leftEarLandmark = face.landmark(ofType: .leftEar) {\n      let point = pointFrom(leftEarLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.purple,\n        radius: Constants.largeDotRadius\n      )\n    }\n    if let rightEarLandmark = face.landmark(ofType: .rightEar) {\n      let point = pointFrom(rightEarLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.purple,\n        radius: Constants.largeDotRadius\n      )\n    }\n\n    // Cheeks\n    if let leftCheekLandmark = face.landmark(ofType: .leftCheek) {\n      let point = pointFrom(leftCheekLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.orange,\n        radius: Constants.largeDotRadius\n      )\n    }\n    if let rightCheekLandmark = face.landmark(ofType: .rightCheek) {\n      let point = pointFrom(rightCheekLandmark.position)\n      let transformedPoint = point.applying(transform)\n      UIUtilities.addCircle(\n        atPoint: transformedPoint,\n        to: annotationOverlayView,\n        color: UIColor.orange,\n        radius: Constants.largeDotRadius\n      )\n    }\n  }\n\n  private func process(_ visionImage: VisionImage, with textRecognizer: TextRecognizer?) {\n    weak var weakSelf = self\n    textRecognizer?.process(visionImage) { text, error in\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      guard error == nil, let text = text else {\n        let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n        strongSelf.resultsText = \"Text recognizer failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        return\n      }\n      // Blocks.\n      for block in text.blocks {\n        let transformedRect = block.frame.applying(strongSelf.transformMatrix())\n        UIUtilities.addRectangle(\n          transformedRect,\n          to: strongSelf.annotationOverlayView,\n          color: UIColor.purple\n        )\n\n        // Lines.\n        for line in block.lines {\n          let transformedRect = line.frame.applying(strongSelf.transformMatrix())\n          UIUtilities.addRectangle(\n            transformedRect,\n            to: strongSelf.annotationOverlayView,\n            color: UIColor.orange\n          )\n\n          // Elements.\n          for element in line.elements {\n            let transformedRect = element.frame.applying(strongSelf.transformMatrix())\n            UIUtilities.addRectangle(\n              transformedRect,\n              to: strongSelf.annotationOverlayView,\n              color: UIColor.green\n            )\n            let label = UILabel(frame: transformedRect)\n            label.text = element.text\n            label.adjustsFontSizeToFitWidth = true\n            strongSelf.annotationOverlayView.addSubview(label)\n          }\n        }\n      }\n      strongSelf.resultsText += \"\\(text.text)\\n\"\n      strongSelf.showResults()\n    }\n  }\n}\n\nextension ViewController: UIPickerViewDataSource, UIPickerViewDelegate {\n\n  // MARK: - UIPickerViewDataSource\n\n  func numberOfComponents(in pickerView: UIPickerView) -> Int {\n    return DetectorPickerRow.componentsCount\n  }\n\n  func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {\n    return DetectorPickerRow.rowsCount\n  }\n\n  // MARK: - UIPickerViewDelegate\n\n  func pickerView(\n    _ pickerView: UIPickerView,\n    titleForRow row: Int,\n    forComponent component: Int\n  ) -> String? {\n    return DetectorPickerRow(rawValue: row)?.description\n  }\n\n  func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {\n    clearResults()\n  }\n}\n\n// MARK: - UIImagePickerControllerDelegate\n\nextension ViewController: UIImagePickerControllerDelegate {\n\n  func imagePickerController(\n    _ picker: UIImagePickerController,\n    didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]\n  ) {\n    // Local variable inserted by Swift 4.2 migrator.\n    let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)\n\n    clearResults()\n    if let pickedImage =\n      info[\n        convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.originalImage)]\n      as? UIImage\n    {\n      updateImageView(with: pickedImage)\n    }\n    dismiss(animated: true)\n  }\n}\n\n/// Extension of ViewController for On-Device detection.\nextension ViewController {\n\n  // MARK: - Vision On-Device Detection\n\n  /// Detects faces on the specified image and draws a frame around the detected faces using\n  /// On-Device face API.\n  ///\n  /// - Parameter image: The image.\n  func detectFaces(image: UIImage?) {\n    guard let image = image else { return }\n\n    // Create a face detector with options.\n    // [START config_face]\n    let options = FaceDetectorOptions()\n    options.landmarkMode = .all\n    options.classificationMode = .all\n    options.performanceMode = .accurate\n    options.contourMode = .all\n    // [END config_face]\n\n    // [START init_face]\n    let faceDetector = FaceDetector.faceDetector(options: options)\n    // [END init_face]\n\n    // Initialize a `VisionImage` object with the given `UIImage`.\n    let visionImage = VisionImage(image: image)\n    visionImage.orientation = image.imageOrientation\n\n    // [START detect_faces]\n    weak var weakSelf = self\n    faceDetector.process(visionImage) { faces, error in\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      guard error == nil, let faces = faces, !faces.isEmpty else {\n        // [START_EXCLUDE]\n        let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n        strongSelf.resultsText = \"On-Device face detection failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        // [END_EXCLUDE]\n        return\n      }\n\n      // Faces detected\n      // [START_EXCLUDE]\n      faces.forEach { face in\n        let transform = strongSelf.transformMatrix()\n        let transformedRect = face.frame.applying(transform)\n        UIUtilities.addRectangle(\n          transformedRect,\n          to: strongSelf.annotationOverlayView,\n          color: UIColor.green\n        )\n        strongSelf.addLandmarks(forFace: face, transform: transform)\n        strongSelf.addContours(forFace: face, transform: transform)\n      }\n      strongSelf.resultsText = faces.map { face in\n        let headEulerAngleX = face.hasHeadEulerAngleX ? face.headEulerAngleX.description : \"NA\"\n        let headEulerAngleY = face.hasHeadEulerAngleY ? face.headEulerAngleY.description : \"NA\"\n        let headEulerAngleZ = face.hasHeadEulerAngleZ ? face.headEulerAngleZ.description : \"NA\"\n        let leftEyeOpenProbability =\n          face.hasLeftEyeOpenProbability\n          ? face.leftEyeOpenProbability.description : \"NA\"\n        let rightEyeOpenProbability =\n          face.hasRightEyeOpenProbability\n          ? face.rightEyeOpenProbability.description : \"NA\"\n        let smilingProbability =\n          face.hasSmilingProbability\n          ? face.smilingProbability.description : \"NA\"\n        let output = \"\"\"\n          Frame: \\(face.frame)\n          Head Euler Angle X: \\(headEulerAngleX)\n          Head Euler Angle Y: \\(headEulerAngleY)\n          Head Euler Angle Z: \\(headEulerAngleZ)\n          Left Eye Open Probability: \\(leftEyeOpenProbability)\n          Right Eye Open Probability: \\(rightEyeOpenProbability)\n          Smiling Probability: \\(smilingProbability)\n          \"\"\"\n        return \"\\(output)\"\n      }.joined(separator: \"\\n\")\n      strongSelf.showResults()\n      // [END_EXCLUDE]\n    }\n    // [END detect_faces]\n  }\n\n  func detectSegmentationMask(image: UIImage?) {\n    guard let image = image else { return }\n\n    // Initialize a `VisionImage` object with the given `UIImage`.\n    let visionImage = VisionImage(image: image)\n    visionImage.orientation = image.imageOrientation\n\n    guard let segmenter = self.segmenter else {\n      return\n    }\n\n    weak var weakSelf = self\n    segmenter.process(visionImage) { mask, error in\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n\n      guard error == nil, let mask = mask else {\n        let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n        strongSelf.resultsText = \"Segmentation failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        return\n      }\n\n      guard let imageBuffer = UIUtilities.createImageBuffer(from: image) else {\n        let errorString = \"Failed to create image buffer from UIImage\"\n        strongSelf.resultsText = \"Segmentation failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        return\n      }\n\n      UIUtilities.applySegmentationMask(\n        mask: mask, to: imageBuffer,\n        backgroundColor: UIColor.purple.withAlphaComponent(Constants.segmentationMaskAlpha),\n        foregroundColor: nil)\n      let maskedImage = UIUtilities.createUIImage(from: imageBuffer, orientation: .up)\n\n      let imageView = UIImageView()\n      imageView.frame = strongSelf.annotationOverlayView.bounds\n      imageView.contentMode = .scaleAspectFit\n      imageView.image = maskedImage\n\n      strongSelf.annotationOverlayView.addSubview(imageView)\n      strongSelf.resultsText = \"Segmentation Succeeded\"\n      strongSelf.showResults()\n    }\n  }\n\n  /// Detects poses on the specified image and draw pose landmark points and line segments using\n  /// the On-Device face API.\n  ///\n  /// - Parameter image: The image.\n  func detectPose(image: UIImage?) {\n    guard let image = image else { return }\n\n    guard let inputImage = MLImage(image: image) else {\n      print(\"Failed to create MLImage from UIImage.\")\n      return\n    }\n    inputImage.orientation = image.imageOrientation\n\n    if let poseDetector = self.poseDetector {\n      poseDetector.process(inputImage) { poses, error in\n        guard error == nil, let poses = poses, !poses.isEmpty else {\n          let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n          self.resultsText = \"Pose detection failed with error: \\(errorString)\"\n          self.showResults()\n          return\n        }\n        let transform = self.transformMatrix()\n\n        // Pose detected. Currently, only single person detection is supported.\n        poses.forEach { pose in\n          let poseOverlayView = UIUtilities.createPoseOverlayView(\n            forPose: pose,\n            inViewWithBounds: self.annotationOverlayView.bounds,\n            lineWidth: Constants.lineWidth,\n            dotRadius: Constants.smallDotRadius,\n            positionTransformationClosure: { (position) -> CGPoint in\n              return self.pointFrom(position).applying(transform)\n            }\n          )\n          self.annotationOverlayView.addSubview(poseOverlayView)\n          self.resultsText = \"Pose Detected\"\n          self.showResults()\n        }\n      }\n    }\n  }\n\n  /// Detects barcodes on the specified image and draws a frame around the detected barcodes using\n  /// On-Device barcode API.\n  ///\n  /// - Parameter image: The image.\n  func detectBarcodes(image: UIImage?) {\n    guard let image = image else { return }\n\n    // Define the options for a barcode detector.\n    // [START config_barcode]\n    let format = BarcodeFormat.all\n    let barcodeOptions = BarcodeScannerOptions(formats: format)\n    // [END config_barcode]\n\n    // Create a barcode scanner.\n    // [START init_barcode]\n    let barcodeScanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)\n    // [END init_barcode]\n\n    // Initialize a `VisionImage` object with the given `UIImage`.\n    let visionImage = VisionImage(image: image)\n    visionImage.orientation = image.imageOrientation\n\n    // [START detect_barcodes]\n    weak var weakSelf = self\n    barcodeScanner.process(visionImage) { features, error in\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      guard error == nil, let features = features, !features.isEmpty else {\n        // [START_EXCLUDE]\n        let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n        strongSelf.resultsText = \"On-Device barcode detection failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        // [END_EXCLUDE]\n        return\n      }\n\n      // [START_EXCLUDE]\n      features.forEach { feature in\n        let transformedRect = feature.frame.applying(strongSelf.transformMatrix())\n        UIUtilities.addRectangle(\n          transformedRect,\n          to: strongSelf.annotationOverlayView,\n          color: UIColor.green\n        )\n      }\n      strongSelf.resultsText = features.map { feature in\n        return \"DisplayValue: \\(feature.displayValue ?? \"\"), RawValue: \"\n          + \"\\(feature.rawValue ?? \"\"), Frame: \\(feature.frame)\"\n      }.joined(separator: \"\\n\")\n      strongSelf.showResults()\n      // [END_EXCLUDE]\n    }\n    // [END detect_barcodes]\n  }\n\n  /// Detects labels on the specified image using On-Device label API.\n  ///\n  /// - Parameter image: The image.\n  /// - Parameter shouldUseCustomModel: Whether to use the custom image labeling model.\n  func detectLabels(image: UIImage?, shouldUseCustomModel: Bool) {\n    guard let image = image else { return }\n\n    // [START config_label]\n    var options: CommonImageLabelerOptions!\n    if shouldUseCustomModel {\n      guard\n        let localModelFilePath = Bundle.main.path(\n          forResource: Constants.localModelFile.name,\n          ofType: Constants.localModelFile.type\n        )\n      else {\n        self.resultsText = \"On-Device label detection failed because custom model was not found.\"\n        self.showResults()\n        return\n      }\n      let localModel = LocalModel(path: localModelFilePath)\n      options = CustomImageLabelerOptions(localModel: localModel)\n    } else {\n      options = ImageLabelerOptions()\n    }\n    options.confidenceThreshold = NSNumber(floatLiteral: Constants.labelConfidenceThreshold)\n    // [END config_label]\n\n    // [START init_label]\n    let onDeviceLabeler = ImageLabeler.imageLabeler(options: options)\n    // [END init_label]\n\n    // Initialize a `VisionImage` object with the given `UIImage`.\n    let visionImage = VisionImage(image: image)\n    visionImage.orientation = image.imageOrientation\n\n    // [START detect_label]\n    weak var weakSelf = self\n    onDeviceLabeler.process(visionImage) { labels, error in\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      guard error == nil, let labels = labels, !labels.isEmpty else {\n        // [START_EXCLUDE]\n        let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n        strongSelf.resultsText = \"On-Device label detection failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        // [END_EXCLUDE]\n        return\n      }\n\n      // [START_EXCLUDE]\n      strongSelf.resultsText = labels.map { label -> String in\n        return \"Label: \\(label.text), Confidence: \\(label.confidence), Index: \\(label.index)\"\n      }.joined(separator: \"\\n\")\n      strongSelf.showResults()\n      // [END_EXCLUDE]\n    }\n    // [END detect_label]\n  }\n\n  /// Detects text on the specified image and draws a frame around the recognized text using the\n  /// On-Device text recognizer.\n  ///\n  /// - Parameter image: The image.\n  private func detectTextOnDevice(image: UIImage?, detectorType: DetectorPickerRow) {\n    guard let image = image else { return }\n\n    // [START init_text]\n    var options: CommonTextRecognizerOptions\n    if detectorType == .detectTextChineseOnDevice {\n      options = ChineseTextRecognizerOptions.init()\n    } else if detectorType == .detectTextDevanagariOnDevice {\n      options = DevanagariTextRecognizerOptions.init()\n    } else if detectorType == .detectTextJapaneseOnDevice {\n      options = JapaneseTextRecognizerOptions.init()\n    } else if detectorType == .detectTextKoreanOnDevice {\n      options = KoreanTextRecognizerOptions.init()\n    } else {\n      options = TextRecognizerOptions.init()\n    }\n\n    let onDeviceTextRecognizer = TextRecognizer.textRecognizer(options: options)\n    // [END init_text]\n\n    // Initialize a `VisionImage` object with the given `UIImage`.\n    let visionImage = VisionImage(image: image)\n    visionImage.orientation = image.imageOrientation\n\n    self.resultsText += \"Running On-Device Text Recognition...\\n\"\n    process(visionImage, with: onDeviceTextRecognizer)\n  }\n\n  /// Detects objects on the specified image and draws a frame around them.\n  ///\n  /// - Parameter image: The image.\n  /// - Parameter options: The options for object detector.\n  private func detectObjectsOnDevice(in image: UIImage?, options: CommonObjectDetectorOptions) {\n    guard let image = image else { return }\n\n    // Initialize a `VisionImage` object with the given `UIImage`.\n    let visionImage = VisionImage(image: image)\n    visionImage.orientation = image.imageOrientation\n\n    // [START init_object_detector]\n    // Create an objects detector with options.\n    let detector = ObjectDetector.objectDetector(options: options)\n    // [END init_object_detector]\n\n    // [START detect_object]\n    weak var weakSelf = self\n    detector.process(visionImage) { objects, error in\n      guard let strongSelf = weakSelf else {\n        print(\"Self is nil!\")\n        return\n      }\n      guard error == nil else {\n        // [START_EXCLUDE]\n        let errorString = error?.localizedDescription ?? Constants.detectionNoResultsMessage\n        strongSelf.resultsText = \"Object detection failed with error: \\(errorString)\"\n        strongSelf.showResults()\n        // [END_EXCLUDE]\n        return\n      }\n      guard let objects = objects, !objects.isEmpty else {\n        // [START_EXCLUDE]\n        strongSelf.resultsText = \"On-Device object detector returned no results.\"\n        strongSelf.showResults()\n        // [END_EXCLUDE]\n        return\n      }\n\n      objects.forEach { object in\n        // [START_EXCLUDE]\n        let transform = strongSelf.transformMatrix()\n        let transformedRect = object.frame.applying(transform)\n        UIUtilities.addRectangle(\n          transformedRect,\n          to: strongSelf.annotationOverlayView,\n          color: .green\n        )\n        // [END_EXCLUDE]\n      }\n\n      // [START_EXCLUDE]\n      strongSelf.resultsText = objects.map { object in\n        var description = \"Frame: \\(object.frame)\\n\"\n        if let trackingID = object.trackingID {\n          description += \"Object ID: \" + trackingID.stringValue + \"\\n\"\n        }\n        description += object.labels.enumerated().map { (index, label) in\n          \"Label \\(index): \\(label.text), \\(label.confidence), \\(label.index)\"\n        }.joined(separator: \"\\n\")\n        return description\n      }.joined(separator: \"\\n\")\n\n      strongSelf.showResults()\n      // [END_EXCLUDE]\n    }\n    // [END detect_object]\n  }\n\n  /// Resets any detector instances which use a conventional lifecycle paradigm. This method should\n  /// be invoked immediately prior to performing detection. This approach is advantageous to tearing\n  /// down old detectors in the `UIPickerViewDelegate` method because that method isn't actually\n  /// invoked in-sync with when the selected row changes and can result in tearing down the wrong\n  /// detector in the event of a race condition.\n  private func resetManagedLifecycleDetectors(activeDetectorRow: DetectorPickerRow) {\n    if activeDetectorRow == self.lastDetectorRow {\n      // Same row as before, no need to reset any detectors.\n      return\n    }\n    // Clear the old detector, if applicable.\n    switch self.lastDetectorRow {\n    case .detectPose, .detectPoseAccurate:\n      self.poseDetector = nil\n      break\n    case .detectSegmentationMaskSelfie:\n      self.segmenter = nil\n      break\n    default:\n      break\n    }\n    // Initialize the new detector, if applicable.\n    switch activeDetectorRow {\n    case .detectPose, .detectPoseAccurate:\n      let options =\n        activeDetectorRow == .detectPose\n        ? PoseDetectorOptions()\n        : AccuratePoseDetectorOptions()\n      options.detectorMode = .singleImage\n      self.poseDetector = PoseDetector.poseDetector(options: options)\n      break\n    case .detectSegmentationMaskSelfie:\n      let options = SelfieSegmenterOptions()\n      options.segmenterMode = .singleImage\n      self.segmenter = Segmenter.segmenter(options: options)\n      break\n    default:\n      break\n    }\n    self.lastDetectorRow = activeDetectorRow\n  }\n}\n\n// MARK: - Enums\n\nprivate enum DetectorPickerRow: Int {\n  case detectFaceOnDevice = 0\n\n  case\n    detectTextOnDevice,\n    detectTextChineseOnDevice,\n    detectTextDevanagariOnDevice,\n    detectTextJapaneseOnDevice,\n    detectTextKoreanOnDevice,\n    detectBarcodeOnDevice,\n    detectImageLabelsOnDevice,\n    detectImageLabelsCustomOnDevice,\n    detectObjectsProminentNoClassifier,\n    detectObjectsProminentWithClassifier,\n    detectObjectsMultipleNoClassifier,\n    detectObjectsMultipleWithClassifier,\n    detectObjectsCustomProminentNoClassifier,\n    detectObjectsCustomProminentWithClassifier,\n    detectObjectsCustomMultipleNoClassifier,\n    detectObjectsCustomMultipleWithClassifier,\n    detectPose,\n    detectPoseAccurate,\n    detectSegmentationMaskSelfie\n\n  static let rowsCount = 20\n  static let componentsCount = 1\n\n  public var description: String {\n    switch self {\n    case .detectFaceOnDevice:\n      return \"Face Detection\"\n    case .detectTextOnDevice:\n      return \"Text Recognition\"\n    case .detectTextChineseOnDevice:\n      return \"Text Recognition Chinese\"\n    case .detectTextDevanagariOnDevice:\n      return \"Text Recognition Devanagari\"\n    case .detectTextJapaneseOnDevice:\n      return \"Text Recognition Japanese\"\n    case .detectTextKoreanOnDevice:\n      return \"Text Recognition Korean\"\n    case .detectBarcodeOnDevice:\n      return \"Barcode Scanning\"\n    case .detectImageLabelsOnDevice:\n      return \"Image Labeling\"\n    case .detectImageLabelsCustomOnDevice:\n      return \"Image Labeling Custom\"\n    case .detectObjectsProminentNoClassifier:\n      return \"ODT, single, no labeling\"\n    case .detectObjectsProminentWithClassifier:\n      return \"ODT, single, labeling\"\n    case .detectObjectsMultipleNoClassifier:\n      return \"ODT, multiple, no labeling\"\n    case .detectObjectsMultipleWithClassifier:\n      return \"ODT, multiple, labeling\"\n    case .detectObjectsCustomProminentNoClassifier:\n      return \"ODT, custom, single, no labeling\"\n    case .detectObjectsCustomProminentWithClassifier:\n      return \"ODT, custom, single, labeling\"\n    case .detectObjectsCustomMultipleNoClassifier:\n      return \"ODT, custom, multiple, no labeling\"\n    case .detectObjectsCustomMultipleWithClassifier:\n      return \"ODT, custom, multiple, labeling\"\n    case .detectPose:\n      return \"Pose Detection\"\n    case .detectPoseAccurate:\n      return \"Pose Detection, accurate\"\n    case .detectSegmentationMaskSelfie:\n      return \"Selfie Segmentation\"\n    }\n  }\n}\n\nprivate enum Constants {\n  static let images = [\n    \"grace_hopper.jpg\", \"image_has_text.jpg\", \"chinese_sparse.png\", \"chinese.png\",\n    \"devanagari_sparse.png\", \"devanagari.png\", \"japanese_sparse.png\", \"japanese.png\",\n    \"korean_sparse.png\", \"korean.png\", \"barcode_128.png\", \"qr_code.jpg\", \"beach.jpg\", \"liberty.jpg\",\n    \"bird.jpg\",\n  ]\n\n  static let detectionNoResultsMessage = \"No results returned.\"\n  static let failedToDetectObjectsMessage = \"Failed to detect objects in image.\"\n  static let localModelFile = (name: \"bird\", type: \"tflite\")\n  static let labelConfidenceThreshold = 0.75\n  static let smallDotRadius: CGFloat = 5.0\n  static let largeDotRadius: CGFloat = 10.0\n  static let lineColor = UIColor.yellow.cgColor\n  static let lineWidth: CGFloat = 3.0\n  static let fillColor = UIColor.clear.cgColor\n  static let segmentationMaskAlpha: CGFloat = 0.5\n}\n\n// Helper function inserted by Swift 4.2 migrator.\nprivate func convertFromUIImagePickerControllerInfoKeyDictionary(\n  _ input: [UIImagePickerController.InfoKey: Any]\n) -> [String: Any] {\n  return Dictionary(uniqueKeysWithValues: input.map { key, value in (key.rawValue, value) })\n}\n\n// Helper function inserted by Swift 4.2 migrator.\nprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey)\n  -> String\n{\n  return input.rawValue\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 48;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1001E6F720CEE0DD00445CB3 /* UIUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */; };\n\t\t1001E6F920CF021E00445CB3 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1001E6F820CF021E00445CB3 /* CameraViewController.swift */; };\n\t\t1001E6FD20CF0C8F00445CB3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */; };\n\t\t10224B582087E43100A77316 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10224B572087E43100A77316 /* ViewController.swift */; };\n\t\t10224B762087E5A900A77316 /* grace_hopper.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 10224B702087E5A900A77316 /* grace_hopper.jpg */; };\n\t\t1077670E210FBBB6007A19A7 /* liberty.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1077670D210FBBB6007A19A7 /* liberty.jpg */; };\n\t\t1077670F210FBBB6007A19A7 /* liberty.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1077670D210FBBB6007A19A7 /* liberty.jpg */; };\n\t\t10E114E420E5CBAA0013E4A4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E114E320E5CBAA0013E4A4 /* AppDelegate.m */; };\n\t\t10E114E720E5CBAA0013E4A4 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E114E620E5CBAA0013E4A4 /* ViewController.m */; };\n\t\t10E114F220E5CBAE0013E4A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E114F120E5CBAE0013E4A4 /* main.m */; };\n\t\t10E1151420EBF5EB0013E4A4 /* UIUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E1151320EBF5EB0013E4A4 /* UIUtilities.m */; };\n\t\t10E1151720EBF6220013E4A4 /* CameraViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E1151620EBF6220013E4A4 /* CameraViewController.m */; };\n\t\t10E1151A20EBF7E10013E4A4 /* UIImage+VisionDetection.m in Sources */ = {isa = PBXBuildFile; fileRef = 10E1151920EBF7E10013E4A4 /* UIImage+VisionDetection.m */; };\n\t\t10E1152120F3D5F60013E4A4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB287B3C20729CE90069707A /* Main.storyboard */; };\n\t\t10E1152520F3DFE20013E4A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */; };\n\t\t10E1152620F3E0930013E4A4 /* grace_hopper.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 10224B702087E5A900A77316 /* grace_hopper.jpg */; };\n\t\t10E1152720F3E0960013E4A4 /* barcode_128.png in Resources */ = {isa = PBXBuildFile; fileRef = 7202DC6620D0C1A300034C35 /* barcode_128.png */; };\n\t\t10E1152820F3E0990013E4A4 /* beach.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7202DC6720D0C1A300034C35 /* beach.jpg */; };\n\t\t10E1152920F3E09C0013E4A4 /* image_has_text.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7202DC6520D0C1A300034C35 /* image_has_text.jpg */; };\n\t\t10E1152A20F3E09F0013E4A4 /* qr_code.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7202DC6420D0C1A300034C35 /* qr_code.jpg */; };\n\t\t1B8783042808DE3900EACC08 /* devanagari.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B8783002808DE3900EACC08 /* devanagari.png */; };\n\t\t1B8783052808DE3900EACC08 /* devanagari.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B8783002808DE3900EACC08 /* devanagari.png */; };\n\t\t1B8783062808DE3900EACC08 /* chinese.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B8783012808DE3900EACC08 /* chinese.png */; };\n\t\t1B8783072808DE3900EACC08 /* chinese.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B8783012808DE3900EACC08 /* chinese.png */; };\n\t\t1B8783082808DE3900EACC08 /* japanese.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B8783022808DE3900EACC08 /* japanese.png */; };\n\t\t1B8783092808DE3900EACC08 /* japanese.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B8783022808DE3900EACC08 /* japanese.png */; };\n\t\t1B87830A2808DE3900EACC08 /* korean.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B8783032808DE3900EACC08 /* korean.png */; };\n\t\t1B87830B2808DE3900EACC08 /* korean.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B8783032808DE3900EACC08 /* korean.png */; };\n\t\t1BB7EC7226AB69660082BEE8 /* chinese_sparse.png in Resources */ = {isa = PBXBuildFile; fileRef = 1BB7EC6E26AB69650082BEE8 /* chinese_sparse.png */; };\n\t\t1BB7EC7326AB69660082BEE8 /* chinese_sparse.png in Resources */ = {isa = PBXBuildFile; fileRef = 1BB7EC6E26AB69650082BEE8 /* chinese_sparse.png */; };\n\t\t1BB7EC7426AB69660082BEE8 /* japanese_sparse.png in Resources */ = {isa = PBXBuildFile; fileRef = 1BB7EC6F26AB69650082BEE8 /* japanese_sparse.png */; };\n\t\t1BB7EC7526AB69660082BEE8 /* japanese_sparse.png in Resources */ = {isa = PBXBuildFile; fileRef = 1BB7EC6F26AB69650082BEE8 /* japanese_sparse.png */; };\n\t\t1BB7EC7626AB69660082BEE8 /* devanagari_sparse.png in Resources */ = {isa = PBXBuildFile; fileRef = 1BB7EC7026AB69650082BEE8 /* devanagari_sparse.png */; };\n\t\t1BB7EC7726AB69660082BEE8 /* devanagari_sparse.png in Resources */ = {isa = PBXBuildFile; fileRef = 1BB7EC7026AB69650082BEE8 /* devanagari_sparse.png */; };\n\t\t1BB7EC7826AB69660082BEE8 /* korean_sparse.png in Resources */ = {isa = PBXBuildFile; fileRef = 1BB7EC7126AB69660082BEE8 /* korean_sparse.png */; };\n\t\t1BB7EC7926AB69660082BEE8 /* korean_sparse.png in Resources */ = {isa = PBXBuildFile; fileRef = 1BB7EC7126AB69660082BEE8 /* korean_sparse.png */; };\n\t\t4ADD356323BAC29A001277A7 /* MLKitExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10224B5B2087E49F00A77316 /* MLKitExtensions.swift */; };\n\t\t7202DC6920D0C1A300034C35 /* qr_code.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7202DC6420D0C1A300034C35 /* qr_code.jpg */; };\n\t\t7202DC6A20D0C1A300034C35 /* image_has_text.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7202DC6520D0C1A300034C35 /* image_has_text.jpg */; };\n\t\t7202DC6B20D0C1A300034C35 /* barcode_128.png in Resources */ = {isa = PBXBuildFile; fileRef = 7202DC6620D0C1A300034C35 /* barcode_128.png */; };\n\t\t7202DC6C20D0C1A300034C35 /* beach.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7202DC6720D0C1A300034C35 /* beach.jpg */; };\n\t\tA4F89299243BB4BF00B58767 /* bird.tflite in Resources */ = {isa = PBXBuildFile; fileRef = A4F89297243BB4BE00B58767 /* bird.tflite */; };\n\t\tA4F8929A243BB4BF00B58767 /* bird.tflite in Resources */ = {isa = PBXBuildFile; fileRef = A4F89297243BB4BE00B58767 /* bird.tflite */; };\n\t\tA4F8929B243BB4BF00B58767 /* bird.jpg in Resources */ = {isa = PBXBuildFile; fileRef = A4F89298243BB4BF00B58767 /* bird.jpg */; };\n\t\tA4F8929C243BB4BF00B58767 /* bird.jpg in Resources */ = {isa = PBXBuildFile; fileRef = A4F89298243BB4BF00B58767 /* bird.jpg */; };\n\t\tBB287B3920729CE90069707A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB287B3820729CE90069707A /* AppDelegate.swift */; };\n\t\tBB287B3E20729CE90069707A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB287B3C20729CE90069707A /* Main.storyboard */; };\n/* End PBXBuildFile section */\n\n\n/* Begin PBXFileReference section */\n\t\t1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIUtilities.swift; sourceTree = \"<group>\"; };\n\t\t1001E6F820CF021E00445CB3 /* CameraViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = \"<group>\"; };\n\t\t1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t10224B572087E43100A77316 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\t10224B5B2087E49F00A77316 /* MLKitExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MLKitExtensions.swift; sourceTree = \"<group>\"; };\n\t\t10224B702087E5A900A77316 /* grace_hopper.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = grace_hopper.jpg; path = Resources/grace_hopper.jpg; sourceTree = \"<group>\"; };\n\t\t1077670D210FBBB6007A19A7 /* liberty.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = liberty.jpg; sourceTree = \"<group>\"; };\n\t\t10E114E020E5CBAA0013E4A4 /* VisionExampleObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VisionExampleObjC.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t10E114E220E5CBAA0013E4A4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t10E114E320E5CBAA0013E4A4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t10E114E520E5CBAA0013E4A4 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\t10E114E620E5CBAA0013E4A4 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\t10E114F120E5CBAE0013E4A4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t10E1151220EBF5EB0013E4A4 /* UIUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIUtilities.h; sourceTree = \"<group>\"; };\n\t\t10E1151320EBF5EB0013E4A4 /* UIUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIUtilities.m; sourceTree = \"<group>\"; };\n\t\t10E1151520EBF6220013E4A4 /* CameraViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CameraViewController.h; sourceTree = \"<group>\"; };\n\t\t10E1151620EBF6220013E4A4 /* CameraViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraViewController.m; sourceTree = \"<group>\"; };\n\t\t10E1151820EBF7E10013E4A4 /* UIImage+VisionDetection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"UIImage+VisionDetection.h\"; sourceTree = \"<group>\"; };\n\t\t10E1151920EBF7E10013E4A4 /* UIImage+VisionDetection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = \"UIImage+VisionDetection.m\"; sourceTree = \"<group>\"; };\n\t\t1B32934C280E30E100761318 /* MLKSegmentationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKSegmentationTests.m; sourceTree = \"<group>\"; };\n\t\t1B8783002808DE3900EACC08 /* devanagari.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = devanagari.png; path = Resources/devanagari.png; sourceTree = \"<group>\"; };\n\t\t1B8783012808DE3900EACC08 /* chinese.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chinese.png; path = Resources/chinese.png; sourceTree = \"<group>\"; };\n\t\t1B8783022808DE3900EACC08 /* japanese.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = japanese.png; path = Resources/japanese.png; sourceTree = \"<group>\"; };\n\t\t1B8783032808DE3900EACC08 /* korean.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = korean.png; path = Resources/korean.png; sourceTree = \"<group>\"; };\n\t\t1BB7EC6E26AB69650082BEE8 /* chinese_sparse.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chinese_sparse.png; path = Resources/chinese_sparse.png; sourceTree = \"<group>\"; };\n\t\t1BB7EC6F26AB69650082BEE8 /* japanese_sparse.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = japanese_sparse.png; path = Resources/japanese_sparse.png; sourceTree = \"<group>\"; };\n\t\t1BB7EC7026AB69650082BEE8 /* devanagari_sparse.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = devanagari_sparse.png; path = Resources/devanagari_sparse.png; sourceTree = \"<group>\"; };\n\t\t1BB7EC7126AB69660082BEE8 /* korean_sparse.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = korean_sparse.png; path = Resources/korean_sparse.png; sourceTree = \"<group>\"; };\n\t\t7202DC6420D0C1A300034C35 /* qr_code.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = qr_code.jpg; path = Resources/qr_code.jpg; sourceTree = \"<group>\"; };\n\t\t7202DC6520D0C1A300034C35 /* image_has_text.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = image_has_text.jpg; path = Resources/image_has_text.jpg; sourceTree = \"<group>\"; };\n\t\t7202DC6620D0C1A300034C35 /* barcode_128.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = barcode_128.png; path = Resources/barcode_128.png; sourceTree = \"<group>\"; };\n\t\t7202DC6720D0C1A300034C35 /* beach.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = beach.jpg; path = Resources/beach.jpg; sourceTree = \"<group>\"; };\n\t\tA4F89297243BB4BE00B58767 /* bird.tflite */ = {isa = PBXFileReference; lastKnownFileType = file; name = bird.tflite; path = Resources/bird.tflite; sourceTree = \"<group>\"; };\n\t\tA4F89298243BB4BF00B58767 /* bird.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = bird.jpg; path = Resources/bird.jpg; sourceTree = \"<group>\"; };\n\t\tBB287B3520729CE90069707A /* VisionExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VisionExample.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tBB287B3820729CE90069707A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tBB287B3D20729CE90069707A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tBB287B4420729CE90069707A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t10E114DD20E5CBAA0013E4A4 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3220729CE90069707A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t10224B642087E52600A77316 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1B8783012808DE3900EACC08 /* chinese.png */,\n\t\t\t\t1B8783002808DE3900EACC08 /* devanagari.png */,\n\t\t\t\t1B8783022808DE3900EACC08 /* japanese.png */,\n\t\t\t\t1B8783032808DE3900EACC08 /* korean.png */,\n\t\t\t\t1BB7EC6E26AB69650082BEE8 /* chinese_sparse.png */,\n\t\t\t\t1BB7EC7026AB69650082BEE8 /* devanagari_sparse.png */,\n\t\t\t\t1BB7EC6F26AB69650082BEE8 /* japanese_sparse.png */,\n\t\t\t\t1BB7EC7126AB69660082BEE8 /* korean_sparse.png */,\n\t\t\t\t10224B702087E5A900A77316 /* grace_hopper.jpg */,\n\t\t\t\t7202DC6620D0C1A300034C35 /* barcode_128.png */,\n\t\t\t\t7202DC6720D0C1A300034C35 /* beach.jpg */,\n\t\t\t\tA4F89298243BB4BF00B58767 /* bird.jpg */,\n\t\t\t\tA4F89297243BB4BE00B58767 /* bird.tflite */,\n\t\t\t\t7202DC6520D0C1A300034C35 /* image_has_text.jpg */,\n\t\t\t\t7202DC6420D0C1A300034C35 /* qr_code.jpg */,\n\t\t\t\t1077670D210FBBB6007A19A7 /* liberty.jpg */,\n\t\t\t);\n\t\t\tname = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t10E114E120E5CBAA0013E4A4 /* VisionExampleObjC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t10E114E220E5CBAA0013E4A4 /* AppDelegate.h */,\n\t\t\t\t10E114E320E5CBAA0013E4A4 /* AppDelegate.m */,\n\t\t\t\t10E114E520E5CBAA0013E4A4 /* ViewController.h */,\n\t\t\t\t10E114E620E5CBAA0013E4A4 /* ViewController.m */,\n\t\t\t\t10E114F120E5CBAE0013E4A4 /* main.m */,\n\t\t\t\t10E1151220EBF5EB0013E4A4 /* UIUtilities.h */,\n\t\t\t\t10E1151320EBF5EB0013E4A4 /* UIUtilities.m */,\n\t\t\t\t10E1151520EBF6220013E4A4 /* CameraViewController.h */,\n\t\t\t\t10E1151620EBF6220013E4A4 /* CameraViewController.m */,\n\t\t\t\t10E1151820EBF7E10013E4A4 /* UIImage+VisionDetection.h */,\n\t\t\t\t10E1151920EBF7E10013E4A4 /* UIImage+VisionDetection.m */,\n\t\t\t);\n\t\t\tpath = VisionExampleObjC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B2C20729CE90069707A = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */,\n\t\t\t\t10224B642087E52600A77316 /* Resources */,\n\t\t\t\tBB287B3720729CE90069707A /* VisionExample */,\n\t\t\t\t10E114E120E5CBAA0013E4A4 /* VisionExampleObjC */,\n\t\t\t\tBB287B3620729CE90069707A /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B3620729CE90069707A /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3520729CE90069707A /* VisionExample.app */,\n\t\t\t\t10E114E020E5CBAA0013E4A4 /* VisionExampleObjC.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B3720729CE90069707A /* VisionExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3820729CE90069707A /* AppDelegate.swift */,\n\t\t\t\t10224B572087E43100A77316 /* ViewController.swift */,\n\t\t\t\t10224B5B2087E49F00A77316 /* MLKitExtensions.swift */,\n\t\t\t\t1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */,\n\t\t\t\t1001E6F820CF021E00445CB3 /* CameraViewController.swift */,\n\t\t\t\tBB287B4A2072A0200069707A /* Supporting Files */,\n\t\t\t\tBB287B4420729CE90069707A /* Info.plist */,\n\t\t\t);\n\t\t\tpath = VisionExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B4A2072A0200069707A /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3C20729CE90069707A /* Main.storyboard */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t10E114DF20E5CBAA0013E4A4 /* VisionExampleObjC */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 10E1150F20E5CBAE0013E4A4 /* Build configuration list for PBXNativeTarget \"VisionExampleObjC\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t10E114DC20E5CBAA0013E4A4 /* Sources */,\n\t\t\t\t10E114DD20E5CBAA0013E4A4 /* Frameworks */,\n\t\t\t\t10E114DE20E5CBAA0013E4A4 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = VisionExampleObjC;\n\t\t\tproductName = VisionExampleObjC;\n\t\t\tproductReference = 10E114E020E5CBAA0013E4A4 /* VisionExampleObjC.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tBB287B3420729CE90069707A /* VisionExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = BB287B4720729CE90069707A /* Build configuration list for PBXNativeTarget \"VisionExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tBB287B3120729CE90069707A /* Sources */,\n\t\t\t\tBB287B3220729CE90069707A /* Frameworks */,\n\t\t\t\tBB287B3320729CE90069707A /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = VisionExample;\n\t\t\tproductName = \"ml-kit-sampler\";\n\t\t\tproductReference = BB287B3520729CE90069707A /* VisionExample.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tBB287B2D20729CE90069707A /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0930;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = \"Google Inc.\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t10E114DF20E5CBAA0013E4A4 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.4;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t1BF9CA8E2829621C009FFC23 = {\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = BB287B3420729CE90069707A;\n\t\t\t\t\t};\n\t\t\t\t\t1BFC50082726FCDB006EC1EC = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 13.0;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = 10E114DF20E5CBAA0013E4A4;\n\t\t\t\t\t};\n\t\t\t\t\tBB287B3420729CE90069707A = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = BB287B3020729CE90069707A /* Build configuration list for PBXProject \"VisionExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = BB287B2C20729CE90069707A;\n\t\t\tproductRefGroup = BB287B3620729CE90069707A /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tBB287B3420729CE90069707A /* VisionExample */,\n\t\t\t\t10E114DF20E5CBAA0013E4A4 /* VisionExampleObjC */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t10E114DE20E5CBAA0013E4A4 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1BB7EC7326AB69660082BEE8 /* chinese_sparse.png in Resources */,\n\t\t\t\t10E1152120F3D5F60013E4A4 /* Main.storyboard in Resources */,\n\t\t\t\t1BB7EC7526AB69660082BEE8 /* japanese_sparse.png in Resources */,\n\t\t\t\t1B8783092808DE3900EACC08 /* japanese.png in Resources */,\n\t\t\t\t10E1152520F3DFE20013E4A4 /* Assets.xcassets in Resources */,\n\t\t\t\t1B87830B2808DE3900EACC08 /* korean.png in Resources */,\n\t\t\t\t10E1152720F3E0960013E4A4 /* barcode_128.png in Resources */,\n\t\t\t\t10E1152820F3E0990013E4A4 /* beach.jpg in Resources */,\n\t\t\t\t10E1152620F3E0930013E4A4 /* grace_hopper.jpg in Resources */,\n\t\t\t\t10E1152920F3E09C0013E4A4 /* image_has_text.jpg in Resources */,\n\t\t\t\t1BB7EC7726AB69660082BEE8 /* devanagari_sparse.png in Resources */,\n\t\t\t\tA4F8929C243BB4BF00B58767 /* bird.jpg in Resources */,\n\t\t\t\t10E1152A20F3E09F0013E4A4 /* qr_code.jpg in Resources */,\n\t\t\t\t1BB7EC7926AB69660082BEE8 /* korean_sparse.png in Resources */,\n\t\t\t\tA4F8929A243BB4BF00B58767 /* bird.tflite in Resources */,\n\t\t\t\t1B8783072808DE3900EACC08 /* chinese.png in Resources */,\n\t\t\t\t1B8783052808DE3900EACC08 /* devanagari.png in Resources */,\n\t\t\t\t1077670F210FBBB6007A19A7 /* liberty.jpg in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t1BF9CA9B2829621C009FFC23 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t1BFC50072726FCDB006EC1EC /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3320729CE90069707A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1BB7EC7226AB69660082BEE8 /* chinese_sparse.png in Resources */,\n\t\t\t\t10224B762087E5A900A77316 /* grace_hopper.jpg in Resources */,\n\t\t\t\t1BB7EC7426AB69660082BEE8 /* japanese_sparse.png in Resources */,\n\t\t\t\t1B8783082808DE3900EACC08 /* japanese.png in Resources */,\n\t\t\t\t7202DC6C20D0C1A300034C35 /* beach.jpg in Resources */,\n\t\t\t\t1B87830A2808DE3900EACC08 /* korean.png in Resources */,\n\t\t\t\t7202DC6920D0C1A300034C35 /* qr_code.jpg in Resources */,\n\t\t\t\t7202DC6B20D0C1A300034C35 /* barcode_128.png in Resources */,\n\t\t\t\t7202DC6A20D0C1A300034C35 /* image_has_text.jpg in Resources */,\n\t\t\t\tBB287B3E20729CE90069707A /* Main.storyboard in Resources */,\n\t\t\t\t1BB7EC7626AB69660082BEE8 /* devanagari_sparse.png in Resources */,\n\t\t\t\tA4F8929B243BB4BF00B58767 /* bird.jpg in Resources */,\n\t\t\t\t1001E6FD20CF0C8F00445CB3 /* Assets.xcassets in Resources */,\n\t\t\t\t1BB7EC7826AB69660082BEE8 /* korean_sparse.png in Resources */,\n\t\t\t\tA4F89299243BB4BF00B58767 /* bird.tflite in Resources */,\n\t\t\t\t1B8783062808DE3900EACC08 /* chinese.png in Resources */,\n\t\t\t\t1B8783042808DE3900EACC08 /* devanagari.png in Resources */,\n\t\t\t\t1077670E210FBBB6007A19A7 /* liberty.jpg in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t10E114DC20E5CBAA0013E4A4 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t10E1151720EBF6220013E4A4 /* CameraViewController.m in Sources */,\n\t\t\t\t10E1151A20EBF7E10013E4A4 /* UIImage+VisionDetection.m in Sources */,\n\t\t\t\t10E114E720E5CBAA0013E4A4 /* ViewController.m in Sources */,\n\t\t\t\t10E114F220E5CBAE0013E4A4 /* main.m in Sources */,\n\t\t\t\t10E1151420EBF5EB0013E4A4 /* UIUtilities.m in Sources */,\n\t\t\t\t10E114E420E5CBAA0013E4A4 /* AppDelegate.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3120729CE90069707A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t10224B582087E43100A77316 /* ViewController.swift in Sources */,\n\t\t\t\t1001E6F920CF021E00445CB3 /* CameraViewController.swift in Sources */,\n\t\t\t\tBB287B3920729CE90069707A /* AppDelegate.swift in Sources */,\n\t\t\t\t4ADD356323BAC29A001277A7 /* MLKitExtensions.swift in Sources */,\n\t\t\t\t1001E6F720CEE0DD00445CB3 /* UIUtilities.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t1BF9CAA128296229009FFC23 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = BB287B3420729CE90069707A /* VisionExample */;\n\t\t\ttargetProxy = 1BF9CAA028296229009FFC23 /* PBXContainerItemProxy */;\n\t\t};\n\t\t1BFC50102726FCDB006EC1EC /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 10E114DF20E5CBAA0013E4A4 /* VisionExampleObjC */;\n\t\t\ttargetProxy = 1BFC500F2726FCDB006EC1EC /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tBB287B3C20729CE90069707A /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3D20729CE90069707A /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t10E1150920E5CBAE0013E4A4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/VisionExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.VisionExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t10E1150A20E5CBAE0013E4A4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/VisionExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.VisionExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBB287B4520729CE90069707A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBB287B4620729CE90069707A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBB287B4820729CE90069707A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/VisionExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.VisionExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBB287B4920729CE90069707A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/VisionExample/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.quickstart.VisionExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = \"x86_64 arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t10E1150F20E5CBAE0013E4A4 /* Build configuration list for PBXNativeTarget \"VisionExampleObjC\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t10E1150920E5CBAE0013E4A4 /* Debug */,\n\t\t\t\t10E1150A20E5CBAE0013E4A4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBB287B3020729CE90069707A /* Build configuration list for PBXProject \"VisionExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBB287B4520729CE90069707A /* Debug */,\n\t\t\t\tBB287B4620729CE90069707A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBB287B4720729CE90069707A /* Build configuration list for PBXNativeTarget \"VisionExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBB287B4820729CE90069707A /* Debug */,\n\t\t\t\tBB287B4920729CE90069707A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = BB287B2D20729CE90069707A /* Project object */;\n}\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/AppDelegate.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property(nonatomic) UIWindow *window;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/AppDelegate.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"AppDelegate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface AppDelegate ()\n@end\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application\n    didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions {\n  return YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/CameraViewController.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface CameraViewController : UIViewController\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/CameraViewController.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"CameraViewController.h\"\n#import <AVFoundation/AVFoundation.h>\n#import <CoreVideo/CoreVideo.h>\n#import \"UIUtilities.h\"\n\n@import MLImage;\n@import MLKit;\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic NSString *const alertControllerTitle = @\"Vision Detectors\";\nstatic NSString *const alertControllerMessage = @\"Select a detector\";\nstatic NSString *const cancelActionTitleText = @\"Cancel\";\nstatic NSString *const videoDataOutputQueueLabel =\n    @\"com.google.mlkit.visiondetector.VideoDataOutputQueue\";\nstatic NSString *const sessionQueueLabel = @\"com.google.mlkit.visiondetector.SessionQueue\";\nstatic NSString *const noResultsMessage = @\"No Results\";\nstatic NSString *const localModelFileName = @\"bird\";\nstatic NSString *const localModelFileType = @\"tflite\";\n\nstatic float const MLKImageLabelConfidenceThreshold = 0.75;\nstatic const CGFloat MLKSmallDotRadius = 4.0;\nstatic const CGFloat MLKconstantScale = 1.0;\nstatic const CGFloat MLKImageLabelResultFrameX = 0.4;\nstatic const CGFloat MLKImageLabelResultFrameY = 0.1;\nstatic const CGFloat MLKImageLabelResultFrameWidth = 0.5;\nstatic const CGFloat MLKImageLabelResultFrameHeight = 0.8;\nstatic const CGFloat MLKSegmentationMaskAlpha = 0.5;\n\n@interface CameraViewController () <AVCaptureVideoDataOutputSampleBufferDelegate>\n\ntypedef NS_ENUM(NSInteger, Detector) {\n  DetectorOnDeviceBarcode,\n  DetectorOnDeviceFace,\n  DetectorOnDeviceText,\n  DetectorOnDeviceTextChinese,\n  DetectorOnDeviceTextDevanagari,\n  DetectorOnDeviceTextJapanese,\n  DetectorOnDeviceTextKorean,\n  DetectorOnDeviceImageLabels,\n  DetectorOnDeviceImageLabelsCustom,\n  DetectorOnDeviceObjectProminentNoClassifier,\n  DetectorOnDeviceObjectProminentWithClassifier,\n  DetectorOnDeviceObjectMultipleNoClassifier,\n  DetectorOnDeviceObjectMultipleWithClassifier,\n  DetectorOnDeviceObjectCustomProminentNoClassifier,\n  DetectorOnDeviceObjectCustomProminentWithClassifier,\n  DetectorOnDeviceObjectCustomMultipleNoClassifier,\n  DetectorOnDeviceObjectCustomMultipleWithClassifier,\n  DetectorPose,\n  DetectorPoseAccurate,\n  DetectorSegmentationSelfie,\n};\n\n@property(nonatomic) NSArray *detectors;\n@property(nonatomic) Detector currentDetector;\n@property(nonatomic) bool isUsingFrontCamera;\n@property(nonatomic, nonnull) AVCaptureVideoPreviewLayer *previewLayer;\n@property(nonatomic) AVCaptureSession *captureSession;\n@property(nonatomic) dispatch_queue_t sessionQueue;\n@property(nonatomic) UIView *annotationOverlayView;\n@property(nonatomic) UIImageView *previewOverlayView;\n@property(weak, nonatomic) IBOutlet UIView *cameraView;\n@property(nonatomic) CMSampleBufferRef lastFrame;\n\n/** Initialized when one of the pose detector rows are chosen. Reset to `nil` when neither are. */\n@property(nonatomic, nullable) MLKPoseDetector *poseDetector;\n\n/** Initialized when a segmentation detector row is chosen. Reset to `nil` otherwise. */\n@property(nonatomic, nullable) MLKSegmenter *segmenter;\n\n/**\n * The detector mode with which detection was most recently run. Only used on the video output\n * queue. Useful for inferring when to reset detector instances which use a conventional lifecycle\n * paradigm.\n */\n@property(nonatomic) Detector lastDetector;\n\n@end\n\n@implementation CameraViewController\n\n- (NSString *)stringForDetector:(Detector)detector {\n  switch (detector) {\n    case DetectorOnDeviceBarcode:\n      return @\"Barcode Scanning\";\n    case DetectorOnDeviceFace:\n      return @\"Face Detection\";\n    case DetectorOnDeviceImageLabels:\n      return @\"Image Labeling\";\n    case DetectorOnDeviceImageLabelsCustom:\n      return @\"Image Labeling Custom\";\n    case DetectorOnDeviceText:\n      return @\"Text Recognition\";\n    case DetectorOnDeviceTextChinese:\n      return @\"Text Recognition Chinese\";\n    case DetectorOnDeviceTextDevanagari:\n      return @\"Text Recognition Devanagari\";\n    case DetectorOnDeviceTextJapanese:\n      return @\"Text Recognition Japanese\";\n    case DetectorOnDeviceTextKorean:\n      return @\"Text Recognition Korean\";\n    case DetectorOnDeviceObjectProminentNoClassifier:\n      return @\"ODT, single, no labeling\";\n    case DetectorOnDeviceObjectProminentWithClassifier:\n      return @\"ODT, single, labeling\";\n    case DetectorOnDeviceObjectMultipleNoClassifier:\n      return @\"ODT, multiple, no labeling\";\n    case DetectorOnDeviceObjectMultipleWithClassifier:\n      return @\"ODT, multiple, labeling\";\n    case DetectorOnDeviceObjectCustomProminentNoClassifier:\n      return @\"ODT, custom, single, no labeling\";\n    case DetectorOnDeviceObjectCustomProminentWithClassifier:\n      return @\"ODT, custom, single, labeling\";\n    case DetectorOnDeviceObjectCustomMultipleNoClassifier:\n      return @\"ODT, custom, multiple, no labeling\";\n    case DetectorOnDeviceObjectCustomMultipleWithClassifier:\n      return @\"ODT, custom, multiple, labeling\";\n    case DetectorPose:\n      return @\"Pose Detection\";\n    case DetectorPoseAccurate:\n      return @\"Pose Detection, accurate\";\n    case DetectorSegmentationSelfie:\n      return @\"Selfie Segmentation\";\n  }\n}\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  _detectors = @[\n    @(DetectorOnDeviceBarcode),\n    @(DetectorOnDeviceFace),\n    @(DetectorOnDeviceText),\n    @(DetectorOnDeviceTextChinese),\n    @(DetectorOnDeviceTextDevanagari),\n    @(DetectorOnDeviceTextJapanese),\n    @(DetectorOnDeviceTextKorean),\n    @(DetectorOnDeviceImageLabels),\n    @(DetectorOnDeviceImageLabelsCustom),\n    @(DetectorOnDeviceObjectProminentNoClassifier),\n    @(DetectorOnDeviceObjectProminentWithClassifier),\n    @(DetectorOnDeviceObjectMultipleNoClassifier),\n    @(DetectorOnDeviceObjectMultipleWithClassifier),\n    @(DetectorOnDeviceObjectCustomProminentNoClassifier),\n    @(DetectorOnDeviceObjectCustomProminentWithClassifier),\n    @(DetectorOnDeviceObjectCustomMultipleNoClassifier),\n    @(DetectorOnDeviceObjectCustomMultipleWithClassifier),\n    @(DetectorPose),\n    @(DetectorPoseAccurate),\n    @(DetectorSegmentationSelfie),\n  ];\n  self.currentDetector = DetectorOnDeviceFace;\n  _isUsingFrontCamera = YES;\n  _captureSession = [[AVCaptureSession alloc] init];\n  _sessionQueue = dispatch_queue_create(sessionQueueLabel.UTF8String, nil);\n  _previewOverlayView = [[UIImageView alloc] initWithFrame:CGRectZero];\n  _previewOverlayView.contentMode = UIViewContentModeScaleAspectFill;\n  _previewOverlayView.translatesAutoresizingMaskIntoConstraints = NO;\n  _annotationOverlayView = [[UIView alloc] initWithFrame:CGRectZero];\n  _annotationOverlayView.translatesAutoresizingMaskIntoConstraints = NO;\n\n  self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_captureSession];\n  [self setUpPreviewOverlayView];\n  [self setUpAnnotationOverlayView];\n  [self setUpCaptureSessionOutput];\n  [self setUpCaptureSessionInput];\n}\n\n- (void)viewDidAppear:(BOOL)animated {\n  [super viewDidAppear:animated];\n  [self startSession];\n}\n\n- (void)viewDidDisappear:(BOOL)animated {\n  [super viewDidDisappear:animated];\n  [self stopSession];\n}\n\n- (void)viewDidLayoutSubviews {\n  [super viewDidLayoutSubviews];\n  _previewLayer.frame = _cameraView.frame;\n}\n\n- (IBAction)selectDetector:(id)sender {\n  [self presentDetectorsAlertController];\n}\n\n- (IBAction)switchCamera:(id)sender {\n  self.isUsingFrontCamera = !_isUsingFrontCamera;\n  [self removeDetectionAnnotations];\n  [self setUpCaptureSessionInput];\n}\n\n#pragma mark - On-Device Detections\n\n- (void)detectFacesOnDeviceInImage:(MLKVisionImage *)image\n                             width:(CGFloat)width\n                            height:(CGFloat)height {\n  // When performing latency tests to determine ideal detection settings, run the app in 'release'\n  // mode to get accurate performance metrics.\n  MLKFaceDetectorOptions *options = [[MLKFaceDetectorOptions alloc] init];\n  options.performanceMode = MLKFaceDetectorPerformanceModeFast;\n  options.contourMode = MLKFaceDetectorContourModeAll;\n  options.landmarkMode = MLKFaceDetectorLandmarkModeNone;\n  options.classificationMode = MLKFaceDetectorClassificationModeNone;\n  MLKFaceDetector *faceDetector = [MLKFaceDetector faceDetectorWithOptions:options];\n  NSError *error;\n  NSArray<MLKFace *> *faces = [faceDetector resultsInImage:image error:&error];\n  __weak typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf updatePreviewOverlayViewWithLastFrame];\n    [strongSelf removeDetectionAnnotations];\n    if (error != nil) {\n      NSLog(@\"Failed to detect faces with error: %@\", error.localizedDescription);\n      return;\n    }\n    if (faces.count == 0) {\n      NSLog(@\"On-Device face detector returned no results.\");\n      return;\n    }\n    for (MLKFace *face in faces) {\n      CGRect normalizedRect =\n          CGRectMake(face.frame.origin.x / width, face.frame.origin.y / height,\n                     face.frame.size.width / width, face.frame.size.height / height);\n      CGRect standardizedRect = CGRectStandardize(\n          [strongSelf.previewLayer rectForMetadataOutputRectOfInterest:normalizedRect]);\n      [UIUtilities addRectangle:standardizedRect\n                         toView:strongSelf.annotationOverlayView\n                          color:UIColor.greenColor];\n      [strongSelf addContoursForFace:face width:width height:height];\n    }\n  });\n}\n\n- (void)recognizeTextOnDeviceInImage:(MLKVisionImage *)image\n                               width:(CGFloat)width\n                              height:(CGFloat)height\n                        detectorType:(Detector)detectorType {\n  MLKCommonTextRecognizerOptions *options;\n  if (detectorType == DetectorOnDeviceText) {\n    options = [[MLKTextRecognizerOptions alloc] init];\n  } else if (detectorType == DetectorOnDeviceTextChinese) {\n    options = [[MLKChineseTextRecognizerOptions alloc] init];\n  } else if (detectorType == DetectorOnDeviceTextDevanagari) {\n    options = [[MLKDevanagariTextRecognizerOptions alloc] init];\n  } else if (detectorType == DetectorOnDeviceTextJapanese) {\n    options = [[MLKJapaneseTextRecognizerOptions alloc] init];\n  } else if (detectorType == DetectorOnDeviceTextKorean) {\n    options = [[MLKKoreanTextRecognizerOptions alloc] init];\n  }\n  MLKTextRecognizer *textRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];\n  NSError *error;\n  MLKText *text = [textRecognizer resultsInImage:image error:&error];\n  __weak typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf removeDetectionAnnotations];\n    [strongSelf updatePreviewOverlayViewWithLastFrame];\n    if (error != nil) {\n      NSLog(@\"Failed to recognize text with error: %@\", error.localizedDescription);\n      return;\n    }\n    // Blocks.\n    for (MLKTextBlock *block in text.blocks) {\n      NSArray<NSValue *> *points = [strongSelf convertedPointsFromPoints:block.cornerPoints\n                                                                   width:width\n                                                                  height:height];\n      [UIUtilities addShapeWithPoints:points\n                               toView:strongSelf.annotationOverlayView\n                                color:UIColor.purpleColor];\n\n      // Lines.\n      for (MLKTextLine *line in block.lines) {\n        points = [strongSelf convertedPointsFromPoints:line.cornerPoints width:width height:height];\n        [UIUtilities addShapeWithPoints:points\n                                 toView:strongSelf.annotationOverlayView\n                                  color:UIColor.purpleColor];\n\n        // Elements.\n        for (MLKTextElement *element in line.elements) {\n          CGRect normalizedRect =\n              CGRectMake(element.frame.origin.x / width, element.frame.origin.y / height,\n                         element.frame.size.width / width, element.frame.size.height / height);\n          CGRect convertedRect =\n              [strongSelf.previewLayer rectForMetadataOutputRectOfInterest:normalizedRect];\n          [UIUtilities addRectangle:convertedRect\n                             toView:strongSelf.annotationOverlayView\n                              color:UIColor.greenColor];\n          UILabel *label = [[UILabel alloc] initWithFrame:convertedRect];\n          label.text = element.text;\n          label.adjustsFontSizeToFitWidth = YES;\n          [strongSelf rotateView:label orientation:image.orientation];\n          [strongSelf.annotationOverlayView addSubview:label];\n        }\n      }\n    }\n  });\n}\n\n- (void)detectLabelsInImage:(MLKVisionImage *)image useCustomModel:(BOOL)useCustomModel {\n  MLKCommonImageLabelerOptions *options;\n  if (useCustomModel) {\n    NSString *localModelPath = [[NSBundle mainBundle] pathForResource:localModelFileName\n                                                               ofType:localModelFileType];\n    MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelPath];\n    options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];\n  } else {\n    options = [[MLKImageLabelerOptions alloc] init];\n  }\n  options.confidenceThreshold = @(MLKImageLabelConfidenceThreshold);\n  NSError *error;\n  MLKImageLabeler *onDeviceLabeler = [MLKImageLabeler imageLabelerWithOptions:options];\n  NSArray<MLKImageLabel *> *labels = [onDeviceLabeler resultsInImage:image error:&error];\n  __weak typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf updatePreviewOverlayViewWithLastFrame];\n    [strongSelf removeDetectionAnnotations];\n    if (labels.count == 0) {\n      NSString *errorString = error != nil ? error.localizedDescription : noResultsMessage;\n      NSLog(@\"On-Device label detection failed with error: %@\", errorString);\n      return;\n    }\n    NSMutableString *description = [[NSMutableString alloc] init];\n    CGRect normalizedRect =\n        CGRectMake(MLKImageLabelResultFrameX, MLKImageLabelResultFrameY,\n                   MLKImageLabelResultFrameWidth, MLKImageLabelResultFrameHeight);\n    CGRect standardizedRect = CGRectStandardize(\n        [strongSelf.previewLayer rectForMetadataOutputRectOfInterest:normalizedRect]);\n    [UIUtilities addRectangle:standardizedRect\n                       toView:strongSelf.annotationOverlayView\n                        color:UIColor.grayColor];\n    UILabel *uiLabel = [[UILabel alloc] initWithFrame:standardizedRect];\n\n    [description appendString:@\"Labels:\\n\"];\n    for (MLKImageLabel *label in labels) {\n      NSString *labelString =\n          [NSString stringWithFormat:@\"Label: %@, Confidence: %f, Index: %lu\\n\", label.text,\n                                     label.confidence, (unsigned long)label.index];\n      [description appendString:labelString];\n    }\n    uiLabel.text = description;\n    uiLabel.numberOfLines = 0;\n    uiLabel.adjustsFontSizeToFitWidth = YES;\n    [strongSelf rotateView:uiLabel orientation:image.orientation];\n    [strongSelf.annotationOverlayView addSubview:uiLabel];\n  });\n}\n\n- (void)detectPoseInImage:(GMLImage *)image width:(CGFloat)width height:(CGFloat)height {\n  NSError *error;\n  NSArray<MLKPose *> *poses = [self.poseDetector resultsInImage:image error:&error];\n  __weak typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf updatePreviewOverlayViewWithLastFrame];\n    [strongSelf removeDetectionAnnotations];\n\n    if (poses.count == 0) {\n      if (error != nil) {\n        NSLog(@\"Failed to detect pose with error: %@\", error.localizedDescription);\n      }\n      return;\n    }\n\n    // Pose detection currently only supports single pose.\n    MLKPose *pose = poses.firstObject;\n\n    UIView *poseOverlay = [UIUtilities poseOverlayViewForPose:pose\n                                             inViewWithBounds:self.annotationOverlayView.bounds\n                                                    lineWidth:3.0f\n                                                    dotRadius:MLKSmallDotRadius\n                                  positionTransformationBlock:^(MLKVisionPoint *position) {\n                                    return [strongSelf normalizedPointFromVisionPoint:position\n                                                                                width:width\n                                                                               height:height];\n                                  }];\n\n    [strongSelf.annotationOverlayView addSubview:poseOverlay];\n  });\n}\n\n- (void)detectSegmentationMaskInImage:(MLKVisionImage *)image\n                         sampleBuffer:(CMSampleBufferRef)sampleBuffer {\n  NSError *error;\n  MLKSegmentationMask *mask = [self.segmenter resultsInImage:image error:&error];\n  CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);\n\n  if (mask != nil) {\n    UIColor *backgroundColor =\n        [UIColor.purpleColor colorWithAlphaComponent:MLKSegmentationMaskAlpha];\n    [UIUtilities applySegmentationMask:mask\n                         toImageBuffer:imageBuffer\n                   withBackgroundColor:backgroundColor\n                       foregroundColor:nil];\n  } else {\n    NSLog(@\"Failed to segment image with error: %@\", error.localizedDescription);\n  }\n\n  __weak __typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf updatePreviewOverlayViewWithImageBuffer:imageBuffer];\n    [strongSelf removeDetectionAnnotations];\n  });\n}\n\n- (void)scanBarcodesOnDeviceInImage:(MLKVisionImage *)image\n                              width:(CGFloat)width\n                             height:(CGFloat)height\n                            options:(MLKBarcodeScannerOptions *)options {\n  MLKBarcodeScanner *scanner = [MLKBarcodeScanner barcodeScannerWithOptions:options];\n  NSError *error;\n  NSArray<MLKBarcode *> *barcodes = [scanner resultsInImage:image error:&error];\n  __weak typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf removeDetectionAnnotations];\n    [strongSelf updatePreviewOverlayViewWithLastFrame];\n    if (error != nil) {\n      NSLog(@\"Failed to scan barcodes with error: %@\", error.localizedDescription);\n      return;\n    }\n    if (barcodes.count == 0) {\n      NSLog(@\"On-Device barcode scanner returned no results.\");\n      return;\n    }\n    for (MLKBarcode *barcode in barcodes) {\n      CGRect normalizedRect = CGRectMake(barcode.frame.origin.x / width,       // X\n                                         barcode.frame.origin.y / height,      // Y\n                                         barcode.frame.size.width / width,     // Width\n                                         barcode.frame.size.height / height);  // Height\n      CGRect standardizedRect = CGRectStandardize(\n          [strongSelf.previewLayer rectForMetadataOutputRectOfInterest:normalizedRect]);\n      [UIUtilities addRectangle:standardizedRect\n                         toView:strongSelf.annotationOverlayView\n                          color:UIColor.greenColor];\n      UILabel *label = [[UILabel alloc] initWithFrame:standardizedRect];\n      label.numberOfLines = 0;\n      NSMutableString *description = [NSMutableString new];\n      if (barcode.displayValue) {\n        [description appendString:barcode.displayValue];\n      }\n      label.text = description;\n      label.adjustsFontSizeToFitWidth = YES;\n      [strongSelf rotateView:label orientation:image.orientation];\n      [strongSelf.annotationOverlayView addSubview:label];\n    }\n  });\n}\n\n- (void)detectObjectsOnDeviceInImage:(MLKVisionImage *)image\n                               width:(CGFloat)width\n                              height:(CGFloat)height\n                             options:(MLKCommonObjectDetectorOptions *)options {\n  MLKObjectDetector *detector = [MLKObjectDetector objectDetectorWithOptions:options];\n\n  NSError *error;\n  NSArray *objects = [detector resultsInImage:image error:&error];\n  __weak typeof(self) weakSelf = self;\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf updatePreviewOverlayViewWithLastFrame];\n    [strongSelf removeDetectionAnnotations];\n    if (error != nil) {\n      NSLog(@\"Failed to detect object with error: %@\", error.localizedDescription);\n      return;\n    }\n    if (objects.count == 0) {\n      NSLog(@\"On-Device object detector returned no results.\");\n      return;\n    }\n    for (MLKObject *object in objects) {\n      NSMutableString *description = [[NSMutableString alloc] init];\n      CGRect normalizedRect =\n          CGRectMake(object.frame.origin.x / width, object.frame.origin.y / height,\n                     object.frame.size.width / width, object.frame.size.height / height);\n      CGRect standardizedRect = CGRectStandardize(\n          [strongSelf.previewLayer rectForMetadataOutputRectOfInterest:normalizedRect]);\n      [UIUtilities addRectangle:standardizedRect\n                         toView:strongSelf.annotationOverlayView\n                          color:UIColor.greenColor];\n      UILabel *label = [[UILabel alloc] initWithFrame:standardizedRect];\n      if (object.trackingID != nil) {\n        [description appendFormat:@\"Object ID: %@\\n\", object.trackingID];\n      }\n\n      [description appendString:@\"Labels:\\n\"];\n      int i = 0;\n      for (MLKObjectLabel *l in object.labels) {\n        NSString *labelString = [NSString stringWithFormat:@\"Label %d: %@, %f, %lu\\n\", i++, l.text,\n                                                           l.confidence, (unsigned long)l.index];\n        [description appendString:labelString];\n      }\n      label.text = description;\n      label.numberOfLines = 0;\n      label.adjustsFontSizeToFitWidth = YES;\n      [strongSelf rotateView:label orientation:image.orientation];\n      [strongSelf.annotationOverlayView addSubview:label];\n    }\n  });\n}\n\n#pragma mark - Private\n\n- (void)setUpCaptureSessionOutput {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(_sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    if (strongSelf == nil) {\n      NSLog(@\"Failed to setUpCaptureSessionOutput because self was deallocated\");\n      return;\n    }\n    [strongSelf.captureSession beginConfiguration];\n    // When performing latency tests to determine ideal capture settings,\n    // run the app in 'release' mode to get accurate performance metrics\n    strongSelf.captureSession.sessionPreset = AVCaptureSessionPresetMedium;\n\n    AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];\n    output.videoSettings = @{\n      (id)\n      kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]\n    };\n    output.alwaysDiscardsLateVideoFrames = YES;\n    dispatch_queue_t outputQueue = dispatch_queue_create(videoDataOutputQueueLabel.UTF8String, nil);\n    [output setSampleBufferDelegate:self queue:outputQueue];\n    if ([strongSelf.captureSession canAddOutput:output]) {\n      [strongSelf.captureSession addOutput:output];\n      [strongSelf.captureSession commitConfiguration];\n    } else {\n      NSLog(@\"%@\", @\"Failed to add capture session output.\");\n    }\n  });\n}\n\n- (void)setUpCaptureSessionInput {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(_sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    if (strongSelf == nil) {\n      NSLog(@\"Failed to setUpCaptureSessionInput because self was deallocated\");\n      return;\n    }\n    AVCaptureDevicePosition cameraPosition =\n        strongSelf.isUsingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;\n    AVCaptureDevice *device = [strongSelf captureDeviceForPosition:cameraPosition];\n    if (device) {\n      [strongSelf.captureSession beginConfiguration];\n      NSArray<AVCaptureInput *> *currentInputs = strongSelf.captureSession.inputs;\n      for (AVCaptureInput *input in currentInputs) {\n        [strongSelf.captureSession removeInput:input];\n      }\n      NSError *error;\n      AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device\n                                                                          error:&error];\n      if (error) {\n        NSLog(@\"Failed to create capture device input: %@\", error.localizedDescription);\n        return;\n      } else {\n        if ([strongSelf.captureSession canAddInput:input]) {\n          [strongSelf.captureSession addInput:input];\n        } else {\n          NSLog(@\"%@\", @\"Failed to add capture session input.\");\n        }\n      }\n      [strongSelf.captureSession commitConfiguration];\n    } else {\n      NSLog(@\"Failed to get capture device for camera position: %ld\", cameraPosition);\n    }\n  });\n}\n\n- (void)startSession {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(_sessionQueue, ^{\n    [weakSelf.captureSession startRunning];\n  });\n}\n\n- (void)stopSession {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(_sessionQueue, ^{\n    [weakSelf.captureSession stopRunning];\n  });\n}\n\n- (void)setUpPreviewOverlayView {\n  [_cameraView addSubview:_previewOverlayView];\n  [NSLayoutConstraint activateConstraints:@[\n    [_previewOverlayView.centerYAnchor constraintEqualToAnchor:_cameraView.centerYAnchor],\n    [_previewOverlayView.centerXAnchor constraintEqualToAnchor:_cameraView.centerXAnchor],\n    [_previewOverlayView.leadingAnchor constraintEqualToAnchor:_cameraView.leadingAnchor],\n    [_previewOverlayView.trailingAnchor constraintEqualToAnchor:_cameraView.trailingAnchor]\n  ]];\n}\n- (void)setUpAnnotationOverlayView {\n  [_cameraView addSubview:_annotationOverlayView];\n  [NSLayoutConstraint activateConstraints:@[\n    [_annotationOverlayView.topAnchor constraintEqualToAnchor:_cameraView.topAnchor],\n    [_annotationOverlayView.leadingAnchor constraintEqualToAnchor:_cameraView.leadingAnchor],\n    [_annotationOverlayView.trailingAnchor constraintEqualToAnchor:_cameraView.trailingAnchor],\n    [_annotationOverlayView.bottomAnchor constraintEqualToAnchor:_cameraView.bottomAnchor]\n  ]];\n}\n\n- (AVCaptureDevice *)captureDeviceForPosition:(AVCaptureDevicePosition)position {\n  if (@available(iOS 10, *)) {\n    AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession\n        discoverySessionWithDeviceTypes:@[ AVCaptureDeviceTypeBuiltInWideAngleCamera ]\n                              mediaType:AVMediaTypeVideo\n                               position:AVCaptureDevicePositionUnspecified];\n    for (AVCaptureDevice *device in discoverySession.devices) {\n      if (device.position == position) {\n        return device;\n      }\n    }\n  }\n  return nil;\n}\n\n- (void)presentDetectorsAlertController {\n  UIAlertController *alertController =\n      [UIAlertController alertControllerWithTitle:alertControllerTitle\n                                          message:alertControllerMessage\n                                   preferredStyle:UIAlertControllerStyleAlert];\n  for (NSNumber *detectorType in _detectors) {\n    NSInteger detector = detectorType.integerValue;\n    UIAlertAction *action = [UIAlertAction actionWithTitle:[self stringForDetector:detector]\n                                                     style:UIAlertActionStyleDefault\n                                                   handler:^(UIAlertAction *_Nonnull actionArg) {\n                                                     self.currentDetector = detector;\n                                                     [self removeDetectionAnnotations];\n                                                   }];\n    if (detector == self.currentDetector) {\n      [action setEnabled:NO];\n    }\n    [alertController addAction:action];\n  }\n  [alertController addAction:[UIAlertAction actionWithTitle:cancelActionTitleText\n                                                      style:UIAlertActionStyleCancel\n                                                    handler:nil]];\n  [self presentViewController:alertController animated:YES completion:nil];\n}\n\n- (void)removeDetectionAnnotations {\n  for (UIView *annotationView in _annotationOverlayView.subviews) {\n    [annotationView removeFromSuperview];\n  }\n}\n\n- (void)updatePreviewOverlayViewWithLastFrame {\n  CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(_lastFrame);\n  [self updatePreviewOverlayViewWithImageBuffer:imageBuffer];\n}\n\n- (void)updatePreviewOverlayViewWithImageBuffer:(CVImageBufferRef)imageBuffer {\n  if (imageBuffer == nil) {\n    return;\n  }\n  UIImageOrientation orientation =\n      _isUsingFrontCamera ? UIImageOrientationLeftMirrored : UIImageOrientationRight;\n  UIImage *image = [UIUtilities UIImageFromImageBuffer:imageBuffer orientation:orientation];\n  _previewOverlayView.image = image;\n}\n\n- (NSArray<NSValue *> *)convertedPointsFromPoints:(NSArray<NSValue *> *)points\n                                            width:(CGFloat)width\n                                           height:(CGFloat)height {\n  NSMutableArray *result = [NSMutableArray arrayWithCapacity:points.count];\n  for (NSValue *point in points) {\n    CGPoint cgPointValue = point.CGPointValue;\n    CGPoint normalizedPoint = CGPointMake(cgPointValue.x / width, cgPointValue.y / height);\n    CGPoint cgPoint = [_previewLayer pointForCaptureDevicePointOfInterest:normalizedPoint];\n    [result addObject:[NSValue valueWithCGPoint:cgPoint]];\n  }\n  return result;\n}\n\n- (CGPoint)normalizedPointFromVisionPoint:(MLKVisionPoint *)point\n                                    width:(CGFloat)width\n                                   height:(CGFloat)height {\n  CGPoint cgPointValue = CGPointMake(point.x, point.y);\n  CGPoint normalizedPoint = CGPointMake(cgPointValue.x / width, cgPointValue.y / height);\n  CGPoint cgPoint = [_previewLayer pointForCaptureDevicePointOfInterest:normalizedPoint];\n  return cgPoint;\n}\n\n- (void)addContoursForFace:(MLKFace *)face width:(CGFloat)width height:(CGFloat)height {\n  // Face\n  MLKFaceContour *faceContour = [face contourOfType:MLKFaceContourTypeFace];\n  for (MLKVisionPoint *point in faceContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.blueColor\n                           radius:MLKSmallDotRadius];\n  }\n\n  // Eyebrows\n  MLKFaceContour *leftEyebrowTopContour = [face contourOfType:MLKFaceContourTypeLeftEyebrowTop];\n  for (MLKVisionPoint *point in leftEyebrowTopContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.orangeColor\n                           radius:MLKSmallDotRadius];\n  }\n  MLKFaceContour *leftEyebrowBottomContour =\n      [face contourOfType:MLKFaceContourTypeLeftEyebrowBottom];\n  for (MLKVisionPoint *point in leftEyebrowBottomContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.orangeColor\n                           radius:MLKSmallDotRadius];\n  }\n  MLKFaceContour *rightEyebrowTopContour = [face contourOfType:MLKFaceContourTypeRightEyebrowTop];\n  for (MLKVisionPoint *point in rightEyebrowTopContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.orangeColor\n                           radius:MLKSmallDotRadius];\n  }\n  MLKFaceContour *rightEyebrowBottomContour =\n      [face contourOfType:MLKFaceContourTypeRightEyebrowBottom];\n  for (MLKVisionPoint *point in rightEyebrowBottomContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.orangeColor\n                           radius:MLKSmallDotRadius];\n  }\n\n  // Eyes\n  MLKFaceContour *leftEyeContour = [face contourOfType:MLKFaceContourTypeLeftEye];\n  for (MLKVisionPoint *point in leftEyeContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.cyanColor\n                           radius:MLKSmallDotRadius];\n  }\n  MLKFaceContour *rightEyeContour = [face contourOfType:MLKFaceContourTypeRightEye];\n  for (MLKVisionPoint *point in rightEyeContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.cyanColor\n                           radius:MLKSmallDotRadius];\n  }\n\n  // Lips\n  MLKFaceContour *upperLipTopContour = [face contourOfType:MLKFaceContourTypeUpperLipTop];\n  for (MLKVisionPoint *point in upperLipTopContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.redColor\n                           radius:MLKSmallDotRadius];\n  }\n  MLKFaceContour *upperLipBottomContour = [face contourOfType:MLKFaceContourTypeUpperLipBottom];\n  for (MLKVisionPoint *point in upperLipBottomContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.redColor\n                           radius:MLKSmallDotRadius];\n  }\n  MLKFaceContour *lowerLipTopContour = [face contourOfType:MLKFaceContourTypeLowerLipTop];\n  for (MLKVisionPoint *point in lowerLipTopContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.redColor\n                           radius:MLKSmallDotRadius];\n  }\n  MLKFaceContour *lowerLipBottomContour = [face contourOfType:MLKFaceContourTypeLowerLipBottom];\n  for (MLKVisionPoint *point in lowerLipBottomContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.redColor\n                           radius:MLKSmallDotRadius];\n  }\n\n  // Nose\n  MLKFaceContour *noseBridgeContour = [face contourOfType:MLKFaceContourTypeNoseBridge];\n  for (MLKVisionPoint *point in noseBridgeContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.yellowColor\n                           radius:MLKSmallDotRadius];\n  }\n  MLKFaceContour *noseBottomContour = [face contourOfType:MLKFaceContourTypeNoseBottom];\n  for (MLKVisionPoint *point in noseBottomContour.points) {\n    CGPoint cgPoint = [self normalizedPointFromVisionPoint:point width:width height:height];\n    [UIUtilities addCircleAtPoint:cgPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.yellowColor\n                           radius:MLKSmallDotRadius];\n  }\n}\n\n- (void)rotateView:(UIView *)view orientation:(UIImageOrientation)orientation {\n  CGFloat degree = 0.0;\n  switch (orientation) {\n    case UIImageOrientationUp:\n    case UIImageOrientationUpMirrored:\n      degree = 90.0;\n      break;\n    case UIImageOrientationRightMirrored:\n    case UIImageOrientationLeft:\n      degree = 180.0;\n      break;\n    case UIImageOrientationDown:\n    case UIImageOrientationDownMirrored:\n      degree = 270.0;\n      break;\n    case UIImageOrientationLeftMirrored:\n    case UIImageOrientationRight:\n      degree = 0.0;\n      break;\n  }\n  view.transform = CGAffineTransformMakeRotation(degree * 3.141592654 / 180);\n}\n\n#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate\n\n- (void)captureOutput:(AVCaptureOutput *)output\n    didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer\n           fromConnection:(AVCaptureConnection *)connection {\n  CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);\n  if (imageBuffer) {\n    // Evaluate `self.currentDetector` once to ensure consistency throughout this method since it\n    // can be concurrently modified from the main thread.\n    Detector activeDetector = self.currentDetector;\n    [self resetManagedLifecycleDetectorsForActiveDetector:activeDetector];\n\n    _lastFrame = sampleBuffer;\n    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];\n    UIImageOrientation orientation = [UIUtilities\n        imageOrientationFromDevicePosition:_isUsingFrontCamera ? AVCaptureDevicePositionFront\n                                                               : AVCaptureDevicePositionBack];\n\n    visionImage.orientation = orientation;\n\n    GMLImage *inputImage = [[GMLImage alloc] initWithSampleBuffer:sampleBuffer];\n    inputImage.orientation = orientation;\n\n    CGFloat imageWidth = CVPixelBufferGetWidth(imageBuffer);\n    CGFloat imageHeight = CVPixelBufferGetHeight(imageBuffer);\n    BOOL shouldEnableClassification = NO;\n    BOOL shouldEnableMultipleObjects = NO;\n    switch (activeDetector) {\n      case DetectorOnDeviceObjectCustomMultipleWithClassifier:\n      case DetectorOnDeviceObjectCustomProminentWithClassifier:\n      case DetectorOnDeviceObjectMultipleWithClassifier:\n      case DetectorOnDeviceObjectProminentWithClassifier:\n        shouldEnableClassification = YES;\n      default:\n        break;\n    }\n    switch (activeDetector) {\n      case DetectorOnDeviceObjectCustomMultipleNoClassifier:\n      case DetectorOnDeviceObjectCustomMultipleWithClassifier:\n      case DetectorOnDeviceObjectMultipleNoClassifier:\n      case DetectorOnDeviceObjectMultipleWithClassifier:\n        shouldEnableMultipleObjects = YES;\n      default:\n        break;\n    }\n\n    switch (activeDetector) {\n      case DetectorOnDeviceBarcode: {\n        MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] init];\n        [self scanBarcodesOnDeviceInImage:visionImage\n                                    width:imageWidth\n                                   height:imageHeight\n                                  options:options];\n        break;\n      }\n      case DetectorOnDeviceFace:\n        [self detectFacesOnDeviceInImage:visionImage width:imageWidth height:imageHeight];\n        break;\n      case DetectorOnDeviceText:            // Falls through\n      case DetectorOnDeviceTextChinese:     // Falls through\n      case DetectorOnDeviceTextDevanagari:  // Falls through\n      case DetectorOnDeviceTextJapanese:    // Falls through\n      case DetectorOnDeviceTextKorean:\n        [self recognizeTextOnDeviceInImage:visionImage\n                                     width:imageWidth\n                                    height:imageHeight\n                              detectorType:activeDetector];\n        break;\n      case DetectorOnDeviceImageLabels:\n        [self detectLabelsInImage:visionImage useCustomModel:NO];\n        break;\n      case DetectorOnDeviceImageLabelsCustom:\n        [self detectLabelsInImage:visionImage useCustomModel:YES];\n        break;\n      case DetectorPose:\n      case DetectorPoseAccurate:\n        [self detectPoseInImage:inputImage width:imageWidth height:imageHeight];\n        break;\n      case DetectorSegmentationSelfie:\n        [self detectSegmentationMaskInImage:visionImage sampleBuffer:_lastFrame];\n        break;\n      case DetectorOnDeviceObjectProminentNoClassifier:\n      case DetectorOnDeviceObjectProminentWithClassifier:\n      case DetectorOnDeviceObjectMultipleNoClassifier:\n      case DetectorOnDeviceObjectMultipleWithClassifier: {\n        // The `options.detectorMode` defaults to `MLKObjectDetectorModeStream`.\n        MLKObjectDetectorOptions *options = [MLKObjectDetectorOptions new];\n        options.shouldEnableClassification = shouldEnableClassification;\n        options.shouldEnableMultipleObjects = shouldEnableMultipleObjects;\n        [self detectObjectsOnDeviceInImage:visionImage\n                                     width:imageWidth\n                                    height:imageHeight\n                                   options:options];\n        break;\n      }\n      case DetectorOnDeviceObjectCustomProminentNoClassifier:\n      case DetectorOnDeviceObjectCustomProminentWithClassifier:\n      case DetectorOnDeviceObjectCustomMultipleNoClassifier:\n      case DetectorOnDeviceObjectCustomMultipleWithClassifier: {\n        NSString *localModelFilePath = [[NSBundle mainBundle] pathForResource:localModelFileName\n                                                                       ofType:localModelFileType];\n        if (localModelFilePath == nil) {\n          NSLog(@\"Failed to find custom local model file: %@.%@\", localModelFileName,\n                localModelFileType);\n          return;\n        }\n        MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];\n        // The `options.detectorMode` defaults to `MLKObjectDetectorModeStream`.\n        MLKCustomObjectDetectorOptions *options =\n            [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];\n        options.shouldEnableClassification = shouldEnableClassification;\n        options.shouldEnableMultipleObjects = shouldEnableMultipleObjects;\n        [self detectObjectsOnDeviceInImage:visionImage\n                                     width:imageWidth\n                                    height:imageHeight\n                                   options:options];\n        break;\n      }\n    }\n  } else {\n    NSLog(@\"%@\", @\"Failed to get image buffer from sample buffer.\");\n  }\n}\n\n#pragma mark - Private\n\n/**\n * Resets any detector instances which use a conventional lifecycle paradigm. This method is\n * expected to be invoked on the AVCaptureOutput queue - the same queue on which detection is run.\n *\n * @param activeDetector The detector mode for which detection will be run.\n */\n- (void)resetManagedLifecycleDetectorsForActiveDetector:(Detector)activeDetector {\n  if (activeDetector == self.lastDetector) {\n    // Same row as before, no need to reset any detectors.\n    return;\n  }\n  // Clear the old detector, if applicable.\n  switch (self.lastDetector) {\n    case DetectorPose:\n    case DetectorPoseAccurate:\n      self.poseDetector = nil;\n      break;\n    case DetectorSegmentationSelfie:\n      self.segmenter = nil;\n    default:\n      break;\n  }\n  // Initialize the new detector, if applicable.\n  switch (activeDetector) {\n    case DetectorPose:\n    case DetectorPoseAccurate: {\n      // The `options.detectorMode` defaults to `MLKPoseDetectorModeStream`.\n      MLKCommonPoseDetectorOptions *options = activeDetector == DetectorPose\n          ? [[MLKPoseDetectorOptions alloc] init] : [[MLKAccuratePoseDetectorOptions alloc] init];\n      self.poseDetector = [MLKPoseDetector poseDetectorWithOptions:options];\n      break;\n    }\n    case DetectorSegmentationSelfie: {\n      // The `options.segmenterMode` defaults to `MLKSegmenterModeStream`.\n      MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init];\n      self.segmenter = [MLKSegmenter segmenterWithOptions:options];\n      break;\n    }\n    default:\n      break;\n  }\n  self.lastDetector = activeDetector;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/UIImage+VisionDetection.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** A `UIImage` category used for vision detection. */\n@interface UIImage (VisionDetection)\n\n- (UIImage *)scaledImageWithSize:(CGSize)size;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/UIImage+VisionDetection.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"UIImage+VisionDetection.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation UIImage (VisionDetection)\n\n/**\n * Returns a scaled image to the given size.\n *\n * @param size Maximum size of the returned image.\n * @return Image scaled according to the give size or `nil` if image resize fails.\n */\n- (UIImage *)scaledImageWithSize:(CGSize)size {\n  UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);\n  [self drawInRect:CGRectMake(0, 0, size.width, size.height)];\n  UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();\n  UIGraphicsEndImageContext();\n\n  // Attempt to convert the scaled image to PNG or JPEG data to preserve the bitmap info.\n  if (!scaledImage) {\n    return nil;\n  }\n  NSData *imageData = UIImagePNGRepresentation(scaledImage);\n  if (!imageData) {\n    imageData = UIImageJPEGRepresentation(scaledImage, 0.8);\n  }\n  return [UIImage imageWithData:imageData];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/UIUtilities.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <AVFoundation/AVFoundation.h>\n#import <CoreVideo/CoreVideo.h>\n#import <UIKit/UIKit.h>\n\n@import MLKit;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface UIUtilities : NSObject\n\n+ (void)addCircleAtPoint:(CGPoint)point\n                  toView:(UIView *)view\n                   color:(UIColor *)color\n                  radius:(CGFloat)radius;\n\n+ (void)addLineSegmentFromPoint:(CGPoint)fromPoint\n                        toPoint:(CGPoint)toPoint\n                         inView:(UIView *)view\n                          color:(UIColor *)color\n                          width:(CGFloat)width;\n\n+ (void)addRectangle:(CGRect)rectangle toView:(UIView *)view color:(UIColor *)color;\n+ (void)addShapeWithPoints:(NSArray<NSValue *> *)points\n                    toView:(UIView *)view\n                     color:(UIColor *)color;\n+ (UIImageOrientation)imageOrientation;\n+ (UIImageOrientation)imageOrientationFromDevicePosition:(AVCaptureDevicePosition)devicePosition;\n+ (UIDeviceOrientation)currentUIOrientation;\n\n/**\n * Returns an overlay view for visualizing a given `pose`.\n *\n * @param pose The pose which will be visualized.\n * @param bounds The bounds of the view to which this overlay will be added. The overlay view's\n *     bounds will match this value.\n * @param lineWidth The width of the lines connecting the landmark dots.\n * @param dotRadius The radius of the landmark dots.\n * @param positionTransformationBlock Block which transforms a landmark `position` to the\n *     `UIView` `CGPoint` coordinate where it should be shown on-screen.\n */\n+ (UIView *)poseOverlayViewForPose:(MLKPose *)pose\n                  inViewWithBounds:(CGRect)bounds\n                         lineWidth:(CGFloat)lineWidth\n                         dotRadius:(CGFloat)dotRadius\n       positionTransformationBlock:(CGPoint (^)(MLKVisionPoint *))positionTransformationBlock;\n\n/**\n * Applies a segmentation mask to an image buffer by replacing colors in the segmented regions.\n *\n * @param The mask output from a segmentation operation.\n * @param imageBuffer The image buffer on which segmentation was performed. Must have pixel format\n *     type `kCVPixelFormatType_32BGRA`.\n * @param backgroundColor Optional color to render into the background region (i.e. outside of the\n *     segmented region of interest).\n * @param foregroundColor Optional color to render into the foreground region (i.e. inside the\n *     segmented region of interest).\n */\n+ (void)applySegmentationMask:(MLKSegmentationMask *)mask\n                toImageBuffer:(CVImageBufferRef)imageBuffer\n          withBackgroundColor:(nullable UIColor *)backgroundColor\n              foregroundColor:(nullable UIColor *)foregroundColor;\n\n/**\n * Converts an image buffer to a `UIImage`.\n *\n * @param imageBuffer The image buffer which should be converted.\n * @param orientation The orientation already applied to the image.\n * @return A new `UIImage` instance.\n */\n+ (UIImage *)UIImageFromImageBuffer:(CVImageBufferRef)imageBuffer\n                        orientation:(UIImageOrientation)orientation;\n\n/**\n * Converts a `UIImage` to an image buffer.\n *\n * @param image The `UIImage` which should be converted.\n * @return The image buffer. Callers own the returned buffer and are responsible for releasing it\n *     when it is no longer needed. Additionally, the image orientation will not be accounted for\n *     in the returned buffer, so callers must keep track of the orientation separately.\n */\n+ (CVImageBufferRef)imageBufferFromUIImage:(UIImage *)image;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/UIUtilities.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"UIUtilities.h\"\n\n@import MLKit;\n\nstatic CGFloat const circleViewAlpha = 0.7;\nstatic CGFloat const rectangleViewAlpha = 0.3;\nstatic CGFloat const shapeViewAlpha = 0.3;\nstatic CGFloat const rectangleViewCornerRadius = 10.0;\n\nstatic NSString *const MLKCircleViewIdentifier = @\"MLKit Circle View\";\nstatic NSString *const MLKLineViewIdentifier = @\"MLKit Line View\";\nstatic NSString *const MLKRectangleViewIdentifier = @\"MLKit Rectangle View\";\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation UIUtilities\n\n+ (void)addCircleAtPoint:(CGPoint)point\n                  toView:(UIView *)view\n                   color:(UIColor *)color\n                  radius:(CGFloat)radius {\n  CGFloat divisor = 2.0;\n  CGFloat xCoord = point.x - radius / divisor;\n  CGFloat yCoord = point.y - radius / divisor;\n  CGRect circleRect = CGRectMake(xCoord, yCoord, radius, radius);\n  UIView *circleView = [[UIView alloc] initWithFrame:circleRect];\n  circleView.layer.cornerRadius = radius / divisor;\n  circleView.alpha = circleViewAlpha;\n  circleView.backgroundColor = color;\n  circleView.isAccessibilityElement = YES;\n  circleView.accessibilityIdentifier = MLKCircleViewIdentifier;\n  [view addSubview:circleView];\n}\n\n+ (void)addLineSegmentFromPoint:(CGPoint)fromPoint\n                        toPoint:(CGPoint)toPoint\n                         inView:(UIView *)view\n                          color:(UIColor *)color\n                          width:(CGFloat)width {\n  UIBezierPath *path = [UIBezierPath bezierPath];\n  [path moveToPoint:fromPoint];\n  [path addLineToPoint:toPoint];\n  CAShapeLayer *lineLayer = [CAShapeLayer layer];\n  lineLayer.path = path.CGPath;\n  lineLayer.strokeColor = color.CGColor;\n  lineLayer.fillColor = nil;\n  lineLayer.opacity = 1.0f;\n  lineLayer.lineWidth = width;\n  UIView *lineView = [[UIView alloc] initWithFrame:view.bounds];\n  [lineView.layer addSublayer:lineLayer];\n  [view addSubview:lineView];\n}\n\n+ (void)addRectangle:(CGRect)rectangle toView:(UIView *)view color:(UIColor *)color {\n  UIView *rectangleView = [[UIView alloc] initWithFrame:rectangle];\n  rectangleView.layer.cornerRadius = rectangleViewCornerRadius;\n  rectangleView.alpha = rectangleViewAlpha;\n  rectangleView.backgroundColor = color;\n  rectangleView.isAccessibilityElement = YES;\n  rectangleView.accessibilityIdentifier = MLKRectangleViewIdentifier;\n  [view addSubview:rectangleView];\n}\n\n+ (void)addShapeWithPoints:(NSArray<NSValue *> *)points\n                    toView:(UIView *)view\n                     color:(UIColor *)color {\n  UIBezierPath *path = [UIBezierPath new];\n  for (int i = 0; i < [points count]; i++) {\n    CGPoint point = points[i].CGPointValue;\n    if (i == 0) {\n      [path moveToPoint:point];\n    } else {\n      [path addLineToPoint:point];\n    }\n    if (i == points.count - 1) {\n      [path closePath];\n    }\n  }\n  CAShapeLayer *shapeLayer = [CAShapeLayer new];\n  shapeLayer.path = path.CGPath;\n  shapeLayer.fillColor = color.CGColor;\n  CGRect rect = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height);\n  UIView *shapeView = [[UIView alloc] initWithFrame:rect];\n  shapeView.alpha = shapeViewAlpha;\n  [shapeView.layer addSublayer:shapeLayer];\n  [view addSubview:shapeView];\n}\n\n+ (UIImageOrientation)imageOrientation {\n  return [self imageOrientationFromDevicePosition:AVCaptureDevicePositionBack];\n}\n\n+ (UIImageOrientation)imageOrientationFromDevicePosition:(AVCaptureDevicePosition)devicePosition {\n  UIDeviceOrientation deviceOrientation = UIDevice.currentDevice.orientation;\n  if (deviceOrientation == UIDeviceOrientationFaceDown ||\n      deviceOrientation == UIDeviceOrientationFaceUp ||\n      deviceOrientation == UIDeviceOrientationUnknown) {\n    deviceOrientation = [self currentUIOrientation];\n  }\n  switch (deviceOrientation) {\n    case UIDeviceOrientationPortrait:\n      return devicePosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored\n                                                            : UIImageOrientationRight;\n    case UIDeviceOrientationLandscapeLeft:\n      return devicePosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored\n                                                            : UIImageOrientationUp;\n    case UIDeviceOrientationPortraitUpsideDown:\n      return devicePosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored\n                                                            : UIImageOrientationLeft;\n    case UIDeviceOrientationLandscapeRight:\n      return devicePosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored\n                                                            : UIImageOrientationDown;\n    case UIDeviceOrientationFaceDown:\n    case UIDeviceOrientationFaceUp:\n    case UIDeviceOrientationUnknown:\n      return UIImageOrientationUp;\n  }\n}\n\n+ (UIDeviceOrientation)currentUIOrientation {\n  UIDeviceOrientation (^deviceOrientation)(void) = ^UIDeviceOrientation(void) {\n    switch (UIApplication.sharedApplication.statusBarOrientation) {\n      case UIInterfaceOrientationLandscapeLeft:\n        return UIDeviceOrientationLandscapeRight;\n      case UIInterfaceOrientationLandscapeRight:\n        return UIDeviceOrientationLandscapeLeft;\n      case UIInterfaceOrientationPortraitUpsideDown:\n        return UIDeviceOrientationPortraitUpsideDown;\n      case UIInterfaceOrientationPortrait:\n      case UIInterfaceOrientationUnknown:\n        return UIDeviceOrientationPortrait;\n    }\n  };\n\n  if (NSThread.isMainThread) {\n    return deviceOrientation();\n  } else {\n    __block UIDeviceOrientation currentOrientation = UIDeviceOrientationPortrait;\n    dispatch_sync(dispatch_get_main_queue(), ^{\n      currentOrientation = deviceOrientation();\n    });\n    return currentOrientation;\n  }\n}\n\n+ (void)applySegmentationMask:(MLKSegmentationMask *)mask\n                toImageBuffer:(CVImageBufferRef)imageBuffer\n          withBackgroundColor:(nullable UIColor *)backgroundColor\n              foregroundColor:(nullable UIColor *)foregroundColor {\n  NSAssert(CVPixelBufferGetPixelFormatType(imageBuffer) == kCVPixelFormatType_32BGRA,\n           @\"Image buffer must have 32BGRA pixel format type\");\n  size_t width = CVPixelBufferGetWidth(mask.buffer);\n  size_t height = CVPixelBufferGetHeight(mask.buffer);\n  NSAssert(CVPixelBufferGetWidth(imageBuffer) == width, @\"Height must match\");\n  NSAssert(CVPixelBufferGetHeight(imageBuffer) == height, @\"Width must match\");\n\n  if (backgroundColor == nil && foregroundColor == nil) {\n    return;\n  }\n\n  CVPixelBufferLockBaseAddress(imageBuffer, 0);\n  CVPixelBufferLockBaseAddress(mask.buffer, kCVPixelBufferLock_ReadOnly);\n\n  float *maskAddress = (float *)CVPixelBufferGetBaseAddress(mask.buffer);\n  size_t maskBytesPerRow = CVPixelBufferGetBytesPerRow(mask.buffer);\n\n  unsigned char *imageAddress = (unsigned char *)CVPixelBufferGetBaseAddress(imageBuffer);\n  size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);\n  static const int kBGRABytesPerPixel = 4;\n\n  foregroundColor = foregroundColor ?: UIColor.clearColor;\n  backgroundColor = backgroundColor ?: UIColor.clearColor;\n  CGFloat redFG, greenFG, blueFG, alphaFG;\n  CGFloat redBG, greenBG, blueBG, alphaBG;\n  [foregroundColor getRed:&redFG green:&greenFG blue:&blueFG alpha:&alphaFG];\n  [backgroundColor getRed:&redBG green:&greenBG blue:&blueBG alpha:&alphaBG];\n\n  static const float kMaxColorComponentValue = 255.0f;\n\n  for (int row = 0; row < height; ++row) {\n    for (int col = 0; col < width; ++col) {\n      int pixelOffset = col * kBGRABytesPerPixel;\n      int blueOffset = pixelOffset;\n      int greenOffset = pixelOffset + 1;\n      int redOffset = pixelOffset + 2;\n      int alphaOffset = pixelOffset + 3;\n\n      float maskValue = maskAddress[col];\n      float backgroundRegionRatio = 1.0f - maskValue;\n      float foregroundRegionRatio = maskValue;\n\n      float originalPixelRed = imageAddress[redOffset] / kMaxColorComponentValue;\n      float originalPixelGreen = imageAddress[greenOffset] / kMaxColorComponentValue;\n      float originalPixelBlue = imageAddress[blueOffset] / kMaxColorComponentValue;\n      float originalPixelAlpha = imageAddress[alphaOffset] / kMaxColorComponentValue;\n\n      float redOverlay = redBG * backgroundRegionRatio + redFG * foregroundRegionRatio;\n      float greenOverlay = greenBG * backgroundRegionRatio + greenFG * foregroundRegionRatio;\n      float blueOverlay = blueBG * backgroundRegionRatio + blueFG * foregroundRegionRatio;\n      float alphaOverlay = alphaBG * backgroundRegionRatio + alphaFG * foregroundRegionRatio;\n\n      // Calculate composite color component values.\n      // Derived from https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending\n      float compositeAlpha = ((1.0f - alphaOverlay) * originalPixelAlpha) + alphaOverlay;\n      float compositeRed = 0.0f;\n      float compositeGreen = 0.0f;\n      float compositeBlue = 0.0f;\n      // Only perform rgb blending calculations if the output alpha is > 0. A zero-value alpha\n      // means none of the color channels actually matter, and would introduce division by 0.\n      if (fabs(compositeAlpha) > FLT_EPSILON) {\n        compositeRed = (((1.0f - alphaOverlay) * originalPixelAlpha * originalPixelRed) +\n                        (alphaOverlay * redOverlay)) /\n                       compositeAlpha;\n        compositeGreen = (((1.0f - alphaOverlay) * originalPixelAlpha * originalPixelGreen) +\n                          (alphaOverlay * greenOverlay)) /\n                         compositeAlpha;\n        compositeBlue = (((1.0f - alphaOverlay) * originalPixelAlpha * originalPixelBlue) +\n                         (alphaOverlay * blueOverlay)) /\n                        compositeAlpha;\n      }\n\n      imageAddress[blueOffset] = compositeBlue * kMaxColorComponentValue;\n      imageAddress[greenOffset] = compositeGreen * kMaxColorComponentValue;\n      imageAddress[redOffset] = compositeRed * kMaxColorComponentValue;\n      imageAddress[alphaOffset] = compositeAlpha * kMaxColorComponentValue;\n    }\n    imageAddress += bytesPerRow / sizeof(unsigned char);\n    maskAddress += maskBytesPerRow / sizeof(float);\n  }\n\n  CVPixelBufferUnlockBaseAddress(imageBuffer, 0);\n  CVPixelBufferUnlockBaseAddress(mask.buffer, kCVPixelBufferLock_ReadOnly);\n}\n\n+ (UIImage *)UIImageFromImageBuffer:(CVImageBufferRef)imageBuffer\n                        orientation:(UIImageOrientation)orientation {\n  CIImage *CIImg = [CIImage imageWithCVPixelBuffer:imageBuffer];\n  CIContext *context = [[CIContext alloc] initWithOptions:nil];\n  CGImageRef CGImg = [context createCGImage:CIImg fromRect:CIImg.extent];\n  UIImage *image = [UIImage imageWithCGImage:CGImg scale:1.0f orientation:orientation];\n  CGImageRelease(CGImg);\n  return image;\n}\n\n+ (CVImageBufferRef)imageBufferFromUIImage:(UIImage *)image {\n  size_t width = CGImageGetWidth(image.CGImage);\n  size_t height = CGImageGetHeight(image.CGImage);\n\n  CVPixelBufferRef imageBuffer;\n  CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA,\n                      (__bridge CFDictionaryRef) @{}, &imageBuffer);\n\n  CVPixelBufferLockBaseAddress(imageBuffer, 0);\n\n  void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);\n  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();\n  size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);\n  CGContextRef context = CGBitmapContextCreate(\n      baseAddress, width, height, /*bitsPerComponent=*/8, bytesPerRow, colorSpace,\n      kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);\n\n  CGRect rect = CGRectMake(0, 0, width, height);\n  CGContextClearRect(context, rect);\n  CGContextDrawImage(context, rect, image.CGImage);\n\n  CGContextRelease(context);\n  CGColorSpaceRelease(colorSpace);\n  CVPixelBufferUnlockBaseAddress(imageBuffer, 0);\n\n  return imageBuffer;\n}\n\n+ (UIView *)poseOverlayViewForPose:(MLKPose *)pose\n                  inViewWithBounds:(CGRect)bounds\n                         lineWidth:(CGFloat)lineWidth\n                         dotRadius:(CGFloat)dotRadius\n       positionTransformationBlock:\n           (CGPoint (^)(MLKVisionPoint *position))positionTransformationBlock {\n  UIView *overlayView = [[UIView alloc] initWithFrame:bounds];\n\n  CGFloat lowerBodyHeight =\n      [UIUtilities distanceFromPoint:[pose landmarkOfType:MLKPoseLandmarkTypeLeftAnkle].position\n                             toPoint:[pose landmarkOfType:MLKPoseLandmarkTypeLeftKnee].position] +\n      [UIUtilities distanceFromPoint:[pose landmarkOfType:MLKPoseLandmarkTypeLeftKnee].position\n                             toPoint:[pose landmarkOfType:MLKPoseLandmarkTypeLeftHip].position];\n\n  // Pick arbitrary z extents to form a range of z values mapped to our colors. Red = close, blue\n  // = far. Assume that the z values will roughly follow physical extents of the human body, but\n  // apply an adjustment ratio to increase this color-coded z-range because this is not always the\n  // case.\n  static const CGFloat kAdjustmentRatio = 1.2f;\n  CGFloat nearZExtent = -lowerBodyHeight * kAdjustmentRatio;\n  CGFloat farZExtent = lowerBodyHeight * kAdjustmentRatio;\n  CGFloat zColorRange = farZExtent - nearZExtent;\n  UIColor *nearZColor = UIColor.redColor;\n  UIColor *farZColor = UIColor.blueColor;\n\n  NSDictionary<MLKPoseLandmarkType, NSArray<MLKPoseLandmarkType> *> *connections =\n      [UIUtilities poseConnections];\n\n  for (MLKPoseLandmarkType landmarkType in connections) {\n    for (MLKPoseLandmarkType connectedLandmarkType in connections[landmarkType]) {\n      MLKPoseLandmark *landmark = [pose landmarkOfType:landmarkType];\n      MLKPoseLandmark *connectedLandmark = [pose landmarkOfType:connectedLandmarkType];\n      CGPoint landmarkPosition = positionTransformationBlock(landmark.position);\n      CGPoint connectedLandmarkPosition = positionTransformationBlock(connectedLandmark.position);\n\n      CGFloat landmarkZRatio = (landmark.position.z - nearZExtent) / zColorRange;\n      CGFloat connectedLandmarkZRatio = (connectedLandmark.position.z - nearZExtent) / zColorRange;\n\n      UIColor *startColor = [UIUtilities colorInterpolatedFromColor:nearZColor\n                                                            toColor:farZColor\n                                                              ratio:landmarkZRatio];\n      UIColor *endColor = [UIUtilities colorInterpolatedFromColor:nearZColor\n                                                          toColor:farZColor\n                                                            ratio:connectedLandmarkZRatio];\n      [UIUtilities addLineSegmentFromPoint:landmarkPosition\n                                   toPoint:connectedLandmarkPosition\n                                    inView:overlayView\n                                    colors:@[ startColor, endColor ]\n                                     width:lineWidth];\n    }\n  }\n  for (MLKPoseLandmark *landmark in pose.landmarks) {\n    CGPoint position = positionTransformationBlock(landmark.position);\n    [UIUtilities addCircleAtPoint:position\n                           toView:overlayView\n                            color:UIColor.blueColor\n                           radius:dotRadius];\n  }\n  return overlayView;\n}\n\n/**\n * Adds a gradient-colored line segment subview in a given `view`.\n *\n * @param fromPoint The starting point of the line, in the view's coordinate space.\n * @param toPoint The end point of the line, in the view's coordinate space.\n * @param view The view to which the line should be added as a subview.\n * @param colors The colors that the gradient should traverse over. Must be non-empty.\n * @param width The width of the line segment.\n */\n+ (void)addLineSegmentFromPoint:(CGPoint)fromPoint\n                        toPoint:(CGPoint)toPoint\n                         inView:(UIView *)view\n                         colors:(NSArray<UIColor *> *)colors\n                          width:(CGFloat)width {\n  CGFloat viewWidth = CGRectGetWidth(view.bounds);\n  CGFloat viewHeight = CGRectGetHeight(view.bounds);\n  if (viewWidth == 0.0f || viewHeight == 0.0f) {\n    return;\n  }\n\n  UIBezierPath *path = [UIBezierPath bezierPath];\n  [path moveToPoint:fromPoint];\n  [path addLineToPoint:toPoint];\n  CAShapeLayer *lineMaskLayer = [CAShapeLayer layer];\n  lineMaskLayer.path = path.CGPath;\n  lineMaskLayer.strokeColor = UIColor.blackColor.CGColor;\n  lineMaskLayer.fillColor = nil;\n  lineMaskLayer.opacity = 1.0f;\n  lineMaskLayer.lineWidth = width;\n\n  CAGradientLayer *gradientLayer = [CAGradientLayer layer];\n  gradientLayer.startPoint = CGPointMake(fromPoint.x / viewWidth, fromPoint.y / viewHeight);\n  gradientLayer.endPoint = CGPointMake(toPoint.x / viewWidth, toPoint.y / viewHeight);\n  gradientLayer.frame = view.bounds;\n  NSMutableArray<id> *CGColors = [NSMutableArray arrayWithCapacity:colors.count];\n  for (UIColor *color in colors) {\n    [CGColors addObject:(id)color.CGColor];\n  }\n  if (colors.count == 1) {\n    // Single-colored lines must still supply a start and end color for the gradient layer to render\n    // anything. Just add the single color to the colors list again to fulfill this requirement.\n    [CGColors addObject:(id)colors.firstObject.CGColor];\n  }\n  gradientLayer.colors = CGColors;\n  gradientLayer.mask = lineMaskLayer;\n\n  UIView *lineView = [[UIView alloc] initWithFrame:view.bounds];\n  [lineView.layer addSublayer:gradientLayer];\n  lineView.isAccessibilityElement = YES;\n  lineView.accessibilityIdentifier = MLKLineViewIdentifier;\n  [view addSubview:lineView];\n}\n\n/**\n * Returns a color interpolated between two other colors.\n *\n * @param fromColor The start color of the interpolation.\n * @param toColor The end color of the interpolation.\n * @param ratio The ratio in range [0, 1] by which the colors should be interpolated. Passing 0\n *     results in `fromColor` and passing 1 results in `toColor`, whereas passing 0.5 results in a\n *     color that is half-way between `fromColor` and `startColor`. Values are clamped between 0 and\n *     1.\n */\n+ (UIColor *)colorInterpolatedFromColor:(UIColor *)fromColor\n                                toColor:(UIColor *)toColor\n                                  ratio:(CGFloat)ratio {\n  CGFloat fromR, fromG, fromB, fromA;\n  [fromColor getRed:&fromR green:&fromG blue:&fromB alpha:&fromA];\n\n  CGFloat toR, toG, toB, toA;\n  [toColor getRed:&toR green:&toG blue:&toB alpha:&toA];\n\n  // Clamp ratio to [0, 1]\n  ratio = MAX(0.0, MIN(ratio, 1.0));\n\n  CGFloat interpolatedR = fromR + (toR - fromR) * ratio;\n  CGFloat interpolatedG = fromG + (toG - fromG) * ratio;\n  CGFloat interpolatedB = fromB + (toB - fromB) * ratio;\n  CGFloat interpolatedA = fromA + (toA - fromA) * ratio;\n\n  return [UIColor colorWithRed:interpolatedR\n                         green:interpolatedG\n                          blue:interpolatedB\n                         alpha:interpolatedA];\n}\n\n/**\n * Returns the distance between two 3D points.\n *\n * @param fromPoint The start point.\n * @param toPoint The end point.\n */\n+ (CGFloat)distanceFromPoint:(MLKVision3DPoint *)fromPoint toPoint:(MLKVision3DPoint *)toPoint {\n  CGFloat xDiff = fromPoint.x - toPoint.x;\n  CGFloat yDiff = fromPoint.y - toPoint.y;\n  CGFloat zDiff = fromPoint.z - toPoint.z;\n  return sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff);\n}\n\n/**\n * Returns the minimum subset of all connected pose landmarks. Each key represents a start landmark,\n * and each value in the key's value array represents an end landmark which is connected to the\n * start landmark. These connections may be used for visualizing the landmark positions on a pose\n * object.\n */\n+ (NSDictionary<MLKPoseLandmarkType, NSArray<MLKPoseLandmarkType> *> *)poseConnections {\n  static dispatch_once_t onceToken;\n  static NSDictionary<MLKPoseLandmarkType, NSArray<MLKPoseLandmarkType> *> *connections;\n  dispatch_once(&onceToken, ^{\n    connections = @{\n      MLKPoseLandmarkTypeLeftEar : @[MLKPoseLandmarkTypeLeftEyeOuter],\n      MLKPoseLandmarkTypeLeftEyeOuter : @[MLKPoseLandmarkTypeLeftEye],\n      MLKPoseLandmarkTypeLeftEye : @[MLKPoseLandmarkTypeLeftEyeInner],\n      MLKPoseLandmarkTypeLeftEyeInner : @[MLKPoseLandmarkTypeNose],\n      MLKPoseLandmarkTypeNose : @[MLKPoseLandmarkTypeRightEyeInner],\n      MLKPoseLandmarkTypeRightEyeInner : @[MLKPoseLandmarkTypeRightEye],\n      MLKPoseLandmarkTypeRightEye : @[MLKPoseLandmarkTypeRightEyeOuter],\n      MLKPoseLandmarkTypeRightEyeOuter : @[MLKPoseLandmarkTypeRightEar],\n      MLKPoseLandmarkTypeMouthLeft : @[MLKPoseLandmarkTypeMouthRight],\n      MLKPoseLandmarkTypeLeftShoulder: @[MLKPoseLandmarkTypeRightShoulder,\n                                         MLKPoseLandmarkTypeLeftHip],\n      MLKPoseLandmarkTypeRightShoulder : @[MLKPoseLandmarkTypeRightHip,\n                                           MLKPoseLandmarkTypeRightElbow],\n      MLKPoseLandmarkTypeRightWrist : @[MLKPoseLandmarkTypeRightElbow,\n                                        MLKPoseLandmarkTypeRightThumb,\n                                        MLKPoseLandmarkTypeRightIndexFinger,\n                                        MLKPoseLandmarkTypeRightPinkyFinger],\n      MLKPoseLandmarkTypeLeftHip : @[MLKPoseLandmarkTypeRightHip, MLKPoseLandmarkTypeLeftKnee],\n      MLKPoseLandmarkTypeRightHip : @[MLKPoseLandmarkTypeRightKnee],\n      MLKPoseLandmarkTypeRightKnee : @[MLKPoseLandmarkTypeRightAnkle],\n      MLKPoseLandmarkTypeLeftKnee : @[MLKPoseLandmarkTypeLeftAnkle],\n      MLKPoseLandmarkTypeLeftElbow : @[MLKPoseLandmarkTypeLeftShoulder],\n      MLKPoseLandmarkTypeLeftWrist : @[MLKPoseLandmarkTypeLeftElbow, MLKPoseLandmarkTypeLeftThumb,\n                                       MLKPoseLandmarkTypeLeftIndexFinger,\n                                       MLKPoseLandmarkTypeLeftPinkyFinger],\n      MLKPoseLandmarkTypeLeftAnkle : @[MLKPoseLandmarkTypeLeftHeel, MLKPoseLandmarkTypeLeftToe],\n      MLKPoseLandmarkTypeRightAnkle : @[MLKPoseLandmarkTypeRightHeel, MLKPoseLandmarkTypeRightToe],\n      MLKPoseLandmarkTypeRightHeel : @[MLKPoseLandmarkTypeRightToe],\n      MLKPoseLandmarkTypeLeftHeel : @[MLKPoseLandmarkTypeLeftToe],\n      MLKPoseLandmarkTypeRightIndexFinger : @[MLKPoseLandmarkTypeRightPinkyFinger],\n      MLKPoseLandmarkTypeLeftIndexFinger : @[MLKPoseLandmarkTypeLeftPinkyFinger],\n    };\n  });\n  return connections;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/ViewController.h",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ViewController : UIViewController\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/ViewController.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import \"ViewController.h\"\n#import \"UIImage+VisionDetection.h\"\n#import \"UIUtilities.h\"\n\n@import MLImage;\n@import MLKit;\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic NSArray *images;\n\nstatic NSString *const detectionNoResultsMessage = @\"No results returned.\";\nstatic NSString *const failedToDetectObjectsMessage = @\"Failed to detect objects in image.\";\nstatic NSString *const sparseTextModelName = @\"Sparse\";\nstatic NSString *const denseTextModelName = @\"Dense\";\nstatic NSString *const localModelFileName = @\"bird\";\nstatic NSString *const localModelFileType = @\"tflite\";\n\nstatic const float labelConfidenceThreshold = 0.75;\nstatic const CGFloat smallDotRadius = 5.0;\nstatic const CGFloat largeDotRadius = 10.0;\nstatic const CGFloat segmentationMaskAlpha = 1;\nstatic CGColorRef lineColor;\nstatic CGColorRef fillColor;\n\nstatic int const rowsCount = 20;\nstatic int const componentsCount = 1;\n\n/**\n * @enum DetectorPickerRow\n * Defines the ML Kit SDK vision detector types.\n */\ntypedef NS_ENUM(NSInteger, DetectorPickerRow) {\n  /** On-Device vision face vision detector. */\n  DetectorPickerRowDetectFaceOnDevice,\n  /** On-Device vision text vision detector. */\n  DetectorPickerRowDetectTextOnDevice,\n  /** On-Device vision Chinese text vision detector. */\n  DetectorPickerRowDetectTextChineseOnDevice,\n  /** On-Device vision Devanagari text vision detector. */\n  DetectorPickerRowDetectTextDevanagariOnDevice,\n  /** On-Device vision Japanese text vision detector. */\n  DetectorPickerRowDetectTextJapaneseOnDevice,\n  /** On-Device vision Korean text vision detector. */\n  DetectorPickerRowDetectTextKoreanOnDevice,\n  /** On-Device vision barcode vision detector. */\n  DetectorPickerRowDetectBarcodeOnDevice,\n  /** On-Device vision image label detector. */\n  DetectorPickerRowDetectImageLabelsOnDevice,\n  /** On-Device vision image custom label detector. */\n  DetectorPickerRowDetectImageLabelsCustomOnDevice,\n  /** On-Device vision object detector, prominent, only tracking. */\n  DetectorPickerRowDetectObjectsProminentNoClassifier,\n  /** On-Device vision object detector, prominent, with classification. */\n  DetectorPickerRowDetectObjectsProminentWithClassifier,\n  /** On-Device vision object detector, multiple, only tracking. */\n  DetectorPickerRowDetectObjectsMultipleNoClassifier,\n  /** On-Device vision object detector, multiple, with classification. */\n  DetectorPickerRowDetectObjectsMultipleWithClassifier,\n  /** On-Device vision object detector, custom model, prominent, only tracking. */\n  DetectorPickerRowDetectObjectsCustomProminentNoClassifier,\n  /** On-Device vision object detector, custom model, prominent, with classification. */\n  DetectorPickerRowDetectObjectsCustomProminentWithClassifier,\n  /** On-Device vision object detector, custom model, multiple, only tracking. */\n  DetectorPickerRowDetectObjectsCustomMultipleNoClassifier,\n  /** On-Device vision object detector, custom model, multiple, with classification. */\n  DetectorPickerRowDetectObjectsCustomMultipleWithClassifier,\n  /** Vision pose detector. */\n  DetectorPickerRowDetectPose,\n  /** Vision pose accurate detector. */\n  DetectorPickerRowDetectPoseAccurate,\n  /** Vision selfie segmenter. */\n  DetectorPickerRowSegmentationSelfie,\n};\n\n@interface ViewController () <UINavigationControllerDelegate,\n                              UIPickerViewDelegate,\n                              UIPickerViewDataSource,\n                              UIImagePickerControllerDelegate>\n\n/** A string holding current results from detection. */\n@property(nonatomic) NSMutableString *resultsText;\n\n/** An overlay view that displays detection annotations. */\n@property(nonatomic) UIView *annotationOverlayView;\n\n/** An image picker for accessing the photo library or camera. */\n@property(nonatomic) UIImagePickerController *imagePicker;\n@property(weak, nonatomic) IBOutlet UIBarButtonItem *detectButton;\n\n// Image counter.\n@property(nonatomic) NSUInteger currentImage;\n\n@property(weak, nonatomic) IBOutlet UIPickerView *detectorPicker;\n@property(weak, nonatomic) IBOutlet UIImageView *imageView;\n@property(weak, nonatomic) IBOutlet UIBarButtonItem *photoCameraButton;\n@property(weak, nonatomic) IBOutlet UIBarButtonItem *videoCameraButton;\n\n/** Initialized when one of the pose detector rows are chosen. Reset to `nil` when neither are. */\n@property(nonatomic, nullable) MLKPoseDetector *poseDetector;\n\n/** Initialized when a segmentation row is chose. Reset to `nil` otherwise. */\n@property(nonatomic, nullable) MLKSegmenter *segmenter;\n\n/**\n * The detector row with which detection was most recently run. Useful for inferring when to reset\n * detector instances which use a conventional lifecyle paradigm.\n */\n@property(nonatomic) DetectorPickerRow lastDetectorRow;\n\n@end\n\n@implementation ViewController\n\n- (NSString *)stringForDetectorPickerRow:(DetectorPickerRow)detectorPickerRow {\n  switch (detectorPickerRow) {\n    case DetectorPickerRowDetectFaceOnDevice:\n      return @\"Face Detection\";\n    case DetectorPickerRowDetectTextOnDevice:\n      return @\"Text Recognition\";\n    case DetectorPickerRowDetectTextChineseOnDevice:\n      return @\"Text Recognition Chinese\";\n    case DetectorPickerRowDetectTextDevanagariOnDevice:\n      return @\"Text Recognition Devanagari\";\n    case DetectorPickerRowDetectTextJapaneseOnDevice:\n      return @\"Text Recognition Japanese\";\n    case DetectorPickerRowDetectTextKoreanOnDevice:\n      return @\"Text Recognition Korean\";\n    case DetectorPickerRowDetectBarcodeOnDevice:\n      return @\"Barcode Scanning\";\n    case DetectorPickerRowDetectImageLabelsOnDevice:\n      return @\"Image Labeling\";\n    case DetectorPickerRowDetectImageLabelsCustomOnDevice:\n      return @\"Image Labeling Custom\";\n    case DetectorPickerRowDetectObjectsProminentNoClassifier:\n      return @\"ODT, single, no labeling\";\n    case DetectorPickerRowDetectObjectsProminentWithClassifier:\n      return @\"ODT, single, labeling\";\n    case DetectorPickerRowDetectObjectsMultipleNoClassifier:\n      return @\"ODT, multiple, no labeling\";\n    case DetectorPickerRowDetectObjectsMultipleWithClassifier:\n      return @\"ODT, multiple, labeling\";\n    case DetectorPickerRowDetectObjectsCustomProminentNoClassifier:\n      return @\"ODT, custom, single, no labeling\";\n    case DetectorPickerRowDetectObjectsCustomProminentWithClassifier:\n      return @\"ODT, custom, single, labeling\";\n    case DetectorPickerRowDetectObjectsCustomMultipleNoClassifier:\n      return @\"ODT, custom, multiple, no labeling\";\n    case DetectorPickerRowDetectObjectsCustomMultipleWithClassifier:\n      return @\"ODT, custom, multiple, labeling\";\n    case DetectorPickerRowDetectPose:\n      return @\"Pose Detection\";\n    case DetectorPickerRowDetectPoseAccurate:\n      return @\"Pose Detection, accurate\";\n    case DetectorPickerRowSegmentationSelfie:\n      return @\"Selfie Segmentation\";\n  }\n}\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n\n  images = @[\n    @\"grace_hopper.jpg\", @\"image_has_text.jpg\", @\"chinese_sparse.png\", @\"chinese.png\",\n    @\"devanagari_sparse.png\", @\"devanagari.png\", @\"japanese_sparse.png\", @\"japanese.png\",\n    @\"korean_sparse.png\", @\"korean.png\", @\"barcode_128.png\", @\"qr_code.jpg\", @\"beach.jpg\",\n    @\"liberty.jpg\", @\"bird.jpg\"\n  ];\n  lineColor = UIColor.yellowColor.CGColor;\n  fillColor = UIColor.clearColor.CGColor;\n\n  self.imagePicker = [UIImagePickerController new];\n  self.resultsText = [NSMutableString new];\n  _currentImage = 0;\n  _imageView.image = [UIImage imageNamed:images[_currentImage]];\n  _annotationOverlayView = [[UIView alloc] initWithFrame:CGRectZero];\n  _annotationOverlayView.translatesAutoresizingMaskIntoConstraints = NO;\n  _annotationOverlayView.clipsToBounds = YES;\n  [_imageView addSubview:_annotationOverlayView];\n  [NSLayoutConstraint activateConstraints:@[\n    [_annotationOverlayView.topAnchor constraintEqualToAnchor:_imageView.topAnchor],\n    [_annotationOverlayView.leadingAnchor constraintEqualToAnchor:_imageView.leadingAnchor],\n    [_annotationOverlayView.trailingAnchor constraintEqualToAnchor:_imageView.trailingAnchor],\n    [_annotationOverlayView.bottomAnchor constraintEqualToAnchor:_imageView.bottomAnchor]\n  ]];\n  _imagePicker.delegate = self;\n  _imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;\n\n  _detectorPicker.delegate = self;\n  _detectorPicker.dataSource = self;\n\n  BOOL isCameraAvailable =\n      [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront] ||\n      [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear];\n  if (isCameraAvailable) {\n    // `CameraViewController` uses `AVCaptureDeviceDiscoverySession` which is only supported for\n    // iOS 10 or newer.\n    if (@available(iOS 10, *)) {\n      [_videoCameraButton setEnabled:YES];\n    }\n  } else {\n    [_photoCameraButton setEnabled:NO];\n  }\n\n  int defaultRow = (rowsCount / 2) - 1;\n  [_detectorPicker selectRow:defaultRow inComponent:0 animated:NO];\n}\n\n- (void)viewWillAppear:(BOOL)animated {\n  [super viewWillAppear:animated];\n}\n\n- (void)viewWillDisappear:(BOOL)animated {\n  [super viewWillDisappear:animated];\n}\n\n- (IBAction)detect:(id)sender {\n  [self clearResults];\n  NSInteger rowIndex = [_detectorPicker selectedRowInComponent:0];\n  [self resetManagedLifecycleDetectorsForActiveDetectorRow:rowIndex];\n  BOOL shouldEnableClassification =\n      (rowIndex == DetectorPickerRowDetectObjectsProminentWithClassifier) ||\n      (rowIndex == DetectorPickerRowDetectObjectsMultipleWithClassifier) ||\n      (rowIndex == DetectorPickerRowDetectObjectsCustomProminentWithClassifier) ||\n      (rowIndex == DetectorPickerRowDetectObjectsCustomMultipleWithClassifier);\n  BOOL shouldEnableMultipleObjects =\n      (rowIndex == DetectorPickerRowDetectObjectsMultipleNoClassifier) ||\n      (rowIndex == DetectorPickerRowDetectObjectsMultipleWithClassifier) ||\n      (rowIndex == DetectorPickerRowDetectObjectsCustomMultipleNoClassifier) ||\n      (rowIndex == DetectorPickerRowDetectObjectsCustomMultipleWithClassifier);\n  switch (rowIndex) {\n    case DetectorPickerRowDetectFaceOnDevice:\n      [self detectFacesInImage:_imageView.image];\n      break;\n    case DetectorPickerRowDetectTextOnDevice:            // Falls through\n    case DetectorPickerRowDetectTextChineseOnDevice:     // Falls through\n    case DetectorPickerRowDetectTextDevanagariOnDevice:  // Falls through\n    case DetectorPickerRowDetectTextJapaneseOnDevice:    // Falls through\n    case DetectorPickerRowDetectTextKoreanOnDevice:\n      [self detectTextOnDeviceInImage:_imageView.image fromRow:rowIndex];\n      break;\n    case DetectorPickerRowDetectBarcodeOnDevice:\n      [self detectBarcodesInImage:_imageView.image];\n      break;\n    case DetectorPickerRowDetectImageLabelsOnDevice:\n      [self detectLabelsInImage:_imageView.image useCustomModel:NO];\n      break;\n    case DetectorPickerRowDetectImageLabelsCustomOnDevice:\n      [self detectLabelsInImage:_imageView.image useCustomModel:YES];\n      break;\n    case DetectorPickerRowDetectObjectsProminentNoClassifier:\n    case DetectorPickerRowDetectObjectsProminentWithClassifier:\n    case DetectorPickerRowDetectObjectsMultipleNoClassifier:\n    case DetectorPickerRowDetectObjectsMultipleWithClassifier: {\n      MLKObjectDetectorOptions *options = [MLKObjectDetectorOptions new];\n      options.shouldEnableClassification = shouldEnableClassification;\n      options.shouldEnableMultipleObjects = shouldEnableMultipleObjects;\n      options.detectorMode = MLKObjectDetectorModeSingleImage;\n      [self detectObjectsOnDeviceInImage:_imageView.image withOptions:options];\n      break;\n    }\n    case DetectorPickerRowDetectObjectsCustomProminentNoClassifier:\n    case DetectorPickerRowDetectObjectsCustomProminentWithClassifier:\n    case DetectorPickerRowDetectObjectsCustomMultipleNoClassifier:\n    case DetectorPickerRowDetectObjectsCustomMultipleWithClassifier: {\n      NSString *localModelFilePath = [[NSBundle mainBundle] pathForResource:localModelFileName\n                                                                     ofType:localModelFileType];\n      if (localModelFilePath == nil) {\n        NSLog(@\"Failed to find custom local model file: %@.%@\", localModelFileName,\n              localModelFileType);\n        return;\n      }\n      MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];\n      MLKCustomObjectDetectorOptions *options =\n          [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];\n      options.shouldEnableClassification = shouldEnableClassification;\n      options.shouldEnableMultipleObjects = shouldEnableMultipleObjects;\n      options.detectorMode = MLKObjectDetectorModeSingleImage;\n      [self detectObjectsOnDeviceInImage:_imageView.image withOptions:options];\n      break;\n    }\n    case DetectorPickerRowDetectPose:\n    case DetectorPickerRowDetectPoseAccurate:\n      [self detectPoseInImage:_imageView.image];\n      break;\n    case DetectorPickerRowSegmentationSelfie:\n      [self detectSegmentationMaskInImage:_imageView.image];\n      break;\n  }\n}\n\n- (IBAction)openPhotoLibrary:(id)sender {\n  _imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;\n  [self presentViewController:_imagePicker animated:YES completion:nil];\n}\n\n- (IBAction)openCamera:(id)sender {\n  if (![UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront] &&\n      ![UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]) {\n    return;\n  }\n  _imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;\n  [self presentViewController:_imagePicker animated:YES completion:nil];\n}\n\n- (IBAction)changeImage:(id)sender {\n  [self clearResults];\n  self.currentImage = (_currentImage + 1) % images.count;\n  _imageView.image = [UIImage imageNamed:images[_currentImage]];\n}\n\n/** Removes the detection annotations from the annotation overlay view. */\n- (void)removeDetectionAnnotations {\n  for (UIView *annotationView in _annotationOverlayView.subviews) {\n    [annotationView removeFromSuperview];\n  }\n}\n\n/** Clears the results text view and removes any frames that are visible. */\n- (void)clearResults {\n  [self removeDetectionAnnotations];\n  self.resultsText = [NSMutableString new];\n}\n\n- (void)showResults {\n  UIAlertController *resultsAlertController =\n      [UIAlertController alertControllerWithTitle:@\"Detection Results\"\n                                          message:nil\n                                   preferredStyle:UIAlertControllerStyleActionSheet];\n  [resultsAlertController\n      addAction:[UIAlertAction actionWithTitle:@\"OK\"\n                                         style:UIAlertActionStyleDestructive\n                                       handler:^(UIAlertAction *_Nonnull action) {\n                                         [resultsAlertController dismissViewControllerAnimated:YES\n                                                                                    completion:nil];\n                                       }]];\n  resultsAlertController.message = _resultsText;\n  resultsAlertController.popoverPresentationController.barButtonItem = _detectButton;\n  resultsAlertController.popoverPresentationController.sourceView = self.view;\n  [self presentViewController:resultsAlertController animated:YES completion:nil];\n  NSLog(@\"%@\", _resultsText);\n}\n\n/** Updates the image view with a scaled version of the given image. */\n- (void)updateImageViewWithImage:(UIImage *)image {\n  CGFloat scaledImageWidth = 0.0;\n  CGFloat scaledImageHeight = 0.0;\n  switch (UIApplication.sharedApplication.statusBarOrientation) {\n    case UIInterfaceOrientationPortrait:\n    case UIInterfaceOrientationPortraitUpsideDown:\n    case UIInterfaceOrientationUnknown:\n      scaledImageWidth = _imageView.bounds.size.width;\n      scaledImageHeight = image.size.height * scaledImageWidth / image.size.width;\n      break;\n    case UIInterfaceOrientationLandscapeLeft:\n    case UIInterfaceOrientationLandscapeRight:\n      scaledImageWidth = image.size.width * scaledImageHeight / image.size.height;\n      scaledImageHeight = _imageView.bounds.size.height;\n      break;\n  }\n\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{\n    // Scale image while maintaining aspect ratio so it displays better in the UIImageView.\n    UIImage *scaledImage =\n        [image scaledImageWithSize:CGSizeMake(scaledImageWidth, scaledImageHeight)];\n    if (!scaledImage) {\n      scaledImage = image;\n    }\n    if (!scaledImage) {\n      return;\n    }\n    dispatch_async(dispatch_get_main_queue(), ^{\n      __strong typeof(weakSelf) strongSelf = weakSelf;\n      strongSelf->_imageView.image = scaledImage;\n    });\n  });\n}\n\n- (CGAffineTransform)transformMatrix {\n  UIImage *image = _imageView.image;\n  if (!image) {\n    return CGAffineTransformMake(0, 0, 0, 0, 0, 0);\n  }\n  CGFloat imageViewWidth = _imageView.frame.size.width;\n  CGFloat imageViewHeight = _imageView.frame.size.height;\n  CGFloat imageWidth = image.size.width;\n  CGFloat imageHeight = image.size.height;\n\n  CGFloat imageViewAspectRatio = imageViewWidth / imageViewHeight;\n  CGFloat imageAspectRatio = imageWidth / imageHeight;\n  CGFloat scale = (imageViewAspectRatio > imageAspectRatio) ? imageViewHeight / imageHeight\n                                                            : imageViewWidth / imageWidth;\n\n  // Image view's `contentMode` is `scaleAspectFit`, which scales the image to fit the size of the\n  // image view by maintaining the aspect ratio. Multiple by `scale` to get image's original size.\n  CGFloat scaledImageWidth = imageWidth * scale;\n  CGFloat scaledImageHeight = imageHeight * scale;\n  CGFloat xValue = (imageViewWidth - scaledImageWidth) / 2.0;\n  CGFloat yValue = (imageViewHeight - scaledImageHeight) / 2.0;\n\n  CGAffineTransform transform =\n      CGAffineTransformTranslate(CGAffineTransformIdentity, xValue, yValue);\n  return CGAffineTransformScale(transform, scale, scale);\n}\n\n- (CGPoint)pointFromVisionPoint:(MLKVisionPoint *)visionPoint {\n  return CGPointMake(visionPoint.x, visionPoint.y);\n}\n\n- (void)addContoursForFace:(MLKFace *)face transform:(CGAffineTransform)transform {\n  // Face\n  MLKFaceContour *faceContour = [face contourOfType:MLKFaceContourTypeFace];\n  for (MLKVisionPoint *visionPoint in faceContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n\n  // Eyebrows\n  MLKFaceContour *leftEyebrowTopContour = [face contourOfType:MLKFaceContourTypeLeftEyebrowTop];\n  for (MLKVisionPoint *visionPoint in leftEyebrowTopContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n  MLKFaceContour *leftEyebrowBottomContour =\n      [face contourOfType:MLKFaceContourTypeLeftEyebrowBottom];\n  for (MLKVisionPoint *visionPoint in leftEyebrowBottomContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n  MLKFaceContour *rightEyebrowTopContour = [face contourOfType:MLKFaceContourTypeRightEyebrowTop];\n  for (MLKVisionPoint *visionPoint in rightEyebrowTopContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n  MLKFaceContour *rightEyebrowBottomContour =\n      [face contourOfType:MLKFaceContourTypeRightEyebrowBottom];\n  for (MLKVisionPoint *visionPoint in rightEyebrowBottomContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n\n  // Eyes\n  MLKFaceContour *leftEyeContour = [face contourOfType:MLKFaceContourTypeLeftEye];\n  for (MLKVisionPoint *visionPoint in leftEyeContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n  MLKFaceContour *rightEyeContour = [face contourOfType:MLKFaceContourTypeRightEye];\n  for (MLKVisionPoint *visionPoint in rightEyeContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n\n  // Lips\n  MLKFaceContour *upperLipTopContour = [face contourOfType:MLKFaceContourTypeUpperLipTop];\n  for (MLKVisionPoint *visionPoint in upperLipTopContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n  MLKFaceContour *upperLipBottomContour = [face contourOfType:MLKFaceContourTypeUpperLipBottom];\n  for (MLKVisionPoint *visionPoint in upperLipBottomContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n  MLKFaceContour *lowerLipTopContour = [face contourOfType:MLKFaceContourTypeLowerLipTop];\n  for (MLKVisionPoint *visionPoint in lowerLipTopContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n  MLKFaceContour *lowerLipBottomContour = [face contourOfType:MLKFaceContourTypeLowerLipBottom];\n  for (MLKVisionPoint *visionPoint in lowerLipBottomContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n\n  // Nose\n  MLKFaceContour *noseBridgeContour = [face contourOfType:MLKFaceContourTypeNoseBridge];\n  for (MLKVisionPoint *visionPoint in noseBridgeContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n  MLKFaceContour *noseBottomContour = [face contourOfType:MLKFaceContourTypeNoseBottom];\n  for (MLKVisionPoint *visionPoint in noseBottomContour.points) {\n    CGPoint point = [self pointFromVisionPoint:visionPoint];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:self->_annotationOverlayView\n                            color:UIColor.greenColor\n                           radius:smallDotRadius];\n  }\n}\n\n- (void)addLandmarksForFace:(MLKFace *)face transform:(CGAffineTransform)transform {\n  // Mouth\n  MLKFaceLandmark *bottomMouthLandmark = [face landmarkOfType:MLKFaceLandmarkTypeMouthBottom];\n  if (bottomMouthLandmark) {\n    CGPoint point = [self pointFromVisionPoint:bottomMouthLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.redColor\n                           radius:largeDotRadius];\n  }\n  MLKFaceLandmark *leftMouthLandmark = [face landmarkOfType:MLKFaceLandmarkTypeMouthLeft];\n  if (leftMouthLandmark) {\n    CGPoint point = [self pointFromVisionPoint:leftMouthLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.redColor\n                           radius:largeDotRadius];\n  }\n  MLKFaceLandmark *rightMouthLandmark = [face landmarkOfType:MLKFaceLandmarkTypeMouthLeft];\n  if (rightMouthLandmark) {\n    CGPoint point = [self pointFromVisionPoint:rightMouthLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.redColor\n                           radius:largeDotRadius];\n  }\n\n  // Nose\n  MLKFaceLandmark *noseBaseLandmark = [face landmarkOfType:MLKFaceLandmarkTypeNoseBase];\n  if (noseBaseLandmark) {\n    CGPoint point = [self pointFromVisionPoint:noseBaseLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.yellowColor\n                           radius:largeDotRadius];\n  }\n\n  // Eyes\n  MLKFaceLandmark *leftEyeLandmark = [face landmarkOfType:MLKFaceLandmarkTypeLeftEye];\n  if (leftEyeLandmark) {\n    CGPoint point = [self pointFromVisionPoint:leftEyeLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.cyanColor\n                           radius:largeDotRadius];\n  }\n  MLKFaceLandmark *rightEyeLandmark = [face landmarkOfType:MLKFaceLandmarkTypeRightEye];\n  if (rightEyeLandmark) {\n    CGPoint point = [self pointFromVisionPoint:rightEyeLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.cyanColor\n                           radius:largeDotRadius];\n  }\n\n  // Ears\n  MLKFaceLandmark *leftEarLandmark = [face landmarkOfType:MLKFaceLandmarkTypeLeftEye];\n  if (leftEarLandmark) {\n    CGPoint point = [self pointFromVisionPoint:leftEarLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.purpleColor\n                           radius:largeDotRadius];\n  }\n  MLKFaceLandmark *rightEarLandmark = [face landmarkOfType:MLKFaceLandmarkTypeRightEye];\n  if (rightEarLandmark) {\n    CGPoint point = [self pointFromVisionPoint:rightEarLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.purpleColor\n                           radius:largeDotRadius];\n  }\n\n  // Cheeks\n  MLKFaceLandmark *leftCheekLandmark = [face landmarkOfType:MLKFaceLandmarkTypeLeftEye];\n  if (leftCheekLandmark) {\n    CGPoint point = [self pointFromVisionPoint:leftCheekLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.orangeColor\n                           radius:largeDotRadius];\n  }\n  MLKFaceLandmark *rightCheekLandmark = [face landmarkOfType:MLKFaceLandmarkTypeRightEye];\n  if (rightCheekLandmark) {\n    CGPoint point = [self pointFromVisionPoint:rightCheekLandmark.position];\n    CGPoint transformedPoint = CGPointApplyAffineTransform(point, transform);\n    [UIUtilities addCircleAtPoint:transformedPoint\n                           toView:_annotationOverlayView\n                            color:UIColor.orangeColor\n                           radius:largeDotRadius];\n  }\n}\n\n- (void)process:(MLKVisionImage *)visionImage\n    withTextRecognizer:(MLKTextRecognizer *)textRecognizer {\n  __weak typeof(self) weakSelf = self;\n  // [START recognize_text]\n  [textRecognizer\n      processImage:visionImage\n        completion:^(MLKText *_Nullable text, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (text == nil) {\n            // [START_EXCLUDE]\n            strongSelf.resultsText = [NSMutableString\n                stringWithFormat:@\"Text recognizer failed with error: %@\",\n                                 error ? error.localizedDescription : detectionNoResultsMessage];\n            [strongSelf showResults];\n            // [END_EXCLUDE]\n            return;\n          }\n\n          // [START_EXCLUDE]\n          // Blocks.\n          for (MLKTextBlock *block in text.blocks) {\n            CGRect transformedRect =\n                CGRectApplyAffineTransform(block.frame, [strongSelf transformMatrix]);\n            [UIUtilities addRectangle:transformedRect\n                               toView:self.annotationOverlayView\n                                color:UIColor.purpleColor];\n\n            // Lines.\n            for (MLKTextLine *line in block.lines) {\n              transformedRect =\n                  CGRectApplyAffineTransform(line.frame, [strongSelf transformMatrix]);\n              [UIUtilities addRectangle:transformedRect\n                                 toView:strongSelf.annotationOverlayView\n                                  color:UIColor.orangeColor];\n\n              // Elements.\n              for (MLKTextElement *element in line.elements) {\n                transformedRect =\n                    CGRectApplyAffineTransform(element.frame, [strongSelf transformMatrix]);\n                [UIUtilities addRectangle:transformedRect\n                                   toView:strongSelf.annotationOverlayView\n                                    color:UIColor.greenColor];\n                UILabel *label = [[UILabel alloc] initWithFrame:transformedRect];\n                label.text = element.text;\n                label.adjustsFontSizeToFitWidth = YES;\n                [strongSelf.annotationOverlayView addSubview:label];\n              }\n            }\n          }\n          [strongSelf.resultsText appendFormat:@\"%@\\n\", text.text];\n          [strongSelf showResults];\n          // [END_EXCLUDE]\n        }];\n  // [END recognize_text]\n}\n\n#pragma mark - UIPickerViewDataSource\n\n- (NSInteger)numberOfComponentsInPickerView:(nonnull UIPickerView *)pickerView {\n  return componentsCount;\n}\n\n- (NSInteger)pickerView:(nonnull UIPickerView *)pickerView\n    numberOfRowsInComponent:(NSInteger)component {\n  return rowsCount;\n}\n\n#pragma mark - UIPickerViewDelegate\n\n- (nullable NSString *)pickerView:(UIPickerView *)pickerView\n                      titleForRow:(NSInteger)row\n                     forComponent:(NSInteger)component {\n  return [self stringForDetectorPickerRow:row];\n}\n\n- (void)pickerView:(UIPickerView *)pickerView\n      didSelectRow:(NSInteger)row\n       inComponent:(NSInteger)component {\n  [self clearResults];\n}\n\n#pragma mark - UIImagePickerControllerDelegate\n\n- (void)imagePickerController:(UIImagePickerController *)picker\n    didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info {\n  [self clearResults];\n  UIImage *pickedImage = info[UIImagePickerControllerOriginalImage];\n  if (pickedImage) {\n    [self updateImageViewWithImage:pickedImage];\n  }\n  [self dismissViewControllerAnimated:YES completion:nil];\n}\n\n#pragma mark - Vision On-Device Detection\n\n/**\n * Detects faces on the specified image and draws a frame around the detected faces using the\n * On-Device face API.\n *\n * @param image The image.\n */\n- (void)detectFacesInImage:(UIImage *)image {\n  if (!image) {\n    return;\n  }\n\n  // Create a face detector with options.\n  // [START config_face]\n  MLKFaceDetectorOptions *options = [MLKFaceDetectorOptions new];\n  options.landmarkMode = MLKFaceDetectorLandmarkModeAll;\n  options.contourMode = MLKFaceDetectorContourModeAll;\n  options.classificationMode = MLKFaceDetectorClassificationModeAll;\n  options.performanceMode = MLKFaceDetectorPerformanceModeAccurate;\n  // [END config_face]\n\n  // [START init_face]\n  MLKFaceDetector *faceDetector = [MLKFaceDetector faceDetectorWithOptions:options];\n  // [END init_face]\n\n  // Initialize a `VisionImage` object with the given `UIImage`.\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];\n  visionImage.orientation = image.imageOrientation;\n\n  // [START detect_faces]\n  __weak typeof(self) weakSelf = self;\n  [faceDetector\n      processImage:visionImage\n        completion:^(NSArray<MLKFace *> *_Nullable faces, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (!faces || faces.count == 0) {\n            // [START_EXCLUDE]\n            NSString *errorString = error ? error.localizedDescription : detectionNoResultsMessage;\n            strongSelf.resultsText = [NSMutableString\n                stringWithFormat:@\"On-Device face detection failed with error: %@\", errorString];\n            [strongSelf showResults];\n            // [END_EXCLUDE]\n            return;\n          }\n\n          // Faces detected\n          // [START_EXCLUDE]\n          [strongSelf.resultsText setString:@\"\"];\n          for (MLKFace *face in faces) {\n            CGAffineTransform transform = [strongSelf transformMatrix];\n            CGRect transformedRect = CGRectApplyAffineTransform(face.frame, transform);\n            [UIUtilities addRectangle:transformedRect\n                               toView:strongSelf.annotationOverlayView\n                                color:UIColor.greenColor];\n            [strongSelf addLandmarksForFace:face transform:transform];\n            [strongSelf addContoursForFace:face transform:transform];\n            [strongSelf.resultsText appendFormat:@\"Frame: %@\\n\", NSStringFromCGRect(face.frame)];\n            NSString *headEulerAngleX =\n                face.hasHeadEulerAngleX ? [NSString stringWithFormat:@\"%.2f\", face.headEulerAngleX]\n                                        : @\"NA\";\n            NSString *headEulerAngleY =\n                face.hasHeadEulerAngleY ? [NSString stringWithFormat:@\"%.2f\", face.headEulerAngleY]\n                                        : @\"NA\";\n            NSString *headEulerAngleZ =\n                face.hasHeadEulerAngleZ ? [NSString stringWithFormat:@\"%.2f\", face.headEulerAngleZ]\n                                        : @\"NA\";\n            NSString *leftEyeOpenProbability =\n                face.hasLeftEyeOpenProbability\n                    ? [NSString stringWithFormat:@\"%.2f\", face.leftEyeOpenProbability]\n                    : @\"NA\";\n            NSString *rightEyeOpenProbability =\n                face.hasRightEyeOpenProbability\n                    ? [NSString stringWithFormat:@\"%.2f\", face.rightEyeOpenProbability]\n                    : @\"NA\";\n            NSString *smilingProbability =\n                face.hasSmilingProbability\n                    ? [NSString stringWithFormat:@\"%.2f\", face.smilingProbability]\n                    : @\"NA\";\n            [strongSelf.resultsText appendFormat:@\"Head Euler Angle X: %@\\n\", headEulerAngleX];\n            [strongSelf.resultsText appendFormat:@\"Head Euler Angle Y: %@\\n\", headEulerAngleY];\n            [strongSelf.resultsText appendFormat:@\"Head Euler Angle Z: %@\\n\", headEulerAngleZ];\n            [strongSelf.resultsText\n                appendFormat:@\"Left Eye Open Probability: %@\\n\", leftEyeOpenProbability];\n            [strongSelf.resultsText\n                appendFormat:@\"Right Eye Open Probability: %@\\n\", rightEyeOpenProbability];\n            [strongSelf.resultsText appendFormat:@\"Smiling Probability: %@\\n\", smilingProbability];\n          }\n          [strongSelf showResults];\n          // [END_EXCLUDE]\n        }];\n  // [END detect_faces]\n}\n\n/**\n * Detects barcodes on the specified image and draws a frame around the detected barcodes using\n * the On-Device barcode API.\n *\n * @param image The image.\n */\n- (void)detectBarcodesInImage:(UIImage *)image {\n  if (!image) {\n    return;\n  }\n\n  // Define the options for a barcode detector.\n  // [START config_barcode]\n  MLKBarcodeFormat format = MLKBarcodeFormatAll;\n  MLKBarcodeScannerOptions *barcodeOptions =\n      [[MLKBarcodeScannerOptions alloc] initWithFormats:format];\n  // [END config_barcode]\n\n  // Create a barcode detector.\n  // [START init_barcode]\n  MLKBarcodeScanner *barcodeScanner = [MLKBarcodeScanner barcodeScannerWithOptions:barcodeOptions];\n  // [END init_barcode]\n\n  // Initialize a `VisionImage` object with the given `UIImage`.\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];\n  visionImage.orientation = image.imageOrientation;\n\n  // [START detect_barcodes]\n  __weak typeof(self) weakSelf = self;\n  [barcodeScanner\n      processImage:visionImage\n        completion:^(NSArray<MLKBarcode *> *_Nullable barcodes, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (!barcodes || barcodes.count == 0) {\n            // [START_EXCLUDE]\n            NSString *errorString = error ? error.localizedDescription : detectionNoResultsMessage;\n            strongSelf.resultsText = [NSMutableString\n                stringWithFormat:@\"On-Device barcode detection failed with error: %@\", errorString];\n            [strongSelf showResults];\n            // [END_EXCLUDE]\n            return;\n          }\n\n          // [START_EXCLUDE]\n          [strongSelf.resultsText setString:@\"\"];\n          for (MLKBarcode *barcode in barcodes) {\n            CGAffineTransform transform = [strongSelf transformMatrix];\n            CGRect transformedRect = CGRectApplyAffineTransform(barcode.frame, transform);\n            [UIUtilities addRectangle:transformedRect\n                               toView:strongSelf.annotationOverlayView\n                                color:UIColor.greenColor];\n            [strongSelf.resultsText appendFormat:@\"DisplayValue: %@, RawValue: %@, Frame: %@\\n\",\n                                                 barcode.displayValue, barcode.rawValue,\n                                                 NSStringFromCGRect(barcode.frame)];\n          }\n          [strongSelf showResults];\n          // [END_EXCLUDE]\n        }];\n  // [END detect_barcodes]\n}\n\n/**\n * Detects poses on the specified image and draws pose landmark points and line segments using the\n * pose API.\n *\n * @param image The image.\n */\n- (void)detectPoseInImage:(UIImage *)image {\n  if (!image) {\n    return;\n  }\n\n  GMLImage *inputImage = [[GMLImage alloc] initWithImage:image];\n  inputImage.orientation = image.imageOrientation;\n\n  CGAffineTransform transform = [self transformMatrix];\n\n  __weak typeof(self) weakSelf = self;\n  [self.poseDetector\n      processImage:inputImage\n        completion:^(NSArray<MLKPose *> *_Nullable poses, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (strongSelf == nil) {\n            return;\n          }\n          if (poses.count == 0) {\n            NSString *errorString = error ? error.localizedDescription : detectionNoResultsMessage;\n            strongSelf.resultsText = [NSMutableString\n                stringWithFormat:@\"Pose detection failed with error: %@\", errorString];\n            [strongSelf showResults];\n            return;\n          }\n\n          // Pose detection currently only supports single pose.\n          MLKPose *pose = poses.firstObject;\n\n          UIView *poseOverlay =\n              [UIUtilities poseOverlayViewForPose:pose\n                                 inViewWithBounds:self.annotationOverlayView.bounds\n                                        lineWidth:3.0f\n                                        dotRadius:smallDotRadius\n                      positionTransformationBlock:^(MLKVisionPoint *position) {\n                        return CGPointApplyAffineTransform(\n                            [strongSelf pointFromVisionPoint:position], transform);\n                      }];\n\n          [strongSelf.annotationOverlayView addSubview:poseOverlay];\n          strongSelf.resultsText = [NSMutableString stringWithFormat:@\"Pose Detected\"];\n          [strongSelf showResults];\n        }];\n}\n\n- (void)detectSegmentationMaskInImage:(UIImage *)image {\n  if (!image) {\n    return;\n  }\n\n  // Initialize a `VisionImage` object with the given `UIImage`.\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];\n  visionImage.orientation = image.imageOrientation;\n\n  __weak __typeof(self) weakSelf = self;\n  [self.segmenter\n      processImage:visionImage\n        completion:^(MLKSegmentationMask *_Nullable mask, NSError *_Nullable error) {\n          __strong __typeof(weakSelf) strongSelf = weakSelf;\n\n          if (mask == nil) {\n            NSString *errorString = error ? error.localizedDescription : detectionNoResultsMessage;\n            strongSelf.resultsText = [NSMutableString\n                stringWithFormat:@\"Segmentation failed with error: %@\", errorString];\n            [strongSelf showResults];\n            return;\n          }\n\n          CVPixelBufferRef imageBuffer = [UIUtilities imageBufferFromUIImage:image];\n          UIColor *backgroundColor =\n              [UIColor.purpleColor colorWithAlphaComponent:segmentationMaskAlpha];\n          [UIUtilities applySegmentationMask:mask\n                               toImageBuffer:imageBuffer\n                         withBackgroundColor:backgroundColor\n                             foregroundColor:nil];\n\n          UIImage *maskedImage = [UIUtilities UIImageFromImageBuffer:imageBuffer\n                                                         orientation:image.imageOrientation];\n          CVPixelBufferRelease(imageBuffer);\n\n          UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero];\n          imageView.frame = strongSelf.annotationOverlayView.bounds;\n          imageView.contentMode = UIViewContentModeScaleAspectFit;\n          imageView.image = maskedImage;\n\n          [strongSelf.annotationOverlayView addSubview:imageView];\n          strongSelf.resultsText = [NSMutableString stringWithFormat:@\"Segmentation Succeeded\"];\n          [strongSelf showResults];\n        }];\n}\n\n/**\n * Detects labels on the specified image using the On-Device label API.\n *\n * @param image The image.\n * @param useCustomModel Whether to use the custom image labeling model.\n */\n- (void)detectLabelsInImage:(UIImage *)image useCustomModel:(BOOL)useCustomModel {\n  if (!image) {\n    return;\n  }\n\n  // [START config_label]\n  MLKCommonImageLabelerOptions *options;\n  if (useCustomModel) {\n    NSString *localModelPath = [[NSBundle mainBundle] pathForResource:localModelFileName\n                                                               ofType:localModelFileType];\n    MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelPath];\n    options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];\n  } else {\n    options = [[MLKImageLabelerOptions alloc] init];\n  }\n  options.confidenceThreshold = @(labelConfidenceThreshold);\n  // [END config_label]\n\n  // [START init_label]\n  MLKImageLabeler *onDeviceLabeler = [MLKImageLabeler imageLabelerWithOptions:options];\n  // [END init_label]\n\n  // Initialize a `VisionImage` object with the given `UIImage`.\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];\n  visionImage.orientation = image.imageOrientation;\n\n  // [START detect_label]\n  __weak typeof(self) weakSelf = self;\n  [onDeviceLabeler\n      processImage:visionImage\n        completion:^(NSArray<MLKImageLabel *> *_Nullable labels, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (labels.count == 0) {\n            // [START_EXCLUDE]\n            NSString *errorString =\n                error != nil ? error.localizedDescription : detectionNoResultsMessage;\n            [strongSelf.resultsText\n                appendFormat:@\"On-Device label detection failed with error: %@\", errorString];\n            [strongSelf showResults];\n            // [END_EXCLUDE]\n            return;\n          }\n\n          // [START_EXCLUDE]\n          [strongSelf.resultsText setString:@\"\"];\n          for (MLKImageLabel *label in labels) {\n            [strongSelf.resultsText\n                appendFormat:@\"Label: %@, Confidence: %f\\n\", label.text, label.confidence];\n          }\n          [strongSelf showResults];\n          // [END_EXCLUDE]\n        }];\n  // [END detect_label]\n}\n\n/**\n * Detects text on the specified image and draws a frame around the recognized text using the\n * On-Device text recognizer.\n *\n * @param image The image.\n */\n- (void)detectTextOnDeviceInImage:(UIImage *)image fromRow:(DetectorPickerRow)row {\n  if (!image) {\n    return;\n  }\n\n  // [START init_text]\n  MLKCommonTextRecognizerOptions *options;\n  if (row == DetectorPickerRowDetectTextChineseOnDevice) {\n    options = [[MLKChineseTextRecognizerOptions alloc] init];\n  } else if (row == DetectorPickerRowDetectTextDevanagariOnDevice) {\n    options = [[MLKDevanagariTextRecognizerOptions alloc] init];\n  } else if (row == DetectorPickerRowDetectTextJapaneseOnDevice) {\n    options = [[MLKJapaneseTextRecognizerOptions alloc] init];\n  } else if (row == DetectorPickerRowDetectTextKoreanOnDevice) {\n    options = [[MLKKoreanTextRecognizerOptions alloc] init];\n  } else {\n    options = [[MLKTextRecognizerOptions alloc] init];\n  }\n  MLKTextRecognizer *onDeviceTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];\n  // [END init_text]\n\n  // Initialize a `VisionImage` object with the given `UIImage`.\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];\n  visionImage.orientation = image.imageOrientation;\n\n  [self.resultsText appendString:@\"Running On-Device Text Recognition...\\n\"];\n  [self process:visionImage withTextRecognizer:onDeviceTextRecognizer];\n}\n\n/**\n * Detects objects on the specified image and draws a frame around them.\n *\n * @param image The image.\n * @param options The options for object detector.\n */\n- (void)detectObjectsOnDeviceInImage:(UIImage *)image\n                         withOptions:(MLKCommonObjectDetectorOptions *)options {\n  if (!image) {\n    return;\n  }\n\n  // [START init_object_detector]\n  // Create an objects detector with options.\n  MLKObjectDetector *detector = [MLKObjectDetector objectDetectorWithOptions:options];\n  // [END init_object_detector]\n\n  // Initialize a `VisionImage` object with the given `UIImage`.\n  MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];\n  visionImage.orientation = image.imageOrientation;\n\n  // [START detect_object]\n  __weak typeof(self) weakSelf = self;\n  [detector processImage:visionImage\n              completion:^(NSArray<MLKObject *> *_Nullable objects, NSError *_Nullable error) {\n                __strong typeof(weakSelf) strongSelf = weakSelf;\n                if (error != nil) {\n                  // [START_EXCLUDE]\n                  NSString *errorString =\n                      error ? error.localizedDescription : detectionNoResultsMessage;\n                  strongSelf.resultsText = [NSMutableString\n                      stringWithFormat:@\"Object detection failed with error: %@\", errorString];\n                  [strongSelf showResults];\n                  // [END_EXCLUDE]\n                }\n                if (!objects || objects.count == 0) {\n                  // [START_EXCLUDE]\n                  strongSelf.resultsText =\n                      [@\"On-Device object detector returned no results.\" mutableCopy];\n                  [strongSelf showResults];\n                  // [END_EXCLUDE]\n                  return;\n                }\n\n                // [START_EXCLUDE]\n                [strongSelf.resultsText setString:@\"\"];\n                for (MLKObject *object in objects) {\n                  CGAffineTransform transform = [self transformMatrix];\n                  CGRect transformedRect = CGRectApplyAffineTransform(object.frame, transform);\n                  [UIUtilities addRectangle:transformedRect\n                                     toView:self.annotationOverlayView\n                                      color:UIColor.greenColor];\n\n                  [strongSelf.resultsText appendFormat:@\"Frame: %@\\nObject ID: %@\\nLabels:\\n\",\n                                                       NSStringFromCGRect(object.frame),\n                                                       object.trackingID];\n                  int i = 0;\n                  for (MLKObjectLabel *l in object.labels) {\n                    NSString *labelString =\n                        [NSString stringWithFormat:@\"Label %d: %@, %f, %lu\\n\", i++, l.text,\n                                                   l.confidence, (unsigned long)l.index];\n                    [strongSelf.resultsText appendString:labelString];\n                  }\n                }\n                [strongSelf showResults];\n                // [END_EXCLUDE]\n              }];\n  // [END detect_object]\n}\n\n#pragma mark - Private\n\n/**\n * Resets any detector instances which use a conventional lifecycle paradigm. This approach is\n * advantageous to tearing down old detectors in the `UIPickerViewDelegate` method because that\n * method isn't actually invoked in-sync with when the selected row changes and can result in\n * tearing down the wrong detector in the event of a race condition.\n *\n * @param activeDetectorRow The new detector row for which detection will be run.\n */\n- (void)resetManagedLifecycleDetectorsForActiveDetectorRow:(DetectorPickerRow)activeDetectorRow {\n  if (activeDetectorRow == self.lastDetectorRow) {\n    // Same row as before, no need to reset any detectors.\n    return;\n  }\n  // Clear the old detector, if applicable.\n  switch (self.lastDetectorRow) {\n    case DetectorPickerRowDetectPose:\n    case DetectorPickerRowDetectPoseAccurate:\n      self.poseDetector = nil;\n      break;\n    case DetectorPickerRowSegmentationSelfie:\n      self.segmenter = nil;\n      break;\n    default:\n      break;\n  }\n  // Initialize the new detector, if applicable.\n  switch (activeDetectorRow) {\n    case DetectorPickerRowDetectPose:\n    case DetectorPickerRowDetectPoseAccurate: {\n      MLKCommonPoseDetectorOptions *options = activeDetectorRow == DetectorPickerRowDetectPose\n                                                  ? [[MLKPoseDetectorOptions alloc] init]\n                                                  : [[MLKAccuratePoseDetectorOptions alloc] init];\n      options.detectorMode = MLKPoseDetectorModeSingleImage;\n      self.poseDetector = [MLKPoseDetector poseDetectorWithOptions:options];\n      break;\n    }\n    case DetectorPickerRowSegmentationSelfie: {\n      MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init];\n      options.segmenterMode = MLKSegmenterModeSingleImage;\n      self.segmenter = [MLKSegmenter segmenterWithOptions:options];\n      break;\n    }\n    default:\n      break;\n  }\n  self.lastDetectorRow = activeDetectorRow;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/quickstarts/vision/VisionExampleObjC/main.m",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char* argv[]) {\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/showcase/translate-showcase/Assets.xcassets/Image.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"greyscale-regular.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"greyscale-regular@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"greyscale-regular@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/showcase/translate-showcase/Assets.xcassets/baseline_check_black_24pt.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_check_black_24pt_1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_check_black_24pt_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"baseline_check_black_24pt_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "ios/showcase/translate-showcase/Assets.xcassets/ic_arrow_back.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_arrow_back.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_arrow_back_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_arrow_back_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "ios/showcase/translate-showcase/Assets.xcassets/ic_close.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_close.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_close_2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ic_close_3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/showcase/translate-showcase/Podfile",
    "content": "platform :ios, '10.0'\nuse_frameworks!\n\npod 'GoogleMLKit/LanguageID'\npod 'GoogleMLKit/TextRecognition'\npod 'GoogleMLKit/Translate'\npod 'MaterialComponents'\n\ntarget 'TranslateDemo' do\nend\n\n"
  },
  {
    "path": "ios/showcase/translate-showcase/README.md",
    "content": "# ML Kit Translate Demo with Material Design\n\nThis app demonstrates how to build an end-to-end user experience with [Google ML Kit APIs](https://developers.google.com/ml-kit) and following the new [Material for ML design guidelines](https://material.io/design/machine-learning/).\n\nThe goal is to make it as easy as possible to integrate ML Kit into your app with an experience that has been user tested:\n\n* Real-time translate using the on-device Text Recognition, Language ID, Translate APIs - an end-to-end solution from text recognition to translate in live camera.\n\n![live_translate](./translate.gif)\n\n\n## Steps to run the app\n\n1. Clone this repo locally\n  ```\n  git clone https://github.com/googlecodelabs/mlkit-ios\n  ```\n2. Find a `Podfile` in the folder and install all the dependency pods by running the following command:\n  ```\n  cd mlkit-ios\n  cd translate\n  pod cache clean --all\n  pod install --repo-update\n  ```\n3. Open the generated `TranslateDemo.xcworkspace` file.\n4. [Create a Firebase project in the Firebase console](https://firebase.google.com/docs/ios/setup),if you don't already have one.\n5. Add a new iOS app into your Firebase project with a bundle ID like ***com.google.firebase.ml.md***.\n6. Download `GoogleService-Info.plist` from the newly added app and add it to the\n  ShowcaseApp project in Xcode. Remember to check `Copy items if needed` and\n  select `Create folder references`.\n7. Select the project in Xcode and uncheck `Automatically manage signing` option in\n  `General` tab, and choose your own provisioning file.\n8. Build and run it on a physical device (the simulator isn't recommended, as the app needs to use the camera on the device).\n\n## How to use the app\n\nThis app demonstrates live text translate using the camera:\n* Open the app and point the bounding box of the camera at a text of interest. The recognized text and it's detected language will show up on the top part of the bottom sheet.\n* As you keep the camera stable to recognize a text, you'll see the translated version of this text on the bottom in real-time using the on-device Translate API.\n* You can also switch the translate language using the chips below, or clicking the \"More\" chip to search & select any of the 59 languages available.\n\n\n## License\n© Google, 2019. Licensed under an [Apache-2](./LICENSE) license.\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/AppDelegate.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n  var window: UIWindow?\n\n  func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?\n  ) -> Bool {\n    return true\n  }\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14490.70\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"0Q6-lG-sCk\">\n    <device id=\"retina5_9\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14490.49\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Navigation Controller-->\n        <scene sceneID=\"rAH-gT-x68\">\n            <objects>\n                <navigationController id=\"0Q6-lG-sCk\" sceneMemberID=\"viewController\">\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"JoS-YE-9OV\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"44\" width=\"375\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <color key=\"tintColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <color key=\"barTintColor\" red=\"0.0078431372549019607\" green=\"0.53333333333333333\" blue=\"0.81960784313725488\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <textAttributes key=\"titleTextAttributes\">\n                            <fontDescription key=\"fontDescription\" style=\"UICTFontTextStyleTitle2\"/>\n                            <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        </textAttributes>\n                    </navigationBar>\n                    <connections>\n                        <segue destination=\"YXl-5B-mBF\" kind=\"relationship\" relationship=\"rootViewController\" id=\"v8c-tJ-HdM\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"6gn-Xt-3Nz\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-607\" y=\"134\"/>\n        </scene>\n        <!--Camera View Controller-->\n        <scene sceneID=\"kPU-gK-lh6\">\n            <objects>\n                <viewController id=\"YXl-5B-mBF\" customClass=\"CameraViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"qO2-JB-Jc4\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"7NG-lt-hPa\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"bWY-Sx-TCF\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"812\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vwd-Qp-BMC\" userLabel=\"Camera View\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"88\" width=\"375\" height=\"321\"/>\n                                <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                            </view>\n                            <view contentMode=\"scaleToFill\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"R5j-gh-HrB\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"409\" width=\"375\" height=\"369\"/>\n                                <subviews>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Original\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GHM-ed-7bY\">\n                                        <rect key=\"frame\" x=\"16\" y=\"8\" width=\"343\" height=\"17\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"14\"/>\n                                        <color key=\"textColor\" white=\"0.33333333329999998\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"detected\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" minimumScaleFactor=\"0.69999999999999996\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ljw-4O-M6o\">\n                                        <rect key=\"frame\" x=\"16\" y=\"33\" width=\"343\" height=\"28.666666666666671\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"24\"/>\n                                        <color key=\"textColor\" cocoaTouchSystemColor=\"scrollViewTexturedBackgroundColor\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                    <view userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1fF-V6-9LH\">\n                                        <rect key=\"frame\" x=\"16\" y=\"94.666666666666686\" width=\"343\" height=\"0.3333333333333286\"/>\n                                        <color key=\"backgroundColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"0.5\" id=\"Fn7-fA-U8q\"/>\n                                        </constraints>\n                                    </view>\n                                    <collectionView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" scrollEnabled=\"NO\" dataMode=\"prototypes\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Yby-EB-vdy\">\n                                        <rect key=\"frame\" x=\"16\" y=\"279.66666666666663\" width=\"343\" height=\"33\"/>\n                                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"33\" id=\"Uqz-YR-ZFD\"/>\n                                        </constraints>\n                                        <collectionViewLayout key=\"collectionViewLayout\" id=\"gRy-Gl-BSE\" customClass=\"MDCChipCollectionViewFlowLayout\"/>\n                                        <cells/>\n                                    </collectionView>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"fresh\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"3\" baselineAdjustment=\"alignBaselines\" minimumScaleFactor=\"0.5\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"P66-8P-ATH\">\n                                        <rect key=\"frame\" x=\"16\" y=\"150.33333333333337\" width=\"343\" height=\"52.666666666666657\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"44\"/>\n                                        <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                    <view userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"icr-zj-AEI\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"328.66666666666663\" width=\"375\" height=\"0.33333333333331439\"/>\n                                        <color key=\"backgroundColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"0.5\" id=\"VBL-2A-m5f\"/>\n                                        </constraints>\n                                    </view>\n                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"Image\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Sot-mj-34e\">\n                                        <rect key=\"frame\" x=\"99.666666666666686\" y=\"345\" width=\"176\" height=\"16\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"16\" id=\"jFh-rK-bxe\"/>\n                                        </constraints>\n                                    </imageView>\n                                </subviews>\n                                <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <constraints>\n                                    <constraint firstItem=\"icr-zj-AEI\" firstAttribute=\"leading\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"leading\" id=\"1fN-W3-H0r\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"1fF-V6-9LH\" secondAttribute=\"trailing\" constant=\"16\" id=\"Aym-Iq-CeP\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"GHM-ed-7bY\" secondAttribute=\"trailing\" constant=\"16\" id=\"Ez3-aT-xcx\"/>\n                                    <constraint firstItem=\"Yby-EB-vdy\" firstAttribute=\"leading\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"leading\" constant=\"16\" id=\"GWd-Bt-SmC\"/>\n                                    <constraint firstItem=\"Sot-mj-34e\" firstAttribute=\"centerX\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"centerX\" id=\"PC9-Zd-tvC\"/>\n                                    <constraint firstItem=\"Sot-mj-34e\" firstAttribute=\"top\" secondItem=\"icr-zj-AEI\" secondAttribute=\"bottom\" constant=\"16\" id=\"QPP-BU-TyM\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"369\" id=\"RMC-N9-65S\"/>\n                                    <constraint firstItem=\"icr-zj-AEI\" firstAttribute=\"top\" secondItem=\"Yby-EB-vdy\" secondAttribute=\"bottom\" constant=\"16\" id=\"T1x-4k-2PM\"/>\n                                    <constraint firstItem=\"1fF-V6-9LH\" firstAttribute=\"leading\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"leading\" constant=\"16\" id=\"ZNn-Yz-pSP\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"Ljw-4O-M6o\" secondAttribute=\"trailing\" constant=\"16\" id=\"gFr-lm-Pyp\"/>\n                                    <constraint firstItem=\"GHM-ed-7bY\" firstAttribute=\"leading\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"leading\" constant=\"16\" id=\"hAi-ke-9ph\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"icr-zj-AEI\" secondAttribute=\"trailing\" id=\"hz0-fi-BXh\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"1fF-V6-9LH\" secondAttribute=\"bottom\" constant=\"274\" id=\"iz5-8t-ay8\"/>\n                                    <constraint firstItem=\"P66-8P-ATH\" firstAttribute=\"leading\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"leading\" constant=\"16\" id=\"nJO-GR-gw5\"/>\n                                    <constraint firstItem=\"GHM-ed-7bY\" firstAttribute=\"top\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"top\" constant=\"8\" id=\"nOH-an-MnG\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"Yby-EB-vdy\" secondAttribute=\"trailing\" constant=\"16\" id=\"o1T-ps-gp4\"/>\n                                    <constraint firstItem=\"P66-8P-ATH\" firstAttribute=\"centerY\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"centerY\" constant=\"-8\" id=\"ofj-xB-YCH\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"P66-8P-ATH\" secondAttribute=\"trailing\" constant=\"16\" id=\"rZh-9w-fUu\"/>\n                                    <constraint firstItem=\"Ljw-4O-M6o\" firstAttribute=\"top\" secondItem=\"GHM-ed-7bY\" secondAttribute=\"bottom\" constant=\"8\" id=\"sUA-tC-bEA\"/>\n                                    <constraint firstItem=\"Ljw-4O-M6o\" firstAttribute=\"leading\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"leading\" constant=\"16\" id=\"yJc-GT-Fcb\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"Vwd-Qp-BMC\" secondAttribute=\"trailing\" id=\"4tT-Pw-HXy\"/>\n                            <constraint firstItem=\"R5j-gh-HrB\" firstAttribute=\"top\" secondItem=\"Vwd-Qp-BMC\" secondAttribute=\"bottom\" id=\"DP0-YN-AI6\"/>\n                            <constraint firstItem=\"R5j-gh-HrB\" firstAttribute=\"leading\" secondItem=\"bWY-Sx-TCF\" secondAttribute=\"leading\" id=\"G5P-08-zpO\"/>\n                            <constraint firstItem=\"7NG-lt-hPa\" firstAttribute=\"top\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"bottom\" id=\"SU8-UZ-zOU\"/>\n                            <constraint firstItem=\"Vwd-Qp-BMC\" firstAttribute=\"top\" secondItem=\"qO2-JB-Jc4\" secondAttribute=\"bottom\" id=\"XtO-qt-xHB\"/>\n                            <constraint firstItem=\"7NG-lt-hPa\" firstAttribute=\"top\" secondItem=\"Sot-mj-34e\" secondAttribute=\"bottom\" constant=\"8\" id=\"mzm-TY-yHW\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"R5j-gh-HrB\" secondAttribute=\"trailing\" id=\"syv-b2-JOc\"/>\n                            <constraint firstItem=\"Vwd-Qp-BMC\" firstAttribute=\"leading\" secondItem=\"bWY-Sx-TCF\" secondAttribute=\"leading\" id=\"wxk-6a-dVn\"/>\n                        </constraints>\n                    </view>\n                    <navigationItem key=\"navigationItem\" id=\"8dJ-Hr-2St\">\n                        <nil key=\"title\"/>\n                    </navigationItem>\n                    <connections>\n                        <outlet property=\"chipCollectionView\" destination=\"Yby-EB-vdy\" id=\"Dzn-kl-gfs\"/>\n                        <outlet property=\"detectedLanguageLabel\" destination=\"GHM-ed-7bY\" id=\"iAj-71-a6J\"/>\n                        <outlet property=\"detectedTextLabel\" destination=\"Ljw-4O-M6o\" id=\"4Da-PU-tf4\"/>\n                        <outlet property=\"previewView\" destination=\"Vwd-Qp-BMC\" id=\"4C6-fD-Xal\"/>\n                        <outlet property=\"resultsView\" destination=\"R5j-gh-HrB\" id=\"6ZS-2G-WWK\"/>\n                        <outlet property=\"translatedLabel\" destination=\"P66-8P-ATH\" id=\"2DB-jN-lAD\"/>\n                        <segue destination=\"C7w-EA-mVh\" kind=\"show\" identifier=\"search\" id=\"mmx-RR-deJ\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Tub-Fx-HUo\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"293.60000000000002\" y=\"133.00492610837438\"/>\n        </scene>\n        <!--Search View Controller-->\n        <scene sceneID=\"K2X-Ve-t6I\">\n            <objects>\n                <collectionViewController id=\"C7w-EA-mVh\" customClass=\"SearchViewController\" customModule=\"TranslateDemo\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <collectionView key=\"view\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" id=\"qiz-Dl-qvF\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"812\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <collectionViewFlowLayout key=\"collectionViewLayout\" minimumLineSpacing=\"10\" minimumInteritemSpacing=\"10\" id=\"r6X-As-iia\">\n                            <size key=\"itemSize\" width=\"50\" height=\"50\"/>\n                            <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                            <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                            <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                        </collectionViewFlowLayout>\n                        <cells/>\n                        <connections>\n                            <outlet property=\"dataSource\" destination=\"C7w-EA-mVh\" id=\"2gZ-S7-GoD\"/>\n                            <outlet property=\"delegate\" destination=\"C7w-EA-mVh\" id=\"92E-cj-P6S\"/>\n                        </connections>\n                    </collectionView>\n                </collectionViewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dXt-N6-c9u\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"1183\" y=\"134\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"Image\" width=\"176\" height=\"16\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/CVPixelBuffer+Helpers.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Accelerate\nimport CoreImage\nimport Foundation\n\n/// Crops the pixel buffer.\npublic func resizePixelBuffer(\n  _ srcPixelBuffer: CVPixelBuffer,\n  cropX: Int,\n  cropY: Int,\n  cropWidth: Int,\n  cropHeight: Int\n) -> CVPixelBuffer? {\n  let flags = CVPixelBufferLockFlags(rawValue: 0)\n  guard kCVReturnSuccess == CVPixelBufferLockBaseAddress(srcPixelBuffer, flags) else {\n    return nil\n  }\n  defer { CVPixelBufferUnlockBaseAddress(srcPixelBuffer, flags) }\n\n  guard let srcData = CVPixelBufferGetBaseAddress(srcPixelBuffer) else {\n    print(\"Error: could not get pixel buffer base address\")\n    return nil\n  }\n  let srcBytesPerRow = CVPixelBufferGetBytesPerRow(srcPixelBuffer)\n  let offset = cropY * srcBytesPerRow + cropX * 4\n  var srcBuffer = vImage_Buffer(\n    data: srcData.advanced(by: offset),\n    height: vImagePixelCount(cropHeight),\n    width: vImagePixelCount(cropWidth),\n    rowBytes: srcBytesPerRow)\n\n  let destBytesPerRow = cropWidth * 4\n  guard let destData = malloc(cropHeight * destBytesPerRow) else {\n    print(\"Error: out of memory\")\n    return nil\n  }\n  var destBuffer = vImage_Buffer(\n    data: destData,\n    height: vImagePixelCount(cropHeight),\n    width: vImagePixelCount(cropWidth),\n    rowBytes: destBytesPerRow)\n\n  let error = vImageCopyBuffer(&srcBuffer, &destBuffer, 4, vImage_Flags(0))\n  if error != kvImageNoError {\n    print(\"Error:\", error)\n    free(destData)\n    return nil\n  }\n\n  let releaseCallback: CVPixelBufferReleaseBytesCallback = { _, ptr in\n    if let ptr = ptr {\n      free(UnsafeMutableRawPointer(mutating: ptr))\n    }\n  }\n\n  let pixelFormat = CVPixelBufferGetPixelFormatType(srcPixelBuffer)\n  var dstPixelBuffer: CVPixelBuffer?\n  let status = CVPixelBufferCreateWithBytes(\n    nil, cropWidth, cropHeight,\n    pixelFormat, destData,\n    destBytesPerRow, releaseCallback,\n    nil, nil, &dstPixelBuffer)\n  if status != kCVReturnSuccess {\n    print(\"Error: could not create new pixel buffer\")\n    free(destData)\n    return nil\n  }\n  return dstPixelBuffer\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/CameraOverlayview.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport MaterialComponents\n\nprivate let kBoxBorderWidth: CGFloat = 2.0\nprivate let kLightBoxBorderAlpha: CGFloat = 0.5\nprivate let kBoxCornerRadius: CGFloat = 12.0\nprivate let kChipBackgroundAlpha: CGFloat = 0.6\nprivate let kChipCornerRadius: CGFloat = 8.0\nprivate let kChipFadeInDuration: CGFloat = 0.075\nprivate let kChipScaleDuration: CGFloat = 0.15\nprivate let kChipScaleFromRatio: CGFloat = 0.8\nprivate let kChipScaleToRatio: CGFloat = 1.0\nprivate let kChipBottomPadding: CGFloat = 36.0\nprivate let kBoxBackgroundAlpha: CGFloat = 0.40\n\nclass CameraOverlayView: UIView {\n  private var boxLayer: CAShapeLayer!\n  private var boxMaskLayer: CAShapeLayer!\n  private var messageChip = MDCChipView()\n\n  override init(frame: CGRect) {\n    super.init(frame: frame)\n\n    boxMaskLayer = CAShapeLayer()\n    layer.addSublayer(boxMaskLayer)\n\n    boxLayer = CAShapeLayer()\n    boxLayer.cornerRadius = kBoxCornerRadius\n    layer.addSublayer(boxLayer)\n\n    messageChip.setBackgroundColor(\n      UIColor.black.withAlphaComponent(kChipBackgroundAlpha), for: .normal)\n    messageChip.clipsToBounds = true\n    messageChip.titleLabel.textColor = UIColor.white\n    messageChip.layer.cornerRadius = kChipCornerRadius\n    addSubview(messageChip)\n  }\n\n  required init?(coder aDecoder: NSCoder) {\n    fatalError(\"init(coder:) has not been implemented\")\n  }\n\n  func showBox(in rect: CGRect) {\n    let maskPath = UIBezierPath(rect: self.bounds)\n    let boxPath = UIBezierPath(roundedRect: rect, cornerRadius: kBoxCornerRadius).reversing()\n    maskPath.append(boxPath)\n    boxMaskLayer.frame = self.frame\n    boxMaskLayer.path = maskPath.cgPath\n    boxMaskLayer.strokeStart = 0.0\n    boxMaskLayer.strokeEnd = 1.0\n    self.layer.backgroundColor = UIColor.black.withAlphaComponent(kBoxBackgroundAlpha).cgColor\n\n    self.layer.mask = boxMaskLayer\n    boxLayer.path = UIBezierPath(roundedRect: rect, cornerRadius: kBoxCornerRadius).cgPath\n    boxLayer.lineWidth = kBoxBorderWidth\n    boxLayer.strokeStart = 0.0\n    boxLayer.strokeEnd = 1.0\n    boxLayer.strokeColor = UIColor.white.cgColor\n    boxLayer.fillColor = nil\n  }\n\n  func showMessage(_ message: String?, in center: CGPoint) {\n    if messageChip.titleLabel.text?.isEqual(message) ?? false {\n      return\n    }\n    messageChip.titleLabel.text = message\n    messageChip.sizeToFit()\n    self.messageChip.center = center\n\n  }\n\n  func clear() {\n    boxLayer?.isHidden = true\n    boxLayer?.removeFromSuperlayer()\n  }\n\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/CameraViewController.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport AVFoundation\nimport CoreVideo\nimport MLKit\nimport MaterialComponents\n\nprivate let kBoxCornerRadius: CGFloat = 12.0\nprivate let kBoxBorderWidth: CGFloat = 2.0\nprivate let kBoxBackgroundAlpha: CGFloat = 0.12\nprivate let boxWidth: CGFloat = 340.0\nprivate let boxHeight: CGFloat = 100.0\nprivate let boxWidthHalf = boxWidth / 2\nprivate let boxHeightHalf = boxHeight / 2\nprivate let hdWidth: CGFloat = 720  // AVCaptureSession.Preset.hd1280x720\nprivate let hdHeight: CGFloat = 1280  // AVCaptureSession.Preset.hd1280x720\nprivate let hdWidthHalf = hdWidth / 2\nprivate let hdHeightHalf = hdHeight / 2\nprivate let defaultMargin: CGFloat = 16\nprivate let chipHeight: CGFloat = 32\nprivate let chipHeightHalf = chipHeight / 2\nprivate let customSelectedColor = UIColor(red: 0.10, green: 0.45, blue: 0.91, alpha: 1.0)\nprivate let backgroundColor = UIColor(red: 0.91, green: 0.94, blue: 0.99, alpha: 1.0)\n\n@objc(CameraViewController)\nclass CameraViewController: UIViewController {\n  var detectCounts = [String: Int]()\n  var detectQueue = [String]()\n  var detectedText = \"\"\n  var recentOutputLanguages = [TranslateLanguage.english, TranslateLanguage.spanish]\n  let sizingChip = MDCChipView()\n  var selectedItem = 0\n  var cropX = 0\n  var cropWidth = 0\n  var cropY = 0\n  var cropHeight = 0\n\n  @IBOutlet var chipCollectionView: UICollectionView!\n\n  // We keep track of the pending work item as a property\n  private var pendingRequestWorkItem: DispatchWorkItem?\n\n  private lazy var shapeGenerator: MDCRectangleShapeGenerator = {\n    let gen = MDCRectangleShapeGenerator()\n    gen.setCorners(MDCCornerTreatment.corner(withRadius: 4))\n    return gen\n  }()\n\n  private var previewLayer: AVCaptureVideoPreviewLayer!\n  private var cameraOverlayView: CameraOverlayView!\n  private lazy var captureSession = AVCaptureSession()\n  private lazy var sessionQueue = DispatchQueue(label: Constant.sessionQueueLabel)\n  private lazy var languageId = LanguageIdentification.languageIdentification()\n\n  var translator: Translator!\n\n  @IBOutlet var resultsView: UIView!\n  @IBOutlet var detectedTextLabel: UILabel!\n  @IBOutlet var translateLanguageLabel: UILabel!\n  @IBOutlet var detectedLanguageLabel: UILabel!\n  @IBOutlet var translatedLabel: UILabel!\n  let containerScheme = MDCContainerScheme()\n  var detectedLanguage = TranslateLanguage.english\n\n  private lazy var annotationOverlayView: UIView = {\n    precondition(isViewLoaded)\n    let annotationOverlayView = UIView(frame: .zero)\n    annotationOverlayView.translatesAutoresizingMaskIntoConstraints = false\n    return annotationOverlayView\n  }()\n\n  // MARK: - IBOutlets\n\n  @IBOutlet private weak var previewView: UIView!\n\n  // MARK: - UIViewController\n\n  override func viewDidLoad() {\n    super.viewDidLoad()\n    //Translator.setMaxLoadedTranslators(8);\n    setUpCameraPreviewLayer()\n    sizingChip.mdc_adjustsFontForContentSizeCategory = true\n    setUpAnnotationOverlayView()\n    chipCollectionView.register(\n      MDCChipCollectionViewCell.self, forCellWithReuseIdentifier: \"identifier\")\n    chipCollectionView.dataSource = self\n    chipCollectionView.delegate = self\n    chipCollectionView.isScrollEnabled = false\n\n    let ratio = hdWidth / previewView.bounds.width\n    cropX = Int(hdHeightHalf - (ratio * boxHeightHalf))\n    cropWidth = Int(boxHeight * ratio)\n    cropY = Int(hdWidthHalf - (ratio * boxWidthHalf))\n    cropHeight = Int(boxWidth * ratio)\n\n    setUpCaptureSessionOutput()\n    setUpCaptureSessionInput()\n\n    MDCCornerTreatment.corner(withRadius: 4)\n  }\n\n  private func setUpCameraPreviewLayer() {\n    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)\n    previewLayer.backgroundColor = UIColor.black.cgColor\n    previewLayer.videoGravity = .resizeAspectFill\n    let rootLayer = previewView.layer\n    rootLayer.masksToBounds = true\n    previewLayer.frame = rootLayer.bounds\n    rootLayer.addSublayer(previewLayer)\n  }\n\n  private func setUpCameraOverlayView() {\n    cameraOverlayView = CameraOverlayView(frame: previewView.bounds)\n    let rect = CGRect(\n      x: previewView.bounds.midX - boxWidthHalf,\n      y: previewView.bounds.midY - boxHeightHalf,\n      width: boxWidth,\n      height: boxHeight)\n    cameraOverlayView.showBox(in: rect)\n    previewView.addSubview(cameraOverlayView)\n    let chipY = previewView.bounds.midY + boxHeightHalf + chipHeightHalf + defaultMargin\n    cameraOverlayView.showMessage(\n      \"Center text in box and hold for a while\",\n      in: CGPoint(x: previewView.bounds.midX, y: chipY))\n  }\n\n  override func viewDidAppear(_ animated: Bool) {\n    super.viewDidAppear(animated)\n    if cameraOverlayView == nil {\n      setUpCameraOverlayView()\n    }\n    startSession()\n    chipCollectionView.reloadData()\n  }\n\n  override func viewWillAppear(_ animated: Bool) {\n    super.viewWillAppear(animated)\n    navigationController?.setNavigationBarHidden(true, animated: false)\n  }\n\n  override func viewDidDisappear(_ animated: Bool) {\n    super.viewDidDisappear(animated)\n    stopSession()\n  }\n\n  override func viewDidLayoutSubviews() {\n    super.viewDidLayoutSubviews()\n    previewLayer.frame = previewView.bounds\n  }\n\n  func numberOfComponents(in pickerView: UIPickerView) -> Int {\n    return 1\n  }\n\n  private func configureChip(_ chip: MDCChipView?) {\n    chip?.setTitleColor(customSelectedColor, for: .selected)\n    chip?.setBorderColor(customSelectedColor, for: UIControl.State.selected)\n    chip?.setBorderWidth(0, for: UIControl.State.selected)\n    chip?.setBackgroundColor(backgroundColor, for: .selected)\n    chip?.shapeGenerator = shapeGenerator\n    chip?.setInkColor(backgroundColor, for: .normal)\n  }\n\n  private func recognizeTextOnDevice(in image: VisionImage) {\n    let textRecognizer = TextRecognizer.textRecognizer()\n    let group = DispatchGroup()\n    group.enter()\n    textRecognizer.process(image) { text, error in\n      group.leave()\n      self.removeDetectionAnnotations()\n\n      guard error == nil, let text = text else {\n        print(\n          \"On-Device text recognizer error: \"\n            + \"\\(error?.localizedDescription ?? Constant.noResultsMessage)\")\n        return\n      }\n      // Blocks.\n      guard let block = text.blocks.first else { return }\n      let detection = block.text\n      if detection == self.detectedText {\n        return\n      }\n\n      self.detectedText = detection\n      DispatchQueue.main.async {\n        self.detectedTextLabel.text = detection\n      }\n\n      self.identifyLanguage(for: detection)\n    }\n    group.wait()\n  }\n\n  private func identifyLanguage(for text: String) {\n    self.pendingRequestWorkItem?.cancel()\n\n    // Wrap our request in a work item\n    let requestWorkItem = DispatchWorkItem { [weak self] in\n      self?.languageId.identifyLanguage(for: text) { languageTag, error in\n        if let error = error {\n          print(\"Failed with error: \\(error)\")\n          return\n        }\n        guard let languageTag = languageTag else {\n          print(\"No language was identified.\")\n          return\n        }\n        let detectedLanguage = TranslateLanguage(rawValue: languageTag)\n        guard TranslateLanguage.allLanguages().contains(detectedLanguage) else {\n          return\n        }\n        if detectedLanguage != self?.detectedLanguage {\n          self?.detectedLanguage = detectedLanguage\n          DispatchQueue.main.async {\n            self?.detectedLanguageLabel.text = detectedLanguage.localizedName()\n          }\n        }\n        self?.translate(text)\n      }\n    }\n\n    // Save the new work item and execute it after 50 ms\n    self.pendingRequestWorkItem = requestWorkItem\n    DispatchQueue.main.asyncAfter(\n      deadline: .now() + .milliseconds(50),\n      execute: requestWorkItem)\n  }\n\n  func translate(_ inputText: String) {\n    let options = TranslatorOptions(\n      sourceLanguage: detectedLanguage,\n      targetLanguage: recentOutputLanguages[selectedItem])\n    translator = Translator.translator(options: options)\n\n    let translatorForDownloading = self.translator!\n    translatorForDownloading.downloadModelIfNeeded { error in\n      guard error == nil else {\n        self.startSession()\n        print(\"Failed to ensure model downloaded with error \\(error!)\")\n        return\n      }\n      if translatorForDownloading == self.translator {\n        translatorForDownloading.translate(inputText) { result, error in\n          self.startSession()\n          guard error == nil else {\n            print(\"Failed with error \\(error!)\")\n            return\n          }\n          if translatorForDownloading == self.translator {\n            DispatchQueue.main.async {\n              self.translatedLabel.text = result\n            }\n          }\n        }\n      }\n    }\n  }\n\n  private func removeDetectionAnnotations() {\n    for annotationView in annotationOverlayView.subviews {\n      annotationView.removeFromSuperview()\n    }\n  }\n\n  // MARK: - Private\n\n  private func setUpCaptureSessionOutput() {\n    sessionQueue.async {\n      self.captureSession.beginConfiguration()\n      // When performing latency tests to determine ideal capture settings,\n      // run the app in 'release' mode to get accurate performance metrics\n      self.captureSession.sessionPreset = AVCaptureSession.Preset.hd1280x720\n\n      let output = AVCaptureVideoDataOutput()\n      output.videoSettings =\n        [(kCVPixelBufferPixelFormatTypeKey as String): kCVPixelFormatType_32BGRA]\n      let outputQueue = DispatchQueue(label: Constant.videoDataOutputQueueLabel)\n      output.alwaysDiscardsLateVideoFrames = true\n      output.setSampleBufferDelegate(self, queue: outputQueue)\n      guard self.captureSession.canAddOutput(output) else {\n        print(\"Failed to add capture session output.\")\n        return\n      }\n      self.captureSession.addOutput(output)\n      self.captureSession.commitConfiguration()\n    }\n  }\n\n  private func setUpCaptureSessionInput() {\n    sessionQueue.async {\n      let cameraPosition: AVCaptureDevice.Position = .back\n      guard let device = self.captureDevice(forPosition: cameraPosition) else {\n        print(\"Failed to get capture device for back camera position\")\n        return\n      }\n      do {\n        self.captureSession.beginConfiguration()\n        let currentInputs = self.captureSession.inputs\n        for input in currentInputs {\n          self.captureSession.removeInput(input)\n        }\n\n        let input = try AVCaptureDeviceInput(device: device)\n        guard self.captureSession.canAddInput(input) else {\n          print(\"Failed to add capture session input.\")\n          return\n        }\n        self.captureSession.addInput(input)\n        self.captureSession.commitConfiguration()\n      } catch {\n        print(\"Failed to create capture device input: \\(error.localizedDescription)\")\n      }\n    }\n  }\n\n  private func startSession() {\n    sessionQueue.async {\n      self.captureSession.startRunning()\n    }\n  }\n\n  private func stopSession() {\n    sessionQueue.async {\n      self.captureSession.stopRunning()\n    }\n  }\n\n  private func setUpAnnotationOverlayView() {\n    previewView.addSubview(annotationOverlayView)\n    NSLayoutConstraint.activate([\n      annotationOverlayView.topAnchor.constraint(equalTo: previewView.topAnchor),\n      annotationOverlayView.leadingAnchor.constraint(equalTo: previewView.leadingAnchor),\n      annotationOverlayView.trailingAnchor.constraint(equalTo: previewView.trailingAnchor),\n      annotationOverlayView.bottomAnchor.constraint(equalTo: previewView.bottomAnchor),\n    ])\n  }\n\n  private func captureDevice(forPosition position: AVCaptureDevice.Position) -> AVCaptureDevice? {\n    if #available(iOS 10.0, *) {\n      let discoverySession = AVCaptureDevice.DiscoverySession(\n        deviceTypes: [.builtInWideAngleCamera],\n        mediaType: .video,\n        position: .unspecified\n      )\n      return discoverySession.devices.first { $0.position == position }\n    }\n    return nil\n  }\n\n  private func convertedPoints(\n    from points: [NSValue]?,\n    width: CGFloat,\n    height: CGFloat\n  ) -> [NSValue]? {\n    return points?.map {\n      let cgPointValue = $0.cgPointValue\n      let normalizedPoint = CGPoint(x: cgPointValue.x / width, y: cgPointValue.y / height)\n      let cgPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: normalizedPoint)\n      let value = NSValue(cgPoint: cgPoint)\n      return value\n    }\n  }\n\n  private func normalizedPoint(\n    fromVisionPoint point: VisionPoint,\n    width: CGFloat,\n    height: CGFloat\n  ) -> CGPoint {\n    let cgPoint = CGPoint(x: point.x, y: point.y)\n    var normalizedPoint = CGPoint(x: cgPoint.x / width, y: cgPoint.y / height)\n    normalizedPoint = previewLayer.layerPointConverted(fromCaptureDevicePoint: normalizedPoint)\n    return normalizedPoint\n  }\n}\n\nextension CameraViewController: UICollectionViewDelegate, UICollectionViewDataSource,\n  UICollectionViewDelegateFlowLayout\n{\n  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int)\n    -> Int\n  {\n    return 3\n  }\n\n  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)\n    -> UICollectionViewCell\n  {\n    let cell =\n      collectionView.dequeueReusableCell(withReuseIdentifier: \"identifier\", for: indexPath)\n      as! MDCChipCollectionViewCell\n    let chip = cell.chipView\n    chip.applyOutlinedTheme(withScheme: containerScheme)\n    configureChip(chip)\n    if indexPath.item == 2 {\n      chip.titleLabel.text = \"More\"\n    } else {\n      chip.isSelected = indexPath.item == selectedItem\n      chip.titleLabel.text = recentOutputLanguages[indexPath.item].localizedName()\n\n      chip.selectedImageView.image = #imageLiteral(resourceName: \"baseline_check_black_24pt\")\n      cell.alwaysAnimateResize = true\n    }\n    return cell\n  }\n\n  func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {\n    if indexPath.item == 2 {\n      collectionView.deselectItem(at: IndexPath(item: 2, section: 0), animated: false)\n      performSegue(withIdentifier: \"search\", sender: nil)\n      return\n    }\n    selectedItem = indexPath.item\n    collectionView.performBatchUpdates(nil, completion: nil)\n    translate(self.detectedText)\n  }\n\n  func collectionView(\n    _ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,\n    sizeForItemAt indexPath: IndexPath\n  ) -> CGSize {\n    sizingChip.titleLabel.text =\n      indexPath.item == 2 ? \"More\" : recentOutputLanguages[indexPath.item].localizedName()\n    sizingChip.applyOutlinedTheme(withScheme: containerScheme)\n    sizingChip.selectedImageView.image = #imageLiteral(resourceName: \"baseline_check_black_24pt\")\n    sizingChip.isSelected = indexPath.item == selectedItem\n    configureChip(sizingChip)\n    return sizingChip.sizeThatFits(collectionView.bounds.size)\n  }\n}\n\n// MARK: AVCaptureVideoDataOutputSampleBufferDelegate\n\nextension CameraViewController: AVCaptureVideoDataOutputSampleBufferDelegate {\n\n  func captureOutput(\n    _ output: AVCaptureOutput,\n    didOutput sampleBuffer: CMSampleBuffer,\n    from connection: AVCaptureConnection\n  ) {\n\n    guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }\n    let newBuffer = resizePixelBuffer(\n      imageBuffer, cropX: cropX, cropY: cropY, cropWidth: cropWidth, cropHeight: cropHeight)\n\n    var sampleTime = CMSampleTimingInfo()\n    sampleTime.duration = CMSampleBufferGetDuration(sampleBuffer)\n    sampleTime.presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)\n    sampleTime.decodeTimeStamp = CMSampleBufferGetDecodeTimeStamp(sampleBuffer)\n    var videoInfo: CMVideoFormatDescription?\n    CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, newBuffer!, &videoInfo)\n\n    // Creates `CMSampleBufferRef`.\n    var resultBuffer: CMSampleBuffer? = nil\n    CMSampleBufferCreateForImageBuffer(\n      kCFAllocatorDefault, newBuffer!, true, nil, nil, videoInfo!, &sampleTime, &resultBuffer)\n\n    let visionImage = VisionImage.init(buffer: resultBuffer!)\n    let orientation = UIUtilities.imageOrientation(\n      fromDevicePosition: .back\n    )\n\n    visionImage.orientation = orientation\n\n    self.recognizeTextOnDevice(in: visionImage)\n\n  }\n\n}\n\n// MARK: - Constants\n\nprivate enum Constant {\n  static let videoDataOutputQueueLabel = \"com.google.mlkit.visiondetector.VideoDataOutputQueue\"\n  static let sessionQueueLabel = \"com.google.mlkit.visiondetector.SessionQueue\"\n  static let noResultsMessage = \"No Results\"\n  static let smallDotRadius: CGFloat = 4.0\n  static let originalScale: CGFloat = 1.0\n  static let padding: CGFloat = 10.0\n  static let resultsLabelHeight: CGFloat = 200.0\n  static let resultsLabelLines = 5\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string>We use the data from the camera for the image recognition.</string>\n\t<key>NSPhotoLibraryUsageDescription</key>\n\t<string>We use the data from the photo library for the image recognition.</string>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UIRequiresFullScreen</key>\n\t<true/>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/MLKitExtensions.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport CoreGraphics\nimport UIKit\n\n// MARK: - UIImage\n\nextension UIImage {\n\n  /// Creates and returns a new image scaled to the given size. The image preserves its original PNG\n  /// or JPEG bitmap info.\n  ///\n  /// - Parameter size: The size to scale the image to.\n  /// - Returns: The scaled image or `nil` if image could not be resized.\n  public func scaledImage(with size: CGSize) -> UIImage? {\n    UIGraphicsBeginImageContextWithOptions(size, false, scale)\n    defer { UIGraphicsEndImageContext() }\n    draw(in: CGRect(origin: .zero, size: size))\n    return UIGraphicsGetImageFromCurrentImageContext()?.data.flatMap(UIImage.init)\n  }\n\n  // MARK: - Private\n\n  /// The PNG or JPEG data representation of the image or `nil` if the conversion failed.\n  private var data: Data? {\n    #if swift(>=4.2)\n      return self.pngData() ?? self.jpegData(compressionQuality: Constant.jpegCompressionQuality)\n    #else\n      return UIImagePNGRepresentation(self)\n        ?? UIImageJPEGRepresentation(self, Constant.jpegCompressionQuality)\n    #endif  // swift(>=4.2)\n  }\n}\n\n// MARK: - Constants\n\nprivate enum Constant {\n  static let jpegCompressionQuality: CGFloat = 0.8\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/SearchViewController.swift",
    "content": "//\n//  Copyright (c) 2019 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport MLKit\nimport MaterialComponents.MaterialList\n\nprivate let reuseIdentifier = \"Cell\"\n\nclass SearchViewController: UICollectionViewController, UISearchBarDelegate,\n  UISearchControllerDelegate\n{\n  private var allLanguages: [TranslateLanguage] = {\n    return TranslateLanguage.allLanguages().sorted {\n      $0.localizedName() < $1.localizedName()\n    }\n  }()\n\n  private lazy var languages = self.allLanguages\n\n  let searchController = UISearchController(searchResultsController: nil)\n  let emptyLabel: UILabel = {\n    let messageLabel = UILabel()\n    messageLabel.text = \"No language found.\"\n    messageLabel.textColor = UIColor.black\n    messageLabel.numberOfLines = 0\n    messageLabel.textAlignment = .center\n    messageLabel.font = UIFont.preferredFont(forTextStyle: .title3)\n    messageLabel.sizeToFit()\n    return messageLabel\n  }()\n  // We keep track of the pending work item as a property\n  private var pendingRequestWorkItem: DispatchWorkItem?\n\n  override func viewDidLoad() {\n    super.viewDidLoad()\n\n    self.collectionView!.register(\n      MDCSelfSizingStereoCell.self, forCellWithReuseIdentifier: reuseIdentifier)\n    guard let col = collectionViewLayout as? UICollectionViewFlowLayout else { return }\n    col.estimatedItemSize = CGSize.init(width: collectionView!.bounds.width, height: 52)\n\n    searchController.searchResultsUpdater = self\n    searchController.searchBar.delegate = self\n    searchController.delegate = self\n    searchController.obscuresBackgroundDuringPresentation = false\n    searchController.hidesNavigationBarDuringPresentation = false\n    searchController.searchBar.placeholder = \"Search for a language\"\n\n    UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).leftViewMode = .never\n    searchController.searchBar.setImage(\n      #imageLiteral(resourceName: \"ic_close\"), for: .clear, state: .normal)\n    UIImageView.appearance(whenContainedInInstancesOf: [UISearchBar.self]).bounds = CGRect(\n      x: 0, y: 0, width: 24, height: 24)\n\n    let x = UIButton.init()\n    x.setImage(#imageLiteral(resourceName: \"ic_arrow_back\"), for: .normal)\n    x.addTarget(self, action: #selector(back), for: .touchUpInside)\n\n    UIButton.appearance(whenContainedInInstancesOf: [UINavigationBar.self])\n      .translatesAutoresizingMaskIntoConstraints = false\n    UIButton.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).contentEdgeInsets =\n      UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -4)\n\n    navigationItem.leftBarButtonItem = UIBarButtonItem(customView: x)\n\n    navigationItem.titleView = searchController.searchBar\n    navigationItem.hidesBackButton = true\n    definesPresentationContext = true\n    searchController.searchBar.showsCancelButton = false\n\n    UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = UIColor.init(\n      red: 0, green: 137 / 255, blue: 249 / 255, alpha: 1)\n  }\n\n  @objc func back() {\n    navigationController?.popViewController(animated: true)\n  }\n\n  func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {\n    searchController.searchBar.showsCancelButton = false\n    self.searchController.searchBar.becomeFirstResponder()\n  }\n\n  func didPresentSearchController(_ searchController: UISearchController) {\n    searchController.searchBar.showsCancelButton = false\n    self.searchController.searchBar.becomeFirstResponder()\n  }\n\n  override func viewDidAppear(_ animated: Bool) {\n    super.viewDidAppear(animated)\n  }\n\n  override func viewWillAppear(_ animated: Bool) {\n    super.viewWillAppear(animated)\n    navigationController?.setNavigationBarHidden(false, animated: false)\n\n    navigationController?.navigationBar.barTintColor = .white\n    navigationController?.navigationBar.tintColor = .gray\n  }\n\n  override func viewWillDisappear(_ animated: Bool) {\n    super.viewWillDisappear(animated)\n    navigationController?.navigationBar.barTintColor = UIColor(\n      red: 0.01, green: 0.53, blue: 0.82, alpha: 1.0)\n    navigationController?.navigationBar.tintColor = .white\n  }\n\n  // MARK: UICollectionViewDataSource\n\n  override func numberOfSections(in collectionView: UICollectionView) -> Int {\n    return 1\n  }\n\n  func filterContentForSearchText(_ searchText: String, scope: String = \"All\") {\n    if searchText.isEmpty {\n      self.languages = self.allLanguages\n      collectionView?.reloadData()\n      return\n    }\n    // Cancel the currently pending item\n    pendingRequestWorkItem?.cancel()\n\n    // Wrap our request in a work item\n    let requestWorkItem = DispatchWorkItem { [weak self] in\n      guard let self = self else { return }\n      self.languages =\n        self.allLanguages.filter { $0.localizedName().localizedStandardContains(searchText) }\n      self.collectionView?.reloadData()\n    }\n\n    // Save the new work item and execute it after 250 ms\n    pendingRequestWorkItem = requestWorkItem\n    DispatchQueue.main.asyncAfter(\n      deadline: .now() + .milliseconds(250),\n      execute: requestWorkItem)\n  }\n\n  override func collectionView(\n    _ collectionView: UICollectionView, numberOfItemsInSection section: Int\n  ) -> Int {\n    collectionView.backgroundView = languages.isEmpty ? emptyLabel : nil\n    return languages.count\n  }\n\n  override func collectionView(\n    _ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath\n  ) -> UICollectionViewCell {\n    guard\n      let cell = collectionView.dequeueReusableCell(\n        withReuseIdentifier: reuseIdentifier,\n        for: indexPath) as? MDCSelfSizingStereoCell\n    else {\n      return UICollectionViewCell()\n    }\n    cell.titleLabel.text = languages[indexPath.item].localizedName()\n    return cell\n  }\n\n  override func collectionView(\n    _ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath\n  ) {\n    guard let cameraController = self.parent?.childViewControllers[0] as? CameraViewController\n    else { return }\n    let recents = cameraController.recentOutputLanguages\n    let selected = languages[indexPath.item]\n    if selected != recents[0] {\n      cameraController.recentOutputLanguages[1] = recents[0]\n      cameraController.recentOutputLanguages[0] = selected\n    }\n    cameraController.selectedItem = 0\n    back()\n  }\n}\n\nextension SearchViewController: UISearchResultsUpdating {\n  func updateSearchResults(for searchController: UISearchController) {\n    filterContentForSearchText(searchController.searchBar.text!)\n  }\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/TranslateLanguage+Helpers.swift",
    "content": "//\n//  Copyright (c) 2020 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport Foundation\nimport MLKit\n\nextension TranslateLanguage {\n\n  func localizedName() -> String {\n    let locale = Locale.current\n    return locale.localizedString(forLanguageCode: self.rawValue)!\n  }\n\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo/UIUtilities.swift",
    "content": "//\n//  Copyright (c) 2018 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//\n\nimport AVFoundation\nimport MLKit\n\n/// Defines UI-related utilitiy methods for vision detection.\npublic class UIUtilities {\n\n  // MARK: - Public\n\n  public static func addCircle(\n    atPoint point: CGPoint,\n    to view: UIView,\n    color: UIColor,\n    radius: CGFloat\n  ) {\n    let divisor: CGFloat = 2.0\n    let xCoord = point.x - radius / divisor\n    let yCoord = point.y - radius / divisor\n    let circleRect = CGRect(x: xCoord, y: yCoord, width: radius, height: radius)\n    let circleView = UIView(frame: circleRect)\n    circleView.layer.cornerRadius = radius / divisor\n    circleView.alpha = Constants.circleViewAlpha\n    circleView.backgroundColor = color\n    view.addSubview(circleView)\n  }\n\n  public static func addRectangle(_ rectangle: CGRect, to view: UIView, color: UIColor) {\n    let rectangleView = UIView(frame: rectangle)\n    rectangleView.layer.cornerRadius = Constants.rectangleViewCornerRadius\n    rectangleView.alpha = Constants.rectangleViewAlpha\n    rectangleView.backgroundColor = color\n    view.addSubview(rectangleView)\n  }\n\n  public static func addShape(withPoints points: [NSValue]?, to view: UIView, color: UIColor) {\n    guard let points = points else { return }\n    let path = UIBezierPath()\n    for (index, value) in points.enumerated() {\n      let point = value.cgPointValue\n      if index == 0 {\n        path.move(to: point)\n      } else {\n        path.addLine(to: point)\n      }\n      if index == points.count - 1 {\n        path.close()\n      }\n    }\n    let shapeLayer = CAShapeLayer()\n    shapeLayer.path = path.cgPath\n    shapeLayer.fillColor = color.cgColor\n    let rect = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)\n    let shapeView = UIView(frame: rect)\n    shapeView.alpha = Constants.shapeViewAlpha\n    shapeView.layer.addSublayer(shapeLayer)\n    view.addSubview(shapeView)\n  }\n\n  public static func imageOrientation(\n    fromDevicePosition devicePosition: AVCaptureDevice.Position = .back\n  ) -> UIImageOrientation {\n    var deviceOrientation = UIDevice.current.orientation\n    if deviceOrientation == .faceDown || deviceOrientation == .faceUp\n      || deviceOrientation == .unknown\n    {\n      deviceOrientation = currentUIOrientation()\n    }\n    switch deviceOrientation {\n    case .portrait:\n      return devicePosition == .front ? .leftMirrored : .right\n    case .landscapeLeft:\n      return devicePosition == .front ? .downMirrored : .up\n    case .portraitUpsideDown:\n      return devicePosition == .front ? .rightMirrored : .left\n    case .landscapeRight:\n      return devicePosition == .front ? .upMirrored : .down\n    case .faceDown, .faceUp, .unknown:\n      return .up\n    }\n  }\n\n  // MARK: - Private\n\n  private static func currentUIOrientation() -> UIDeviceOrientation {\n    let deviceOrientation = { () -> UIDeviceOrientation in\n      switch UIApplication.shared.statusBarOrientation {\n      case .landscapeLeft:\n        return .landscapeRight\n      case .landscapeRight:\n        return .landscapeLeft\n      case .portraitUpsideDown:\n        return .portraitUpsideDown\n      case .portrait, .unknown:\n        return .portrait\n      }\n    }\n    guard Thread.isMainThread else {\n      var currentOrientation: UIDeviceOrientation = .portrait\n      DispatchQueue.main.sync {\n        currentOrientation = deviceOrientation()\n      }\n      return currentOrientation\n    }\n    return deviceOrientation()\n  }\n}\n\n// MARK: - Constants\n\nprivate enum Constants {\n  static let circleViewAlpha: CGFloat = 0.7\n  static let rectangleViewAlpha: CGFloat = 0.1\n  static let shapeViewAlpha: CGFloat = 0.3\n  static let rectangleViewCornerRadius: CGFloat = 10.0\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 48;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1001E6F720CEE0DD00445CB3 /* UIUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */; };\n\t\t1001E6FD20CF0C8F00445CB3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */; };\n\t\t1003B0862290631D00C6F6AE /* TranslateDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1003B0852290631D00C6F6AE /* TranslateDemoTests.swift */; };\n\t\t10224B5E2087E49F00A77316 /* MLKitExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10224B5B2087E49F00A77316 /* MLKitExtensions.swift */; };\n\t\t10330DC82270B43B00B68BC5 /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10330DC72270B43B00B68BC5 /* SearchViewController.swift */; };\n\t\t10330DCC227261B200B68BC5 /* CameraOverlayview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10330DCB227261B200B68BC5 /* CameraOverlayview.swift */; };\n\t\t107B2687227AA30500A74931 /* CVPixelBuffer+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 107B2686227AA30500A74931 /* CVPixelBuffer+Helpers.swift */; };\n\t\t10C59CE22268AD0100FCC676 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10C59CE12268AD0100FCC676 /* CameraViewController.swift */; };\n\t\t10C59CE72268AD4200FCC676 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 10C59CE52268AD4200FCC676 /* Main.storyboard */; };\n\t\t40004C20247E743C00B6A679 /* TranslateLanguage+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40004C1F247E743C00B6A679 /* TranslateLanguage+Helpers.swift */; };\n\t\tBB287B3920729CE90069707A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB287B3820729CE90069707A /* AppDelegate.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t1003B0882290631D00C6F6AE /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = BB287B2D20729CE90069707A /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = BB287B3420729CE90069707A;\n\t\t\tremoteInfo = TranslateDemo;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIUtilities.swift; sourceTree = \"<group>\"; };\n\t\t1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t1003B0832290631D00C6F6AE /* TranslateDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TranslateDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t1003B0852290631D00C6F6AE /* TranslateDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslateDemoTests.swift; sourceTree = \"<group>\"; };\n\t\t1003B0872290631D00C6F6AE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t10224B5B2087E49F00A77316 /* MLKitExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MLKitExtensions.swift; sourceTree = \"<group>\"; };\n\t\t10330DC72270B43B00B68BC5 /* SearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = \"<group>\"; };\n\t\t10330DCB227261B200B68BC5 /* CameraOverlayview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraOverlayview.swift; sourceTree = \"<group>\"; };\n\t\t107B2686227AA30500A74931 /* CVPixelBuffer+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"CVPixelBuffer+Helpers.swift\"; sourceTree = \"<group>\"; };\n\t\t10C59CE12268AD0100FCC676 /* CameraViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = \"<group>\"; };\n\t\t10C59CE62268AD4200FCC676 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t40004C1F247E743C00B6A679 /* TranslateLanguage+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"TranslateLanguage+Helpers.swift\"; sourceTree = \"<group>\"; };\n\t\tBB287B3520729CE90069707A /* TranslateDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TranslateDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tBB287B3820729CE90069707A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tBB287B4420729CE90069707A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t1003B0802290631D00C6F6AE /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3220729CE90069707A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t1003B0842290631D00C6F6AE /* TranslateDemoTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1003B0852290631D00C6F6AE /* TranslateDemoTests.swift */,\n\t\t\t\t1003B0872290631D00C6F6AE /* Info.plist */,\n\t\t\t);\n\t\t\tpath = TranslateDemoTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70430DF470DFF802A6B65781 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B2C20729CE90069707A = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1001E6FC20CF0C8F00445CB3 /* Assets.xcassets */,\n\t\t\t\tBB287B3720729CE90069707A /* TranslateDemo */,\n\t\t\t\t1003B0842290631D00C6F6AE /* TranslateDemoTests */,\n\t\t\t\tBB287B3620729CE90069707A /* Products */,\n\t\t\t\t70430DF470DFF802A6B65781 /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B3620729CE90069707A /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB287B3520729CE90069707A /* TranslateDemo.app */,\n\t\t\t\t1003B0832290631D00C6F6AE /* TranslateDemoTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B3720729CE90069707A /* TranslateDemo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t10C59CE12268AD0100FCC676 /* CameraViewController.swift */,\n\t\t\t\t10330DCB227261B200B68BC5 /* CameraOverlayview.swift */,\n\t\t\t\t10330DC72270B43B00B68BC5 /* SearchViewController.swift */,\n\t\t\t\tBB287B3820729CE90069707A /* AppDelegate.swift */,\n\t\t\t\t10224B5B2087E49F00A77316 /* MLKitExtensions.swift */,\n\t\t\t\t1001E6F620CEE0DD00445CB3 /* UIUtilities.swift */,\n\t\t\t\t107B2686227AA30500A74931 /* CVPixelBuffer+Helpers.swift */,\n\t\t\t\t40004C1F247E743C00B6A679 /* TranslateLanguage+Helpers.swift */,\n\t\t\t\tBB287B4A2072A0200069707A /* Supporting Files */,\n\t\t\t\tBB287B4420729CE90069707A /* Info.plist */,\n\t\t\t);\n\t\t\tpath = TranslateDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB287B4A2072A0200069707A /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t10C59CE52268AD4200FCC676 /* Main.storyboard */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t1003B0822290631D00C6F6AE /* TranslateDemoTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1003B08C2290631D00C6F6AE /* Build configuration list for PBXNativeTarget \"TranslateDemoTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t1003B07F2290631D00C6F6AE /* Sources */,\n\t\t\t\t1003B0802290631D00C6F6AE /* Frameworks */,\n\t\t\t\t1003B0812290631D00C6F6AE /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t1003B0892290631D00C6F6AE /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = TranslateDemoTests;\n\t\t\tproductName = TranslateDemoTests;\n\t\t\tproductReference = 1003B0832290631D00C6F6AE /* TranslateDemoTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\tBB287B3420729CE90069707A /* TranslateDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = BB287B4720729CE90069707A /* Build configuration list for PBXNativeTarget \"TranslateDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tBB287B3120729CE90069707A /* Sources */,\n\t\t\t\tBB287B3220729CE90069707A /* Frameworks */,\n\t\t\t\tBB287B3320729CE90069707A /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = TranslateDemo;\n\t\t\tproductName = \"ml-kit-sampler\";\n\t\t\tproductReference = BB287B3520729CE90069707A /* TranslateDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tBB287B2D20729CE90069707A /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1020;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = \"Google Inc.\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t1003B0822290631D00C6F6AE = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.2.1;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = BB287B3420729CE90069707A;\n\t\t\t\t\t};\n\t\t\t\t\tBB287B3420729CE90069707A = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = BB287B3020729CE90069707A /* Build configuration list for PBXProject \"TranslateDemo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = BB287B2C20729CE90069707A;\n\t\t\tproductRefGroup = BB287B3620729CE90069707A /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tBB287B3420729CE90069707A /* TranslateDemo */,\n\t\t\t\t1003B0822290631D00C6F6AE /* TranslateDemoTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t1003B0812290631D00C6F6AE /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3320729CE90069707A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1001E6FD20CF0C8F00445CB3 /* Assets.xcassets in Resources */,\n\t\t\t\t10C59CE72268AD4200FCC676 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t1003B07F2290631D00C6F6AE /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1003B0862290631D00C6F6AE /* TranslateDemoTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tBB287B3120729CE90069707A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t10330DC82270B43B00B68BC5 /* SearchViewController.swift in Sources */,\n\t\t\t\t107B2687227AA30500A74931 /* CVPixelBuffer+Helpers.swift in Sources */,\n\t\t\t\t10330DCC227261B200B68BC5 /* CameraOverlayview.swift in Sources */,\n\t\t\t\t10C59CE22268AD0100FCC676 /* CameraViewController.swift in Sources */,\n\t\t\t\tBB287B3920729CE90069707A /* AppDelegate.swift in Sources */,\n\t\t\t\t40004C20247E743C00B6A679 /* TranslateLanguage+Helpers.swift in Sources */,\n\t\t\t\t10224B5E2087E49F00A77316 /* MLKitExtensions.swift in Sources */,\n\t\t\t\t1001E6F720CEE0DD00445CB3 /* UIUtilities.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t1003B0892290631D00C6F6AE /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = BB287B3420729CE90069707A /* TranslateDemo */;\n\t\t\ttargetProxy = 1003B0882290631D00C6F6AE /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t10C59CE52268AD4200FCC676 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t10C59CE62268AD4200FCC676 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1003B08A2290631D00C6F6AE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tINFOPLIST_FILE = TranslateDemoTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.firebaseml.showcase.TranslateDemoTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TranslateDemo.app/TranslateDemo\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1003B08B2290631D00C6F6AE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tINFOPLIST_FILE = TranslateDemoTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.firebaseml.showcase.TranslateDemoTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TranslateDemo.app/TranslateDemo\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBB287B4520729CE90069707A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.2;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBB287B4620729CE90069707A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.2;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tBB287B4820729CE90069707A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/TranslateDemo/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.showcase.translate;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tBB287B4920729CE90069707A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/TranslateDemo/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.showcase.translate;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1003B08C2290631D00C6F6AE /* Build configuration list for PBXNativeTarget \"TranslateDemoTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1003B08A2290631D00C6F6AE /* Debug */,\n\t\t\t\t1003B08B2290631D00C6F6AE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBB287B3020729CE90069707A /* Build configuration list for PBXProject \"TranslateDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBB287B4520729CE90069707A /* Debug */,\n\t\t\t\tBB287B4620729CE90069707A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tBB287B4720729CE90069707A /* Build configuration list for PBXNativeTarget \"TranslateDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tBB287B4820729CE90069707A /* Debug */,\n\t\t\t\tBB287B4920729CE90069707A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = BB287B2D20729CE90069707A /* Project object */;\n}\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemoTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/showcase/translate-showcase/TranslateDemoTests/TranslateDemoTests.swift",
    "content": "//\n//  TranslateDemoTests.swift\n//  TranslateDemoTests\n//\n//  Created by Ibrahim Ulukaya on 5/18/19.\n//  Copyright © 2019 Google Inc. All rights reserved.\n//\n\nimport XCTest\n\nclass TranslateDemoTests: XCTestCase {\n\n  override func setUp() {\n    // Put setup code here. This method is called before the invocation of each test method in the class.\n  }\n\n  override func tearDown() {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n  }\n\n  func testExample() {\n    // This is an example of a functional test case.\n    // Use XCTAssert and related functions to verify your tests produce the correct results.\n  }\n\n  func testPerformanceExample() {\n    // This is an example of a performance test case.\n    self.measure {\n      // Put the code you want to measure the time of here.\n    }\n  }\n\n}\n"
  },
  {
    "path": "ios/showcase/vision-showcase/Podfile",
    "content": "source 'https://github.com/CocoaPods/Specs.git'\n\nplatform :ios, '10.0'\n# Comment the next line if you're not using Swift and don't want to use dynamic frameworks\nuse_frameworks!\n\npod 'GoogleMLKit/ObjectDetection'\npod 'GoogleMLKit/ObjectDetectionCustom'\n\npod 'MaterialComponents'\npod 'PINRemoteImage'\n\ntarget 'ShowcaseApp' do\nend\n"
  },
  {
    "path": "ios/showcase/vision-showcase/README.md",
    "content": "# ML Kit Showcase Apps with Material Design\n\nThese apps demonstrate how to build an end-to-end user experience with [Google ML Kit APIs](https://developers.google.com/ml-kit) and following the new [Material for ML design guidelines](https://material.io/design/machine-learning/).\n\nThe goal is to make it as easy as possible to integrate ML Kit into your app with an experience that has been user tested.\n\n## Apps\n\nYou can open each of the following apps as an Xcode project, and run\nthem on a mobile device or a simulator. Simply install the pods and open\nthe .xcworkspace file to see the project in Xcode.\n\n```\n$ pod install --repo-update\n$ open your-project.xcworkspace\n```\n\n- Object Detection and Tracking:\n  Search using the Object Detection & Tracking API - a complete workflow from object detection to product search in live camera.\n![live_odt](screenshots/live_odt.gif)\n\n- Object detection and Tracking with custom TensorFlow Lite model:\n  Search using a custom TensorFlow Lite model (Example used: Bird recognition model) to detect and recognize objects with a live camera view. This shows how to implement a visual search flow with a custom TensorFlow Lite model.\n\n## License\n© Google, 2020. Licensed under an [Apache-2](./LICENSE) license.\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/AppDelegate.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property(nonatomic) UIWindow *window;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/AppDelegate.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"AppDelegate.h\"\n\n#import \"MLKLiveObjectDetectionViewController.h\"\n#import \"MLKResultListViewController.h\"\n#import \"MLKStartPageViewController.h\"\n#import \"MLKResult.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation AppDelegate\n\n#pragma mark - UIApplicationDelegate\n\n- (BOOL)application:(UIApplication *)application\n    didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions {\n  MLKStartPageViewController *startPageViewController =\n      [[MLKStartPageViewController alloc] init];\n\n  UIApplication.sharedApplication.idleTimerDisabled = YES;\n\n  self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];\n  self.window.backgroundColor = UIColor.blackColor;\n  self.window.rootViewController = startPageViewController;\n  [self.window makeKeyAndVisible];\n  return YES;\n}\n\n- (NSArray<MLKResult *> *)fakeResultss {\n  NSMutableArray<MLKResult *> *fakeResultss = [NSMutableArray array];\n  for (NSInteger index = 0; index < 10; index++) {\n\n    MLKResult *result = [[MLKResult alloc] init];\n    result.title = @\"Name\";\n    result.details = @\"Type\";\n    result.priceFullText = @\"Price\";\n    [fakeResultss addObject:result];\n  }\n  return fakeResultss;\n}\n\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Base.lproj/LaunchScreen.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"15702\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"15704\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"480\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"  Copyright (c) 2020 Google. All rights reserved.\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8ie-xW-0ye\">\n                    <rect key=\"frame\" x=\"20\" y=\"439\" width=\"440\" height=\"21\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"MLKit Showcase\" textAlignment=\"center\" lineBreakMode=\"middleTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kId-c2-rCX\">\n                    <rect key=\"frame\" x=\"20\" y=\"139.5\" width=\"440\" height=\"43\"/>\n                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"36\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n            </subviews>\n            <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n            <constraints>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"centerY\" secondItem=\"iN0-l3-epB\" secondAttribute=\"bottom\" multiplier=\"1/3\" constant=\"1\" id=\"5cJ-9S-tgC\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"kId-c2-rCX\" secondAttribute=\"centerX\" id=\"Koa-jz-hwk\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"bottom\" constant=\"20\" id=\"Kzo-t9-V3l\"/>\n                <constraint firstItem=\"8ie-xW-0ye\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"MfP-vx-nX0\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"centerX\" id=\"ZEH-qu-HZ9\"/>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"fvb-Df-36g\"/>\n            </constraints>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"548\" y=\"455\"/>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Common/MLKImageUtilities.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <CoreMedia/CoreMedia.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Provides image related utility APIs. */\n@interface MLKImageUtilities : NSObject\n\n/**\n * Converts a `CMSampleBuffer` to a `UIImage`, returns `nil` when `sampleBuffer` is unsupported.\n * Currently this method only handles `CMSampleBufferRef` with RGB color space.\n *\n * @param sampleBuffer The given `CMSampleBufferRef`.\n * @return Converted `UIImage`.\n */\n+ (nullable UIImage *)imageFromSampleBuffer:(CMSampleBufferRef)sampleBuffer;\n\n/**\n * Crops `CMSampleBuffer` to a specified rect. This will not alter the original data. Currently this\n * method only handles `CMSampleBufferRef` with RGB color space.\n *\n * @param sampleBuffer The original `CMSampleBuffer`.\n * @param rect The rect to crop to.\n * @return A `CMSampleBuffer` cropped to the given rect.\n */\n+ (CMSampleBufferRef)croppedSampleBuffer:(CMSampleBufferRef)sampleBuffer withRect:(CGRect)rect;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Common/MLKImageUtilities.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKImageUtilities.h\"\n\n#import <MetalKit/MetalKit.h>\n\n#ifdef __ARM_NEON__\n#import \"arm_neon.h\"\n#endif\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** `CIContext` to render pixel buffer to images. */\nstatic CIContext *gCIContext;\n\n@implementation MLKImageUtilities\n\n#pragma mark - NSObject\n\n+ (void)initialize {\n  if ([self isKindOfClass:[MLKImageUtilities class]]) {\n    gCIContext = [CIContext contextWithMTLDevice:MTLCreateSystemDefaultDevice()];\n  }\n}\n\n#pragma mark - Public\n\n+ (nullable UIImage *)imageFromSampleBuffer:(CMSampleBufferRef)sampleBuffer {\n  if (sampleBuffer == NULL) {\n    NSLog(@\"Sample buffer is NULL.\");\n    return nil;\n  }\n  CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);\n  if (imageBuffer == NULL) {\n    NSLog(@\"Invalid sample buffer.\");\n    return nil;\n  }\n\n  CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);\n\n  void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);\n  size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);\n  size_t bitPerComponent = 8;  // TODO(zhoumi): This may vary on other formats.\n\n  size_t width = CVPixelBufferGetWidth(imageBuffer);\n  size_t height = CVPixelBufferGetHeight(imageBuffer);\n\n  // TODO(zhoumi): Add more support for non-RGB color space.\n  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();\n\n  if (colorSpace == NULL) {\n    NSLog(@\"Failed to create RGB color space\");\n    CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);\n    return nil;\n  }\n\n  // TODO(zhoumi): Add more support for other formats.\n  CGContextRef context =\n      CGBitmapContextCreate(baseAddress, width, height, bitPerComponent, bytesPerRow, colorSpace,\n                            kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);\n  if (context == NULL) {\n    NSLog(@\"Failed to create CGContextRef\");\n    CGColorSpaceRelease(colorSpace);\n    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);\n    return nil;\n  }\n\n  CGImageRef cgImage = CGBitmapContextCreateImage(context);\n  if (cgImage == NULL) {\n    NSLog(@\"Failed to create CGImage\");\n    CGColorSpaceRelease(colorSpace);\n    CGContextRelease(context);\n    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);\n    return nil;\n  }\n\n  CVPixelBufferUnlockBaseAddress(imageBuffer, 0);\n  CGContextRelease(context);\n  CGColorSpaceRelease(colorSpace);\n\n  UIImage *image = [UIImage imageWithCGImage:cgImage];\n  CGImageRelease(cgImage);\n  return image;\n}\n\n+ (CMSampleBufferRef)croppedSampleBuffer:(CMSampleBufferRef)sampleBuffer withRect:(CGRect)rect {\n  CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);\n\n  CVPixelBufferLockBaseAddress(imageBuffer, 0);\n\n  size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);\n  size_t width = CVPixelBufferGetWidth(imageBuffer);\n  size_t bytesPerPixel = bytesPerRow / width;\n  void *baseAddressStart = CVPixelBufferGetBaseAddress(imageBuffer);\n\n  NSUInteger cropX = rect.origin.x;\n  NSUInteger cropY = rect.origin.y;\n\n  // Start pixel in RGB color space can't be odd.\n  if (cropX % 2 != 0) {\n    cropX++;\n  }\n\n  NSUInteger cropStartOffset = cropY * bytesPerRow + cropX * bytesPerPixel;\n\n  CVPixelBufferRef pixelBuffer = NULL;\n  CVReturn error;\n\n  // Initiates pixelBuffer.\n  OSType pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer);\n  NSDictionary<NSString *, NSNumber *> *options = @{\n    (__bridge NSString *)kCVPixelBufferCGImageCompatibilityKey : @YES,\n    (__bridge NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,\n    (__bridge NSString *)kCVPixelBufferWidthKey : @(rect.size.width),\n    (__bridge NSString *)kCVPixelBufferHeightKey : @(rect.size.height),\n  };\n\n  error = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,                 // allocator\n                                       rect.size.width,                     // width\n                                       rect.size.height,                    // height\n                                       pixelFormat,                         // pixelFormatType\n                                       &baseAddressStart[cropStartOffset],  // baseAddress\n                                       bytesPerRow,                         // bytesPerRow\n                                       NULL,                                // releaseCallback\n                                       NULL,                                // releaseRefCon\n                                       (__bridge CFDictionaryRef)options,   // pixelBufferAttributes\n                                       &pixelBuffer);                       // pixelBuffer\n  if (error != kCVReturnSuccess) {\n    NSLog(@\"Crop CVPixelBufferCreateWithBytes error %d\", (int)error);\n    return NULL;\n  }\n\n  // Cropping using CIImage.\n  CIImage *ciImage = [CIImage imageWithCVImageBuffer:imageBuffer];\n  ciImage = [ciImage imageByCroppingToRect:rect];\n  // CIImage is not in the original point after cropping. So we need to pan.\n  ciImage = [ciImage imageByApplyingTransform:CGAffineTransformMakeTranslation(-cropX, -cropY)];\n\n  [gCIContext render:ciImage toCVPixelBuffer:pixelBuffer];\n\n  // Prepares sample timing info.\n  CMSampleTimingInfo sampleTime = {\n      .duration = CMSampleBufferGetDuration(sampleBuffer),\n      .presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer),\n      .decodeTimeStamp = CMSampleBufferGetDecodeTimeStamp(sampleBuffer)};\n\n  CMVideoFormatDescriptionRef videoInfo;\n  error =\n      CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer, &videoInfo);\n  if (error != kCVReturnSuccess) {\n    NSLog(@\"CMVideoFormatDescriptionCreateForImageBuffer error %d\", (int)error);\n    CVPixelBufferRelease(pixelBuffer);\n    CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);\n    return NULL;\n  }\n\n  // Creates `CMSampleBufferRef`.\n  CMSampleBufferRef resultBuffer = NULL;\n  error = CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer, true, NULL, NULL,\n                                             videoInfo, &sampleTime, &resultBuffer);\n  if (error != kCVReturnSuccess) {\n    NSLog(@\"CMSampleBufferCreateForImageBuffer error %d\", (int)error);\n  }\n  CFRelease(videoInfo);\n  CVPixelBufferRelease(pixelBuffer);\n  CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);\n  return resultBuffer;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Common/MLKUIUtilities.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <AVFoundation/AVFoundation.h>\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n * A utility for creating UI.\n */\n@interface MLKUIUtilities : NSObject\n\n/**\n * Converts given `AVCaptureDevicePosition` and `UIDeviceOrientation` into `UIImageOrientation`.\n */\n+ (UIImageOrientation)imageOrientationFromOrientation:(UIDeviceOrientation)deviceOrientation\n                            withCaptureDevicePosition:(AVCaptureDevicePosition)position;\n\n/**\n * Rotates the given image, based on the current device orientation, so its orientation is `.up`.\n *\n * @param image The image that comes from camera.\n * @return Image with orientation adjusted to upright.\n */\n+ (UIImage *)orientedUpImageFromImage:(UIImage *)image;\n\n/** Returns safe area insets of the view. */\n+ (UIEdgeInsets)safeAreaInsets;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Common/MLKUIUtilities.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKUIUtilities.h\"\n\n#import <AVFoundation/AVFoundation.h>\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation MLKUIUtilities\n\n#pragma mark - Public\n\n+ (UIImageOrientation)imageOrientationFromOrientation:(UIDeviceOrientation)deviceOrientation\n                            withCaptureDevicePosition:(AVCaptureDevicePosition)position {\n  if (deviceOrientation == UIDeviceOrientationFaceDown ||\n      deviceOrientation == UIDeviceOrientationFaceUp ||\n      deviceOrientation == UIDeviceOrientationUnknown) {\n    deviceOrientation = [MLKUIUtilities currentUIOrientation];\n  }\n  UIImageOrientation orientation = UIImageOrientationUp;\n  switch (deviceOrientation) {\n    case UIDeviceOrientationPortrait:\n      orientation = position == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored\n                                                             : UIImageOrientationRight;\n      break;\n    case UIDeviceOrientationLandscapeLeft:\n      orientation = position == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored\n                                                             : UIImageOrientationUp;\n      break;\n    case UIDeviceOrientationPortraitUpsideDown:\n      orientation = position == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored\n                                                             : UIImageOrientationLeft;\n      break;\n    case UIDeviceOrientationLandscapeRight:\n      orientation = position == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored\n                                                             : UIImageOrientationDown;\n      break;\n    case UIDeviceOrientationUnknown:\n    case UIDeviceOrientationFaceUp:\n    case UIDeviceOrientationFaceDown:\n      orientation = UIImageOrientationUp;\n      break;\n  }\n\n  return orientation;\n}\n\n+ (UIDeviceOrientation)currentUIOrientation {\n  UIDeviceOrientation (^deviceOrientation)(void) = ^{\n    switch (UIApplication.sharedApplication.statusBarOrientation) {\n      case UIInterfaceOrientationLandscapeLeft:\n        return UIDeviceOrientationLandscapeRight;\n        break;\n      case UIInterfaceOrientationLandscapeRight:\n        return UIDeviceOrientationLandscapeLeft;\n        break;\n      case UIInterfaceOrientationPortraitUpsideDown:\n        return UIDeviceOrientationPortraitUpsideDown;\n        break;\n      case UIInterfaceOrientationPortrait:\n      case UIInterfaceOrientationUnknown:\n        return UIDeviceOrientationPortrait;\n        break;\n    }\n  };\n  if (NSThread.isMainThread) {\n    return deviceOrientation();\n  }\n  __block UIDeviceOrientation currentOrientation = UIDeviceOrientationPortrait;\n\n  // Must access the `statusBarOrientation` on the main thread only.\n  dispatch_sync(dispatch_get_main_queue(), ^{\n    currentOrientation = deviceOrientation();\n  });\n  return currentOrientation;\n}\n\n+ (UIImage *)orientedUpImageFromImage:(UIImage *)image {\n  UIImageOrientation orientation =\n      [MLKUIUtilities imageOrientationFromOrientation:UIDevice.currentDevice.orientation\n                            withCaptureDevicePosition:AVCaptureDevicePositionBack];\n  // No-op if the orientation is already correct\n  if (orientation == UIImageOrientationUp) return image;\n\n  CGSize size = image.size;\n  switch (orientation) {\n    case UIImageOrientationRight: {\n      UIGraphicsBeginImageContext(CGSizeMake(size.height, size.width));\n      [[UIImage imageWithCGImage:image.CGImage scale:1.0 orientation:UIImageOrientationRight]\n          drawInRect:CGRectMake(0, 0, size.height, size.width)];\n      UIImage *rotatedImage = UIGraphicsGetImageFromCurrentImageContext();\n      UIGraphicsEndImageContext();\n      return rotatedImage;\n    }\n    case UIImageOrientationUp:\n    case UIImageOrientationUpMirrored:\n    case UIImageOrientationDown:\n    case UIImageOrientationDownMirrored:\n    case UIImageOrientationLeftMirrored:\n    case UIImageOrientationRightMirrored:\n    case UIImageOrientationLeft: {\n      // TODO(zhoumi): handle other cases as well.\n      return image;\n    }\n  }\n}\n\n+ (UIEdgeInsets)safeAreaInsets {\n#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)\n  if (@available(iOS 11.0, *)) {\n    return UIApplication.sharedApplication.keyWindow.safeAreaInsets;\n  }\n#endif  // defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)\n  CGRect statusBarFrame = UIApplication.sharedApplication.statusBarFrame;\n  return UIEdgeInsetsMake(MIN(statusBarFrame.size.width, statusBarFrame.size.height), 0, 0, 0);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Common/UIImage+MLKShowcase.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n * An extension of `UIImage` that provides custom image data management.\n */\n@interface UIImage (MLKShowcase)\n\n/**\n * Returns a base 64 encoded string for `UIImage`.\n *\n * @return Returns the base 64 encoded string for `UIImage` or `nil` if its JPEG representation is\n *     `nil`.\n */\n- (nullable NSString *)mlk_base64EncodedString NS_SWIFT_NAME(base64EncodedString());\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Common/UIImage+MLKShowcase.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"UIImage+MLKShowcase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic const CGFloat kJPEGCompressionQuality = 0.7f;\n\n@implementation UIImage (MLKShowcase)\n\n- (nullable NSString *)mlk_base64EncodedString {\n  NSData *jpegEncoding = UIImageJPEGRepresentation(self, kJPEGCompressionQuality);\n  return [jpegEncoding base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Controllers/MLKLiveObjectDetectionViewController.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n#import \"MLKStartPageViewController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Delegate to handle interactions in the  view.*/\n@protocol MLKLiveObjectDetectionViewControllerDelegate <NSObject>\n\n/** Called when the close button is tapped in the view. */\n- (void)didTapBackButton;\n\n@end\n\n/**\n * The camera mode view controller that displays a rear facing live feed.\n */\n@interface MLKLiveObjectDetectionViewController : UIViewController\n\n/** Delegate to handle interactions in the view. */\n@property(weak) id<MLKLiveObjectDetectionViewControllerDelegate> delegate;\n\n/** Initates the live view controller with the given detector type. */\n- (instancetype)initWithDetectorType:(MLKDetectorType)detectorType;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Controllers/MLKLiveObjectDetectionViewController.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKLiveObjectDetectionViewController.h\"\n\n#import <AVFoundation/AVFoundation.h>\n#import <UIKit/UIKit.h>\n\n#import \"MLKCameraReticle.h\"\n#import \"MLKConfirmationSpinner.h\"\n#import \"MLKDetectionOverlayView.h\"\n#import \"MLKImageUtilities.h\"\n#import \"MLKODTStatus.h\"\n#import \"MLKResult.h\"\n#import \"MLKResultListHeaderView.h\"\n#import \"MLKResultListViewController.h\"\n#import \"MLKProductSearchRequest.h\"\n#import \"MLKUIUtilities.h\"\n\n@import MLKitObjectDetection;\n@import MLKitObjectDetectionCommon;\n@import MLKitCommon;\n@import MLKitVision;\n@import MLKitObjectDetectionCustom;\n@import MaterialComponents;\n@import GTMSessionFetcher;\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic char *const MLKVideoDataOutputQueueLabel =\n    \"com.google.mlkit.visiondetector.VideoDataOutputQueue\";\nstatic char *const MLKVideoSessionQueueLabel = \"com.google.mlkit.visiondetector.VideoSessionQueue\";\n\n/** Duration for presenting the bottom sheet. */\nstatic const CGFloat kBottomSheetAnimationDurationInSec = 0.25f;\n\n/** Duration for confirming stage. */\nstatic const CGFloat kconfirmingDurationInSec = 1.5f;\n\n// Constants for alpha values.\nstatic const CGFloat kOpaqueAlpha = 1.0f;\nstatic const CGFloat kTransparentAlpha = 0.0f;\n\n/**  Radius of the searching indicator. */\nstatic const CGFloat kSearchingIndicatorRadius = 24.0f;\n\n/** Target height of the thumbnail when it sits on top of the bottom sheet. */\nstatic const CGFloat kThumbnailbottomSheetTargetHeight = 200.0f;\n\n/** Padding around the thumbnail when it sits on top of the bottom sheet. */\nstatic const CGFloat kThumbnailPaddingAround = 24.0f;\n\n/** The thumbnail will fade out when it reaches this threshold from screen edge. */\nstatic const CGFloat kThumbnailFadeOutEdgeThreshold = 200.0f;\n\n// Chip message related values.\nstatic const CGFloat kChipBackgroundAlpha = 0.6f;\nstatic const CGFloat kChipCornerRadius = 8.0f;\nstatic const CGFloat kChipFadeInDuration = 0.075f;\nstatic const CGFloat kChipScaleDuration = 0.15f;\nstatic const CGFloat kChipScaleFromRatio = 0.8f;\nstatic const CGFloat kChipScaleToRatio = 1.25f;\nstatic const CGFloat kChipBottomPadding = 36.0f;\n\n/** Number of faked product search results. */\nstatic const NSUInteger kFakeSearchResultCount = 10;\n\n/**  Back button related constants. */\nstatic const CGFloat kBackButtonSize = 48.0f;\nstatic const CGFloat kBackButtonBackgroundAlpha = 0.6f;\nstatic const CGFloat kBackButtonPadding = 16.0f;\n\n/** The messages shown in detecting stage.  */\nstatic NSString *const kDetectingStageMessage = @\"Point your camera at an object\";\nstatic NSString *const kDetectingStageMessageBird = @\"Point your camera at a bird\";\n\n/** The Message shown in confirming stage. */\nstatic NSString *const kConfirmingStageMessage = @\"Keep camera still for a moment\";\n\n/** The message shown in searching stage. */\nstatic NSString *const kSearchingMessage = @\"Searching\";\n\n/** Strings for bird search. */\nstatic NSString *const kDescriptionPlaceHoler = @\"Some description about the bird from wiki\";\nstatic NSString *const kWikiSearchURLPattern = @\"https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=%@\";\n\n/** Model related strings. */\nstatic NSString *const kModelNameBird = @\"bird\";\nstatic NSString *const kModelTypeTFLite = @\"tflite\";\n\n// Strings for fake search results.\nstatic NSString *const kFakeResultTitleFormat = @\"Fake product name: %li\";\nstatic NSString *const kFakeProductTypeName = @\"Fashion\";\nstatic NSString *const kFakeProductPriceText = @\"$10\";\nstatic NSString *const kFakeProductItemNumberText = @\"12345678\";\n\n/**\n * A wrapper class that holds a reference to `CMSampleBufferRef` to let ARC take care of its\n * lifecyle for this `CMSampleBufferRef`.\n */\n@interface MLKSampleBuffer : NSObject\n\n// The encapsulated `CMSampleBufferRef` data.\n@property(nonatomic) CMSampleBufferRef data;\n\n@end\n\n@implementation MLKSampleBuffer\n\n#pragma mark - Public\n\n- (instancetype)initWithSampleBuffer:(CMSampleBufferRef)sampleBuffer {\n  self = [super init];\n  if (self != nil) {\n    _data = sampleBuffer;\n    CFRetain(sampleBuffer);\n  }\n  return self;\n}\n\n- (void)dealloc {\n  CFRelease(self.data);\n}\n\n@end\n\n@interface MLKLiveObjectDetectionViewController () <AVCaptureVideoDataOutputSampleBufferDelegate,\n                                                    MDCBottomSheetControllerDelegate>\n\n// Views to be added as subviews of current view.\n@property(nonatomic) UIView *previewView;\n@property(nonatomic) MLKDetectionOverlayView *overlayView;\n@property(nonatomic) MDCButton *backButton;\n@property(nonatomic) MLKCameraReticle *detectingReticle;\n@property(nonatomic) MLKConfirmationSpinner *confirmingSpinner;\n@property(nonatomic) MDCActivityIndicator *searchingIndicator;\n\n// Video capture related properties.\n@property(nonatomic) AVCaptureSession *session;\n@property(nonatomic, nullable) AVCaptureVideoDataOutput *videoDataOutput;\n@property(nonatomic) dispatch_queue_t videoDataOutputQueue;\n@property(nonatomic) dispatch_queue_t sessionQueue;\n@property(nonatomic) AVCaptureVideoPreviewLayer *previewLayer;\n\n// The `MLKObjectDetector` used to detect objects.\n@property(nonatomic) MLKObjectDetector *detector;\n\n// Current status in object detection.\n@property(nonatomic) MLKODTStatus status;\n\n// View to show message during different stages.\n@property(nonatomic) MDCChipView *messageView;\n\n// Properties to record latest detected results.\n@property(nonatomic, nullable) MLKObject *lastDetectedObject;\n@property(nonatomic, nullable) MLKSampleBuffer *lastDetectedSampleBuffer;\n\n// Width to height ratio of the thumbnail.\n@property(nonatomic) CGFloat thumbnailWidthHeightRatio;\n\n// Target Y offset of the bottom sheet.\n@property(nonatomic) CGFloat bottomSheetTargetOffsetY;\n\n// Array of timers scheduled before Confirmation.\n@property(nonatomic, nullable) NSMutableArray<NSTimer *> *timers;\n\n// Used to fetch product search results.\n@property(nonatomic) GTMSessionFetcherService *fetcherService;\n\n/** Type of current detector. */\n@property(nonatomic) MLKDetectorType detectorType;\n\n@end\n\n@implementation MLKLiveObjectDetectionViewController\n\n#pragma mark - Public\n\n- (id)initWithDetectorType:(MLKDetectorType)detectorType {\n  self = [super init];\n  if (self != nil) {\n    _detectorType = detectorType;\n    _videoDataOutputQueue =\n        dispatch_queue_create(MLKVideoDataOutputQueueLabel, DISPATCH_QUEUE_SERIAL);\n    _sessionQueue = dispatch_queue_create(MLKVideoSessionQueueLabel, DISPATCH_QUEUE_SERIAL);\n    _session = [[AVCaptureSession alloc] init];\n    _fetcherService = [[GTMSessionFetcherService alloc] init];\n    _status = MLKODTStatus_NotStarted;\n    _timers = [NSMutableArray array];\n    [self setUpDetectorOfType:detectorType];\n  }\n  return self;\n}\n\n- (void)dealloc {\n  [self clearLastDetectedObject];\n  [self.fetcherService stopAllFetchers];\n}\n\n#pragma mark - UIViewController\n\n- (void)loadView {\n  [super loadView];\n\n  self.view.clipsToBounds = YES;\n\n  [self setUpPreviewView];\n  [self setUpOverlayView];\n}\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  self.view.backgroundColor = UIColor.whiteColor;\n\n  [self setCameraSelection];\n\n  // Set up video processing pipeline.\n  [self setUpVideoProcessing];\n\n  // Set up camera preview.\n#if !TARGET_IPHONE_SIMULATOR\n  [self setUpCameraPreviewLayer];\n#endif\n\n  [self setUpDetectingReticle];\n  [self setUpconfirmingSpinner];\n  [self setUpSearchingIndicator];\n  [self setUpMessageView];\n\n  [self setupBackButton];\n  [self startToDetect];\n}\n\n- (void)viewDidLayoutSubviews {\n  [super viewDidLayoutSubviews];\n\n  self.previewLayer.frame = self.view.frame;\n  self.previewLayer.position =\n      CGPointMake(CGRectGetMidX(self.previewLayer.frame), CGRectGetMidY(self.previewLayer.frame));\n}\n\n- (void)viewDidDisappear:(BOOL)animated {\n  [super viewDidDisappear:animated];\n  __weak typeof(self) weakSelf = self;\n#if !TARGET_IPHONE_SIMULATOR\n  dispatch_async(self.sessionQueue, ^{\n    [weakSelf.session stopRunning];\n  });\n#endif\n}\n\n#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate\n\n- (void)captureOutput:(AVCaptureOutput *)captureOutput\n    didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer\n           fromConnection:(AVCaptureConnection *)connection {\n  [self detectObjectInSampleBuffer:[[MLKSampleBuffer alloc] initWithSampleBuffer:sampleBuffer]];\n}\n\n#pragma mark - MDCBottomSheetControllerDelegate\n\n- (void)bottomSheetControllerDidDismissBottomSheet:(nonnull MDCBottomSheetController *)controller {\n  self.bottomSheetTargetOffsetY = 0;\n  [self startToDetect];\n}\n\n- (void)bottomSheetControllerDidChangeYOffset:(MDCBottomSheetController *)controller\n                                      yOffset:(CGFloat)yOffset {\n  CGFloat imageStartY = yOffset - kThumbnailbottomSheetTargetHeight - kThumbnailPaddingAround;\n  CGRect rect =\n      CGRectMake(kThumbnailPaddingAround,                                             // X\n                 imageStartY,                                                         // Y\n                 kThumbnailbottomSheetTargetHeight * self.thumbnailWidthHeightRatio,  // Width\n                 kThumbnailbottomSheetTargetHeight);                                  // Height\n\n  UIWindow *currentWindow = UIApplication.sharedApplication.keyWindow;\n\n  UIEdgeInsets safeInsets = [MLKUIUtilities safeAreaInsets];\n  CGFloat screenHeight = currentWindow.bounds.size.height;\n  CGFloat topFadeOutOffsetY = safeInsets.top + kThumbnailFadeOutEdgeThreshold;\n  CGFloat bottomFadeOutOffsetY = screenHeight - safeInsets.bottom - kThumbnailFadeOutEdgeThreshold;\n\n  CGFloat imageAlpha =\n      [self ratioOfCurrentValue:yOffset\n                           from:(yOffset > self.bottomSheetTargetOffsetY) ? bottomFadeOutOffsetY\n                                                                          : topFadeOutOffsetY\n                             to:self.bottomSheetTargetOffsetY];\n  [self.overlayView showImageInRect:rect alpha:imageAlpha];\n}\n\n#pragma mark - Private\n\n- (NSString *)detectingStageMessage {\n  switch (self.detectorType) {\n    case MLKDetectorTypeODTBirdModel:\n      return kDetectingStageMessageBird;\n    case MLKDetectorTypeODTDefaultModel: // Falls through\n    default:\n      return kDetectingStageMessage;\n  }\n}\n\n- (void) didTapBackButton {\n  [self.delegate didTapBackButton];\n}\n\n- (void)setUpDetectorOfType:(MLKDetectorType)detectorType {\n  switch (detectorType) {\n    case MLKDetectorTypeODTDefaultModel: {\n      MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init];\n      _detector = [MLKObjectDetector objectDetectorWithOptions:options];\n      break;\n    }\n    case MLKDetectorTypeODTBirdModel: {\n      NSString *localModelPath = [[NSBundle mainBundle] pathForResource:kModelNameBird\n                                                                 ofType:kModelTypeTFLite];\n      MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelPath];\n      MLKCommonObjectDetectorOptions *options =\n          [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];\n      options.shouldEnableClassification = YES;\n      _detector = [MLKObjectDetector objectDetectorWithOptions:options];\n      break;\n    }\n    default:\n      break;\n  }\n}\n\n/** Prepares camera session for video processing. */\n- (void)setUpVideoProcessing {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(self.sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    if (strongSelf == nil) {\n      return;\n    }\n    strongSelf.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];\n    NSDictionary<NSString *, NSNumber *> *rgbOutputSettings =\n        @{(__bridge NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA)};\n    [strongSelf.videoDataOutput setVideoSettings:rgbOutputSettings];\n\n    if (![strongSelf.session canAddOutput:strongSelf.videoDataOutput]) {\n      if (strongSelf.videoDataOutput) {\n        [strongSelf.session removeOutput:strongSelf.videoDataOutput];\n        strongSelf.videoDataOutput = nil;\n      }\n      NSLog(@\"Failed to set up video output\");\n      return;\n    }\n    [strongSelf.videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];\n    [strongSelf.videoDataOutput setSampleBufferDelegate:strongSelf\n                                                  queue:strongSelf.videoDataOutputQueue];\n    [strongSelf.session addOutput:strongSelf.videoDataOutput];\n  });\n}\n\n/** Prepares preview view for camera session. */\n- (void)setUpPreviewView {\n  self.previewView = [[UIView alloc] initWithFrame:self.view.frame];\n  self.previewView.translatesAutoresizingMaskIntoConstraints = NO;\n  [self.view addSubview:self.previewView];\n}\n\n/** Initiates and prepares camera preview layer for later video capture. */\n- (void)setUpCameraPreviewLayer {\n  self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];\n  [self.previewLayer setBackgroundColor:UIColor.blackColor.CGColor];\n  [self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];\n  CALayer *rootLayer = [self.previewView layer];\n  [rootLayer setMasksToBounds:YES];\n  [self.previewView setFrame:[rootLayer bounds]];\n  [rootLayer addSublayer:self.previewLayer];\n}\n\n/** Prepares camera for later video capture. */\n- (void)setCameraSelection {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(self.sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    if (strongSelf == nil) {\n      return;\n    }\n\n    [strongSelf.session beginConfiguration];\n    strongSelf.session.sessionPreset = AVCaptureSessionPreset1280x720;\n\n    NSArray<AVCaptureInput *> *oldInputs = [strongSelf.session inputs];\n    for (AVCaptureInput *oldInput in oldInputs) {\n      [strongSelf.session removeInput:oldInput];\n    }\n\n    AVCaptureDeviceInput *input = [strongSelf pickCamera:AVCaptureDevicePositionBack];\n    if (!input) {\n      // Failed, restore old inputs\n      for (AVCaptureInput *oldInput in oldInputs) {\n        [strongSelf.session addInput:oldInput];\n      }\n    } else {\n      // Succeeded, set input and update connection states\n      [strongSelf.session addInput:input];\n    }\n    [strongSelf.session commitConfiguration];\n  });\n}\n\n/** Determines camera for later video capture. Here only rear camera is picked. */\n- (AVCaptureDeviceInput *)pickCamera:(AVCaptureDevicePosition)desiredPosition {\n  BOOL hadError = NO;\n  for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {\n    if ([device position] == desiredPosition) {\n      NSError *error = nil;\n      AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device\n                                                                          error:&error];\n      if (error != nil) {\n        hadError = YES;\n        NSLog(@\"Could not initialize for AVMediaTypeVideo for device %@\", device);\n      } else if ([self.session canAddInput:input]) {\n        return input;\n      }\n    }\n  }\n  if (!hadError) {\n    NSLog(@\"No camera found for requested orientation\");\n  }\n  return nil;\n}\n\n/** Initiates and prepares overlay view for later video capture. */\n- (void)setUpOverlayView {\n  self.overlayView = [[MLKDetectionOverlayView alloc] initWithFrame:self.view.frame];\n  self.overlayView.translatesAutoresizingMaskIntoConstraints = NO;\n  [self.view addSubview:self.overlayView];\n}\n\n- (void)setupBackButton {\n  self.backButton = [[MDCButton alloc] init];\n  UIImage *backArrow = [UIImage imageNamed:@\"ic_arrow_back_ios\"];\n  [self.backButton setTintColor:UIColor.whiteColor];\n  [self.backButton setImage:backArrow forState:UIControlStateNormal];\n  [self.backButton clipsToBounds];\n  [self.backButton.layer setCornerRadius:kBackButtonSize / 2];\n  CGFloat statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;\n  self.backButton.frame = CGRectMake(kBackButtonPadding, //X\n                                     kBackButtonPadding + statusBarHeight, // Y\n                                     kBackButtonSize, // Width\n                                     kBackButtonSize); // Height\n  self.backButton.backgroundColor =\n    [UIColor.blackColor colorWithAlphaComponent:kBackButtonBackgroundAlpha];\n  [self.backButton addTarget:self\n                      action:@selector(didTapBackButton)\n            forControlEvents:UIControlEventTouchUpInside];\n  [self.view addSubview:self.backButton];\n  [NSLayoutConstraint activateConstraints:@[\n    [self.backButton.leftAnchor constraintEqualToAnchor:self.view.leftAnchor],\n    [self.backButton.topAnchor constraintEqualToAnchor:self.view.topAnchor],\n  ]];\n}\n\n/** Clears up the overlay view. Caller must make sure this runs on the main thread. */\n- (void)cleanUpOverlayView {\n  NSAssert([NSThread.currentThread isEqual:NSThread.mainThread],\n           @\"cleanUpOverlayView is not running on the main thread\");\n\n  [self.overlayView hideSubviews];\n  self.overlayView.frame = self.view.frame;\n}\n\n/** Initiates and prepares detecting reticle for later video capture. */\n- (void)setUpDetectingReticle {\n  self.detectingReticle = [[MLKCameraReticle alloc] init];\n  self.detectingReticle.translatesAutoresizingMaskIntoConstraints = NO;\n  CGSize size = [self.detectingReticle sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];\n  self.detectingReticle.frame = CGRectMake(0, 0, size.width, size.height);\n  [self.view addSubview:self.detectingReticle];\n  [NSLayoutConstraint activateConstraints:@[\n    [self.detectingReticle.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],\n    [self.detectingReticle.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],\n  ]];\n}\n\n/** Initiates and prepares confirming spinner for later video capture. */\n- (void)setUpconfirmingSpinner {\n  self.confirmingSpinner =\n      [[MLKConfirmationSpinner alloc] initWithDuration:kconfirmingDurationInSec];\n  self.confirmingSpinner.translatesAutoresizingMaskIntoConstraints = NO;\n  CGSize size = [self.confirmingSpinner sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];\n  self.confirmingSpinner.frame = CGRectMake(0, 0, size.width, size.height);\n  [self.view addSubview:self.confirmingSpinner];\n  [NSLayoutConstraint activateConstraints:@[\n    [self.confirmingSpinner.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],\n    [self.confirmingSpinner.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],\n  ]];\n}\n\n/** Initiates and prepares searching indicator for later video capture. */\n- (void)setUpSearchingIndicator {\n  self.searchingIndicator = [[MDCActivityIndicator alloc] init];\n  self.searchingIndicator.radius = kSearchingIndicatorRadius;\n  self.searchingIndicator.cycleColors = @[ UIColor.whiteColor ];\n  CGSize size = [self.confirmingSpinner sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];\n  CGFloat centerX = CGRectGetMidX(self.view.frame);\n  CGFloat centerY = CGRectGetMidY(self.view.frame);\n  self.searchingIndicator.frame = CGRectMake(centerX, centerY, size.width, size.height);\n  [self.view addSubview:self.searchingIndicator];\n  [NSLayoutConstraint activateConstraints:@[\n    [self.searchingIndicator.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],\n    [self.searchingIndicator.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],\n  ]];\n}\n\n/** Initiates and prepares message view for later video capture. */\n- (void)setUpMessageView {\n  self.messageView = [[MDCChipView alloc] init];\n  [self.messageView setBackgroundColor:[UIColor.blackColor colorWithAlphaComponent:kChipBackgroundAlpha] forState:UIControlStateNormal];\n\n  self.messageView.userInteractionEnabled = NO;\n  self.messageView.clipsToBounds = YES;\n  self.messageView.titleLabel.textColor = UIColor.whiteColor;\n  self.messageView.layer.cornerRadius = kChipCornerRadius;\n  [self.view addSubview:self.messageView];\n  self.messageView.alpha = kTransparentAlpha;\n}\n\n/**\n * Clears last detected object. Caller must make sure that this method runs on the main thread.\n */\n- (void)clearLastDetectedObject {\n  NSAssert([NSThread.currentThread isEqual:NSThread.mainThread],\n           @\"clearLastDetectedObject is not running on the main thread\");\n\n  self.lastDetectedObject = nil;\n  self.lastDetectedSampleBuffer = nil;\n  for (NSTimer *timer in self.timers) {\n    [timer invalidate];\n  }\n}\n\n#pragma mark - Object detection and tracking.\n\n/**\n * Called to detect objects in the given sample buffer.\n *\n * @param sampleBuffer The `SampleBuffer` for object detection.\n */\n- (void)detectObjectInSampleBuffer:(MLKSampleBuffer *)sampleBuffer {\n  MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer.data];\n  image.orientation =\n      [MLKUIUtilities imageOrientationFromOrientation:UIDevice.currentDevice.orientation\n                            withCaptureDevicePosition:AVCaptureDevicePositionBack];\n  NSError *error;\n  NSArray<MLKObject *> *objects = [self.detector resultsInImage:image error:&error];\n  if (error == nil) {\n    __weak typeof(self) weakSelf = self;\n    dispatch_async(dispatch_get_main_queue(), ^{\n      [weakSelf onDetectedObjects:objects inSampleBuffer:sampleBuffer];\n    });\n  }\n}\n\n/**\n * Call when objects are detected in the given sample buffer. Caller must make sure that this method\n * runs on the main thread.\n *\n * @param objects The list of objects that is detected in the given sample buffer.\n * @param sampleBuffer The given sampleBuffer.\n */\n- (void)onDetectedObjects:(nullable NSArray<MLKObject *> *)objects\n           inSampleBuffer:(MLKSampleBuffer *)sampleBuffer {\n  NSAssert([NSThread.currentThread isEqual:NSThread.mainThread],\n           @\"onDetectedObjects:inSampleBuffer is not running on the main thread\");\n\n  if (objects.count < 1) {\n    [self startToDetect];\n    return;\n  }\n\n  MLKObject *object = [objects firstObject];\n  self.lastDetectedObject = object;\n  if (object.trackingID.stringValue.length == 0) {\n    [self startToDetect];\n    return;\n  }\n\n  CGSize sampleBufferSize = [self sampleBufferSize:sampleBuffer.data];\n  BOOL isFocusInsideObjectFrame = CGRectContainsPoint(\n      object.frame, CGPointMake(sampleBufferSize.width / 2, sampleBufferSize.height / 2));\n  if (!isFocusInsideObjectFrame) {\n    [self startToDetect];\n    return;\n  }\n\n  switch (self.status) {\n    case MLKODTStatus_Detecting: {\n      [self cleanUpOverlayView];\n      CGRect convertedRect = [self convertedRectOfObjectFrame:object.frame\n                                      inSampleBufferFrameSize:sampleBufferSize];\n      [self.overlayView showBoxInRect:convertedRect];\n      [self startToConfirmObject:object sampleBuffer:sampleBuffer];\n      break;\n    }\n    case MLKODTStatus_Confirming: {\n      CGRect convertedRect = [self convertedRectOfObjectFrame:object.frame\n                                      inSampleBufferFrameSize:sampleBufferSize];\n      [self.overlayView showBoxInRect:convertedRect];\n      self.lastDetectedObject = object;\n      self.lastDetectedSampleBuffer = sampleBuffer;\n      break;\n    }\n    case MLKODTStatus_Searching:\n    case MLKODTStatus_Searched:\n    case MLKODTStatus_NotStarted:\n      break;\n  }\n}\n\n#pragma mark - Status Handling\n\n/**\n * Called when it needs to start the detection. Caller must make sure that this method runs on the\n * main thread.\n */\n- (void)startToDetect {\n  NSAssert([NSThread.currentThread isEqual:NSThread.mainThread],\n           @\"startToDetect is not running on the main thread\");\n\n  self.status = MLKODTStatus_Detecting;\n  [self cleanUpOverlayView];\n  [self clearLastDetectedObject];\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(self.sessionQueue, ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    if (strongSelf == nil) {\n      return;\n    }\n#if !TARGET_IPHONE_SIMULATOR\n    if (![strongSelf.session isRunning]) {\n      [strongSelf.session startRunning];\n    }\n#endif\n  });\n}\n\n/**\n * Starts a search with last detected object. Caller must make sure that this method runs on the\n * main thread.\n */\n- (void)startToSearch {\n  NSAssert(\n      [NSThread.currentThread isEqual:NSThread.mainThread],\n      @\"startToSearchWithImage:originalWidth:originalHeight is not running on the main thread\");\n\n  self.status = MLKODTStatus_Searching;\n\n  CGSize originalSampleBufferSize = [self sampleBufferSize:self.lastDetectedSampleBuffer.data];\n\n  UIImage *croppedImage = [self croppedImageFromSampleBuffer:self.lastDetectedSampleBuffer.data\n                                                      inRect:self.lastDetectedObject.frame];\n  CGRect convertedRect = [self convertedRectOfObjectFrame:self.lastDetectedObject.frame\n                                  inSampleBufferFrameSize:originalSampleBufferSize];\n  self.thumbnailWidthHeightRatio =\n      self.lastDetectedObject.frame.size.height / self.lastDetectedObject.frame.size.width;\n  self.overlayView.image.image = croppedImage;\n  [self cleanUpOverlayView];\n  [self.overlayView showImageInRect:convertedRect alpha:1];\n\n  switch (self.detectorType) {\n    case MLKDetectorTypeODTDefaultModel: {\n      MLKProductSearchRequest *request = [[MLKProductSearchRequest alloc] initWithUIImage:croppedImage];\n      GTMSessionFetcher *fetcher = [self.fetcherService fetcherWithRequest:request];\n      if (request.URL.absoluteString.length == 0) {\n        [self processSearchResponse:nil\n                           forImage:croppedImage\n                      originalWidth:originalSampleBufferSize.width\n                     originalHeight:originalSampleBufferSize.height\n                    useFakeResponse:YES];\n        [self clearLastDetectedObject];\n        return;\n      }\n      __weak typeof(self) weakSelf = self;\n      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{\n        [fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (strongSelf == nil) {\n            return;\n          }\n          if (error) {\n            NSLog(@\"error in fetching: %@\", error);\n            [strongSelf clearLastDetectedObject];\n            return;\n          }\n          dispatch_async(dispatch_get_main_queue(), ^{\n            __strong typeof(weakSelf) strongSelf = weakSelf;\n            if (strongSelf == nil) {\n              return;\n            }\n            [strongSelf processSearchResponse:data\n                                     forImage:croppedImage\n                                originalWidth:originalSampleBufferSize.width\n                               originalHeight:originalSampleBufferSize.height\n                              useFakeResponse:NO];\n            [strongSelf clearLastDetectedObject];\n          });\n        }];\n      });\n      break;\n    }\n    case MLKDetectorTypeODTBirdModel: {\n      NSString *birdName = self.lastDetectedObject.labels[0].text;\n      NSString *encodedKeyword = [self encodedKeyword:birdName];\n      NSString *urlWithKeyword = [NSString stringWithFormat:kWikiSearchURLPattern,\n                                  encodedKeyword];\n      NSMutableURLRequest *request =\n        [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:urlWithKeyword]];\n      static GTMSessionFetcherService * gFetcherService;\n      static dispatch_once_t onceToken;\n      dispatch_once(&onceToken, ^{\n        gFetcherService = [[GTMSessionFetcherService alloc] init];\n      });\n      GTMSessionFetcher *fetcher = [gFetcherService fetcherWithRequest:request];\n      __weak typeof(self) weakSelf = self;\n      __block NSString *abstract = nil;\n      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{\n        [fetcher beginFetchWithCompletionHandler:^(NSData *_Nullable data, NSError *_Nullable error) {\n          __strong typeof(weakSelf) strongSelf = weakSelf;\n          if (strongSelf == nil) {\n            return;\n          }\n          if (error) {\n            NSLog(@\"error in fetching: %@\", error);\n            abstract = @\"No result\";\n            return;\n          }\n          [strongSelf processSearchResponse:data\n                                   forImage:croppedImage\n                              originalWidth:originalSampleBufferSize.width\n                             originalHeight:originalSampleBufferSize.height\n                            useFakeResponse:NO];\n          [strongSelf clearLastDetectedObject];\n        }];\n      });\n      break;\n    }\n    default: {\n      break;\n  }\n  }\n}\n\n/**\n * Processes search response from server. Caller must make sure that this method runs on the main\n * thread.\n *\n * @param response The raw response from server on product search request.\n * @param image The image of the detected object that is to be searched.\n * @param width The width of the original sample buffer.\n * @param height The height of the original sample buffer.\n * @param useFakeResponse Whether to use fake response or send a product search request to the\n * server.\n */\n- (void)processSearchResponse:(nullable NSData *)response\n                     forImage:(UIImage *)image\n                originalWidth:(size_t)width\n               originalHeight:(size_t)height\n              useFakeResponse:(BOOL)useFakeResponse {\n  NSAssert([NSThread.currentThread isEqual:NSThread.mainThread],\n           @\"processSearchRespose:forImage:originalWidth:originalHeight is not running on the main \"\n           @\"thread\");\n  self.status = MLKODTStatus_Searched;\n  NSArray<MLKResult *> *results;\n  if (useFakeResponse) {\n    results = [self fakeSearchResults];\n  } else {\n    results = [MLKResult resultsFromResponse:response forDetectortype: self.detectorType];\n  }\n  MLKResultListViewController *resultsViewController =\n      [[MLKResultListViewController alloc] initWithResults:results];\n\n  MDCBottomSheetController *bottomSheet =\n      [[MDCBottomSheetController alloc] initWithContentViewController:resultsViewController];\n  bottomSheet.trackingScrollView = resultsViewController.collectionView;\n\n  bottomSheet.scrimColor = UIColor.clearColor;\n  bottomSheet.dismissOnBackgroundTap = YES;\n  bottomSheet.delegate = self;\n\n  CGFloat contentHeight =\n      resultsViewController.collectionViewLayout.collectionViewContentSize.height;\n  CGFloat screenHeight = self.view.frame.size.height;\n\n  UIEdgeInsets safeInsets = [MLKUIUtilities safeAreaInsets];\n\n  CGFloat toOffsetY = contentHeight > screenHeight / 2.0f\n                          ? screenHeight / 2.0f - safeInsets.bottom\n                          : screenHeight - contentHeight - safeInsets.top - safeInsets.bottom;\n  self.bottomSheetTargetOffsetY = toOffsetY;\n\n  CGRect toFrame =\n      CGRectMake(kThumbnailPaddingAround,                                                  // X\n                 toOffsetY - kThumbnailbottomSheetTargetHeight - kThumbnailPaddingAround,  // Y\n                 self.thumbnailWidthHeightRatio * kThumbnailbottomSheetTargetHeight,       // Width\n                 kThumbnailbottomSheetTargetHeight);                                       // Height\n\n  [UIView animateWithDuration:kBottomSheetAnimationDurationInSec\n                   animations:^{\n                     [self.overlayView showImageInRect:toFrame alpha:1];\n                   }];\n  [self presentViewController:bottomSheet animated:YES completion:nil];\n}\n\n/**\n * Calculates the ratio of current value based on `from` and `to` value.\n *\n * @param currentValue The current value.\n * @param fromValue The start point of the range.\n * @param toValue The end point of the range.\n * @return Position of current value in the whole range. It falls into [0,1].\n */\n- (CGFloat)ratioOfCurrentValue:(CGFloat)currentValue from:(CGFloat)fromValue to:(CGFloat)toValue {\n  CGFloat ratio = (currentValue - fromValue) / (toValue - fromValue);\n  ratio = MIN(ratio, 1);\n  return MAX(ratio, 0);\n}\n\n/**\n * Called to confirm on the given object.Caller must make sure that this method runs on the main\n * thread.\n *\n * @param object The object to confirm. It will be regarded as the same object if its objectID stays\n *     the same during this stage.\n * @param sampleBuffer The original sample buffer that this object was detected in.\n */\n- (void)startToConfirmObject:(MLKObject *)object sampleBuffer:(MLKSampleBuffer *)sampleBuffer {\n  NSAssert([NSThread.currentThread isEqual:NSThread.mainThread],\n           @\"startToConfirmObject:sampleBuffer is not running on the main thread\");\n  [self clearLastDetectedObject];\n  NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:kconfirmingDurationInSec\n                                                    target:self\n                                                  selector:@selector(onTimerMLKed)\n                                                  userInfo:nil\n                                                   repeats:NO];\n  [self.timers addObject:timer];\n\n  self.status = MLKODTStatus_Confirming;\n  self.lastDetectedObject = object;\n  self.lastDetectedSampleBuffer = sampleBuffer;\n}\n\n/** Called when timer is up and the detected object is confirmed. */\n- (void)onTimerMLKed {\n  __weak typeof(self) weakSelf = self;\n  dispatch_async(dispatch_get_main_queue(), ^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    if (strongSelf == nil) {\n      return;\n    }\n    switch (strongSelf.status) {\n      case MLKODTStatus_Confirming: {\n#if !TARGET_IPHONE_SIMULATOR\n        dispatch_async(strongSelf.sessionQueue, ^{\n          [weakSelf.session stopRunning];\n        });\n#endif\n        [strongSelf startToSearch];\n        break;\n      }\n      case MLKODTStatus_Detecting:\n      case MLKODTStatus_NotStarted:\n      case MLKODTStatus_Searched:\n      case MLKODTStatus_Searching:\n        break;\n    }\n  });\n}\n\n/**\n * Overrides setter for `status` property. It also shows corresponding indicator/message with the\n * status change. Caller must make sure that this method runs on the main thread.\n *\n * @param status The new status.\n */\n- (void)setStatus:(MLKODTStatus)status {\n  NSAssert([NSThread.currentThread isEqual:NSThread.mainThread],\n           @\"setStatus is not running on the main thread\");\n\n  if (_status == status) {\n    return;\n  }\n  _status = status;\n\n  switch (status) {\n    case MLKODTStatus_NotStarted: {\n      [self hideMessage];\n      [self.confirmingSpinner setHidden:YES];\n      [self.detectingReticle setHidden:YES];\n      [self showSearchingIndicator:NO];\n      break;\n    }\n    case MLKODTStatus_Detecting: {\n      [self showMessage:[self detectingStageMessage]];\n      [self.detectingReticle setHidden:NO];\n      [self.confirmingSpinner setHidden:YES];\n      [self showSearchingIndicator:NO];\n      break;\n    }\n    case MLKODTStatus_Confirming: {\n      [self showMessage:kConfirmingStageMessage];\n      [self.detectingReticle setHidden:YES];\n      [self.confirmingSpinner setHidden:NO];\n      [self showSearchingIndicator:NO];\n      break;\n    }\n    case MLKODTStatus_Searching: {\n      [self showMessage:kSearchingMessage];\n      [self.confirmingSpinner setHidden:YES];\n      [self.detectingReticle setHidden:YES];\n      [self showSearchingIndicator:YES];\n      break;\n    }\n    case MLKODTStatus_Searched: {\n      [self hideMessage];\n      [self.confirmingSpinner setHidden:YES];\n      [self.detectingReticle setHidden:YES];\n      [self showSearchingIndicator:NO];\n      break;\n    }\n  }\n}\n\n#pragma mark - Util methods\n\n/**\n * Returns size of given `CMSampleBufferRef`.\n *\n * @param sampleBuffer The `CMSampleBufferRef` to get size from.\n * @return The size of the given `CMSampleBufferRef`. It describes its width and height.\n */\n- (CGSize)sampleBufferSize:(CMSampleBufferRef)sampleBuffer {\n  CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);\n  size_t imageWidth = CVPixelBufferGetWidth(imageBuffer);\n  size_t imageHeight = CVPixelBufferGetHeight(imageBuffer);\n  return CGSizeMake(imageWidth, imageHeight);\n}\n\n/**\n * Converts given frame of a detected object to a `CGRect` in coordinate system of current view.\n *\n * @param frame The frame of detected object.\n * @param size The frame size of the sample buffer.\n * @return Converted rect.\n */\n- (CGRect)convertedRectOfObjectFrame:(CGRect)frame inSampleBufferFrameSize:(CGSize)size {\n  CGRect normalizedRect = CGRectMake(frame.origin.x / size.width,       // X\n                                     frame.origin.y / size.height,      // Y\n                                     frame.size.width / size.width,     // Width\n                                     frame.size.height / size.height);  // Height\n  CGRect convertedRect = [self.previewLayer rectForMetadataOutputRectOfInterest:normalizedRect];\n  return CGRectStandardize(convertedRect);\n}\n\n/**\n * Crops given `CMSampleBufferRef` with given rect.\n *\n * @param sampleBuffer The sample buffer to be cropped.\n * @param rect The rect of the area to be cropped.\n * @return Returns cropped image to the given rect.\n */\n- (UIImage *)croppedImageFromSampleBuffer:(CMSampleBufferRef)sampleBuffer inRect:(CGRect)rect {\n  CMSampleBufferRef croppedSampleBuffer = [MLKImageUtilities croppedSampleBuffer:sampleBuffer\n                                                                        withRect:rect];\n  UIImage *croppedImage = [MLKImageUtilities imageFromSampleBuffer:croppedSampleBuffer];\n  return [MLKUIUtilities orientedUpImageFromImage:croppedImage];\n}\n\n/**\n * Shows/Hides searching indicator.\n *\n * @param isVisible Whether to show/hide searching indicator. YES to show, NO to hide.\n */\n- (void)showSearchingIndicator:(BOOL)isVisible {\n  if (isVisible) {\n    [self.searchingIndicator setHidden:NO];\n    [self.searchingIndicator startAnimating];\n  } else {\n    [self.searchingIndicator setHidden:YES];\n    [self.searchingIndicator stopAnimating];\n  }\n}\n\n- (void)showMessage:(NSString *)message {\n  if ([self.messageView.titleLabel.text isEqual:message]) {\n    return;\n  }\n  self.messageView.titleLabel.text = message;\n  [self.messageView sizeToFit];\n  CGSize size = [self.messageView sizeThatFits:self.view.frame.size];\n  CGFloat startX = (self.view.frame.size.width - size.width) / 2.0f;\n  CGFloat startY = self.view.frame.size.height - kChipBottomPadding - size.height;\n  self.messageView.frame = CGRectMake(startX, startY, size.width, size.height);\n\n  if (self.messageView.alpha != kTransparentAlpha) {\n    return;\n  }\n  self.messageView.alpha = kTransparentAlpha;\n  [UIView animateWithDuration:kChipFadeInDuration\n                   animations:^{\n                     self.messageView.alpha = kOpaqueAlpha;\n                   }];\n\n  CGPoint messageCenter =\n      CGPointMake(CGRectGetMidX(self.messageView.frame), CGRectGetMidY(self.messageView.frame));\n\n  self.messageView.transform =\n      CGAffineTransformScale(self.messageView.transform, kChipScaleFromRatio, kChipScaleFromRatio);\n  [self.messageView sizeToFit];\n\n  [UIView animateWithDuration:kChipScaleDuration\n                   animations:^{\n                     self.messageView.center = messageCenter;\n                     self.messageView.transform = CGAffineTransformScale(\n                         self.messageView.transform, kChipScaleToRatio, kChipScaleToRatio);\n                   }];\n}\n\n- (void)hideMessage {\n  [UIView animateWithDuration:kChipFadeInDuration\n                   animations:^{\n                     self.messageView.alpha = kTransparentAlpha;\n                   }];\n}\n\n/**\n * Generates fake search results for demo when there are no backend server hooked up.\n */\n- (NSArray<MLKResult *> *)fakeSearchResults {\n  switch (self.detectorType) {\n    case MLKDetectorTypeODTDefaultModel: {\n      NSMutableArray<MLKResult *> *fakeSearchResults = [NSMutableArray array];\n       for (NSInteger index = 0; index < kFakeSearchResultCount; index++) {\n         MLKResult *result = [[MLKResult alloc] init];\n         result.title = [NSString stringWithFormat:kFakeResultTitleFormat, index + 1];\n         result.details = kFakeProductTypeName;\n         result.priceFullText = kFakeProductPriceText;\n         result.itemNumber = kFakeProductItemNumberText;\n         [fakeSearchResults addObject:result];\n       }\n       return fakeSearchResults;\n    }\n    case MLKDetectorTypeODTBirdModel: {\n      NSMutableArray<MLKResult *> *fakeSearchResults = [NSMutableArray array];\n      for (NSInteger index = 0; index < self.lastDetectedObject.labels.count; index++) {\n        MLKObjectLabel *label = self.lastDetectedObject.labels[index];\n        MLKResult *result = [[MLKResult alloc] init];\n        result.title = label.text;\n        NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@\" \"];\n        NSArray<NSString *>*keywords = [label.text componentsSeparatedByCharactersInSet:set];\n        result.details = kDescriptionPlaceHoler;\n        [fakeSearchResults addObject:result];\n      }\n      return fakeSearchResults;\n    }\n    default: {\n      return nil;\n    }\n  }\n}\n\n/** Converts the given keyword to a encoded one so as to be used in requests. */\n- (nullable NSString *)encodedKeyword:(NSString *)birdName{\n  if (birdName.length == 0 || [birdName isEqual:@\"N/A\"] || [birdName isEqual: @\"n/a\"]) {\n    return nil;\n  }\n  NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@\"(\"];\n  NSArray<NSString *>*keywords = [birdName componentsSeparatedByCharactersInSet:set];\n    NSUInteger location = 0;\n    unichar charBuffer[[keywords[0] length]];\n    [keywords[0] getCharacters:charBuffer];\n    NSUInteger i = 0;\n    for(i = [keywords[0] length]; i >0; i--) {\n        NSCharacterSet* charSet = [NSCharacterSet whitespaceCharacterSet];\n        if(![charSet characterIsMember:charBuffer[i - 1]]) {\n            break;\n        }\n    }\n    NSString *strippedKeyword = [keywords[0] substringWithRange:\n                                 NSMakeRange(location, i  - location)];\n    return [strippedKeyword stringByAddingPercentEncodingWithAllowedCharacters:\n      [NSCharacterSet  alphanumericCharacterSet]];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Controllers/MLKResultListViewController.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@class MLKResult;\n@class MLKResultListHeaderView;\n@class MDCFlexibleHeaderViewController;\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** View controller showing a list of products. */\n@interface MLKResultListViewController : UICollectionViewController\n\n/**\n * Header of the list, it stays on top of the screen when it expands to the whole screen and\n * contents will be scrolled underneath it.\n */\n@property(nonatomic) MDCFlexibleHeaderViewController *headerViewController;\n\n/** Header view for this panel view. */\n@property(nonatomic) MLKResultListHeaderView *headerView;\n\n/**\n * Initializes and returns a `ProductListViewController` object using the provided product list.\n *\n * @param products List of the products that serves as the model to this view.\n * @return An instance of the `ProductListViewController`.\n */\n- (instancetype)initWithResults:(NSArray<MLKResult *> *)products;\n\n/** Calculates and updates minimum and maximum height for header view. */\n- (void)updateMinMaxHeightForHeaderView;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Controllers/MLKResultListViewController.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKResultListViewController.h\"\n\n#import \"MLKResultListHeaderView.h\"\n#import \"MLKResultCell.h\"\n\n@import MaterialComponents;\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic NSString *const kResultCellReuseIdentifier = @\"ResultCell\";\n\n@interface MLKResultListViewController ()\n\n/** Cell that is used to calculate the height of each row. */\n@property(nonatomic) MLKResultCell *measureCell;\n\n/** Data model for this view. Content of the view is generated from its value. */\n@property(nonatomic) NSArray<MLKResult *> *results;\n\n@end\n\n@implementation MLKResultListViewController\n\n#pragma mark - Public\n\n- (instancetype)initWithResults:(NSArray<MLKResult *> *)results {\n  UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];\n  self = [super initWithCollectionViewLayout:layout];\n  if (self != nil) {\n    _results = [results copy];\n    _measureCell = [[MLKResultCell alloc] init];\n  }\n  return self;\n}\n\n- (void)updateMinMaxHeightForHeaderView {\n  MDCFlexibleHeaderView *flexibleHeaderView = self.headerViewController.headerView;\n  flexibleHeaderView.maximumHeight =\n      [self.headerView maxHeaderHeightForWidth:self.view.bounds.size.width];\n  flexibleHeaderView.minimumHeight =\n      [self.headerView minHeaderHeightForWidth:self.view.bounds.size.width];\n}\n\n#pragma mark - UIViewController\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n\n  self.collectionView.backgroundColor = UIColor.whiteColor;\n\n  // Register cell classes\n  [self.collectionView registerClass:MLKResultCell.class\n          forCellWithReuseIdentifier:kResultCellReuseIdentifier];\n\n  [self addFlexibleHeader];\n}\n\n#pragma mark - UICollectionViewDataSource\n\n- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {\n  return 1;\n}\n\n- (NSInteger)collectionView:(UICollectionView *)collectionView\n     numberOfItemsInSection:(NSInteger)section {\n  return self.results.count;\n}\n\n- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView\n                  cellForItemAtIndexPath:(NSIndexPath *)indexPath {\n  MLKResultCell *cell =\n      [collectionView dequeueReusableCellWithReuseIdentifier:kResultCellReuseIdentifier\n                                                forIndexPath:indexPath];\n  [cell isCellPopulatedWithResult:self.results[indexPath.row]];\n  [cell setNeedsLayout];\n  return cell;\n}\n\n- (CGSize)collectionView:(UICollectionView *)collectionView\n                    layout:(nonnull UICollectionViewLayout *)collectionViewLayout\n    sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {\n  [self.measureCell isCellPopulatedWithResult:self.results[indexPath.row]];\n  CGFloat contentWidth = self.view.frame.size.width - self.collectionView.contentInset.left -\n                         self.collectionView.contentInset.right;\n  return CGSizeMake(contentWidth,\n                    [self.measureCell sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)].height);\n}\n\n#pragma mark - UIScrollViewDelegate\n\n- (void)scrollViewDidScroll:(UIScrollView *)scrollView {\n  if (scrollView == self.headerViewController.headerView.trackingScrollView) {\n    [self.headerViewController.headerView trackingScrollViewDidScroll];\n  }\n}\n\n- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {\n  if (scrollView == self.headerViewController.headerView.trackingScrollView) {\n    [self.headerViewController.headerView trackingScrollViewDidEndDecelerating];\n  }\n}\n\n- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {\n  if (scrollView == self.headerViewController.headerView.trackingScrollView) {\n    [self.headerViewController.headerView\n        trackingScrollViewDidEndDraggingWillDecelerate:decelerate];\n  }\n}\n\n- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView\n                     withVelocity:(CGPoint)velocity\n              targetContentOffset:(inout CGPoint *)targetContentOffset {\n  if (scrollView == self.headerViewController.headerView.trackingScrollView) {\n    [self.headerViewController.headerView\n        trackingScrollViewWillEndDraggingWithVelocity:velocity\n                                  targetContentOffset:targetContentOffset];\n  }\n}\n\n#pragma mark - Private\n\n- (void)addFlexibleHeader {\n  if (self.headerViewController == nil) {\n    self.headerViewController = [[MDCFlexibleHeaderViewController alloc] init];\n  }\n  if (self.headerView == nil) {\n    self.headerView = [[MLKResultListHeaderView alloc] init];\n  }\n  NSString *headerText = [NSString stringWithFormat:@\"%ld search results\", self.results.count];\n  self.headerView.resultLabel.text = headerText;\n  [self updateMinMaxHeightForHeaderView];\n\n  [self.headerViewController willMoveToParentViewController:self];\n  [self addChildViewController:self.headerViewController];\n\n  self.headerView.autoresizingMask =\n      (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);\n\n  MDCFlexibleHeaderView *flexibleHeaderView = self.headerViewController.headerView;\n  flexibleHeaderView.canOverExtend = NO;\n  flexibleHeaderView.trackingScrollView = self.collectionView;\n\n  [flexibleHeaderView addSubview:self.headerView];\n  [self.view addSubview:flexibleHeaderView];\n\n  self.headerView.frame = flexibleHeaderView.bounds;\n  flexibleHeaderView.frame = self.view.bounds;\n\n  [self.headerViewController didMoveToParentViewController:self];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Controllers/MLKStartPageViewController.h",
    "content": "/**\n* Copyright 2020 Google ML Kit team\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*     https://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n#import <UIKit/UIKit.h>\n\n@class MDCFlexibleHeaderViewController;\n@class MLKStartPageHeaderView;\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** An enum for the type of showcase app. */\ntypedef NS_ENUM(NSInteger, MLKDetectorType) {\n  // Object Detection and Tracking showcase app with default model.\n  MLKDetectorTypeODTDefaultModel = 0,\n  // Object Detection and Tracking showcase app with bird model.\n  MLKDetectorTypeODTBirdModel,\n  // Total count of this enum value.\n  MLKDetectorTypeCount,\n};\n\n@interface MLKStartPageViewController : UICollectionViewController\n\n/** Header of the list, it stays on top of the list and contents will be scrolled underneath it. */\n@property(nonatomic) MDCFlexibleHeaderViewController *headerViewController;\n\n/** Header view for the list. */\n@property(nonatomic) MLKStartPageHeaderView *headerView;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Controllers/MLKStartPageViewController.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKStartPageViewController.h\"\n\n#import \"MLKLiveObjectDetectionViewController.h\"\n#import \"MLKStartPageHeaderView.h\"\n#import \"MLKStartPageCell.h\"\n\n@import MaterialComponents;\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic NSString *const kStartPageCellReuseIdentifier = @\"ShowcaseItemCell\";\n\n@interface MLKStartPageViewController ()<MLKLiveObjectDetectionViewControllerDelegate>\n\n/** Cell that is used to calculate the height of each row. */\n@property(nonatomic) MLKStartPageCell *measureCell;\n\n@end\n\n@implementation MLKStartPageViewController\n\n#pragma mark - Public\n\n- (instancetype)init {\n  UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];\n  self = [super initWithCollectionViewLayout:layout];\n  if (self != nil) {\n    _measureCell = [[MLKStartPageCell alloc] init];\n  }\n  return self;\n}\n\n- (void)updateMinMaxHeightForHeaderView {\n  MDCFlexibleHeaderView *flexibleHeaderView = self.headerViewController.headerView;\n  flexibleHeaderView.maximumHeight =\n      [self.headerView maxHeaderHeightForWidth:self.view.bounds.size.width];\n  flexibleHeaderView.minimumHeight =\n      [self.headerView minHeaderHeightForWidth:self.view.bounds.size.width];\n}\n\n#pragma mark - UIViewController\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n\n  self.collectionView.backgroundColor = UIColor.blackColor;\n  // Register cell classes\n  [self.collectionView registerClass:MLKStartPageCell.class\n          forCellWithReuseIdentifier:kStartPageCellReuseIdentifier];\n\n  [self addFlexibleHeader];\n}\n\n#pragma mark - UICollectionViewDataSource\n\n- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {\n  return 1;\n}\n\n- (NSInteger)collectionView:(UICollectionView *)collectionView\n     numberOfItemsInSection:(NSInteger)section {\n  return MLKDetectorTypeCount;\n}\n\n- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView\n                  cellForItemAtIndexPath:(NSIndexPath *)indexPath {\n  MLKStartPageCell *cell =\n      [collectionView dequeueReusableCellWithReuseIdentifier:kStartPageCellReuseIdentifier\n                                                forIndexPath:indexPath];\n  [cell isCellPopulatedWithName:[self nameForRowIndex:indexPath.row]\n                        details:[self detailsForRowIndex:indexPath.row]];\n  [cell setNeedsLayout];\n  return cell;\n}\n\n- (CGSize)collectionView:(UICollectionView *)collectionView\n                    layout:(nonnull UICollectionViewLayout *)collectionViewLayout\n    sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {\n  [self.measureCell isCellPopulatedWithName:[self nameForRowIndex:indexPath.row]\n                                    details:[self detailsForRowIndex:indexPath.row]];\n  CGFloat contentWidth = self.view.frame.size.width - self.collectionView.contentInset.left -\n                         self.collectionView.contentInset.right;\n  return CGSizeMake(contentWidth,\n                    [self.measureCell sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)].height);\n}\n\n  - (void)collectionView:(UICollectionView *)collectionView\ndidSelectItemAtIndexPath:(NSIndexPath *)indexPath {\n    MLKLiveObjectDetectionViewController *liveViewController = [[MLKLiveObjectDetectionViewController alloc] initWithDetectorType:indexPath.row];\n    liveViewController.modalPresentationStyle = UIModalPresentationFullScreen;\n    [self presentViewController:liveViewController animated:YES completion:nil];\n    liveViewController.delegate = self;\n  }\n\n#pragma mark - UIScrollViewDelegate\n\n- (void)scrollViewDidScroll:(UIScrollView *)scrollView {\n  if (scrollView == self.headerViewController.headerView.trackingScrollView) {\n    [self.headerViewController.headerView trackingScrollViewDidScroll];\n  }\n}\n\n- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {\n  if (scrollView == self.headerViewController.headerView.trackingScrollView) {\n    [self.headerViewController.headerView trackingScrollViewDidEndDecelerating];\n  }\n}\n\n- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {\n  if (scrollView == self.headerViewController.headerView.trackingScrollView) {\n    [self.headerViewController.headerView\n        trackingScrollViewDidEndDraggingWillDecelerate:decelerate];\n  }\n}\n\n- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView\n                     withVelocity:(CGPoint)velocity\n              targetContentOffset:(inout CGPoint *)targetContentOffset {\n  if (scrollView == self.headerViewController.headerView.trackingScrollView) {\n    [self.headerViewController.headerView\n        trackingScrollViewWillEndDraggingWithVelocity:velocity\n                                  targetContentOffset:targetContentOffset];\n  }\n}\n\n#pragma mark - Private\n\n- (void)addFlexibleHeader {\n  if (self.headerViewController == nil) {\n    self.headerViewController = [[MDCFlexibleHeaderViewController alloc] init];\n  }\n  if (self.headerView == nil) {\n    self.headerView = [[MLKStartPageHeaderView alloc] init];\n  }\n  NSString *headerText = @\"MLKit Showcase\";\n  self.headerView.titleLabel.text = headerText;\n  [self updateMinMaxHeightForHeaderView];\n\n  [self.headerViewController willMoveToParentViewController:self];\n  [self addChildViewController:self.headerViewController];\n\n  self.headerView.autoresizingMask =\n      (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);\n\n  MDCFlexibleHeaderView *flexibleHeaderView = self.headerViewController.headerView;\n  flexibleHeaderView.canOverExtend = NO;\n  flexibleHeaderView.trackingScrollView = self.collectionView;\n\n  [flexibleHeaderView addSubview:self.headerView];\n  [self.view addSubview:flexibleHeaderView];\n\n  self.headerView.frame = flexibleHeaderView.bounds;\n  flexibleHeaderView.frame = self.view.bounds;\n\n  [self.headerViewController didMoveToParentViewController:self];\n}\n\n/** Returns the name of the item for given index. */\n- (nullable NSString *)nameForRowIndex:(NSInteger)index {\n  static dispatch_once_t onceToken;\n  static NSDictionary<NSNumber *, NSString *>* gShowcaseItemTypeToName;\n  dispatch_once(&onceToken, ^{\n     gShowcaseItemTypeToName = @{\n       @(MLKDetectorTypeODTDefaultModel): @\"Object Detection\",\n       @(MLKDetectorTypeODTBirdModel): @\"Object Detection: Bird\",\n     };\n  });\n  return gShowcaseItemTypeToName[@(index)];\n}\n\n/** Returns the details of the item for given index. */\n- (nullable NSString *)detailsForRowIndex:(NSInteger)index {\n  static dispatch_once_t onceToken;\n  static NSDictionary<NSNumber *, NSString *>* gShowcaseItemTypeToDetails;\n  dispatch_once(&onceToken, ^{\n    gShowcaseItemTypeToDetails = @{\n      @(MLKDetectorTypeODTDefaultModel): @\"Detect objects in the live camera view.\",\n      @(MLKDetectorTypeODTBirdModel): @\"Detect bird in the camera view.\",\n    };\n  });\n  return gShowcaseItemTypeToDetails[@(index)];\n}\n\n#pragma mark - MLKLiveObjectDetectionViewControllerDelegate\n\n- (void)didTapBackButton {\n  [self dismissViewControllerAnimated:YES completion:nil];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"icon_120.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"logo_180.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Images.xcassets/ic_arrow_back_ios.imageset/Contents.json",
    "content": "{\n    \"images\": [\n        {\n            \"filename\": \"ic_arrow_back_ios.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"1x\"\n        },\n        {\n            \"filename\": \"ic_arrow_back_ios_2x.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"2x\"\n        },\n        {\n            \"filename\": \"ic_arrow_back_ios_3x.png\",\n            \"idiom\": \"universal\",\n            \"scale\": \"3x\"\n        }\n    ],\n    \"info\": {\n        \"author\": \"xcode\",\n        \"template-rendering-intent\": \"template\",\n        \"version\": 1\n    }\n}\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>UIStatusBarHidden</key>\n\t<false/>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<false/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>arm64</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string>$(PRODUCT_NAME) showcase</string>\n\t<key>UIBackgroundModes</key>\n\t<array>\n\t\t<string>fetch</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Models/MLKODTStatus.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Object detection statuses. */\ntypedef NS_ENUM(NSInteger, MLKODTStatus) {\n  /** Object detection hasn't started yet. */\n  MLKODTStatus_NotStarted,\n  /** Object detection started detecting on new objects. */\n  MLKODTStatus_Detecting,\n  /** Object detection is confirming on the same object. */\n  MLKODTStatus_Confirming,\n  /** Object detection is searching the detected object. */\n  MLKODTStatus_Searching,\n  /** Object detection has got search results on detected object. */\n  MLKODTStatus_Searched,\n};\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Models/MLKProductSearchRequest.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Request sent for the product search. */\n@interface MLKProductSearchRequest : NSMutableURLRequest\n\n/**\n * Initializes and returns a `ProductSearchRequest` instance with an image to be sent for product\n * search.\n *\n * @param image The image sent for product search.\n * @return An instance of `ProductSearchRequest`.\n */\n- (instancetype)initWithUIImage:(UIImage *)image;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Models/MLKProductSearchRequest.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKProductSearchRequest.h\"\n\n#import \"UIImage+MLKShowcase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n// Key-value pairs in the product search request.\nstatic NSString *const kJSONBodyImageContentKey = @\"content\";\n\nstatic NSString *const kJSONBodyRetailUnitKey = @\"RU\";\nstatic NSString *const kJSONBodyRetailUnitValue = @\"US\";\n\nstatic NSString *const kURLKey = @\"URL\";\nstatic NSString *const kHeaderAcceptTypeKey = @\"Accept\";\n\nstatic NSString *const kHeaderContentTypeKey = @\"Content-Type\";\nstatic NSString *const kHeaderContentTypeValue = @\"application/json\";\n\nstatic NSString *const kHeaderAPIKeyKey = @\"X-IVS-APIKey\";\n\nstatic NSString *const kHTTPMethodPost = @\"POST\";\n\nstatic NSString *const kKeyFileName = @\"key\";\nstatic NSString *const kKeyFileType = @\"plist\";\n\n@interface MLKProductSearchRequest ()\n\n/** Product search backend server information. */\n@property(nonatomic) NSDictionary<NSString *, NSString *> *serverInfo;\n\n@end\n\n@implementation MLKProductSearchRequest\n\n#pragma mark - Public\n\n- (instancetype)initWithUIImage:(UIImage *)image {\n  self = [super initWithURL:[NSURL URLWithString:[self productSearchURL]]];\n  if (self != nil) {\n    super.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;\n    super.HTTPMethod = kHTTPMethodPost;\n\n    // Set body.\n    NSMutableDictionary<NSString *, id> *JSONDictionary = [NSMutableDictionary dictionary];\n    NSString *encodedString = image.mlk_base64EncodedString;\n    JSONDictionary[kJSONBodyImageContentKey] = encodedString;\n    JSONDictionary[kJSONBodyRetailUnitKey] = kJSONBodyRetailUnitValue;\n\n    NSError *JSONError;\n\n    NSData *JSONData = [NSJSONSerialization dataWithJSONObject:JSONDictionary\n                                                       options:0\n                                                         error:&JSONError];\n    if (JSONData == nil) {\n      NSLog(@\"Unable to generate JSONData from JSONDictionary: %@\", JSONError.description);\n    }\n\n    super.HTTPBody = JSONData;\n\n    // Set headers.\n    [self setValue:[self APIKey] forHTTPHeaderField:kHeaderAPIKeyKey];\n    [self setValue:kHeaderContentTypeValue forHTTPHeaderField:kHeaderContentTypeKey];\n    [self setValue:[self acceptType] forHTTPHeaderField:kHeaderAcceptTypeKey];\n  }\n  return self;\n}\n\n#pragma mark - Private\n\n/** API Key from a resource file. */\n- (nullable NSString *)APIKey {\n  return self.serverInfo[kHeaderAPIKeyKey];\n}\n\n/** Product search URL from a resource file. */\n- (nullable NSString *)productSearchURL {\n  return self.serverInfo[kURLKey];\n}\n\n/** `acceptType` from a resource file. */\n- (nullable NSString *)acceptType {\n  return self.serverInfo[kHeaderAcceptTypeKey];\n}\n\n/** Overrides getter of `serverInfo`. */\n- (NSDictionary *)serverInfo {\n  if (_serverInfo == nil) {\n    NSString *serverInfoFileName = [NSBundle.mainBundle pathForResource:kKeyFileName\n                                                                 ofType:kKeyFileType];\n\n    _serverInfo = [[NSDictionary alloc] initWithContentsOfFile:serverInfoFileName];\n  }\n  return _serverInfo;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Models/MLKResult.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <Foundation/Foundation.h>\n\n#import \"MLKLiveObjectDetectionViewController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Model for a product search results. */\n@interface MLKResult : NSObject\n\n@property(nonatomic, copy, nullable) NSString *title;\n@property(nonatomic, copy, nullable) NSString *imageURL;\n@property(nonatomic, nullable) NSNumber *score;\n@property(nonatomic, copy, nullable) NSString *itemNumber;\n@property(nonatomic, copy, nullable) NSString *priceFullText;\n@property(nonatomic, copy, nullable) NSString *details;\n\n/**\n * Generates a list of results from given  search response.\n *\n * @param response The search response.\n * @param type The detector type.\n * @return Generated list of results.\n */\n+ (nullable NSArray<MLKResult *> *)resultsFromResponse:(nullable NSData *)response\n                                       forDetectortype:(MLKDetectorType)type;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Models/MLKResult.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKResult.h\"\n\n// Key for wrapped data in product search response.\nstatic NSString *const kSearchResponseKeyData = @\"data\";\nstatic NSString *const kSearchResponseKeySearchResults = @\"productSearchResults\";\nstatic NSString *const kSearchResponseKeyProducts = @\"products\";\n\n// Key for product properties in product search response.\nstatic NSString *const kProductNameKey = @\"productName\";\nstatic NSString *const kProductScoreKey = @\"score\";\nstatic NSString *const kProductImageURLKey = @\"imageUrl\";\nstatic NSString *const kProductItemNumberKey = @\"itemNo\";\nstatic NSString *const kProductPriceTextKey = @\"priceFullText\";\nstatic NSString *const kProductTypeNameKey = @\"productTypeName\";\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation MLKResult\n\n+ (nullable NSArray<MLKResult *> *)resultsFromResponse:(nullable NSData *)response\n                                       forDetectortype:(MLKDetectorType)type {\n  if (response == nil) {\n    return nil;\n  }\n  NSError *JSONError;\n  NSDictionary<NSObject *, NSData *> *responseJSONObject =\n      [NSJSONSerialization JSONObjectWithData:response options:0 error:&JSONError];\n  if (JSONError != nil) {\n    NSLog(@\"Error in parsing a response: %@\", JSONError);\n    return nil;\n  }\n\n\n  switch (type) {\n    case MLKDetectorTypeODTDefaultModel: {\n      NSData *_Nullable responseData = [responseJSONObject valueForKey:kSearchResponseKeyData];\n      if (responseData == nil || ![responseData isKindOfClass:[NSDictionary class]]) {\n        return nil;\n      }\n      NSDictionary<NSObject *, NSData *> *responseDataDictionary = (NSDictionary *)responseData;\n      NSData *productSearchResultsData =\n          [responseDataDictionary valueForKey:kSearchResponseKeySearchResults];\n\n      if (productSearchResultsData == nil ||\n          ![productSearchResultsData isKindOfClass:[NSDictionary class]]) {\n        return nil;\n      }\n\n      NSArray<NSObject *> *productSearchResultsArray = (NSArray *)(\n          [(NSDictionary *)productSearchResultsData valueForKey:kSearchResponseKeyProducts]);\n      NSMutableArray<MLKResult *> *results =\n          [NSMutableArray arrayWithCapacity:productSearchResultsArray.count];\n      for (NSData *resultData in productSearchResultsArray) {\n        [results addObject:[self productFromData:resultData]];\n      }\n      return results;\n      break;\n    }\n    case MLKDetectorTypeODTBirdModel: {\n      if (JSONError != nil) {\n        NSLog(@\"Error in parsing a response: %@\", JSONError);\n        return nil;\n      }\n      NSDictionary<NSString*,NSDictionary<NSString * , NSDictionary *>*>*body = (NSDictionary<NSString*,NSDictionary<NSString * , NSDictionary *>*>*)responseJSONObject[@\"query\"];\n      NSDictionary<NSString *, NSString *> *values = body[@\"pages\"].allValues[0];\n      NSString *extract = values[@\"extract\"];\n      NSString *title = values[@\"title\"];\n      if (title.length > 0 && ![title isEqual:@\"Null\"]) {\n        MLKResult *result = [[MLKResult alloc] init];\n        result.title = title;\n        result.details = extract;\n        return @[result];\n      }\n      return nil;\n    }\n    default: {\n      return nil;\n    }\n  }\n\n\n}\n\n- (NSString *)description {\n  return [NSString stringWithFormat:@\"Product name: %@, type: %@, price:%@, item Number: %@\",\n                                    self.title, self.details, self.priceFullText,\n                                    self.itemNumber];\n}\n\n#pragma mark - Private\n\n+ (nullable MLKResult *)productFromData:(NSData *)data {\n  if (data == nil || ![data isKindOfClass:NSDictionary.class]) {\n    return nil;\n  }\n  MLKResult *product = [[MLKResult alloc] init];\n  NSDictionary<NSString *, NSString *> *dictionary = (NSDictionary *)data;\n  product.title = dictionary[kProductNameKey];\n  product.score = @(dictionary[kProductScoreKey].doubleValue);\n  product.itemNumber = dictionary[kProductItemNumberKey];\n  product.imageURL = dictionary[kProductImageURLKey];\n  product.priceFullText = dictionary[kProductPriceTextKey];\n  product.details = dictionary[kProductTypeNameKey];\n  return product;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKCameraReticle.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n * A camera reticle that locates at the center of screen and uses ambient ripple to indicate that\n * the system is active but has not detected an object yet.\n */\n@interface MLKCameraReticle : UIView\n\n/** Starts animating the reticle. Does nothing if the reticle is already animating. */\n- (void)startAnimating;\n\n/** Stops animating the reticle. Does nothing if the reticle is not animating. */\n- (void)stopAnimating;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKCameraReticle.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKCameraReticle.h\"\n\n#import <CoreFoundation/CoreFoundation.h>\n#import <QuartzCore/QuartzCore.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n// Layout values.\nstatic const CGFloat kInnerRingRadius = 14.f;\nstatic const CGFloat kInnerRingDiameter = 2.f * kInnerRingRadius;\nstatic const CGFloat kInnerRingLineWidth = 2.f;\n\nstatic const CGFloat kOuterRingRadius = 24.f;\nstatic const CGFloat kOuterRingDiameter = 2.f * kOuterRingRadius;\nstatic const CGFloat kOuterRingLineWidth = 4.f;\nstatic const CGFloat kOuterRingStrokeAlpha = 0.6f;\nstatic const CGFloat kOuterRingFillAlpha = 0.12f;\n\nstatic const CGFloat kRippleRingFinalScale = 2.f;\nstatic const CGFloat kRippleRingFinalLineWidth = 2.f;\nstatic const CFTimeInterval kRippleRingFadeInDuration = 0.333f;\nstatic const CFTimeInterval kRippleRingExpandDuration = 0.833f;\nstatic const CFTimeInterval kRippleRingFadeOutBeginTime = 0.333f;\nstatic const CFTimeInterval kRippleRingFadeOutDuration = 0.5f;\nstatic const CFTimeInterval kHibernationDuration = 1.167f;\n\nstatic NSString *const kOpacityKeyPath = @\"opacity\";\nstatic NSString *const kPathKeyPath = @\"path\";\nstatic NSString *const kPositionKeyPath = @\"position\";\nstatic NSString *const kLineWidthKeyPath = @\"lineWidth\";\n\n/**\n * The reticle consists of 3 rings, an inner ring and an outer ring of fixed size, and an animating\n * ripple ring that can change in opacity, line width, and radius. They all live in their own\n * layers.\n */\n@interface MLKCameraReticle ()\n\n/** Whether the reticle is currently animating. */\n@property(nonatomic) BOOL isAnimating;\n/** The layer hosting the fixed inner ring. */\n@property(nonatomic, readonly) CAShapeLayer *innerRingLayer;\n/** The layer hosting the fixed outer ring. */\n@property(nonatomic, readonly) CAShapeLayer *outerRingLayer;\n/** The layer hosting the animating ripple ring. */\n@property(nonatomic, readonly) CAShapeLayer *rippleRingLayer;\n\n@end\n\n@implementation MLKCameraReticle\n\n#pragma mark - Public\n\n- (instancetype)initWithFrame:(CGRect)frame {\n  self = [super initWithFrame:frame];\n  if (self != nil) {\n    _outerRingLayer = [CAShapeLayer layer];\n    _outerRingLayer.opacity = kOuterRingStrokeAlpha;\n    [self createRingInRect:CGRectMake(0, 0, kOuterRingDiameter, kOuterRingDiameter)\n                     layer:_outerRingLayer\n                 lineWidth:kOuterRingLineWidth\n               strokeColor:UIColor.whiteColor\n                 fillColor:[UIColor.blackColor colorWithAlphaComponent:kOuterRingFillAlpha]];\n    [self.layer addSublayer:_outerRingLayer];\n\n    _rippleRingLayer = [CAShapeLayer layer];\n    _rippleRingLayer.opacity = 0;\n    [self createRingInRect:CGRectMake(0, 0, kOuterRingDiameter, kOuterRingDiameter)\n                     layer:_rippleRingLayer\n                 lineWidth:kOuterRingLineWidth\n               strokeColor:UIColor.whiteColor\n                 fillColor:UIColor.clearColor];\n    [self.layer addSublayer:_rippleRingLayer];\n\n    _innerRingLayer = [CAShapeLayer layer];\n    [self createRingInRect:CGRectMake(0, 0, kInnerRingDiameter, kInnerRingDiameter)\n                     layer:_innerRingLayer\n                 lineWidth:kInnerRingLineWidth\n               strokeColor:UIColor.whiteColor\n                 fillColor:UIColor.clearColor];\n    [self.layer addSublayer:_innerRingLayer];\n  }\n  return self;\n}\n\n- (void)startAnimating {\n  if (self.isAnimating) {\n    return;\n  }\n\n  self.isAnimating = YES;\n  [self fadeInRippleRing];\n}\n\n- (void)stopAnimating {\n  if (!self.isAnimating) {\n    return;\n  }\n  self.isAnimating = NO;\n  [self hibernate];\n}\n\n#pragma mark - UIView(UIViewHierarchy)\n\n- (void)layoutSubviews {\n  [super layoutSubviews];\n  CGFloat centerX = [self centerX];\n  CGFloat centerY = [self centerY];\n  CGRect outerRingRect = CGRectMake(centerX - kOuterRingRadius, centerY - kOuterRingRadius,\n                                    kOuterRingDiameter, kOuterRingDiameter);\n  self.outerRingLayer.frame = outerRingRect;\n  self.outerRingLayer.bounds = outerRingRect;\n  self.outerRingLayer.position = outerRingRect.origin;\n\n  self.rippleRingLayer.frame = outerRingRect;\n  self.rippleRingLayer.bounds = outerRingRect;\n  self.rippleRingLayer.position = outerRingRect.origin;\n\n  CGRect innerRingRect = CGRectMake(centerX - kInnerRingRadius, centerY - kInnerRingRadius,\n                                    kInnerRingDiameter, kInnerRingDiameter);\n  self.innerRingLayer.frame = innerRingRect;\n  self.innerRingLayer.bounds = innerRingRect;\n  self.innerRingLayer.position = innerRingRect.origin;\n}\n\n- (void)setHidden:(BOOL)hidden {\n  [super setHidden:hidden];\n  if (hidden) {\n    [self stopAnimating];\n  } else {\n    [self startAnimating];\n  }\n}\n\n- (void)willMoveToWindow:(nullable UIWindow *)newWindow {\n  [super willMoveToWindow:newWindow];\n  // If the reticle is removed from the window, we should stop animating to avoid chewing up CPU.\n  if (!newWindow) {\n    [self stopAnimating];\n  }\n}\n\n#pragma mark - Private\n\n/**\n * Creates a ring inscribed in the given rectangle with the given line width, stroke color, and\n * fill color.\n *\n * @param rect The rectangle in which to inscribe the ring.\n * @param layer The layer in which to draw the ring.\n * @param lineWidth The line width of the ring.\n * @param strokeColor The color of the ring.\n * @param fillColor The color to fill inside the ring.\n */\n- (void)createRingInRect:(CGRect)rect\n                   layer:(CAShapeLayer *)layer\n               lineWidth:(CGFloat)lineWidth\n             strokeColor:(UIColor *)strokeColor\n               fillColor:(UIColor *)fillColor {\n  layer.path = [UIBezierPath bezierPathWithOvalInRect:rect].CGPath;\n  layer.lineWidth = lineWidth;\n  layer.strokeStart = 0.f;\n  layer.strokeEnd = 1.f;\n  layer.strokeColor = strokeColor.CGColor;\n  layer.fillColor = fillColor.CGColor;\n}\n\n/** Fades in the ripple ring with a linear timing function. */\n- (void)fadeInRippleRing {\n  [CATransaction begin];\n  __weak typeof(self) weakSelf = self;\n  [CATransaction setCompletionBlock:^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf expandRippleRing];\n  }];\n  CABasicAnimation *fadeIn = [[CABasicAnimation alloc] init];\n  fadeIn.keyPath = kOpacityKeyPath;\n  fadeIn.fromValue = @0.f;\n  fadeIn.toValue = @(kOuterRingStrokeAlpha);\n  fadeIn.duration = kRippleRingFadeInDuration;\n  fadeIn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];\n  fadeIn.fillMode = kCAFillModeForwards;\n  fadeIn.removedOnCompletion = NO;\n  [self.rippleRingLayer addAnimation:fadeIn forKey:nil];\n  [CATransaction commit];\n}\n\n/** Expands and fades out the ripple ring while thinning the line width. */\n- (void)expandRippleRing {\n  [CATransaction begin];\n  __weak typeof(self) weakSelf = self;\n  [CATransaction setCompletionBlock:^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf hibernate];\n  }];\n\n  CGRect finalRect = CGRectMake(0, 0, kRippleRingFinalScale * kOuterRingDiameter,\n                                kRippleRingFinalScale * kOuterRingDiameter);\n  CGPathRef finalPath = [UIBezierPath bezierPathWithOvalInRect:finalRect].CGPath;\n  CABasicAnimation *scale = [[CABasicAnimation alloc] init];\n  scale.keyPath = kPathKeyPath;\n  scale.fromValue = (__bridge id _Nullable)(self.rippleRingLayer.path);\n  scale.toValue = (__bridge id _Nullable)(finalPath);\n\n  CABasicAnimation *recenter = [[CABasicAnimation alloc] init];\n  recenter.keyPath = kPositionKeyPath;\n  recenter.fromValue = @(self.rippleRingLayer.position);\n  recenter.toValue =\n      @(CGPointMake([self centerX] - kOuterRingDiameter, [self centerY] - kOuterRingDiameter));\n\n  CABasicAnimation *thin = [[CABasicAnimation alloc] init];\n  thin.keyPath = kLineWidthKeyPath;\n  thin.fromValue = @(kOuterRingLineWidth);\n  thin.toValue = @(kRippleRingFinalLineWidth);\n\n  CABasicAnimation *fadeOut = [[CABasicAnimation alloc] init];\n  fadeOut.keyPath = kOpacityKeyPath;\n  fadeOut.fromValue = @(kOuterRingStrokeAlpha);\n  fadeOut.toValue = @0.f;\n  fadeOut.beginTime = kRippleRingFadeOutBeginTime;\n  fadeOut.duration = kRippleRingFadeOutDuration;\n  fadeOut.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];\n  fadeOut.fillMode = kCAFillModeForwards;\n\n  CAAnimationGroup *expand = [[CAAnimationGroup alloc] init];\n  expand.animations = [[NSArray alloc] initWithObjects:scale, recenter, thin, fadeOut, nil];\n  expand.duration = kRippleRingExpandDuration;\n  // Animation begins and ends with easing.\n  expand.timingFunction = [[CAMediaTimingFunction alloc] initWithControlPoints:0.4f:0.0f:0.2f:1.0f];\n  expand.fillMode = kCAFillModeForwards;\n  expand.removedOnCompletion = NO;\n  [self.rippleRingLayer addAnimation:expand forKey:nil];\n  [CATransaction commit];\n}\n\n/** Hibernates and prepares for the next cycle of animation, or stops the animation upon request. */\n- (void)hibernate {\n  if (!self.isAnimating) {\n    [self.rippleRingLayer removeAllAnimations];\n    return;\n  }\n  [CATransaction begin];\n  __weak typeof(self) weakSelf = self;\n  [CATransaction setCompletionBlock:^{\n    __strong typeof(weakSelf) strongSelf = weakSelf;\n    [strongSelf fadeInRippleRing];\n  }];\n\n  CGRect outerRect = CGRectMake(0, 0, kOuterRingDiameter, kOuterRingDiameter);\n  CGPathRef path = [UIBezierPath bezierPathWithOvalInRect:outerRect].CGPath;\n  CABasicAnimation *scale = [[CABasicAnimation alloc] init];\n  scale.keyPath = kPathKeyPath;\n  scale.fromValue = (__bridge id _Nullable)(self.rippleRingLayer.path);\n  scale.toValue = (__bridge id _Nullable)(path);\n\n  CABasicAnimation *thicken = [[CABasicAnimation alloc] init];\n  thicken.keyPath = kLineWidthKeyPath;\n  thicken.fromValue = @(kRippleRingFinalLineWidth);\n  thicken.toValue = @(kOuterRingLineWidth);\n\n  CABasicAnimation *recenter = [[CABasicAnimation alloc] init];\n  recenter.keyPath = kPositionKeyPath;\n  recenter.fromValue = @(self.rippleRingLayer.position);\n  recenter.toValue =\n      @(CGPointMake([self centerX] - kOuterRingRadius, [self centerY] - kOuterRingRadius));\n\n  CAAnimationGroup *hibernate = [[CAAnimationGroup alloc] init];\n  hibernate.animations = [[NSArray alloc] initWithObjects:scale, recenter, thicken, nil];\n  hibernate.duration = kHibernationDuration;\n  hibernate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];\n  hibernate.fillMode = kCAFillModeForwards;\n  hibernate.removedOnCompletion = NO;\n  [self.rippleRingLayer addAnimation:hibernate forKey:nil];\n\n  [CATransaction commit];\n}\n\n/** Determines whether the main screen is in the portrait mode. */\n- (BOOL)isPortraitMode {\n  CGSize screenSize = UIScreen.mainScreen.bounds.size;\n  return screenSize.height > screenSize.width;\n}\n\n/** Returns the center X coordinate of the main screen. */\n- (CGFloat)centerX {\n  return [self isPortraitMode] ? self.center.x : self.center.y;\n}\n\n/** Returns the center Y coordinate of the main screen. */\n- (CGFloat)centerY {\n  return [self isPortraitMode] ? self.center.y : self.center.x;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKConfirmationSpinner.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <CoreFoundation/CoreFoundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** A progress ring located at the center of the screen for confirming the user intention. */\n@interface MLKConfirmationSpinner : UIView\n\n/** Starts confirming by animating spinner. Does nothing if confirming is already underway. */\n- (void)startConfirming;\n\n/** Stops any pending confirmation and resets the spinner. */\n- (void)reset;\n\n/**\n * Initializes a `MLKConfirmationSpinner` with the given confirming duration.\n *\n * @param duration The duration of the confirming period.\n * @return A new instance of `MLKConfirmationSpinner` with the given confirming duration.\n */\n- (instancetype)initWithDuration:(CFTimeInterval)duration;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKConfirmationSpinner.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKConfirmationSpinner.h\"\n\n#import <CoreFoundation/CoreFoundation.h>\n#import <QuartzCore/QuartzCore.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n// Layout values.\nstatic const CGFloat kInnerRingRadius = 14.f;\nstatic const CGFloat kInnerRingDiameter = 2.f * kInnerRingRadius;\nstatic const CGFloat kInnerRingLineWidth = 2.f;\n\nstatic const CGFloat kOuterRingRadius = 24.f;\nstatic const CGFloat kOuterRingDiameter = 2.f * kOuterRingRadius;\nstatic const CGFloat kOuterRingLineWidth = 4.f;\nstatic const CGFloat kOuterRingStrokeAlpha = 0.6f;\nstatic const CGFloat kOuterRingFillAlpha = 0.12f;\nstatic const CGFloat kSpinnerRingStartAngle = -1.57079632679f;  // -0.5 * pi in radians\nstatic const CGFloat kSpinnerRingEndAngle = 4.71238898038f;     // 1.5 * pi in radians\n\nstatic const CGFloat kStartValueZero = 0.f;\nstatic const CGFloat kEndValueFull = 1.f;\n\nstatic const CFTimeInterval kDefaultConfirmingDuration = 1.5f;\n\nstatic NSString *const kStrokeEndKeyPath = @\"strokeEnd\";\n\n/**\n * The spinner consists of 3 rings, an inner ring and an outer ring of fixed size, and an animating\n * spinner ring that animates. They all live in their own layers.\n */\n@interface MLKConfirmationSpinner ()\n\n/** The duration of the confirming period. */\n@property(nonatomic, readonly) CFTimeInterval duration;\n/** Whether the spinner is currently confirming. */\n@property(nonatomic) BOOL isConfirming;\n/** The layer hosting the fixed inner ring. */\n@property(nonatomic, readonly) CAShapeLayer *innerRingLayer;\n/** The layer hosting the fixed outer ring. */\n@property(nonatomic, readonly) CAShapeLayer *outerRingLayer;\n/** The layer hosting the animating spinner ring. */\n@property(nonatomic, readonly) CAShapeLayer *spinnerRingLayer;\n\n@end\n\n@implementation MLKConfirmationSpinner\n\n#pragma mark - Public\n\n- (instancetype)initWithFrame:(CGRect)frame {\n  self = [super initWithFrame:frame];\n  if (self != nil) {\n    _duration = kDefaultConfirmingDuration;\n    _outerRingLayer = [CAShapeLayer layer];\n    _outerRingLayer.opacity = kOuterRingStrokeAlpha;\n    [self createRingInRect:CGRectMake(0, 0, kOuterRingDiameter, kOuterRingDiameter)\n                     layer:_outerRingLayer\n                 lineWidth:kOuterRingLineWidth\n               strokeColor:UIColor.whiteColor\n                 fillColor:[UIColor.blackColor colorWithAlphaComponent:kOuterRingFillAlpha]];\n    [self.layer addSublayer:_outerRingLayer];\n\n    _spinnerRingLayer = [CAShapeLayer layer];\n    _spinnerRingLayer.opacity = kOuterRingStrokeAlpha;\n    [self.layer addSublayer:_spinnerRingLayer];\n    [self reset];\n\n    _innerRingLayer = [CAShapeLayer layer];\n    [self createRingInRect:CGRectMake(0, 0, kInnerRingDiameter, kInnerRingDiameter)\n                     layer:_innerRingLayer\n                 lineWidth:kInnerRingLineWidth\n               strokeColor:UIColor.whiteColor\n                 fillColor:UIColor.clearColor];\n    [self.layer addSublayer:_innerRingLayer];\n  }\n  return self;\n}\n\n- (instancetype)initWithDuration:(CFTimeInterval)duration {\n  self = [self initWithFrame:CGRectZero];\n  if (self != nil) {\n    _duration = duration;\n  }\n  return self;\n}\n\n- (void)startConfirming {\n  if (self.isConfirming) {\n    return;\n  }\n\n  self.isConfirming = YES;\n  [self startAnimation];\n}\n\n- (void)reset {\n  [self.spinnerRingLayer removeAllAnimations];\n  UIBezierPath *circle =\n      [UIBezierPath bezierPathWithArcCenter:CGPointMake(kOuterRingRadius, kOuterRingRadius)\n                                     radius:kOuterRingRadius\n                                 startAngle:kSpinnerRingStartAngle\n                                   endAngle:kSpinnerRingEndAngle\n                                  clockwise:YES];\n  self.spinnerRingLayer.path = circle.CGPath;\n  self.spinnerRingLayer.lineWidth = kOuterRingLineWidth;\n  self.spinnerRingLayer.strokeStart = kStartValueZero;\n  self.spinnerRingLayer.strokeEnd = kStartValueZero;\n  self.spinnerRingLayer.strokeColor = UIColor.whiteColor.CGColor;\n  self.spinnerRingLayer.fillColor = UIColor.clearColor.CGColor;\n  self.isConfirming = NO;\n}\n\n- (void)setHidden:(BOOL)hidden {\n  [super setHidden:hidden];\n  if (!hidden) {\n    [self startConfirming];\n  } else {\n    [self reset];\n  }\n}\n\n#pragma mark - UIView(UIViewHierarchy)\n\n- (void)layoutSubviews {\n  [super layoutSubviews];\n  CGFloat centerX = [self centerX];\n  CGFloat centerY = [self centerY];\n  CGRect outerRingRect = CGRectMake(centerX - kOuterRingRadius, centerY - kOuterRingRadius,\n                                    kOuterRingDiameter, kOuterRingDiameter);\n  self.outerRingLayer.frame = outerRingRect;\n  self.outerRingLayer.bounds = outerRingRect;\n  self.outerRingLayer.position = outerRingRect.origin;\n\n  self.spinnerRingLayer.frame = outerRingRect;\n  self.spinnerRingLayer.bounds = outerRingRect;\n  self.spinnerRingLayer.position = outerRingRect.origin;\n\n  CGRect innerRingRect = CGRectMake(centerX - kInnerRingRadius, centerY - kInnerRingRadius,\n                                    kInnerRingDiameter, kInnerRingDiameter);\n  self.innerRingLayer.frame = innerRingRect;\n  self.innerRingLayer.bounds = innerRingRect;\n  self.innerRingLayer.position = innerRingRect.origin;\n}\n\n- (void)willMoveToWindow:(nullable UIWindow *)newWindow {\n  [super willMoveToWindow:newWindow];\n  // If the reticle is removed from the window, we should stop animating to avoid chewing up CPU.\n  if (!newWindow) {\n    [self reset];\n  }\n}\n\n#pragma mark - Private\n\n/**\n * Creates a ring inscribed in the given rectangle with the given line width, stroke color, and\n * fill color.\n *\n * @param rect The rectangle in which to inscribe the ring.\n * @param layer The layer in which to draw the ring.\n * @param lineWidth The line width of the ring.\n * @param strokeColor The color of the ring.\n * @param fillColor The color to fill inside the ring.\n */\n- (void)createRingInRect:(CGRect)rect\n                   layer:(CAShapeLayer *)layer\n               lineWidth:(CGFloat)lineWidth\n             strokeColor:(UIColor *)strokeColor\n               fillColor:(UIColor *)fillColor {\n  layer.path = [UIBezierPath bezierPathWithOvalInRect:rect].CGPath;\n  layer.lineWidth = lineWidth;\n  layer.strokeStart = kStartValueZero;\n  layer.strokeEnd = kEndValueFull;\n  layer.strokeColor = strokeColor.CGColor;\n  layer.fillColor = fillColor.CGColor;\n}\n\n/** Fills in the spinner ring with a linear timing function. */\n- (void)startAnimation {\n  [CATransaction begin];\n  CABasicAnimation *fill = [[CABasicAnimation alloc] init];\n  fill.keyPath = kStrokeEndKeyPath;\n  fill.fromValue = @0.0f;\n  fill.toValue = @1.0f;\n  fill.duration = self.duration;\n  fill.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];\n  fill.fillMode = kCAFillModeForwards;\n  fill.removedOnCompletion = NO;\n  [self.spinnerRingLayer addAnimation:fill forKey:nil];\n  [CATransaction commit];\n}\n\n/** Determines whether the main screen is in the portrait mode. */\n- (BOOL)isPortraitMode {\n  CGSize screenSize = UIScreen.mainScreen.bounds.size;\n  return screenSize.height > screenSize.width;\n}\n\n/** Returns the center X coordinate of the main screen. */\n- (CGFloat)centerX {\n  return [self isPortraitMode] ? self.center.x : self.center.y;\n}\n\n/** Returns the center Y coordinate of the main screen. */\n- (CGFloat)centerY {\n  return [self isPortraitMode] ? self.center.y : self.center.x;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKDetectionOverlayView.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Overlay view that shows on top of the object detection window. */\n@interface MLKDetectionOverlayView : UIView\n\n/** Thumbnail image of the result to be searched. */\n@property(nonatomic, readonly) UIImageView *image;\n\n/**\n * Shows a box in the given rect. It also shows a scrim background outside of the box area.\n *\n * @param rect The given area of the box.\n */\n- (void)showBoxInRect:(CGRect)rect;\n\n/**\n * Shows image in the given area of given alpha. It also shows a border around the image as well as\n * a dark background.\n *\n * @param rect The frame of the image.\n * @param alpha The alpha value of the image view.\n */\n- (void)showImageInRect:(CGRect)rect alpha:(CGFloat)alpha;\n\n/** Clears all elements in the view. */\n- (void)hideSubviews;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKDetectionOverlayView.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKDetectionOverlayView.h\"\n\n// Box related values.\nstatic const CGFloat kBoxBorderWidth = 2.0f;\nstatic const CGFloat kImageBorderWidth = 4.0f;\nstatic const CGFloat kBoxBackgroundAlpha = 0.12f;\nstatic const CGFloat kBoxCornerRadius = 12.0f;\n\n// Image related values.\nstatic const CGFloat kImageBackgroundAlpha = 0.6f;\n\nstatic const CGFloat kStrokeStartValueZero = 0.0f;\nstatic const CGFloat kStrokeEndValueOne = 1.0f;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface MLKDetectionOverlayView ()\n\n/** Layer to show a box in the view. */\n@property(nonatomic, readonly) CAShapeLayer *boxLayer;\n\n/** Layer to show a mask outside of the box in the view. */\n@property(nonatomic, readonly) CAShapeLayer *boxMaskLayer;\n\n@end\n\n@implementation MLKDetectionOverlayView\n\n#pragma mark - Public\n\n- (instancetype)initWithFrame:(CGRect)frame {\n  self = [super initWithFrame:frame];\n  if (self != nil) {\n    _boxMaskLayer = [[CAShapeLayer alloc] init];\n    [self.layer addSublayer:_boxMaskLayer];\n\n    _boxLayer = [CAShapeLayer layer];\n    _boxLayer.cornerRadius = kBoxCornerRadius;\n    [self.layer addSublayer:_boxLayer];\n\n    _image = [[UIImageView alloc] init];\n    _image.layer.cornerRadius = kBoxCornerRadius;\n    _image.layer.borderWidth = kImageBorderWidth;\n    _image.layer.masksToBounds = YES;\n    _image.layer.borderColor = UIColor.whiteColor.CGColor;\n    [self addSubview:_image];\n  }\n  return self;\n}\n\n- (void)showBoxInRect:(CGRect)rect {\n  [self.boxMaskLayer setHidden:NO];\n  UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.bounds];\n  UIBezierPath *boxPath =\n      [[UIBezierPath bezierPathWithRoundedRect:rect\n                                  cornerRadius:kBoxCornerRadius] bezierPathByReversingPath];\n  [maskPath appendPath:boxPath];\n\n  self.boxMaskLayer.frame = self.frame;\n  self.boxMaskLayer.path = maskPath.CGPath;\n  self.boxMaskLayer.strokeStart = kStrokeStartValueZero;\n  self.boxMaskLayer.strokeEnd = kStrokeEndValueOne;\n  self.layer.backgroundColor =\n      [UIColor.blackColor colorWithAlphaComponent:kBoxBackgroundAlpha].CGColor;\n  self.layer.mask = self.boxMaskLayer;\n\n  [self.boxLayer setHidden:NO];\n  self.boxLayer.path =\n      [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:kBoxCornerRadius].CGPath;\n  self.boxLayer.lineWidth = kBoxBorderWidth;\n  self.boxLayer.strokeStart = kStrokeStartValueZero;\n  self.boxLayer.strokeEnd = kStrokeEndValueOne;\n  self.boxLayer.strokeColor = UIColor.whiteColor.CGColor;\n  self.boxLayer.fillColor = nil;\n}\n\n- (void)showImageInRect:(CGRect)rect alpha:(CGFloat)alpha {\n  [self.image setHidden:NO];\n  self.image.alpha = alpha;\n  self.image.frame = rect;\n  self.layer.backgroundColor =\n      [UIColor.blackColor colorWithAlphaComponent:kImageBackgroundAlpha].CGColor;\n}\n\n- (void)hideSubviews {\n  [self hideBox];\n  [self hideImage];\n}\n\n#pragma mark - Private\n\n/** Hides box in the view. */\n- (void)hideBox {\n  self.layer.mask = nil;\n  [self.boxMaskLayer setHidden:YES];\n  [self.boxLayer setHidden:YES];\n}\n\n/** Hides image in the view. */\n- (void)hideImage {\n  [self.image setHidden:YES];\n  self.layer.backgroundColor = nil;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKResultCell.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@import MaterialComponents;\n\n@class MLKResult;\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Cell that shows details of a search result. */\n@interface MLKResultCell : MDCBaseCell\n\n/** Thumbnail of the result. */\n@property(nonatomic, readonly) UIImageView *thumbnailImage;\n\n/** Label showing the title of the result. */\n@property(nonatomic, readonly) UILabel *titleLabel;\n\n/** Label showing the details of the results. */\n@property(nonatomic, readonly) UILabel *detailsLabel;\n\n/** Label showing the item number of the result. */\n@property(nonatomic, readonly) UILabel *itemNumberLabel;\n\n/** Label showing the price of the result. */\n@property(nonatomic, readonly) UILabel *priceLabel;\n\n/**\n * Populates the content of the cell with a `Result` model.\n *\n * @param result The result info to populate the cell with.\n * @return YES if product is not nil, otherwise, NO.\n */\n- (BOOL)isCellPopulatedWithResult:(nullable MLKResult *)result;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKResultCell.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKResultCell.h\"\n\n#import \"MLKResult.h\"\n\n@import MaterialComponents;\n@import PINRemoteImage;\n\n/** Layout values. */\nstatic CGFloat const kHorizontalPadding = 16.0f;\nstatic CGFloat const kVerticalPadding = 16.0f;\nstatic CGFloat const kVerticalPaddingSmall = 6.0f;\nstatic CGFloat const kThumbnailSize = 80.0f;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation MLKResultCell {\n  BOOL _hasImage;\n}\n\n#pragma mark - Public\n\n- (instancetype)initWithFrame:(CGRect)frame {\n  self = [super initWithFrame:frame];\n  if (self != nil) {\n    _thumbnailImage = [[UIImageView alloc] init];\n    [self addSubview:_thumbnailImage];\n\n    _titleLabel = [[UILabel alloc] init];\n    _titleLabel.numberOfLines = 0;\n    _titleLabel.font = [[MDCBasicFontScheme alloc] init].subtitle1;\n    [self addSubview:_titleLabel];\n\n    _detailsLabel = [[UILabel alloc] init];\n    _detailsLabel.numberOfLines = 0;\n    _detailsLabel.font = [[MDCBasicFontScheme alloc] init].body2;\n    _detailsLabel.textColor = MDCPalette.greyPalette.tint700;\n    [self addSubview:_detailsLabel];\n\n    _priceLabel = [[UILabel alloc] init];\n    _priceLabel.numberOfLines = 0;\n    _priceLabel.font = [[MDCBasicFontScheme alloc] init].body1;\n    [self addSubview:_priceLabel];\n\n    _itemNumberLabel = [[UILabel alloc] init];\n    _itemNumberLabel.numberOfLines = 0;\n    _itemNumberLabel.font = [[MDCBasicFontScheme alloc] init].body1;\n    [self addSubview:_itemNumberLabel];\n  }\n  return self;\n}\n\n- (BOOL)isCellPopulatedWithResult:(nullable MLKResult *)result {\n  if (result == nil) {\n    return NO;\n  }\n  if (result.imageURL.length > 0) {\n    [self.thumbnailImage pin_setImageFromURL:[NSURL URLWithString: result.imageURL]];\n    _hasImage = YES;\n  }\n  self.titleLabel.text = result.title;\n  self.detailsLabel.text = result.details;\n  self.priceLabel.text = result.priceFullText;\n  self.itemNumberLabel.text = result.itemNumber;\n  return YES;\n}\n\n#pragma mark - UICollectionReusableView\n\n- (void)prepareForReuse {\n  [super prepareForReuse];\n  self.thumbnailImage.image = nil;\n  self.titleLabel.text = nil;\n  self.priceLabel.text = nil;\n  self.detailsLabel.text = nil;\n  self.itemNumberLabel.text = nil;\n}\n\n#pragma mark - UIView\n\n- (void)layoutSubviews {\n  [super layoutSubviews];\n  [self layoutSubviewsForWidth:self.frame.size.width shouldSetFrame:YES];\n}\n\n- (CGSize)sizeThatFits:(CGSize)size {\n  CGFloat width = size.width;\n  CGFloat height = [self layoutSubviewsForWidth:width shouldSetFrame:NO];\n  return CGSizeMake(width, height);\n}\n\n#pragma mark - Private\n\n/**\n * Calculates the height that best fits the specified width for subviews.\n *\n * @param width The available width for the view.\n * @param shouldSetFrame Whether to set frames for subviews.\n *    If it is set to NO, this function will simply measure the space without affecting subviews,\n *    otherwise, subviews will be laid out accordingly.\n * @return The best height of the view that fits the width.\n */\n- (CGFloat)layoutSubviewsForWidth:(CGFloat)width shouldSetFrame:(BOOL)shouldSetFrame {\n  CGFloat contentWidth = width - 2 * kHorizontalPadding;\n\n  CGFloat currentHeight = kVerticalPadding;\n  CGFloat startX = kHorizontalPadding;\n\n  if (_hasImage) {\n    if (shouldSetFrame) {\n      self.thumbnailImage.frame = CGRectMake(startX, currentHeight, kThumbnailSize, kThumbnailSize);\n    }\n    startX += kThumbnailSize + kHorizontalPadding;\n    contentWidth -= kThumbnailSize + kHorizontalPadding;\n  }\n\n  CGSize nameLabelSize = [self.titleLabel sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)];\n  if (shouldSetFrame) {\n    self.titleLabel.frame = CGRectMake(startX, currentHeight, contentWidth, nameLabelSize.height);\n  }\n  currentHeight += nameLabelSize.height + kVerticalPaddingSmall;\n\n  if (self.detailsLabel.text.length > 0) {\n    CGSize detailsLabelSize =\n        [self.detailsLabel sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)];\n    if (shouldSetFrame) {\n      self.detailsLabel.frame =\n          CGRectMake(startX, currentHeight, contentWidth, detailsLabelSize.height);\n    }\n\n    currentHeight += detailsLabelSize.height + kVerticalPadding;\n  }\n\n  if (self.priceLabel.text.length > 0) {\n    CGSize priceLabelSize = [self.priceLabel sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)];\n    if (shouldSetFrame) {\n      self.priceLabel.frame =\n          CGRectMake(startX, currentHeight, priceLabelSize.width, priceLabelSize.height);\n    }\n    currentHeight += priceLabelSize.height + kVerticalPadding;\n  }\n  return _hasImage ? MAX(currentHeight, kThumbnailSize + 2 * kVerticalPadding) : currentHeight;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKResultListHeaderView.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Header view for search results list view. */\n@interface MLKResultListHeaderView : UIView\n\n/** Labels that shows search results number. */\n@property(nonatomic) UILabel *resultLabel;\n\n/** Minimum header height for the given width. */\n- (CGFloat)minHeaderHeightForWidth:(CGFloat)width;\n\n/** Maximum header height for the given width. */\n- (CGFloat)maxHeaderHeightForWidth:(CGFloat)width;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKResultListHeaderView.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKResultListHeaderView.h\"\n\n@import MaterialComponents;\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Layout constants. */\nstatic CGFloat const kHorizontalPadding = 16;\nstatic CGFloat const kVerticalPadding = 16;\n\n@implementation MLKResultListHeaderView\n\n#pragma mark - Public\n\n- (instancetype)initWithFrame:(CGRect)frame {\n  self = [super initWithFrame:frame];\n  if (self != nil) {\n    _resultLabel = [[UILabel alloc] init];\n    _resultLabel.font = [[MDCBasicFontScheme alloc] init].subtitle1;\n    _resultLabel.backgroundColor = UIColor.whiteColor;\n    [self addSubview:_resultLabel];\n\n    self.backgroundColor = UIColor.whiteColor;\n  }\n\n  return self;\n}\n\n- (CGFloat)maxHeaderHeightForWidth:(CGFloat)width {\n  CGSize labelSize =\n      [self.resultLabel sizeThatFits:CGSizeMake(width - 2 * kHorizontalPadding, CGFLOAT_MAX)];\n  return 2 * kVerticalPadding + labelSize.height;\n}\n\n- (CGFloat)minHeaderHeightForWidth:(CGFloat)width {\n  CGSize labelSize =\n      [self.resultLabel sizeThatFits:CGSizeMake(width - 2 * kHorizontalPadding, CGFLOAT_MAX)];\n  return 2 * kVerticalPadding + labelSize.height;\n}\n\n#pragma mark - UIView\n\n- (void)layoutSubviews {\n  [super layoutSubviews];\n  CGFloat currentHeight = self.frame.size.height;\n  CGFloat contentWidth = self.frame.size.width - 2 * kHorizontalPadding;\n  CGSize labelSize = [self.resultLabel sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)];\n  currentHeight -= kVerticalPadding + labelSize.height;\n  self.resultLabel.frame =\n      CGRectMake(kHorizontalPadding, currentHeight, contentWidth, labelSize.height);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKStartPageCell.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n@import MaterialComponents;\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Cell that shows  details of a item on the start page. */\n@interface MLKStartPageCell : MDCBaseCell\n\n/** Label showing the name of the item. */\n@property(nonatomic, readonly) UILabel *nameLabel;\n\n/** Label showing the details of the item. */\n@property(nonatomic, readonly) UILabel *detailLabel;\n\n/** Separator line that lives at the bottom of each cell. */\n@property(nonatomic, readonly) UIView *separator;\n\n/**\n * Populates the content of the cell with `name` and `details`.\n *\n * @param name The name of the item;\n * @param details The details of the item;\n * @return YES if populated successfully, otherwise, NO.\n */\n- (BOOL)isCellPopulatedWithName:(nullable NSString *)name\n                        details:(nullable NSString*)details;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKStartPageCell.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKStartPageCell.h\"\n\n@import MaterialComponents;\n\n/** Layout values. */\nstatic CGFloat const kHorizontalPadding = 16.0f;\nstatic CGFloat const kVerticalPadding = 16.0f;\nstatic CGFloat const kVerticalPaddingSmall = 6.0f;\nstatic CGFloat const kSeparatorHeight = 1.0f;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation MLKStartPageCell\n\n#pragma mark - Public\n\n- (instancetype)initWithFrame:(CGRect)frame {\n  self = [super initWithFrame:frame];\n  if (self != nil) {\n    self.backgroundColor = UIColor.blackColor;\n\n    _nameLabel = [[UILabel alloc] init];\n    _nameLabel.numberOfLines = 0;\n    _nameLabel.backgroundColor = UIColor.blackColor;\n    _nameLabel.textColor = MDCPalette.greyPalette.tint200;\n    _nameLabel.font = [[MDCBasicFontScheme alloc] init].headline1;\n    [self addSubview:_nameLabel];\n\n    _detailLabel = [[UILabel alloc] init];\n    _detailLabel.numberOfLines = 0;\n    _detailLabel.backgroundColor = UIColor.blackColor;\n    _detailLabel.font = [[MDCBasicFontScheme alloc] init].body2;\n    _detailLabel.textColor = MDCPalette.greyPalette.tint600;\n    [self addSubview:_detailLabel];\n\n    _separator = [[UIView alloc] init];\n    _separator.backgroundColor = MDCPalette.greyPalette.tint200;\n    [self addSubview:_separator];\n  }\n  return self;\n}\n\n- (BOOL)isCellPopulatedWithName:(nullable NSString *)name\n                        details:(nullable NSString*)details {\n  if (name.length == 0 && details.length == 0) {\n    return NO;\n  }\n  self.nameLabel.text = name;\n  self.detailLabel.text = details;\n  return YES;\n}\n\n#pragma mark - UICollectionReusableView\n\n- (void)prepareForReuse {\n  [super prepareForReuse];\n  self.nameLabel.text = nil;\n  self.detailLabel.text = nil;\n}\n\n#pragma mark - UIView\n\n- (void)layoutSubviews {\n  [super layoutSubviews];\n  [self layoutSubviewsForWidth:self.frame.size.width shouldSetFrame:YES];\n}\n\n- (CGSize)sizeThatFits:(CGSize)size {\n  CGFloat width = self.frame.size.width;\n  CGFloat height = [self layoutSubviewsForWidth:width shouldSetFrame:NO];\n  return CGSizeMake(width, height);\n}\n\n#pragma mark - Private\n\n/**\n * Calculates the height that best fits the specified width for subviews.\n *\n * @param width The available width for the view.\n * @param shouldSetFrame Whether to set frames for subviews.\n *    If it is set to NO, this function will simply measure the space without affecting subviews,\n *    otherwise, subviews will be laid out accordingly.\n * @return The best height of the view that fits the width.\n */\n- (CGFloat)layoutSubviewsForWidth:(CGFloat)width shouldSetFrame:(BOOL)shouldSetFrame {\n  CGFloat contentWidth = width - 2 * kHorizontalPadding;\n\n  CGFloat currentHeight = kVerticalPadding;\n  CGFloat startX = kHorizontalPadding;\n\n  CGSize nameLabelSize = [self.nameLabel sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)];\n  if (shouldSetFrame) {\n    self.nameLabel.frame = CGRectMake(startX, currentHeight, contentWidth, nameLabelSize.height);\n  }\n  currentHeight += nameLabelSize.height + kVerticalPaddingSmall;\n\n  CGSize detailLabelSize =\n      [self.detailLabel sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)];\n  if (shouldSetFrame) {\n    self.detailLabel.frame =\n        CGRectMake(startX, currentHeight, contentWidth, detailLabelSize.height);\n  }\n\n  currentHeight += detailLabelSize.height + kVerticalPadding;\n\n  if (shouldSetFrame) {\n    self.separator.frame = CGRectMake(startX,\n                                      currentHeight,\n                                      contentWidth,\n                                      kSeparatorHeight);\n  }\n  currentHeight += kSeparatorHeight;\n  return currentHeight;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKStartPageHeaderView.h",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Header view for start page view. */\n@interface MLKStartPageHeaderView : UIView\n\n/** Labels that shows the title of the start page. */\n@property(nonatomic) UILabel *titleLabel;\n\n/** Minimum header height for the given width. */\n- (CGFloat)minHeaderHeightForWidth:(CGFloat)width;\n\n/** Maximum header height for the given width. */\n- (CGFloat)maxHeaderHeightForWidth:(CGFloat)width;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/Views/MLKStartPageHeaderView.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import \"MLKStartPageHeaderView.h\"\n\n@import MaterialComponents;\n\nNS_ASSUME_NONNULL_BEGIN\n\n/** Layout constants. */\nstatic CGFloat const kHorizontalPadding = 32;\nstatic CGFloat const kVerticalPadding = 48;\n\n@implementation MLKStartPageHeaderView\n\n#pragma mark - Public\n\n- (instancetype)initWithFrame:(CGRect)frame {\n  self = [super initWithFrame:frame];\n  if (self != nil) {\n    _titleLabel = [[UILabel alloc] init];\n    _titleLabel.font = [[MDCBasicFontScheme alloc] init].headline3;\n    _titleLabel.textColor = UIColor.whiteColor;\n    _titleLabel.backgroundColor = UIColor.blackColor;\n    [self addSubview:_titleLabel];\n\n    self.backgroundColor = UIColor.blackColor;\n  }\n\n  return self;\n}\n\n- (CGFloat)maxHeaderHeightForWidth:(CGFloat)width {\n  CGSize labelSize =\n      [self.titleLabel sizeThatFits:CGSizeMake(width - 2 * kHorizontalPadding, CGFLOAT_MAX)];\n  return 2 * kVerticalPadding + labelSize.height;\n}\n\n- (CGFloat)minHeaderHeightForWidth:(CGFloat)width {\n  CGSize labelSize =\n      [self.titleLabel sizeThatFits:CGSizeMake(width - 2 * kHorizontalPadding, CGFLOAT_MAX)];\n  return 2 * kVerticalPadding + labelSize.height;\n}\n\n#pragma mark - UIView\n\n- (void)layoutSubviews {\n  [super layoutSubviews];\n  CGFloat currentHeight = self.frame.size.height;\n  CGFloat contentWidth = self.frame.size.width - 2 * kHorizontalPadding;\n  CGSize labelSize = [self.titleLabel sizeThatFits:CGSizeMake(contentWidth, CGFLOAT_MAX)];\n  CGFloat startX = (self.frame.size.width - labelSize.width) / 2.0f;\n  currentHeight -= kVerticalPadding + labelSize.height;\n  self.titleLabel.frame = CGRectMake(startX, currentHeight, contentWidth, labelSize.height);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp/main.m",
    "content": "/**\n * Copyright 2020 Google ML Kit team\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#import <UIKit/UIKit.h>\n\n#import \"AppDelegate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nint main(int argc, char* _Nonnull argv[]) {\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "ios/showcase/vision-showcase/ShowcaseApp.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1B29147C227A54EB009B5E23 /* MLKDetectionOverlayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B29147A227A54EA009B5E23 /* MLKDetectionOverlayView.m */; };\n\t\t1B291481227A54F4009B5E23 /* MLKResultListHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B29147D227A54F2009B5E23 /* MLKResultListHeaderView.m */; };\n\t\t1B291482227A54F4009B5E23 /* MLKResultCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B29147E227A54F2009B5E23 /* MLKResultCell.m */; };\n\t\t1B291485227A551B009B5E23 /* MLKImageUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B291483227A551A009B5E23 /* MLKImageUtilities.m */; };\n\t\t1B29148C227A5554009B5E23 /* MLKResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B291487227A5552009B5E23 /* MLKResult.m */; };\n\t\t1B29148D227A5554009B5E23 /* MLKProductSearchRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B29148A227A5553009B5E23 /* MLKProductSearchRequest.m */; };\n\t\t1B291490227A5E4A009B5E23 /* MLKResultListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B29148F227A5E4A009B5E23 /* MLKResultListViewController.m */; };\n\t\t1B5AC8E3246340A2009BDAED /* MLKStartPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B5AC8E2246340A2009BDAED /* MLKStartPageViewController.m */; };\n\t\t1B5AC8E924634F7E009BDAED /* MLKStartPageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B5AC8E824634F7E009BDAED /* MLKStartPageCell.m */; };\n\t\t1B5AC8EC246355DF009BDAED /* MLKStartPageHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B5AC8EB246355DF009BDAED /* MLKStartPageHeaderView.m */; };\n\t\t1BEE5C182450C1B100C18F44 /* bird.tflite in Resources */ = {isa = PBXBuildFile; fileRef = 1BEE5C172450C1B000C18F44 /* bird.tflite */; };\n\t\tAA10D303226F745E0057608A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AA10D302226F745E0057608A /* AppDelegate.m */; };\n\t\tAA10D311226F74610057608A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = AA10D310226F74610057608A /* main.m */; };\n\t\tAA10D33D226F7C930057608A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = AA10D33B226F7C930057608A /* LaunchScreen.xib */; };\n\t\tAA10D341226F7D260057608A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AA10D340226F7D260057608A /* Images.xcassets */; };\n\t\tAA10D353226F7F880057608A /* MLKLiveObjectDetectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AA10D344226F7F860057608A /* MLKLiveObjectDetectionViewController.m */; };\n\t\tAA10D354226F7F880057608A /* MLKCameraReticle.m in Sources */ = {isa = PBXBuildFile; fileRef = AA10D347226F7F870057608A /* MLKCameraReticle.m */; };\n\t\tAA10D355226F7F880057608A /* MLKConfirmationSpinner.m in Sources */ = {isa = PBXBuildFile; fileRef = AA10D349226F7F870057608A /* MLKConfirmationSpinner.m */; };\n\t\tAA10D358226F7F880057608A /* UIImage+MLKShowcase.m in Sources */ = {isa = PBXBuildFile; fileRef = AA10D350226F7F870057608A /* UIImage+MLKShowcase.m */; };\n\t\tAA10D35C226F83FE0057608A /* MLKUIUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = AA10D35B226F83FE0057608A /* MLKUIUtilities.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t1B29147A227A54EA009B5E23 /* MLKDetectionOverlayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKDetectionOverlayView.m; sourceTree = \"<group>\"; };\n\t\t1B29147B227A54EA009B5E23 /* MLKDetectionOverlayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKDetectionOverlayView.h; sourceTree = \"<group>\"; };\n\t\t1B29147D227A54F2009B5E23 /* MLKResultListHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKResultListHeaderView.m; sourceTree = \"<group>\"; };\n\t\t1B29147E227A54F2009B5E23 /* MLKResultCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKResultCell.m; sourceTree = \"<group>\"; };\n\t\t1B29147F227A54F3009B5E23 /* MLKResultCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKResultCell.h; sourceTree = \"<group>\"; };\n\t\t1B291480227A54F3009B5E23 /* MLKResultListHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKResultListHeaderView.h; sourceTree = \"<group>\"; };\n\t\t1B291483227A551A009B5E23 /* MLKImageUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKImageUtilities.m; sourceTree = \"<group>\"; };\n\t\t1B291484227A551B009B5E23 /* MLKImageUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKImageUtilities.h; sourceTree = \"<group>\"; };\n\t\t1B291487227A5552009B5E23 /* MLKResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MLKResult.m; path = Models/MLKResult.m; sourceTree = \"<group>\"; };\n\t\t1B291488227A5552009B5E23 /* MLKResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MLKResult.h; path = Models/MLKResult.h; sourceTree = \"<group>\"; };\n\t\t1B291489227A5553009B5E23 /* MLKProductSearchRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MLKProductSearchRequest.h; path = Models/MLKProductSearchRequest.h; sourceTree = \"<group>\"; };\n\t\t1B29148A227A5553009B5E23 /* MLKProductSearchRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MLKProductSearchRequest.m; path = Models/MLKProductSearchRequest.m; sourceTree = \"<group>\"; };\n\t\t1B29148B227A5553009B5E23 /* MLKODTStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MLKODTStatus.h; path = Models/MLKODTStatus.h; sourceTree = \"<group>\"; };\n\t\t1B29148E227A5E49009B5E23 /* MLKResultListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKResultListViewController.h; sourceTree = \"<group>\"; };\n\t\t1B29148F227A5E4A009B5E23 /* MLKResultListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKResultListViewController.m; sourceTree = \"<group>\"; };\n\t\t1B5AC8E1246340A2009BDAED /* MLKStartPageViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MLKStartPageViewController.h; sourceTree = \"<group>\"; };\n\t\t1B5AC8E2246340A2009BDAED /* MLKStartPageViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MLKStartPageViewController.m; sourceTree = \"<group>\"; };\n\t\t1B5AC8E724634F7D009BDAED /* MLKStartPageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MLKStartPageCell.h; sourceTree = \"<group>\"; };\n\t\t1B5AC8E824634F7E009BDAED /* MLKStartPageCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MLKStartPageCell.m; sourceTree = \"<group>\"; };\n\t\t1B5AC8EA246355DF009BDAED /* MLKStartPageHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MLKStartPageHeaderView.h; sourceTree = \"<group>\"; };\n\t\t1B5AC8EB246355DF009BDAED /* MLKStartPageHeaderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MLKStartPageHeaderView.m; sourceTree = \"<group>\"; };\n\t\t1BEE5C172450C1B000C18F44 /* bird.tflite */ = {isa = PBXFileReference; lastKnownFileType = file; path = bird.tflite; sourceTree = \"<group>\"; };\n\t\tAA10D2FE226F745E0057608A /* ShowcaseApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShowcaseApp.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tAA10D301226F745E0057608A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\tAA10D302226F745E0057608A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\tAA10D30F226F74610057608A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tAA10D310226F74610057608A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tAA10D33C226F7C930057608A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = \"<group>\"; };\n\t\tAA10D340226F7D260057608A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = \"<group>\"; };\n\t\tAA10D343226F7F860057608A /* MLKLiveObjectDetectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKLiveObjectDetectionViewController.h; sourceTree = \"<group>\"; };\n\t\tAA10D344226F7F860057608A /* MLKLiveObjectDetectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKLiveObjectDetectionViewController.m; sourceTree = \"<group>\"; };\n\t\tAA10D346226F7F870057608A /* MLKCameraReticle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKCameraReticle.h; sourceTree = \"<group>\"; };\n\t\tAA10D347226F7F870057608A /* MLKCameraReticle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKCameraReticle.m; sourceTree = \"<group>\"; };\n\t\tAA10D348226F7F870057608A /* MLKConfirmationSpinner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKConfirmationSpinner.h; sourceTree = \"<group>\"; };\n\t\tAA10D349226F7F870057608A /* MLKConfirmationSpinner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKConfirmationSpinner.m; sourceTree = \"<group>\"; };\n\t\tAA10D34F226F7F870057608A /* UIImage+MLKShowcase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"UIImage+MLKShowcase.h\"; sourceTree = \"<group>\"; };\n\t\tAA10D350226F7F870057608A /* UIImage+MLKShowcase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"UIImage+MLKShowcase.m\"; sourceTree = \"<group>\"; };\n\t\tAA10D35A226F83FD0057608A /* MLKUIUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLKUIUtilities.h; sourceTree = \"<group>\"; };\n\t\tAA10D35B226F83FE0057608A /* MLKUIUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLKUIUtilities.m; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tAA10D2FB226F745E0057608A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t1B291486227A5533009B5E23 /* Models */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1B29148B227A5553009B5E23 /* MLKODTStatus.h */,\n\t\t\t\t1B291488227A5552009B5E23 /* MLKResult.h */,\n\t\t\t\t1B291487227A5552009B5E23 /* MLKResult.m */,\n\t\t\t\t1B291489227A5553009B5E23 /* MLKProductSearchRequest.h */,\n\t\t\t\t1B29148A227A5553009B5E23 /* MLKProductSearchRequest.m */,\n\t\t\t);\n\t\t\tname = Models;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA10D2F5226F745E0057608A = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA10D300226F745E0057608A /* ShowcaseApp */,\n\t\t\t\tAA10D2FF226F745E0057608A /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA10D2FF226F745E0057608A /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA10D2FE226F745E0057608A /* ShowcaseApp.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA10D300226F745E0057608A /* ShowcaseApp */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA10D301226F745E0057608A /* AppDelegate.h */,\n\t\t\t\tAA10D302226F745E0057608A /* AppDelegate.m */,\n\t\t\t\t1B291486227A5533009B5E23 /* Models */,\n\t\t\t\tAA10D34A226F7F870057608A /* Common */,\n\t\t\t\tAA10D342226F7F860057608A /* Controllers */,\n\t\t\t\tAA10D345226F7F870057608A /* Views */,\n\t\t\t\tAA10D30F226F74610057608A /* Info.plist */,\n\t\t\t\tAA10D33B226F7C930057608A /* LaunchScreen.xib */,\n\t\t\t\tAA10D340226F7D260057608A /* Images.xcassets */,\n\t\t\t\t1BEE5C172450C1B000C18F44 /* bird.tflite */,\n\t\t\t\tAA10D310226F74610057608A /* main.m */,\n\t\t\t);\n\t\t\tpath = ShowcaseApp;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA10D342226F7F860057608A /* Controllers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1B29148E227A5E49009B5E23 /* MLKResultListViewController.h */,\n\t\t\t\t1B29148F227A5E4A009B5E23 /* MLKResultListViewController.m */,\n\t\t\t\tAA10D343226F7F860057608A /* MLKLiveObjectDetectionViewController.h */,\n\t\t\t\tAA10D344226F7F860057608A /* MLKLiveObjectDetectionViewController.m */,\n\t\t\t\t1B5AC8E1246340A2009BDAED /* MLKStartPageViewController.h */,\n\t\t\t\t1B5AC8E2246340A2009BDAED /* MLKStartPageViewController.m */,\n\t\t\t);\n\t\t\tpath = Controllers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA10D345226F7F870057608A /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1B291480227A54F3009B5E23 /* MLKResultListHeaderView.h */,\n\t\t\t\t1B29147D227A54F2009B5E23 /* MLKResultListHeaderView.m */,\n\t\t\t\t1B29147F227A54F3009B5E23 /* MLKResultCell.h */,\n\t\t\t\t1B29147E227A54F2009B5E23 /* MLKResultCell.m */,\n\t\t\t\t1B5AC8EA246355DF009BDAED /* MLKStartPageHeaderView.h */,\n\t\t\t\t1B5AC8EB246355DF009BDAED /* MLKStartPageHeaderView.m */,\n\t\t\t\t1B5AC8E724634F7D009BDAED /* MLKStartPageCell.h */,\n\t\t\t\t1B5AC8E824634F7E009BDAED /* MLKStartPageCell.m */,\n\t\t\t\t1B29147B227A54EA009B5E23 /* MLKDetectionOverlayView.h */,\n\t\t\t\t1B29147A227A54EA009B5E23 /* MLKDetectionOverlayView.m */,\n\t\t\t\tAA10D346226F7F870057608A /* MLKCameraReticle.h */,\n\t\t\t\tAA10D347226F7F870057608A /* MLKCameraReticle.m */,\n\t\t\t\tAA10D348226F7F870057608A /* MLKConfirmationSpinner.h */,\n\t\t\t\tAA10D349226F7F870057608A /* MLKConfirmationSpinner.m */,\n\t\t\t);\n\t\t\tpath = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA10D34A226F7F870057608A /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1B291484227A551B009B5E23 /* MLKImageUtilities.h */,\n\t\t\t\t1B291483227A551A009B5E23 /* MLKImageUtilities.m */,\n\t\t\t\tAA10D34F226F7F870057608A /* UIImage+MLKShowcase.h */,\n\t\t\t\tAA10D350226F7F870057608A /* UIImage+MLKShowcase.m */,\n\t\t\t\tAA10D35A226F83FD0057608A /* MLKUIUtilities.h */,\n\t\t\t\tAA10D35B226F83FE0057608A /* MLKUIUtilities.m */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tAA10D2FD226F745E0057608A /* ShowcaseApp */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = AA10D314226F74610057608A /* Build configuration list for PBXNativeTarget \"ShowcaseApp\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tAA10D2FA226F745E0057608A /* Sources */,\n\t\t\t\tAA10D2FB226F745E0057608A /* Frameworks */,\n\t\t\t\tAA10D2FC226F745E0057608A /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = ShowcaseApp;\n\t\t\tproductName = ShowcaseApp;\n\t\t\tproductReference = AA10D2FE226F745E0057608A /* ShowcaseApp.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tAA10D2F6226F745E0057608A /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0940;\n\t\t\t\tORGANIZATIONNAME = \"Google Inc\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tAA10D2FD226F745E0057608A = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.4.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = AA10D2F9226F745E0057608A /* Build configuration list for PBXProject \"ShowcaseApp\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = AA10D2F5226F745E0057608A;\n\t\t\tproductRefGroup = AA10D2FF226F745E0057608A /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tAA10D2FD226F745E0057608A /* ShowcaseApp */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tAA10D2FC226F745E0057608A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tAA10D33D226F7C930057608A /* LaunchScreen.xib in Resources */,\n\t\t\t\t1BEE5C182450C1B100C18F44 /* bird.tflite in Resources */,\n\t\t\t\tAA10D341226F7D260057608A /* Images.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tAA10D2FA226F745E0057608A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1B5AC8E3246340A2009BDAED /* MLKStartPageViewController.m in Sources */,\n\t\t\t\t1B291485227A551B009B5E23 /* MLKImageUtilities.m in Sources */,\n\t\t\t\tAA10D355226F7F880057608A /* MLKConfirmationSpinner.m in Sources */,\n\t\t\t\t1B29147C227A54EB009B5E23 /* MLKDetectionOverlayView.m in Sources */,\n\t\t\t\tAA10D311226F74610057608A /* main.m in Sources */,\n\t\t\t\t1B291490227A5E4A009B5E23 /* MLKResultListViewController.m in Sources */,\n\t\t\t\t1B29148D227A5554009B5E23 /* MLKProductSearchRequest.m in Sources */,\n\t\t\t\tAA10D358226F7F880057608A /* UIImage+MLKShowcase.m in Sources */,\n\t\t\t\t1B29148C227A5554009B5E23 /* MLKResult.m in Sources */,\n\t\t\t\t1B291482227A54F4009B5E23 /* MLKResultCell.m in Sources */,\n\t\t\t\tAA10D303226F745E0057608A /* AppDelegate.m in Sources */,\n\t\t\t\tAA10D353226F7F880057608A /* MLKLiveObjectDetectionViewController.m in Sources */,\n\t\t\t\t1B5AC8E924634F7E009BDAED /* MLKStartPageCell.m in Sources */,\n\t\t\t\tAA10D35C226F83FE0057608A /* MLKUIUtilities.m in Sources */,\n\t\t\t\t1B5AC8EC246355DF009BDAED /* MLKStartPageHeaderView.m in Sources */,\n\t\t\t\tAA10D354226F7F880057608A /* MLKCameraReticle.m in Sources */,\n\t\t\t\t1B291481227A54F4009B5E23 /* MLKResultListHeaderView.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tAA10D33B226F7C930057608A /* LaunchScreen.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tAA10D33C226F7C930057608A /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tAA10D312226F74610057608A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tAA10D313226F74610057608A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tAA10D315226F74610057608A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = ShowcaseApp/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.sampleapp.showcase;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tAA10D316226F74610057608A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = ShowcaseApp/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.google.mlkit.sampleapp.showcase;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tAA10D2F9226F745E0057608A /* Build configuration list for PBXProject \"ShowcaseApp\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tAA10D312226F74610057608A /* Debug */,\n\t\t\t\tAA10D313226F74610057608A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tAA10D314226F74610057608A /* Build configuration list for PBXNativeTarget \"ShowcaseApp\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tAA10D315226F74610057608A /* Debug */,\n\t\t\t\tAA10D316226F74610057608A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = AA10D2F6226F745E0057608A /* Project object */;\n}\n"
  },
  {
    "path": "tutorials/README.md",
    "content": "# ML Kit / TFLite Tutorials\n\nThis is a collection of runnable tutorials hosted on Colaboratory. Colaboratory is a hosted Jupyter notebook environment that’s easy to use and requires no setup.\n\n**[ML Kit Image Labeling Model Maker](https://colab.sandbox.google.com/github/googlesamples/mlkit/blob/master/tutorials/mlkit_image_labeling_model_maker.ipynb)** - Follow this Colab to learn how to use an Image Labeling model with TFLite ModelMaker. The TFLite Model Maker library simplifies the process of adapting and converting a TensorFlow neural-network model to a model suitable for on-device ML applications.\n\n## How to make contributions?\nPlease read and follow the steps in the [CONTRIBUTING.md](CONTRIBUTING.md)\n"
  },
  {
    "path": "tutorials/mlkit_image_labeling_model_maker.ipynb",
    "content": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"accelerator\": \"GPU\",\n    \"colab\": {\n      \"name\": \"mlkit_image_labeling_model_maker.ipynb\",\n      \"provenance\": [],\n      \"private_outputs\": true,\n      \"collapsed_sections\": [],\n      \"toc_visible\": true\n    },\n    \"kernelspec\": {\n      \"display_name\": \"Python 3\",\n      \"language\": \"python\",\n      \"name\": \"python3\"\n    },\n    \"language_info\": {\n      \"codemirror_mode\": {\n        \"name\": \"ipython\",\n        \"version\": 3\n      },\n      \"file_extension\": \".py\",\n      \"mimetype\": \"text/x-python\",\n      \"name\": \"python\",\n      \"nbconvert_exporter\": \"python\",\n      \"pygments_lexer\": \"ipython3\",\n      \"version\": \"3.6.8\"\n    }\n  },\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"h2q27gKz1H20\"\n      },\n      \"source\": [\n        \"##### Copyright 2019 The TensorFlow Authors.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"cellView\": \"form\",\n        \"colab_type\": \"code\",\n        \"id\": \"TUfAcER1oUS6\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"#@title Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\\n\",\n        \"# you may not use this file except in compliance with the License.\\n\",\n        \"# You may obtain a copy of the License at\\n\",\n        \"#\\n\",\n        \"# https://www.apache.org/licenses/LICENSE-2.0\\n\",\n        \"#\\n\",\n        \"# Unless required by applicable law or agreed to in writing, software\\n\",\n        \"# distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n\",\n        \"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n\",\n        \"# See the License for the specific language governing permissions and\\n\",\n        \"# limitations under the License.\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"Gb7qyhNL1yWt\"\n      },\n      \"source\": [\n        \"# Create ML Kit Image labeling model with Tensorflow Lite Model Maker\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"nDABAblytltI\"\n      },\n      \"source\": [\n        \"<table class=\\\"tfo-notebook-buttons\\\" align=\\\"left\\\">\\n\",\n        \"  <td>\\n\",\n        \"    <a target=\\\"_blank\\\" href=\\\"https://www.tensorflow.org/lite/tutorials/model_maker_image_classification\\\"><img src=\\\"https://www.tensorflow.org/images/tf_logo_32px.png\\\" />View on TensorFlow.org</a>\\n\",\n        \"  </td>\\n\",\n        \"  <td>\\n\",\n        \"    <a target=\\\"_blank\\\" href=\\\"https://colab.research.google.com/github/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/tutorials/model_maker_image_classification.ipynb\\\"><img src=\\\"https://www.tensorflow.org/images/colab_logo_32px.png\\\" />Run in Google Colab</a>\\n\",\n        \"  </td>\\n\",\n        \"  <td>\\n\",\n        \"    <a target=\\\"_blank\\\" href=\\\"https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/tutorials/model_maker_image_classification.ipynb\\\"><img src=\\\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\\\" />View source on GitHub</a>\\n\",\n        \"  </td>\\n\",\n        \"  <td>\\n\",\n        \"    <a href=\\\"https://storage.googleapis.com/tensorflow_docs/tensorflow/tensorflow/lite/g3doc/tutorials/model_maker_image_classification.ipynb\\\"><img src=\\\"https://www.tensorflow.org/images/download_logo_32px.png\\\" />Download notebook</a>\\n\",\n        \"  </td>\\n\",\n        \"</table>\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"m86-Nh4pMHqY\"\n      },\n      \"source\": [\n        \"Model Maker library simplifies the process of adapting and converting a TensorFlow neural-network model to particular input data when deploying this model for on-device ML applications.\\n\",\n        \"\\n\",\n        \"This notebook shows an end-to-end example that utilizes this Model Maker library to create an image labeling model for ML Kit custom Image Labeling and Object Detection and Tracking features.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"bcLF2PKkSbV3\"\n      },\n      \"source\": [\n        \"## Prerequisites\\n\",\n        \"\\n\",\n        \"To run this example, we first need to install serveral required packages, including Model Maker package that in github [repo](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker).\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"colab_type\": \"code\",\n        \"id\": \"6cv3K3oaksJv\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"!pip install git+https://github.com/tensorflow/examples.git#egg=tensorflow-examples[model_maker]\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"Gx1HGRoFQ54j\"\n      },\n      \"source\": [\n        \"Import the required packages.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"colab_type\": \"code\",\n        \"id\": \"XtxiUeZEiXpt\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"import numpy as np\\n\",\n        \"\\n\",\n        \"import tensorflow as tf\\n\",\n        \"\\n\",\n        \"from tensorflow_examples.lite.model_maker.core.data_util.image_dataloader import ImageClassifierDataLoader\\n\",\n        \"from tensorflow_examples.lite.model_maker.core.task import image_classifier\\n\",\n        \"from tensorflow_examples.lite.model_maker.core.task.model_spec import ImageModelSpec\\n\",\n        \"from tensorflow_examples.lite.model_maker.core.task import configs\\n\",\n        \"from tensorflow_examples.lite.model_maker.core import compat\\n\",\n        \"import matplotlib.pyplot as plt\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"brWCSWSn4ASn\",\n        \"colab_type\": \"text\"\n      },\n      \"source\": [\n        \"Make sure to set tf_version as 1 to produce models with uint8 input and output types to be compatible with ML Kit.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"WfwMNeYY4L98\",\n        \"colab_type\": \"code\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"compat.setup_tf_behavior(tf_version=1)\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"SiZZ5DHXotaW\"\n      },\n      \"source\": [\n        \"## Get the data path\\n\",\n        \"\\n\",\n        \"Let's get some images to play with this simple end-to-end example. Hundreds of images is a good start for Model Maker while more data could achieve better accuracy.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"cellView\": \"form\",\n        \"colab_type\": \"code\",\n        \"id\": \"3jz5x0JoskPv\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"image_path = tf.keras.utils.get_file(\\n\",\n        \"      'flower_photos',\\n\",\n        \"      'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',\\n\",\n        \"      untar=True)\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"a55MR6i6nuDm\"\n      },\n      \"source\": [\n        \"You could replace `image_path` with your own image folders. As for uploading data to colab, you could find the upload button in the left sidebar shown in the image below with the red rectangle. Just have a try to upload a zip file and unzip it. The root file path is the current path.\\n\",\n        \"\\n\",\n        \"<img src=\\\"https://storage.googleapis.com/download.tensorflow.org/models/tflite/screenshots/model_maker_image_classification.png\\\" alt=\\\"Upload File\\\" width=\\\"800\\\" hspace=\\\"100\\\">\\n\",\n        \"\\n\",\n        \"Make sure the file structure is correct. For example, the flower dataset contains 3670 images belonging to 5 classes. \\n\",\n        \"\\n\",\n        \"The dataset has the following directory structure:\\n\",\n        \"\\n\",\n        \"<pre>\\n\",\n        \"<b>flower_photos</b>\\n\",\n        \"|__ <b>daisy</b>\\n\",\n        \"    |______ 100080576_f52e8ee070_n.jpg\\n\",\n        \"    |______ 14167534527_781ceb1b7a_n.jpg\\n\",\n        \"    |______ ...\\n\",\n        \"|__ <b>dandelion</b>\\n\",\n        \"    |______ 10043234166_e6dd915111_n.jpg\\n\",\n        \"    |______ 1426682852_e62169221f_m.jpg\\n\",\n        \"    |______ ...\\n\",\n        \"|__ <b>roses</b>\\n\",\n        \"    |______ 102501987_3cdb8e5394_n.jpg\\n\",\n        \"    |______ 14982802401_a3dfb22afb.jpg\\n\",\n        \"    |______ ...\\n\",\n        \"|__ <b>sunflowers</b>\\n\",\n        \"    |______ 12471791574_bb1be83df4.jpg\\n\",\n        \"    |______ 15122112402_cafa41934f.jpg\\n\",\n        \"    |______ ...\\n\",\n        \"|__ <b>tulips</b>\\n\",\n        \"    |______ 13976522214_ccec508fe7.jpg\\n\",\n        \"    |______ 14487943607_651e8062a1_m.jpg\\n\",\n        \"    |______ ...\\n\",\n        \"</pre>\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"NNRNv_mloS89\"\n      },\n      \"source\": [\n        \"If you prefer not to upload your images to the cloud, you could try to run the library locally following the [guide](https://github.com/tensorflow/examples/tree/master/tensorflow_examples/lite/model_maker) in github.\\n\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"w-VDriAdsowu\"\n      },\n      \"source\": [\n        \"## Run the example\\n\",\n        \"The example just consists of 4 lines of code as shown below, each of which representing one step of the overall process.\\n\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"6ahtcO86tZBL\"\n      },\n      \"source\": [\n        \"Step 1.   Load input data specific to an on-device ML app. Split it to training data and testing data.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"colab_type\": \"code\",\n        \"id\": \"lANoNS_gtdH1\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"train_data, test_data = ImageClassifierDataLoader.from_folder(image_path).split(0.9)\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"Y_9IWyIztuRF\"\n      },\n      \"source\": [\n        \"Step 2. Customize the TensorFlow model.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"colab_type\": \"code\",\n        \"id\": \"yRXMZbrwtyRD\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"model = image_classifier.create(train_data)\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"oxU2fDr-t2Ya\"\n      },\n      \"source\": [\n        \"Step 3. Evaluate the model.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"colab_type\": \"code\",\n        \"id\": \"wQr02VxJt6Cs\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"loss, accuracy = model.evaluate(test_data)\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"NtCLU30l4ZSV\",\n        \"colab_type\": \"text\"\n      },\n      \"source\": [\n        \"Step 4. Setup config for quantized model with uint8 input and output type\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"W4QMeF974hgD\",\n        \"colab_type\": \"code\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"config = configs.QuantizationConfig.create_full_integer_quantization(\\n\",\n        \"    representative_data=test_data, is_integer_only=True)\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"colab_type\": \"text\",\n        \"id\": \"eVZw9zU8t84y\"\n      },\n      \"source\": [\n        \"Step 4.  Export to TensorFlow Lite model.\\n\",\n        \"\\n\",\n        \"Here, we export TensorFlow Lite model with [metadata](https://www.tensorflow.org/lite/convert/metadata) which provides a standard for model descriptions.\\n\",\n        \"You could download it in the left sidebar same as the uploading part for your own use.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"colab_type\": \"code\",\n        \"id\": \"Zb-eIzfluCoa\",\n        \"colab\": {}\n      },\n      \"source\": [\n        \"model.export(export_dir='.', quantization_config=config)\"\n      ],\n      \"execution_count\": 0,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"gwIhJ6-93qrw\",\n        \"colab_type\": \"text\"\n      },\n      \"source\": [\n        \"After this simple 4 steps, we could further use TensorFlow Lite model file in ML Kit Image Labeling and Object Detection and Tracking features.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"Lpppfth3kgJA\",\n        \"colab_type\": \"text\"\n      },\n      \"source\": [\n        \"Tensorflow Lite Model Maker allows changing model architecture to suit different needs. Here is the instructions of how to change model architecture:\\n\",\n        \"https://www.tensorflow.org/lite/tutorials/model_maker_image_classification#change_the_model\"\n      ]\n    }\n  ]\n}"
  }
]