[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_size = 2\nindent_style = space\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nend_of_line = lf\n\n[*.{kt, kts}]\nktlint_code_style = intellij_idea\nij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,kotlinx.**,^\nij_kotlin_allow_trailing_comma = false\nij_kotlin_allow_trailing_comma_on_call_site = false\n\nktlint_standard_argument-list-wrapping = disabled\nktlint_function_naming_ignore_when_annotated_with = Composable"
  },
  {
    "path": ".gitattributes",
    "content": "**/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text\n"
  },
  {
    "path": ".github/workflows/build.yaml",
    "content": "name: build\n\non:\n  pull_request: {}\n\n  push:\n    branches:\n      - '**'\n    tags-ignore:\n      - '**'\n\nenv:\n  GRADLE_OPTS: \"-Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false -Dkotlin.incremental=false\"\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          lfs: true\n\n      - name: Configure JDK\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v3\n        with:\n          validate-wrappers: true\n\n      - name: Run Tests\n        run: ./gradlew check picasso-paparazzi-sample:verifyPaparazziDebug\n\n      - name: Upload Test Failures\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: test-failures\n          path: |\n            **/build/reports/tests/test/\n\n  instrumentation-tests:\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        api-level: [21, 27, 28]\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Configure JDK\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v3\n        with:\n          validate-wrappers: true\n\n      - run: ./gradlew assembleAndroidTest\n\n      - name: Enable KVM\n        run: |\n          echo 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules\n          sudo udevadm control --reload-rules\n          sudo udevadm trigger --name-match=kvm\n\n      - uses: reactivecircus/android-emulator-runner@v2\n        with:\n          api-level: ${{ matrix.api-level }}\n          script: ./gradlew connectedCheck\n\n  publish:\n    runs-on: ubuntu-latest\n    if: github.ref == 'refs/heads/master'\n    needs:\n      - build\n      - instrumentation-tests\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Configure JDK\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n\n      - name: Publish Artifacts\n        run: ./gradlew publishMavenPublicationToMavenCentralRepository\n        env:\n          ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }}\n          ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}\n          ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ARTIFACT_SIGNING_PRIVATE_KEY }}\n"
  },
  {
    "path": ".github/workflows/release.yaml",
    "content": "name: release\n\non:\n  push:\n    tags:\n      - '**'\n\nenv:\n  GRADLE_OPTS: \"-Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false -Dkotlin.incremental=false\"\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Configure JDK\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n\n      - name: Publish Artifacts\n        run: ./gradlew publishMavenPublicationToMavenCentralRepository\n        env:\n          ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }}\n          ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}\n          ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ARTIFACT_SIGNING_PRIVATE_KEY }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Eclipse\n.classpath\n.project\n.settings\neclipsebin\n\n# Ant\nbin\ngen\nbuild\nout\nlib\n\n# Maven\ntarget\npom.xml.*\nrelease.properties\ncoverage.ec\n\n# IntelliJ\n.idea\n*.iml\n*.iws\n*.ipr\nclasses\ngen-external-apklibs\n\n# Robolectric\ntmp\n\n.DS_Store\n\n# Gradle\n.gradle\njniLibs\nbuild\nlocal.properties\nreports\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Change Log\n==========\n\nVersion 2.71828 *(2018-03-07)*\n------------------------------\n\nThis version is not fully backwards compatible with previous 2.x releases!\nIt is intended to be a stable, pre-3.0 release that users of 3.0.0-SNAPSHOT can use in the mean time.\n\nIts changes are many, as evidenced by the nearly 3 years since 2.5.2. If you are interested\nin them you can browse the commits here: https://github.com/square/picasso/compare/picasso-parent-2.5.2...2.71828\n\nOtherwise, stay tuned for 3.0 whose change log will be in relation to 2.5.2 and thus encompass any\nchanges present in this release.\n\n\nVersion 2.5.2 *(2015-03-20)*\n----------------------------\n\n * Fix: Correct problems with adapter-based recycling of drawables and interop with external libraries like RoundImageView.\n\n\nVersion 2.5.1 *(2015-03-19)*\n----------------------------\n\n * Specifying transformations in a request now accepts a list.\n * Fix: Correctly handle `null` values from content providers.\n * Fix: Ensure contact photo thumbnail Uris are loaded with the correct request handler.\n * Fix: Eliminate potential (albeit temporary) memory leak on pre-5.0 Android due to message pooling.\n * Fix: Prevent placeholder image aspect ratio from changing while crossfading in image.\n\n\nVersion 2.5.0 *(2015-02-06)*\n--------------------------\n\n * Update to OkHttp 2.x's native API. If you are using OkHttp you must use version 2.0 or newer (the latest is 2.2 at time of writing) and you no longer need to use the `okhttp-urlconnection` shim.\n * Memory and Network policy API controls reading and storing bitmaps in memory and/or disk cache.\n * Allow returning `InputStream` from `RequestHandler`.\n * Allow removing items from memory cache using `clearKeyUri`.\n * `fetch()` can now accept a `Callback`.\n * Provide option with `onlyScaleDown` to perform scaling only if the source bitmap is larger than the target.\n * Fix: Potential workaround handling improperly cached responses with unknown `Content-Length`. (#632)\n * Fix: Ensure resized images completely fill ImageView (#769)\n * Fix: Properly report correct exception when disk cache fails to load (504 gateway error).\n * Fix: Resize now properly maintains aspect ratio if width or height is 0.\n * Fix: Update debug indicators for the visually impaired (blue color instead of yellow for disk cache hits).\n\n\nVersion 2.4.0 *(2014-11-04)*\n--------------------------\n\n * New `RequestHandler` beta API adds support for custom bitmap loading.\n * `priority` API for setting request priority. By default `fetch()` requests are set to `Priority.LOW`.\n * Requests can now be grouped with a `tag` and can be batch paused, resumed, or canceled.\n * Resizing with either height or width of 0 will now maintain aspect ratio.\n * `Picasso.setSingletonInstance` allows setting the global Picasso instance returned from `Picasso.with`.\n * Request `stableKey` provides an override value for the URI or resource ID when caching.\n * Fix: Properly calculate sample size for requests with `centerInside()`.\n * Fix: `ConcurrentModificationException` could occur in the `Dispatcher` when submitting a request.\n * Fix: Correctly log when a request was canceled due to garbage collection.\n * Fix: Provide correct target for `RemoteViews` requests.\n * Fix: Propagate exceptions thrown from custom transformations.\n * Fix: Invoking `shutdown()` now will close the disk cache.\n\n\nVersion 2.3.4 *(2014-08-25)*\n----------------------------\n\n * Fix: Revert fail fast when missing internet permission.\n * Fix: Account for null paths when naming a Request.\n * Add API to allow canceling of remote views requests.\n\n\nVersion 2.3.3 *(2014-07-21)*\n----------------------------\n\n * Fix: Crash when attempting to swap dimension for EXIF transformation.\n * Fix: Properly honor alpha value in PicassoDrawable.\n * Fix: Use `getWidth()` and `getHeight()` instead of `getMeasuredWidth()` and `getMeasuredHeight()` during `fit()`.\n\n\nVersion 2.3.2 *(2014-06-05)*\n----------------------------\n\n * Fix: Correctly invalidate PicassoDrawable for GB.\n * Fix: Attempt to decode responses with missing `Content-Length` header.\n * Fix: Prevent race condition to initial `with()` call.\n\n\nVersion 2.3.1 *(2014-05-29)*\n----------------------------\n\n * Fix: Deprecated Response constructor used 0 for content-length.\n \n\nVersion 2.3.0 *(2014-05-29)*\n----------------------------\n\n * Requests will now be automatically replayed if they failed due to network errors.\n * Add API for logging. This is mostly useful for debugging Picasso itself.\n * Add API for loading images into remote views (notifications and widgets).\n * Stats now provide download statistics.\n * Updated to use Pollexor 2.0.\n * When using OkHttp version 1.6 or newer (including 2.0+) is now required.\n * `MediaStoreBitmapHunter` now properly returns video thumbnails if requested URI is for a video.\n * All API calls now properly validate the current thread they must run on.\n * Performance: Various optimizations for reducing object allocations.\n * Fix: Stats were incorrectly invoked even if the bitmap failed to decode.\n * Fix: Handle `null` intent case in network broadcast receiver extras.\n * Fix: `Target` now correctly invokes bitmap failed if an error drawable or resource is supplied.\n\n\nVersion 2.2.0 *(2014-01-31)*\n----------------------------\n\n * Add support decoding various contact photo URIs. \n * Add support for loading `android.resource` URIs (e.g. load assets from other packages).\n * Add support for MICRO/MINI thumbnails for media images.\n * Add API to supply custom `Bitmap.Config` for decoding.\n * Performance: Reduce GC by reusing same `StringBuilder` instance on main thread for key creation.\n * Performance: Reduce default buffer allocation to 4k for `MarkableInputStream`.\n * Fix: Detect and decode WebP streams from byte array.\n * Fix: Non-200 HTTP responses will now display error drawable if supplied.\n * Fix: All exceptions during decode will now dispatch a failure.\n * Fix: Catch `OutOfMemory` errors, dispatch a failure, and output stats in logcat.\n * Fix: `fit()` now handles cases where either width or height was not zero.\n * Fix: Prevent crash from `null` intent on `NetworkBroadcastReceiver`.\n * Fix: Honor exif orientation when no custom transformations supplied.\n * Fix: Exceptions during transformations propagate to the main thread. \n * Fix: Correct skia decoding problem during underflow.\n * Fix: Placeholder uses full bounds.\n\n\nVersion 2.1.1 *(2013-10-04)*\n----------------------------\n\n * `Target` now has callback for applying placeholder. This makes it symmetric with image views when\n   using `into()`.\n * Fix: Another work around for Android's header decoding algorthm readin more than 4K of image data\n   when decoding bounds.\n * Fix: Ensure default network-based executor is unregistered when instance is shut down.\n * Fix: Ensure connection is always closed for non-2xx response codes.\n\n\nVersion 2.1.0 *(2013-10-01)*\n----------------------------\n\n*Duplicate of v2.0.2. Do not use.*\n\n\nVersion 2.0.2 *(2013-09-11)*\n----------------------------\n\n * Fix: Additional work around for Android's header decoding algorithm reading more than 4K of image\n   data when decoding bounds.\n\n\nVersion 2.0.1 *(2013-09-04)*\n----------------------------\n\n * Enable filtered bitmaps for higher transform quality.\n * Fix: Using callbacks with `into()` on `fit()` requests are now always invoked.\n * Fix: Ensure final frame of cross-fade between place holder and image renders correctly.\n * Fix: Work around Android's behavior of reading more than 1K of image header data when decoding\n   bounds for some images.\n\n\nVersion 2.0.0 *(2013-08-30)*\n----------------------------\n\n * New architecture distances Picasso further from the main thread using a dedicated dispatcher\n   thread to manage requests.\n * Request merging. Two requests on the same key will be combined and the result will be delivered\n   to both at the same time.\n * `fetch()` requests are now properly wired up to be used as \"warm up the cache\" type of requests\n   without a target.\n * `fit()` will now automatically wait for the view to be measured before executing the request.\n * `shutdown()` API added. Clears the memory cache and stops all threads. Submitting new requests\n   will cause a crash after `shutdown()` has been called.\n * Batch completed requests to the main thread to reduce main thread re-layout/draw calls.\n * Variable thread count depending on network connectivity. The faster the network the more threads\n   and vice versa.\n * Ability to specify a callback with `ImageView` requests.\n * Picasso will now decode the bounds of the target bitmap over the network. This helps avoid\n   decoding 2000x2000 images meant for 100x100 views.\n * Support loading asset URIs in the form `file:///android_asset/...`.\n * BETA: Ability to rewrite requests on the fly. This is useful if you want to add custom logic for\n   wiring up requests differently.\n\n\nVersion 1.1.1 *(2013-06-14)*\n----------------------------\n\n * Fix: Ensure old requests for targets are cancelled when using a `null` image.\n\n\nVersion 1.1.0 *(2013-06-13)*\n----------------------------\n\n * `load` method can now take a `Uri`.\n * Support loading contact photos given a contact `Uri`.\n * Add `centerInside()` image transformation.\n * Fix: Prevent network stream decodes from blocking each other.\n\n\nVersion 1.0.2 *(2013-05-23)*\n----------------------------\n\n * Auto-scale disk cache based on file system size.\n * `placeholder` now accepts `null` for clearing an existing image when used in an adapter and\n   without an explicit placeholder image.\n * New global failure listener for reporting load errors to a remote analytics or crash service.\n * Fix: Ensure disk cache folder is created before initialization.\n * Fix: Only use the built-in disk cache on API 14+ (but you're all using [OkHttp][1] anyways,\n   right?).\n\n\nVersion 1.0.1 *(2013-05-14)*\n----------------------------\n\n * Fix: Properly set priority for download threads.\n * Fix: Ensure stats thread is always initialized.\n\n\nVersion 1.0.0 *(2013-05-14)*\n----------------------------\n\nInitial release.\n\n\n\n\n [1]: http://square.github.io/okhttp/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing\n============\n\nIf you would like to contribute code to this project you can do so through GitHub by\nforking the repository and sending a pull request.\n\nWhen submitting code, please make every effort to follow existing conventions\nand style in order to keep the code as readable as possible.\n\nBefore your code can be accepted into the project you must also sign the\n[Individual Contributor License Agreement (CLA)][1].\n\n\n [1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1\n"
  },
  {
    "path": "LICENSE.txt",
    "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.\n"
  },
  {
    "path": "README.md",
    "content": "Picasso\n=======\n\n**Attention**: This library is deprecated.\nPlease use alternatives like [Coil](https://coil-kt.github.io/coil/) for future projects, and start planning to migrate existing projects, especially if they rely on Compose UI.\nExisting versions will continue to function, but no new work is planned.\nWhile some changes may land in the repo as we support internal legacy usage and migration, there will be no more public releases to Maven Central.\n\nThank you to all who used and/or contributed to Picasso over its decade of image loading.\n\n---\n\nA powerful image downloading and caching library for Android\n\n![](website/static/sample.png)\n\nFor more information please see [the website][1]\n\n\n\nDownload\n--------\n\nDownload the latest AAR from [Maven Central][2] or grab via Gradle:\n```groovy\nimplementation 'com.squareup.picasso:picasso:2.8'\n```\nor Maven:\n```xml\n<dependency>\n  <groupId>com.squareup.picasso</groupId>\n  <artifactId>picasso</artifactId>\n  <version>2.8</version>\n</dependency>\n```\n\nSnapshots of the development version are available in [Sonatype's `snapshots` repository][snap].\n\nPicasso requires at minimum Java 8 and API 21.\n\n\nProGuard\n--------\n\nIf you are using ProGuard you might need to add OkHttp's rules: https://github.com/square/okhttp/#r8--proguard\n\n\n\nLicense\n--------\n\n    Copyright 2013 Square, Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    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 [1]: https://square.github.io/picasso/\n [2]: https://search.maven.org/search?q=g:com.squareup.picasso%20AND%20a:picasso\n [snap]: https://s01.oss.sonatype.org/content/repositories/snapshots/\n"
  },
  {
    "path": "RELEASING.md",
    "content": "Releasing\n========\n\n 1. Update `VERSION_NAME` in `gradle.properties` to the release (non-SNAPSHOT) version.\n 2. Update `CHANGELOG.md` for the impending release.\n 3. Update the `README.md` with the new version.\n 4. `git commit -am \"Prepare for release X.Y.Z\"` (where X.Y.Z is the new version)\n 5. `git tag -a X.Y.Z -m \"X.Y.Z\"` (where X.Y.Z is the new version)\n 6. Update `VERSION_NAME` in `gradle.properties` to the next SNAPSHOT version.\n 7. `git commit -am \"Prepare next development version\"`\n 8. `git push && git push --tags`\n\nThis will trigger a GitHub Action workflow which will upload the release artifacts to Maven Central.\n"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n  ext.isCi = \"true\" == System.getenv('CI')\n\n  repositories {\n    mavenCentral()\n    google()\n    gradlePluginPortal()\n  }\n\n  dependencies {\n    classpath libs.plugin.android\n    classpath libs.plugin.kotlin\n    classpath libs.plugin.kotlin.compose\n    classpath libs.plugin.publish\n    classpath libs.plugin.spotless\n    classpath libs.plugin.binaryCompatibilityValidator\n    classpath libs.plugin.paparazzi\n  }\n}\n\napply plugin: 'binary-compatibility-validator'\n\napiValidation {\n  ignoredProjects += ['picasso-sample', 'picasso-paparazzi-sample']\n}\n\nsubprojects {\n  repositories {\n    mavenCentral()\n    google()\n  }\n\n  tasks.withType(Test).configureEach {\n    testLogging {\n      events \"failed\"\n      exceptionFormat \"full\"\n      showExceptions true\n      showStackTraces true\n      showCauses true\n    }\n  }\n\n  plugins.withId('com.vanniktech.maven.publish') {\n    publishing {\n      repositories {\n        /**\n         * Want to push to an internal repository for testing?\n         * Set the following properties in ~/.gradle/gradle.properties.\n         *\n         * internalUrl=YOUR_INTERNAL_URL\n         * internalUsername=YOUR_USERNAME\n         * internalPassword=YOUR_PASSWORD\n         */\n        maven {\n          name = \"internal\"\n          url = providers.gradleProperty(\"internalUrl\")\n          credentials(PasswordCredentials)\n        }\n      }\n    }\n  }\n\n  apply plugin: 'com.diffplug.spotless'\n  spotless {\n    kotlin {\n      target('**/*.kt')\n      licenseHeaderFile(rootProject.file('gradle/license-header.txt'))\n      ktlint(libs.versions.ktlint.get())\n        .setEditorConfigPath(rootProject.file(\".editorconfig\"))\n    }\n  }\n\n  group = GROUP\n  version = VERSION_NAME\n}\n\ntasks.named('wrapper').configure {\n  distributionType = Wrapper.DistributionType.ALL\n}\n\nconfigurations {\n  osstrich\n}\n\ndependencies {\n  osstrich 'com.squareup.osstrich:osstrich:1.4.0'\n}\n\ntasks.register('deployJavadoc', JavaExec) {\n  classpath = configurations.osstrich\n  main = 'com.squareup.osstrich.JavadocPublisher'\n  args \"$buildDir/osstrich\", 'git@github.com:square/picasso.git', 'com.squareup.picasso'\n}\n"
  },
  {
    "path": "deploy_website.sh",
    "content": "#!/bin/bash\n\nset -ex\n\nREPO=\"git@github.com:square/picasso.git\"\nDIR=temp-clone\n\n# Delete any existing temporary website clone\nrm -rf $DIR\n\n# Clone the current repo into temp folder\ngit clone $REPO $DIR\n\n# Move working directory into temp folder\ncd $DIR\n\n# Checkout and track the gh-pages branch\ngit checkout -t origin/gh-pages\n\n# Delete everything that isn't versioned (1.x, 2.x)\nls | grep -E -v '^\\d+\\.x$' | xargs rm -rf\n\n# Copy website files from real repo\ncp -R ../website/* .\n\n# Stage all files in git and create a commit\ngit add .\ngit add -u\ngit commit -m \"Website at $(date)\"\n\n# Push the new files up to GitHub\ngit push origin gh-pages\n\n# Delete our temp folder\ncd ..\nrm -rf $DIR\n"
  },
  {
    "path": "gradle/libs.versions.toml",
    "content": "[versions]\nagp = '8.7.2'\ncoroutines = '1.8.1'\ncomposeUi = '1.6.8'\njavaTarget = '1.8'\nkotlin = '2.0.0'\nktlint = '1.2.1'\nokhttp = '4.12.0'\nokio = '3.2.0'\npaparazzi = '1.3.4'\n\nminSdk = '21'\ncompileSdk = '34'\n\n[libraries]\nandroidx-annotations = { module = 'androidx.annotation:annotation', version = '1.9.1' }\nandroidx-core = { module = 'androidx.core:core', version = '1.13.1' }\nandroidx-cursorAdapter = { module = 'androidx.cursoradapter:cursoradapter', version = '1.0.0' }\nandroidx-exifInterface = { module = 'androidx.exifinterface:exifinterface', version = '1.3.7' }\nandroidx-fragment = { module = 'androidx.fragment:fragment', version = '1.8.1' }\nandroidx-junit = { module = 'androidx.test.ext:junit', version = '1.2.1' }\nandroidx-lifecycle = { module = 'androidx.lifecycle:lifecycle-common', version = '2.8.7' }\nandroidx-startup = { module = 'androidx.startup:startup-runtime', version = '1.1.1' }\nandroidx-testRunner = { module = 'androidx.test:runner', version = '1.6.2' }\n\ncoroutines-test = { module = \"org.jetbrains.kotlinx:kotlinx-coroutines-test\", version.ref = 'coroutines' }\n\ncomposeUi = { module = 'androidx.compose.ui:ui', version.ref = 'composeUi' }\ncomposeRuntime = { module = 'androidx.compose.runtime:runtime', version.ref = 'composeUi' }\ncomposeUi-foundation = { module = 'androidx.compose.foundation:foundation', version.ref = 'composeUi' }\ncomposeUi-material = { module = 'androidx.compose.material:material', version.ref = 'composeUi' }\ncomposeUi-uiTooling = { module = 'androidx.compose.ui:ui-tooling', version.ref = 'composeUi' }\ncomposeUi-test = { module = 'androidx.compose.ui:ui-test-junit4', version.ref = 'composeUi' }\ncomposeUi-testManifest = { module = 'androidx.compose.ui:ui-test-manifest', version.ref = 'composeUi' }\n\ndrawablePainter = { module = 'com.google.accompanist:accompanist-drawablepainter', version = '0.34.0' }\n\nokio = { module = \"com.squareup.okio:okio\", version = '3.9.0' }\n\nokhttp = { module = 'com.squareup.okhttp3:okhttp', version.ref = 'okhttp' }\nokhttp-mockWebServer = { module = 'com.squareup.okhttp3:mockwebserver', version.ref = 'okhttp' }\n\npollexor = { module = 'com.squareup:pollexor', version = '3.0.0' }\n\n# Test libraries\njunit = { module = 'junit:junit', version = '4.13.2' }\ntruth = { module = 'com.google.truth:truth', version = '1.4.4' }\nrobolectric = { module = 'org.robolectric:robolectric', version = '4.7' }\nmockito = { module = 'org.mockito:mockito-core', version = '5.12.0' }\n\n# Plugins\nplugin-android = { module = 'com.android.tools.build:gradle', version.ref = 'agp' }\nplugin-binaryCompatibilityValidator = { module = \"org.jetbrains.kotlinx:binary-compatibility-validator\", version = '0.16.3' }\nplugin-kotlin = { module = 'org.jetbrains.kotlin:kotlin-gradle-plugin', version.ref = 'kotlin' }\nplugin-kotlin-compose = { module = \"org.jetbrains.kotlin:compose-compiler-gradle-plugin\", version.ref = \"kotlin\" }\nplugin-paparazzi = { module = 'app.cash.paparazzi:paparazzi-gradle-plugin', version.ref = 'paparazzi' }\nplugin-publish = { module = \"com.vanniktech:gradle-maven-publish-plugin\", version = '0.29.0' }\nplugin-spotless = { module = \"com.diffplug.spotless:spotless-plugin-gradle\", version = '6.25.0' }\nplugin-test-aggregation = { module = \"io.github.gmazzo.test.aggregation:plugin\", version = '2.2.1' }\n"
  },
  {
    "path": "gradle/license-header.txt",
    "content": "/*\n * Copyright (C) $YEAR Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.10.2-all.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "GROUP=com.squareup.picasso3\nVERSION_NAME=3.0.0-SNAPSHOT\n\nPOM_URL=https://github.com/square/picasso/\nPOM_SCM_URL=https://github.com/square/picasso/\nPOM_SCM_CONNECTION=scm:git:git://github.com/square/picasso.git\nPOM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/square/picasso.git\n\nPOM_LICENCE_NAME=The Apache Software License, Version 2.0\nPOM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt\nPOM_LICENCE_DIST=repo\n\nPOM_DEVELOPER_ID=square\nPOM_DEVELOPER_NAME=Square, Inc.\n\norg.gradle.jvmargs=-Xmx1536M\n\nandroid.useAndroidX=true\n\nandroid.defaults.buildfeatures.buildconfig=false\nandroid.defaults.buildfeatures.aidl=false\nandroid.defaults.buildfeatures.renderscript=false\nandroid.defaults.buildfeatures.resvalues=false\nandroid.defaults.buildfeatures.shaders=false\n\nSONATYPE_HOST=S01\nRELEASE_SIGNING_ENABLED=true\nSONATYPE_AUTOMATIC_RELEASE=true\n"
  },
  {
    "path": "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# SPDX-License-Identifier: Apache-2.0\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/platforms/jvm/plugins-application/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##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\n' \"$PWD\" ) || exit\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    if ! command -v java >/dev/null 2>&1\n    then\n        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.\"\n    fi\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=SC2039,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=SC2039,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\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# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\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": "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@rem SPDX-License-Identifier: Apache-2.0\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. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\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. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\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": "lint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lint>\n  <issue id=\"KotlinPropertyAccess\" severity=\"error\"/>\n  <issue id=\"LambdaLast\" severity=\"error\"/>\n  <issue id=\"NoHardKeywords\" severity=\"error\"/>\n  <issue id=\"UnknownNullness\" severity=\"error\"/>\n  <issue id=\"SyntheticAccessor\" severity=\"error\"/>\n</lint>\n"
  },
  {
    "path": "picasso/api/picasso.api",
    "content": "public abstract interface class com/squareup/picasso3/BitmapTarget {\n\tpublic abstract fun onBitmapFailed (Ljava/lang/Exception;Landroid/graphics/drawable/Drawable;)V\n\tpublic abstract fun onBitmapLoaded (Landroid/graphics/Bitmap;Lcom/squareup/picasso3/Picasso$LoadedFrom;)V\n\tpublic abstract fun onPrepareLoad (Landroid/graphics/drawable/Drawable;)V\n}\n\npublic abstract interface class com/squareup/picasso3/Callback {\n\tpublic abstract fun onError (Ljava/lang/Throwable;)V\n\tpublic abstract fun onSuccess ()V\n}\n\npublic class com/squareup/picasso3/Callback$EmptyCallback : com/squareup/picasso3/Callback {\n\tpublic fun <init> ()V\n\tpublic fun onError (Ljava/lang/Throwable;)V\n\tpublic fun onSuccess ()V\n}\n\npublic abstract interface class com/squareup/picasso3/DrawableTarget {\n\tpublic abstract fun onDrawableFailed (Ljava/lang/Exception;Landroid/graphics/drawable/Drawable;)V\n\tpublic abstract fun onDrawableLoaded (Landroid/graphics/drawable/Drawable;Lcom/squareup/picasso3/Picasso$LoadedFrom;)V\n\tpublic abstract fun onPrepareLoad (Landroid/graphics/drawable/Drawable;)V\n}\n\npublic abstract interface class com/squareup/picasso3/EventListener : java/io/Closeable {\n\tpublic abstract fun bitmapDecoded (Landroid/graphics/Bitmap;)V\n\tpublic abstract fun bitmapTransformed (Landroid/graphics/Bitmap;)V\n\tpublic abstract fun cacheHit ()V\n\tpublic abstract fun cacheMaxSize (I)V\n\tpublic abstract fun cacheMiss ()V\n\tpublic abstract fun cacheSize (I)V\n\tpublic abstract fun close ()V\n\tpublic abstract fun downloadFinished (J)V\n}\n\npublic final class com/squareup/picasso3/EventListener$DefaultImpls {\n\tpublic static fun close (Lcom/squareup/picasso3/EventListener;)V\n}\n\npublic abstract interface annotation class com/squareup/picasso3/Initializer : java/lang/annotation/Annotation {\n}\n\npublic final class com/squareup/picasso3/MemoryPolicy : java/lang/Enum {\n\tpublic static final field Companion Lcom/squareup/picasso3/MemoryPolicy$Companion;\n\tpublic static final field NO_CACHE Lcom/squareup/picasso3/MemoryPolicy;\n\tpublic static final field NO_STORE Lcom/squareup/picasso3/MemoryPolicy;\n\tpublic static fun getEntries ()Lkotlin/enums/EnumEntries;\n\tpublic final fun getIndex ()I\n\tpublic static final fun shouldReadFromMemoryCache (I)Z\n\tpublic static final fun shouldWriteToMemoryCache (I)Z\n\tpublic static fun valueOf (Ljava/lang/String;)Lcom/squareup/picasso3/MemoryPolicy;\n\tpublic static fun values ()[Lcom/squareup/picasso3/MemoryPolicy;\n}\n\npublic final class com/squareup/picasso3/MemoryPolicy$Companion {\n\tpublic final fun shouldReadFromMemoryCache (I)Z\n\tpublic final fun shouldWriteToMemoryCache (I)Z\n}\n\npublic final class com/squareup/picasso3/NetworkPolicy : java/lang/Enum {\n\tpublic static final field Companion Lcom/squareup/picasso3/NetworkPolicy$Companion;\n\tpublic static final field NO_CACHE Lcom/squareup/picasso3/NetworkPolicy;\n\tpublic static final field NO_STORE Lcom/squareup/picasso3/NetworkPolicy;\n\tpublic static final field OFFLINE Lcom/squareup/picasso3/NetworkPolicy;\n\tpublic static fun getEntries ()Lkotlin/enums/EnumEntries;\n\tpublic final fun getIndex ()I\n\tpublic static final fun isOfflineOnly (I)Z\n\tpublic static final fun shouldReadFromDiskCache (I)Z\n\tpublic static final fun shouldWriteToDiskCache (I)Z\n\tpublic static fun valueOf (Ljava/lang/String;)Lcom/squareup/picasso3/NetworkPolicy;\n\tpublic static fun values ()[Lcom/squareup/picasso3/NetworkPolicy;\n}\n\npublic final class com/squareup/picasso3/NetworkPolicy$Companion {\n\tpublic final fun isOfflineOnly (I)Z\n\tpublic final fun shouldReadFromDiskCache (I)Z\n\tpublic final fun shouldWriteToDiskCache (I)Z\n}\n\npublic final class com/squareup/picasso3/Picasso : androidx/lifecycle/DefaultLifecycleObserver {\n\tpublic final fun cancelRequest (Landroid/widget/ImageView;)V\n\tpublic final fun cancelRequest (Landroid/widget/RemoteViews;I)V\n\tpublic final fun cancelRequest (Lcom/squareup/picasso3/BitmapTarget;)V\n\tpublic final fun cancelRequest (Lcom/squareup/picasso3/DrawableTarget;)V\n\tpublic final fun cancelTag (Ljava/lang/Object;)V\n\tpublic final fun evictAll ()V\n\tpublic final fun getIndicatorsEnabled ()Z\n\tpublic final fun invalidate (Landroid/net/Uri;)V\n\tpublic final fun invalidate (Ljava/io/File;)V\n\tpublic final fun invalidate (Ljava/lang/String;)V\n\tpublic final fun isLoggingEnabled ()Z\n\tpublic final fun load (I)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun load (Landroid/net/Uri;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun load (Ljava/io/File;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun load (Ljava/lang/String;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun newBuilder ()Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic fun onDestroy (Landroidx/lifecycle/LifecycleOwner;)V\n\tpublic fun onStart (Landroidx/lifecycle/LifecycleOwner;)V\n\tpublic fun onStop (Landroidx/lifecycle/LifecycleOwner;)V\n\tpublic final fun pauseTag (Ljava/lang/Object;)V\n\tpublic final fun resumeTag (Ljava/lang/Object;)V\n\tpublic final fun setIndicatorsEnabled (Z)V\n\tpublic final fun setLoggingEnabled (Z)V\n\tpublic final fun shutdown ()V\n}\n\npublic final class com/squareup/picasso3/Picasso$Builder {\n\tpublic fun <init> (Landroid/content/Context;)V\n\tpublic final fun addEventListener (Lcom/squareup/picasso3/EventListener;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun addRequestHandler (Lcom/squareup/picasso3/RequestHandler;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun addRequestTransformer (Lcom/squareup/picasso3/Picasso$RequestTransformer;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun build ()Lcom/squareup/picasso3/Picasso;\n\tpublic final fun callFactory (Lokhttp3/Call$Factory;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun client (Lokhttp3/OkHttpClient;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun defaultBitmapConfig (Landroid/graphics/Bitmap$Config;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun dispatchers (Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic static synthetic fun dispatchers$default (Lcom/squareup/picasso3/Picasso$Builder;Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;ILjava/lang/Object;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun executor (Ljava/util/concurrent/ExecutorService;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun indicatorsEnabled (Z)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun listener (Lcom/squareup/picasso3/Picasso$Listener;)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun loggingEnabled (Z)Lcom/squareup/picasso3/Picasso$Builder;\n\tpublic final fun withCacheSize (I)Lcom/squareup/picasso3/Picasso$Builder;\n}\n\npublic abstract interface class com/squareup/picasso3/Picasso$Listener {\n\tpublic abstract fun onImageLoadFailed (Lcom/squareup/picasso3/Picasso;Landroid/net/Uri;Ljava/lang/Exception;)V\n}\n\npublic final class com/squareup/picasso3/Picasso$LoadedFrom : java/lang/Enum {\n\tpublic static final field DISK Lcom/squareup/picasso3/Picasso$LoadedFrom;\n\tpublic static final field MEMORY Lcom/squareup/picasso3/Picasso$LoadedFrom;\n\tpublic static final field NETWORK Lcom/squareup/picasso3/Picasso$LoadedFrom;\n\tpublic static fun getEntries ()Lkotlin/enums/EnumEntries;\n\tpublic static fun valueOf (Ljava/lang/String;)Lcom/squareup/picasso3/Picasso$LoadedFrom;\n\tpublic static fun values ()[Lcom/squareup/picasso3/Picasso$LoadedFrom;\n}\n\npublic final class com/squareup/picasso3/Picasso$Priority : java/lang/Enum {\n\tpublic static final field HIGH Lcom/squareup/picasso3/Picasso$Priority;\n\tpublic static final field LOW Lcom/squareup/picasso3/Picasso$Priority;\n\tpublic static final field NORMAL Lcom/squareup/picasso3/Picasso$Priority;\n\tpublic static fun getEntries ()Lkotlin/enums/EnumEntries;\n\tpublic static fun valueOf (Ljava/lang/String;)Lcom/squareup/picasso3/Picasso$Priority;\n\tpublic static fun values ()[Lcom/squareup/picasso3/Picasso$Priority;\n}\n\npublic abstract interface class com/squareup/picasso3/Picasso$RequestTransformer {\n\tpublic abstract fun transformRequest (Lcom/squareup/picasso3/Request;)Lcom/squareup/picasso3/Request;\n}\n\npublic final class com/squareup/picasso3/PicassoExecutorService : java/util/concurrent/ThreadPoolExecutor {\n\tpublic fun <init> ()V\n\tpublic fun <init> (ILjava/util/concurrent/ThreadFactory;)V\n\tpublic synthetic fun <init> (ILjava/util/concurrent/ThreadFactory;ILkotlin/jvm/internal/DefaultConstructorMarker;)V\n\tpublic fun submit (Ljava/lang/Runnable;)Ljava/util/concurrent/Future;\n}\n\npublic final class com/squareup/picasso3/PicassoKt {\n\tpublic static final field TAG Ljava/lang/String;\n}\n\npublic final class com/squareup/picasso3/Request {\n\tpublic static final field KEY_SEPARATOR C\n\tpublic final field centerCrop Z\n\tpublic final field centerCropGravity I\n\tpublic final field centerInside Z\n\tpublic final field config Landroid/graphics/Bitmap$Config;\n\tpublic final field hasRotationPivot Z\n\tpublic final field headers Lokhttp3/Headers;\n\tpublic field id I\n\tpublic field key Ljava/lang/String;\n\tpublic final field memoryPolicy I\n\tpublic final field networkPolicy I\n\tpublic final field onlyScaleDown Z\n\tpublic final field priority Lcom/squareup/picasso3/Picasso$Priority;\n\tpublic final field resourceId I\n\tpublic final field rotationDegrees F\n\tpublic final field rotationPivotX F\n\tpublic final field rotationPivotY F\n\tpublic field started J\n\tpublic final field targetHeight I\n\tpublic final field targetWidth I\n\tpublic field transformations Ljava/util/List;\n\tpublic final field uri Landroid/net/Uri;\n\tpublic final fun getName ()Ljava/lang/String;\n\tpublic final fun getStableKey ()Ljava/lang/String;\n\tpublic final fun getTag ()Ljava/lang/Object;\n\tpublic final fun hasSize ()Z\n\tpublic final fun logId ()Ljava/lang/String;\n\tpublic final fun needsMatrixTransform ()Z\n\tpublic final fun newBuilder ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun plainId ()Ljava/lang/String;\n\tpublic fun toString ()Ljava/lang/String;\n}\n\npublic final class com/squareup/picasso3/Request$Builder {\n\tpublic fun <init> (I)V\n\tpublic fun <init> (Landroid/net/Uri;)V\n\tpublic final fun addHeader (Ljava/lang/String;Ljava/lang/String;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun build ()Lcom/squareup/picasso3/Request;\n\tpublic final fun centerCrop ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun centerCrop (I)Lcom/squareup/picasso3/Request$Builder;\n\tpublic static synthetic fun centerCrop$default (Lcom/squareup/picasso3/Request$Builder;IILjava/lang/Object;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun centerInside ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun clearCenterCrop ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun clearCenterInside ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun clearOnlyScaleDown ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun clearResize ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun clearRotation ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun clearTag ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun config (Landroid/graphics/Bitmap$Config;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun getCenterCrop ()Z\n\tpublic final fun getCenterCropGravity ()I\n\tpublic final fun getCenterInside ()Z\n\tpublic final fun getConfig ()Landroid/graphics/Bitmap$Config;\n\tpublic final fun getHasRotationPivot ()Z\n\tpublic final fun getHeaders ()Lokhttp3/Headers;\n\tpublic final fun getMemoryPolicy ()I\n\tpublic final fun getNetworkPolicy ()I\n\tpublic final fun getOnlyScaleDown ()Z\n\tpublic final fun getPriority ()Lcom/squareup/picasso3/Picasso$Priority;\n\tpublic final fun getResourceId ()I\n\tpublic final fun getRotationDegrees ()F\n\tpublic final fun getRotationPivotX ()F\n\tpublic final fun getRotationPivotY ()F\n\tpublic final fun getStableKey ()Ljava/lang/String;\n\tpublic final fun getTag ()Ljava/lang/Object;\n\tpublic final fun getTargetHeight ()I\n\tpublic final fun getTargetWidth ()I\n\tpublic final fun getTransformations ()Ljava/util/List;\n\tpublic final fun getUri ()Landroid/net/Uri;\n\tpublic final fun hasImage ()Z\n\tpublic final fun hasPriority ()Z\n\tpublic final fun hasSize ()Z\n\tpublic final fun memoryPolicy (Lcom/squareup/picasso3/MemoryPolicy;[Lcom/squareup/picasso3/MemoryPolicy;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun networkPolicy (Lcom/squareup/picasso3/NetworkPolicy;[Lcom/squareup/picasso3/NetworkPolicy;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun onlyScaleDown ()Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun priority (Lcom/squareup/picasso3/Picasso$Priority;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun resize (II)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun rotate (F)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun rotate (FFF)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun setCenterCrop (Z)V\n\tpublic final fun setCenterCropGravity (I)V\n\tpublic final fun setCenterInside (Z)V\n\tpublic final fun setConfig (Landroid/graphics/Bitmap$Config;)V\n\tpublic final fun setHasRotationPivot (Z)V\n\tpublic final fun setHeaders (Lokhttp3/Headers;)V\n\tpublic final fun setMemoryPolicy (I)V\n\tpublic final fun setNetworkPolicy (I)V\n\tpublic final fun setOnlyScaleDown (Z)V\n\tpublic final fun setPriority (Lcom/squareup/picasso3/Picasso$Priority;)V\n\tpublic final fun setResourceId (I)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun setResourceId (I)V\n\tpublic final fun setRotationDegrees (F)V\n\tpublic final fun setRotationPivotX (F)V\n\tpublic final fun setRotationPivotY (F)V\n\tpublic final fun setStableKey (Ljava/lang/String;)V\n\tpublic final fun setTag (Ljava/lang/Object;)V\n\tpublic final fun setTargetHeight (I)V\n\tpublic final fun setTargetWidth (I)V\n\tpublic final fun setTransformations (Ljava/util/List;)V\n\tpublic final fun setUri (Landroid/net/Uri;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun setUri (Landroid/net/Uri;)V\n\tpublic final fun stableKey (Ljava/lang/String;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun tag (Ljava/lang/Object;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun transform (Lcom/squareup/picasso3/Transformation;)Lcom/squareup/picasso3/Request$Builder;\n\tpublic final fun transform (Ljava/util/List;)Lcom/squareup/picasso3/Request$Builder;\n}\n\npublic final class com/squareup/picasso3/RequestCreator {\n\tpublic final fun addHeader (Ljava/lang/String;Ljava/lang/String;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun centerCrop ()Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun centerCrop (I)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun centerInside ()Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun config (Landroid/graphics/Bitmap$Config;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun error (I)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun error (Landroid/graphics/drawable/Drawable;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun fetch ()V\n\tpublic final fun fetch (Lcom/squareup/picasso3/Callback;)V\n\tpublic static synthetic fun fetch$default (Lcom/squareup/picasso3/RequestCreator;Lcom/squareup/picasso3/Callback;ILjava/lang/Object;)V\n\tpublic final fun fit ()Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun get ()Landroid/graphics/Bitmap;\n\tpublic final fun into (Landroid/widget/ImageView;)V\n\tpublic final fun into (Landroid/widget/ImageView;Lcom/squareup/picasso3/Callback;)V\n\tpublic final fun into (Landroid/widget/RemoteViews;IILandroid/app/Notification;)V\n\tpublic final fun into (Landroid/widget/RemoteViews;IILandroid/app/Notification;Ljava/lang/String;)V\n\tpublic final fun into (Landroid/widget/RemoteViews;IILandroid/app/Notification;Ljava/lang/String;Lcom/squareup/picasso3/Callback;)V\n\tpublic final fun into (Landroid/widget/RemoteViews;IILcom/squareup/picasso3/Callback;)V\n\tpublic final fun into (Landroid/widget/RemoteViews;I[I)V\n\tpublic final fun into (Landroid/widget/RemoteViews;I[ILcom/squareup/picasso3/Callback;)V\n\tpublic final fun into (Lcom/squareup/picasso3/BitmapTarget;)V\n\tpublic final fun into (Lcom/squareup/picasso3/DrawableTarget;)V\n\tpublic static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/ImageView;Lcom/squareup/picasso3/Callback;ILjava/lang/Object;)V\n\tpublic static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/RemoteViews;IILandroid/app/Notification;Ljava/lang/String;Lcom/squareup/picasso3/Callback;ILjava/lang/Object;)V\n\tpublic static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/RemoteViews;IILcom/squareup/picasso3/Callback;ILjava/lang/Object;)V\n\tpublic static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/RemoteViews;I[ILcom/squareup/picasso3/Callback;ILjava/lang/Object;)V\n\tpublic final fun memoryPolicy (Lcom/squareup/picasso3/MemoryPolicy;[Lcom/squareup/picasso3/MemoryPolicy;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun networkPolicy (Lcom/squareup/picasso3/NetworkPolicy;[Lcom/squareup/picasso3/NetworkPolicy;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun noFade ()Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun noPlaceholder ()Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun onlyScaleDown ()Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun placeholder (I)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun placeholder (Landroid/graphics/drawable/Drawable;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun priority (Lcom/squareup/picasso3/Picasso$Priority;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun resize (II)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun resizeDimen (II)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun rotate (F)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun rotate (FFF)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun stableKey (Ljava/lang/String;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun tag (Ljava/lang/Object;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun transform (Lcom/squareup/picasso3/Transformation;)Lcom/squareup/picasso3/RequestCreator;\n\tpublic final fun transform (Ljava/util/List;)Lcom/squareup/picasso3/RequestCreator;\n}\n\npublic abstract class com/squareup/picasso3/RequestHandler {\n\tpublic fun <init> ()V\n\tpublic abstract fun canHandleRequest (Lcom/squareup/picasso3/Request;)Z\n\tpublic fun getRetryCount ()I\n\tpublic abstract fun load (Lcom/squareup/picasso3/Picasso;Lcom/squareup/picasso3/Request;Lcom/squareup/picasso3/RequestHandler$Callback;)V\n\tpublic fun shouldRetry (ZLandroid/net/NetworkInfo;)Z\n\tpublic fun supportsReplay ()Z\n}\n\npublic abstract interface class com/squareup/picasso3/RequestHandler$Callback {\n\tpublic abstract fun onError (Ljava/lang/Throwable;)V\n\tpublic abstract fun onSuccess (Lcom/squareup/picasso3/RequestHandler$Result;)V\n}\n\npublic abstract class com/squareup/picasso3/RequestHandler$Result {\n\tpublic synthetic fun <init> (Lcom/squareup/picasso3/Picasso$LoadedFrom;IILkotlin/jvm/internal/DefaultConstructorMarker;)V\n\tpublic synthetic fun <init> (Lcom/squareup/picasso3/Picasso$LoadedFrom;ILkotlin/jvm/internal/DefaultConstructorMarker;)V\n\tpublic final fun getExifRotation ()I\n\tpublic final fun getLoadedFrom ()Lcom/squareup/picasso3/Picasso$LoadedFrom;\n}\n\npublic final class com/squareup/picasso3/RequestHandler$Result$Bitmap : com/squareup/picasso3/RequestHandler$Result {\n\tpublic fun <init> (Landroid/graphics/Bitmap;Lcom/squareup/picasso3/Picasso$LoadedFrom;I)V\n\tpublic synthetic fun <init> (Landroid/graphics/Bitmap;Lcom/squareup/picasso3/Picasso$LoadedFrom;IILkotlin/jvm/internal/DefaultConstructorMarker;)V\n\tpublic final fun getBitmap ()Landroid/graphics/Bitmap;\n}\n\npublic final class com/squareup/picasso3/RequestHandler$Result$Drawable : com/squareup/picasso3/RequestHandler$Result {\n\tpublic fun <init> (Landroid/graphics/drawable/Drawable;Lcom/squareup/picasso3/Picasso$LoadedFrom;I)V\n\tpublic synthetic fun <init> (Landroid/graphics/drawable/Drawable;Lcom/squareup/picasso3/Picasso$LoadedFrom;IILkotlin/jvm/internal/DefaultConstructorMarker;)V\n\tpublic final fun getDrawable ()Landroid/graphics/drawable/Drawable;\n}\n\npublic abstract interface class com/squareup/picasso3/Transformation {\n\tpublic abstract fun key ()Ljava/lang/String;\n\tpublic abstract fun transform (Lcom/squareup/picasso3/RequestHandler$Result$Bitmap;)Lcom/squareup/picasso3/RequestHandler$Result$Bitmap;\n}\n\n"
  },
  {
    "path": "picasso/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'com.vanniktech.maven.publish'\n\nandroid {\n  namespace 'com.squareup.picasso3'\n\n  compileSdkVersion libs.versions.compileSdk.get() as int\n\n  defaultConfig {\n    minSdkVersion libs.versions.minSdk.get() as int\n    consumerProguardFiles 'consumer-proguard-rules.txt'\n\n    testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'\n  }\n\n  compileOptions {\n    sourceCompatibility libs.versions.javaTarget.get()\n    targetCompatibility libs.versions.javaTarget.get()\n  }\n\n  kotlinOptions {\n    jvmTarget = libs.versions.javaTarget.get()\n  }\n\n  lintOptions {\n    textOutput 'stdout'\n    textReport true\n    lintConfig rootProject.file('lint.xml')\n  }\n\n  testOptions {\n    unitTests {\n      includeAndroidResources = true\n    }\n  }\n}\n\ndependencies {\n  api libs.okhttp\n  api libs.okio\n  api libs.androidx.lifecycle\n  implementation libs.androidx.annotations\n  implementation libs.androidx.core\n  implementation libs.androidx.exifInterface\n\n  testImplementation libs.coroutines.test\n  testImplementation libs.junit\n  testImplementation libs.truth\n  testImplementation libs.robolectric\n  testImplementation libs.mockito\n  testImplementation libs.okhttp.mockWebServer\n\n  androidTestImplementation libs.androidx.junit\n  androidTestImplementation libs.androidx.testRunner\n  androidTestImplementation libs.truth\n}\n\nspotless {\n  kotlin {\n    targetExclude(\n      // Non-Square licensed files\n      \"src/test/java/com/squareup/picasso3/PlatformLruCacheTest.kt\",\n    )\n  }\n}\n"
  },
  {
    "path": "picasso/consumer-proguard-rules.txt",
    "content": "### OKHTTP\n\n# Platform calls Class.forName on types which do not exist on Android to determine platform.\n-dontnote okhttp3.internal.Platform\n\n\n### OKIO\n\n# java.nio.file.* usage which cannot be used at runtime. Animal sniffer annotation.\n-dontwarn okio.Okio\n# JDK 7-only method which is @hide on Android. Animal sniffer annotation.\n-dontwarn okio.DeflaterSink\n"
  },
  {
    "path": "picasso/gradle.properties",
    "content": "POM_ARTIFACT_ID=picasso\nPOM_NAME=Picasso\nPOM_DESCRIPTION=A powerful image downloading and caching library for Android\nPOM_PACKAGING=aar\n"
  },
  {
    "path": "picasso/src/androidTest/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n  <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n\n</manifest>\n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/AssetRequestHandlerTest.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.net.Uri\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport com.google.common.truth.Truth.assertThat\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\n@RunWith(AndroidJUnit4::class)\nclass AssetRequestHandlerTest {\n  @Test fun truncatesFilePrefix() {\n    val uri = Uri.parse(\"file:///android_asset/foo/bar.png\")\n    val request = Request.Builder(uri).build()\n\n    val actual = AssetRequestHandler.getFilePath(request)\n    assertThat(actual).isEqualTo(\"foo/bar.png\")\n  }\n}\n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/BitmapUtilsTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config.RGB_565\nimport android.graphics.BitmapFactory\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.BitmapUtils.calculateInSampleSize\nimport com.squareup.picasso3.BitmapUtils.createBitmapOptions\nimport com.squareup.picasso3.BitmapUtils.requiresInSampleSize\nimport com.squareup.picasso3.TestUtils.URI_1\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\n@RunWith(AndroidJUnit4::class)\nclass BitmapUtilsTest {\n\n  @Test fun bitmapConfig() {\n    for (config in Bitmap.Config.values()) {\n      val data = Request.Builder(URI_1).config(config).build()\n      val copy = data.newBuilder().build()\n\n      assertThat(createBitmapOptions(data)!!.inPreferredConfig).isSameInstanceAs(config)\n      assertThat(createBitmapOptions(copy)!!.inPreferredConfig).isSameInstanceAs(config)\n    }\n  }\n\n  @Test fun requiresComputeInSampleSize() {\n    assertThat(requiresInSampleSize(null)).isFalse()\n\n    val defaultOptions = BitmapFactory.Options()\n    assertThat(requiresInSampleSize(defaultOptions)).isFalse()\n\n    val justBounds = BitmapFactory.Options().apply { inJustDecodeBounds = true }\n    assertThat(requiresInSampleSize(justBounds)).isTrue()\n  }\n\n  @Test fun calculateInSampleSizeNoResize() {\n    val options = BitmapFactory.Options()\n    val data = Request.Builder(URI_1).build()\n    calculateInSampleSize(100, 100, 150, 150, options, data)\n    assertThat(options.inSampleSize).isEqualTo(1)\n  }\n\n  @Test fun calculateInSampleSizeResize() {\n    val options = BitmapFactory.Options()\n    val data = Request.Builder(URI_1).build()\n    calculateInSampleSize(100, 100, 200, 200, options, data)\n    assertThat(options.inSampleSize).isEqualTo(2)\n  }\n\n  @Test fun calculateInSampleSizeResizeCenterInside() {\n    val options = BitmapFactory.Options()\n    val data = Request.Builder(URI_1).centerInside().resize(100, 100).build()\n    calculateInSampleSize(data.targetWidth, data.targetHeight, 400, 200, options, data)\n    assertThat(options.inSampleSize).isEqualTo(4)\n  }\n\n  @Test fun calculateInSampleSizeKeepAspectRatioWithWidth() {\n    val options = BitmapFactory.Options()\n    val data = Request.Builder(URI_1).resize(400, 0).build()\n    calculateInSampleSize(data.targetWidth, data.targetHeight, 800, 200, options, data)\n    assertThat(options.inSampleSize).isEqualTo(2)\n  }\n\n  @Test fun calculateInSampleSizeKeepAspectRatioWithHeight() {\n    val options = BitmapFactory.Options()\n    val data = Request.Builder(URI_1).resize(0, 100).build()\n    calculateInSampleSize(data.targetWidth, data.targetHeight, 800, 200, options, data)\n    assertThat(options.inSampleSize).isEqualTo(2)\n  }\n\n  @Test fun nullBitmapOptionsIfNoResizing() {\n    // No resize must return no bitmap options\n    val noResize = Request.Builder(URI_1).build()\n    val noResizeOptions = createBitmapOptions(noResize)\n    assertThat(noResizeOptions).isNull()\n  }\n\n  @Test fun inJustDecodeBoundsIfResizing() {\n    // Resize must return bitmap options with inJustDecodeBounds = true\n    val requiresResize = Request.Builder(URI_1).resize(20, 15).build()\n    val resizeOptions = createBitmapOptions(requiresResize)\n    assertThat(resizeOptions).isNotNull()\n    assertThat(resizeOptions!!.inJustDecodeBounds).isTrue()\n  }\n\n  @Test fun createWithConfigAndNotInJustDecodeBounds() {\n    // Given a config, must return bitmap options and false inJustDecodeBounds\n    val config = Request.Builder(URI_1).config(RGB_565).build()\n    val configOptions = createBitmapOptions(config)\n    assertThat(configOptions).isNotNull()\n    assertThat(configOptions!!.inJustDecodeBounds).isFalse()\n  }\n}\n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/PicassoDrawableTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap\nimport android.graphics.Color.RED\nimport android.graphics.drawable.ColorDrawable\nimport android.graphics.drawable.Drawable\nimport androidx.test.core.app.ApplicationProvider\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.Picasso.LoadedFrom.DISK\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\n@RunWith(AndroidJUnit4::class)\nclass PicassoDrawableTest {\n  private val placeholder: Drawable = ColorDrawable(RED)\n  private val bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8)\n\n  @Test fun createWithNoPlaceholderAnimation() {\n    val pd = PicassoDrawable(\n      placeholder = null,\n      context = ApplicationProvider.getApplicationContext(),\n      bitmap = bitmap,\n      loadedFrom = DISK,\n      noFade = false,\n      debugging = false\n    )\n    assertThat(pd.bitmap).isSameInstanceAs(bitmap)\n    assertThat(pd.placeholder).isNull()\n    assertThat(pd.animating).isTrue()\n  }\n\n  @Test fun createWithPlaceholderAnimation() {\n    val pd = PicassoDrawable(\n      context = ApplicationProvider.getApplicationContext(),\n      bitmap = bitmap,\n      placeholder,\n      loadedFrom = DISK,\n      noFade = false,\n      debugging = false\n    )\n    assertThat(pd.bitmap).isSameInstanceAs(bitmap)\n    assertThat(pd.placeholder).isSameInstanceAs(placeholder)\n    assertThat(pd.animating).isTrue()\n  }\n\n  @Test fun createWithBitmapCacheHit() {\n    val pd = PicassoDrawable(\n      context = ApplicationProvider.getApplicationContext(),\n      bitmap = bitmap,\n      placeholder,\n      loadedFrom = Picasso.LoadedFrom.MEMORY,\n      noFade = false,\n      debugging = false\n    )\n    assertThat(pd.bitmap).isSameInstanceAs(bitmap)\n    assertThat(pd.placeholder).isNull()\n    assertThat(pd.animating).isFalse()\n  }\n}\n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/PlatformLruCacheTest.kt",
    "content": "/*\n * Copyright (C) 2011 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config.ALPHA_8\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport com.google.common.truth.Truth.assertThat\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\n@RunWith(AndroidJUnit4::class)\nclass PlatformLruCacheTest {\n  // The use of ALPHA_8 simplifies the size math in tests since only one byte is used per-pixel.\n  private val bitmapA = Bitmap.createBitmap(1, 1, ALPHA_8)\n  private val bitmapB = Bitmap.createBitmap(1, 1, ALPHA_8)\n  private val bitmapC = Bitmap.createBitmap(1, 1, ALPHA_8)\n  private val bitmapD = Bitmap.createBitmap(1, 1, ALPHA_8)\n  private val bitmapE = Bitmap.createBitmap(1, 1, ALPHA_8)\n\n  private var expectedPutCount = 0\n  private var expectedHitCount = 0\n  private var expectedMissCount = 0\n  private var expectedEvictionCount = 0\n\n  @Test fun testStatistics() {\n    val cache = PlatformLruCache(3)\n    assertStatistics(cache)\n\n    cache[\"a\"] = bitmapA\n    expectedPutCount++\n    assertStatistics(cache)\n    assertHit(cache, \"a\", bitmapA)\n\n    cache[\"b\"] = bitmapB\n    expectedPutCount++\n    assertStatistics(cache)\n    assertHit(cache, \"a\", bitmapA)\n    assertHit(cache, \"b\", bitmapB)\n    assertSnapshot(cache, \"a\", bitmapA, \"b\", bitmapB)\n\n    cache[\"c\"] = bitmapC\n    expectedPutCount++\n    assertStatistics(cache)\n    assertHit(cache, \"a\", bitmapA)\n    assertHit(cache, \"b\", bitmapB)\n    assertHit(cache, \"c\", bitmapC)\n    assertSnapshot(cache, \"a\", bitmapA, \"b\", bitmapB, \"c\", bitmapC)\n\n    cache[\"d\"] = bitmapD\n    expectedPutCount++\n    expectedEvictionCount++ // a should have been evicted\n    assertStatistics(cache)\n    assertMiss(cache, \"a\")\n    assertHit(cache, \"b\", bitmapB)\n    assertHit(cache, \"c\", bitmapC)\n    assertHit(cache, \"d\", bitmapD)\n    assertHit(cache, \"b\", bitmapB)\n    assertHit(cache, \"c\", bitmapC)\n    assertSnapshot(cache, \"d\", bitmapD, \"b\", bitmapB, \"c\", bitmapC)\n\n    cache[\"e\"] = bitmapE\n    expectedPutCount++\n    expectedEvictionCount++ // d should have been evicted\n    assertStatistics(cache)\n    assertMiss(cache, \"d\")\n    assertMiss(cache, \"a\")\n    assertHit(cache, \"e\", bitmapE)\n    assertHit(cache, \"b\", bitmapB)\n    assertHit(cache, \"c\", bitmapC)\n    assertSnapshot(cache, \"e\", bitmapE, \"b\", bitmapB, \"c\", bitmapC)\n  }\n\n  @Test fun evictionWithSingletonCache() {\n    val cache = PlatformLruCache(1)\n    cache[\"a\"] = bitmapA\n    cache[\"b\"] = bitmapB\n    assertSnapshot(cache, \"b\", bitmapB)\n  }\n\n  /**\n   * Replacing the value for a key doesn't cause an eviction but it does bring the replaced entry to\n   * the front of the queue.\n   */\n  @Test fun putCauseEviction() {\n    val cache = PlatformLruCache(3)\n\n    cache[\"a\"] = bitmapA\n    cache[\"b\"] = bitmapB\n    cache[\"c\"] = bitmapC\n    cache[\"b\"] = bitmapD\n    assertSnapshot(cache, \"a\", bitmapA, \"c\", bitmapC, \"b\", bitmapD)\n  }\n\n  @Test fun evictAll() {\n    val cache = PlatformLruCache(4)\n    cache[\"a\"] = bitmapA\n    cache[\"b\"] = bitmapB\n    cache[\"c\"] = bitmapC\n    cache.clear()\n    assertThat(cache.cache.snapshot()).isEmpty()\n  }\n\n  @Test fun clearPrefixedKey() {\n    val cache = PlatformLruCache(3)\n\n    cache[\"Hello\\nAlice!\"] = bitmapA\n    cache[\"Hello\\nBob!\"] = bitmapB\n    cache[\"Hello\\nEve!\"] = bitmapC\n    cache[\"Hellos\\nWorld!\"] = bitmapD\n\n    cache.clearKeyUri(\"Hello\")\n    assertThat(cache.cache.snapshot()).hasSize(1)\n    assertThat(cache.cache.snapshot()).containsKey(\"Hellos\\nWorld!\")\n  }\n\n  @Test fun invalidate() {\n    val cache = PlatformLruCache(3)\n    cache[\"Hello\\nAlice!\"] = bitmapA\n    assertThat(cache.size()).isEqualTo(1)\n    cache.clearKeyUri(\"Hello\")\n    assertThat(cache.size()).isEqualTo(0)\n  }\n\n  @Test fun overMaxSizeDoesNotClear() {\n    val cache = PlatformLruCache(16)\n    val size4 = Bitmap.createBitmap(2, 2, ALPHA_8)\n    val size16 = Bitmap.createBitmap(4, 4, ALPHA_8)\n    val size25 = Bitmap.createBitmap(5, 5, ALPHA_8)\n    cache[\"4\"] = size4\n    expectedPutCount++\n    assertHit(cache, \"4\", size4)\n    cache[\"16\"] = size16\n    expectedPutCount++\n    expectedEvictionCount++ // size4 was evicted.\n    assertMiss(cache, \"4\")\n    assertHit(cache, \"16\", size16)\n    cache[\"25\"] = size25\n    assertHit(cache, \"16\", size16)\n    assertMiss(cache, \"25\")\n    assertThat(cache.size()).isEqualTo(16)\n  }\n\n  @Test fun overMaxSizeRemovesExisting() {\n    val cache = PlatformLruCache(20)\n    val size4 = Bitmap.createBitmap(2, 2, ALPHA_8)\n    val size16 = Bitmap.createBitmap(4, 4, ALPHA_8)\n    val size25 = Bitmap.createBitmap(5, 5, ALPHA_8)\n    cache[\"small\"] = size4\n    expectedPutCount++\n    assertHit(cache, \"small\", size4)\n    cache[\"big\"] = size16\n    expectedPutCount++\n    assertHit(cache, \"small\", size4)\n    assertHit(cache, \"big\", size16)\n    cache[\"big\"] = size25\n    assertHit(cache, \"small\", size4)\n    assertMiss(cache, \"big\")\n    assertThat(cache.size()).isEqualTo(4)\n  }\n\n  private fun assertHit(cache: PlatformLruCache, key: String, value: Bitmap) {\n    assertThat(cache[key]).isEqualTo(value)\n    expectedHitCount++\n    assertStatistics(cache)\n  }\n\n  private fun assertMiss(cache: PlatformLruCache, key: String) {\n    assertThat(cache[key]).isNull()\n    expectedMissCount++\n    assertStatistics(cache)\n  }\n\n  private fun assertStatistics(cache: PlatformLruCache) {\n    assertThat(cache.putCount()).isEqualTo(expectedPutCount)\n    assertThat(cache.hitCount()).isEqualTo(expectedHitCount)\n    assertThat(cache.missCount()).isEqualTo(expectedMissCount)\n    assertThat(cache.evictionCount()).isEqualTo(expectedEvictionCount)\n  }\n\n  @OptIn(ExperimentalStdlibApi::class)\n  private fun assertSnapshot(cache: PlatformLruCache, vararg keysAndValues: Any) {\n    val actualKeysAndValues = buildList {\n      cache.cache.snapshot().forEach { (key, value) ->\n        add(key)\n        add(value.bitmap)\n      }\n    }\n\n    // assert using lists because order is important for LRUs\n    assertThat(actualKeysAndValues).isEqualTo(listOf(*keysAndValues))\n  }\n}\n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/TestUtils.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.net.Uri\n\nobject TestUtils {\n  val URI_1: Uri = Uri.parse(\"http://example.com/1.png\")\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Action.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport com.squareup.picasso3.RequestHandler.Result\n\ninternal abstract class Action(\n  val picasso: Picasso,\n  val request: Request\n) {\n  var willReplay = false\n  var cancelled = false\n\n  abstract fun complete(result: Result)\n  abstract fun error(e: Exception)\n\n  abstract fun getTarget(): Any?\n\n  open fun cancel() {\n    cancelled = true\n  }\n\n  val tag: Any\n    get() = request.tag ?: this\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/AssetRequestHandler.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.ContentResolver\nimport android.content.Context\nimport android.content.res.AssetManager\nimport com.squareup.picasso3.BitmapUtils.decodeStream\nimport com.squareup.picasso3.Picasso.LoadedFrom.DISK\nimport okio.source\n\ninternal class AssetRequestHandler(private val context: Context) : RequestHandler() {\n  private val lock = Any()\n\n  @Volatile\n  private var assetManager: AssetManager? = null\n\n  override fun canHandleRequest(data: Request): Boolean {\n    val uri = data.uri\n    return uri != null &&\n      ContentResolver.SCHEME_FILE == uri.scheme &&\n      uri.pathSegments.isNotEmpty() &&\n      ANDROID_ASSET == uri.pathSegments[0]\n  }\n\n  override fun load(\n    picasso: Picasso,\n    request: Request,\n    callback: Callback\n  ) {\n    initializeIfFirstTime()\n    var signaledCallback = false\n    try {\n      assetManager!!.open(getFilePath(request))\n        .source()\n        .use { source ->\n          val bitmap = decodeStream(source, request)\n          signaledCallback = true\n          callback.onSuccess(Result.Bitmap(bitmap, DISK))\n        }\n    } catch (e: Exception) {\n      if (!signaledCallback) {\n        callback.onError(e)\n      }\n    }\n  }\n\n  @Initializer private fun initializeIfFirstTime() {\n    if (assetManager == null) {\n      synchronized(lock) {\n        if (assetManager == null) {\n          assetManager = context.assets\n        }\n      }\n    }\n  }\n\n  companion object {\n    private const val ANDROID_ASSET = \"android_asset\"\n    private const val ASSET_PREFIX_LENGTH =\n      \"${ContentResolver.SCHEME_FILE}:///$ANDROID_ASSET/\".length\n\n    fun getFilePath(request: Request): String {\n      val uri = checkNotNull(request.uri)\n      return uri.toString()\n        .substring(ASSET_PREFIX_LENGTH)\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BaseDispatcher.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.Manifest.permission.ACCESS_NETWORK_STATE\nimport android.annotation.SuppressLint\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.Intent.ACTION_AIRPLANE_MODE_CHANGED\nimport android.content.IntentFilter\nimport android.net.ConnectivityManager\nimport android.net.ConnectivityManager.CONNECTIVITY_ACTION\nimport android.net.NetworkInfo\nimport android.os.Handler\nimport android.util.Log\nimport androidx.annotation.CallSuper\nimport androidx.annotation.MainThread\nimport androidx.core.content.ContextCompat\nimport com.squareup.picasso3.BitmapHunter.Companion.forRequest\nimport com.squareup.picasso3.MemoryPolicy.Companion.shouldWriteToMemoryCache\nimport com.squareup.picasso3.NetworkPolicy.NO_CACHE\nimport com.squareup.picasso3.NetworkRequestHandler.ContentLengthException\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport com.squareup.picasso3.Utils.OWNER_DISPATCHER\nimport com.squareup.picasso3.Utils.VERB_CANCELED\nimport com.squareup.picasso3.Utils.VERB_DELIVERED\nimport com.squareup.picasso3.Utils.VERB_ENQUEUED\nimport com.squareup.picasso3.Utils.VERB_IGNORED\nimport com.squareup.picasso3.Utils.VERB_PAUSED\nimport com.squareup.picasso3.Utils.VERB_REPLAYING\nimport com.squareup.picasso3.Utils.VERB_RETRYING\nimport com.squareup.picasso3.Utils.getLogIdsForHunter\nimport com.squareup.picasso3.Utils.hasPermission\nimport com.squareup.picasso3.Utils.isAirplaneModeOn\nimport com.squareup.picasso3.Utils.log\nimport java.util.WeakHashMap\n\ninternal abstract class BaseDispatcher internal constructor(\n  private val context: Context,\n  private val mainThreadHandler: Handler,\n  private val cache: PlatformLruCache\n) : Dispatcher {\n  @get:JvmName(\"-hunterMap\")\n  internal val hunterMap = mutableMapOf<String, BitmapHunter>()\n\n  @get:JvmName(\"-failedActions\")\n  internal val failedActions = WeakHashMap<Any, Action>()\n\n  @get:JvmName(\"-pausedActions\")\n  internal val pausedActions = WeakHashMap<Any, Action>()\n\n  @get:JvmName(\"-pausedTags\")\n  internal val pausedTags = mutableSetOf<Any>()\n\n  @get:JvmName(\"-receiver\")\n  internal val receiver: NetworkBroadcastReceiver\n\n  @get:JvmName(\"-airplaneMode\")\n  @set:JvmName(\"-airplaneMode\")\n  internal var airplaneMode = isAirplaneModeOn(context)\n\n  private val scansNetworkChanges: Boolean\n\n  init {\n    scansNetworkChanges = hasPermission(context, ACCESS_NETWORK_STATE)\n    receiver = NetworkBroadcastReceiver(this)\n    receiver.register()\n  }\n\n  @CallSuper override fun shutdown() {\n    // Unregister network broadcast receiver on the main thread.\n    mainThreadHandler.post { receiver.unregister() }\n  }\n\n  fun performSubmit(action: Action, dismissFailed: Boolean = true) {\n    if (action.tag in pausedTags) {\n      pausedActions[action.getTarget()] = action\n      if (action.picasso.isLoggingEnabled) {\n        log(\n          owner = OWNER_DISPATCHER,\n          verb = VERB_PAUSED,\n          logId = action.request.logId(),\n          extras = \"because tag '${action.tag}' is paused\"\n        )\n      }\n      return\n    }\n\n    var hunter = hunterMap[action.request.key]\n    if (hunter != null) {\n      hunter.attach(action)\n      return\n    }\n\n    if (isShutdown()) {\n      if (action.picasso.isLoggingEnabled) {\n        log(\n          owner = OWNER_DISPATCHER,\n          verb = VERB_IGNORED,\n          logId = action.request.logId(),\n          extras = \"because shut down\"\n        )\n      }\n      return\n    }\n\n    hunter = forRequest(action.picasso, this, cache, action)\n    dispatchSubmit(hunter)\n    hunterMap[action.request.key] = hunter\n    if (dismissFailed) {\n      failedActions.remove(action.getTarget())\n    }\n\n    if (action.picasso.isLoggingEnabled) {\n      log(owner = OWNER_DISPATCHER, verb = VERB_ENQUEUED, logId = action.request.logId())\n    }\n  }\n\n  fun performCancel(action: Action) {\n    val key = action.request.key\n    val hunter = hunterMap[key]\n    if (hunter != null) {\n      hunter.detach(action)\n      if (hunter.cancel()) {\n        hunterMap.remove(key)\n        if (action.picasso.isLoggingEnabled) {\n          log(OWNER_DISPATCHER, VERB_CANCELED, action.request.logId())\n        }\n      }\n    }\n\n    if (action.tag in pausedTags) {\n      pausedActions.remove(action.getTarget())\n      if (action.picasso.isLoggingEnabled) {\n        log(\n          owner = OWNER_DISPATCHER,\n          verb = VERB_CANCELED,\n          logId = action.request.logId(),\n          extras = \"because paused request got canceled\"\n        )\n      }\n    }\n\n    val remove = failedActions.remove(action.getTarget())\n    if (remove != null && remove.picasso.isLoggingEnabled) {\n      log(OWNER_DISPATCHER, VERB_CANCELED, remove.request.logId(), \"from replaying\")\n    }\n  }\n\n  fun performPauseTag(tag: Any) {\n    // Trying to pause a tag that is already paused.\n    if (!pausedTags.add(tag)) {\n      return\n    }\n\n    // Go through all active hunters and detach/pause the requests\n    // that have the paused tag.\n    val iterator = hunterMap.values.iterator()\n    while (iterator.hasNext()) {\n      val hunter = iterator.next()\n      val loggingEnabled = hunter.picasso.isLoggingEnabled\n\n      val single = hunter.action\n      val joined = hunter.actions\n      val hasMultiple = !joined.isNullOrEmpty()\n\n      // Hunter has no requests, bail early.\n      if (single == null && !hasMultiple) {\n        continue\n      }\n\n      if (single != null && single.tag == tag) {\n        hunter.detach(single)\n        pausedActions[single.getTarget()] = single\n        if (loggingEnabled) {\n          log(\n            owner = OWNER_DISPATCHER,\n            verb = VERB_PAUSED,\n            logId = single.request.logId(),\n            extras = \"because tag '$tag' was paused\"\n          )\n        }\n      }\n\n      if (joined != null) {\n        for (i in joined.indices.reversed()) {\n          val action = joined[i]\n          if (action.tag != tag) {\n            continue\n          }\n          hunter.detach(action)\n          pausedActions[action.getTarget()] = action\n          if (loggingEnabled) {\n            log(\n              owner = OWNER_DISPATCHER,\n              verb = VERB_PAUSED,\n              logId = action.request.logId(),\n              extras = \"because tag '$tag' was paused\"\n            )\n          }\n        }\n      }\n\n      // Check if the hunter can be cancelled in case all its requests\n      // had the tag being paused here.\n      if (hunter.cancel()) {\n        iterator.remove()\n        if (loggingEnabled) {\n          log(\n            owner = OWNER_DISPATCHER,\n            verb = VERB_CANCELED,\n            logId = getLogIdsForHunter(hunter),\n            extras = \"all actions paused\"\n          )\n        }\n      }\n    }\n  }\n\n  fun performResumeTag(tag: Any) {\n    // Trying to resume a tag that is not paused.\n    if (!pausedTags.remove(tag)) {\n      return\n    }\n\n    val batch = mutableListOf<Action>()\n    val iterator = pausedActions.values.iterator()\n    while (iterator.hasNext()) {\n      val action = iterator.next()\n      if (action.tag == tag) {\n        batch += action\n        iterator.remove()\n      }\n    }\n\n    if (batch.isNotEmpty()) {\n      dispatchBatchResumeMain(batch)\n    }\n  }\n\n  @SuppressLint(\"MissingPermission\")\n  fun performRetry(hunter: BitmapHunter) {\n    if (hunter.isCancelled) return\n\n    if (isShutdown()) {\n      performError(hunter)\n      return\n    }\n\n    var networkInfo: NetworkInfo? = null\n    if (scansNetworkChanges) {\n      val connectivityManager =\n        ContextCompat.getSystemService(context, ConnectivityManager::class.java)\n      if (connectivityManager != null) {\n        networkInfo = connectivityManager.activeNetworkInfo\n      }\n    }\n\n    if (hunter.shouldRetry(airplaneMode, networkInfo)) {\n      if (hunter.picasso.isLoggingEnabled) {\n        log(\n          owner = OWNER_DISPATCHER,\n          verb = VERB_RETRYING,\n          logId = getLogIdsForHunter(hunter)\n        )\n      }\n      if (hunter.exception is ContentLengthException) {\n        hunter.data = hunter.data.newBuilder().networkPolicy(NO_CACHE).build()\n      }\n      dispatchSubmit(hunter)\n    } else {\n      performError(hunter)\n      // Mark for replay only if we observe network info changes and support replay.\n      if (scansNetworkChanges && hunter.supportsReplay()) {\n        markForReplay(hunter)\n      }\n    }\n  }\n\n  fun performComplete(hunter: BitmapHunter) {\n    if (shouldWriteToMemoryCache(hunter.data.memoryPolicy)) {\n      val result = hunter.result\n      if (result != null) {\n        if (result is Bitmap) {\n          val bitmap = result.bitmap\n          cache[hunter.key] = bitmap\n        }\n      }\n    }\n    hunterMap.remove(hunter.key)\n    deliver(hunter)\n  }\n\n  fun performError(hunter: BitmapHunter) {\n    hunterMap.remove(hunter.key)\n    deliver(hunter)\n  }\n\n  fun performAirplaneModeChange(airplaneMode: Boolean) {\n    this.airplaneMode = airplaneMode\n  }\n\n  fun performNetworkStateChange(info: NetworkInfo?) {\n    // Intentionally check only if isConnected() here before we flush out failed actions.\n    if (info != null && info.isConnected) {\n      flushFailedActions()\n    }\n  }\n\n  @MainThread\n  fun performCompleteMain(hunter: BitmapHunter) {\n    hunter.picasso.complete(hunter)\n  }\n\n  @MainThread\n  fun performBatchResumeMain(batch: List<Action>) {\n    for (i in batch.indices) {\n      val action = batch[i]\n      action.picasso.resumeAction(action)\n    }\n  }\n\n  private fun flushFailedActions() {\n    if (failedActions.isNotEmpty()) {\n      val iterator = failedActions.values.iterator()\n      while (iterator.hasNext()) {\n        val action = iterator.next()\n        iterator.remove()\n        if (action.picasso.isLoggingEnabled) {\n          log(\n            owner = OWNER_DISPATCHER,\n            verb = VERB_REPLAYING,\n            logId = action.request.logId()\n          )\n        }\n        performSubmit(action, false)\n      }\n    }\n  }\n\n  private fun markForReplay(hunter: BitmapHunter) {\n    hunter.action?.let { markForReplay(it) }\n    hunter.actions?.forEach { markForReplay(it) }\n  }\n\n  private fun markForReplay(action: Action) {\n    val target = action.getTarget()\n    action.willReplay = true\n    failedActions[target] = action\n  }\n\n  private fun deliver(hunter: BitmapHunter) {\n    if (hunter.isCancelled) {\n      return\n    }\n    val result = hunter.result\n    if (result != null) {\n      if (result is Bitmap) {\n        val bitmap = result.bitmap\n        bitmap.prepareToDraw()\n      }\n    }\n\n    dispatchCompleteMain(hunter)\n    logDelivery(hunter)\n  }\n\n  private fun logDelivery(bitmapHunter: BitmapHunter) {\n    val picasso = bitmapHunter.picasso\n    if (picasso.isLoggingEnabled) {\n      log(\n        owner = OWNER_DISPATCHER,\n        verb = VERB_DELIVERED,\n        logId = getLogIdsForHunter(bitmapHunter)\n      )\n    }\n  }\n\n  internal class NetworkBroadcastReceiver(\n    private val dispatcher: BaseDispatcher\n  ) : BroadcastReceiver() {\n    fun register() {\n      val filter = IntentFilter()\n      filter.addAction(ACTION_AIRPLANE_MODE_CHANGED)\n      if (dispatcher.scansNetworkChanges) {\n        filter.addAction(CONNECTIVITY_ACTION)\n      }\n      dispatcher.context.registerReceiver(this, filter)\n    }\n\n    fun unregister() {\n      dispatcher.context.unregisterReceiver(this)\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    override fun onReceive(context: Context, intent: Intent?) {\n      // On some versions of Android this may be called with a null Intent,\n      // also without extras (getExtras() == null), in such case we use defaults.\n      if (intent == null) {\n        return\n      }\n      when (intent.action) {\n        ACTION_AIRPLANE_MODE_CHANGED -> {\n          if (!intent.hasExtra(EXTRA_AIRPLANE_STATE)) {\n            return // No airplane state, ignore it. Should we query Utils.isAirplaneModeOn?\n          }\n          dispatcher.dispatchAirplaneModeChange(intent.getBooleanExtra(EXTRA_AIRPLANE_STATE, false))\n        }\n        CONNECTIVITY_ACTION -> {\n          val connectivityManager =\n            ContextCompat.getSystemService(context, ConnectivityManager::class.java)\n          val networkInfo = try {\n            connectivityManager!!.activeNetworkInfo\n          } catch (re: RuntimeException) {\n            Log.w(TAG, \"System UI crashed, ignoring attempt to change network state.\")\n            return\n          }\n          if (networkInfo == null) {\n            Log.w(\n              TAG,\n              \"No default network is currently active, ignoring attempt to change network state.\"\n            )\n            return\n          }\n          dispatcher.dispatchNetworkStateChange(networkInfo)\n        }\n      }\n    }\n\n    internal companion object {\n      const val EXTRA_AIRPLANE_STATE = \"state\"\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BitmapHunter.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.net.NetworkInfo\nimport com.squareup.picasso3.MemoryPolicy.Companion.shouldReadFromMemoryCache\nimport com.squareup.picasso3.Picasso.LoadedFrom\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport com.squareup.picasso3.Utils.OWNER_HUNTER\nimport com.squareup.picasso3.Utils.THREAD_PREFIX\nimport com.squareup.picasso3.Utils.VERB_DECODED\nimport com.squareup.picasso3.Utils.VERB_EXECUTING\nimport com.squareup.picasso3.Utils.VERB_JOINED\nimport com.squareup.picasso3.Utils.VERB_REMOVED\nimport com.squareup.picasso3.Utils.VERB_TRANSFORMED\nimport com.squareup.picasso3.Utils.getLogIdsForHunter\nimport com.squareup.picasso3.Utils.log\nimport java.io.IOException\nimport java.io.InterruptedIOException\nimport java.util.concurrent.CountDownLatch\nimport java.util.concurrent.Future\nimport java.util.concurrent.atomic.AtomicInteger\nimport java.util.concurrent.atomic.AtomicReference\nimport kotlinx.coroutines.Job\n\ninternal open class BitmapHunter(\n  val picasso: Picasso,\n  private val dispatcher: Dispatcher,\n  private val cache: PlatformLruCache,\n  action: Action,\n  val requestHandler: RequestHandler\n) : Runnable {\n  val sequence: Int = SEQUENCE_GENERATOR.incrementAndGet()\n  var priority: Picasso.Priority = action.request.priority\n  var data: Request = action.request\n  val key: String = action.request.key\n  var retryCount: Int = requestHandler.retryCount\n\n  var action: Action? = action\n    private set\n  var actions: MutableList<Action>? = null\n    private set\n\n  var future: Future<*>? = null\n\n  var job: Job? = null\n\n  var result: RequestHandler.Result? = null\n    private set\n  var exception: Exception? = null\n    private set\n\n  val isCancelled: Boolean\n    get() = future?.isCancelled ?: job?.isCancelled ?: false\n\n  override fun run() {\n    val originalName = Thread.currentThread().name\n    try {\n      Thread.currentThread().name = getName()\n\n      if (picasso.isLoggingEnabled) {\n        log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this))\n      }\n\n      result = hunt()\n      dispatcher.dispatchComplete(this)\n    } catch (e: IOException) {\n      exception = e\n      if (retryCount > 0) {\n        dispatcher.dispatchRetry(this)\n      } else {\n        dispatcher.dispatchFailed(this)\n      }\n    } catch (e: Exception) {\n      exception = e\n      dispatcher.dispatchFailed(this)\n    } finally {\n      Thread.currentThread().name = originalName\n    }\n  }\n\n  fun getName() = NAME_BUILDER.get()!!.also {\n    val name = data.name\n    it.ensureCapacity(THREAD_PREFIX.length + name.length)\n    it.replace(THREAD_PREFIX.length, it.length, name)\n  }.toString()\n\n  fun hunt(): Bitmap? {\n    if (shouldReadFromMemoryCache(data.memoryPolicy)) {\n      cache[key]?.let { bitmap ->\n        picasso.cacheHit()\n        if (picasso.isLoggingEnabled) {\n          log(OWNER_HUNTER, VERB_DECODED, data.logId(), \"from cache\")\n        }\n\n        return Bitmap(bitmap, LoadedFrom.MEMORY)\n      }\n    }\n\n    if (retryCount == 0) {\n      data = data.newBuilder().networkPolicy(NetworkPolicy.OFFLINE).build()\n    }\n\n    val resultReference = AtomicReference<RequestHandler.Result?>()\n    val exceptionReference = AtomicReference<Throwable>()\n\n    val latch = CountDownLatch(1)\n    try {\n      requestHandler.load(\n        picasso = picasso,\n        request = data,\n        callback = object : RequestHandler.Callback {\n          override fun onSuccess(result: RequestHandler.Result?) {\n            resultReference.set(result)\n            latch.countDown()\n          }\n\n          override fun onError(t: Throwable) {\n            exceptionReference.set(t)\n            latch.countDown()\n          }\n        }\n      )\n\n      latch.await()\n    } catch (ie: InterruptedException) {\n      val interruptedIoException = InterruptedIOException()\n      interruptedIoException.initCause(ie)\n      throw interruptedIoException\n    }\n\n    exceptionReference.get()?.let { throwable ->\n      when (throwable) {\n        is IOException, is Error, is RuntimeException -> throw throwable\n        else -> throw RuntimeException(throwable)\n      }\n    }\n\n    val result = resultReference.get() as? Bitmap ?: return null\n    val bitmap = result.bitmap\n    if (picasso.isLoggingEnabled) {\n      log(OWNER_HUNTER, VERB_DECODED, data.logId())\n    }\n    picasso.bitmapDecoded(bitmap)\n\n    val transformations = ArrayList<Transformation>(data.transformations.size + 1)\n    if (data.needsMatrixTransform() || result.exifRotation != 0) {\n      transformations += MatrixTransformation(data)\n    }\n    transformations += data.transformations\n\n    val transformedResult =\n      applyTransformations(picasso, data, transformations, result) ?: return null\n    val transformedBitmap = transformedResult.bitmap\n    picasso.bitmapTransformed(transformedBitmap)\n\n    return transformedResult\n  }\n\n  fun attach(action: Action) {\n    val loggingEnabled = picasso.isLoggingEnabled\n    val request = action.request\n    if (this.action == null) {\n      this.action = action\n      if (loggingEnabled) {\n        if (actions.isNullOrEmpty()) {\n          log(OWNER_HUNTER, VERB_JOINED, request.logId(), \"to empty hunter\")\n        } else {\n          log(OWNER_HUNTER, VERB_JOINED, request.logId(), getLogIdsForHunter(this, \"to \"))\n        }\n      }\n\n      return\n    }\n\n    if (actions == null) {\n      actions = ArrayList(3)\n    }\n    actions!!.add(action)\n\n    if (loggingEnabled) {\n      log(OWNER_HUNTER, VERB_JOINED, request.logId(), getLogIdsForHunter(this, \"to \"))\n    }\n\n    val actionPriority = action.request.priority\n    if (actionPriority.ordinal > priority.ordinal) {\n      priority = actionPriority\n    }\n  }\n\n  fun detach(action: Action) {\n    val detached = when {\n      this.action === action -> {\n        this.action = null\n        true\n      }\n      else -> actions?.remove(action) ?: false\n    }\n\n    // The action being detached had the highest priority. Update this\n    // hunter's priority with the remaining actions.\n    if (detached && action.request.priority == priority) {\n      priority = computeNewPriority()\n    }\n\n    if (picasso.isLoggingEnabled) {\n      log(OWNER_HUNTER, VERB_REMOVED, action.request.logId(), getLogIdsForHunter(this, \"from \"))\n    }\n  }\n\n  fun cancel(): Boolean =\n    action == null && actions.isNullOrEmpty() && future?.cancel(false)\n      ?: job?.let {\n        it.cancel()\n        true\n      }\n      ?: false\n\n  fun shouldRetry(airplaneMode: Boolean, info: NetworkInfo?): Boolean {\n    val hasRetries = retryCount > 0\n    if (!hasRetries) {\n      return false\n    }\n    retryCount--\n\n    return requestHandler.shouldRetry(airplaneMode, info)\n  }\n\n  fun supportsReplay(): Boolean = requestHandler.supportsReplay()\n\n  private fun computeNewPriority(): Picasso.Priority {\n    val hasMultiple = actions?.isNotEmpty() ?: false\n    val hasAny = action != null || hasMultiple\n\n    // Hunter has no requests, low priority.\n    if (!hasAny) {\n      return Picasso.Priority.LOW\n    }\n\n    var newPriority = action?.request?.priority ?: Picasso.Priority.LOW\n\n    actions?.let { actions ->\n      // Index-based loop to avoid allocating an iterator.\n      for (i in actions.indices) {\n        val priority = actions[i].request.priority\n        if (priority.ordinal > newPriority.ordinal) {\n          newPriority = priority\n        }\n      }\n    }\n\n    return newPriority\n  }\n\n  companion object {\n    internal val NAME_BUILDER: ThreadLocal<StringBuilder> = object : ThreadLocal<StringBuilder>() {\n      override fun initialValue(): StringBuilder = StringBuilder(THREAD_PREFIX)\n    }\n    val SEQUENCE_GENERATOR = AtomicInteger()\n    internal val ERRORING_HANDLER: RequestHandler = object : RequestHandler() {\n      override fun canHandleRequest(data: Request): Boolean = true\n\n      override fun load(picasso: Picasso, request: Request, callback: Callback) {\n        callback.onError(IllegalStateException(\"Unrecognized type of request: $request\"))\n      }\n    }\n\n    fun forRequest(\n      picasso: Picasso,\n      dispatcher: Dispatcher,\n      cache: PlatformLruCache,\n      action: Action\n    ): BitmapHunter {\n      val request = action.request\n      val requestHandlers = picasso.requestHandlers\n\n      // Index-based loop to avoid allocating an iterator.\n      for (i in requestHandlers.indices) {\n        val requestHandler = requestHandlers[i]\n        if (requestHandler.canHandleRequest(request)) {\n          return BitmapHunter(picasso, dispatcher, cache, action, requestHandler)\n        }\n      }\n\n      return BitmapHunter(picasso, dispatcher, cache, action, ERRORING_HANDLER)\n    }\n\n    fun applyTransformations(\n      picasso: Picasso,\n      data: Request,\n      transformations: List<Transformation>,\n      result: Bitmap\n    ): Bitmap? {\n      var res = result\n\n      for (i in transformations.indices) {\n        val transformation = transformations[i]\n        val newResult = try {\n          val transformedResult = transformation.transform(res)\n          if (picasso.isLoggingEnabled) {\n            log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), \"from transformations\")\n          }\n\n          transformedResult\n        } catch (e: RuntimeException) {\n          Picasso.HANDLER.post {\n            throw RuntimeException(\n              \"Transformation ${transformation.key()} crashed with exception.\",\n              e\n            )\n          }\n\n          return null\n        }\n\n        val bitmap = newResult.bitmap\n        if (bitmap.isRecycled) {\n          Picasso.HANDLER.post {\n            throw IllegalStateException(\n              \"Transformation ${transformation.key()} returned a recycled Bitmap.\"\n            )\n          }\n\n          return null\n        }\n\n        res = newResult\n      }\n\n      return res\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BitmapTarget.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap\nimport android.graphics.drawable.Drawable\nimport com.squareup.picasso3.Picasso.LoadedFrom\n\n/**\n * Represents an arbitrary listener for image loading.\n *\n * Objects implementing this class **must** have a working implementation of\n * [Object.equals] and [Object.hashCode] for proper storage internally.\n * Instances of this interface will also be compared to determine if view recycling is occurring.\n * It is recommended that you add this interface directly on to a custom view type when using in an\n * adapter to ensure correct recycling behavior.\n */\ninterface BitmapTarget {\n  /**\n   * Callback when an image has been successfully loaded.\n   *\n   * **Note:** You must not recycle the bitmap.\n   */\n  fun onBitmapLoaded(\n    bitmap: Bitmap,\n    from: LoadedFrom\n  )\n\n  /**\n   * Callback indicating the image could not be successfully loaded.\n   *\n   * **Note:** The passed [Drawable] may be `null` if none has been\n   * specified via [RequestCreator.error] or [RequestCreator.error].\n   */\n  fun onBitmapFailed(\n    e: Exception,\n    errorDrawable: Drawable?\n  )\n\n  /**\n   * Callback invoked right before your request is submitted.\n   *\n   *\n   * **Note:** The passed [Drawable] may be `null` if none has been\n   * specified via [RequestCreator.placeholder] or [RequestCreator.placeholder].\n   */\n  fun onPrepareLoad(placeHolderDrawable: Drawable?)\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BitmapTargetAction.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.drawable.Drawable\nimport androidx.annotation.DrawableRes\nimport androidx.core.content.ContextCompat\nimport com.squareup.picasso3.RequestHandler.Result\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport java.lang.ref.WeakReference\n\ninternal class BitmapTargetAction(\n  picasso: Picasso,\n  target: BitmapTarget,\n  data: Request,\n  private val errorDrawable: Drawable?,\n  @DrawableRes val errorResId: Int\n) : Action(picasso, data) {\n  private val targetReference = WeakReference(target)\n\n  override fun complete(result: Result) {\n    val target = targetReference.get() ?: return\n\n    if (result is Bitmap) {\n      val bitmap = result.bitmap\n      target.onBitmapLoaded(bitmap, result.loadedFrom)\n      check(!bitmap.isRecycled) { \"Target callback must not recycle bitmap!\" }\n    }\n  }\n\n  override fun error(e: Exception) {\n    val target = targetReference.get() ?: return\n\n    val drawable = if (errorResId != 0) {\n      ContextCompat.getDrawable(picasso.context, errorResId)\n    } else {\n      errorDrawable\n    }\n\n    target.onBitmapFailed(e, drawable)\n  }\n\n  override fun getTarget(): BitmapTarget? {\n    return targetReference.get()\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BitmapUtils.kt",
    "content": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.res.Resources\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.graphics.ImageDecoder\nimport android.os.Build.VERSION\nimport android.util.TypedValue\nimport androidx.annotation.DrawableRes\nimport androidx.annotation.RequiresApi\nimport okio.Buffer\nimport okio.BufferedSource\nimport okio.ForwardingSource\nimport okio.Source\nimport okio.buffer\nimport java.io.IOException\nimport java.nio.ByteBuffer\nimport kotlin.math.max\nimport kotlin.math.min\n\ninternal object BitmapUtils {\n  /**\n   * Lazily create [BitmapFactory.Options] based in given\n   * [Request], only instantiating them if needed.\n   */\n  fun createBitmapOptions(data: Request): BitmapFactory.Options? {\n    val justBounds = data.hasSize()\n    return if (justBounds || data.config != null) {\n      BitmapFactory.Options().apply {\n        inJustDecodeBounds = justBounds\n        if (data.config != null) {\n          inPreferredConfig = data.config\n        }\n      }\n    } else {\n      null\n    }\n  }\n\n  fun requiresInSampleSize(options: BitmapFactory.Options?): Boolean {\n    return options != null && options.inJustDecodeBounds\n  }\n\n  fun calculateInSampleSize(\n    reqWidth: Int,\n    reqHeight: Int,\n    options: BitmapFactory.Options,\n    request: Request\n  ) {\n    calculateInSampleSize(\n      reqWidth,\n      reqHeight,\n      options.outWidth,\n      options.outHeight,\n      options,\n      request\n    )\n  }\n\n  fun shouldResize(\n    onlyScaleDown: Boolean,\n    inWidth: Int,\n    inHeight: Int,\n    targetWidth: Int,\n    targetHeight: Int\n  ): Boolean {\n    return (\n      !onlyScaleDown || targetWidth != 0 && inWidth > targetWidth ||\n        targetHeight != 0 && inHeight > targetHeight\n      )\n  }\n\n  fun calculateInSampleSize(\n    requestWidth: Int,\n    requestHeight: Int,\n    width: Int,\n    height: Int,\n    options: BitmapFactory.Options,\n    request: Request\n  ) {\n    options.inSampleSize = ratio(requestWidth, requestHeight, width, height, request)\n    options.inJustDecodeBounds = false\n  }\n\n  /**\n   * Decode a byte stream into a Bitmap. This method will take into account additional information\n   * about the supplied request in order to do the decoding efficiently (such as through leveraging\n   * `inSampleSize`).\n   */\n  fun decodeStream(source: Source, request: Request): Bitmap {\n    val exceptionCatchingSource = ExceptionCatchingSource(source)\n    val bufferedSource = exceptionCatchingSource.buffer()\n    val bitmap =\n      if (VERSION.SDK_INT >= 28) {\n        decodeStreamP(request, bufferedSource)\n      } else {\n        decodeStreamPreP(request, bufferedSource)\n      }\n    exceptionCatchingSource.throwIfCaught()\n    return bitmap\n  }\n\n  @RequiresApi(28)\n  @SuppressLint(\"Override\")\n  private fun decodeStreamP(request: Request, bufferedSource: BufferedSource): Bitmap {\n    val imageSource = ImageDecoder.createSource(ByteBuffer.wrap(bufferedSource.readByteArray()))\n    return decodeImageSource(imageSource, request)\n  }\n\n  private fun decodeStreamPreP(request: Request, bufferedSource: BufferedSource): Bitmap {\n    val isWebPFile = Utils.isWebPFile(bufferedSource)\n    val options = createBitmapOptions(request)\n    val calculateSize = requiresInSampleSize(options)\n    // We decode from a byte array because, when decoding a WebP network stream, BitmapFactory\n    // throws a JNI Exception, so we workaround by decoding a byte array.\n    val bitmap = if (isWebPFile) {\n      val bytes = bufferedSource.readByteArray()\n      if (calculateSize) {\n        BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)\n        calculateInSampleSize(request.targetWidth, request.targetHeight, options!!, request)\n      }\n      BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)\n    } else {\n      if (calculateSize) {\n        BitmapFactory.decodeStream(bufferedSource.peek().inputStream(), null, options)\n        calculateInSampleSize(request.targetWidth, request.targetHeight, options!!, request)\n      }\n      BitmapFactory.decodeStream(bufferedSource.inputStream(), null, options)\n    }\n    if (bitmap == null) {\n      // Treat null as an IO exception, we will eventually retry.\n      throw IOException(\"Failed to decode bitmap.\")\n    }\n    return bitmap\n  }\n\n  fun decodeResource(context: Context, request: Request): Bitmap {\n    val resources = Utils.getResources(context, request)\n    val id = Utils.getResourceId(resources, request)\n    return if (VERSION.SDK_INT >= 28) {\n      decodeResourceP(resources, id, request)\n    } else {\n      decodeResourcePreP(resources, id, request)\n    }\n  }\n\n  @RequiresApi(28)\n  private fun decodeResourceP(resources: Resources, @DrawableRes id: Int, request: Request): Bitmap {\n    val imageSource = ImageDecoder.createSource(resources, id)\n    return decodeImageSource(imageSource, request)\n  }\n\n  private fun decodeResourcePreP(resources: Resources, @DrawableRes id: Int, request: Request): Bitmap {\n    val options = createBitmapOptions(request)\n    if (requiresInSampleSize(options)) {\n      BitmapFactory.decodeResource(resources, id, options)\n      calculateInSampleSize(request.targetWidth, request.targetHeight, options!!, request)\n    }\n    return BitmapFactory.decodeResource(resources, id, options)\n  }\n\n  @RequiresApi(28)\n  private fun decodeImageSource(imageSource: ImageDecoder.Source, request: Request): Bitmap {\n    return ImageDecoder.decodeBitmap(imageSource) { imageDecoder, imageInfo, source ->\n      imageDecoder.isMutableRequired = true\n      if (request.hasSize()) {\n        val size = imageInfo.size\n        val width = size.width\n        val height = size.height\n        val targetWidth = request.targetWidth\n        val targetHeight = request.targetHeight\n        if (shouldResize(request.onlyScaleDown, width, height, targetWidth, targetHeight)) {\n          val ratio = ratio(targetWidth, targetHeight, width, height, request)\n          imageDecoder.setTargetSize(width / ratio, height / ratio)\n        }\n      }\n    }\n  }\n\n  private fun ratio(\n    requestWidth: Int,\n    requestHeight: Int,\n    width: Int,\n    height: Int,\n    request: Request\n  ): Int =\n    if (height > requestHeight || width > requestWidth) {\n      val ratio = if (requestHeight == 0) {\n        width / requestWidth\n      } else if (requestWidth == 0) {\n        height / requestHeight\n      } else {\n        val heightRatio = height / requestHeight\n        val widthRatio = width / requestWidth\n        if (request.centerInside) {\n          max(heightRatio, widthRatio)\n        } else {\n          min(heightRatio, widthRatio)\n        }\n      }\n      if (ratio != 0) ratio else 1\n    } else {\n      1\n    }\n\n  fun isXmlResource(resources: Resources, @DrawableRes drawableId: Int): Boolean {\n    val typedValue = TypedValue()\n    resources.getValue(drawableId, typedValue, true)\n    val file = typedValue.string\n    return file != null && file.toString().endsWith(\".xml\")\n  }\n\n  internal class ExceptionCatchingSource(delegate: Source) : ForwardingSource(delegate) {\n    var thrownException: IOException? = null\n\n    override fun read(sink: Buffer, byteCount: Long): Long {\n      return try {\n        super.read(sink, byteCount)\n      } catch (e: IOException) {\n        thrownException = e\n        throw e\n      }\n    }\n\n    fun throwIfCaught() {\n      if (thrownException is IOException) {\n        // TODO: Log when Android returns a non-null Bitmap after swallowing an IOException.\n        // TODO: https://github.com/square/picasso/issues/2003/\n        throw thrownException as IOException\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Callback.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\ninterface Callback {\n  fun onSuccess()\n  fun onError(t: Throwable)\n  open class EmptyCallback : Callback {\n    override fun onSuccess() = Unit\n    override fun onError(t: Throwable) = Unit\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ContactsPhotoRequestHandler.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.ContentResolver\nimport android.content.Context\nimport android.content.UriMatcher\nimport android.net.Uri\nimport android.provider.ContactsContract\nimport android.provider.ContactsContract.Contacts\nimport com.squareup.picasso3.BitmapUtils.decodeStream\nimport com.squareup.picasso3.Picasso.LoadedFrom.DISK\nimport okio.Source\nimport okio.source\nimport java.io.FileNotFoundException\nimport java.io.IOException\n\ninternal class ContactsPhotoRequestHandler(private val context: Context) : RequestHandler() {\n  companion object {\n    /** A lookup uri (e.g. content://com.android.contacts/contacts/lookup/3570i61d948d30808e537) */\n    private const val ID_LOOKUP = 1\n\n    /** A contact thumbnail uri (e.g. content://com.android.contacts/contacts/38/photo) */\n    private const val ID_THUMBNAIL = 2\n\n    /** A contact uri (e.g. content://com.android.contacts/contacts/38) */\n    private const val ID_CONTACT = 3\n\n    /**\n     * A contact display photo (high resolution) uri\n     * (e.g. content://com.android.contacts/display_photo/5)\n     */\n    private const val ID_DISPLAY_PHOTO = 4\n\n    private val matcher: UriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {\n      addURI(ContactsContract.AUTHORITY, \"contacts/lookup/*/#\", ID_LOOKUP)\n      addURI(ContactsContract.AUTHORITY, \"contacts/lookup/*\", ID_LOOKUP)\n      addURI(ContactsContract.AUTHORITY, \"contacts/#/photo\", ID_THUMBNAIL)\n      addURI(ContactsContract.AUTHORITY, \"contacts/#\", ID_CONTACT)\n      addURI(ContactsContract.AUTHORITY, \"display_photo/#\", ID_DISPLAY_PHOTO)\n    }\n  }\n\n  override fun canHandleRequest(data: Request): Boolean {\n    val uri = data.uri\n    return uri != null &&\n      ContentResolver.SCHEME_CONTENT == uri.scheme &&\n      Contacts.CONTENT_URI.host == uri.host &&\n      matcher.match(data.uri) != UriMatcher.NO_MATCH\n  }\n\n  override fun load(\n    picasso: Picasso,\n    request: Request,\n    callback: Callback\n  ) {\n    var signaledCallback = false\n    try {\n      val requestUri = checkNotNull(request.uri)\n      val source = getSource(requestUri)\n      val bitmap = decodeStream(source, request)\n      signaledCallback = true\n      callback.onSuccess(Result.Bitmap(bitmap, DISK))\n    } catch (e: Exception) {\n      if (!signaledCallback) {\n        callback.onError(e)\n      }\n    }\n  }\n\n  private fun getSource(uri: Uri): Source {\n    val contentResolver = context.contentResolver\n    val input = when (matcher.match(uri)) {\n      ID_LOOKUP -> {\n        val contactUri =\n          Contacts.lookupContact(contentResolver, uri) ?: throw IOException(\"no contact found\")\n        Contacts.openContactPhotoInputStream(contentResolver, contactUri, true)\n      }\n      ID_CONTACT -> Contacts.openContactPhotoInputStream(contentResolver, uri, true)\n      ID_THUMBNAIL, ID_DISPLAY_PHOTO -> contentResolver.openInputStream(uri)\n      else -> throw IllegalStateException(\"Invalid uri: $uri\")\n    } ?: throw FileNotFoundException(\"can't open input stream, uri: $uri\")\n\n    return input.source()\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ContentStreamRequestHandler.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.ContentResolver\nimport android.content.Context\nimport android.net.Uri\nimport androidx.exifinterface.media.ExifInterface\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_NORMAL\nimport androidx.exifinterface.media.ExifInterface.TAG_ORIENTATION\nimport com.squareup.picasso3.Picasso.LoadedFrom.DISK\nimport okio.Source\nimport okio.source\nimport java.io.FileNotFoundException\n\ninternal open class ContentStreamRequestHandler(val context: Context) : RequestHandler() {\n  override fun canHandleRequest(data: Request): Boolean =\n    ContentResolver.SCHEME_CONTENT == data.uri?.scheme ?: false\n\n  override fun load(\n    picasso: Picasso,\n    request: Request,\n    callback: Callback\n  ) {\n    var signaledCallback = false\n    try {\n      val requestUri = checkNotNull(request.uri)\n      val source = getSource(requestUri)\n      val bitmap = BitmapUtils.decodeStream(source, request)\n      val exifRotation = getExifOrientation(requestUri)\n      signaledCallback = true\n      callback.onSuccess(Result.Bitmap(bitmap, DISK, exifRotation))\n    } catch (e: Exception) {\n      if (!signaledCallback) {\n        callback.onError(e)\n      }\n    }\n  }\n\n  fun getSource(uri: Uri): Source {\n    val contentResolver = context.contentResolver\n    val inputStream = contentResolver.openInputStream(uri)\n      ?: throw FileNotFoundException(\"can't open input stream, uri: $uri\")\n    return inputStream.source()\n  }\n\n  protected open fun getExifOrientation(uri: Uri): Int {\n    val contentResolver = context.contentResolver\n    contentResolver.openInputStream(uri)?.use { input ->\n      return ExifInterface(input).getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL)\n    } ?: throw FileNotFoundException(\"can't open input stream, uri: $uri\")\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/DeferredRequestCreator.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.view.View\nimport android.view.View.OnAttachStateChangeListener\nimport android.view.ViewTreeObserver\nimport android.widget.ImageView\nimport java.lang.ref.WeakReference\n\ninternal class DeferredRequestCreator(\n  private val creator: RequestCreator,\n  target: ImageView,\n  internal var callback: Callback?\n) : ViewTreeObserver.OnPreDrawListener, OnAttachStateChangeListener {\n  private val targetReference = WeakReference(target)\n\n  init {\n    target.addOnAttachStateChangeListener(this)\n\n    // Only add the pre-draw listener if the view is already attached.\n    // See: https://github.com/square/picasso/issues/1321\n    if (target.windowToken != null) {\n      onViewAttachedToWindow(target)\n    }\n  }\n\n  override fun onViewAttachedToWindow(view: View) {\n    view.viewTreeObserver.addOnPreDrawListener(this)\n  }\n\n  override fun onViewDetachedFromWindow(view: View) {\n    view.viewTreeObserver.removeOnPreDrawListener(this)\n  }\n\n  override fun onPreDraw(): Boolean {\n    val target = targetReference.get() ?: return true\n\n    val vto = target.viewTreeObserver\n    if (!vto.isAlive) {\n      return true\n    }\n\n    val width = target.width\n    val height = target.height\n\n    if (width <= 0 || height <= 0) {\n      return true\n    }\n\n    target.removeOnAttachStateChangeListener(this)\n    vto.removeOnPreDrawListener(this)\n    targetReference.clear()\n\n    creator.unfit().resize(width, height).into(target, callback)\n    return true\n  }\n\n  fun cancel() {\n    creator.clearTag()\n    callback = null\n\n    val target = targetReference.get() ?: return\n    targetReference.clear()\n    target.removeOnAttachStateChangeListener(this)\n\n    val vto = target.viewTreeObserver\n    if (vto.isAlive) {\n      vto.removeOnPreDrawListener(this)\n    }\n  }\n\n  val tag: Any?\n    get() = creator.tag\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Dispatcher.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.net.NetworkInfo\n\ninternal interface Dispatcher {\n  fun shutdown()\n\n  fun dispatchSubmit(action: Action)\n\n  fun dispatchCancel(action: Action)\n\n  fun dispatchPauseTag(tag: Any)\n\n  fun dispatchResumeTag(tag: Any)\n\n  fun dispatchComplete(hunter: BitmapHunter)\n\n  fun dispatchRetry(hunter: BitmapHunter)\n\n  fun dispatchFailed(hunter: BitmapHunter)\n\n  fun dispatchNetworkStateChange(info: NetworkInfo)\n\n  fun dispatchAirplaneModeChange(airplaneMode: Boolean)\n\n  fun dispatchSubmit(hunter: BitmapHunter)\n\n  fun dispatchCompleteMain(hunter: BitmapHunter)\n\n  fun dispatchBatchResumeMain(batch: MutableList<Action>)\n\n  fun isShutdown(): Boolean\n\n  companion object {\n    const val RETRY_DELAY = 500L\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/DrawableLoader.kt",
    "content": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.drawable.Drawable\nimport androidx.annotation.DrawableRes\n\ninternal fun interface DrawableLoader {\n  fun load(@DrawableRes resId: Int): Drawable?\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/DrawableTarget.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.drawable.Drawable\nimport com.squareup.picasso3.Picasso.LoadedFrom\n\n/**\n * Represents an arbitrary listener for image loading.\n *\n * Objects implementing this class **must** have a working implementation of\n * [Object.equals] and [Object.hashCode] for proper storage internally.\n * Instances of this interface will also be compared to determine if view recycling is occurring.\n * It is recommended that you add this interface directly on to a custom view type when using in an\n * adapter to ensure correct recycling behavior.\n */\ninterface DrawableTarget {\n  /**\n   * Callback when an image has been successfully loaded.\n   *\n   */\n  fun onDrawableLoaded(\n    drawable: Drawable,\n    from: LoadedFrom\n  )\n\n  /**\n   * Callback indicating the image could not be successfully loaded.\n   *\n   * **Note:** The passed [Drawable] may be `null` if none has been\n   * specified via [RequestCreator.error].\n   */\n  fun onDrawableFailed(\n    e: Exception,\n    errorDrawable: Drawable?\n  )\n\n  /**\n   * Callback invoked right before your request is submitted.\n   *\n   *\n   * **Note:** The passed [Drawable] may be `null` if none has been\n   * specified via [RequestCreator.placeholder].\n   */\n  fun onPrepareLoad(placeHolderDrawable: Drawable?)\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/DrawableTargetAction.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.drawable.Drawable\nimport androidx.annotation.DrawableRes\nimport androidx.core.content.ContextCompat\nimport com.squareup.picasso3.RequestHandler.Result\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\n\ninternal class DrawableTargetAction(\n  picasso: Picasso,\n  private val target: DrawableTarget,\n  data: Request,\n  private val noFade: Boolean,\n  private val placeholderDrawable: Drawable?,\n  private val errorDrawable: Drawable?,\n  @DrawableRes val errorResId: Int\n) : Action(picasso, data) {\n  override fun complete(result: Result) {\n    if (result is Bitmap) {\n      val bitmap = result.bitmap\n      target.onDrawableLoaded(\n        PicassoDrawable(\n          context = picasso.context,\n          bitmap = bitmap,\n          placeholder = placeholderDrawable,\n          loadedFrom = result.loadedFrom,\n          noFade = noFade,\n          debugging = picasso.indicatorsEnabled\n        ),\n        result.loadedFrom\n      )\n      check(!bitmap.isRecycled) { \"Target callback must not recycle bitmap!\" }\n    }\n  }\n\n  override fun error(e: Exception) {\n    val drawable = if (errorResId != 0) {\n      ContextCompat.getDrawable(picasso.context, errorResId)\n    } else {\n      errorDrawable\n    }\n\n    target.onDrawableFailed(e, drawable)\n  }\n\n  override fun getTarget(): Any {\n    return target\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/EventListener.kt",
    "content": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap\nimport java.io.Closeable\n\ninterface EventListener : Closeable {\n  fun cacheMaxSize(maxSize: Int)\n  fun cacheSize(size: Int)\n  fun cacheHit()\n  fun cacheMiss()\n  fun downloadFinished(size: Long)\n  fun bitmapDecoded(bitmap: Bitmap)\n  fun bitmapTransformed(bitmap: Bitmap)\n  override fun close() = Unit\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/FetchAction.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport com.squareup.picasso3.RequestHandler.Result\n\ninternal class FetchAction(\n  picasso: Picasso,\n  data: Request,\n  private var callback: Callback?\n) : Action(picasso, data) {\n  override fun complete(result: Result) {\n    callback?.onSuccess()\n  }\n\n  override fun error(e: Exception) {\n    callback?.onError(e)\n  }\n\n  override fun getTarget() = this\n\n  override fun cancel() {\n    super.cancel()\n    callback = null\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/FileRequestHandler.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.ContentResolver\nimport android.content.Context\nimport android.net.Uri\nimport androidx.exifinterface.media.ExifInterface\nimport com.squareup.picasso3.BitmapUtils.decodeStream\nimport com.squareup.picasso3.Picasso.LoadedFrom.DISK\nimport java.io.FileNotFoundException\n\ninternal class FileRequestHandler(context: Context) : ContentStreamRequestHandler(context) {\n  override fun canHandleRequest(data: Request): Boolean {\n    val uri = data.uri\n    return uri != null && ContentResolver.SCHEME_FILE == uri.scheme\n  }\n\n  override fun load(\n    picasso: Picasso,\n    request: Request,\n    callback: Callback\n  ) {\n    var signaledCallback = false\n    try {\n      val requestUri = checkNotNull(request.uri)\n      val source = getSource(requestUri)\n      val bitmap = decodeStream(source, request)\n      val exifRotation = getExifOrientation(requestUri)\n      signaledCallback = true\n      callback.onSuccess(Result.Bitmap(bitmap, DISK, exifRotation))\n    } catch (e: Exception) {\n      if (!signaledCallback) {\n        callback.onError(e)\n      }\n    }\n  }\n\n  override fun getExifOrientation(uri: Uri): Int {\n    val path = uri.path ?: throw FileNotFoundException(\"path == null, uri: $uri\")\n    return ExifInterface(path).getAttributeInt(\n      ExifInterface.TAG_ORIENTATION,\n      ExifInterface.ORIENTATION_NORMAL\n    )\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/GetAction.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport com.squareup.picasso3.RequestHandler.Result\n\ninternal class GetAction(\n  picasso: Picasso,\n  data: Request\n) : Action(picasso, data) {\n  override fun complete(result: Result) = Unit\n  override fun error(e: Exception) = Unit\n  override fun getTarget() = throw AssertionError()\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/HandlerDispatcher.kt",
    "content": "/*\n * Copyright (C) 2023 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.net.NetworkInfo\nimport android.os.Handler\nimport android.os.HandlerThread\nimport android.os.Looper\nimport android.os.Message\nimport android.os.Process.THREAD_PRIORITY_BACKGROUND\nimport com.squareup.picasso3.Picasso.Priority.HIGH\nimport com.squareup.picasso3.Utils.flushStackLocalLeaks\nimport java.util.concurrent.ExecutorService\n\ninternal class HandlerDispatcher internal constructor(\n  context: Context,\n  @get:JvmName(\"-service\") val service: ExecutorService,\n  mainThreadHandler: Handler,\n  cache: PlatformLruCache\n) : BaseDispatcher(context, mainThreadHandler, cache) {\n\n  private val dispatcherThread: DispatcherThread\n  private val handler: Handler\n  private val mainHandler: Handler\n\n  init {\n    dispatcherThread = DispatcherThread()\n    dispatcherThread.start()\n    val dispatcherThreadLooper = dispatcherThread.looper\n    flushStackLocalLeaks(dispatcherThreadLooper)\n    handler = DispatcherHandler(dispatcherThreadLooper, this)\n    mainHandler = MainDispatcherHandler(mainThreadHandler.looper, this)\n  }\n\n  override fun shutdown() {\n    super.shutdown()\n    // Shutdown the thread pool only if it is the one created by Picasso.\n    (service as? PicassoExecutorService)?.shutdown()\n\n    dispatcherThread.quit()\n  }\n\n  override fun dispatchSubmit(action: Action) {\n    handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action))\n  }\n\n  override fun dispatchCancel(action: Action) {\n    handler.sendMessage(handler.obtainMessage(REQUEST_CANCEL, action))\n  }\n\n  override fun dispatchPauseTag(tag: Any) {\n    handler.sendMessage(handler.obtainMessage(TAG_PAUSE, tag))\n  }\n\n  override fun dispatchResumeTag(tag: Any) {\n    handler.sendMessage(handler.obtainMessage(TAG_RESUME, tag))\n  }\n\n  override fun dispatchComplete(hunter: BitmapHunter) {\n    handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter))\n  }\n\n  override fun dispatchRetry(hunter: BitmapHunter) {\n    handler.sendMessageDelayed(handler.obtainMessage(HUNTER_RETRY, hunter), RETRY_DELAY)\n  }\n\n  override fun dispatchFailed(hunter: BitmapHunter) {\n    handler.sendMessage(handler.obtainMessage(HUNTER_DECODE_FAILED, hunter))\n  }\n\n  override fun dispatchNetworkStateChange(info: NetworkInfo) {\n    handler.sendMessage(handler.obtainMessage(NETWORK_STATE_CHANGE, info))\n  }\n\n  override fun dispatchAirplaneModeChange(airplaneMode: Boolean) {\n    handler.sendMessage(\n      handler.obtainMessage(\n        AIRPLANE_MODE_CHANGE,\n        if (airplaneMode) AIRPLANE_MODE_ON else AIRPLANE_MODE_OFF,\n        0\n      )\n    )\n  }\n\n  override fun dispatchSubmit(hunter: BitmapHunter) {\n    hunter.future = service.submit(hunter)\n  }\n\n  override fun dispatchCompleteMain(hunter: BitmapHunter) {\n    val message = mainHandler.obtainMessage(HUNTER_COMPLETE, hunter)\n    if (hunter.priority == HIGH) {\n      mainHandler.sendMessageAtFrontOfQueue(message)\n    } else {\n      mainHandler.sendMessage(message)\n    }\n  }\n\n  override fun dispatchBatchResumeMain(batch: MutableList<Action>) {\n    mainHandler.sendMessage(mainHandler.obtainMessage(REQUEST_BATCH_RESUME, batch))\n  }\n  override fun isShutdown() = service.isShutdown\n\n  private class DispatcherHandler(\n    looper: Looper,\n    private val dispatcher: HandlerDispatcher\n  ) : Handler(looper) {\n    override fun handleMessage(msg: Message) {\n      when (msg.what) {\n        REQUEST_SUBMIT -> {\n          val action = msg.obj as Action\n          dispatcher.performSubmit(action)\n        }\n        REQUEST_CANCEL -> {\n          val action = msg.obj as Action\n          dispatcher.performCancel(action)\n        }\n        TAG_PAUSE -> {\n          val tag = msg.obj\n          dispatcher.performPauseTag(tag)\n        }\n        TAG_RESUME -> {\n          val tag = msg.obj\n          dispatcher.performResumeTag(tag)\n        }\n        HUNTER_COMPLETE -> {\n          val hunter = msg.obj as BitmapHunter\n          dispatcher.performComplete(hunter)\n        }\n        HUNTER_RETRY -> {\n          val hunter = msg.obj as BitmapHunter\n          dispatcher.performRetry(hunter)\n        }\n        HUNTER_DECODE_FAILED -> {\n          val hunter = msg.obj as BitmapHunter\n          dispatcher.performError(hunter)\n        }\n        NETWORK_STATE_CHANGE -> {\n          val info = msg.obj as NetworkInfo\n          dispatcher.performNetworkStateChange(info)\n        }\n        AIRPLANE_MODE_CHANGE -> {\n          dispatcher.performAirplaneModeChange(msg.arg1 == AIRPLANE_MODE_ON)\n        }\n        else -> {\n          dispatcher.mainHandler.post {\n            throw AssertionError(\"Unknown handler message received: ${msg.what}\")\n          }\n        }\n      }\n    }\n  }\n\n  private class MainDispatcherHandler(\n    looper: Looper,\n    val dispatcher: HandlerDispatcher\n  ) : Handler(looper) {\n    override fun handleMessage(msg: Message) {\n      when (msg.what) {\n        HUNTER_COMPLETE -> {\n          val hunter = msg.obj as BitmapHunter\n          dispatcher.performCompleteMain(hunter)\n        }\n        REQUEST_BATCH_RESUME -> {\n          val batch = msg.obj as List<Action>\n          dispatcher.performBatchResumeMain(batch)\n        }\n        else -> throw AssertionError(\"Unknown handler message received: \" + msg.what)\n      }\n    }\n  }\n\n  internal class DispatcherThread : HandlerThread(\n    Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME,\n    THREAD_PRIORITY_BACKGROUND\n  )\n  internal companion object {\n    private const val RETRY_DELAY = 500L\n    private const val AIRPLANE_MODE_ON = 1\n    private const val AIRPLANE_MODE_OFF = 0\n    private const val REQUEST_SUBMIT = 1\n    private const val REQUEST_CANCEL = 2\n    private const val HUNTER_COMPLETE = 4\n    private const val HUNTER_RETRY = 5\n    private const val HUNTER_DECODE_FAILED = 6\n    private const val NETWORK_STATE_CHANGE = 9\n    private const val AIRPLANE_MODE_CHANGE = 10\n    private const val TAG_PAUSE = 11\n    private const val TAG_RESUME = 12\n    private const val REQUEST_BATCH_RESUME = 13\n    private const val DISPATCHER_THREAD_NAME = \"Dispatcher\"\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ImageViewAction.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.drawable.Animatable\nimport android.graphics.drawable.Drawable\nimport android.widget.ImageView\nimport androidx.annotation.DrawableRes\nimport com.squareup.picasso3.RequestHandler.Result\nimport java.lang.ref.WeakReference\n\ninternal class ImageViewAction(\n  picasso: Picasso,\n  target: ImageView,\n  data: Request,\n  val errorDrawable: Drawable?,\n  @DrawableRes val errorResId: Int,\n  val noFade: Boolean,\n  var callback: Callback?\n) : Action(picasso, data) {\n  private val targetReference = WeakReference(target)\n\n  override fun complete(result: Result) {\n    val target = targetReference.get() ?: return\n\n    PicassoDrawable.setResult(target, picasso.context, result, noFade, picasso.indicatorsEnabled)\n    callback?.onSuccess()\n  }\n\n  override fun error(e: Exception) {\n    val target = targetReference.get() ?: return\n\n    val placeholder = target.drawable\n    if (placeholder is Animatable) {\n      (placeholder as Animatable).stop()\n    }\n    if (errorResId != 0) {\n      target.setImageResource(errorResId)\n    } else if (errorDrawable != null) {\n      target.setImageDrawable(errorDrawable)\n    }\n    callback?.onError(e)\n  }\n\n  override fun getTarget(): ImageView? {\n    return targetReference.get()\n  }\n\n  override fun cancel() {\n    super.cancel()\n    callback = null\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Initializer.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport androidx.annotation.RestrictTo\nimport androidx.annotation.RestrictTo.Scope.LIBRARY\nimport kotlin.annotation.AnnotationRetention.SOURCE\n\n@Retention(SOURCE)\n@RestrictTo(LIBRARY)\nannotation class Initializer\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/InternalCoroutineDispatcher.kt",
    "content": "/*\n * Copyright (C) 2023 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.net.NetworkInfo\nimport android.os.Handler\nimport com.squareup.picasso3.Dispatcher.Companion.RETRY_DELAY\nimport com.squareup.picasso3.Picasso.Priority.HIGH\nimport com.squareup.picasso3.Utils.OWNER_DISPATCHER\nimport com.squareup.picasso3.Utils.VERB_CANCELED\nimport com.squareup.picasso3.Utils.log\nimport kotlin.coroutines.CoroutineContext\nimport kotlin.coroutines.EmptyCoroutineContext\nimport kotlinx.coroutines.CoroutineName\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.SupervisorJob\nimport kotlinx.coroutines.cancel\nimport kotlinx.coroutines.channels.Channel\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.flow.receiveAsFlow\nimport kotlinx.coroutines.isActive\nimport kotlinx.coroutines.launch\n\ninternal class InternalCoroutineDispatcher internal constructor(\n  context: Context,\n  mainThreadHandler: Handler,\n  cache: PlatformLruCache,\n  val mainContext: CoroutineContext,\n  val backgroundContext: CoroutineContext\n) : BaseDispatcher(context, mainThreadHandler, cache) {\n\n  private val scope = CoroutineScope(SupervisorJob() + backgroundContext)\n  private val channel = Channel<() -> Unit>(capacity = Channel.UNLIMITED)\n\n  init {\n    // Using a channel to enforce sequential access for this class' internal state\n    scope.launch {\n      channel.receiveAsFlow().collect {\n        it.invoke()\n      }\n    }\n  }\n\n  override fun shutdown() {\n    super.shutdown()\n    channel.close()\n    scope.cancel()\n  }\n\n  override fun dispatchSubmit(action: Action) {\n    channel.trySend {\n      performSubmit(action)\n    }\n  }\n\n  override fun dispatchCancel(action: Action) {\n    channel.trySend {\n      performCancel(action)\n    }\n  }\n\n  override fun dispatchPauseTag(tag: Any) {\n    channel.trySend {\n      performPauseTag(tag)\n    }\n  }\n\n  override fun dispatchResumeTag(tag: Any) {\n    channel.trySend {\n      performResumeTag(tag)\n    }\n  }\n\n  override fun dispatchComplete(hunter: BitmapHunter) {\n    channel.trySend {\n      performComplete(hunter)\n    }\n  }\n\n  override fun dispatchRetry(hunter: BitmapHunter) {\n    scope.launch {\n      delay(RETRY_DELAY)\n      channel.send {\n        performRetry(hunter)\n      }\n    }\n  }\n\n  override fun dispatchFailed(hunter: BitmapHunter) {\n    channel.trySend {\n      performError(hunter)\n    }\n  }\n\n  override fun dispatchNetworkStateChange(info: NetworkInfo) {\n    channel.trySend {\n      performNetworkStateChange(info)\n    }\n  }\n\n  override fun dispatchAirplaneModeChange(airplaneMode: Boolean) {\n    channel.trySend {\n      performAirplaneModeChange(airplaneMode)\n    }\n  }\n\n  override fun dispatchCompleteMain(hunter: BitmapHunter) {\n    scope.launch(mainContext) {\n      performCompleteMain(hunter)\n    }\n  }\n\n  override fun dispatchBatchResumeMain(batch: MutableList<Action>) {\n    scope.launch(mainContext) {\n      performBatchResumeMain(batch)\n    }\n  }\n\n  override fun dispatchSubmit(hunter: BitmapHunter) {\n    val highPriority = hunter.action?.request?.priority == HIGH\n    val context = if (highPriority) EmptyCoroutineContext else mainContext\n\n    scope.launch(context) {\n      channel.trySend {\n        if (hunter.action != null) {\n          hunter.job = scope.launch(CoroutineName(hunter.getName())) {\n            hunter.run()\n          }\n        } else {\n          hunterMap.remove(hunter.key)\n          if (hunter.picasso.isLoggingEnabled) {\n            log(OWNER_DISPATCHER, VERB_CANCELED, hunter.key)\n          }\n        }\n      }\n    }\n  }\n\n  override fun isShutdown() = !scope.isActive\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/MatrixTransformation.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap.createBitmap\nimport android.graphics.Matrix\nimport android.os.Build.VERSION\nimport android.view.Gravity\nimport androidx.annotation.VisibleForTesting\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_FLIP_HORIZONTAL\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_FLIP_VERTICAL\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_180\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_270\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_90\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_TRANSPOSE\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_TRANSVERSE\nimport com.squareup.picasso3.BitmapUtils.shouldResize\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport kotlin.math.ceil\nimport kotlin.math.cos\nimport kotlin.math.floor\nimport kotlin.math.max\nimport kotlin.math.min\nimport kotlin.math.sin\n\ninternal class MatrixTransformation(private val data: Request) : Transformation {\n  override fun transform(source: Bitmap): Bitmap {\n    val sourceBitmap = source.bitmap\n    val transformedBitmap = transformResult(data, sourceBitmap, source.exifRotation)\n    return Bitmap(transformedBitmap, source.loadedFrom, source.exifRotation)\n  }\n\n  override fun key() = \"matrixTransformation()\"\n\n  internal companion object {\n    @VisibleForTesting\n    @JvmName(\"-transformResult\")\n    internal fun transformResult(\n      data: Request,\n      result: android.graphics.Bitmap,\n      exifOrientation: Int\n    ): android.graphics.Bitmap {\n      val inWidth = result.width\n      val inHeight = result.height\n      val onlyScaleDown = data.onlyScaleDown\n\n      var drawX = 0\n      var drawY = 0\n      var drawWidth = inWidth\n      var drawHeight = inHeight\n\n      val matrix = Matrix()\n\n      if (data.needsMatrixTransform() || exifOrientation != 0) {\n        var targetWidth = data.targetWidth\n        var targetHeight = data.targetHeight\n\n        val targetRotation = data.rotationDegrees\n        if (targetRotation != 0f) {\n          val cosR = cos(Math.toRadians(targetRotation.toDouble()))\n          val sinR = sin(Math.toRadians(targetRotation.toDouble()))\n          if (data.hasRotationPivot) {\n            matrix.setRotate(targetRotation, data.rotationPivotX, data.rotationPivotY)\n            // Recalculate dimensions after rotation around pivot point\n            val x1T = data.rotationPivotX * (1.0 - cosR) + data.rotationPivotY * sinR\n            val y1T = data.rotationPivotY * (1.0 - cosR) - data.rotationPivotX * sinR\n            val x2T = x1T + data.targetWidth * cosR\n            val y2T = y1T + data.targetWidth * sinR\n            val x3T = x1T + data.targetWidth * cosR - data.targetHeight * sinR\n            val y3T = y1T + data.targetWidth * sinR + data.targetHeight * cosR\n            val x4T = x1T - data.targetHeight * sinR\n            val y4T = y1T + data.targetHeight * cosR\n\n            val maxX = max(x4T, max(x3T, max(x1T, x2T)))\n            val minX = min(x4T, min(x3T, min(x1T, x2T)))\n            val maxY = max(y4T, max(y3T, max(y1T, y2T)))\n            val minY = min(y4T, min(y3T, min(y1T, y2T)))\n            targetWidth = floor(maxX - minX).toInt()\n            targetHeight = floor(maxY - minY).toInt()\n          } else {\n            matrix.setRotate(targetRotation)\n            // Recalculate dimensions after rotation (around origin)\n            val x1T = 0.0\n            val y1T = 0.0\n            val x2T = data.targetWidth * cosR\n            val y2T = data.targetWidth * sinR\n            val x3T = data.targetWidth * cosR - data.targetHeight * sinR\n            val y3T = data.targetWidth * sinR + data.targetHeight * cosR\n            val x4T = -(data.targetHeight * sinR)\n            val y4T = data.targetHeight * cosR\n\n            val maxX = max(x4T, max(x3T, max(x1T, x2T)))\n            val minX = min(x4T, min(x3T, min(x1T, x2T)))\n            val maxY = max(y4T, max(y3T, max(y1T, y2T)))\n            val minY = min(y4T, min(y3T, min(y1T, y2T)))\n            targetWidth = floor(maxX - minX).toInt()\n            targetHeight = floor(maxY - minY).toInt()\n          }\n        }\n\n        // EXIf interpretation should be done before cropping in case the dimensions need to\n        // be recalculated; SDK 28+ uses ImageDecoder which handles EXIF orientation\n        if (exifOrientation != 0 && VERSION.SDK_INT < 28) {\n          val exifRotation = getExifRotation(exifOrientation)\n          val exifTranslation = getExifTranslation(exifOrientation)\n          if (exifRotation != 0) {\n            matrix.preRotate(exifRotation.toFloat())\n            if (exifRotation == 90 || exifRotation == 270) {\n              // Recalculate dimensions after exif rotation\n              val tmpHeight = targetHeight\n              targetHeight = targetWidth\n              targetWidth = tmpHeight\n            }\n          }\n          if (exifTranslation != 1) {\n            matrix.postScale(exifTranslation.toFloat(), 1f)\n          }\n        }\n\n        if (data.centerCrop) {\n          // Keep aspect ratio if one dimension is set to 0\n          val widthRatio = if (targetWidth != 0) {\n            targetWidth / inWidth.toFloat()\n          } else {\n            targetHeight / inHeight.toFloat()\n          }\n          val heightRatio = if (targetHeight != 0) {\n            targetHeight / inHeight.toFloat()\n          } else {\n            targetWidth / inWidth.toFloat()\n          }\n          val scaleX: Float\n          val scaleY: Float\n          if (widthRatio > heightRatio) {\n            val newSize = ceil((inHeight * (heightRatio / widthRatio)).toDouble()).toInt()\n            drawY = if (data.centerCropGravity and Gravity.TOP == Gravity.TOP) {\n              0\n            } else if (data.centerCropGravity and Gravity.BOTTOM == Gravity.BOTTOM) {\n              inHeight - newSize\n            } else {\n              (inHeight - newSize) / 2\n            }\n            drawHeight = newSize\n            scaleX = widthRatio\n            scaleY = targetHeight / drawHeight.toFloat()\n          } else if (widthRatio < heightRatio) {\n            val newSize = ceil((inWidth * (widthRatio / heightRatio)).toDouble()).toInt()\n            drawX = if (data.centerCropGravity and Gravity.LEFT == Gravity.LEFT) {\n              0\n            } else if (data.centerCropGravity and Gravity.RIGHT == Gravity.RIGHT) {\n              inWidth - newSize\n            } else {\n              (inWidth - newSize) / 2\n            }\n            drawWidth = newSize\n            scaleX = targetWidth / drawWidth.toFloat()\n            scaleY = heightRatio\n          } else {\n            drawX = 0\n            drawWidth = inWidth\n            scaleY = heightRatio\n            scaleX = scaleY\n          }\n          if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {\n            matrix.preScale(scaleX, scaleY)\n          }\n        } else if (data.centerInside) {\n          // Keep aspect ratio if one dimension is set to 0\n          val widthRatio =\n            if (targetWidth != 0) targetWidth / inWidth.toFloat() else targetHeight / inHeight.toFloat()\n          val heightRatio =\n            if (targetHeight != 0) targetHeight / inHeight.toFloat() else targetWidth / inWidth.toFloat()\n          val scale = if (widthRatio < heightRatio) widthRatio else heightRatio\n          if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {\n            matrix.preScale(scale, scale)\n          }\n        } else if ((targetWidth != 0 || targetHeight != 0) && //\n          (targetWidth != inWidth || targetHeight != inHeight)\n        ) {\n          // If an explicit target size has been specified and they do not match the results bounds,\n          // pre-scale the existing matrix appropriately.\n          // Keep aspect ratio if one dimension is set to 0.\n          val sx =\n            if (targetWidth != 0) targetWidth / inWidth.toFloat() else targetHeight / inHeight.toFloat()\n          val sy =\n            if (targetHeight != 0) targetHeight / inHeight.toFloat() else targetWidth / inWidth.toFloat()\n          if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {\n            matrix.preScale(sx, sy)\n          }\n        }\n      }\n\n      val transformedResult = createBitmap(result, drawX, drawY, drawWidth, drawHeight, matrix, true)\n      if (transformedResult != result) {\n        result.recycle()\n      }\n      return transformedResult\n    }\n\n    @Suppress(\"MemberVisibilityCanBePrivate\")\n    @JvmName(\"-getExifRotation\")\n    internal fun getExifRotation(orientation: Int) =\n      when (orientation) {\n        ORIENTATION_ROTATE_90, ORIENTATION_TRANSPOSE -> 90\n        ORIENTATION_ROTATE_180, ORIENTATION_FLIP_VERTICAL -> 180\n        ORIENTATION_ROTATE_270, ORIENTATION_TRANSVERSE -> 270\n        else -> 0\n      }\n\n    @Suppress(\"MemberVisibilityCanBePrivate\")\n    @JvmName(\"-getExifTranslation\")\n    internal fun getExifTranslation(orientation: Int) =\n      when (orientation) {\n        ORIENTATION_FLIP_HORIZONTAL, ORIENTATION_FLIP_VERTICAL,\n        ORIENTATION_TRANSPOSE, ORIENTATION_TRANSVERSE -> -1\n        else -> 1\n      }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/MediaStoreRequestHandler.kt",
    "content": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.ContentResolver\nimport android.content.ContentUris\nimport android.content.Context\nimport android.provider.MediaStore\nimport android.provider.MediaStore.Video\nimport com.squareup.picasso3.BitmapUtils.calculateInSampleSize\nimport com.squareup.picasso3.BitmapUtils.createBitmapOptions\nimport com.squareup.picasso3.BitmapUtils.decodeStream\nimport com.squareup.picasso3.Picasso.LoadedFrom\n\ninternal class MediaStoreRequestHandler(context: Context) : ContentStreamRequestHandler(context) {\n  override fun canHandleRequest(data: Request): Boolean {\n    val uri = data.uri\n    return uri != null &&\n      ContentResolver.SCHEME_CONTENT == uri.scheme &&\n      MediaStore.AUTHORITY == uri.authority\n  }\n\n  override fun load(picasso: Picasso, request: Request, callback: Callback) {\n    var signaledCallback = false\n    try {\n      val contentResolver = context.contentResolver\n      val requestUri = checkNotNull(request.uri, { \"request.uri == null\" })\n      val exifOrientation = getExifOrientation(requestUri)\n\n      val mimeType = contentResolver.getType(requestUri)\n      val isVideo = mimeType != null && mimeType.startsWith(\"video/\")\n\n      if (request.hasSize()) {\n        val picassoKind = getPicassoKind(request.targetWidth, request.targetHeight)\n        if (!isVideo && picassoKind == PicassoKind.FULL) {\n          val source = getSource(requestUri)\n          val bitmap = decodeStream(source, request)\n          signaledCallback = true\n          callback.onSuccess(Result.Bitmap(bitmap, LoadedFrom.DISK, exifOrientation))\n          return\n        }\n\n        val id = ContentUris.parseId(requestUri)\n\n        val options = checkNotNull(createBitmapOptions(request), { \"options == null\" })\n        options.inJustDecodeBounds = true\n\n        calculateInSampleSize(\n          request.targetWidth,\n          request.targetHeight,\n          picassoKind.width,\n          picassoKind.height,\n          options,\n          request\n        )\n\n        val bitmap = if (isVideo) {\n          // Since MediaStore doesn't provide the full screen kind thumbnail, we use the mini kind\n          // instead which is the largest thumbnail size can be fetched from MediaStore.\n          val kind =\n            if (picassoKind == PicassoKind.FULL) Video.Thumbnails.MINI_KIND else picassoKind.androidKind\n          Video.Thumbnails.getThumbnail(contentResolver, id, kind, options)\n        } else {\n          MediaStore.Images.Thumbnails.getThumbnail(\n            contentResolver,\n            id,\n            picassoKind.androidKind,\n            options\n          )\n        }\n\n        if (bitmap != null) {\n          signaledCallback = true\n          callback.onSuccess(Result.Bitmap(bitmap, LoadedFrom.DISK, exifOrientation))\n          return\n        }\n      }\n\n      val source = getSource(requestUri)\n      val bitmap = decodeStream(source, request)\n      signaledCallback = true\n      callback.onSuccess(Result.Bitmap(bitmap, LoadedFrom.DISK, exifOrientation))\n    } catch (e: Exception) {\n      if (!signaledCallback) {\n        callback.onError(e)\n      }\n    }\n  }\n\n  internal enum class PicassoKind(val androidKind: Int, val width: Int, val height: Int) {\n    MICRO(MediaStore.Images.Thumbnails.MICRO_KIND, 96, 96),\n    MINI(MediaStore.Images.Thumbnails.MINI_KIND, 512, 384),\n    FULL(MediaStore.Images.Thumbnails.FULL_SCREEN_KIND, -1, -1)\n  }\n\n  companion object {\n    fun getPicassoKind(targetWidth: Int, targetHeight: Int): PicassoKind {\n      return if (targetWidth <= PicassoKind.MICRO.width && targetHeight <= PicassoKind.MICRO.height) {\n        PicassoKind.MICRO\n      } else if (targetWidth <= PicassoKind.MINI.width && targetHeight <= PicassoKind.MINI.height) {\n        PicassoKind.MINI\n      } else {\n        PicassoKind.FULL\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/MemoryPolicy.kt",
    "content": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\n/** Designates the policy to use when dealing with memory cache.  */\nenum class MemoryPolicy(val index: Int) {\n  /** Skips memory cache lookup when processing a request.  */\n  NO_CACHE(1 shl 0),\n\n  /**\n   * Skips storing the final result into memory cache. Useful for one-off requests\n   * to avoid evicting other bitmaps from the cache.\n   */\n  NO_STORE(1 shl 1);\n\n  companion object {\n    @JvmStatic fun shouldReadFromMemoryCache(memoryPolicy: Int) =\n      memoryPolicy and NO_CACHE.index == 0\n\n    @JvmStatic fun shouldWriteToMemoryCache(memoryPolicy: Int) =\n      memoryPolicy and NO_STORE.index == 0\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/NetworkPolicy.kt",
    "content": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\n/** Designates the policy to use for network requests.  */\nenum class NetworkPolicy(val index: Int) {\n  /**\n   * Skips checking the disk cache and forces loading through the network.\n   */\n  NO_CACHE(1 shl 0),\n\n  /**\n   * Skips storing the result into the disk cache.\n   */\n  NO_STORE(1 shl 1),\n\n  /**\n   * Forces the request through the disk cache only, skipping network.\n   */\n  OFFLINE(1 shl 2);\n\n  companion object {\n    @JvmStatic fun shouldReadFromDiskCache(networkPolicy: Int) =\n      networkPolicy and NO_CACHE.index == 0\n\n    @JvmStatic fun shouldWriteToDiskCache(networkPolicy: Int) =\n      networkPolicy and NO_STORE.index == 0\n\n    @JvmStatic fun isOfflineOnly(networkPolicy: Int) =\n      networkPolicy and OFFLINE.index != 0\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/NetworkRequestHandler.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.net.NetworkInfo\nimport com.squareup.picasso3.BitmapUtils.decodeStream\nimport com.squareup.picasso3.NetworkPolicy.Companion.isOfflineOnly\nimport com.squareup.picasso3.NetworkPolicy.Companion.shouldReadFromDiskCache\nimport com.squareup.picasso3.NetworkPolicy.Companion.shouldWriteToDiskCache\nimport com.squareup.picasso3.Picasso.LoadedFrom.DISK\nimport com.squareup.picasso3.Picasso.LoadedFrom.NETWORK\nimport okhttp3.CacheControl\nimport okhttp3.Call\nimport okhttp3.Response\nimport java.io.IOException\n\ninternal class NetworkRequestHandler(\n  private val callFactory: Call.Factory\n) : RequestHandler() {\n  override fun canHandleRequest(data: Request): Boolean {\n    val uri = data.uri ?: return false\n    val scheme = uri.scheme\n    return SCHEME_HTTP.equals(scheme, ignoreCase = true) ||\n      SCHEME_HTTPS.equals(scheme, ignoreCase = true)\n  }\n\n  override fun load(picasso: Picasso, request: Request, callback: Callback) {\n    val callRequest = createRequest(request)\n    callFactory\n      .newCall(callRequest)\n      .enqueue(object : okhttp3.Callback {\n        override fun onResponse(call: Call, response: Response) {\n          if (!response.isSuccessful) {\n            callback.onError(ResponseException(response.code, request.networkPolicy))\n            return\n          }\n\n          // Cache response is only null when the response comes fully from the network. Both\n          // completely cached and conditionally cached responses will have a non-null cache\n          // response.\n          val loadedFrom = if (response.cacheResponse == null) NETWORK else DISK\n\n          // Sometimes response content length is zero when requests are being replayed.\n          // Haven't found root cause to this but retrying the request seems safe to do so.\n          val body = response.body\n          if (loadedFrom == DISK && body!!.contentLength() == 0L) {\n            body.close()\n            callback.onError(\n              ContentLengthException(\"Received response with 0 content-length header.\")\n            )\n            return\n          }\n          if (loadedFrom == NETWORK && body!!.contentLength() > 0) {\n            picasso.downloadFinished(body.contentLength())\n          }\n          try {\n            val bitmap = decodeStream(body!!.source(), request)\n            callback.onSuccess(Result.Bitmap(bitmap, loadedFrom))\n          } catch (e: IOException) {\n            body!!.close()\n            callback.onError(e)\n          }\n        }\n\n        override fun onFailure(call: Call, e: IOException) {\n          callback.onError(e)\n        }\n      })\n  }\n\n  override val retryCount: Int\n    get() = 2\n\n  override fun shouldRetry(airplaneMode: Boolean, info: NetworkInfo?): Boolean =\n    info == null || info.isConnected\n\n  override fun supportsReplay(): Boolean = true\n\n  private fun createRequest(request: Request): okhttp3.Request {\n    var cacheControl: CacheControl? = null\n    val networkPolicy = request.networkPolicy\n    if (networkPolicy != 0) {\n      cacheControl = if (isOfflineOnly(networkPolicy)) {\n        CacheControl.FORCE_CACHE\n      } else {\n        val builder = CacheControl.Builder()\n        if (!shouldReadFromDiskCache(networkPolicy)) {\n          builder.noCache()\n        }\n        if (!shouldWriteToDiskCache(networkPolicy)) {\n          builder.noStore()\n        }\n        builder.build()\n      }\n    }\n\n    val uri = checkNotNull(request.uri) { \"request.uri == null\" }\n    val builder = okhttp3.Request.Builder().url(uri.toString())\n    if (cacheControl != null) {\n      builder.cacheControl(cacheControl)\n    }\n    val requestHeaders = request.headers\n    if (requestHeaders != null) {\n      builder.headers(requestHeaders)\n    }\n    return builder.build()\n  }\n\n  internal class ContentLengthException(message: String) : RuntimeException(message)\n  internal class ResponseException(\n    val code: Int,\n    val networkPolicy: Int\n  ) : RuntimeException(\"HTTP $code\")\n\n  private companion object {\n    private const val SCHEME_HTTP = \"http\"\n    private const val SCHEME_HTTPS = \"https\"\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Picasso.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config\nimport android.graphics.Color\nimport android.net.Uri\nimport android.os.Handler\nimport android.os.Looper\nimport android.widget.ImageView\nimport android.widget.RemoteViews\nimport androidx.annotation.DrawableRes\nimport androidx.annotation.IdRes\nimport androidx.lifecycle.DefaultLifecycleObserver\nimport androidx.lifecycle.LifecycleOwner\nimport com.squareup.picasso3.MemoryPolicy.Companion.shouldReadFromMemoryCache\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.RemoteViewsAction.RemoteViewsTarget\nimport com.squareup.picasso3.RequestHandler.Result\nimport com.squareup.picasso3.Utils.OWNER_MAIN\nimport com.squareup.picasso3.Utils.VERB_COMPLETED\nimport com.squareup.picasso3.Utils.VERB_ERRORED\nimport com.squareup.picasso3.Utils.VERB_RESUMED\nimport com.squareup.picasso3.Utils.calculateDiskCacheSize\nimport com.squareup.picasso3.Utils.calculateMemoryCacheSize\nimport com.squareup.picasso3.Utils.checkMain\nimport com.squareup.picasso3.Utils.createDefaultCacheDir\nimport com.squareup.picasso3.Utils.log\nimport okhttp3.Cache\nimport okhttp3.Call\nimport okhttp3.OkHttpClient\nimport java.io.File\nimport java.io.IOException\nimport java.util.WeakHashMap\nimport java.util.concurrent.ExecutorService\nimport kotlin.coroutines.CoroutineContext\nimport kotlinx.coroutines.Dispatchers\n\n/**\n * Image downloading, transformation, and caching manager.\n *\n * Use [PicassoProvider.get] for a global singleton instance\n * or construct your own instance with [Picasso.Builder].\n */\n@OptIn(ExperimentalStdlibApi::class)\nclass Picasso internal constructor(\n  @get:JvmName(\"-context\") internal val context: Context,\n  @get:JvmName(\"-dispatcher\") internal val dispatcher: Dispatcher,\n  @get:JvmName(\"-callFactory\") internal val callFactory: Call.Factory,\n  private val closeableCache: Cache?,\n  @get:JvmName(\"-cache\") internal val cache: PlatformLruCache,\n  @get:JvmName(\"-listener\") internal val listener: Listener?,\n  requestTransformers: List<RequestTransformer>,\n  extraRequestHandlers: List<RequestHandler>,\n  eventListeners: List<EventListener>,\n  @get:JvmName(\"-defaultBitmapConfig\") internal val defaultBitmapConfig: Config?,\n  /** Toggle whether to display debug indicators on images.  */\n  var indicatorsEnabled: Boolean,\n  /**\n   * Toggle whether debug logging is enabled.\n   *\n   * **WARNING:** Enabling this will result in excessive object allocation. This should be only\n   * be used for debugging purposes. Do NOT pass `BuildConfig.DEBUG`.\n   */\n  @Volatile var isLoggingEnabled: Boolean\n) : DefaultLifecycleObserver {\n  @get:JvmName(\"-requestTransformers\")\n  internal val requestTransformers: List<RequestTransformer> = requestTransformers.toList()\n\n  @get:JvmName(\"-requestHandlers\")\n  internal val requestHandlers: List<RequestHandler>\n\n  @get:JvmName(\"-eventListeners\")\n  internal val eventListeners: List<EventListener> = eventListeners.toList()\n\n  @get:JvmName(\"-targetToAction\")\n  internal val targetToAction = WeakHashMap<Any, Action>()\n\n  @get:JvmName(\"-targetToDeferredRequestCreator\")\n  internal val targetToDeferredRequestCreator = WeakHashMap<ImageView, DeferredRequestCreator>()\n\n  @get:JvmName(\"-shutdown\")\n  @set:JvmName(\"-shutdown\")\n  internal var shutdown = false\n\n  init {\n    // Adjust this and Builder(Picasso) as internal handlers are added or removed.\n    val builtInHandlers = 8\n\n    requestHandlers = buildList(builtInHandlers + extraRequestHandlers.size) {\n      // ResourceRequestHandler needs to be the first in the list to avoid\n      // forcing other RequestHandlers to perform null checks on request.uri\n      // to cover the (request.resourceId != 0) case.\n      add(ResourceDrawableRequestHandler.create(context))\n      add(ResourceRequestHandler(context))\n      addAll(extraRequestHandlers)\n      add(ContactsPhotoRequestHandler(context))\n      add(MediaStoreRequestHandler(context))\n      add(ContentStreamRequestHandler(context))\n      add(AssetRequestHandler(context))\n      add(FileRequestHandler(context))\n      add(NetworkRequestHandler(callFactory))\n    }\n  }\n\n  override fun onDestroy(owner: LifecycleOwner) {\n    super.onDestroy(owner)\n    cancelAll()\n  }\n\n  @JvmName(\"-cancelAll\")\n  internal fun cancelAll() {\n    checkMain()\n\n    val actions = targetToAction.values.toList()\n    for (i in actions.indices) {\n      val target = actions[i].getTarget() ?: continue\n      cancelExistingRequest(target)\n    }\n\n    val deferredRequestCreators = targetToDeferredRequestCreator.values.toList()\n    for (i in deferredRequestCreators.indices) {\n      deferredRequestCreators[i].cancel()\n    }\n  }\n\n  /** Cancel any existing requests for the specified target [ImageView]. */\n  fun cancelRequest(view: ImageView) {\n    // checkMain() is called from cancelExistingRequest()\n    cancelExistingRequest(view)\n  }\n\n  /** Cancel any existing requests for the specified [BitmapTarget] instance. */\n  fun cancelRequest(target: BitmapTarget) {\n    // checkMain() is called from cancelExistingRequest()\n    cancelExistingRequest(target)\n  }\n\n  /** Cancel any existing requests for the specified [DrawableTarget] instance. */\n  fun cancelRequest(target: DrawableTarget) {\n    // checkMain() is called from cancelExistingRequest()\n    cancelExistingRequest(target)\n  }\n\n  /**\n   * Cancel any existing requests for the specified [RemoteViews] target with the given [viewId].\n   */\n  fun cancelRequest(remoteViews: RemoteViews, @IdRes viewId: Int) {\n    // checkMain() is called from cancelExistingRequest()\n    cancelExistingRequest(RemoteViewsTarget(remoteViews, viewId))\n  }\n\n  /**\n   * Cancel any existing requests with given tag. You can set a tag\n   * on new requests with [RequestCreator.tag].\n   *\n   * @see RequestCreator.tag\n   */\n  fun cancelTag(tag: Any) {\n    checkMain()\n\n    val actions = targetToAction.values.toList()\n    for (i in actions.indices) {\n      val action = actions[i]\n      if (tag == action.tag) {\n        val target = action.getTarget() ?: continue\n        cancelExistingRequest(target)\n      }\n    }\n\n    val deferredRequestCreators = targetToDeferredRequestCreator.values.toList()\n    for (i in deferredRequestCreators.indices) {\n      val deferredRequestCreator = deferredRequestCreators[i]\n      if (tag == deferredRequestCreator.tag) {\n        deferredRequestCreator.cancel()\n      }\n    }\n  }\n\n  override fun onStop(owner: LifecycleOwner) {\n    super.onStop(owner)\n    pauseAll()\n  }\n\n  @JvmName(\"-pauseAll\")\n  internal fun pauseAll() {\n    checkMain()\n\n    val actions = targetToAction.values.toList()\n    for (i in actions.indices) {\n      dispatcher.dispatchPauseTag(actions[i].tag)\n    }\n\n    val deferredRequestCreators = targetToDeferredRequestCreator.values.toList()\n    for (i in deferredRequestCreators.indices) {\n      val tag = deferredRequestCreators[i].tag\n      if (tag != null) {\n        dispatcher.dispatchPauseTag(tag)\n      }\n    }\n  }\n\n  /**\n   * Pause existing requests with the given tag. Use [resumeTag]\n   * to resume requests with the given tag.\n   *\n   * @see [resumeTag]\n   * @see RequestCreator.tag\n   */\n  fun pauseTag(tag: Any) {\n    dispatcher.dispatchPauseTag(tag)\n  }\n\n  override fun onStart(owner: LifecycleOwner) {\n    resumeAll()\n  }\n\n  @JvmName(\"-resumeAll\")\n  internal fun resumeAll() {\n    checkMain()\n\n    val actions = targetToAction.values.toList()\n    for (i in actions.indices) {\n      dispatcher.dispatchResumeTag(actions[i].tag)\n    }\n\n    val deferredRequestCreators = targetToDeferredRequestCreator.values.toList()\n    for (i in deferredRequestCreators.indices) {\n      val tag = deferredRequestCreators[i].tag\n      if (tag != null) {\n        dispatcher.dispatchResumeTag(tag)\n      }\n    }\n  }\n\n  /**\n   * Resume paused requests with the given tag. Use [pauseTag]\n   * to pause requests with the given tag.\n   *\n   * @see [pauseTag]\n   * @see RequestCreator.tag\n   */\n  fun resumeTag(tag: Any) {\n    dispatcher.dispatchResumeTag(tag)\n  }\n\n  /**\n   * Start an image request using the specified URI.\n   *\n   * Passing `null` as a [uri] will not trigger any request but will set a placeholder,\n   * if one is specified.\n   *\n   * @see #load(File)\n   * @see #load(String)\n   * @see #load(int)\n   */\n  fun load(uri: Uri?): RequestCreator {\n    return RequestCreator(this, uri, 0)\n  }\n\n  /**\n   * Start an image request using the specified path. This is a convenience method for calling\n   * [load].\n   *\n   * This path may be a remote URL, file resource (prefixed with `file:`), content resource\n   * (prefixed with `content:`), or android resource (prefixed with `android.resource:`.\n   *\n   * Passing `null` as a [path] will not trigger any request but will set a\n   * placeholder, if one is specified.\n   *\n   * @throws IllegalArgumentException if [path] is empty or blank string.\n   * @see #load(Uri)\n   * @see #load(File)\n   * @see #load(int)\n   */\n  fun load(path: String?): RequestCreator {\n    if (path == null) {\n      return RequestCreator(this, null, 0)\n    }\n    require(path.isNotBlank()) { \"Path must not be empty.\" }\n    return load(Uri.parse(path))\n  }\n\n  /**\n   * Start an image request using the specified image file. This is a convenience method for\n   * calling [load].\n   *\n   * Passing `null` as a [file] will not trigger any request but will set a\n   * placeholder, if one is specified.\n   *\n   * Equivalent to calling [load(Uri.fromFile(file))][load].\n   *\n   * @see #load(Uri)\n   * @see #load(String)\n   * @see #load(int)\n   */\n  fun load(file: File?): RequestCreator {\n    return if (file == null) {\n      RequestCreator(this, null, 0)\n    } else {\n      load(Uri.fromFile(file))\n    }\n  }\n\n  /**\n   * Start an image request using the specified drawable resource ID.\n   *\n   * @see #load(Uri)\n   * @see #load(String)\n   * @see #load(File)\n   */\n  fun load(@DrawableRes resourceId: Int): RequestCreator {\n    require(resourceId != 0) { \"Resource ID must not be zero.\" }\n    return RequestCreator(this, null, resourceId)\n  }\n\n  /**\n   * Clear all the bitmaps from the memory cache.\n   */\n  fun evictAll() {\n    cache.clear()\n  }\n\n  /**\n   * Invalidate all memory cached images for the specified [uri].\n   *\n   * @see #invalidate(String)\n   * @see #invalidate(File)\n   */\n  fun invalidate(uri: Uri?) {\n    if (uri != null) {\n      cache.clearKeyUri(uri.toString())\n    }\n  }\n\n  /**\n   * Invalidate all memory cached images for the specified [path]. You can also pass a\n   * [stable key][RequestCreator.stableKey].\n   *\n   * @see #invalidate(Uri)\n   * @see #invalidate(File)\n   */\n  fun invalidate(path: String?) {\n    if (path != null) {\n      invalidate(Uri.parse(path))\n    }\n  }\n\n  /**\n   * Invalidate all memory cached images for the specified [file].\n   *\n   * @see #invalidate(Uri)\n   * @see #invalidate(String)\n   */\n  fun invalidate(file: File) {\n    invalidate(Uri.fromFile(file))\n  }\n\n  /** Stops this instance from accepting further requests.  */\n  fun shutdown() {\n    if (shutdown) {\n      return\n    }\n    cache.clear()\n\n    close()\n\n    dispatcher.shutdown()\n    try {\n      closeableCache?.close()\n    } catch (ignored: IOException) {\n    }\n    for (deferredRequestCreator in targetToDeferredRequestCreator.values) {\n      deferredRequestCreator.cancel()\n    }\n    targetToAction.clear()\n    targetToDeferredRequestCreator.clear()\n    shutdown = true\n  }\n\n  @JvmName(\"-transformRequest\")\n  internal fun transformRequest(request: Request): Request {\n    var nextRequest = request\n    for (i in requestTransformers.indices) {\n      val transformer = requestTransformers[i]\n      nextRequest = transformer.transformRequest(nextRequest)\n    }\n    return nextRequest\n  }\n\n  @JvmName(\"-defer\")\n  internal fun defer(view: ImageView, request: DeferredRequestCreator) {\n    // If there is already a deferred request, cancel it.\n    if (targetToDeferredRequestCreator.containsKey(view)) {\n      cancelExistingRequest(view)\n    }\n    targetToDeferredRequestCreator[view] = request\n  }\n\n  @JvmName(\"-enqueueAndSubmit\")\n  internal fun enqueueAndSubmit(action: Action) {\n    val target = action.getTarget() ?: return\n    if (targetToAction[target] !== action) {\n      // This will also check we are on the main thread.\n      cancelExistingRequest(target)\n      targetToAction[target] = action\n    }\n    submit(action)\n  }\n\n  @JvmName(\"-submit\")\n  internal fun submit(action: Action) {\n    dispatcher.dispatchSubmit(action)\n  }\n\n  @JvmName(\"-quickMemoryCacheCheck\")\n  internal fun quickMemoryCacheCheck(key: String): Bitmap? {\n    val cached = cache[key]\n    if (cached != null) {\n      cacheHit()\n    } else {\n      cacheMiss()\n    }\n    return cached\n  }\n\n  @JvmName(\"-complete\")\n  internal fun complete(hunter: BitmapHunter) {\n    val single = hunter.action\n    val joined = hunter.actions\n\n    val hasMultiple = !joined.isNullOrEmpty()\n    val shouldDeliver = single != null || hasMultiple\n\n    if (!shouldDeliver) {\n      return\n    }\n\n    val exception = hunter.exception\n    val result = hunter.result\n\n    single?.let { deliverAction(result, it, exception) }\n\n    if (joined != null) {\n      for (i in joined.indices) {\n        deliverAction(result, joined[i], exception)\n      }\n    }\n\n    if (listener != null && exception != null) {\n      listener.onImageLoadFailed(this, hunter.data.uri, exception)\n    }\n  }\n\n  @JvmName(\"-resumeAction\")\n  internal fun resumeAction(action: Action) {\n    val bitmap = if (shouldReadFromMemoryCache(action.request.memoryPolicy)) {\n      quickMemoryCacheCheck(action.request.key)\n    } else {\n      null\n    }\n\n    if (bitmap != null) {\n      // Resumed action is cached, complete immediately.\n      deliverAction(Result.Bitmap(bitmap, MEMORY), action, null)\n      if (isLoggingEnabled) {\n        log(\n          owner = OWNER_MAIN,\n          verb = VERB_COMPLETED,\n          logId = action.request.logId(),\n          extras = \"from $MEMORY\"\n        )\n      }\n    } else {\n      // Re-submit the action to the executor.\n      enqueueAndSubmit(action)\n      if (isLoggingEnabled) {\n        log(\n          owner = OWNER_MAIN,\n          verb = VERB_RESUMED,\n          logId = action.request.logId()\n        )\n      }\n    }\n  }\n\n  private fun deliverAction(result: Result?, action: Action, e: Exception?) {\n    if (action.cancelled) {\n      return\n    }\n    if (!action.willReplay) {\n      targetToAction.remove(action.getTarget())\n    }\n    if (result != null) {\n      action.complete(result)\n      if (isLoggingEnabled) {\n        log(\n          owner = OWNER_MAIN,\n          verb = VERB_COMPLETED,\n          logId = action.request.logId(),\n          extras = \"from ${result.loadedFrom}\"\n        )\n      }\n    } else if (e != null) {\n      action.error(e)\n      if (isLoggingEnabled) {\n        log(\n          owner = OWNER_MAIN,\n          verb = VERB_ERRORED,\n          logId = action.request.logId(),\n          extras = e.message\n        )\n      }\n    }\n  }\n\n  private fun cancelExistingRequest(target: Any) {\n    checkMain()\n    val action = targetToAction.remove(target)\n    if (action != null) {\n      action.cancel()\n      dispatcher.dispatchCancel(action)\n    }\n    if (target is ImageView) {\n      val deferredRequestCreator = targetToDeferredRequestCreator.remove(target)\n      deferredRequestCreator?.cancel()\n    }\n  }\n\n  fun newBuilder(): Builder = Builder(this)\n\n  /** Fluent API for creating [Picasso] instances.  */\n  class Builder {\n    private val context: Context\n    private var callFactory: Call.Factory? = null\n    private var service: ExecutorService? = null\n    private var mainContext: CoroutineContext? = null\n    private var backgroundContext: CoroutineContext? = null\n    private var cache: PlatformLruCache? = null\n    private var listener: Listener? = null\n    private val requestTransformers = mutableListOf<RequestTransformer>()\n    private val requestHandlers = mutableListOf<RequestHandler>()\n    private val eventListeners = mutableListOf<EventListener>()\n    private var defaultBitmapConfig: Config? = null\n    private var indicatorsEnabled = false\n    private var loggingEnabled = false\n\n    /** Start building a new [Picasso] instance.  */\n    constructor(context: Context) {\n      this.context = context.applicationContext\n    }\n\n    internal constructor(picasso: Picasso) {\n      context = picasso.context\n      callFactory = picasso.callFactory\n      service = (picasso.dispatcher as? HandlerDispatcher)?.service\n      mainContext = (picasso.dispatcher as? InternalCoroutineDispatcher)?.mainContext\n      backgroundContext = (picasso.dispatcher as? InternalCoroutineDispatcher)?.backgroundContext\n      cache = picasso.cache\n      listener = picasso.listener\n      requestTransformers += picasso.requestTransformers\n      // See Picasso(). Removes internal request handlers added before and after custom handlers.\n      val numRequestHandlers = picasso.requestHandlers.size\n      requestHandlers += picasso.requestHandlers.subList(2, numRequestHandlers - 6)\n      eventListeners += picasso.eventListeners\n\n      defaultBitmapConfig = picasso.defaultBitmapConfig\n      indicatorsEnabled = picasso.indicatorsEnabled\n      loggingEnabled = picasso.isLoggingEnabled\n    }\n\n    /**\n     * Specify the default [Bitmap.Config] used when decoding images. This can be overridden\n     * on a per-request basis using [RequestCreator.config].\n     */\n    fun defaultBitmapConfig(bitmapConfig: Config) = apply {\n      defaultBitmapConfig = bitmapConfig\n    }\n\n    /**\n     * Specify the HTTP client to be used for network requests.\n     *\n     * Note: Calling [callFactory] overwrites this value.\n     */\n    fun client(client: OkHttpClient) = apply {\n      callFactory = client\n    }\n\n    /**\n     * Specify the call factory to be used for network requests.\n     *\n     * Note: Calling [client] overwrites this value.\n     */\n    fun callFactory(factory: Call.Factory) = apply {\n      callFactory = factory\n    }\n\n    /**\n     * Specify the executor service for loading images in the background.\n     *\n     * Note: Calling [Picasso.shutdown] will not shutdown supplied executors.\n     */\n    fun executor(executorService: ExecutorService) = apply {\n      service = executorService\n    }\n\n    /**\n     * Specify the memory cache size in bytes to use for the most recent images.\n     * A size of 0 disables in-memory caching.\n     */\n    fun withCacheSize(maxByteCount: Int) = apply {\n      require(maxByteCount >= 0) { \"maxByteCount < 0: $maxByteCount\" }\n      cache = PlatformLruCache(maxByteCount)\n    }\n\n    /** Specify a listener for interesting events. */\n    fun listener(listener: Listener) = apply {\n      this.listener = listener\n    }\n\n    /** Add a transformer that observes and potentially modify all incoming requests. */\n    fun addRequestTransformer(transformer: RequestTransformer) = apply {\n      requestTransformers += transformer\n    }\n\n    /** Register a [RequestHandler]. */\n    fun addRequestHandler(requestHandler: RequestHandler) = apply {\n      requestHandlers += requestHandler\n    }\n\n    /** Register a [EventListener]. */\n    fun addEventListener(eventListener: EventListener) = apply {\n      eventListeners += eventListener\n    }\n\n    /** Toggle whether to display debug indicators on images. */\n    fun indicatorsEnabled(enabled: Boolean) = apply {\n      indicatorsEnabled = enabled\n    }\n\n    /**\n     * Toggle whether debug logging is enabled.\n     *\n     * **WARNING:** Enabling this will result in excessive object allocation. This should be only\n     * be used for debugging purposes. Do NOT pass `BuildConfig.DEBUG`.\n     */\n    fun loggingEnabled(enabled: Boolean) = apply {\n      loggingEnabled = enabled\n    }\n\n    /**\n     * Sets the CoroutineDispatchers used internally\n     */\n    fun dispatchers(\n      mainContext: CoroutineContext = Dispatchers.Main,\n      backgroundContext: CoroutineContext = Dispatchers.IO\n    ) = apply {\n      this.mainContext = mainContext\n      this.backgroundContext = backgroundContext\n    }\n\n    /** Create the [Picasso] instance. */\n    fun build(): Picasso {\n      var unsharedCache: okhttp3.Cache? = null\n      if (callFactory == null) {\n        val cacheDir = createDefaultCacheDir(context)\n        val maxSize = calculateDiskCacheSize(cacheDir)\n        unsharedCache = okhttp3.Cache(cacheDir, maxSize)\n        callFactory = OkHttpClient.Builder()\n          .cache(unsharedCache)\n          .build()\n      }\n      if (cache == null) {\n        cache = PlatformLruCache(calculateMemoryCacheSize(context))\n      }\n\n      val dispatcher = if (backgroundContext != null) {\n        InternalCoroutineDispatcher(context, HANDLER, cache!!, mainContext!!, backgroundContext!!)\n      } else {\n        if (service == null) {\n          service = PicassoExecutorService()\n        }\n\n        HandlerDispatcher(context, service!!, HANDLER, cache!!)\n      }\n\n      return Picasso(\n        context, dispatcher, callFactory!!, unsharedCache, cache!!, listener,\n        requestTransformers, requestHandlers, eventListeners, defaultBitmapConfig,\n        indicatorsEnabled, loggingEnabled\n      )\n    }\n  }\n\n  /** Event listener methods **/\n\n  @JvmName(\"-cacheMaxSize\") // Prefix with '-' to hide from Java.\n  internal fun cacheMaxSize(maxSize: Int) {\n    val numListeners = eventListeners.size\n    for (i in 0 until numListeners) {\n      eventListeners[i].cacheMaxSize(maxSize)\n    }\n  }\n\n  @JvmName(\"-cacheSize\") // Prefix with '-' to hide from Java.\n  internal fun cacheSize(size: Int) {\n    val numListeners = eventListeners.size\n    for (i in 0 until numListeners) {\n      eventListeners[i].cacheSize(size)\n    }\n  }\n\n  @JvmName(\"-cacheHit\") // Prefix with '-' to hide from Java.\n  internal fun cacheHit() {\n    val numListeners = eventListeners.size\n    for (i in 0 until numListeners) {\n      eventListeners[i].cacheHit()\n    }\n  }\n\n  @JvmName(\"-cacheMiss\") // Prefix with '-' to hide from Java.\n  internal fun cacheMiss() {\n    val numListeners = eventListeners.size\n    for (i in 0 until numListeners) {\n      eventListeners[i].cacheMiss()\n    }\n  }\n\n  @JvmName(\"-downloadFinished\") // Prefix with '-' to hide from Java.\n  internal fun downloadFinished(size: Long) {\n    val numListeners = eventListeners.size\n    for (i in 0 until numListeners) {\n      eventListeners[i].downloadFinished(size)\n    }\n  }\n\n  @JvmName(\"-bitmapDecoded\") // Prefix with '-' to hide from Java.\n  internal fun bitmapDecoded(bitmap: Bitmap) {\n    val numListeners = eventListeners.size\n    for (i in 0 until numListeners) {\n      eventListeners[i].bitmapDecoded(bitmap)\n    }\n  }\n\n  @JvmName(\"-bitmapTransformed\") // Prefix with '-' to hide from Java.\n  internal fun bitmapTransformed(bitmap: Bitmap) {\n    val numListeners = eventListeners.size\n    for (i in 0 until numListeners) {\n      eventListeners[i].bitmapTransformed(bitmap)\n    }\n  }\n\n  @JvmName(\"-close\") // Prefix with '-' to hide from Java.\n  internal fun close() {\n    val numListeners = eventListeners.size\n    for (i in 0 until numListeners) {\n      eventListeners[i].close()\n    }\n  }\n\n  /** Callbacks for Picasso events.  */\n  fun interface Listener {\n    /**\n     * Invoked when an image has failed to load. This is useful for reporting image failures to a\n     * remote analytics service, for example.\n     */\n    fun onImageLoadFailed(picasso: Picasso, uri: Uri?, exception: Exception)\n  }\n\n  /**\n   * A transformer that is called immediately before every request is submitted. This can be used to\n   * modify any information about a request.\n   *\n   * For example, if you use a CDN you can change the hostname for the image based on the current\n   * location of the user in order to get faster download speeds.\n   */\n  fun interface RequestTransformer {\n    /**\n     * Transform a request before it is submitted to be processed.\n     *\n     * @return The original request or a new request to replace it. Must not be null.\n     */\n    fun transformRequest(request: Request): Request\n  }\n\n  /**\n   * The priority of a request.\n   *\n   * @see RequestCreator.priority\n   */\n  enum class Priority {\n    LOW,\n    NORMAL,\n\n    /**\n     * High priority requests will post to the front of main thread's message queue when\n     * they complete loading and their images need to be rendered.\n     */\n    HIGH\n  }\n\n  /** Describes where the image was loaded from.  */\n  enum class LoadedFrom(@get:JvmName(\"-debugColor\") internal val debugColor: Int) {\n    MEMORY(Color.GREEN),\n    DISK(Color.BLUE),\n    NETWORK(Color.RED)\n  }\n\n  internal companion object {\n    @get:JvmName(\"-handler\")\n    internal val HANDLER = Handler(Looper.getMainLooper())\n  }\n}\n\nconst val TAG = \"Picasso\"\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/PicassoDrawable.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.ColorFilter\nimport android.graphics.Paint\nimport android.graphics.Path\nimport android.graphics.Rect\nimport android.graphics.drawable.Animatable\nimport android.graphics.drawable.BitmapDrawable\nimport android.graphics.drawable.Drawable\nimport android.os.SystemClock\nimport android.widget.ImageView\nimport com.squareup.picasso3.Picasso.LoadedFrom\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.RequestHandler.Result\n\ninternal class PicassoDrawable(\n  context: Context,\n  bitmap: Bitmap,\n  placeholder: Drawable?,\n  private val loadedFrom: LoadedFrom,\n  noFade: Boolean,\n  private val debugging: Boolean\n) : BitmapDrawable(context.resources, bitmap) {\n  private val density: Float = context.resources.displayMetrics.density\n  var placeholder: Drawable? = null\n  var startTimeMillis: Long = 0\n  var animating = false\n  private var alpha = 0xFF\n\n  init {\n    val fade = loadedFrom != MEMORY && !noFade\n    if (fade) {\n      this.placeholder = placeholder\n      animating = true\n      startTimeMillis = SystemClock.uptimeMillis()\n    }\n  }\n\n  override fun draw(canvas: Canvas) {\n    if (!animating) {\n      super.draw(canvas)\n    } else {\n      val normalized = (SystemClock.uptimeMillis() - startTimeMillis) / FADE_DURATION\n      if (normalized >= 1f) {\n        animating = false\n        placeholder = null\n        super.draw(canvas)\n      } else {\n        if (placeholder != null) {\n          placeholder!!.draw(canvas)\n        }\n\n        // setAlpha will call invalidateSelf and drive the animation.\n        val partialAlpha = (alpha * normalized).toInt()\n        super.setAlpha(partialAlpha)\n        super.draw(canvas)\n        super.setAlpha(alpha)\n      }\n    }\n\n    if (debugging) {\n      drawDebugIndicator(canvas)\n    }\n  }\n\n  override fun setAlpha(alpha: Int) {\n    this.alpha = alpha\n    if (placeholder != null) {\n      placeholder!!.alpha = alpha\n    }\n    super.setAlpha(alpha)\n  }\n\n  override fun setColorFilter(cf: ColorFilter?) {\n    if (placeholder != null) {\n      placeholder!!.colorFilter = cf\n    }\n    super.setColorFilter(cf)\n  }\n\n  override fun onBoundsChange(bounds: Rect) {\n    if (placeholder != null) {\n      placeholder!!.bounds = bounds\n    }\n    super.onBoundsChange(bounds)\n  }\n\n  private fun drawDebugIndicator(canvas: Canvas) {\n    DEBUG_PAINT.color = Color.WHITE\n    var path = getTrianglePath(0, 0, (16 * density).toInt())\n    canvas.drawPath(path, DEBUG_PAINT)\n\n    DEBUG_PAINT.color = loadedFrom.debugColor\n    path = getTrianglePath(0, 0, (15 * density).toInt())\n    canvas.drawPath(path, DEBUG_PAINT)\n  }\n\n  companion object {\n    // Only accessed from main thread.\n    private val DEBUG_PAINT = Paint()\n    private const val FADE_DURATION = 200f // ms\n\n    /**\n     * Create or update the drawable on the target [ImageView] to display the supplied bitmap\n     * image.\n     */\n    fun setResult(\n      target: ImageView,\n      context: Context,\n      result: Result,\n      noFade: Boolean,\n      debugging: Boolean\n    ) {\n      val placeholder = target.drawable\n      if (placeholder is Animatable) {\n        (placeholder as Animatable).stop()\n      }\n\n      if (result is Result.Bitmap) {\n        val bitmap = result.bitmap\n        val loadedFrom = result.loadedFrom\n        val drawable = PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging)\n        target.setImageDrawable(drawable)\n      } else {\n        val drawable = (result as Result.Drawable).drawable\n        target.setImageDrawable(drawable)\n        if (drawable is Animatable) {\n          (drawable as Animatable).start()\n        }\n      }\n    }\n\n    /**\n     * Create or update the drawable on the target [ImageView] to display the supplied\n     * placeholder image.\n     */\n    fun setPlaceholder(target: ImageView, placeholderDrawable: Drawable?) {\n      target.setImageDrawable(placeholderDrawable)\n      if (target.drawable is Animatable) {\n        (target.drawable as Animatable).start()\n      }\n    }\n\n    fun getTrianglePath(x1: Int, y1: Int, width: Int): Path {\n      return Path().apply {\n        moveTo(x1.toFloat(), y1.toFloat())\n        lineTo((x1 + width).toFloat(), y1.toFloat())\n        lineTo(x1.toFloat(), (y1 + width).toFloat())\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/PicassoExecutorService.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.os.Process\nimport android.os.Process.THREAD_PRIORITY_BACKGROUND\nimport java.util.concurrent.Future\nimport java.util.concurrent.FutureTask\nimport java.util.concurrent.PriorityBlockingQueue\nimport java.util.concurrent.ThreadFactory\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit.MILLISECONDS\n\n/**\n * The default [java.util.concurrent.ExecutorService] used for new [Picasso] instances.\n */\nclass PicassoExecutorService(\n  threadCount: Int = DEFAULT_THREAD_COUNT,\n  threadFactory: ThreadFactory = PicassoThreadFactory()\n) : ThreadPoolExecutor(\n  threadCount,\n  threadCount,\n  0,\n  MILLISECONDS,\n  PriorityBlockingQueue(),\n  threadFactory\n) {\n  override fun submit(task: Runnable): Future<*> {\n    val ftask = PicassoFutureTask(task as BitmapHunter)\n    execute(ftask)\n    return ftask\n  }\n\n  private class PicassoThreadFactory : ThreadFactory {\n    override fun newThread(r: Runnable): Thread = PicassoThread(r)\n\n    private class PicassoThread(r: Runnable) : Thread(r) {\n      override fun run() {\n        name = Utils.THREAD_IDLE_NAME\n        Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND)\n        super.run()\n      }\n    }\n  }\n\n  private class PicassoFutureTask(private val hunter: BitmapHunter) :\n    FutureTask<BitmapHunter>(hunter, null), Comparable<PicassoFutureTask> {\n    override fun compareTo(other: PicassoFutureTask): Int {\n      val p1 = hunter.priority\n      val p2 = other.hunter.priority\n\n      // High-priority requests are \"lesser\" so they are sorted to the front.\n      // Equal priorities are sorted by sequence number to provide FIFO ordering.\n      return if (p1 == p2) hunter.sequence - other.hunter.sequence else p2.ordinal - p1.ordinal\n    }\n  }\n\n  private companion object {\n    private const val DEFAULT_THREAD_COUNT = 3\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/PlatformLruCache.kt",
    "content": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap\nimport android.util.LruCache\n\n/** A memory cache which uses a least-recently used eviction policy.  */\ninternal class PlatformLruCache(maxByteCount: Int) {\n  /** Create a cache with a given maximum size in bytes.  */\n  val cache =\n    object : LruCache<String, BitmapAndSize>(if (maxByteCount != 0) maxByteCount else 1) {\n      override fun sizeOf(\n        key: String,\n        value: BitmapAndSize\n      ): Int = value.byteCount\n    }\n\n  operator fun get(key: String): Bitmap? = cache[key]?.bitmap\n\n  operator fun set(\n    key: String,\n    bitmap: Bitmap\n  ) {\n    val byteCount = bitmap.allocationByteCount\n    // If the bitmap is too big for the cache, don't even attempt to store it. Doing so will cause\n    // the cache to be cleared. Instead just evict an existing element with the same key if it\n    // exists.\n    if (byteCount > maxSize()) {\n      cache.remove(key)\n      return\n    }\n\n    cache.put(key, BitmapAndSize(bitmap, byteCount))\n  }\n\n  fun size(): Int = cache.size()\n\n  fun maxSize(): Int = cache.maxSize()\n\n  fun clear() = cache.evictAll()\n\n  fun clearKeyUri(uri: String) {\n    // Keys are prefixed with a URI followed by '\\n'.\n    for (key in cache.snapshot().keys) {\n      if (key.startsWith(uri) &&\n        key.length > uri.length &&\n        key[uri.length] == Request.KEY_SEPARATOR\n      ) {\n        cache.remove(key)\n      }\n    }\n  }\n\n  /** Returns the number of times [get] returned a value.  */\n  fun hitCount(): Int = cache.hitCount()\n\n  /** Returns the number of times [get] returned `null`.  */\n  fun missCount(): Int = cache.missCount()\n\n  /** Returns the number of times [set] was called.  */\n  fun putCount(): Int = cache.putCount()\n\n  /** Returns the number of values that have been evicted.  */\n  fun evictionCount(): Int = cache.evictionCount()\n\n  internal class BitmapAndSize(\n    val bitmap: Bitmap,\n    val byteCount: Int\n  )\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/RemoteViewsAction.kt",
    "content": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.app.Notification\nimport android.app.NotificationManager\nimport android.appwidget.AppWidgetManager\nimport android.widget.RemoteViews\nimport androidx.annotation.DrawableRes\nimport androidx.core.content.ContextCompat\nimport com.squareup.picasso3.RequestHandler.Result\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\n\ninternal abstract class RemoteViewsAction(\n  picasso: Picasso,\n  data: Request,\n  @DrawableRes val errorResId: Int,\n  val target: RemoteViewsTarget,\n  var callback: Callback?\n) : Action(picasso, data) {\n  override fun complete(result: Result) {\n    if (result is Bitmap) {\n      target.remoteViews.setImageViewBitmap(target.viewId, result.bitmap)\n      update()\n      callback?.onSuccess()\n    }\n  }\n\n  override fun cancel() {\n    super.cancel()\n    callback = null\n  }\n\n  override fun error(e: Exception) {\n    if (errorResId != 0) {\n      setImageResource(errorResId)\n    }\n    callback?.onError(e)\n  }\n\n  fun setImageResource(resId: Int) {\n    target.remoteViews.setImageViewResource(target.viewId, resId)\n    update()\n  }\n\n  abstract fun update()\n\n  internal class RemoteViewsTarget(\n    val remoteViews: RemoteViews,\n    val viewId: Int\n  ) {\n    override fun equals(other: Any?): Boolean {\n      if (this === other) return true\n      if (other == null || javaClass != other.javaClass) return false\n      val remoteViewsTarget = other as RemoteViewsTarget\n      return viewId == remoteViewsTarget.viewId && remoteViews ==\n        remoteViewsTarget.remoteViews\n    }\n\n    override fun hashCode(): Int {\n      return 31 * remoteViews.hashCode() + viewId\n    }\n  }\n\n  internal class AppWidgetAction(\n    picasso: Picasso,\n    data: Request,\n    @DrawableRes errorResId: Int,\n    target: RemoteViewsTarget,\n    private val appWidgetIds: IntArray,\n    callback: Callback?\n  ) : RemoteViewsAction(picasso, data, errorResId, target, callback) {\n    override fun update() {\n      val manager = AppWidgetManager.getInstance(picasso.context)\n      manager.updateAppWidget(appWidgetIds, target.remoteViews)\n    }\n\n    override fun getTarget(): Any {\n      return target\n    }\n  }\n\n  internal class NotificationAction(\n    picasso: Picasso,\n    data: Request,\n    @DrawableRes errorResId: Int,\n    target: RemoteViewsTarget,\n    private val notificationId: Int,\n    private val notification: Notification,\n    private val notificationTag: String?,\n    callback: Callback?\n  ) : RemoteViewsAction(picasso, data, errorResId, target, callback) {\n    override fun update() {\n      val manager = ContextCompat.getSystemService(\n        picasso.context,\n        NotificationManager::class.java\n      )\n      manager?.notify(notificationTag, notificationId, notification)\n    }\n\n    override fun getTarget(): Any {\n      return target\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Request.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap.Config\nimport android.net.Uri\nimport android.os.Looper\nimport android.view.Gravity\nimport androidx.annotation.DrawableRes\nimport androidx.annotation.Px\nimport com.squareup.picasso3.Picasso.Priority\nimport com.squareup.picasso3.Picasso.Priority.NORMAL\nimport okhttp3.Headers\nimport java.util.concurrent.TimeUnit.NANOSECONDS\nimport java.util.concurrent.TimeUnit.SECONDS\n\n/** Immutable data about an image and the transformations that will be applied to it. */\nclass Request internal constructor(builder: Builder) {\n  /** A unique ID for the request.  */\n  @JvmField var id = 0\n\n  /** The time that the request was first submitted (in nanos). */\n  @JvmField var started: Long = 0\n\n  /** The [MemoryPolicy] to use for this request. */\n  @JvmField val memoryPolicy: Int = builder.memoryPolicy\n\n  /** The [NetworkPolicy] to use for this request. */\n  @JvmField val networkPolicy: Int = builder.networkPolicy\n\n  /** HTTP headers for the request  */\n  @JvmField val headers: Headers? = builder.headers\n\n  /**\n   * The image URI.\n   *\n   * This is mutually exclusive with [.resourceId].\n   */\n  @JvmField val uri: Uri? = builder.uri\n\n  /**\n   * The image resource ID.\n   *\n   * This is mutually exclusive with [.uri].\n   */\n  @JvmField val resourceId: Int = builder.resourceId\n\n  /**\n   * Optional stable key for this request to be used instead of the URI or resource ID when\n   * caching. Two requests with the same value are considered to be for the same resource.\n   */\n  val stableKey: String? = builder.stableKey\n\n  /** List of custom transformations to be applied after the built-in transformations. */\n  @JvmField var transformations: List<Transformation> =\n    if (builder.transformations == null) {\n      emptyList()\n    } else {\n      builder.transformations!!.toList()\n    }\n\n  /** Target image width for resizing. */\n  @JvmField val targetWidth: Int = builder.targetWidth\n\n  /** Target image height for resizing. */\n  @JvmField val targetHeight: Int = builder.targetHeight\n\n  /**\n   * True if the final image should use the 'centerCrop' scale technique.\n   *\n   * This is mutually exclusive with [.centerInside].\n   */\n  @JvmField val centerCrop: Boolean = builder.centerCrop\n\n  /** If centerCrop is set, controls alignment of centered image */\n  @JvmField val centerCropGravity: Int = builder.centerCropGravity\n\n  /**\n   * True if the final image should use the 'centerInside' scale technique.\n   *\n   * This is mutually exclusive with [.centerCrop].\n   */\n  @JvmField val centerInside: Boolean = builder.centerInside\n\n  @JvmField val onlyScaleDown: Boolean = builder.onlyScaleDown\n\n  /** Amount to rotate the image in degrees. */\n  @JvmField val rotationDegrees: Float = builder.rotationDegrees\n\n  /** Rotation pivot on the X axis. */\n  @JvmField val rotationPivotX: Float = builder.rotationPivotX\n\n  /** Rotation pivot on the Y axis. */\n  @JvmField val rotationPivotY: Float = builder.rotationPivotY\n\n  /** Whether or not [.rotationPivotX] and [.rotationPivotY] are set. */\n  @JvmField val hasRotationPivot: Boolean = builder.hasRotationPivot\n\n  /** Target image config for decoding. */\n  @JvmField val config: Config? = builder.config\n\n  /** The priority of this request. */\n  @JvmField val priority: Priority = checkNotNull(builder.priority)\n\n  /** The cache key for this request. */\n  @JvmField var key: String =\n    if (Looper.myLooper() == Looper.getMainLooper()) {\n      createKey()\n    } else {\n      createKey(StringBuilder())\n    }\n\n  /** User-provided value to track this request. */\n  val tag: Any? = builder.tag\n\n  override fun toString() =\n    buildString {\n      append(\"Request{\")\n      if (resourceId > 0) {\n        append(resourceId)\n      } else {\n        append(uri)\n      }\n      for (transformation in transformations) {\n        append(' ')\n        append(transformation.key())\n      }\n      if (stableKey != null) {\n        append(\" stableKey(\")\n        append(stableKey)\n        append(')')\n      }\n      if (targetWidth > 0) {\n        append(\" resize(\")\n        append(targetWidth)\n        append(',')\n        append(targetHeight)\n        append(')')\n      }\n      if (centerCrop) {\n        append(\" centerCrop\")\n      }\n      if (centerInside) {\n        append(\" centerInside\")\n      }\n      if (rotationDegrees != 0f) {\n        append(\" rotation(\")\n        append(rotationDegrees)\n        if (hasRotationPivot) {\n          append(\" @ \")\n          append(rotationPivotX)\n          append(',')\n          append(rotationPivotY)\n        }\n        append(')')\n      }\n      if (config != null) {\n        append(' ')\n        append(config)\n      }\n      append('}')\n    }\n\n  // TODO make internal\n  fun logId(): String {\n    val delta = System.nanoTime() - started\n    return if (delta > TOO_LONG_LOG) {\n      \"${plainId()}+${NANOSECONDS.toSeconds(delta)}s\"\n    } else {\n      \"${plainId()}+${NANOSECONDS.toMillis(delta)}ms\"\n    }\n  }\n\n  // TODO make internal\n  fun plainId() = \"[R$id]\"\n\n  // TODO make internal\n  val name: String\n    get() = uri?.path ?: Integer.toHexString(resourceId)\n\n  // TODO make internal\n  fun hasSize(): Boolean = targetWidth != 0 || targetHeight != 0\n\n  // TODO make internal\n  fun needsMatrixTransform(): Boolean = hasSize() || rotationDegrees != 0f\n\n  fun newBuilder(): Builder = Builder(this)\n\n  private fun createKey(): String {\n    val result = createKey(Utils.MAIN_THREAD_KEY_BUILDER)\n    Utils.MAIN_THREAD_KEY_BUILDER.setLength(0)\n    return result\n  }\n\n  private fun createKey(builder: StringBuilder): String {\n    val data = this\n    if (data.stableKey != null) {\n      builder.ensureCapacity(data.stableKey.length + KEY_PADDING)\n      builder.append(data.stableKey)\n    } else if (data.uri != null) {\n      val path = data.uri.toString()\n      builder.ensureCapacity(path.length + KEY_PADDING)\n      builder.append(path)\n    } else {\n      builder.ensureCapacity(KEY_PADDING)\n      builder.append(data.resourceId)\n    }\n\n    builder.append(KEY_SEPARATOR)\n\n    if (data.rotationDegrees != 0f) {\n      builder\n        .append(\"rotation:\")\n        .append(data.rotationDegrees)\n\n      if (data.hasRotationPivot) {\n        builder\n          .append('@')\n          .append(data.rotationPivotX)\n          .append('x')\n          .append(data.rotationPivotY)\n      }\n\n      builder.append(KEY_SEPARATOR)\n    }\n\n    if (data.hasSize()) {\n      builder\n        .append(\"resize:\")\n        .append(data.targetWidth)\n        .append('x')\n        .append(data.targetHeight)\n\n      builder.append(KEY_SEPARATOR)\n    }\n\n    if (data.centerCrop) {\n      builder\n        .append(\"centerCrop:\")\n        .append(data.centerCropGravity)\n        .append(KEY_SEPARATOR)\n    } else if (data.centerInside) {\n      builder\n        .append(\"centerInside\")\n        .append(KEY_SEPARATOR)\n    }\n\n    for (i in data.transformations.indices) {\n      builder.append(data.transformations[i].key())\n      builder.append(KEY_SEPARATOR)\n    }\n\n    return builder.toString()\n  }\n\n  /** Builder for creating [Request] instances.  */\n  class Builder {\n    var uri: Uri? = null\n    var resourceId = 0\n    var stableKey: String? = null\n    var targetWidth = 0\n    var targetHeight = 0\n    var centerCrop = false\n    var centerCropGravity = 0\n    var centerInside = false\n    var onlyScaleDown = false\n    var rotationDegrees = 0f\n    var rotationPivotX = 0f\n    var rotationPivotY = 0f\n    var hasRotationPivot = false\n    var transformations: MutableList<Transformation>? = null\n    var config: Config? = null\n    var priority: Priority? = null\n\n    /** Internal use only. Used by [DeferredRequestCreator]. */\n    var tag: Any? = null\n    var memoryPolicy = 0\n    var networkPolicy = 0\n    var headers: Headers? = null\n\n    /** Start building a request using the specified [Uri]. */\n    constructor(uri: Uri) {\n      setUri(uri)\n    }\n\n    /** Start building a request using the specified resource ID. */\n    constructor(@DrawableRes resourceId: Int) {\n      setResourceId(resourceId)\n    }\n\n    internal constructor(\n      uri: Uri?,\n      resourceId: Int,\n      bitmapConfig: Config?\n    ) {\n      this.uri = uri\n      this.resourceId = resourceId\n      config = bitmapConfig\n    }\n\n    internal constructor(request: Request) {\n      uri = request.uri\n      resourceId = request.resourceId\n      stableKey = request.stableKey\n      targetWidth = request.targetWidth\n      targetHeight = request.targetHeight\n      centerCrop = request.centerCrop\n      centerInside = request.centerInside\n      centerCropGravity = request.centerCropGravity\n      rotationDegrees = request.rotationDegrees\n      rotationPivotX = request.rotationPivotX\n      rotationPivotY = request.rotationPivotY\n      hasRotationPivot = request.hasRotationPivot\n      onlyScaleDown = request.onlyScaleDown\n      transformations = request.transformations.toMutableList()\n      config = request.config\n      priority = request.priority\n      memoryPolicy = request.memoryPolicy\n      networkPolicy = request.networkPolicy\n      headers = request.headers\n    }\n\n    fun hasImage(): Boolean {\n      return uri != null || resourceId != 0\n    }\n\n    fun hasSize(): Boolean {\n      return targetWidth != 0 || targetHeight != 0\n    }\n\n    fun hasPriority(): Boolean {\n      return priority != null\n    }\n\n    /**\n     * Set the target image Uri.\n     *\n     * This will clear an image resource ID if one is set.\n     */\n    fun setUri(uri: Uri) = apply {\n      this.uri = uri\n      resourceId = 0\n    }\n\n    /**\n     * Set the target image resource ID.\n     *\n     * This will clear an image Uri if one is set.\n     */\n    fun setResourceId(@DrawableRes resourceId: Int) = apply {\n      require(resourceId != 0) { \"Image resource ID may not be 0.\" }\n      this.resourceId = resourceId\n      uri = null\n    }\n\n    /**\n     * Set the stable key to be used instead of the URI or resource ID when caching.\n     * Two requests with the same value are considered to be for the same resource.\n     */\n    fun stableKey(stableKey: String?) = apply {\n      this.stableKey = stableKey\n    }\n\n    /**\n     * Assign a tag to this request.\n     */\n    fun tag(tag: Any) = apply {\n      check(this.tag == null) { \"Tag already set.\" }\n      this.tag = tag\n    }\n\n    /** Internal use only. Used by [DeferredRequestCreator].  */\n    fun clearTag() = apply {\n      tag = null\n    }\n\n    /**\n     * Resize the image to the specified size in pixels.\n     * Use 0 as desired dimension to resize keeping aspect ratio.\n     */\n    fun resize(@Px targetWidth: Int, @Px targetHeight: Int) = apply {\n      require(targetWidth >= 0) { \"Width must be positive number or 0.\" }\n      require(targetHeight >= 0) { \"Height must be positive number or 0.\" }\n      require(\n        !(targetHeight == 0 && targetWidth == 0)\n      ) { \"At least one dimension has to be positive number.\" }\n      this.targetWidth = targetWidth\n      this.targetHeight = targetHeight\n    }\n\n    /** Clear the resize transformation, if any. This will also clear center crop/inside if set.  */\n    fun clearResize() = apply {\n      targetWidth = 0\n      targetHeight = 0\n      centerCrop = false\n      centerInside = false\n    }\n\n    /**\n     * Crops an image inside of the bounds specified by [resize] rather than\n     * distorting the aspect ratio. This cropping technique scales the image so that it fills the\n     * requested bounds and then crops the extra.\n     */\n    @JvmOverloads\n    fun centerCrop(alignGravity: Int = Gravity.CENTER) = apply {\n      check(!centerInside) { \"Center crop can not be used after calling centerInside\" }\n      centerCrop = true\n      centerCropGravity = alignGravity\n    }\n\n    /** Clear the center crop transformation flag, if set.  */\n    fun clearCenterCrop() = apply {\n      centerCrop = false\n      centerCropGravity = Gravity.CENTER\n    }\n\n    /**\n     * Centers an image inside of the bounds specified by [resize]. This scales\n     * the image so that both dimensions are equal to or less than the requested bounds.\n     */\n    fun centerInside() = apply {\n      check(!centerCrop) { \"Center inside can not be used after calling centerCrop\" }\n      centerInside = true\n    }\n\n    /** Clear the center inside transformation flag, if set.  */\n    fun clearCenterInside() = apply {\n      centerInside = false\n    }\n\n    /**\n     * Only resize an image if the original image size is bigger than the target size\n     * specified by [resize].\n     */\n    fun onlyScaleDown() = apply {\n      check(!(targetHeight == 0 && targetWidth == 0)) {\n        \"onlyScaleDown can not be applied without resize\"\n      }\n      onlyScaleDown = true\n    }\n\n    /** Clear the onlyScaleUp flag, if set.  */\n    fun clearOnlyScaleDown() = apply {\n      onlyScaleDown = false\n    }\n\n    /** Rotate the image by the specified degrees.  */\n    fun rotate(degrees: Float) = apply {\n      rotationDegrees = degrees\n    }\n\n    /** Rotate the image by the specified degrees around a pivot point.  */\n    fun rotate(\n      degrees: Float,\n      pivotX: Float,\n      pivotY: Float\n    ) = apply {\n      rotationDegrees = degrees\n      rotationPivotX = pivotX\n      rotationPivotY = pivotY\n      hasRotationPivot = true\n    }\n\n    /** Clear the rotation transformation, if any.  */\n    fun clearRotation() = apply {\n      rotationDegrees = 0f\n      rotationPivotX = 0f\n      rotationPivotY = 0f\n      hasRotationPivot = false\n    }\n\n    /** Decode the image using the specified config.  */\n    fun config(config: Config) = apply {\n      this.config = config\n    }\n\n    /** Execute request using the specified priority.  */\n    fun priority(priority: Priority) = apply {\n      check(this.priority == null) { \"Priority already set.\" }\n      this.priority = priority\n    }\n\n    /**\n     * Add a custom transformation to be applied to the image.\n     *\n     * Custom transformations will always be run after the built-in transformations.\n     */\n    fun transform(transformation: Transformation) = apply {\n      requireNotNull(transformation.key()) { \"Transformation key must not be null.\" }\n      if (transformations == null) {\n        transformations = ArrayList(2)\n      }\n      transformations!!.add(transformation)\n    }\n\n    /**\n     * Add a list of custom transformations to be applied to the image.\n     *\n     *\n     * Custom transformations will always be run after the built-in transformations.\n     */\n    fun transform(transformations: List<Transformation>) = apply {\n      for (i in transformations.indices) {\n        transform(transformations[i])\n      }\n    }\n\n    /**\n     * Specifies the [MemoryPolicy] to use for this request. You may specify additional policy\n     * options using the varargs parameter.\n     */\n    fun memoryPolicy(\n      policy: MemoryPolicy,\n      vararg additional: MemoryPolicy\n    ) = apply {\n      memoryPolicy = memoryPolicy or policy.index\n\n      for (i in additional.indices) {\n        this.memoryPolicy = this.memoryPolicy or additional[i].index\n      }\n    }\n\n    /**\n     * Specifies the [NetworkPolicy] to use for this request. You may specify additional\n     * policy options using the varargs parameter.\n     */\n    fun networkPolicy(\n      policy: NetworkPolicy,\n      vararg additional: NetworkPolicy\n    ) = apply {\n      networkPolicy = networkPolicy or policy.index\n\n      for (i in additional.indices) {\n        this.networkPolicy = this.networkPolicy or additional[i].index\n      }\n    }\n\n    fun addHeader(\n      name: String,\n      value: String\n    ) = apply {\n      this.headers = (headers?.newBuilder() ?: Headers.Builder())\n        .add(name, value)\n        .build()\n    }\n\n    /** Create the immutable [Request] object.  */\n    fun build(): Request {\n      check(!(centerInside && centerCrop)) {\n        \"Center crop and center inside can not be used together.\"\n      }\n      check(!(centerCrop && targetWidth == 0 && targetHeight == 0)) {\n        \"Center crop requires calling resize with positive width and height.\"\n      }\n      check(!(centerInside && targetWidth == 0 && targetHeight == 0)) {\n        \"Center inside requires calling resize with positive width and height.\"\n      }\n      if (priority == null) {\n        priority = NORMAL\n      }\n      return Request(this)\n    }\n  }\n\n  internal companion object {\n    private val TOO_LONG_LOG = SECONDS.toNanos(5)\n    private const val KEY_PADDING = 50 // Determined by exact science.\n    const val KEY_SEPARATOR = '\\n'\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/RequestCreator.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.app.Notification\nimport android.graphics.Bitmap\nimport android.graphics.drawable.Drawable\nimport android.net.Uri\nimport android.view.Gravity\nimport android.widget.ImageView\nimport android.widget.RemoteViews\nimport androidx.annotation.DimenRes\nimport androidx.annotation.DrawableRes\nimport androidx.annotation.IdRes\nimport androidx.core.content.ContextCompat\nimport com.squareup.picasso3.BitmapHunter.Companion.forRequest\nimport com.squareup.picasso3.MemoryPolicy.Companion.shouldReadFromMemoryCache\nimport com.squareup.picasso3.MemoryPolicy.Companion.shouldWriteToMemoryCache\nimport com.squareup.picasso3.Picasso.LoadedFrom\nimport com.squareup.picasso3.PicassoDrawable.Companion.setPlaceholder\nimport com.squareup.picasso3.PicassoDrawable.Companion.setResult\nimport com.squareup.picasso3.RemoteViewsAction.AppWidgetAction\nimport com.squareup.picasso3.RemoteViewsAction.NotificationAction\nimport com.squareup.picasso3.RemoteViewsAction.RemoteViewsTarget\nimport com.squareup.picasso3.Utils.OWNER_MAIN\nimport com.squareup.picasso3.Utils.VERB_COMPLETED\nimport com.squareup.picasso3.Utils.checkMain\nimport com.squareup.picasso3.Utils.checkNotMain\nimport com.squareup.picasso3.Utils.log\nimport java.io.IOException\nimport java.util.concurrent.atomic.AtomicInteger\n\n/** Fluent API for building an image download request.  */\nclass RequestCreator internal constructor(\n  private val picasso: Picasso,\n  uri: Uri?,\n  resourceId: Int\n) {\n  private val data = Request.Builder(uri, resourceId, picasso.defaultBitmapConfig)\n\n  private var noFade = false\n  private var deferred = false\n  private var setPlaceholder = true\n\n  @DrawableRes private var placeholderResId = 0\n\n  @DrawableRes private var errorResId = 0\n  private var placeholderDrawable: Drawable? = null\n  private var errorDrawable: Drawable? = null\n\n  /** Internal use only. Used by [DeferredRequestCreator].  */\n  @get:JvmName(\"-tag\")\n  internal val tag: Any?\n    get() = data.tag\n\n  init {\n    check(!picasso.shutdown) { \"Picasso instance already shut down. Cannot submit new requests.\" }\n  }\n\n  /**\n   * Explicitly opt-out to having a placeholder set when calling [into].\n   *\n   * By default, Picasso will either set a supplied placeholder or clear the target\n   * [ImageView] in order to ensure behavior in situations where views are recycled. This\n   * method will prevent that behavior and retain any already set image.\n   */\n  fun noPlaceholder(): RequestCreator {\n    check(placeholderResId == 0) { \"Placeholder resource already set.\" }\n    check(placeholderDrawable == null) { \"Placeholder image already set.\" }\n    setPlaceholder = false\n    return this\n  }\n\n  /**\n   * A placeholder drawable to be used while the image is being loaded. If the requested image is\n   * not immediately available in the memory cache then this resource will be set on the target\n   * [ImageView].\n   */\n  fun placeholder(@DrawableRes placeholderResId: Int): RequestCreator {\n    check(setPlaceholder) { \"Already explicitly declared as no placeholder.\" }\n    require(placeholderResId != 0) { \"Placeholder image resource invalid.\" }\n    check(placeholderDrawable == null) { \"Placeholder image already set.\" }\n    this.placeholderResId = placeholderResId\n    return this\n  }\n\n  /**\n   * A placeholder drawable to be used while the image is being loaded. If the requested image is\n   * not immediately available in the memory cache then this resource will be set on the target\n   * [ImageView].\n   *\n   * If you are not using a placeholder image but want to clear an existing image (such as when\n   * used in an [adapter][android.widget.Adapter]), pass in `null`.\n   */\n  fun placeholder(placeholderDrawable: Drawable?): RequestCreator {\n    check(setPlaceholder) { \"Already explicitly declared as no placeholder.\" }\n    check(placeholderResId == 0) { \"Placeholder image already set.\" }\n    this.placeholderDrawable = placeholderDrawable\n    return this\n  }\n\n  /** An error drawable to be used if the request image could not be loaded.  */\n  fun error(@DrawableRes errorResId: Int): RequestCreator {\n    require(errorResId != 0) { \"Error image resource invalid.\" }\n    check(errorDrawable == null) { \"Error image already set.\" }\n    this.errorResId = errorResId\n    return this\n  }\n\n  /** An error drawable to be used if the request image could not be loaded.  */\n  fun error(errorDrawable: Drawable): RequestCreator {\n    check(errorResId == 0) { \"Error image already set.\" }\n    this.errorDrawable = errorDrawable\n    return this\n  }\n\n  /**\n   * Assign a tag to this request. Tags are an easy way to logically associate\n   * related requests that can be managed together e.g. paused, resumed,\n   * or canceled.\n   *\n   * You can either use simple [String] tags or objects that naturally\n   * define the scope of your requests within your app such as a\n   * [android.content.Context], an [android.app.Activity], or a\n   * [android.app.Fragment].\n   *\n   * **WARNING:**: Picasso will keep a reference to the tag for\n   * as long as this tag is paused and/or has active requests. Look out for\n   * potential leaks.\n   *\n   * @see Picasso.cancelTag\n   * @see Picasso.pauseTag\n   * @see Picasso.resumeTag\n   */\n  fun tag(tag: Any): RequestCreator {\n    data.tag(tag)\n    return this\n  }\n\n  /**\n   * Attempt to resize the image to fit exactly into the target [ImageView]'s bounds. This\n   * will result in delayed execution of the request until the [ImageView] has been laid out.\n   *\n   * *Note:* This method works only when your target is an [ImageView].\n   */\n  fun fit(): RequestCreator {\n    deferred = true\n    return this\n  }\n\n  /** Internal use only. Used by [DeferredRequestCreator].  */\n  @JvmName(\"-unfit\")\n  internal fun unfit(): RequestCreator {\n    deferred = false\n    return this\n  }\n\n  /** Internal use only. Used by [DeferredRequestCreator].  */\n  @JvmName(\"-clearTag\")\n  internal fun clearTag(): RequestCreator {\n    data.clearTag()\n    return this\n  }\n\n  /**\n   * Resize the image to the specified dimension size.\n   * Use 0 as desired dimension to resize keeping aspect ratio.\n   */\n  fun resizeDimen(\n    @DimenRes targetWidthResId: Int,\n    @DimenRes targetHeightResId: Int\n  ): RequestCreator {\n    val resources = picasso.context.resources\n    val targetWidth = resources.getDimensionPixelSize(targetWidthResId)\n    val targetHeight = resources.getDimensionPixelSize(targetHeightResId)\n    return resize(targetWidth, targetHeight)\n  }\n\n  /**\n   * Resize the image to the specified size in pixels.\n   * Use 0 as desired dimension to resize keeping aspect ratio.\n   */\n  fun resize(targetWidth: Int, targetHeight: Int): RequestCreator {\n    data.resize(targetWidth, targetHeight)\n    return this\n  }\n\n  /**\n   * Crops an image inside of the bounds specified by [resize] rather than\n   * distorting the aspect ratio. This cropping technique scales the image so that it fills the\n   * requested bounds and then crops the extra.\n   */\n  fun centerCrop(): RequestCreator {\n    data.centerCrop(Gravity.CENTER)\n    return this\n  }\n\n  /**\n   * Crops an image inside of the bounds specified by [resize] rather than\n   * distorting the aspect ratio. This cropping technique scales the image so that it fills the\n   * requested bounds and then crops the extra, preferring the contents at [alignGravity].\n   */\n  fun centerCrop(alignGravity: Int): RequestCreator {\n    data.centerCrop(alignGravity)\n    return this\n  }\n\n  /**\n   * Centers an image inside of the bounds specified by [resize]. This scales\n   * the image so that both dimensions are equal to or less than the requested bounds.\n   */\n  fun centerInside(): RequestCreator {\n    data.centerInside()\n    return this\n  }\n\n  /**\n   * Only resize an image if the original image size is bigger than the target size\n   * specified by [resize].\n   */\n  fun onlyScaleDown(): RequestCreator {\n    data.onlyScaleDown()\n    return this\n  }\n\n  /** Rotate the image by the specified degrees.  */\n  fun rotate(degrees: Float): RequestCreator {\n    data.rotate(degrees)\n    return this\n  }\n\n  /** Rotate the image by the specified degrees around a pivot point.  */\n  fun rotate(degrees: Float, pivotX: Float, pivotY: Float): RequestCreator {\n    data.rotate(degrees, pivotX, pivotY)\n    return this\n  }\n\n  /**\n   * Attempt to decode the image using the specified config.\n   *\n   * Note: This value may be ignored by [BitmapFactory]. See\n   * [its documentation][BitmapFactory.Options.inPreferredConfig] for more details.\n   */\n  fun config(config: Bitmap.Config): RequestCreator {\n    data.config(config)\n    return this\n  }\n\n  /**\n   * Sets the stable key for this request to be used instead of the URI or resource ID when\n   * caching. Two requests with the same value are considered to be for the same resource.\n   */\n  fun stableKey(stableKey: String): RequestCreator {\n    data.stableKey(stableKey)\n    return this\n  }\n\n  /**\n   * Set the priority of this request.\n   *\n   *\n   * This will affect the order in which the requests execute but does not guarantee it.\n   * By default, all requests have [Priority.NORMAL] priority, except for\n   * [fetch] requests, which have [Priority.LOW] priority by default.\n   */\n  fun priority(priority: Picasso.Priority): RequestCreator {\n    data.priority(priority)\n    return this\n  }\n\n  /**\n   * Add a custom transformation to be applied to the image.\n   *\n   * Custom transformations will always be run after the built-in transformations.\n   */\n  // TODO show example of calling resize after a transform in the javadoc\n  fun transform(transformation: Transformation): RequestCreator {\n    data.transform(transformation)\n    return this\n  }\n\n  /**\n   * Add a list of custom transformations to be applied to the image.\n   *\n   * Custom transformations will always be run after the built-in transformations.\n   */\n  fun transform(transformations: List<Transformation>): RequestCreator {\n    data.transform(transformations)\n    return this\n  }\n\n  /**\n   * Specifies the [MemoryPolicy] to use for this request. You may specify additional policy\n   * options using the varargs parameter.\n   */\n  fun memoryPolicy(\n    policy: MemoryPolicy,\n    vararg additional: MemoryPolicy\n  ): RequestCreator {\n    data.memoryPolicy(policy, *additional)\n    return this\n  }\n\n  /**\n   * Specifies the [NetworkPolicy] to use for this request. You may specify additional policy\n   * options using the varargs parameter.\n   */\n  fun networkPolicy(\n    policy: NetworkPolicy,\n    vararg additional: NetworkPolicy\n  ): RequestCreator {\n    data.networkPolicy(policy, *additional)\n    return this\n  }\n\n  /**\n   * Add custom HTTP headers to the image network request, if desired\n   */\n  fun addHeader(key: String, value: String): RequestCreator {\n    data.addHeader(key, value)\n    return this\n  }\n\n  /** Disable brief fade in of images loaded from the disk cache or network.  */\n  fun noFade(): RequestCreator {\n    noFade = true\n    return this\n  }\n\n  /**\n   * Synchronously fulfill this request. Must not be called from the main thread.\n   */\n  @Throws(IOException::class) // TODO make non-null and always throw?\n  fun get(): Bitmap? {\n    val started = System.nanoTime()\n    checkNotMain()\n    check(!deferred) { \"Fit cannot be used with get.\" }\n    if (!data.hasImage()) {\n      return null\n    }\n\n    val request = createRequest(started)\n    val action = GetAction(picasso, request)\n    val result =\n      forRequest(picasso, picasso.dispatcher, picasso.cache, action).hunt() ?: return null\n\n    val bitmap = result.bitmap\n    if (shouldWriteToMemoryCache(request.memoryPolicy)) {\n      picasso.cache[request.key] = bitmap\n    }\n\n    return bitmap\n  }\n\n  /**\n   * Asynchronously fulfills the request without a [ImageView] or [BitmapTarget],\n   * and invokes the target [Callback] with the result. This is useful when you want to warm\n   * up the cache with an image.\n   *\n   * *Note:* The [Callback] param is a strong reference and will prevent your\n   * [android.app.Activity] or [android.app.Fragment] from being garbage collected\n   * until the request is completed.\n   *\n   * *Note:* It is safe to invoke this method from any thread.\n   */\n  @JvmOverloads fun fetch(callback: Callback? = null) {\n    val started = System.nanoTime()\n    check(!deferred) { \"Fit cannot be used with fetch.\" }\n\n    if (data.hasImage()) {\n      // Fetch requests have lower priority by default.\n      if (!data.hasPriority()) {\n        data.priority(Picasso.Priority.LOW)\n      }\n\n      val request = createRequest(started)\n      if (shouldReadFromMemoryCache(request.memoryPolicy)) {\n        val bitmap = picasso.quickMemoryCacheCheck(request.key)\n        if (bitmap != null) {\n          if (picasso.isLoggingEnabled) {\n            log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), \"from \" + LoadedFrom.MEMORY)\n          }\n          callback?.onSuccess()\n          return\n        }\n      }\n\n      val action = FetchAction(picasso, request, callback)\n      picasso.submit(action)\n    }\n  }\n\n  /**\n   * Asynchronously fulfills the request into the specified [BitmapTarget]. In most cases, you\n   * should use this when you are dealing with a custom [View][android.view.View] or view\n   * holder which should implement the [BitmapTarget] interface.\n   *\n   * Implementing on a [View][android.view.View]:\n   * ```\n   * class ProfileView(context: Context) : FrameLayout(context), Target {\n   *   override fun onBitmapLoaded(bitmap: Bitmap, from: LoadedFrom) {\n   *     setBackgroundDrawable(BitmapDrawable(bitmap))\n   *   }\n   *\n   *   override run onBitmapFailed(e: Exception, errorDrawable: Drawable) {\n   *     setBackgroundDrawable(errorDrawable)\n   *   }\n   *\n   *   override fun onPrepareLoad(placeholderDrawable: Drawable) {\n   *     setBackgroundDrawable(placeholderDrawable\n   *   }\n   * }\n   * ```\n   */\n  fun into(target: BitmapTarget) {\n    val started = System.nanoTime()\n    checkMain()\n    check(!deferred) { \"Fit cannot be used with a Target.\" }\n\n    if (!data.hasImage()) {\n      picasso.cancelRequest(target)\n      target.onPrepareLoad(if (setPlaceholder) getPlaceholderDrawable() else null)\n      return\n    }\n\n    val request = createRequest(started)\n    if (shouldReadFromMemoryCache(request.memoryPolicy)) {\n      val bitmap = picasso.quickMemoryCacheCheck(request.key)\n      if (bitmap != null) {\n        picasso.cancelRequest(target)\n        target.onBitmapLoaded(bitmap, LoadedFrom.MEMORY)\n        return\n      }\n    }\n\n    target.onPrepareLoad(if (setPlaceholder) getPlaceholderDrawable() else null)\n    val action = BitmapTargetAction(picasso, target, request, errorDrawable, errorResId)\n    picasso.enqueueAndSubmit(action)\n  }\n\n  /**\n   * Asynchronously fulfills the request into the specified [DrawableTarget]. In most cases, you\n   * should use this when you are dealing with a custom [View][android.view.View] or view\n   * holder which should implement the [DrawableTarget] interface.\n   */\n  fun into(target: DrawableTarget) {\n    val started = System.nanoTime()\n    checkMain()\n    check(!deferred) { \"Fit cannot be used with a Target.\" }\n\n    val placeHolderDrawable = if (setPlaceholder) getPlaceholderDrawable() else null\n    if (!data.hasImage()) {\n      picasso.cancelRequest(target)\n      target.onPrepareLoad(placeHolderDrawable)\n      return\n    }\n\n    val request = createRequest(started)\n    if (shouldReadFromMemoryCache(request.memoryPolicy)) {\n      val bitmap = picasso.quickMemoryCacheCheck(request.key)\n      if (bitmap != null) {\n        picasso.cancelRequest(target)\n        target.onDrawableLoaded(\n          PicassoDrawable(\n            context = picasso.context,\n            bitmap = bitmap,\n            placeholder = null,\n            loadedFrom = LoadedFrom.MEMORY,\n            noFade = noFade,\n            debugging = picasso.indicatorsEnabled\n          ),\n          LoadedFrom.MEMORY\n        )\n        return\n      }\n    }\n\n    target.onPrepareLoad(placeHolderDrawable)\n    val action = DrawableTargetAction(picasso, target, request, noFade, placeHolderDrawable, errorDrawable, errorResId)\n    picasso.enqueueAndSubmit(action)\n  }\n\n  /**\n   * Asynchronously fulfills the request into the specified [RemoteViews] object with the\n   * given [viewId]. This is used for loading bitmaps into a [Notification].\n   */\n  @JvmOverloads\n  fun into(\n    remoteViews: RemoteViews,\n    @IdRes viewId: Int,\n    notificationId: Int,\n    notification: Notification,\n    notificationTag: String? = null,\n    callback: Callback? = null\n  ) {\n    val started = System.nanoTime()\n    check(!deferred) { \"Fit cannot be used with RemoteViews.\" }\n    require(!(placeholderDrawable != null || errorDrawable != null)) {\n      \"Cannot use placeholder or error drawables with remote views.\"\n    }\n\n    val request = createRequest(started)\n    val action = NotificationAction(\n      picasso,\n      request,\n      errorResId,\n      RemoteViewsTarget(remoteViews, viewId),\n      notificationId,\n      notification,\n      notificationTag,\n      callback\n    )\n    performRemoteViewInto(request, action)\n  }\n\n  /**\n   * Asynchronously fulfills the request into the specified [RemoteViews] object with the\n   * given [viewId]. This is used for loading bitmaps into all instances of a widget.\n   */\n  fun into(\n    remoteViews: RemoteViews,\n    @IdRes viewId: Int,\n    appWidgetId: Int,\n    callback: Callback? = null\n  ) {\n    into(remoteViews, viewId, intArrayOf(appWidgetId), callback)\n  }\n\n  /**\n   * Asynchronously fulfills the request into the specified [RemoteViews] object with the\n   * given [viewId]. This is used for loading bitmaps into all instances of a widget.\n   */\n  @JvmOverloads\n  fun into(\n    remoteViews: RemoteViews,\n    @IdRes viewId: Int,\n    appWidgetIds: IntArray,\n    callback: Callback? = null\n  ) {\n    val started = System.nanoTime()\n    check(!deferred) { \"Fit cannot be used with remote views.\" }\n    require(!(placeholderDrawable != null || errorDrawable != null)) {\n      \"Cannot use placeholder or error drawables with remote views.\"\n    }\n\n    val request = createRequest(started)\n    val action = AppWidgetAction(\n      picasso,\n      request,\n      errorResId,\n      RemoteViewsTarget(remoteViews, viewId),\n      appWidgetIds,\n      callback\n    )\n\n    performRemoteViewInto(request, action)\n  }\n\n  /**\n   * Asynchronously fulfills the request into the specified [ImageView] and invokes the\n   * target [Callback] if it's not `null`.\n   *\n   * *Note:* The [Callback] param is a strong reference and will prevent your\n   * [android.app.Activity] or [android.app.Fragment] from being garbage collected. If\n   * you use this method, it is **strongly** recommended you invoke an adjacent\n   * [Picasso.cancelRequest] call to prevent temporary leaking.\n   *\n   * *Note:* This method will automatically support object recycling.\n   */\n  @JvmOverloads fun into(target: ImageView, callback: Callback? = null) {\n    val started = System.nanoTime()\n    checkMain()\n\n    if (!data.hasImage()) {\n      picasso.cancelRequest(target)\n      if (setPlaceholder) {\n        setPlaceholder(target, getPlaceholderDrawable())\n      }\n      return\n    }\n\n    if (deferred) {\n      check(!data.hasSize()) { \"Fit cannot be used with resize.\" }\n      val width = target.width\n      val height = target.height\n      if (width == 0 || height == 0) {\n        if (setPlaceholder) {\n          setPlaceholder(target, getPlaceholderDrawable())\n        }\n        picasso.defer(target, DeferredRequestCreator(this, target, callback))\n        return\n      }\n      data.resize(width, height)\n    }\n\n    val request = createRequest(started)\n\n    if (shouldReadFromMemoryCache(request.memoryPolicy)) {\n      val bitmap = picasso.quickMemoryCacheCheck(request.key)\n      if (bitmap != null) {\n        picasso.cancelRequest(target)\n        val result: RequestHandler.Result = RequestHandler.Result.Bitmap(bitmap, LoadedFrom.MEMORY)\n        setResult(target, picasso.context, result, noFade, picasso.indicatorsEnabled)\n        if (picasso.isLoggingEnabled) {\n          log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), \"from \" + LoadedFrom.MEMORY)\n        }\n        callback?.onSuccess()\n        return\n      }\n    }\n\n    if (setPlaceholder) {\n      setPlaceholder(target, getPlaceholderDrawable())\n    }\n\n    val action = ImageViewAction(\n      picasso,\n      target,\n      request,\n      errorDrawable,\n      errorResId,\n      noFade,\n      callback\n    )\n\n    picasso.enqueueAndSubmit(action)\n  }\n\n  private fun getPlaceholderDrawable(): Drawable? {\n    return if (placeholderResId == 0) {\n      placeholderDrawable\n    } else {\n      ContextCompat.getDrawable(picasso.context, placeholderResId)\n    }\n  }\n\n  /** Create the request optionally passing it through the request transformer.  */\n  private fun createRequest(started: Long): Request {\n    val id = nextId.getAndIncrement()\n    val request = data.build()\n    request.id = id\n    request.started = started\n\n    val loggingEnabled = picasso.isLoggingEnabled\n    if (loggingEnabled) {\n      log(OWNER_MAIN, Utils.VERB_CREATED, request.plainId(), request.toString())\n    }\n\n    val transformed = picasso.transformRequest(request)\n    if (transformed != request) {\n      // If the request was changed, copy over the id and timestamp from the original.\n      transformed.id = id\n      transformed.started = started\n      if (loggingEnabled) {\n        log(OWNER_MAIN, Utils.VERB_CHANGED, transformed.logId(), \"into $transformed\")\n      }\n    }\n\n    return transformed\n  }\n\n  private fun performRemoteViewInto(request: Request, action: RemoteViewsAction) {\n    if (shouldReadFromMemoryCache(request.memoryPolicy)) {\n      val bitmap = picasso.quickMemoryCacheCheck(action.request.key)\n      if (bitmap != null) {\n        action.complete(RequestHandler.Result.Bitmap(bitmap, LoadedFrom.MEMORY))\n        return\n      }\n    }\n\n    if (placeholderResId != 0) {\n      action.setImageResource(placeholderResId)\n    }\n\n    picasso.enqueueAndSubmit(action)\n  }\n\n  private companion object {\n    private val nextId = AtomicInteger()\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/RequestHandler.kt",
    "content": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.net.NetworkInfo\nimport com.squareup.picasso3.Picasso.LoadedFrom\nimport java.io.IOException\n\n/**\n * `RequestHandler` allows you to extend Picasso to load images in ways that are not\n * supported by default in the library.\n *\n * <h2>Usage</h2>\n * `RequestHandler` must be subclassed to be used. You will have to override two methods\n * ([canHandleRequest] and [load]) with your custom logic to load images.\n *\n * You should then register your [RequestHandler] using\n * [Picasso.Builder.addRequestHandler]\n *\n * **Note:** This is a beta feature. The API is subject to change in a backwards incompatible\n * way at any time.\n *\n * @see Picasso.Builder.addRequestHandler\n */\nabstract class RequestHandler {\n  /**\n   * [Result] represents the result of a [load] call in a [RequestHandler].\n   *\n   * @see RequestHandler\n   * @see [load]\n   */\n  sealed class Result constructor(\n    /**\n     * Returns the resulting [Picasso.LoadedFrom] generated from a [load] call.\n     */\n    val loadedFrom: LoadedFrom,\n    /**\n     * Returns the resulting EXIF rotation generated from a [load] call.\n     */\n    val exifRotation: Int = 0\n  ) {\n    class Bitmap constructor(\n      val bitmap: android.graphics.Bitmap,\n      loadedFrom: LoadedFrom,\n      exifRotation: Int = 0\n    ) : Result(loadedFrom, exifRotation)\n\n    class Drawable constructor(\n      val drawable: android.graphics.drawable.Drawable,\n      loadedFrom: LoadedFrom,\n      exifRotation: Int = 0\n    ) : Result(loadedFrom, exifRotation)\n  }\n\n  interface Callback {\n    fun onSuccess(result: Result?)\n    fun onError(t: Throwable)\n  }\n\n  /**\n   * Whether or not this [RequestHandler] can handle a request with the given [Request].\n   */\n  abstract fun canHandleRequest(data: Request): Boolean\n\n  /**\n   * Loads an image for the given [Request].\n   * @param request the data from which the image should be resolved.\n   */\n  @Throws(IOException::class)\n  abstract fun load(\n    picasso: Picasso,\n    request: Request,\n    callback: Callback\n  )\n\n  open val retryCount = 0\n\n  open fun shouldRetry(\n    airplaneMode: Boolean,\n    info: NetworkInfo?\n  ) = false\n\n  open fun supportsReplay() = false\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ResourceDrawableRequestHandler.kt",
    "content": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport androidx.core.content.ContextCompat\nimport com.squareup.picasso3.BitmapUtils.isXmlResource\nimport com.squareup.picasso3.Picasso.LoadedFrom.DISK\n\ninternal class ResourceDrawableRequestHandler private constructor(\n  private val context: Context,\n  private val loader: DrawableLoader\n) : RequestHandler() {\n  override fun canHandleRequest(data: Request): Boolean {\n    return data.resourceId != 0 && isXmlResource(context.resources, data.resourceId)\n  }\n\n  override fun load(\n    picasso: Picasso,\n    request: Request,\n    callback: Callback\n  ) {\n    val drawable = loader.load(request.resourceId)\n    if (drawable == null) {\n      callback.onError(\n        IllegalArgumentException(\"invalid resId: ${Integer.toHexString(request.resourceId)}\")\n      )\n    } else {\n      callback.onSuccess(Result.Drawable(drawable, DISK))\n    }\n  }\n\n  internal companion object {\n    @JvmName(\"-create\")\n    internal fun create(\n      context: Context,\n      loader: DrawableLoader = DrawableLoader { resId -> ContextCompat.getDrawable(context, resId) }\n    ) = ResourceDrawableRequestHandler(context, loader)\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ResourceRequestHandler.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.ContentResolver\nimport android.content.Context\nimport com.squareup.picasso3.BitmapUtils.decodeResource\nimport com.squareup.picasso3.BitmapUtils.isXmlResource\nimport com.squareup.picasso3.Picasso.LoadedFrom.DISK\n\ninternal class ResourceRequestHandler(private val context: Context) : RequestHandler() {\n  override fun canHandleRequest(data: Request): Boolean {\n    return if (data.resourceId != 0 && !isXmlResource(context.resources, data.resourceId)) {\n      true\n    } else {\n      data.uri != null && ContentResolver.SCHEME_ANDROID_RESOURCE == data.uri.scheme\n    }\n  }\n\n  override fun load(\n    picasso: Picasso,\n    request: Request,\n    callback: Callback\n  ) {\n    var signaledCallback = false\n    try {\n      val bitmap = decodeResource(context, request)\n      signaledCallback = true\n      callback.onSuccess(Result.Bitmap(bitmap, DISK))\n    } catch (e: Exception) {\n      if (!signaledCallback) {\n        callback.onError(e)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Transformation.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport com.squareup.picasso3.RequestHandler.Result\n\n/** Image transformation.  */\ninterface Transformation {\n  /**\n   * Transform the source result into a new result. If you create a new bitmap instance, you must\n   * call [android.graphics.Bitmap.recycle] on `source`. You may return the original\n   * if no transformation is required.\n   */\n  fun transform(source: Result.Bitmap): Result.Bitmap\n\n  /**\n   * Returns a unique key for the transformation, used for caching purposes. If the transformation\n   * has parameters (e.g. size, scale factor, etc) then these should be part of the key.\n   */\n  fun key(): String\n}\n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Utils.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.app.ActivityManager\nimport android.content.Context\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageManager\nimport android.content.pm.PackageManager.NameNotFoundException\nimport android.content.res.Resources\nimport android.os.Handler\nimport android.os.Looper\nimport android.os.Message\nimport android.os.StatFs\nimport android.provider.Settings.Global\nimport android.util.Log\nimport androidx.core.content.ContextCompat\nimport okio.BufferedSource\nimport okio.ByteString\nimport okio.ByteString.Companion.encodeUtf8\nimport java.io.File\nimport java.io.FileNotFoundException\nimport kotlin.math.max\nimport kotlin.math.min\n\ninternal object Utils {\n  const val THREAD_PREFIX = \"Picasso-\"\n  const val THREAD_IDLE_NAME = THREAD_PREFIX + \"Idle\"\n  private const val PICASSO_CACHE = \"picasso-cache\"\n  private const val MIN_DISK_CACHE_SIZE = 5 * 1024 * 1024 // 5MB\n  private const val MAX_DISK_CACHE_SIZE = 50 * 1024 * 1024 // 50MB\n  const val THREAD_LEAK_CLEANING_MS = 1000\n\n  /** Thread confined to main thread for key creation.  */\n  val MAIN_THREAD_KEY_BUILDER = StringBuilder()\n\n  /** Logging  */\n  const val OWNER_MAIN = \"Main\"\n  const val OWNER_DISPATCHER = \"Dispatcher\"\n  const val OWNER_HUNTER = \"Hunter\"\n  const val VERB_CREATED = \"created\"\n  const val VERB_CHANGED = \"changed\"\n  const val VERB_IGNORED = \"ignored\"\n  const val VERB_ENQUEUED = \"enqueued\"\n  const val VERB_CANCELED = \"canceled\"\n  const val VERB_RETRYING = \"retrying\"\n  const val VERB_EXECUTING = \"executing\"\n  const val VERB_DECODED = \"decoded\"\n  const val VERB_TRANSFORMED = \"transformed\"\n  const val VERB_JOINED = \"joined\"\n  const val VERB_REMOVED = \"removed\"\n  const val VERB_DELIVERED = \"delivered\"\n  const val VERB_REPLAYING = \"replaying\"\n  const val VERB_COMPLETED = \"completed\"\n  const val VERB_ERRORED = \"errored\"\n  const val VERB_PAUSED = \"paused\"\n  const val VERB_RESUMED = \"resumed\"\n\n  /* WebP file header\n     0                   1                   2                   3\n     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    |      'R'      |      'I'      |      'F'      |      'F'      |\n    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    |                           File Size                           |\n    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n    |      'W'      |      'E'      |      'B'      |      'P'      |\n    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n   */\n  private val WEBP_FILE_HEADER_RIFF: ByteString = \"RIFF\".encodeUtf8()\n  private val WEBP_FILE_HEADER_WEBP: ByteString = \"WEBP\".encodeUtf8()\n\n  fun <T> checkNotNull(value: T?, message: String?): T {\n    if (value == null) {\n      throw NullPointerException(message)\n    }\n    return value\n  }\n\n  fun checkNotMain() {\n    check(!isMain) { \"Method call should not happen from the main thread.\" }\n  }\n\n  fun checkMain() {\n    check(isMain) { \"Method call should happen from the main thread.\" }\n  }\n\n  private val isMain: Boolean\n    get() = Looper.getMainLooper().thread === Thread.currentThread()\n\n  fun getLogIdsForHunter(hunter: BitmapHunter, prefix: String = \"\"): String {\n    return buildString {\n      append(prefix)\n      val action = hunter.action\n      if (action != null) {\n        append(action.request.logId())\n      }\n      val actions = hunter.actions\n      if (actions != null) {\n        for (i in actions.indices) {\n          if (i > 0 || action != null) append(\", \")\n          append(actions[i].request.logId())\n        }\n      }\n    }\n  }\n\n  fun log(owner: String, verb: String, logId: String, extras: String? = \"\") {\n    Log.d(TAG, String.format(\"%1$-11s %2$-12s %3\\$s %4\\$s\", owner, verb, logId, extras ?: \"\"))\n  }\n\n  fun createDefaultCacheDir(context: Context): File {\n    val cache = File(context.applicationContext.cacheDir, PICASSO_CACHE)\n    if (!cache.exists()) {\n      cache.mkdirs()\n    }\n    return cache\n  }\n\n  fun calculateDiskCacheSize(dir: File): Long {\n    var size = MIN_DISK_CACHE_SIZE.toLong()\n\n    try {\n      val statFs = StatFs(dir.absolutePath)\n      val blockCount = statFs.blockCountLong\n      val blockSize = statFs.blockSizeLong\n      val available = blockCount * blockSize\n      // Target 2% of the total space.\n      size = available / 50\n    } catch (ignored: IllegalArgumentException) {\n    }\n\n    // Bound inside min/max size for disk cache.\n    return max(min(size, MAX_DISK_CACHE_SIZE.toLong()), MIN_DISK_CACHE_SIZE.toLong())\n  }\n\n  fun calculateMemoryCacheSize(context: Context): Int {\n    val am = ContextCompat.getSystemService(context, ActivityManager::class.java)\n    val largeHeap = context.applicationInfo.flags and ApplicationInfo.FLAG_LARGE_HEAP != 0\n    val memoryClass = if (largeHeap) am!!.largeMemoryClass else am!!.memoryClass\n    // Target ~15% of the available heap.\n    return (1024L * 1024L * memoryClass / 7).toInt()\n  }\n\n  fun isAirplaneModeOn(context: Context): Boolean {\n    return try {\n      val contentResolver = context.contentResolver\n      Global.getInt(contentResolver, Global.AIRPLANE_MODE_ON, 0) != 0\n    } catch (e: NullPointerException) {\n      // https://github.com/square/picasso/issues/761, some devices might crash here, assume that\n      // airplane mode is off.\n      false\n    } catch (e: SecurityException) {\n      // https://github.com/square/picasso/issues/1197\n      false\n    }\n  }\n\n  fun hasPermission(context: Context, permission: String): Boolean {\n    return context.checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED\n  }\n\n  fun isWebPFile(source: BufferedSource): Boolean {\n    return source.rangeEquals(0, WEBP_FILE_HEADER_RIFF) &&\n      source.rangeEquals(8, WEBP_FILE_HEADER_WEBP)\n  }\n\n  fun getResourceId(resources: Resources, data: Request): Int {\n    if (data.resourceId != 0 || data.uri == null) {\n      return data.resourceId\n    }\n\n    val pkg = data.uri.authority ?: throw FileNotFoundException(\"No package provided: \" + data.uri)\n\n    val segments = data.uri.pathSegments\n    return when (segments?.size ?: 0) {\n      0 -> throw FileNotFoundException(\"No path segments: \" + data.uri)\n      1 -> {\n        try {\n          segments[0].toInt()\n        } catch (e: NumberFormatException) {\n          throw FileNotFoundException(\"Last path segment is not a resource ID: \" + data.uri)\n        }\n      }\n      2 -> {\n        val type = segments[0]\n        val name = segments[1]\n        resources.getIdentifier(name, type, pkg)\n      }\n      else -> throw FileNotFoundException(\"More than two path segments: \" + data.uri)\n    }\n  }\n\n  fun getResources(\n    context: Context,\n    data: Request\n  ): Resources {\n    if (data.resourceId != 0 || data.uri == null) {\n      return context.resources\n    }\n\n    return try {\n      val pkg =\n        data.uri.authority ?: throw FileNotFoundException(\"No package provided: \" + data.uri)\n      context.packageManager.getResourcesForApplication(pkg)\n    } catch (e: NameNotFoundException) {\n      throw FileNotFoundException(\"Unable to obtain resources for package: \" + data.uri)\n    }\n  }\n\n  /**\n   * Prior to Android 12, HandlerThread always keeps a stack local reference to the last message\n   * that was sent to it. This method makes sure that stack local reference never stays there\n   * for too long by sending new messages to it every second.\n   *\n   * https://github.com/square/leakcanary/blob/main/plumber-android-core/src/main/java/leakcanary/AndroidLeakFixes.kt#L153\n   */\n  fun flushStackLocalLeaks(looper: Looper) {\n    val handler: Handler = object : Handler(looper) {\n      override fun handleMessage(msg: Message) {\n        sendMessageDelayed(obtainMessage(), THREAD_LEAK_CLEANING_MS.toLong())\n      }\n    }\n    handler.sendMessageDelayed(handler.obtainMessage(), THREAD_LEAK_CLEANING_MS.toLong())\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/BaseDispatcherTest.kt",
    "content": "/*\n * Copyright (C) 2023 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.content.Intent\nimport android.net.ConnectivityManager\nimport com.squareup.picasso3.BaseDispatcher.NetworkBroadcastReceiver\nimport org.junit.Before\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.Mock\nimport org.mockito.Mockito\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.verifyNoInteractions\nimport org.mockito.MockitoAnnotations.initMocks\nimport org.robolectric.RobolectricTestRunner\n\n@RunWith(RobolectricTestRunner::class)\nclass BaseDispatcherTest {\n  @Mock lateinit var context: Context\n\n  @Before fun setUp() {\n    initMocks(this)\n  }\n\n  @Test fun nullIntentOnReceiveDoesNothing() {\n    val dispatcher = mock(BaseDispatcher::class.java)\n    val receiver = NetworkBroadcastReceiver(dispatcher)\n\n    receiver.onReceive(context, null)\n\n    verifyNoInteractions(dispatcher)\n  }\n\n  @Test fun nullExtrasOnReceiveConnectivityAreOk() {\n    val connectivityManager = mock(ConnectivityManager::class.java)\n    val networkInfo = TestUtils.mockNetworkInfo()\n    Mockito.`when`(connectivityManager.activeNetworkInfo).thenReturn(networkInfo)\n    Mockito.`when`(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(connectivityManager)\n    val dispatcher = mock(BaseDispatcher::class.java)\n    val receiver = NetworkBroadcastReceiver(dispatcher)\n\n    receiver.onReceive(context, Intent(ConnectivityManager.CONNECTIVITY_ACTION))\n\n    verify(dispatcher).dispatchNetworkStateChange(networkInfo)\n  }\n\n  @Test fun nullExtrasOnReceiveAirplaneDoesNothing() {\n    val dispatcher = mock(BaseDispatcher::class.java)\n    val receiver = NetworkBroadcastReceiver(dispatcher)\n\n    receiver.onReceive(context, Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED))\n\n    verifyNoInteractions(dispatcher)\n  }\n\n  @Test fun correctExtrasOnReceiveAirplaneDispatches() {\n    setAndVerifyAirplaneMode(false)\n    setAndVerifyAirplaneMode(true)\n  }\n\n  private fun setAndVerifyAirplaneMode(airplaneOn: Boolean) {\n    val dispatcher = mock(BaseDispatcher::class.java)\n    val receiver = NetworkBroadcastReceiver(dispatcher)\n    val intent = Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)\n    intent.putExtra(NetworkBroadcastReceiver.EXTRA_AIRPLANE_STATE, airplaneOn)\n    receiver.onReceive(context, intent)\n    verify(dispatcher).dispatchAirplaneModeChange(airplaneOn)\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/BitmapHunterTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport android.net.NetworkInfo\nimport android.net.Uri\nimport android.os.Looper\nimport android.view.Gravity\nimport androidx.exifinterface.media.ExifInterface\nimport androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_90\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.BitmapHunter.Companion.applyTransformations\nimport com.squareup.picasso3.BitmapHunter.Companion.forRequest\nimport com.squareup.picasso3.MatrixTransformation.Companion.transformResult\nimport com.squareup.picasso3.NetworkRequestHandler.ResponseException\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Picasso.LoadedFrom.NETWORK\nimport com.squareup.picasso3.Picasso.Priority.HIGH\nimport com.squareup.picasso3.Picasso.Priority.LOW\nimport com.squareup.picasso3.Picasso.Priority.NORMAL\nimport com.squareup.picasso3.Request.Companion.KEY_SEPARATOR\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport com.squareup.picasso3.TestUtils.ASSET_KEY_1\nimport com.squareup.picasso3.TestUtils.ASSET_URI_1\nimport com.squareup.picasso3.TestUtils.BITMAP_RESOURCE_VALUE\nimport com.squareup.picasso3.TestUtils.CONTACT_KEY_1\nimport com.squareup.picasso3.TestUtils.CONTACT_PHOTO_KEY_1\nimport com.squareup.picasso3.TestUtils.CONTACT_PHOTO_URI_1\nimport com.squareup.picasso3.TestUtils.CONTACT_URI_1\nimport com.squareup.picasso3.TestUtils.CONTENT_1_URL\nimport com.squareup.picasso3.TestUtils.CONTENT_KEY_1\nimport com.squareup.picasso3.TestUtils.CUSTOM_URI\nimport com.squareup.picasso3.TestUtils.CUSTOM_URI_KEY\nimport com.squareup.picasso3.TestUtils.EventRecorder\nimport com.squareup.picasso3.TestUtils.FILE_1_URL\nimport com.squareup.picasso3.TestUtils.FILE_KEY_1\nimport com.squareup.picasso3.TestUtils.MEDIA_STORE_CONTENT_1_URL\nimport com.squareup.picasso3.TestUtils.MEDIA_STORE_CONTENT_KEY_1\nimport com.squareup.picasso3.TestUtils.NOOP_REQUEST_HANDLER\nimport com.squareup.picasso3.TestUtils.NO_TRANSFORMERS\nimport com.squareup.picasso3.TestUtils.RESOURCE_ID_1\nimport com.squareup.picasso3.TestUtils.RESOURCE_ID_KEY_1\nimport com.squareup.picasso3.TestUtils.RESOURCE_ID_URI\nimport com.squareup.picasso3.TestUtils.RESOURCE_ID_URI_KEY\nimport com.squareup.picasso3.TestUtils.RESOURCE_TYPE_URI\nimport com.squareup.picasso3.TestUtils.RESOURCE_TYPE_URI_KEY\nimport com.squareup.picasso3.TestUtils.UNUSED_CALL_FACTORY\nimport com.squareup.picasso3.TestUtils.URI_1\nimport com.squareup.picasso3.TestUtils.URI_KEY_1\nimport com.squareup.picasso3.TestUtils.XML_RESOURCE_VALUE\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.makeLoaderWithDrawable\nimport com.squareup.picasso3.TestUtils.mockAction\nimport com.squareup.picasso3.TestUtils.mockImageViewTarget\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport com.squareup.picasso3.TestUtils.mockResources\nimport org.junit.Assert.fail\nimport org.junit.Before\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.Mock\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.`when`\nimport org.mockito.MockitoAnnotations.initMocks\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.Shadows.shadowOf\nimport java.io.File\nimport java.io.IOException\nimport java.util.concurrent.FutureTask\n\n@RunWith(RobolectricTestRunner::class)\nclass BitmapHunterTest {\n  @Mock internal lateinit var context: Context\n\n  @Mock internal lateinit var dispatcher: Dispatcher\n  private lateinit var picasso: Picasso\n\n  private val cache = PlatformLruCache(2048)\n  private val bitmap = makeBitmap()\n\n  @Before fun setUp() {\n    initMocks(this)\n    `when`(context.applicationContext).thenReturn(context)\n    picasso = mockPicasso(context, NOOP_REQUEST_HANDLER)\n  }\n\n  @Test fun nullDecodeResponseIsError() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action, null)\n    hunter.run()\n    verify(dispatcher).dispatchFailed(hunter)\n  }\n\n  @Test fun runWithResultDispatchComplete() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action, bitmap)\n    hunter.run()\n    verify(dispatcher).dispatchComplete(hunter)\n  }\n\n  @Test fun runWithNoResultDispatchFailed() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action)\n    hunter.run()\n    verify(dispatcher).dispatchFailed(hunter)\n  }\n\n  @Test fun responseExceptionDispatchFailed() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter = TestableBitmapHunter(\n      picasso,\n      dispatcher,\n      cache,\n      action,\n      null,\n      ResponseException(504, 0)\n    )\n    hunter.run()\n    verify(dispatcher).dispatchFailed(hunter)\n  }\n\n  @Test fun runWithIoExceptionDispatchRetry() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action, null, IOException())\n    hunter.run()\n    verify(dispatcher).dispatchRetry(hunter)\n  }\n\n  @Test fun huntDecodesWhenNotInCache() {\n    val eventRecorder = EventRecorder()\n    val picasso = picasso.newBuilder().addEventListener(eventRecorder).build()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action, bitmap)\n\n    val result = hunter.hunt()\n    assertThat(cache.missCount()).isEqualTo(1)\n    assertThat(result).isNotNull()\n    assertThat(result!!.bitmap).isEqualTo(bitmap)\n    assertThat(result.loadedFrom).isEqualTo(NETWORK)\n    assertThat(eventRecorder.decodedBitmap).isEqualTo(bitmap)\n  }\n\n  @Test fun huntReturnsWhenResultInCache() {\n    cache[URI_KEY_1 + KEY_SEPARATOR] = bitmap\n    val eventRecorder = EventRecorder()\n    val picasso = picasso.newBuilder().addEventListener(eventRecorder).build()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action, bitmap)\n\n    val result = hunter.hunt()\n    assertThat(cache.hitCount()).isEqualTo(1)\n    assertThat(result).isNotNull()\n    assertThat(result!!.bitmap).isEqualTo(bitmap)\n    assertThat(result.loadedFrom).isEqualTo(MEMORY)\n    assertThat(eventRecorder.decodedBitmap).isNull()\n  }\n\n  @Test fun huntUnrecognizedUri() {\n    val action = mockAction(picasso, CUSTOM_URI_KEY, CUSTOM_URI)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    try {\n      hunter.hunt()\n      fail(\"Unrecognized URI should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun huntDecodesWithRequestHandler() {\n    val picasso = mockPicasso(context, CustomRequestHandler())\n    val action = mockAction(picasso, CUSTOM_URI_KEY, CUSTOM_URI)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    val result = hunter.hunt()\n    assertThat(result!!.bitmap).isEqualTo(bitmap)\n  }\n\n  @Test fun attachSingleRequest() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action1)\n    assertThat(hunter.action).isEqualTo(action1)\n    hunter.detach(action1)\n    hunter.attach(action1)\n    assertThat(hunter.action).isEqualTo(action1)\n    assertThat(hunter.actions).isNull()\n  }\n\n  @Test fun attachMultipleRequests() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val action2 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action1)\n    assertThat(hunter.actions).isNull()\n    hunter.attach(action2)\n    assertThat(hunter.actions).isNotNull()\n    assertThat(hunter.actions).hasSize(1)\n  }\n\n  @Test fun detachSingleRequest() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action)\n    assertThat(hunter.action).isNotNull()\n    hunter.detach(action)\n    assertThat(hunter.action).isNull()\n  }\n\n  @Test fun detachMultipleRequests() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val action2 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action)\n    hunter.attach(action2)\n    hunter.detach(action2)\n    assertThat(hunter.action).isNotNull()\n    assertThat(hunter.actions).isNotNull()\n    assertThat(hunter.actions).isEmpty()\n    hunter.detach(action)\n    assertThat(hunter.action).isNull()\n  }\n\n  @Test fun cancelSingleRequest() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action1)\n    hunter.future = FutureTask(mock(Runnable::class.java), mock(Any::class.java))\n    assertThat(hunter.isCancelled).isFalse()\n    assertThat(hunter.cancel()).isFalse()\n    hunter.detach(action1)\n    assertThat(hunter.cancel()).isTrue()\n    assertThat(hunter.isCancelled).isTrue()\n  }\n\n  @Test fun cancelMultipleRequests() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val action2 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = TestableBitmapHunter(picasso, dispatcher, cache, action1)\n    hunter.future = FutureTask(mock(Runnable::class.java), mock(Any::class.java))\n    hunter.attach(action2)\n    assertThat(hunter.isCancelled).isFalse()\n    assertThat(hunter.cancel()).isFalse()\n    hunter.detach(action1)\n    hunter.detach(action2)\n    assertThat(hunter.cancel()).isTrue()\n    assertThat(hunter.isCancelled).isTrue()\n  }\n\n  // ---------------------------------------\n\n  @Test fun forContentProviderRequest() {\n    val picasso = mockPicasso(context, ContentStreamRequestHandler(context))\n    val action = mockAction(picasso, CONTENT_KEY_1, CONTENT_1_URL)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(ContentStreamRequestHandler::class.java)\n  }\n\n  @Test fun forMediaStoreRequest() {\n    val picasso = mockPicasso(context, MediaStoreRequestHandler(context))\n    val action = mockAction(picasso, MEDIA_STORE_CONTENT_KEY_1, MEDIA_STORE_CONTENT_1_URL)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(MediaStoreRequestHandler::class.java)\n  }\n\n  @Test fun forContactsPhotoRequest() {\n    val picasso = mockPicasso(context, ContactsPhotoRequestHandler(context))\n    val action = mockAction(picasso, CONTACT_KEY_1, CONTACT_URI_1)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(ContactsPhotoRequestHandler::class.java)\n  }\n\n  @Test fun forContactsThumbnailPhotoRequest() {\n    val picasso = mockPicasso(context, ContactsPhotoRequestHandler(context))\n    val action = mockAction(picasso, CONTACT_PHOTO_KEY_1, CONTACT_PHOTO_URI_1)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(ContactsPhotoRequestHandler::class.java)\n  }\n\n  @Test fun forNetworkRequest() {\n    val requestHandler = NetworkRequestHandler(UNUSED_CALL_FACTORY)\n    val picasso = mockPicasso(context, requestHandler)\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isSameInstanceAs(requestHandler)\n  }\n\n  @Test fun forFileWithAuthorityRequest() {\n    val picasso = mockPicasso(context, FileRequestHandler(context))\n    val action = mockAction(picasso, FILE_KEY_1, FILE_1_URL)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(FileRequestHandler::class.java)\n  }\n\n  @Test fun forAndroidBitmapResourceRequest() {\n    val resources = mockResources(BITMAP_RESOURCE_VALUE)\n    `when`(context.resources).thenReturn(resources)\n    val picasso = mockPicasso(context, ResourceRequestHandler(context))\n    val action = mockAction(picasso = picasso, key = RESOURCE_ID_KEY_1, resourceId = RESOURCE_ID_1)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(ResourceRequestHandler::class.java)\n  }\n\n  @Test fun forAndroidBitmapResourceUriWithId() {\n    val picasso = mockPicasso(context, ResourceRequestHandler(context))\n    val action = mockAction(picasso, RESOURCE_ID_URI_KEY, RESOURCE_ID_URI)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(ResourceRequestHandler::class.java)\n  }\n\n  @Test fun forAndroidBitmapResourceUriWithType() {\n    val picasso = mockPicasso(context, ResourceRequestHandler(context))\n    val action = mockAction(picasso, RESOURCE_TYPE_URI_KEY, RESOURCE_TYPE_URI)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(ResourceRequestHandler::class.java)\n  }\n\n  @Test fun forAndroidXmlResourceRequest() {\n    val resources = mockResources(XML_RESOURCE_VALUE)\n    `when`(context.resources).thenReturn(resources)\n    val requestHandler =\n      ResourceDrawableRequestHandler.create(context, makeLoaderWithDrawable(null))\n    val picasso = mockPicasso(context, requestHandler)\n    val action = mockAction(picasso = picasso, key = RESOURCE_ID_KEY_1, resourceId = RESOURCE_ID_1)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(ResourceDrawableRequestHandler::class.java)\n  }\n\n  @Test fun forAssetRequest() {\n    val picasso = mockPicasso(context, AssetRequestHandler(context))\n    val action = mockAction(picasso, ASSET_KEY_1, ASSET_URI_1)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(AssetRequestHandler::class.java)\n  }\n\n  @Test fun forFileWithNoPathSegments() {\n    val picasso = mockPicasso(context, FileRequestHandler(context))\n    val action = mockAction(picasso, \"keykeykey\", Uri.fromFile(File(\"/\")))\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(FileRequestHandler::class.java)\n  }\n\n  @Test fun forCustomRequest() {\n    val picasso = mockPicasso(context, CustomRequestHandler())\n    val action = mockAction(picasso, CUSTOM_URI_KEY, CUSTOM_URI)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isInstanceOf(CustomRequestHandler::class.java)\n  }\n\n  @Test fun forOverrideRequest() {\n    val handler = AssetRequestHandler(context)\n    // Must use non-mock constructor because that is where Picasso's list of handlers is created.\n    val picasso = Picasso(\n      context, dispatcher, UNUSED_CALL_FACTORY, null, cache, null, NO_TRANSFORMERS,\n      listOf(handler), emptyList(), ARGB_8888, false, false\n    )\n    val action = mockAction(picasso, ASSET_KEY_1, ASSET_URI_1)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.requestHandler).isEqualTo(handler)\n  }\n\n  @Test fun sequenceIsIncremented() {\n    val picasso = mockPicasso(context)\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter1 = forRequest(picasso, dispatcher, cache, action)\n    val hunter2 = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter2.sequence).isGreaterThan(hunter1.sequence)\n  }\n\n  @Test fun getPriorityWithNoRequests() {\n    val requestHandler = NetworkRequestHandler(UNUSED_CALL_FACTORY)\n    val picasso = mockPicasso(context, requestHandler)\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    hunter.detach(action)\n    assertThat(hunter.action).isNull()\n    assertThat(hunter.actions).isNull()\n    assertThat(hunter.priority).isEqualTo(LOW)\n  }\n\n  @Test fun getPriorityWithSingleRequest() {\n    val requestHandler = NetworkRequestHandler(UNUSED_CALL_FACTORY)\n    val picasso = mockPicasso(context, requestHandler)\n    val action = mockAction(picasso = picasso, key = URI_KEY_1, uri = URI_1, priority = HIGH)\n    val hunter = forRequest(picasso, dispatcher, cache, action)\n    assertThat(hunter.action).isEqualTo(action)\n    assertThat(hunter.actions).isNull()\n    assertThat(hunter.priority).isEqualTo(HIGH)\n  }\n\n  @Test fun getPriorityWithMultipleRequests() {\n    val requestHandler = NetworkRequestHandler(UNUSED_CALL_FACTORY)\n    val picasso = mockPicasso(context, requestHandler)\n    val action1 = mockAction(picasso = picasso, key = URI_KEY_1, uri = URI_1, priority = NORMAL)\n    val action2 = mockAction(picasso = picasso, key = URI_KEY_1, uri = URI_1, priority = HIGH)\n    val hunter = forRequest(picasso, dispatcher, cache, action1)\n    hunter.attach(action2)\n    assertThat(hunter.action).isEqualTo(action1)\n    assertThat(hunter.actions).containsExactly(action2)\n    assertThat(hunter.priority).isEqualTo(HIGH)\n  }\n\n  @Test fun getPriorityAfterDetach() {\n    val requestHandler = NetworkRequestHandler(UNUSED_CALL_FACTORY)\n    val picasso = mockPicasso(context, requestHandler)\n    val action1 = mockAction(picasso = picasso, key = URI_KEY_1, uri = URI_1, priority = NORMAL)\n    val action2 = mockAction(picasso = picasso, key = URI_KEY_1, uri = URI_1, priority = HIGH)\n    val hunter = forRequest(picasso, dispatcher, cache, action1)\n    hunter.attach(action2)\n    assertThat(hunter.action).isEqualTo(action1)\n    assertThat(hunter.actions).containsExactly(action2)\n    assertThat(hunter.priority).isEqualTo(HIGH)\n    hunter.detach(action2)\n    assertThat(hunter.action).isEqualTo(action1)\n    assertThat(hunter.actions).isEmpty()\n    assertThat(hunter.priority).isEqualTo(NORMAL)\n  }\n\n  @Test fun exifRotation() {\n    val data = Request.Builder(URI_1).rotate(-45f).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, ORIENTATION_ROTATE_90)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"rotate 90.0\")\n  }\n\n  @Test fun exifRotationSizing() {\n    val data = Request.Builder(URI_1).resize(5, 10).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, ORIENTATION_ROTATE_90)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).contains(\"scale 1.0 0.5\")\n  }\n\n  @Test fun exifRotationNoSizing() {\n    val data = Request.Builder(URI_1).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, ORIENTATION_ROTATE_90)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).contains(\"rotate 90.0\")\n  }\n\n  @Test fun rotation90Sizing() {\n    val data = Request.Builder(URI_1).rotate(90f).resize(5, 10).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, 0)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).contains(\"scale 1.0 0.5\")\n  }\n\n  @Test fun rotation180Sizing() {\n    val data = Request.Builder(URI_1).rotate(180f).resize(5, 10).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, 0)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).contains(\"scale 0.5 1.0\")\n  }\n\n  @Test fun rotation90WithPivotSizing() {\n    val data = Request.Builder(URI_1).rotate(90f, 0f, 10f).resize(5, 10).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, 0)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).contains(\"scale 1.0 0.5\")\n  }\n\n  @Test fun exifVerticalFlip() {\n    val data = Request.Builder(URI_1).rotate(-45f).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, ExifInterface.ORIENTATION_FLIP_VERTICAL)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.postOperations).containsExactly(\"scale -1.0 1.0\")\n    assertThat(shadowMatrix.preOperations).containsExactly(\"rotate 180.0\")\n  }\n\n  @Test fun exifHorizontalFlip() {\n    val data = Request.Builder(URI_1).rotate(-45f).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, ExifInterface.ORIENTATION_FLIP_HORIZONTAL)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.postOperations).containsExactly(\"scale -1.0 1.0\")\n    assertThat(shadowMatrix.preOperations).doesNotContain(\"rotate 180.0\")\n    assertThat(shadowMatrix.preOperations).doesNotContain(\"rotate 90.0\")\n    assertThat(shadowMatrix.preOperations).doesNotContain(\"rotate 270.0\")\n  }\n\n  @Test fun exifTranspose() {\n    val data = Request.Builder(URI_1).rotate(-45f).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, ExifInterface.ORIENTATION_TRANSPOSE)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.postOperations).containsExactly(\"scale -1.0 1.0\")\n    assertThat(shadowMatrix.preOperations).containsExactly(\"rotate 90.0\")\n  }\n\n  @Test fun exifTransverse() {\n    val data = Request.Builder(URI_1).rotate(-45f).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, ExifInterface.ORIENTATION_TRANSVERSE)\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.postOperations).containsExactly(\"scale -1.0 1.0\")\n    assertThat(shadowMatrix.preOperations).containsExactly(\"rotate 270.0\")\n  }\n\n  @Test fun keepsAspectRationWhileResizingWhenDesiredWidthIs0() {\n    val request = Request.Builder(URI_1).resize(20, 0).build()\n    val source = android.graphics.Bitmap.createBitmap(40, 20, ARGB_8888)\n\n    val result = transformResult(request, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.5 0.5\")\n  }\n\n  @Test fun keepsAspectRationWhileResizingWhenDesiredHeightIs0() {\n    val request = Request.Builder(URI_1).resize(0, 10).build()\n    val source = android.graphics.Bitmap.createBitmap(40, 20, ARGB_8888)\n\n    val result = transformResult(request, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.5 0.5\")\n  }\n\n  @Test fun centerCropResultMatchesTargetSize() {\n    val request = Request.Builder(URI_1).resize(1080, 642).centerCrop().build()\n    val source = android.graphics.Bitmap.createBitmap(640, 640, ARGB_8888)\n\n    val result = transformResult(request, source, 0)\n\n    assertThat(result.width).isEqualTo(1080)\n    assertThat(result.height).isEqualTo(642)\n  }\n\n  @Test fun centerCropResultMatchesTargetSizeWhileDesiredWidthIs0() {\n    val request = Request.Builder(URI_1).resize(0, 642).centerCrop().build()\n    val source = android.graphics.Bitmap.createBitmap(640, 640, ARGB_8888)\n\n    val result = transformResult(request, source, 0)\n\n    assertThat(result.width).isEqualTo(642)\n    assertThat(result.height).isEqualTo(642)\n  }\n\n  @Test fun centerCropResultMatchesTargetSizeWhileDesiredHeightIs0() {\n    val request = Request.Builder(URI_1).resize(1080, 0).centerCrop().build()\n    val source = android.graphics.Bitmap.createBitmap(640, 640, ARGB_8888)\n\n    val result = transformResult(request, source, 0)\n\n    assertThat(result.width).isEqualTo(1080)\n    assertThat(result.height).isEqualTo(1080)\n  }\n\n  @Test fun centerInsideResultMatchesTargetSizeWhileDesiredWidthIs0() {\n    val request = Request.Builder(URI_1).resize(0, 642).centerInside().build()\n    val source = android.graphics.Bitmap.createBitmap(640, 640, ARGB_8888)\n\n    val result = transformResult(request, source, 0)\n\n    assertThat(result.width).isEqualTo(642)\n    assertThat(result.height).isEqualTo(642)\n  }\n\n  @Test fun centerInsideResultMatchesTargetSizeWhileDesiredHeightIs0() {\n    val request = Request.Builder(URI_1).resize(1080, 0).centerInside().build()\n    val source = android.graphics.Bitmap.createBitmap(640, 640, ARGB_8888)\n\n    val result = transformResult(request, source, 0)\n\n    assertThat(result.width).isEqualTo(1080)\n    assertThat(result.height).isEqualTo(1080)\n  }\n\n  @Test fun exifRotationWithManualRotation() {\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val data = Request.Builder(URI_1).rotate(-45f).build()\n\n    val result = transformResult(data, source, ORIENTATION_ROTATE_90)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"rotate 90.0\")\n    assertThat(shadowMatrix.setOperations).containsEntry(\"rotate\", \"-45.0\")\n  }\n\n  @Test fun rotation() {\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val data = Request.Builder(URI_1).rotate(-45f).build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.setOperations).containsEntry(\"rotate\", \"-45.0\")\n  }\n\n  @Test fun pivotRotation() {\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val data = Request.Builder(URI_1).rotate(-45f, 10f, 10f).build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.setOperations).containsEntry(\"rotate\", \"-45.0 10.0 10.0\")\n  }\n\n  @Test fun resize() {\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(20, 15).build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 2.0 1.5\")\n  }\n\n  @Test fun centerCropTallTooSmall() {\n    val source = android.graphics.Bitmap.createBitmap(10, 20, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(40, 40).centerCrop().build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n    assertThat(shadowBitmap.createdFromX).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromY).isEqualTo(5)\n    assertThat(shadowBitmap.createdFromWidth).isEqualTo(10)\n    assertThat(shadowBitmap.createdFromHeight).isEqualTo(10)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 4.0 4.0\")\n  }\n\n  @Test fun centerCropTallTooLarge() {\n    val source = android.graphics.Bitmap.createBitmap(100, 200, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(50, 50).centerCrop().build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n    assertThat(shadowBitmap.createdFromX).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromY).isEqualTo(50)\n    assertThat(shadowBitmap.createdFromWidth).isEqualTo(100)\n    assertThat(shadowBitmap.createdFromHeight).isEqualTo(100)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.5 0.5\")\n  }\n\n  @Test fun centerCropWideTooSmall() {\n    val source = android.graphics.Bitmap.createBitmap(20, 10, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(40, 40).centerCrop().build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n    assertThat(shadowBitmap.createdFromX).isEqualTo(5)\n    assertThat(shadowBitmap.createdFromY).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromWidth).isEqualTo(10)\n    assertThat(shadowBitmap.createdFromHeight).isEqualTo(10)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 4.0 4.0\")\n  }\n\n  @Test fun centerCropWithGravityHorizontalLeft() {\n    val source = android.graphics.Bitmap.createBitmap(20, 10, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(40, 40).centerCrop(Gravity.LEFT).build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n    assertThat(shadowBitmap.createdFromX).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromY).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromWidth).isEqualTo(10)\n    assertThat(shadowBitmap.createdFromHeight).isEqualTo(10)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 4.0 4.0\")\n  }\n\n  @Test fun centerCropWithGravityHorizontalRight() {\n    val source = android.graphics.Bitmap.createBitmap(20, 10, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(40, 40).centerCrop(Gravity.RIGHT).build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n    assertThat(shadowBitmap.createdFromX).isEqualTo(10)\n    assertThat(shadowBitmap.createdFromY).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromWidth).isEqualTo(10)\n    assertThat(shadowBitmap.createdFromHeight).isEqualTo(10)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 4.0 4.0\")\n  }\n\n  @Test fun centerCropWithGravityVerticalTop() {\n    val source = android.graphics.Bitmap.createBitmap(10, 20, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(40, 40).centerCrop(Gravity.TOP).build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n    assertThat(shadowBitmap.createdFromX).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromY).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromWidth).isEqualTo(10)\n    assertThat(shadowBitmap.createdFromHeight).isEqualTo(10)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 4.0 4.0\")\n  }\n\n  @Test fun centerCropWithGravityVerticalBottom() {\n    val source = android.graphics.Bitmap.createBitmap(10, 20, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(40, 40).centerCrop(Gravity.BOTTOM).build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n    assertThat(shadowBitmap.createdFromX).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromY).isEqualTo(10)\n    assertThat(shadowBitmap.createdFromWidth).isEqualTo(10)\n    assertThat(shadowBitmap.createdFromHeight).isEqualTo(10)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 4.0 4.0\")\n  }\n\n  @Test fun centerCropWideTooLarge() {\n    val source = android.graphics.Bitmap.createBitmap(200, 100, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(50, 50).centerCrop().build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n    assertThat(shadowBitmap.createdFromX).isEqualTo(50)\n    assertThat(shadowBitmap.createdFromY).isEqualTo(0)\n    assertThat(shadowBitmap.createdFromWidth).isEqualTo(100)\n    assertThat(shadowBitmap.createdFromHeight).isEqualTo(100)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.5 0.5\")\n  }\n\n  @Test fun centerInsideTallTooSmall() {\n    val source = android.graphics.Bitmap.createBitmap(20, 10, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(50, 50).centerInside().build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 2.5 2.5\")\n  }\n\n  @Test fun centerInsideTallTooLarge() {\n    val source = android.graphics.Bitmap.createBitmap(100, 50, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(50, 50).centerInside().build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.5 0.5\")\n  }\n\n  @Test fun centerInsideWideTooSmall() {\n    val source = android.graphics.Bitmap.createBitmap(10, 20, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(50, 50).centerInside().build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 2.5 2.5\")\n  }\n\n  @Test fun centerInsideWideTooLarge() {\n    val source = android.graphics.Bitmap.createBitmap(50, 100, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(50, 50).centerInside().build()\n\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.5 0.5\")\n  }\n\n  @Test fun onlyScaleDownOriginalBigger() {\n    val source = android.graphics.Bitmap.createBitmap(100, 100, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(50, 50).onlyScaleDown().build()\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.5 0.5\")\n  }\n\n  @Test fun onlyScaleDownOriginalSmaller() {\n    val source = android.graphics.Bitmap.createBitmap(50, 50, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(100, 100).onlyScaleDown().build()\n    val result = transformResult(data, source, 0)\n    assertThat(result).isSameInstanceAs(source)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isNull()\n    assertThat(shadowBitmap.createdFromBitmap).isNotSameInstanceAs(source)\n  }\n\n  @Test fun onlyScaleDownOriginalSmallerWidthIs0() {\n    val source = android.graphics.Bitmap.createBitmap(50, 50, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(0, 60).onlyScaleDown().build()\n    val result = transformResult(data, source, 0)\n    assertThat(result).isSameInstanceAs(source)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isNull()\n  }\n\n  @Test fun onlyScaleDownOriginalSmallerHeightIs0() {\n    val source = android.graphics.Bitmap.createBitmap(50, 50, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(60, 0).onlyScaleDown().build()\n    val result = transformResult(data, source, 0)\n    assertThat(result).isSameInstanceAs(source)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isNull()\n  }\n\n  @Test fun onlyScaleDownOriginalBiggerWidthIs0() {\n    val source = android.graphics.Bitmap.createBitmap(50, 50, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(0, 40).onlyScaleDown().build()\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.8 0.8\")\n  }\n\n  @Test fun onlyScaleDownOriginalBiggerHeightIs0() {\n    val source = android.graphics.Bitmap.createBitmap(50, 50, ARGB_8888)\n    val data = Request.Builder(URI_1).resize(40, 0).onlyScaleDown().build()\n    val result = transformResult(data, source, 0)\n\n    val shadowBitmap = shadowOf(result)\n    assertThat(shadowBitmap.createdFromBitmap).isSameInstanceAs(source)\n\n    val matrix = shadowBitmap.createdFromMatrix\n    val shadowMatrix = shadowOf(matrix)\n\n    assertThat(shadowMatrix.preOperations).containsExactly(\"scale 0.8 0.8\")\n  }\n\n  @Test fun reusedBitmapIsNotRecycled() {\n    val data = Request.Builder(URI_1).build()\n    val source = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = transformResult(data, source, 0)\n    assertThat(result).isSameInstanceAs(source)\n    assertThat(result.isRecycled).isFalse()\n  }\n\n  @Test fun crashingOnTransformationThrows() {\n    val badTransformation = object : Transformation {\n      override fun transform(source: Bitmap): Bitmap {\n        throw NullPointerException(\"hello\")\n      }\n\n      override fun key(): String {\n        return \"test\"\n      }\n    }\n    val transformations = listOf(badTransformation)\n    val original = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = RequestHandler.Result.Bitmap(original, MEMORY, 0)\n    val data = Request.Builder(URI_1).build()\n    try {\n      applyTransformations(picasso, data, transformations, result)\n      shadowOf(Looper.getMainLooper()).idle()\n      fail(\"Expected exception to be thrown.\")\n    } catch (e: RuntimeException) {\n      assertThat(e)\n        .hasMessageThat()\n        .isEqualTo(\"Transformation ${badTransformation.key()} crashed with exception.\")\n    }\n  }\n\n  @Test fun recycledTransformationBitmapThrows() {\n    val badTransformation: Transformation = object : Transformation {\n      override fun transform(source: Bitmap): Bitmap {\n        source.bitmap.recycle()\n        return source\n      }\n\n      override fun key(): String {\n        return \"test\"\n      }\n    }\n    val transformations = listOf(badTransformation)\n    val original = android.graphics.Bitmap.createBitmap(10, 10, ARGB_8888)\n    val result = RequestHandler.Result.Bitmap(original, MEMORY, 0)\n    val data = Request.Builder(URI_1).build()\n    try {\n      applyTransformations(picasso, data, transformations, result)\n      shadowOf(Looper.getMainLooper()).idle()\n      fail(\"Expected exception to be thrown.\")\n    } catch (e: RuntimeException) {\n      assertThat(e)\n        .hasMessageThat()\n        .isEqualTo(\"Transformation ${badTransformation.key()} returned a recycled Bitmap.\")\n    }\n  }\n\n  // TODO: fix regression from https://github.com/square/picasso/pull/2137\n  // @Test public void transformDrawables() {\n  //  final AtomicInteger transformationCount = new AtomicInteger();\n  //  Transformation identity = new Transformation() {\n  //    @Override public RequestHandler.Result.Bitmap transform(RequestHandler.Result.Bitmap source) {\n  //      transformationCount.incrementAndGet();\n  //      return source;\n  //    }\n  //\n  //    @Override public String key() {\n  //      return \"test\";\n  //    }\n  //  };\n  //  List<Transformation> transformations = asList(identity, identity, identity);\n  //  Drawable original = new BitmapDrawable(Bitmap.createBitmap(10, 10, ARGB_8888));\n  //  RequestHandler.Result.Bitmap result = new RequestHandler.Result.Bitmap(original, MEMORY);\n  //  Request data = new Request.Builder(URI_1).build();\n  //  BitmapHunter.applyTransformations(picasso, data, transformations, result);\n  //  assertThat(transformationCount.get()).isEqualTo(3);\n  // }\n\n  internal class TestableBitmapHunter(\n    picasso: Picasso,\n    dispatcher: Dispatcher,\n    cache: PlatformLruCache,\n    action: Action,\n    result: android.graphics.Bitmap? = null,\n    exception: Exception? = null,\n    shouldRetry: Boolean = false,\n    supportsReplay: Boolean = false\n  ) : BitmapHunter(\n    picasso,\n    dispatcher,\n    cache,\n    action,\n    TestableRequestHandler(result, exception, shouldRetry, supportsReplay)\n  )\n\n  private class TestableRequestHandler internal constructor(\n    private val bitmap: android.graphics.Bitmap?,\n    private val exception: Exception?,\n    private val shouldRetry: Boolean,\n    private val supportsReplay: Boolean\n  ) : RequestHandler() {\n    override fun canHandleRequest(data: Request): Boolean {\n      return true\n    }\n\n    override fun load(picasso: Picasso, request: Request, callback: Callback) {\n      if (exception != null) {\n        callback.onError(exception)\n      } else {\n        callback.onSuccess(Bitmap(bitmap!!, NETWORK))\n      }\n    }\n\n    override val retryCount: Int\n      get() = 1\n\n    override fun shouldRetry(airplaneMode: Boolean, info: NetworkInfo?): Boolean {\n      return shouldRetry\n    }\n\n    override fun supportsReplay(): Boolean {\n      return supportsReplay\n    }\n  }\n\n  private inner class CustomRequestHandler : RequestHandler() {\n    override fun canHandleRequest(data: Request): Boolean {\n      return CUSTOM_URI.scheme == data.uri!!.scheme\n    }\n\n    override fun load(picasso: Picasso, request: Request, callback: Callback) {\n      callback.onSuccess(Result.Bitmap(bitmap, MEMORY))\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/BitmapTargetActionTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport android.graphics.drawable.Drawable\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.TestUtils.NO_EVENT_LISTENERS\nimport com.squareup.picasso3.TestUtils.NO_HANDLERS\nimport com.squareup.picasso3.TestUtils.NO_TRANSFORMERS\nimport com.squareup.picasso3.TestUtils.RESOURCE_ID_1\nimport com.squareup.picasso3.TestUtils.SIMPLE_REQUEST\nimport com.squareup.picasso3.TestUtils.UNUSED_CALL_FACTORY\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.mockBitmapTarget\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport org.junit.Assert.fail\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.`when`\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\n\n@RunWith(RobolectricTestRunner::class)\nclass BitmapTargetActionTest {\n\n  @Test fun invokesSuccessIfTargetIsNotNull() {\n    val bitmap = makeBitmap()\n    val target = mockBitmapTarget()\n    val request = BitmapTargetAction(\n      picasso = mockPicasso(RuntimeEnvironment.application),\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = 0\n    )\n    request.complete(RequestHandler.Result.Bitmap(bitmap, MEMORY))\n    verify(target).onBitmapLoaded(bitmap, MEMORY)\n  }\n\n  @Test fun invokesOnBitmapFailedIfTargetIsNotNullWithErrorDrawable() {\n    val errorDrawable = mock(Drawable::class.java)\n    val target = mockBitmapTarget()\n    val request = BitmapTargetAction(\n      picasso = mockPicasso(RuntimeEnvironment.application),\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = errorDrawable,\n      errorResId = 0\n    )\n    val e = RuntimeException()\n\n    request.error(e)\n\n    verify(target).onBitmapFailed(e, errorDrawable)\n  }\n\n  @Test fun invokesOnBitmapFailedIfTargetIsNotNullWithErrorResourceId() {\n    val errorDrawable = mock(Drawable::class.java)\n    val target = mockBitmapTarget()\n    val context = mock(Context::class.java)\n    val dispatcher = mock(Dispatcher::class.java)\n    val cache = PlatformLruCache(0)\n    val picasso = Picasso(\n      context, dispatcher, UNUSED_CALL_FACTORY, null, cache, null,\n      NO_TRANSFORMERS, NO_HANDLERS, NO_EVENT_LISTENERS, ARGB_8888, false, false\n    )\n    val request = BitmapTargetAction(\n      picasso = picasso,\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = RESOURCE_ID_1\n    )\n\n    `when`(context.getDrawable(RESOURCE_ID_1)).thenReturn(errorDrawable)\n    val e = RuntimeException()\n\n    request.error(e)\n    verify(target).onBitmapFailed(e, errorDrawable)\n  }\n\n  @Test fun recyclingInSuccessThrowsException() {\n    val picasso = mockPicasso(RuntimeEnvironment.application)\n    val bitmap = makeBitmap()\n    val tr = BitmapTargetAction(\n      picasso = picasso,\n      target = object : BitmapTarget {\n        override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) = bitmap.recycle()\n        override fun onBitmapFailed(e: Exception, errorDrawable: Drawable?) = fail()\n        override fun onPrepareLoad(placeHolderDrawable: Drawable?) = fail()\n      },\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = 0\n    )\n    try {\n      tr.complete(RequestHandler.Result.Bitmap(bitmap, MEMORY))\n      fail()\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/DeferredRequestCreatorTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.TestUtils.argumentCaptor\nimport com.squareup.picasso3.TestUtils.mockCallback\nimport com.squareup.picasso3.TestUtils.mockFitImageViewTarget\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport com.squareup.picasso3.TestUtils.mockRequestCreator\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.Mockito.never\nimport org.mockito.Mockito.spy\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.verifyNoMoreInteractions\nimport org.mockito.Mockito.`when`\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\n\n@RunWith(RobolectricTestRunner::class)\nclass DeferredRequestCreatorTest {\n  private val picasso = mockPicasso(RuntimeEnvironment.application)\n\n  @Test fun initWhileAttachedAddsAttachAndPreDrawListener() {\n    val target = mockFitImageViewTarget(true)\n    val observer = target.viewTreeObserver\n    val request = DeferredRequestCreator(mockRequestCreator(picasso), target, null)\n    verify(observer).addOnPreDrawListener(request)\n  }\n\n  @Test fun initWhileDetachedAddsAttachListenerWhichDefersPreDrawListener() {\n    val target = mockFitImageViewTarget(true)\n    `when`(target.windowToken).thenReturn(null)\n    val observer = target.viewTreeObserver\n    val request = DeferredRequestCreator(mockRequestCreator(picasso), target, null)\n    verify(target).addOnAttachStateChangeListener(request)\n    verifyNoMoreInteractions(observer)\n\n    // Attach and ensure we defer to the pre-draw listener.\n    request.onViewAttachedToWindow(target)\n    verify(observer).addOnPreDrawListener(request)\n\n    // Detach and ensure we remove the pre-draw listener from the original VTO.\n    request.onViewDetachedFromWindow(target)\n    verify(observer).removeOnPreDrawListener(request)\n  }\n\n  @Test fun cancelWhileAttachedRemovesAttachListener() {\n    val target = mockFitImageViewTarget(true)\n    val request = DeferredRequestCreator(mockRequestCreator(picasso), target, null)\n    verify(target).addOnAttachStateChangeListener(request)\n    request.cancel()\n    verify(target).removeOnAttachStateChangeListener(request)\n  }\n\n  @Test fun cancelClearsCallback() {\n    val target = mockFitImageViewTarget(true)\n    val callback = mockCallback()\n    val request = DeferredRequestCreator(mockRequestCreator(picasso), target, callback)\n    assertThat(request.callback).isNotNull()\n    request.cancel()\n    assertThat(request.callback).isNull()\n  }\n\n  @Test fun cancelClearsTag() {\n    val target = mockFitImageViewTarget(true)\n    val creator = mockRequestCreator(picasso).tag(\"TAG\")\n    val request = DeferredRequestCreator(creator, target, null)\n\n    assertThat(creator.tag).isNotNull()\n    request.cancel()\n    assertThat(creator.tag).isNull()\n  }\n\n  @Test fun onLayoutSkipsIfViewIsAttachedAndViewTreeObserverIsDead() {\n    val target = mockFitImageViewTarget(false)\n    val creator = mockRequestCreator(picasso)\n    val request = DeferredRequestCreator(creator, target, null)\n    val viewTreeObserver = target.viewTreeObserver\n    request.onPreDraw()\n    verify(viewTreeObserver).addOnPreDrawListener(request)\n    verify(viewTreeObserver).isAlive\n    verifyNoMoreInteractions(viewTreeObserver)\n  }\n\n  @Test fun waitsForAnotherLayoutIfWidthOrHeightIsZero() {\n    val target = mockFitImageViewTarget(true)\n    `when`(target.width).thenReturn(0)\n    `when`(target.height).thenReturn(0)\n    val creator = mockRequestCreator(picasso)\n    val request = DeferredRequestCreator(creator, target, null)\n    request.onPreDraw()\n    verify(target.viewTreeObserver, never()).removeOnPreDrawListener(request)\n  }\n\n  @Test fun cancelSkipsIfViewTreeObserverIsDead() {\n    val target = mockFitImageViewTarget(false)\n    val creator = mockRequestCreator(picasso)\n    val request = DeferredRequestCreator(creator, target, null)\n    request.cancel()\n    verify(target.viewTreeObserver, never()).removeOnPreDrawListener(request)\n  }\n\n  @Test fun preDrawSubmitsRequestAndCleansUp() {\n    val spyPicasso = spy(picasso) // ugh\n    val creator = RequestCreator(spyPicasso, TestUtils.URI_1, 0)\n\n    val target = mockFitImageViewTarget(true)\n    `when`(target.width).thenReturn(100)\n    `when`(target.height).thenReturn(100)\n\n    val observer = target.viewTreeObserver\n\n    val request = DeferredRequestCreator(creator, target, null)\n    request.onPreDraw()\n\n    verify(observer).removeOnPreDrawListener(request)\n    val actionCaptor = argumentCaptor<ImageViewAction>()\n    verify(spyPicasso).enqueueAndSubmit(actionCaptor.capture())\n\n    val value = actionCaptor.value\n    assertThat(value).isInstanceOf(ImageViewAction::class.java)\n    assertThat(value.request.targetWidth).isEqualTo(100)\n    assertThat(value.request.targetHeight).isEqualTo(100)\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/DrawableTargetActionTest.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.content.res.Resources\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport android.graphics.drawable.Drawable\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Picasso.LoadedFrom.NETWORK\nimport com.squareup.picasso3.TestUtils.argumentCaptor\nimport com.squareup.picasso3.TestUtils.eq\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.mockDrawableTarget\nimport org.junit.Assert\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.Mockito\nimport org.mockito.Mockito.mock\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\n\n@RunWith(RobolectricTestRunner::class)\nclass DrawableTargetActionTest {\n\n  @Test fun invokesSuccessIfTargetIsNotNull() {\n    val bitmap = makeBitmap()\n    val target = mockDrawableTarget()\n    val drawableCaptor = argumentCaptor<PicassoDrawable>()\n    val placeholder = mock(Drawable::class.java)\n    val action = DrawableTargetAction(\n      picasso = TestUtils.mockPicasso(RuntimeEnvironment.application),\n      target = target,\n      data = TestUtils.SIMPLE_REQUEST,\n      noFade = false,\n      placeholderDrawable = placeholder,\n      errorDrawable = null,\n      errorResId = 0\n    )\n\n    action.complete(RequestHandler.Result.Bitmap(bitmap, NETWORK))\n\n    Mockito.verify(target).onDrawableLoaded(drawableCaptor.capture(), eq(NETWORK))\n    with(drawableCaptor.value) {\n      assertThat(this.bitmap).isEqualTo(bitmap)\n      assertThat(this.placeholder).isEqualTo(placeholder)\n      assertThat(this.animating).isTrue()\n    }\n  }\n\n  @Test fun invokesOnBitmapFailedIfTargetIsNotNullWithErrorDrawable() {\n    val errorDrawable = mock(Drawable::class.java)\n    val target = mockDrawableTarget()\n    val action = DrawableTargetAction(\n      picasso = TestUtils.mockPicasso(RuntimeEnvironment.application),\n      target = target,\n      data = TestUtils.SIMPLE_REQUEST,\n      noFade = true,\n      placeholderDrawable = null,\n      errorDrawable = errorDrawable,\n      errorResId = 0\n    )\n    val e = RuntimeException()\n\n    action.error(e)\n\n    Mockito.verify(target).onDrawableFailed(e, errorDrawable)\n  }\n\n  @Test fun invokesOnBitmapFailedIfTargetIsNotNullWithErrorResourceId() {\n    val errorDrawable = mock(Drawable::class.java)\n    val context = mock(Context::class.java)\n    val dispatcher = mock(Dispatcher::class.java)\n    val cache = PlatformLruCache(0)\n    val picasso = Picasso(\n      context, dispatcher,\n      TestUtils.UNUSED_CALL_FACTORY, null, cache, null,\n      TestUtils.NO_TRANSFORMERS,\n      TestUtils.NO_HANDLERS,\n      TestUtils.NO_EVENT_LISTENERS, ARGB_8888, false, false\n    )\n    val res = mock(Resources::class.java)\n\n    val target = mockDrawableTarget()\n    val action = DrawableTargetAction(\n      picasso = picasso,\n      target = target,\n      data = TestUtils.SIMPLE_REQUEST,\n      noFade = true,\n      placeholderDrawable = null,\n      errorDrawable = null,\n      errorResId = TestUtils.RESOURCE_ID_1\n    )\n\n    Mockito.`when`(context.getDrawable(TestUtils.RESOURCE_ID_1)).thenReturn(errorDrawable)\n    val e = RuntimeException()\n\n    action.error(e)\n\n    Mockito.verify(target).onDrawableFailed(e, errorDrawable)\n  }\n\n  @Test fun recyclingInSuccessThrowsException() {\n    val picasso = TestUtils.mockPicasso(RuntimeEnvironment.application)\n    val bitmap = makeBitmap()\n    val action = DrawableTargetAction(\n      picasso = picasso,\n      target = object : DrawableTarget {\n        override fun onDrawableLoaded(drawable: Drawable, from: Picasso.LoadedFrom) = (drawable as PicassoDrawable).bitmap.recycle()\n        override fun onDrawableFailed(e: Exception, errorDrawable: Drawable?) = throw AssertionError()\n        override fun onPrepareLoad(placeHolderDrawable: Drawable?) = throw AssertionError()\n      },\n      data = TestUtils.SIMPLE_REQUEST,\n      noFade = true,\n      placeholderDrawable = null,\n      errorDrawable = null,\n      errorResId = 0\n    )\n\n    try {\n      action.complete(RequestHandler.Result.Bitmap(bitmap, MEMORY))\n      Assert.fail()\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/HandlerDispatcherTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.content.Context.CONNECTIVITY_SERVICE\nimport android.content.pm.PackageManager.PERMISSION_DENIED\nimport android.content.pm.PackageManager.PERMISSION_GRANTED\nimport android.net.ConnectivityManager\nimport android.net.NetworkInfo\nimport android.os.Handler\nimport android.os.Looper.getMainLooper\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.MemoryPolicy.NO_STORE\nimport com.squareup.picasso3.NetworkRequestHandler.ContentLengthException\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Picasso.LoadedFrom.NETWORK\nimport com.squareup.picasso3.Request.Builder\nimport com.squareup.picasso3.TestUtils.TestDelegatingService\nimport com.squareup.picasso3.TestUtils.URI_1\nimport com.squareup.picasso3.TestUtils.URI_2\nimport com.squareup.picasso3.TestUtils.URI_KEY_1\nimport com.squareup.picasso3.TestUtils.URI_KEY_2\nimport com.squareup.picasso3.TestUtils.any\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.mockAction\nimport com.squareup.picasso3.TestUtils.mockBitmapTarget\nimport com.squareup.picasso3.TestUtils.mockCallback\nimport com.squareup.picasso3.TestUtils.mockHunter\nimport com.squareup.picasso3.TestUtils.mockNetworkInfo\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport org.junit.Before\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.ArgumentMatchers.anyString\nimport org.mockito.Mock\nimport org.mockito.Mockito.doReturn\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.spy\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.`when`\nimport org.mockito.MockitoAnnotations.initMocks\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.Shadows.shadowOf\nimport org.robolectric.shadows.ShadowLooper\nimport java.lang.Exception\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Future\nimport java.util.concurrent.FutureTask\n\n@RunWith(RobolectricTestRunner::class)\nclass HandlerDispatcherTest {\n  @Mock lateinit var context: Context\n\n  @Mock lateinit var connectivityManager: ConnectivityManager\n\n  @Mock lateinit var serviceMock: ExecutorService\n\n  private lateinit var picasso: Picasso\n  private lateinit var dispatcher: HandlerDispatcher\n\n  private val executorService = spy(PicassoExecutorService())\n  private val cache = PlatformLruCache(2048)\n  private val service = TestDelegatingService(executorService)\n  private val bitmap1 = makeBitmap()\n\n  @Before fun setUp() {\n    initMocks(this)\n    `when`(context.applicationContext).thenReturn(context)\n    doReturn(mock(Future::class.java)).`when`(executorService).submit(any(Runnable::class.java))\n    picasso = mockPicasso(context)\n    dispatcher = createDispatcher(service)\n  }\n\n  @Test fun shutdownStopsService() {\n    val service = PicassoExecutorService()\n    dispatcher = createDispatcher(service)\n    dispatcher.shutdown()\n    assertThat(service.isShutdown).isEqualTo(true)\n  }\n\n  @Test fun shutdownUnregistersReceiver() {\n    dispatcher.shutdown()\n    shadowOf(getMainLooper()).idle()\n    verify(context).unregisterReceiver(dispatcher.receiver)\n  }\n\n  @Test fun performSubmitWithNewRequestQueuesHunter() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    dispatcher.performSubmit(action)\n    assertThat(dispatcher.hunterMap).hasSize(1)\n    assertThat(service.submissions).isEqualTo(1)\n  }\n\n  @Test fun performSubmitWithTwoDifferentRequestsQueuesHunters() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1)\n    val action2 = mockAction(picasso, URI_KEY_2, URI_2)\n    dispatcher.performSubmit(action1)\n    dispatcher.performSubmit(action2)\n    assertThat(dispatcher.hunterMap).hasSize(2)\n    assertThat(service.submissions).isEqualTo(2)\n  }\n\n  @Test fun performSubmitWithExistingRequestAttachesToHunter() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1)\n    val action2 = mockAction(picasso, URI_KEY_1, URI_1)\n    dispatcher.performSubmit(action1)\n    assertThat(dispatcher.hunterMap).hasSize(1)\n    assertThat(service.submissions).isEqualTo(1)\n    dispatcher.performSubmit(action2)\n    assertThat(dispatcher.hunterMap).hasSize(1)\n    assertThat(service.submissions).isEqualTo(1)\n  }\n\n  @Test fun performSubmitWithShutdownServiceIgnoresRequest() {\n    service.shutdown()\n    val action = mockAction(picasso, URI_KEY_1, URI_1)\n    dispatcher.performSubmit(action)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(service.submissions).isEqualTo(0)\n  }\n\n  @Test fun performSubmitWithFetchAction() {\n    val pausedTag = \"pausedTag\"\n    dispatcher.pausedTags.add(pausedTag)\n    assertThat(dispatcher.pausedActions).isEmpty()\n\n    val fetchAction1 = FetchAction(picasso, Request.Builder(URI_1).tag(pausedTag).build(), null)\n    val fetchAction2 = FetchAction(picasso, Request.Builder(URI_1).tag(pausedTag).build(), null)\n    dispatcher.performSubmit(fetchAction1)\n    dispatcher.performSubmit(fetchAction2)\n\n    assertThat(dispatcher.pausedActions).hasSize(2)\n  }\n\n  @Test fun performCancelWithFetchActionWithCallback() {\n    val pausedTag = \"pausedTag\"\n    dispatcher.pausedTags.add(pausedTag)\n    assertThat(dispatcher.pausedActions).isEmpty()\n    val callback = mockCallback()\n\n    val fetchAction1 = FetchAction(picasso, Request.Builder(URI_1).tag(pausedTag).build(), callback)\n    dispatcher.performCancel(fetchAction1)\n    fetchAction1.cancel()\n    assertThat(dispatcher.pausedActions).isEmpty()\n  }\n\n  @Test fun performCancelDetachesRequestAndCleansUp() {\n    val target = mockBitmapTarget()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, target)\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    hunter.future = FutureTask(mock(Runnable::class.java), mock(Any::class.java))\n    dispatcher.hunterMap[URI_KEY_1 + Request.KEY_SEPARATOR] = hunter\n    dispatcher.failedActions[target] = action\n    dispatcher.performCancel(action)\n    assertThat(hunter.action).isNull()\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun performCancelMultipleRequestsDetachesOnly() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1)\n    val action2 = mockAction(picasso, URI_KEY_1, URI_1)\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action1)\n    hunter.attach(action2)\n    dispatcher.hunterMap[URI_KEY_1 + Request.KEY_SEPARATOR] = hunter\n    dispatcher.performCancel(action1)\n    assertThat(hunter.action).isNull()\n    assertThat(hunter.actions).containsExactly(action2)\n    assertThat(dispatcher.hunterMap).hasSize(1)\n  }\n\n  @Test fun performCancelUnqueuesAndDetachesPausedRequest() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget(), tag = \"tag\")\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    dispatcher.hunterMap[URI_KEY_1 + Request.KEY_SEPARATOR] = hunter\n    dispatcher.pausedTags.add(\"tag\")\n    dispatcher.pausedActions[action.getTarget()] = action\n    dispatcher.performCancel(action)\n    assertThat(hunter.action).isNull()\n    assertThat(dispatcher.pausedTags).containsExactly(\"tag\")\n    assertThat(dispatcher.pausedActions).isEmpty()\n  }\n\n  @Test fun performCompleteSetsResultInCache() {\n    val data = Request.Builder(URI_1).build()\n    val action = noopAction(data)\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    hunter.run()\n    assertThat(cache.size()).isEqualTo(0)\n\n    dispatcher.performComplete(hunter)\n\n    assertThat(hunter.result).isInstanceOf(RequestHandler.Result.Bitmap::class.java)\n    val result = hunter.result as RequestHandler.Result.Bitmap\n    assertThat(result.bitmap).isEqualTo(bitmap1)\n    assertThat(result.loadedFrom).isEqualTo(NETWORK)\n    assertThat(cache[hunter.key]).isSameInstanceAs(bitmap1)\n  }\n\n  @Test fun performCompleteWithNoStoreMemoryPolicy() {\n    val data = Request.Builder(URI_1).memoryPolicy(NO_STORE).build()\n    val action = noopAction(data)\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    hunter.run()\n    assertThat(cache.size()).isEqualTo(0)\n\n    dispatcher.performComplete(hunter)\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(cache.size()).isEqualTo(0)\n  }\n\n  @Test fun performCompleteCleansUpAndPostsToMain() {\n    val data = Request.Builder(URI_1).build()\n    var completed = false\n    val action = noopAction(data, onComplete = { completed = true })\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    hunter.run()\n\n    dispatcher.performComplete(hunter)\n    ShadowLooper.idleMainLooper()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(completed).isTrue()\n  }\n\n  @Test fun performCompleteCleansUpAndDoesNotPostToMainIfCancelled() {\n    val data = Request.Builder(URI_1).build()\n    var completed = false\n    val action = noopAction(data, onComplete = { completed = true })\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    hunter.run()\n    hunter.future = FutureTask<Any>(mock(Runnable::class.java), null)\n    hunter.future!!.cancel(false)\n\n    dispatcher.performComplete(hunter)\n    ShadowLooper.idleMainLooper()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(completed).isFalse()\n  }\n\n  @Test fun performErrorCleansUpAndPostsToMain() {\n    val exception = RuntimeException()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget(), tag = \"tag\")\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action, exception)\n    dispatcher.hunterMap[hunter.key] = hunter\n    hunter.run()\n\n    dispatcher.performError(hunter)\n    ShadowLooper.idleMainLooper()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(action.errorException).isSameInstanceAs(exception)\n  }\n\n  @Test fun performErrorCleansUpAndDoesNotPostToMainIfCancelled() {\n    val exception = RuntimeException()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget(), tag = \"tag\")\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action, exception)\n    hunter.future = FutureTask(mock(Runnable::class.java), mock(Any::class.java))\n    hunter.future!!.cancel(false)\n    dispatcher.hunterMap[hunter.key] = hunter\n    hunter.run()\n\n    dispatcher.performError(hunter)\n    ShadowLooper.idleMainLooper()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(action.errorException).isNull()\n    assertThat(action.completedResult).isNull()\n  }\n\n  @Test fun performRetrySkipsIfHunterIsCancelled() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget(), tag = \"tag\")\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    hunter.future = FutureTask(mock(Runnable::class.java), mock(Any::class.java))\n    hunter.future!!.cancel(false)\n    dispatcher.performRetry(hunter)\n    assertThat(hunter.isCancelled).isTrue()\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun performRetryForContentLengthResetsNetworkPolicy() {\n    val networkInfo = mockNetworkInfo(true)\n    `when`(connectivityManager.activeNetworkInfo).thenReturn(networkInfo)\n    val action = mockAction(picasso, URI_KEY_2, URI_2)\n    val e = ContentLengthException(\"304 error\")\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action, e, true)\n    hunter.run()\n    dispatcher.performRetry(hunter)\n    assertThat(NetworkPolicy.shouldReadFromDiskCache(hunter.data.networkPolicy)).isFalse()\n  }\n\n  @Test fun performRetryDoesNotMarkForReplayIfNotSupported() {\n    val networkInfo = mockNetworkInfo(true)\n    val hunter = mockHunter(\n      picasso,\n      RequestHandler.Result.Bitmap(bitmap1, MEMORY),\n      mockAction(picasso, URI_KEY_1, URI_1)\n    )\n    `when`(connectivityManager.activeNetworkInfo).thenReturn(networkInfo)\n    dispatcher.performRetry(hunter)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n    assertThat(service.submissions).isEqualTo(0)\n  }\n\n  @Test fun performRetryDoesNotMarkForReplayIfNoNetworkScanning() {\n    val hunter = mockHunter(\n      picasso,\n      RequestHandler.Result.Bitmap(bitmap1, MEMORY),\n      mockAction(picasso, URI_KEY_1, URI_1),\n      e = null,\n      shouldRetry = false,\n      supportsReplay = true\n    )\n    val dispatcher = createDispatcher(false)\n    dispatcher.performRetry(hunter)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n    assertThat(service.submissions).isEqualTo(0)\n  }\n\n  @Test fun performRetryMarksForReplayIfSupportedScansNetworkChangesAndShouldNotRetry() {\n    val networkInfo = mockNetworkInfo(true)\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget())\n    val hunter = mockHunter(\n      picasso,\n      RequestHandler.Result.Bitmap(bitmap1, MEMORY),\n      action,\n      e = null,\n      shouldRetry = false,\n      supportsReplay = true\n    )\n    `when`(connectivityManager.activeNetworkInfo).thenReturn(networkInfo)\n    dispatcher.performRetry(hunter)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).hasSize(1)\n    assertThat(service.submissions).isEqualTo(0)\n  }\n\n  @Test fun performRetryRetriesIfNoNetworkScanning() {\n    val hunter = mockHunter(\n      picasso,\n      RequestHandler.Result.Bitmap(bitmap1, MEMORY),\n      mockAction(picasso, URI_KEY_1, URI_1),\n      e = null,\n      shouldRetry = true\n    )\n    val dispatcher = createDispatcher(false)\n    dispatcher.performRetry(hunter)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n    assertThat(service.submissions).isEqualTo(1)\n  }\n\n  @Test fun performRetryMarksForReplayIfSupportsReplayAndShouldNotRetry() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget())\n    val hunter = mockHunter(\n      picasso,\n      RequestHandler.Result.Bitmap(bitmap1, MEMORY),\n      action,\n      e = null,\n      shouldRetry = false,\n      supportsReplay = true\n    )\n    dispatcher.performRetry(hunter)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).hasSize(1)\n    assertThat(service.submissions).isEqualTo(0)\n  }\n\n  @Test fun performRetryRetriesIfShouldRetry() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget())\n    val hunter = mockHunter(\n      picasso,\n      RequestHandler.Result.Bitmap(bitmap1, MEMORY),\n      action,\n      e = null,\n      shouldRetry = true\n    )\n    dispatcher.performRetry(hunter)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n    assertThat(service.submissions).isEqualTo(1)\n  }\n\n  @Test fun performRetrySkipIfServiceShutdown() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget())\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    service.shutdown()\n    dispatcher.performRetry(hunter)\n    assertThat(service.submissions).isEqualTo(0)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun performAirplaneModeChange() {\n    assertThat(dispatcher.airplaneMode).isFalse()\n    dispatcher.performAirplaneModeChange(true)\n    assertThat(dispatcher.airplaneMode).isTrue()\n    dispatcher.performAirplaneModeChange(false)\n    assertThat(dispatcher.airplaneMode).isFalse()\n  }\n\n  @Test fun performNetworkStateChangeWithNullInfoIgnores() {\n    val dispatcher = createDispatcher(serviceMock)\n    dispatcher.performNetworkStateChange(null)\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun performNetworkStateChangeWithDisconnectedInfoIgnores() {\n    val dispatcher = createDispatcher(serviceMock)\n    val info = mockNetworkInfo()\n    `when`(info.isConnectedOrConnecting).thenReturn(false)\n    dispatcher.performNetworkStateChange(info)\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun performNetworkStateChangeWithConnectedInfoDifferentInstanceIgnores() {\n    val dispatcher = createDispatcher(serviceMock)\n    val info = mockNetworkInfo(true)\n    dispatcher.performNetworkStateChange(info)\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun performPauseAndResumeUpdatesListOfPausedTags() {\n    dispatcher.performPauseTag(\"tag\")\n    assertThat(dispatcher.pausedTags).containsExactly(\"tag\")\n    dispatcher.performResumeTag(\"tag\")\n    assertThat(dispatcher.pausedTags).isEmpty()\n  }\n\n  @Test fun performPauseTagIsIdempotent() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockBitmapTarget(), tag = \"tag\")\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    dispatcher.hunterMap[URI_KEY_1] = hunter\n    assertThat(dispatcher.pausedActions).isEmpty()\n    dispatcher.performPauseTag(\"tag\")\n    assertThat(dispatcher.pausedActions).containsEntry(action.getTarget(), action)\n    dispatcher.performPauseTag(\"tag\")\n    assertThat(dispatcher.pausedActions).containsEntry(action.getTarget(), action)\n  }\n\n  @Test fun performPauseTagQueuesNewRequestDoesNotSubmit() {\n    dispatcher.performPauseTag(\"tag\")\n    val action = mockAction(picasso = picasso, key = URI_KEY_1, uri = URI_1, tag = \"tag\")\n    dispatcher.performSubmit(action)\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.pausedActions).hasSize(1)\n    assertThat(dispatcher.pausedActions.containsValue(action)).isTrue()\n    assertThat(service.submissions).isEqualTo(0)\n  }\n\n  @Test fun performPauseTagDoesNotQueueUnrelatedRequest() {\n    dispatcher.performPauseTag(\"tag\")\n    val action = mockAction(picasso, URI_KEY_1, URI_1, \"anothertag\")\n    dispatcher.performSubmit(action)\n    assertThat(dispatcher.hunterMap).hasSize(1)\n    assertThat(dispatcher.pausedActions).isEmpty()\n    assertThat(service.submissions).isEqualTo(1)\n  }\n\n  @Test fun performPauseDetachesRequestAndCancelsHunter() {\n    val action = mockAction(\n      picasso = picasso,\n      key = URI_KEY_1,\n      uri = URI_1,\n      tag = \"tag\"\n    )\n    val hunter = mockHunter(\n      picasso = picasso,\n      result = RequestHandler.Result.Bitmap(bitmap1, MEMORY),\n      action = action,\n      dispatcher = dispatcher\n    )\n    hunter.future = FutureTask(mock(Runnable::class.java), mock(Any::class.java))\n    dispatcher.hunterMap[URI_KEY_1] = hunter\n    dispatcher.performPauseTag(\"tag\")\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.pausedActions).hasSize(1)\n    assertThat(dispatcher.pausedActions.containsValue(action)).isTrue()\n    assertThat(hunter.action).isNull()\n  }\n\n  @Test fun performPauseOnlyDetachesPausedRequest() {\n    val action1 = mockAction(\n      picasso = picasso,\n      key = URI_KEY_1,\n      uri = URI_1,\n      target = mockBitmapTarget(),\n      tag = \"tag1\"\n    )\n    val action2 = mockAction(\n      picasso = picasso,\n      key = URI_KEY_1,\n      uri = URI_1,\n      target = mockBitmapTarget(),\n      tag = \"tag2\"\n    )\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action1)\n    hunter.attach(action2)\n    dispatcher.hunterMap[URI_KEY_1] = hunter\n    dispatcher.performPauseTag(\"tag1\")\n    assertThat(dispatcher.hunterMap).hasSize(1)\n    assertThat(dispatcher.hunterMap.containsValue(hunter)).isTrue()\n    assertThat(dispatcher.pausedActions).hasSize(1)\n    assertThat(dispatcher.pausedActions.containsValue(action1)).isTrue()\n    assertThat(hunter.action).isNull()\n    assertThat(hunter.actions).containsExactly(action2)\n  }\n\n  @Test fun performResumeTagResumesPausedActions() {\n    val action = noopAction(Builder(URI_1).tag(\"tag\").build())\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap1, MEMORY), action)\n    dispatcher.hunterMap[URI_KEY_1] = hunter\n    assertThat(dispatcher.pausedActions).isEmpty()\n    dispatcher.performPauseTag(\"tag\")\n    assertThat(dispatcher.pausedActions).containsEntry(action.getTarget(), action)\n\n    dispatcher.performResumeTag(\"tag\")\n\n    assertThat(dispatcher.pausedActions).isEmpty()\n  }\n\n  @Test fun performNetworkStateChangeFlushesFailedHunters() {\n    val info = mockNetworkInfo(true)\n    val failedAction1 = mockAction(picasso, URI_KEY_1, URI_1)\n    val failedAction2 = mockAction(picasso, URI_KEY_2, URI_2)\n    dispatcher.failedActions[URI_KEY_1] = failedAction1\n    dispatcher.failedActions[URI_KEY_2] = failedAction2\n    dispatcher.performNetworkStateChange(info)\n    assertThat(service.submissions).isEqualTo(2)\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  private fun createDispatcher(scansNetworkChanges: Boolean): HandlerDispatcher {\n    return createDispatcher(service, scansNetworkChanges)\n  }\n\n  private fun createDispatcher(\n    service: ExecutorService,\n    scansNetworkChanges: Boolean = true\n  ): HandlerDispatcher {\n    `when`(connectivityManager.activeNetworkInfo).thenReturn(\n      if (scansNetworkChanges) mock(NetworkInfo::class.java) else null\n    )\n    `when`(context.getSystemService(CONNECTIVITY_SERVICE)).thenReturn(connectivityManager)\n    `when`(context.checkCallingOrSelfPermission(anyString())).thenReturn(\n      if (scansNetworkChanges) PERMISSION_GRANTED else PERMISSION_DENIED\n    )\n    return HandlerDispatcher(context, service, Handler(getMainLooper()), cache)\n  }\n\n  private fun noopAction(data: Request, onComplete: () -> Unit = { }): Action {\n    return object : Action(picasso, data) {\n      override fun complete(result: RequestHandler.Result) = onComplete()\n      override fun error(e: Exception) = Unit\n      override fun getTarget(): Any = this\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/ImageViewActionTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport android.graphics.drawable.AnimationDrawable\nimport android.graphics.drawable.Drawable\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport com.squareup.picasso3.TestUtils.NO_EVENT_LISTENERS\nimport com.squareup.picasso3.TestUtils.NO_HANDLERS\nimport com.squareup.picasso3.TestUtils.NO_TRANSFORMERS\nimport com.squareup.picasso3.TestUtils.RESOURCE_ID_1\nimport com.squareup.picasso3.TestUtils.SIMPLE_REQUEST\nimport com.squareup.picasso3.TestUtils.UNUSED_CALL_FACTORY\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.mockCallback\nimport com.squareup.picasso3.TestUtils.mockImageViewTarget\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.ArgumentMatchers.any\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.`when`\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\n\n@RunWith(RobolectricTestRunner::class)\nclass ImageViewActionTest {\n\n  @Test\n  fun invokesTargetAndCallbackSuccessIfTargetIsNotNull() {\n    val bitmap = makeBitmap()\n    val dispatcher = mock(Dispatcher::class.java)\n    val cache = PlatformLruCache(0)\n    val picasso = Picasso(\n      RuntimeEnvironment.application, dispatcher, UNUSED_CALL_FACTORY, null, cache, null,\n      NO_TRANSFORMERS, NO_HANDLERS, NO_EVENT_LISTENERS, ARGB_8888, false, false\n    )\n    val target = mockImageViewTarget()\n    val callback = mockCallback()\n    val request = ImageViewAction(\n      picasso = picasso,\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = 0,\n      noFade = false,\n      callback = callback\n    )\n    request.complete(Bitmap(bitmap, MEMORY))\n    verify(target).setImageDrawable(any(PicassoDrawable::class.java))\n    verify(callback).onSuccess()\n  }\n\n  @Test\n  fun invokesTargetAndCallbackErrorIfTargetIsNotNullWithErrorResourceId() {\n    val target = mockImageViewTarget()\n    val callback = mockCallback()\n    val request = ImageViewAction(\n      picasso = mockPicasso(RuntimeEnvironment.application),\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = RESOURCE_ID_1,\n      noFade = false,\n      callback = callback\n    )\n    val e = RuntimeException()\n\n    request.error(e)\n\n    verify(target).setImageResource(RESOURCE_ID_1)\n    verify(callback).onError(e)\n  }\n\n  @Test fun invokesErrorIfTargetIsNotNullWithErrorResourceId() {\n    val target = mockImageViewTarget()\n    val callback = mockCallback()\n    val request = ImageViewAction(\n      picasso = mockPicasso(RuntimeEnvironment.application),\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = RESOURCE_ID_1,\n      noFade = false,\n      callback = callback\n    )\n    val e = RuntimeException()\n\n    request.error(e)\n    verify(target).setImageResource(RESOURCE_ID_1)\n    verify(callback).onError(e)\n  }\n\n  @Test fun invokesErrorIfTargetIsNotNullWithErrorDrawable() {\n    val errorDrawable = mock(Drawable::class.java)\n    val target = mockImageViewTarget()\n    val callback = mockCallback()\n    val request = ImageViewAction(\n      picasso = mockPicasso(RuntimeEnvironment.application),\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = errorDrawable,\n      errorResId = 0,\n      noFade = false,\n      callback = callback\n    )\n    val e = RuntimeException()\n\n    request.error(e)\n\n    verify(target).setImageDrawable(errorDrawable)\n    verify(callback).onError(e)\n  }\n\n  @Test fun clearsCallbackOnCancel() {\n    val picasso = mockPicasso(RuntimeEnvironment.application)\n    val target = mockImageViewTarget()\n    val callback = mockCallback()\n    val request = ImageViewAction(\n      picasso = picasso,\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = 0,\n      noFade = false,\n      callback = callback\n    )\n    request.cancel()\n    assertThat(request.callback).isNull()\n  }\n\n  @Test fun stopPlaceholderAnimationOnError() {\n    val picasso = mockPicasso(RuntimeEnvironment.application)\n    val placeholder = mock(AnimationDrawable::class.java)\n    val target = mockImageViewTarget()\n    `when`(target.drawable).thenReturn(placeholder)\n    val request = ImageViewAction(\n      picasso = picasso,\n      target = target,\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = 0,\n      noFade = false,\n      callback = null\n    )\n    request.error(RuntimeException())\n    verify(placeholder).stop()\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/InternalCoroutineDispatcherTest.kt",
    "content": "/*\n * Copyright (C) 2023 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.net.ConnectivityManager\nimport android.net.NetworkInfo\nimport android.os.Handler\nimport android.os.Looper\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.MemoryPolicy.NO_STORE\nimport com.squareup.picasso3.NetworkRequestHandler.ContentLengthException\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Picasso.LoadedFrom.NETWORK\nimport com.squareup.picasso3.Picasso.Priority.HIGH\nimport com.squareup.picasso3.Request.Builder\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport org.junit.Before\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.ArgumentMatchers\nimport org.mockito.Mock\nimport org.mockito.Mockito\nimport org.mockito.MockitoAnnotations\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.Shadows\nimport java.lang.Exception\nimport java.lang.RuntimeException\nimport kotlin.coroutines.CoroutineContext\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.test.StandardTestDispatcher\nimport kotlinx.coroutines.test.TestDispatcher\n\n@RunWith(RobolectricTestRunner::class)\nclass InternalCoroutineDispatcherTest {\n\n  @Mock lateinit var context: Context\n\n  @Mock lateinit var connectivityManager: ConnectivityManager\n\n  private lateinit var picasso: Picasso\n  private lateinit var dispatcher: InternalCoroutineDispatcher\n  private lateinit var testDispatcher: TestDispatcher\n\n  private val cache = PlatformLruCache(2048)\n  private val bitmap1 = TestUtils.makeBitmap()\n\n  @Before fun setUp() {\n    MockitoAnnotations.initMocks(this)\n    Mockito.`when`(context.applicationContext).thenReturn(context)\n    dispatcher = createDispatcher()\n  }\n\n  @Test fun shutdownCancelsRunningJob() {\n    createDispatcher(true)\n    val action = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    dispatcher.dispatchSubmit(action)\n\n    dispatcher.shutdown()\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.isShutdown()).isEqualTo(true)\n    assertThat(action.completedResult).isNull()\n  }\n\n  @Test fun shutdownPreventsFurtherChannelUse() {\n    val dispatcher = createDispatcher(true, backgroundContext = Dispatchers.IO)\n    val action = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    dispatcher.shutdown()\n\n    dispatcher.dispatchSubmit(action)\n\n    assertThat(dispatcher.isShutdown()).isEqualTo(true)\n    assertThat(action.completedResult).isNull()\n  }\n\n  @Test fun shutdownUnregistersReceiver() {\n    dispatcher.shutdown()\n    Shadows.shadowOf(Looper.getMainLooper()).idle()\n    Mockito.verify(context).unregisterReceiver(dispatcher.receiver)\n  }\n\n  @Test fun dispatchSubmitWithNewRequestQueuesHunter() {\n    val action = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    dispatcher.dispatchSubmit(action)\n\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(action.completedResult).isNotNull()\n  }\n\n  @Test fun dispatchSubmitWithTwoDifferentRequestsQueuesHunters() {\n    val action1 = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    val action2 = TestUtils.mockAction(picasso, TestUtils.URI_KEY_2, TestUtils.URI_2)\n\n    dispatcher.dispatchSubmit(action1)\n    dispatcher.dispatchSubmit(action2)\n\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(action1.completedResult).isNotNull()\n    assertThat(action2.completedResult).isNotNull()\n    assertThat(action2.completedResult).isNotEqualTo(action1.completedResult)\n  }\n\n  @Test fun performSubmitWithExistingRequestAttachesToHunter() {\n    val action1 = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    val action2 = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n\n    dispatcher.dispatchSubmit(action1)\n    dispatcher.dispatchSubmit(action2)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(action1.completedResult).isNotNull()\n    assertThat(action2.completedResult).isEqualTo(action1.completedResult)\n  }\n\n  @Test fun dispatchSubmitWithShutdownServiceIgnoresRequest() {\n    dispatcher.shutdown()\n\n    val action = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    dispatcher.dispatchSubmit(action)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(action.completedResult).isNull()\n  }\n\n  @Test fun dispatchSubmitWithFetchAction() {\n    val pausedTag = \"pausedTag\"\n    dispatcher.dispatchPauseTag(pausedTag)\n    testDispatcher.scheduler.runCurrent()\n    assertThat(dispatcher.pausedActions).isEmpty()\n\n    var completed = false\n    val fetchAction1 = noopAction(Request.Builder(TestUtils.URI_1).tag(pausedTag).build(), { completed = true })\n    val fetchAction2 = noopAction(Request.Builder(TestUtils.URI_1).tag(pausedTag).build(), { completed = true })\n    dispatcher.dispatchSubmit(fetchAction1)\n    dispatcher.dispatchSubmit(fetchAction2)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.pausedActions).hasSize(2)\n    assertThat(completed).isFalse()\n  }\n\n  @Test fun dispatchCancelWithFetchActionWithCallback() {\n    val pausedTag = \"pausedTag\"\n    dispatcher.dispatchPauseTag(pausedTag)\n    testDispatcher.scheduler.runCurrent()\n    assertThat(dispatcher.pausedActions).isEmpty()\n\n    val callback = TestUtils.mockCallback()\n\n    val fetchAction1 = FetchAction(picasso, Request.Builder(TestUtils.URI_1).tag(pausedTag).build(), callback)\n    dispatcher.dispatchSubmit(fetchAction1)\n    testDispatcher.scheduler.runCurrent()\n    assertThat(dispatcher.pausedActions).hasSize(1)\n\n    dispatcher.dispatchCancel(fetchAction1)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.pausedActions).isEmpty()\n  }\n\n  @Test fun dispatchCancelDetachesRequestAndCleansUp() {\n    val target = TestUtils.mockBitmapTarget()\n    val action = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1, target)\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action).apply {\n      job = Job()\n    }\n    dispatcher.hunterMap[TestUtils.URI_KEY_1 + Request.KEY_SEPARATOR] = hunter\n    dispatcher.failedActions[target] = action\n\n    dispatcher.dispatchCancel(action)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(hunter.job!!.isCancelled).isTrue()\n    assertThat(hunter.action).isNull()\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun dispatchCancelMultipleRequestsDetachesOnly() {\n    val action1 = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    val action2 = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action1)\n    hunter.attach(action2)\n    dispatcher.hunterMap[TestUtils.URI_KEY_1 + Request.KEY_SEPARATOR] = hunter\n\n    dispatcher.dispatchCancel(action1)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(hunter.action).isNull()\n    assertThat(hunter.actions).containsExactly(action2)\n    assertThat(dispatcher.hunterMap).hasSize(1)\n  }\n\n  @Test fun dispatchCancelUnqueuesAndDetachesPausedRequest() {\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget(),\n      tag = \"tag\"\n    )\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action)\n    dispatcher.dispatchSubmit(action)\n    dispatcher.dispatchPauseTag(\"tag\")\n    testDispatcher.scheduler.runCurrent()\n    dispatcher.hunterMap[TestUtils.URI_KEY_1 + Request.KEY_SEPARATOR] = hunter\n\n    dispatcher.dispatchCancel(action)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(hunter.action).isNull()\n    assertThat(dispatcher.pausedTags).containsExactly(\"tag\")\n    assertThat(dispatcher.pausedActions).isEmpty()\n  }\n\n  @Test fun dispatchCompleteSetsResultInCache() {\n    val data = Request.Builder(TestUtils.URI_1).build()\n    val action = noopAction(data)\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action)\n    hunter.run()\n    assertThat(cache.size()).isEqualTo(0)\n\n    dispatcher.dispatchComplete(hunter)\n    testDispatcher.scheduler.runCurrent()\n\n    val result = hunter.result as Bitmap\n    assertThat(result.bitmap).isEqualTo(bitmap1)\n    assertThat(result.loadedFrom).isEqualTo(NETWORK)\n    assertThat(cache[hunter.key]).isSameInstanceAs(bitmap1)\n  }\n\n  @Test fun dispatchCompleteWithNoStoreMemoryPolicy() {\n    val data = Request.Builder(TestUtils.URI_1).memoryPolicy(NO_STORE).build()\n    val action = noopAction(data)\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action)\n    hunter.run()\n    assertThat(cache.size()).isEqualTo(0)\n\n    dispatcher.dispatchComplete(hunter)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(cache.size()).isEqualTo(0)\n  }\n\n  @Test fun dispatchCompleteCleansUpAndPostsToMain() {\n    val data = Request.Builder(TestUtils.URI_1).build()\n    var completed = false\n    val action = noopAction(data, onComplete = { completed = true })\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action)\n    hunter.run()\n\n    dispatcher.dispatchComplete(hunter)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(completed).isTrue()\n  }\n\n  @Test fun dispatchCompleteCleansUpAndDoesNotPostToMainIfCancelled() {\n    val data = Request.Builder(TestUtils.URI_1).build()\n    var completed = false\n    val action = noopAction(data, onComplete = { completed = true })\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action)\n    hunter.run()\n    hunter.job = Job().apply { cancel() }\n\n    dispatcher.dispatchComplete(hunter)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(completed).isFalse()\n  }\n\n  @Test fun dispatchErrorCleansUpAndPostsToMain() {\n    val exception = RuntimeException()\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget(),\n      tag = \"tag\"\n    )\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action, exception)\n    hunter.run()\n    dispatcher.hunterMap[hunter.key] = hunter\n\n    dispatcher.dispatchFailed(hunter)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(action.errorException).isEqualTo(exception)\n  }\n\n  @Test fun dispatchErrorCleansUpAndDoesNotPostToMainIfCancelled() {\n    val exception = RuntimeException()\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget(),\n      tag = \"tag\"\n    )\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action, exception)\n    hunter.run()\n    hunter.job = Job().apply { cancel() }\n    dispatcher.hunterMap[hunter.key] = hunter\n\n    dispatcher.dispatchFailed(hunter)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(action.errorException).isNull()\n  }\n\n  @Test fun dispatchRetrySkipsIfHunterIsCancelled() {\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget(),\n      tag = \"tag\"\n    )\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action)\n    hunter.job = Job().apply { cancel() }\n\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(hunter.isCancelled).isTrue()\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun dispatchRetryForContentLengthResetsNetworkPolicy() {\n    val networkInfo = TestUtils.mockNetworkInfo(true)\n    Mockito.`when`(connectivityManager.activeNetworkInfo).thenReturn(networkInfo)\n    val action = TestUtils.mockAction(picasso, TestUtils.URI_KEY_2, TestUtils.URI_2)\n    val e = ContentLengthException(\"304 error\")\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action, e, true)\n    hunter.run()\n\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.advanceUntilIdle()\n\n    assertThat(NetworkPolicy.shouldReadFromDiskCache(hunter.data.networkPolicy)).isFalse()\n  }\n\n  @Test fun dispatchRetryDoesNotMarkForReplayIfNotSupported() {\n    val networkInfo = TestUtils.mockNetworkInfo(true)\n    val hunter = TestUtils.mockHunter(\n      picasso,\n      Bitmap(bitmap1, MEMORY),\n      TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    )\n    Mockito.`when`(connectivityManager.activeNetworkInfo).thenReturn(networkInfo)\n\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.advanceUntilIdle()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun dispatchRetryDoesNotMarkForReplayIfNoNetworkScanning() {\n    val hunter = TestUtils.mockHunter(\n      picasso,\n      Bitmap(bitmap1, MEMORY),\n      TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1),\n      e = null,\n      shouldRetry = false,\n      supportsReplay = true\n    )\n    val dispatcher = createDispatcher(false)\n\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.advanceUntilIdle()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun dispatchRetryMarksForReplayIfSupportedScansNetworkChangesAndShouldNotRetry() {\n    val networkInfo = TestUtils.mockNetworkInfo(true)\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget()\n    )\n    val hunter = TestUtils.mockHunter(\n      picasso,\n      Bitmap(bitmap1, MEMORY),\n      action,\n      e = null,\n      shouldRetry = false,\n      supportsReplay = true\n    )\n    Mockito.`when`(connectivityManager.activeNetworkInfo).thenReturn(networkInfo)\n\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.advanceUntilIdle()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).hasSize(1)\n    assertThat(action.willReplay).isTrue()\n  }\n\n  @Test fun dispatchRetryRetriesIfNoNetworkScanning() {\n    val dispatcher = createDispatcher(false)\n    val action = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    val hunter = TestUtils.mockHunter(\n      picasso,\n      Bitmap(bitmap1, MEMORY),\n      action,\n      e = null,\n      shouldRetry = true,\n      dispatcher = dispatcher\n    )\n\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.advanceUntilIdle()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n    assertThat(action.completedResult).isInstanceOf(Bitmap::class.java)\n  }\n\n  @Test fun dispatchRetryMarksForReplayIfSupportsReplayAndShouldNotRetry() {\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget()\n    )\n    val hunter = TestUtils.mockHunter(\n      picasso,\n      Bitmap(bitmap1, MEMORY),\n      action,\n      e = null,\n      shouldRetry = false,\n      supportsReplay = true\n    )\n\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.advanceUntilIdle()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).hasSize(1)\n    assertThat(action.willReplay).isTrue()\n  }\n\n  @Test fun dispatchRetryRetriesIfShouldRetry() {\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget()\n    )\n    val hunter = TestUtils.mockHunter(\n      picasso,\n      Bitmap(bitmap1, MEMORY),\n      action,\n      e = null,\n      shouldRetry = true,\n      dispatcher = dispatcher\n    )\n\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.advanceUntilIdle()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n    assertThat(action.completedResult).isInstanceOf(Bitmap::class.java)\n  }\n\n  @Test fun dispatchRetrySkipIfServiceShutdown() {\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget()\n    )\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action)\n\n    dispatcher.shutdown()\n    dispatcher.dispatchRetry(hunter)\n    testDispatcher.scheduler.advanceUntilIdle()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.failedActions).isEmpty()\n    assertThat(action.completedResult).isNull()\n  }\n\n  @Test fun dispatchAirplaneModeChange() {\n    assertThat(dispatcher.airplaneMode).isFalse()\n\n    dispatcher.dispatchAirplaneModeChange(true)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.airplaneMode).isTrue()\n\n    dispatcher.dispatchAirplaneModeChange(false)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.airplaneMode).isFalse()\n  }\n\n  @Test fun dispatchNetworkStateChangeWithDisconnectedInfoIgnores() {\n    val info = TestUtils.mockNetworkInfo()\n    Mockito.`when`(info.isConnectedOrConnecting).thenReturn(false)\n\n    dispatcher.dispatchNetworkStateChange(info)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun dispatchNetworkStateChangeWithConnectedInfoDifferentInstanceIgnores() {\n    val info = TestUtils.mockNetworkInfo(true)\n\n    dispatcher.dispatchNetworkStateChange(info)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun dispatchPauseAndResumeUpdatesListOfPausedTags() {\n    dispatcher.dispatchPauseTag(\"tag\")\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.pausedTags).containsExactly(\"tag\")\n\n    dispatcher.dispatchResumeTag(\"tag\")\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.pausedTags).isEmpty()\n  }\n\n  @Test fun dispatchPauseTagIsIdempotent() {\n    val action = TestUtils.mockAction(\n      picasso,\n      TestUtils.URI_KEY_1,\n      TestUtils.URI_1,\n      TestUtils.mockBitmapTarget(),\n      tag = \"tag\"\n    )\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action)\n    dispatcher.hunterMap[TestUtils.URI_KEY_1] = hunter\n    assertThat(dispatcher.pausedActions).isEmpty()\n\n    dispatcher.dispatchPauseTag(\"tag\")\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.pausedActions).containsEntry(action.getTarget(), action)\n\n    dispatcher.dispatchPauseTag(\"tag\")\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.pausedActions).containsEntry(action.getTarget(), action)\n  }\n\n  @Test fun dispatchPauseTagQueuesNewRequestDoesNotComplete() {\n    dispatcher.dispatchPauseTag(\"tag\")\n    val action = TestUtils.mockAction(\n      picasso = picasso,\n      key = TestUtils.URI_KEY_1,\n      uri = TestUtils.URI_1,\n      tag = \"tag\"\n    )\n\n    dispatcher.dispatchSubmit(action)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.pausedActions).hasSize(1)\n    assertThat(dispatcher.pausedActions.containsValue(action)).isTrue()\n    assertThat(action.completedResult).isNull()\n  }\n\n  @Test fun dispatchPauseTagDoesNotQueueUnrelatedRequest() {\n    dispatcher.dispatchPauseTag(\"tag\")\n    testDispatcher.scheduler.runCurrent()\n\n    val action = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1, \"anothertag\")\n    dispatcher.dispatchSubmit(action)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.pausedActions).isEmpty()\n    assertThat(action.completedResult).isNotNull()\n  }\n\n  @Test fun dispatchPauseDetachesRequestAndCancelsHunter() {\n    val action = TestUtils.mockAction(\n      picasso = picasso,\n      key = TestUtils.URI_KEY_1,\n      uri = TestUtils.URI_1,\n      tag = \"tag\"\n    )\n    val hunter = TestUtils.mockHunter(\n      picasso = picasso,\n      result = Bitmap(bitmap1, MEMORY),\n      action = action,\n      dispatcher = dispatcher\n    )\n    hunter.job = Job()\n\n    dispatcher.hunterMap[TestUtils.URI_KEY_1] = hunter\n    dispatcher.dispatchPauseTag(\"tag\")\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.hunterMap).isEmpty()\n    assertThat(dispatcher.pausedActions).hasSize(1)\n    assertThat(dispatcher.pausedActions.containsValue(action)).isTrue()\n    assertThat(hunter.action).isNull()\n    assertThat(action.completedResult).isNull()\n  }\n\n  @Test fun dispatchPauseOnlyDetachesPausedRequest() {\n    val action1 = TestUtils.mockAction(\n      picasso = picasso,\n      key = TestUtils.URI_KEY_1,\n      uri = TestUtils.URI_1,\n      target = TestUtils.mockBitmapTarget(),\n      tag = \"tag1\"\n    )\n    val action2 = TestUtils.mockAction(\n      picasso = picasso,\n      key = TestUtils.URI_KEY_1,\n      uri = TestUtils.URI_1,\n      target = TestUtils.mockBitmapTarget(),\n      tag = \"tag2\"\n    )\n    val hunter = TestUtils.mockHunter(picasso, Bitmap(bitmap1, MEMORY), action1)\n    hunter.attach(action2)\n    dispatcher.hunterMap[TestUtils.URI_KEY_1] = hunter\n\n    dispatcher.dispatchPauseTag(\"tag1\")\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(dispatcher.hunterMap).hasSize(1)\n    assertThat(dispatcher.hunterMap.containsValue(hunter)).isTrue()\n    assertThat(dispatcher.pausedActions).hasSize(1)\n    assertThat(dispatcher.pausedActions.containsValue(action1)).isTrue()\n    assertThat(hunter.action).isNull()\n    assertThat(hunter.actions).containsExactly(action2)\n  }\n\n  @Test fun dispatchResumeTagIsIdempotent() {\n    var completedCount = 0\n    val action = noopAction(Builder(TestUtils.URI_1).tag(\"tag\").build(), { completedCount++ })\n\n    dispatcher.dispatchPauseTag(\"tag\")\n    dispatcher.dispatchSubmit(action)\n    dispatcher.dispatchResumeTag(\"tag\")\n    dispatcher.dispatchResumeTag(\"tag\")\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(completedCount).isEqualTo(1)\n  }\n\n  @Test fun dispatchNetworkStateChangeFlushesFailedHunters() {\n    val info = TestUtils.mockNetworkInfo(true)\n    val failedAction1 = TestUtils.mockAction(picasso, TestUtils.URI_KEY_1, TestUtils.URI_1)\n    val failedAction2 = TestUtils.mockAction(picasso, TestUtils.URI_KEY_2, TestUtils.URI_2)\n    dispatcher.failedActions[TestUtils.URI_KEY_1] = failedAction1\n    dispatcher.failedActions[TestUtils.URI_KEY_2] = failedAction2\n\n    dispatcher.dispatchNetworkStateChange(info)\n    testDispatcher.scheduler.runCurrent()\n\n    assertThat(failedAction1.completedResult).isNotNull()\n    assertThat(failedAction2.completedResult).isNotNull()\n    assertThat(dispatcher.failedActions).isEmpty()\n  }\n\n  @Test fun syncCancelWithMainBeforeHunting() {\n    val mainDispatcher = StandardTestDispatcher()\n    val dispatcher = createDispatcher(mainContext = mainDispatcher)\n\n    var completed = false\n    val action = noopAction(Request.Builder(TestUtils.URI_1).build()) { completed = true }\n\n    // Submit action, will be gated by main\n    dispatcher.dispatchSubmit(action)\n    testDispatcher.scheduler.runCurrent()\n    assertThat(dispatcher.hunterMap[action.request.key]).isNotNull()\n\n    // Cancel action, detaches from hunter but hunter is queued to be submitted\n    dispatcher.dispatchCancel(action)\n    testDispatcher.scheduler.runCurrent()\n    assertThat(dispatcher.hunterMap[action.request.key]).isNotNull()\n    assertThat(dispatcher.hunterMap[action.request.key]?.action).isNull()\n\n    // Run main, syncs Dispatcher with main\n    mainDispatcher.scheduler.runCurrent()\n    // Dispatches the submitted hunter to run\n    testDispatcher.scheduler.runCurrent()\n\n    // It isn't hanging around\n    assertThat(dispatcher.hunterMap[action.request.key]).isNull()\n\n    // The action is not completed because the hunter never ran\n    mainDispatcher.scheduler.runCurrent()\n    assertThat(completed).isFalse()\n  }\n\n  @Test fun doesntSyncWithMainIfHighPriorityRequestBeforeHunting() {\n    val mainDispatcher = StandardTestDispatcher()\n    val dispatcher = createDispatcher(mainContext = mainDispatcher)\n\n    var completed = false\n    val action = noopAction(Request.Builder(TestUtils.URI_1).priority(HIGH).build()) { completed = true }\n    // Submit action\n    dispatcher.dispatchSubmit(action)\n    testDispatcher.scheduler.runCurrent()\n    assertThat(dispatcher.hunterMap[action.request.key]).isNull()\n\n    // Deliver result to main\n    mainDispatcher.scheduler.runCurrent()\n    assertThat(completed).isTrue()\n  }\n\n  private fun createDispatcher(\n    scansNetworkChanges: Boolean = true,\n    mainContext: CoroutineContext? = null,\n    backgroundContext: CoroutineContext? = null\n  ): InternalCoroutineDispatcher {\n    Mockito.`when`(connectivityManager.activeNetworkInfo).thenReturn(\n      if (scansNetworkChanges) Mockito.mock(NetworkInfo::class.java) else null\n    )\n    Mockito.`when`(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(connectivityManager)\n    Mockito.`when`(context.checkCallingOrSelfPermission(ArgumentMatchers.anyString())).thenReturn(\n      if (scansNetworkChanges) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED\n    )\n\n    testDispatcher = StandardTestDispatcher()\n    picasso = TestUtils.mockPicasso(context).newBuilder().dispatchers(mainContext ?: testDispatcher, testDispatcher).build()\n    return InternalCoroutineDispatcher(\n      context = context,\n      mainThreadHandler = Handler(Looper.getMainLooper()),\n      cache = cache,\n      mainContext = mainContext ?: testDispatcher,\n      backgroundContext = backgroundContext ?: testDispatcher\n    )\n  }\n\n  private fun noopAction(data: Request, onComplete: () -> Unit = { }): Action {\n    return object : Action(picasso, data) {\n      override fun complete(result: RequestHandler.Result) = onComplete()\n      override fun error(e: Exception) = Unit\n      override fun getTarget(): Any = this\n    }\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/MediaStoreRequestHandlerTest.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.MediaStoreRequestHandler.Companion.getPicassoKind\nimport com.squareup.picasso3.MediaStoreRequestHandler.PicassoKind.FULL\nimport com.squareup.picasso3.MediaStoreRequestHandler.PicassoKind.MICRO\nimport com.squareup.picasso3.MediaStoreRequestHandler.PicassoKind.MINI\nimport com.squareup.picasso3.RequestHandler.Callback\nimport com.squareup.picasso3.Shadows.ShadowImageThumbnails\nimport com.squareup.picasso3.Shadows.ShadowVideoThumbnails\nimport com.squareup.picasso3.TestUtils.MEDIA_STORE_CONTENT_1_URL\nimport com.squareup.picasso3.TestUtils.MEDIA_STORE_CONTENT_2_URL\nimport com.squareup.picasso3.TestUtils.MEDIA_STORE_CONTENT_KEY_1\nimport com.squareup.picasso3.TestUtils.MEDIA_STORE_CONTENT_KEY_2\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.mockAction\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport org.junit.Assert.fail\nimport org.junit.Before\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.robolectric.Robolectric\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\nimport org.robolectric.Shadows.shadowOf\nimport org.robolectric.annotation.Config\n\n@RunWith(RobolectricTestRunner::class)\n@Config(shadows = [ShadowVideoThumbnails::class, ShadowImageThumbnails::class])\nclass MediaStoreRequestHandlerTest {\n  private lateinit var context: Context\n  private lateinit var picasso: Picasso\n\n  @Before fun setUp() {\n    context = RuntimeEnvironment.getApplication().applicationContext\n    picasso = mockPicasso(context)\n    Robolectric.setupContentProvider(TestContentProvider::class.java, \"media\")\n  }\n\n  @Test fun decodesVideoThumbnailWithVideoMimeType() {\n    val bitmap = makeBitmap()\n    val request = Request.Builder(\n      uri = MEDIA_STORE_CONTENT_2_URL,\n      resourceId = 0,\n      bitmapConfig = ARGB_8888\n    )\n      .stableKey(MEDIA_STORE_CONTENT_KEY_2)\n      .resize(100, 100)\n      .build()\n    val action = mockAction(picasso, request)\n    val requestHandler = MediaStoreRequestHandler(context)\n    requestHandler.load(\n      picasso = picasso,\n      request = action.request,\n      callback = object : Callback {\n        override fun onSuccess(result: RequestHandler.Result?) =\n          assertBitmapsEqual((result as RequestHandler.Result.Bitmap?)!!.bitmap, bitmap)\n\n        override fun onError(t: Throwable) = fail(t.message)\n      }\n    )\n  }\n\n  @Test fun decodesImageThumbnailWithImageMimeType() {\n    val bitmap = makeBitmap(20, 20)\n    val request = Request.Builder(\n      uri = MEDIA_STORE_CONTENT_1_URL,\n      resourceId = 0,\n      bitmapConfig = ARGB_8888\n    )\n      .stableKey(MEDIA_STORE_CONTENT_KEY_1)\n      .resize(100, 100)\n      .build()\n    val action = mockAction(picasso, request)\n    val requestHandler = MediaStoreRequestHandler(context)\n    requestHandler.load(\n      picasso = picasso,\n      request = action.request,\n      callback = object : Callback {\n        override fun onSuccess(result: RequestHandler.Result?) =\n          assertBitmapsEqual((result as RequestHandler.Result.Bitmap?)!!.bitmap, bitmap)\n\n        override fun onError(t: Throwable) = fail(t.message)\n      }\n    )\n  }\n\n  @Test fun getPicassoKindMicro() {\n    assertThat(getPicassoKind(96, 96)).isEqualTo(MICRO)\n    assertThat(getPicassoKind(95, 95)).isEqualTo(MICRO)\n  }\n\n  @Test fun getPicassoKindMini() {\n    assertThat(getPicassoKind(512, 384)).isEqualTo(MINI)\n    assertThat(getPicassoKind(100, 100)).isEqualTo(MINI)\n  }\n\n  @Test fun getPicassoKindFull() {\n    assertThat(getPicassoKind(513, 385)).isEqualTo(FULL)\n    assertThat(getPicassoKind(1000, 1000)).isEqualTo(FULL)\n    assertThat(getPicassoKind(1000, 384)).isEqualTo(FULL)\n    assertThat(getPicassoKind(1000, 96)).isEqualTo(FULL)\n    assertThat(getPicassoKind(96, 1000)).isEqualTo(FULL)\n  }\n\n  private fun assertBitmapsEqual(a: Bitmap, b: Bitmap) {\n    assertThat(a.height).isEqualTo(b.height)\n    assertThat(a.width).isEqualTo(b.width)\n    assertThat(shadowOf(a).description).isEqualTo(shadowOf(b).description)\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/MemoryPolicyTest.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.MemoryPolicy.NO_CACHE\nimport com.squareup.picasso3.MemoryPolicy.NO_STORE\nimport org.junit.Test\n\nclass MemoryPolicyTest {\n\n  @Test fun dontReadFromMemoryCache() {\n    var memoryPolicy = 0\n    memoryPolicy = memoryPolicy or NO_CACHE.index\n    assertThat(MemoryPolicy.shouldReadFromMemoryCache(memoryPolicy)).isFalse()\n  }\n\n  @Test fun readFromMemoryCache() {\n    var memoryPolicy = 0\n    memoryPolicy = memoryPolicy or NO_STORE.index\n    assertThat(MemoryPolicy.shouldReadFromMemoryCache(memoryPolicy)).isTrue()\n  }\n\n  @Test fun dontWriteToMemoryCache() {\n    var memoryPolicy = 0\n    memoryPolicy = memoryPolicy or NO_STORE.index\n    assertThat(MemoryPolicy.shouldWriteToMemoryCache(memoryPolicy)).isFalse()\n  }\n\n  @Test fun writeToMemoryCache() {\n    var memoryPolicy = 0\n    memoryPolicy = memoryPolicy or NO_CACHE.index\n    assertThat(MemoryPolicy.shouldWriteToMemoryCache(memoryPolicy)).isTrue()\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/NetworkRequestHandlerTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.RequestHandler.Result\nimport com.squareup.picasso3.TestUtils.CUSTOM_HEADER_NAME\nimport com.squareup.picasso3.TestUtils.CUSTOM_HEADER_VALUE\nimport com.squareup.picasso3.TestUtils.EventRecorder\nimport com.squareup.picasso3.TestUtils.PremadeCall\nimport com.squareup.picasso3.TestUtils.URI_1\nimport com.squareup.picasso3.TestUtils.URI_KEY_1\nimport com.squareup.picasso3.TestUtils.mockNetworkInfo\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport okhttp3.CacheControl\nimport okhttp3.MediaType\nimport okhttp3.Protocol.HTTP_1_1\nimport okhttp3.Response\nimport okhttp3.ResponseBody\nimport okhttp3.ResponseBody.Companion.toResponseBody\nimport okio.Buffer\nimport okio.BufferedSource\nimport org.junit.Assert.assertTrue\nimport org.junit.Before\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.Mock\nimport org.mockito.Mockito.`when`\nimport org.mockito.MockitoAnnotations.initMocks\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\nimport java.util.concurrent.CountDownLatch\nimport java.util.concurrent.LinkedBlockingDeque\nimport java.util.concurrent.TimeUnit.SECONDS\nimport java.util.concurrent.atomic.AtomicBoolean\n\n@RunWith(RobolectricTestRunner::class)\nclass NetworkRequestHandlerTest {\n  private val responses = LinkedBlockingDeque<Response>()\n  private val requests = LinkedBlockingDeque<okhttp3.Request>()\n\n  @Mock internal lateinit var dispatcher: Dispatcher\n  private lateinit var picasso: Picasso\n  private lateinit var networkHandler: NetworkRequestHandler\n\n  @Before fun setUp() {\n    initMocks(this)\n    picasso = mockPicasso(RuntimeEnvironment.application)\n    networkHandler = NetworkRequestHandler { request ->\n      requests.add(request)\n      try {\n        PremadeCall(request, responses.takeFirst())\n      } catch (e: InterruptedException) {\n        throw AssertionError(e)\n      }\n    }\n  }\n\n  @Test fun doesNotForceLocalCacheOnlyWithAirplaneModeOffAndRetryCount() {\n    responses.add(responseOf(ByteArray(10).toResponseBody(null)))\n    val action = TestUtils.mockAction(picasso, URI_KEY_1, URI_1)\n    val latch = CountDownLatch(1)\n    networkHandler.load(\n      picasso = picasso,\n      request = action.request,\n      callback = object : RequestHandler.Callback {\n        override fun onSuccess(result: Result?) {\n          try {\n            assertThat(requests.takeFirst().cacheControl.toString()).isEmpty()\n            latch.countDown()\n          } catch (e: InterruptedException) {\n            throw AssertionError(e)\n          }\n        }\n\n        override fun onError(t: Throwable): Unit = throw AssertionError(t)\n      }\n    )\n    assertThat(latch.await(10, SECONDS)).isTrue()\n  }\n\n  @Test fun withZeroRetryCountForcesLocalCacheOnly() {\n    responses.add(responseOf(ByteArray(10).toResponseBody(null)))\n    val action = TestUtils.mockAction(picasso, URI_KEY_1, URI_1)\n    val cache = PlatformLruCache(0)\n    val hunter = BitmapHunter(picasso, dispatcher, cache, action, networkHandler)\n    hunter.retryCount = 0\n    hunter.hunt()\n    assertThat(requests.takeFirst().cacheControl.toString())\n      .isEqualTo(CacheControl.FORCE_CACHE.toString())\n  }\n\n  @Test fun shouldRetryTwiceWithAirplaneModeOffAndNoNetworkInfo() {\n    val action = TestUtils.mockAction(picasso, URI_KEY_1, URI_1)\n    val cache = PlatformLruCache(0)\n    val hunter = BitmapHunter(picasso, dispatcher, cache, action, networkHandler)\n    assertThat(hunter.shouldRetry(airplaneMode = false, info = null)).isTrue()\n    assertThat(hunter.shouldRetry(airplaneMode = false, info = null)).isTrue()\n    assertThat(hunter.shouldRetry(airplaneMode = false, info = null)).isFalse()\n  }\n\n  @Test fun shouldRetryWithUnknownNetworkInfo() {\n    assertThat(networkHandler.shouldRetry(airplaneMode = false, info = null)).isTrue()\n    assertThat(networkHandler.shouldRetry(airplaneMode = true, info = null)).isTrue()\n  }\n\n  @Test fun shouldRetryWithConnectedNetworkInfo() {\n    val info = mockNetworkInfo()\n    `when`(info.isConnected).thenReturn(true)\n    assertThat(networkHandler.shouldRetry(airplaneMode = false, info = info)).isTrue()\n    assertThat(networkHandler.shouldRetry(airplaneMode = true, info = info)).isTrue()\n  }\n\n  @Test fun shouldNotRetryWithDisconnectedNetworkInfo() {\n    val info = mockNetworkInfo()\n    `when`(info.isConnectedOrConnecting).thenReturn(false)\n    assertThat(networkHandler.shouldRetry(airplaneMode = false, info = info)).isFalse()\n    assertThat(networkHandler.shouldRetry(airplaneMode = true, info = info)).isFalse()\n  }\n\n  @Test fun noCacheAndKnownContentLengthDispatchToStats() {\n    val eventRecorder = EventRecorder()\n    val picasso = picasso.newBuilder().addEventListener(eventRecorder).build()\n    val knownContentLengthSize = 10\n    responses.add(responseOf(ByteArray(knownContentLengthSize).toResponseBody(null)))\n    val action = TestUtils.mockAction(picasso, URI_KEY_1, URI_1)\n    val latch = CountDownLatch(1)\n    networkHandler.load(\n      picasso = picasso,\n      request = action.request,\n      callback = object : RequestHandler.Callback {\n        override fun onSuccess(result: Result?) {\n          assertThat(eventRecorder.downloadSize).isEqualTo(knownContentLengthSize)\n          latch.countDown()\n        }\n\n        override fun onError(t: Throwable): Unit = throw AssertionError(t)\n      }\n    )\n    assertThat(latch.await(10, SECONDS)).isTrue()\n  }\n\n  @Test fun unknownContentLengthFromDiskThrows() {\n    val eventRecorder = EventRecorder()\n    val picasso = picasso.newBuilder().addEventListener(eventRecorder).build()\n    val closed = AtomicBoolean()\n    val body = object : ResponseBody() {\n      override fun contentType(): MediaType? = null\n      override fun contentLength(): Long = 0\n      override fun source(): BufferedSource = Buffer()\n      override fun close() {\n        closed.set(true)\n        super.close()\n      }\n    }\n    responses += responseOf(body)\n      .newBuilder()\n      .cacheResponse(responseOf(null))\n      .build()\n    val action = TestUtils.mockAction(picasso, URI_KEY_1, URI_1)\n    val latch = CountDownLatch(1)\n    networkHandler.load(\n      picasso = picasso,\n      request = action.request,\n      callback = object : RequestHandler.Callback {\n        override fun onSuccess(result: Result?): Unit = throw AssertionError()\n\n        override fun onError(t: Throwable) {\n          assertThat(eventRecorder.downloadSize).isEqualTo(0)\n          assertTrue(closed.get())\n          latch.countDown()\n        }\n      }\n    )\n    assertThat(latch.await(10, SECONDS)).isTrue()\n  }\n\n  @Test fun cachedResponseDoesNotDispatchToStats() {\n    val eventRecorder = EventRecorder()\n    val picasso = picasso.newBuilder().addEventListener(eventRecorder).build()\n    responses += responseOf(ByteArray(10).toResponseBody(null))\n      .newBuilder()\n      .cacheResponse(responseOf(null))\n      .build()\n    val action = TestUtils.mockAction(picasso, URI_KEY_1, URI_1)\n    val latch = CountDownLatch(1)\n    networkHandler.load(\n      picasso = picasso,\n      request = action.request,\n      callback = object : RequestHandler.Callback {\n        override fun onSuccess(result: Result?) {\n          assertThat(eventRecorder.downloadSize).isEqualTo(0)\n          latch.countDown()\n        }\n\n        override fun onError(t: Throwable): Unit = throw AssertionError(t)\n      }\n    )\n    assertThat(latch.await(10, SECONDS)).isTrue()\n  }\n\n  @Test fun customHeaders() {\n    responses += responseOf(ByteArray(10).toResponseBody(null))\n      .newBuilder()\n      .cacheResponse(responseOf(null))\n      .build()\n    val action = TestUtils.mockAction(\n      picasso,\n      key = URI_KEY_1,\n      uri = URI_1,\n      headers = mapOf(CUSTOM_HEADER_NAME to CUSTOM_HEADER_VALUE)\n    )\n    val latch = CountDownLatch(1)\n    networkHandler.load(\n      picasso = picasso,\n      request = action.request,\n      callback = object : RequestHandler.Callback {\n        override fun onSuccess(result: Result?) {\n          with(requests.first.headers) {\n            assertThat(names()).containsExactly(CUSTOM_HEADER_NAME)\n            assertThat(values(CUSTOM_HEADER_NAME)).containsExactly(CUSTOM_HEADER_VALUE)\n          }\n          latch.countDown()\n        }\n\n        override fun onError(t: Throwable): Unit = throw AssertionError(t)\n      }\n    )\n    assertThat(latch.await(10, SECONDS)).isTrue()\n  }\n\n  @Test fun shouldHandleSchemeInsensitiveCase() {\n    val schemes = arrayOf(\"http\", \"https\", \"HTTP\", \"HTTPS\", \"HTtP\")\n    for (scheme in schemes) {\n      val uri = URI_1.buildUpon().scheme(scheme).build()\n      assertThat(networkHandler.canHandleRequest(TestUtils.mockRequest(uri))).isTrue()\n    }\n  }\n\n  private fun responseOf(body: ResponseBody?) =\n    Response.Builder()\n      .code(200)\n      .protocol(HTTP_1_1)\n      .request(okhttp3.Request.Builder().url(\"http://example.com\").build())\n      .message(\"OK\")\n      .body(body)\n      .build()\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/PicassoTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.Context\nimport android.graphics.Bitmap.Config.ALPHA_8\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport android.net.Uri\nimport android.widget.RemoteViews\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.Picasso.Listener\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Picasso.LoadedFrom.NETWORK\nimport com.squareup.picasso3.RemoteViewsAction.RemoteViewsTarget\nimport com.squareup.picasso3.RequestHandler.Result\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport com.squareup.picasso3.TestUtils.EventRecorder\nimport com.squareup.picasso3.TestUtils.FakeAction\nimport com.squareup.picasso3.TestUtils.NO_HANDLERS\nimport com.squareup.picasso3.TestUtils.NO_TRANSFORMERS\nimport com.squareup.picasso3.TestUtils.UNUSED_CALL_FACTORY\nimport com.squareup.picasso3.TestUtils.URI_1\nimport com.squareup.picasso3.TestUtils.URI_KEY_1\nimport com.squareup.picasso3.TestUtils.defaultPicasso\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.mockAction\nimport com.squareup.picasso3.TestUtils.mockBitmapTarget\nimport com.squareup.picasso3.TestUtils.mockDeferredRequestCreator\nimport com.squareup.picasso3.TestUtils.mockDrawableTarget\nimport com.squareup.picasso3.TestUtils.mockHunter\nimport com.squareup.picasso3.TestUtils.mockImageViewTarget\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport com.squareup.picasso3.TestUtils.mockRequestCreator\nimport org.junit.Assert.fail\nimport org.junit.Before\nimport org.junit.Rule\nimport org.junit.Test\nimport org.junit.rules.TemporaryFolder\nimport org.junit.runner.RunWith\nimport org.mockito.Mock\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.never\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.verifyNoInteractions\nimport org.mockito.MockitoAnnotations.initMocks\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\nimport java.io.File\n\n@RunWith(RobolectricTestRunner::class)\nclass PicassoTest {\n  @get:Rule\n  val temporaryFolder = TemporaryFolder()\n\n  @Mock internal lateinit var context: Context\n\n  @Mock internal lateinit var dispatcher: Dispatcher\n\n  @Mock internal lateinit var requestHandler: RequestHandler\n\n  @Mock internal lateinit var listener: Listener\n\n  private val cache = PlatformLruCache(2048)\n  private val eventRecorder = EventRecorder()\n  private val bitmap = makeBitmap()\n\n  private lateinit var picasso: Picasso\n\n  @Before fun setUp() {\n    initMocks(this)\n    picasso = Picasso(\n      context = context,\n      dispatcher = dispatcher,\n      callFactory = UNUSED_CALL_FACTORY,\n      closeableCache = null,\n      cache = cache,\n      listener = listener,\n      requestTransformers = NO_TRANSFORMERS,\n      extraRequestHandlers = NO_HANDLERS,\n      eventListeners = listOf(eventRecorder),\n      defaultBitmapConfig = ARGB_8888,\n      indicatorsEnabled = false,\n      isLoggingEnabled = false\n    )\n  }\n\n  @Test fun submitWithTargetInvokesDispatcher() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    assertThat(picasso.targetToAction).isEmpty()\n    picasso.enqueueAndSubmit(action)\n    assertThat(picasso.targetToAction).hasSize(1)\n    verify(dispatcher).dispatchSubmit(action)\n  }\n\n  @Test fun submitWithSameActionDoesNotCancel() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    picasso.enqueueAndSubmit(action)\n    verify(dispatcher).dispatchSubmit(action)\n    assertThat(picasso.targetToAction).hasSize(1)\n    assertThat(picasso.targetToAction.containsValue(action)).isTrue()\n    picasso.enqueueAndSubmit(action)\n    assertThat(action.cancelled).isFalse()\n    verify(dispatcher, never()).dispatchCancel(action)\n  }\n\n  @Test fun quickMemoryCheckReturnsBitmapIfInCache() {\n    cache[URI_KEY_1] = bitmap\n    val cached = picasso.quickMemoryCacheCheck(URI_KEY_1)\n    assertThat(cached).isEqualTo(bitmap)\n    assertThat(eventRecorder.cacheHits).isGreaterThan(0)\n  }\n\n  @Test fun quickMemoryCheckReturnsNullIfNotInCache() {\n    val cached = picasso.quickMemoryCacheCheck(URI_KEY_1)\n    assertThat(cached).isNull()\n    assertThat(eventRecorder.cacheMisses).isGreaterThan(0)\n  }\n\n  @Test fun completeInvokesSuccessOnAllSuccessfulRequests() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap, MEMORY), action1)\n    val action2 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    hunter.attach(action2)\n    action2.cancelled = true\n\n    hunter.run()\n    picasso.complete(hunter)\n\n    verifyActionComplete(action1)\n    assertThat(action2.completedResult).isNull()\n  }\n\n  @Test fun completeInvokesErrorOnAllFailedRequests() {\n    val action1 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val exception = mock(Exception::class.java)\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap, MEMORY), action1, exception)\n    val action2 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    hunter.attach(action2)\n    action2.cancelled = true\n    hunter.run()\n    picasso.complete(hunter)\n\n    assertThat(action1.errorException).hasCauseThat().isEqualTo(exception)\n    assertThat(action2.errorException).isNull()\n    verify(listener).onImageLoadFailed(picasso, URI_1, action1.errorException!!)\n  }\n\n  @Test fun completeInvokesErrorOnFailedResourceRequests() {\n    val action = mockAction(\n      picasso = picasso,\n      key = URI_KEY_1,\n      uri = null,\n      resourceId = 123,\n      target = mockImageViewTarget()\n    )\n    val exception = mock(Exception::class.java)\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap, MEMORY), action, exception)\n    hunter.run()\n    picasso.complete(hunter)\n\n    assertThat(action.errorException).hasCauseThat().isEqualTo(exception)\n    verify(listener).onImageLoadFailed(picasso, null, action.errorException!!)\n  }\n\n  @Test fun completeDeliversToSingle() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap, MEMORY), action)\n    hunter.run()\n    picasso.complete(hunter)\n\n    verifyActionComplete(action)\n  }\n\n  @Test fun completeWithReplayDoesNotRemove() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    action.willReplay = true\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap, MEMORY), action)\n    hunter.run()\n    picasso.enqueueAndSubmit(action)\n    assertThat(picasso.targetToAction).hasSize(1)\n    picasso.complete(hunter)\n    assertThat(picasso.targetToAction).hasSize(1)\n\n    verifyActionComplete(action)\n  }\n\n  @Test fun completeDeliversToSingleAndMultiple() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val action2 = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap, MEMORY), action)\n    hunter.attach(action2)\n    hunter.run()\n    picasso.complete(hunter)\n\n    verifyActionComplete(action)\n    verifyActionComplete(action2)\n  }\n\n  @Test fun completeSkipsIfNoActions() {\n    val action = mockAction(picasso, URI_KEY_1, URI_1, mockImageViewTarget())\n    val hunter = mockHunter(picasso, RequestHandler.Result.Bitmap(bitmap, MEMORY), action)\n    hunter.detach(action)\n    hunter.run()\n    picasso.complete(hunter)\n\n    assertThat(hunter.action).isNull()\n    assertThat(hunter.actions).isNull()\n  }\n\n  @Test fun resumeActionTriggersSubmitOnPausedAction() {\n    val request = Request.Builder(URI_1, 0, ARGB_8888).build()\n    val action = object : Action(mockPicasso(RuntimeEnvironment.application), request) {\n      override fun complete(result: Result) = fail(\"Test execution should not call this method\")\n      override fun error(e: Exception) = fail(\"Test execution should not call this method\")\n      override fun getTarget(): Any = this\n    }\n    picasso.resumeAction(action)\n    verify(dispatcher).dispatchSubmit(action)\n  }\n\n  @Test fun resumeActionImmediatelyCompletesCachedRequest() {\n    cache[URI_KEY_1] = bitmap\n    val request = Request.Builder(URI_1, 0, ARGB_8888).build()\n    val action = object : Action(mockPicasso(RuntimeEnvironment.application), request) {\n      override fun complete(result: Result) {\n        assertThat(result).isInstanceOf(Bitmap::class.java)\n        val bitmapResult = result as Bitmap\n        assertThat(bitmapResult.bitmap).isEqualTo(bitmap)\n        assertThat(bitmapResult.loadedFrom).isEqualTo(MEMORY)\n      }\n\n      override fun error(e: Exception) =\n        fail(\"Reading from memory cache should not throw an exception\")\n\n      override fun getTarget(): Any = this\n    }\n\n    picasso.resumeAction(action)\n  }\n\n  @Test fun cancelExistingRequestWithUnknownTarget() {\n    val target = mockImageViewTarget()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, target)\n    assertThat(action.cancelled).isFalse()\n    picasso.cancelRequest(target)\n    assertThat(action.cancelled).isFalse()\n    verifyNoInteractions(dispatcher)\n  }\n\n  @Test fun cancelExistingRequestWithImageViewTarget() {\n    val target = mockImageViewTarget()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, target)\n    picasso.enqueueAndSubmit(action)\n    assertThat(picasso.targetToAction).hasSize(1)\n    assertThat(action.cancelled).isFalse()\n    picasso.cancelRequest(target)\n    assertThat(picasso.targetToAction).isEmpty()\n    assertThat(action.cancelled).isTrue()\n    verify(dispatcher).dispatchCancel(action)\n  }\n\n  @Test fun cancelExistingRequestWithDeferredImageViewTarget() {\n    val target = mockImageViewTarget()\n    val creator = mockRequestCreator(picasso)\n    val deferredRequestCreator = mockDeferredRequestCreator(creator, target)\n    picasso.targetToDeferredRequestCreator[target] = deferredRequestCreator\n    picasso.cancelRequest(target)\n    verify(target).removeOnAttachStateChangeListener(deferredRequestCreator)\n    assertThat(picasso.targetToDeferredRequestCreator).isEmpty()\n  }\n\n  @Test fun enqueueingDeferredRequestCancelsThePreviousOne() {\n    val target = mockImageViewTarget()\n    val creator = mockRequestCreator(picasso)\n    val firstRequestCreator = mockDeferredRequestCreator(creator, target)\n    picasso.defer(target, firstRequestCreator)\n    assertThat(picasso.targetToDeferredRequestCreator).containsKey(target)\n\n    val secondRequestCreator = mockDeferredRequestCreator(creator, target)\n    picasso.defer(target, secondRequestCreator)\n    verify(target).removeOnAttachStateChangeListener(firstRequestCreator)\n    assertThat(picasso.targetToDeferredRequestCreator).containsKey(target)\n  }\n\n  @Test fun cancelExistingRequestWithBitmapTarget() {\n    val target = mockBitmapTarget()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, target)\n    picasso.enqueueAndSubmit(action)\n    assertThat(picasso.targetToAction).hasSize(1)\n    assertThat(action.cancelled).isFalse()\n    picasso.cancelRequest(target)\n    assertThat(picasso.targetToAction).isEmpty()\n    assertThat(action.cancelled).isTrue()\n    verify(dispatcher).dispatchCancel(action)\n  }\n\n  @Test fun cancelExistingRequestWithDrawableTarget() {\n    val target = mockDrawableTarget()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, target)\n    picasso.enqueueAndSubmit(action)\n    assertThat(picasso.targetToAction).hasSize(1)\n    assertThat(action.cancelled).isFalse()\n    picasso.cancelRequest(target)\n    assertThat(picasso.targetToAction).isEmpty()\n    assertThat(action.cancelled).isTrue()\n    verify(dispatcher).dispatchCancel(action)\n  }\n\n  @Test fun cancelExistingRequestWithRemoteViewTarget() {\n    val layoutId = 0\n    val viewId = 1\n    val remoteViews = RemoteViews(\"com.squareup.picasso3.test\", layoutId)\n    val target = RemoteViewsTarget(remoteViews, viewId)\n    val action = mockAction(picasso, URI_KEY_1, URI_1, target)\n    picasso.enqueueAndSubmit(action)\n    assertThat(picasso.targetToAction).hasSize(1)\n    assertThat(action.cancelled).isFalse()\n    picasso.cancelRequest(remoteViews, viewId)\n    assertThat(picasso.targetToAction).isEmpty()\n    assertThat(action.cancelled).isTrue()\n    verify(dispatcher).dispatchCancel(action)\n  }\n\n  @Test fun cancelTagAllActions() {\n    val target = mockImageViewTarget()\n    val action = mockAction(picasso, URI_KEY_1, URI_1, target, tag = \"TAG\")\n    picasso.enqueueAndSubmit(action)\n    assertThat(picasso.targetToAction).hasSize(1)\n    assertThat(action.cancelled).isFalse()\n    picasso.cancelTag(\"TAG\")\n    assertThat(picasso.targetToAction).isEmpty()\n    assertThat(action.cancelled).isTrue()\n  }\n\n  @Test fun cancelTagAllDeferredRequests() {\n    val target = mockImageViewTarget()\n    val creator = mockRequestCreator(picasso).tag(\"TAG\")\n    val deferredRequestCreator = mockDeferredRequestCreator(creator, target)\n    picasso.defer(target, deferredRequestCreator)\n    picasso.cancelTag(\"TAG\")\n    verify(target).removeOnAttachStateChangeListener(deferredRequestCreator)\n  }\n\n  @Test fun deferAddsToMap() {\n    val target = mockImageViewTarget()\n    val creator = mockRequestCreator(picasso)\n    val deferredRequestCreator = mockDeferredRequestCreator(creator, target)\n    assertThat(picasso.targetToDeferredRequestCreator).isEmpty()\n    picasso.defer(target, deferredRequestCreator)\n    assertThat(picasso.targetToDeferredRequestCreator).hasSize(1)\n  }\n\n  @Test fun shutdown() {\n    cache[\"key\"] = makeBitmap(1, 1)\n    assertThat(cache.size()).isEqualTo(1)\n    picasso.shutdown()\n    assertThat(cache.size()).isEqualTo(0)\n    assertThat(eventRecorder.closed).isTrue()\n    verify(dispatcher).shutdown()\n    assertThat(picasso.shutdown).isTrue()\n  }\n\n  @Test fun shutdownClosesUnsharedCache() {\n    val cache = okhttp3.Cache(temporaryFolder.root, 100)\n    val picasso = Picasso(\n      context, dispatcher, UNUSED_CALL_FACTORY, cache, this.cache, listener,\n      NO_TRANSFORMERS, NO_HANDLERS, listOf(eventRecorder),\n      defaultBitmapConfig = ARGB_8888, indicatorsEnabled = false, isLoggingEnabled = false\n    )\n    picasso.shutdown()\n    assertThat(cache.isClosed).isTrue()\n  }\n\n  @Test fun shutdownTwice() {\n    cache[\"key\"] = makeBitmap(1, 1)\n    assertThat(cache.size()).isEqualTo(1)\n    picasso.shutdown()\n    picasso.shutdown()\n    assertThat(cache.size()).isEqualTo(0)\n    assertThat(eventRecorder.closed).isTrue()\n    verify(dispatcher).shutdown()\n    assertThat(picasso.shutdown).isTrue()\n  }\n\n  @Test fun shutdownClearsTargetsToActions() {\n    picasso.targetToAction[mockImageViewTarget()] = mock(ImageViewAction::class.java)\n    picasso.shutdown()\n    assertThat(picasso.targetToAction).isEmpty()\n  }\n\n  @Test fun shutdownClearsDeferredRequests() {\n    val target = mockImageViewTarget()\n    val creator = mockRequestCreator(picasso)\n    val deferredRequestCreator = mockDeferredRequestCreator(creator, target)\n    picasso.targetToDeferredRequestCreator[target] = deferredRequestCreator\n    picasso.shutdown()\n    verify(target).removeOnAttachStateChangeListener(deferredRequestCreator)\n    assertThat(picasso.targetToDeferredRequestCreator).isEmpty()\n  }\n\n  @Test fun loadThrowsWithInvalidInput() {\n    try {\n      picasso.load(\"\")\n      fail(\"Empty URL should throw exception.\")\n    } catch (expected: IllegalArgumentException) {\n    }\n    try {\n      picasso.load(\"      \")\n      fail(\"Empty URL should throw exception.\")\n    } catch (expected: IllegalArgumentException) {\n    }\n    try {\n      picasso.load(0)\n      fail(\"Zero resourceId should throw exception.\")\n    } catch (expected: IllegalArgumentException) {\n    }\n  }\n\n  @Test fun builderInvalidCache() {\n    try {\n      Picasso.Builder(RuntimeEnvironment.application).withCacheSize(-1)\n      fail()\n    } catch (expected: IllegalArgumentException) {\n      assertThat(expected).hasMessageThat().isEqualTo(\"maxByteCount < 0: -1\")\n    }\n  }\n\n  @Test fun builderWithoutRequestHandler() {\n    val picasso = Picasso.Builder(RuntimeEnvironment.application).build()\n    assertThat(picasso.requestHandlers).isNotEmpty()\n    assertThat(picasso.requestHandlers).doesNotContain(requestHandler)\n  }\n\n  @Test fun builderWithRequestHandler() {\n    val picasso = Picasso.Builder(RuntimeEnvironment.application)\n      .addRequestHandler(requestHandler)\n      .build()\n    assertThat(picasso.requestHandlers).isNotNull()\n    assertThat(picasso.requestHandlers).isNotEmpty()\n    assertThat(picasso.requestHandlers).contains(requestHandler)\n  }\n\n  @Test fun builderWithDebugIndicators() {\n    val picasso = Picasso.Builder(RuntimeEnvironment.application).indicatorsEnabled(true).build()\n    assertThat(picasso.indicatorsEnabled).isTrue()\n  }\n\n  @Test fun evictAll() {\n    val picasso = Picasso.Builder(RuntimeEnvironment.application).indicatorsEnabled(true).build()\n    picasso.cache[\"key\"] = android.graphics.Bitmap.createBitmap(1, 1, ALPHA_8)\n    assertThat(picasso.cache.size()).isEqualTo(1)\n    picasso.evictAll()\n    assertThat(picasso.cache.size()).isEqualTo(0)\n  }\n\n  @Test fun invalidateString() {\n    val request = Request.Builder(Uri.parse(\"https://example.com\")).build()\n    cache[request.key] = makeBitmap(1, 1)\n    assertThat(cache.size()).isEqualTo(1)\n    picasso.invalidate(\"https://example.com\")\n    assertThat(cache.size()).isEqualTo(0)\n  }\n\n  @Test fun invalidateFile() {\n    val request = Request.Builder(Uri.fromFile(File(\"/foo/bar/baz\"))).build()\n    cache[request.key] = makeBitmap(1, 1)\n    assertThat(cache.size()).isEqualTo(1)\n    picasso.invalidate(File(\"/foo/bar/baz\"))\n    assertThat(cache.size()).isEqualTo(0)\n  }\n\n  @Test fun invalidateUri() {\n    val request = Request.Builder(URI_1).build()\n    cache[request.key] = makeBitmap(1, 1)\n    assertThat(cache.size()).isEqualTo(1)\n    picasso.invalidate(URI_1)\n    assertThat(cache.size()).isEqualTo(0)\n  }\n\n  @Test fun clonedRequestHandlersAreIndependent() {\n    val original = defaultPicasso(RuntimeEnvironment.application, false, false)\n\n    original.newBuilder()\n      .addRequestTransformer(TestUtils.NOOP_TRANSFORMER)\n      .addRequestHandler(TestUtils.NOOP_REQUEST_HANDLER)\n      .build()\n\n    assertThat(original.requestTransformers).hasSize(NUM_BUILTIN_TRANSFORMERS)\n    assertThat(original.requestHandlers).hasSize(NUM_BUILTIN_HANDLERS)\n  }\n\n  @Test fun cloneSharesStatefulInstances() {\n    val parent = defaultPicasso(RuntimeEnvironment.application, true, true)\n\n    val child = parent.newBuilder().build()\n\n    assertThat(child.context).isEqualTo(parent.context)\n    assertThat(child.callFactory).isEqualTo(parent.callFactory)\n    assertThat((child.dispatcher as HandlerDispatcher).service).isEqualTo((parent.dispatcher as HandlerDispatcher).service)\n    assertThat(child.cache).isEqualTo(parent.cache)\n    assertThat(child.listener).isEqualTo(parent.listener)\n    assertThat(child.requestTransformers).isEqualTo(parent.requestTransformers)\n\n    assertThat(child.requestHandlers).hasSize(parent.requestHandlers.size)\n    child.requestHandlers.forEachIndexed { index, it ->\n      assertThat(it).isInstanceOf(parent.requestHandlers[index].javaClass)\n    }\n\n    assertThat(child.defaultBitmapConfig).isEqualTo(parent.defaultBitmapConfig)\n    assertThat(child.indicatorsEnabled).isEqualTo(parent.indicatorsEnabled)\n    assertThat(child.isLoggingEnabled).isEqualTo(parent.isLoggingEnabled)\n\n    assertThat(child.targetToAction).isEqualTo(parent.targetToAction)\n    assertThat(child.targetToDeferredRequestCreator).isEqualTo(\n      parent.targetToDeferredRequestCreator\n    )\n  }\n\n  @Test fun cloneSharesCoroutineDispatchers() {\n    val parent =\n      defaultPicasso(RuntimeEnvironment.application, true, true)\n        .newBuilder()\n        .dispatchers()\n        .build()\n    val child = parent.newBuilder().build()\n\n    val parentDispatcher = parent.dispatcher as InternalCoroutineDispatcher\n    val childDispatcher = child.dispatcher as InternalCoroutineDispatcher\n    assertThat(childDispatcher.mainContext).isEqualTo(parentDispatcher.mainContext)\n    assertThat(childDispatcher.backgroundContext).isEqualTo(parentDispatcher.backgroundContext)\n  }\n\n  private fun verifyActionComplete(action: FakeAction) {\n    val result = action.completedResult\n    assertThat(result).isNotNull()\n    assertThat(result).isInstanceOf(RequestHandler.Result.Bitmap::class.java)\n    val bitmapResult = result as RequestHandler.Result.Bitmap\n    assertThat(bitmapResult.bitmap).isEqualTo(bitmap)\n    assertThat(bitmapResult.loadedFrom).isEqualTo(NETWORK)\n  }\n\n  companion object {\n    private const val NUM_BUILTIN_HANDLERS = 8\n    private const val NUM_BUILTIN_TRANSFORMERS = 0\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/RemoteViewsActionTest.kt",
    "content": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport android.widget.RemoteViews\nimport androidx.annotation.DrawableRes\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.Picasso.LoadedFrom.NETWORK\nimport com.squareup.picasso3.RemoteViewsAction.RemoteViewsTarget\nimport com.squareup.picasso3.TestUtils.NO_EVENT_LISTENERS\nimport com.squareup.picasso3.TestUtils.NO_HANDLERS\nimport com.squareup.picasso3.TestUtils.NO_TRANSFORMERS\nimport com.squareup.picasso3.TestUtils.SIMPLE_REQUEST\nimport com.squareup.picasso3.TestUtils.UNUSED_CALL_FACTORY\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.mockCallback\nimport com.squareup.picasso3.TestUtils.mockImageViewTarget\nimport org.junit.Before\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.verifyNoInteractions\nimport org.mockito.Mockito.`when`\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\n\n@RunWith(RobolectricTestRunner::class)\nclass RemoteViewsActionTest {\n  private lateinit var picasso: Picasso\n  private lateinit var remoteViews: RemoteViews\n\n  @Before fun setUp() {\n    picasso = Picasso(\n      context = RuntimeEnvironment.application,\n      dispatcher = mock(Dispatcher::class.java),\n      callFactory = UNUSED_CALL_FACTORY,\n      closeableCache = null,\n      cache = PlatformLruCache(0),\n      listener = null,\n      requestTransformers = NO_TRANSFORMERS,\n      extraRequestHandlers = NO_HANDLERS,\n      eventListeners = NO_EVENT_LISTENERS,\n      defaultBitmapConfig = ARGB_8888,\n      indicatorsEnabled = false,\n      isLoggingEnabled = false\n    )\n    remoteViews = mock(RemoteViews::class.java)\n    `when`(remoteViews.layoutId).thenReturn(android.R.layout.list_content)\n  }\n\n  @Test fun completeSetsBitmapOnRemoteViews() {\n    val callback = mockCallback()\n    val bitmap = makeBitmap()\n    val action = createAction(callback)\n    action.complete(RequestHandler.Result.Bitmap(bitmap, NETWORK))\n    verify(remoteViews).setImageViewBitmap(1, bitmap)\n    verify(callback).onSuccess()\n  }\n\n  @Test fun errorWithNoResourceIsNoop() {\n    val callback = mockCallback()\n    val action = createAction(callback)\n    val e = RuntimeException()\n    action.error(e)\n    verifyNoInteractions(remoteViews)\n    verify(callback).onError(e)\n  }\n\n  @Test fun errorWithResourceSetsResource() {\n    val callback = mockCallback()\n    val action = createAction(callback, 1)\n    val e = RuntimeException()\n    action.error(e)\n    verify(remoteViews).setImageViewResource(1, 1)\n    verify(callback).onError(e)\n  }\n\n  @Test fun clearsCallbackOnCancel() {\n    val request = ImageViewAction(\n      picasso = picasso,\n      target = mockImageViewTarget(),\n      data = SIMPLE_REQUEST,\n      errorDrawable = null,\n      errorResId = 0,\n      noFade = false,\n      callback = mockCallback()\n    )\n    request.cancel()\n    assertThat(request.callback).isNull()\n  }\n\n  private fun createAction(callback: Callback, errorResId: Int = 0): TestableRemoteViewsAction {\n    return TestableRemoteViewsAction(\n      picasso = picasso,\n      data = SIMPLE_REQUEST,\n      errorResId = errorResId,\n      target = RemoteViewsTarget(remoteViews, 1),\n      callback = callback\n    )\n  }\n\n  private class TestableRemoteViewsAction(\n    picasso: Picasso,\n    data: Request,\n    @DrawableRes errorResId: Int,\n    target: RemoteViewsTarget,\n    callback: Callback?\n  ) : RemoteViewsAction(picasso, data, errorResId, target, callback) {\n    override fun update() {}\n    override fun getTarget(): Any = target\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/RequestCreatorTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport android.graphics.drawable.ColorDrawable\nimport android.graphics.drawable.Drawable\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.MemoryPolicy.NO_CACHE\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Picasso.Priority.HIGH\nimport com.squareup.picasso3.Picasso.Priority.LOW\nimport com.squareup.picasso3.Picasso.Priority.NORMAL\nimport com.squareup.picasso3.RemoteViewsAction.AppWidgetAction\nimport com.squareup.picasso3.RemoteViewsAction.NotificationAction\nimport com.squareup.picasso3.TestUtils.CUSTOM_HEADER_NAME\nimport com.squareup.picasso3.TestUtils.CUSTOM_HEADER_VALUE\nimport com.squareup.picasso3.TestUtils.NO_EVENT_LISTENERS\nimport com.squareup.picasso3.TestUtils.NO_HANDLERS\nimport com.squareup.picasso3.TestUtils.NO_TRANSFORMERS\nimport com.squareup.picasso3.TestUtils.STABLE_1\nimport com.squareup.picasso3.TestUtils.STABLE_URI_KEY_1\nimport com.squareup.picasso3.TestUtils.UNUSED_CALL_FACTORY\nimport com.squareup.picasso3.TestUtils.URI_1\nimport com.squareup.picasso3.TestUtils.URI_KEY_1\nimport com.squareup.picasso3.TestUtils.any\nimport com.squareup.picasso3.TestUtils.argumentCaptor\nimport com.squareup.picasso3.TestUtils.eq\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport com.squareup.picasso3.TestUtils.mockBitmapTarget\nimport com.squareup.picasso3.TestUtils.mockCallback\nimport com.squareup.picasso3.TestUtils.mockDrawableTarget\nimport com.squareup.picasso3.TestUtils.mockFitImageViewTarget\nimport com.squareup.picasso3.TestUtils.mockImageViewTarget\nimport com.squareup.picasso3.TestUtils.mockNotification\nimport com.squareup.picasso3.TestUtils.mockPicasso\nimport com.squareup.picasso3.TestUtils.mockRemoteViews\nimport com.squareup.picasso3.TestUtils.mockRequestCreator\nimport org.junit.Assert.fail\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.mockito.ArgumentCaptor\nimport org.mockito.ArgumentMatchers.anyString\nimport org.mockito.Mockito.doCallRealMethod\nimport org.mockito.Mockito.doReturn\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.never\nimport org.mockito.Mockito.spy\nimport org.mockito.Mockito.verify\nimport org.mockito.Mockito.verifyNoMoreInteractions\nimport org.mockito.Mockito.`when`\nimport org.robolectric.RobolectricTestRunner\nimport org.robolectric.RuntimeEnvironment\nimport org.robolectric.Shadows.shadowOf\nimport java.io.IOException\nimport java.util.concurrent.CountDownLatch\n\n@RunWith(RobolectricTestRunner::class)\nclass RequestCreatorTest {\n  private val actionCaptor = argumentCaptor<Action>()\n  private val picasso = spy(mockPicasso(RuntimeEnvironment.application))\n  private val bitmap = makeBitmap()\n\n  @Test fun getOnMainCrashes() {\n    try {\n      RequestCreator(picasso, URI_1, 0).get()\n      fail(\"Calling get() on main thread should throw exception\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun loadWithShutdownCrashes() {\n    picasso.shutdown = true\n    try {\n      RequestCreator(picasso, URI_1, 0).fetch()\n      fail(\"Should have crashed with a shutdown picasso.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun getReturnsNullIfNullUriAndResourceId() {\n    val latch = CountDownLatch(1)\n    val result = arrayOfNulls<Bitmap>(1)\n    Thread {\n      try {\n        result[0] = RequestCreator(picasso, null, 0).get()\n      } catch (e: IOException) {\n        fail(e.message)\n      } finally {\n        latch.countDown()\n      }\n    }.start()\n    latch.await()\n\n    assertThat(result[0]).isNull()\n    verify(picasso).defaultBitmapConfig\n    verify(picasso).shutdown\n    verifyNoMoreInteractions(picasso)\n  }\n\n  @Test fun fetchSubmitsFetchRequest() {\n    RequestCreator(picasso, URI_1, 0).fetch()\n    verify(picasso).submit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(FetchAction::class.java)\n  }\n\n  @Test fun fetchWithFitThrows() {\n    try {\n      RequestCreator(picasso, URI_1, 0).fit().fetch()\n      fail(\"Calling fetch() with fit() should throw an exception\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun fetchWithDefaultPriority() {\n    RequestCreator(picasso, URI_1, 0).fetch()\n    verify(picasso).submit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(LOW)\n  }\n\n  @Test fun fetchWithCustomPriority() {\n    RequestCreator(picasso, URI_1, 0).priority(HIGH).fetch()\n    verify(picasso).submit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(HIGH)\n  }\n\n  @Test fun fetchWithCache() {\n    `when`(picasso.quickMemoryCacheCheck(URI_KEY_1)).thenReturn(bitmap)\n    RequestCreator(picasso, URI_1, 0).memoryPolicy(NO_CACHE).fetch()\n    verify(picasso, never()).enqueueAndSubmit(any(Action::class.java))\n  }\n\n  @Test fun fetchWithMemoryPolicyNoCache() {\n    RequestCreator(picasso, URI_1, 0).memoryPolicy(NO_CACHE).fetch()\n    verify(picasso, never()).quickMemoryCacheCheck(URI_KEY_1)\n    verify(picasso).submit(actionCaptor.capture())\n  }\n\n  @Test fun intoTargetWithFitThrows() {\n    try {\n      RequestCreator(picasso, URI_1, 0).fit().into(mockBitmapTarget())\n      fail(\"Calling into() target with fit() should throw exception\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun intoTargetNoPlaceholderCallsWithNull() {\n    val target = mockBitmapTarget()\n    RequestCreator(picasso, URI_1, 0).noPlaceholder().into(target)\n    verify(target).onPrepareLoad(null)\n  }\n\n  @Test fun intoTargetWithNullUriAndResourceIdSkipsAndCancels() {\n    val target = mockBitmapTarget()\n    val placeHolderDrawable = mock(Drawable::class.java)\n    RequestCreator(picasso, null, 0).placeholder(placeHolderDrawable).into(target)\n    verify(picasso).defaultBitmapConfig\n    verify(picasso).shutdown\n    verify(picasso).cancelRequest(target)\n    verify(target).onPrepareLoad(placeHolderDrawable)\n    verifyNoMoreInteractions(picasso)\n  }\n\n  @Test fun intoTargetWithQuickMemoryCacheCheckDoesNotSubmit() {\n    `when`(picasso.quickMemoryCacheCheck(URI_KEY_1)).thenReturn(bitmap)\n    val target = mockBitmapTarget()\n    RequestCreator(picasso, URI_1, 0).into(target)\n    verify(target).onBitmapLoaded(bitmap, MEMORY)\n    verify(picasso).cancelRequest(target)\n    verify(picasso, never()).enqueueAndSubmit(any(Action::class.java))\n  }\n\n  @Test fun intoTargetWithSkipMemoryPolicy() {\n    val target = mockBitmapTarget()\n    RequestCreator(picasso, URI_1, 0).memoryPolicy(NO_CACHE).into(target)\n    verify(picasso, never()).quickMemoryCacheCheck(URI_KEY_1)\n  }\n\n  @Test fun intoTargetAndNotInCacheSubmitsTargetRequest() {\n    val target = mockBitmapTarget()\n    val placeHolderDrawable = mock(Drawable::class.java)\n    RequestCreator(picasso, URI_1, 0).placeholder(placeHolderDrawable).into(target)\n    verify(target).onPrepareLoad(placeHolderDrawable)\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(BitmapTargetAction::class.java)\n  }\n\n  @Test fun targetActionWithDefaultPriority() {\n    RequestCreator(picasso, URI_1, 0).into(mockBitmapTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(NORMAL)\n  }\n\n  @Test fun targetActionWithCustomPriority() {\n    RequestCreator(picasso, URI_1, 0).priority(HIGH).into(mockBitmapTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(HIGH)\n  }\n\n  @Test fun targetActionWithDefaultTag() {\n    RequestCreator(picasso, URI_1, 0).into(mockBitmapTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.tag).isEqualTo(actionCaptor.value)\n  }\n\n  @Test fun targetActionWithCustomTag() {\n    RequestCreator(picasso, URI_1, 0).tag(\"tag\").into(mockBitmapTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.tag).isEqualTo(\"tag\")\n  }\n\n  @Test fun intoDrawableTargetWithFitThrows() {\n    try {\n      RequestCreator(picasso, URI_1, 0).fit().into(mockDrawableTarget())\n      fail(\"Calling into() drawable target with fit() should throw exception\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun intoDrawableTargetNoPlaceholderCallsWithNull() {\n    val target = mockDrawableTarget()\n    RequestCreator(picasso, URI_1, 0).noPlaceholder().into(target)\n    verify(target).onPrepareLoad(null)\n  }\n\n  @Test fun intoDrawableTargetWithNullUriAndResourceIdSkipsAndCancels() {\n    val target = mockDrawableTarget()\n    val placeHolderDrawable = mock(Drawable::class.java)\n    RequestCreator(picasso, null, 0).placeholder(placeHolderDrawable).into(target)\n    verify(picasso).defaultBitmapConfig\n    verify(picasso).shutdown\n    verify(picasso).cancelRequest(target)\n    verify(target).onPrepareLoad(placeHolderDrawable)\n    verifyNoMoreInteractions(picasso)\n  }\n\n  @Test fun intoDrawableTargetWithQuickMemoryCacheCheckDoesNotSubmit() {\n    `when`(picasso.quickMemoryCacheCheck(URI_KEY_1)).thenReturn(bitmap)\n    val target = mockDrawableTarget()\n    RequestCreator(picasso, URI_1, 0).into(target)\n    verify(target).onDrawableLoaded(any(PicassoDrawable::class.java), eq(MEMORY))\n    verify(picasso).cancelRequest(target)\n    verify(picasso, never()).enqueueAndSubmit(any(Action::class.java))\n  }\n\n  @Test fun intoDrawableTargetWithSkipMemoryPolicy() {\n    val target = mockDrawableTarget()\n    RequestCreator(picasso, URI_1, 0).memoryPolicy(NO_CACHE).into(target)\n    verify(picasso, never()).quickMemoryCacheCheck(URI_KEY_1)\n  }\n\n  @Test fun intoDrawableTargetAndNotInCacheSubmitsTargetRequest() {\n    val target = mockDrawableTarget()\n    val placeHolderDrawable = mock(Drawable::class.java)\n    RequestCreator(picasso, URI_1, 0).placeholder(placeHolderDrawable).into(target)\n    verify(target).onPrepareLoad(placeHolderDrawable)\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(DrawableTargetAction::class.java)\n  }\n\n  @Test fun intoImageViewWithNullUriAndResourceIdSkipsAndCancels() {\n    val target = mockImageViewTarget()\n    RequestCreator(picasso, null, 0).into(target)\n    verify(picasso).cancelRequest(target)\n    verify(picasso, never()).quickMemoryCacheCheck(anyString())\n    verify(picasso, never()).enqueueAndSubmit(any(Action::class.java))\n  }\n\n  @Test fun intoImageViewWithQuickMemoryCacheCheckDoesNotSubmit() {\n    val cache = PlatformLruCache(0)\n    val picasso = spy(\n      Picasso(\n        RuntimeEnvironment.application, mock(Dispatcher::class.java), UNUSED_CALL_FACTORY,\n        null, cache, null, NO_TRANSFORMERS, NO_HANDLERS, NO_EVENT_LISTENERS, ARGB_8888,\n        indicatorsEnabled = false, isLoggingEnabled = false\n      )\n    )\n    doReturn(bitmap).`when`(picasso).quickMemoryCacheCheck(URI_KEY_1)\n    val target = mockImageViewTarget()\n    val callback = mockCallback()\n    RequestCreator(picasso, URI_1, 0).into(target, callback)\n    verify(target).setImageDrawable(any(PicassoDrawable::class.java))\n    verify(callback).onSuccess()\n    verify(picasso).cancelRequest(target)\n    verify(picasso, never()).enqueueAndSubmit(any(Action::class.java))\n  }\n\n  @Test fun intoImageViewSetsPlaceholderDrawable() {\n    val cache = PlatformLruCache(0)\n    val picasso = spy(\n      Picasso(\n        RuntimeEnvironment.application, mock(Dispatcher::class.java), UNUSED_CALL_FACTORY,\n        null, cache, null, NO_TRANSFORMERS, NO_HANDLERS, NO_EVENT_LISTENERS, ARGB_8888,\n        false, false\n      )\n    )\n    val target = mockImageViewTarget()\n    val placeHolderDrawable = mock(Drawable::class.java)\n    RequestCreator(picasso, URI_1, 0).placeholder(placeHolderDrawable).into(target)\n    verify(target).setImageDrawable(placeHolderDrawable)\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(ImageViewAction::class.java)\n  }\n\n  @Test fun intoImageViewNoPlaceholderDrawable() {\n    val cache = PlatformLruCache(0)\n    val picasso = spy(\n      Picasso(\n        RuntimeEnvironment.application, mock(Dispatcher::class.java), UNUSED_CALL_FACTORY,\n        null, cache, null, NO_TRANSFORMERS, NO_HANDLERS, NO_EVENT_LISTENERS, ARGB_8888,\n        indicatorsEnabled = false, isLoggingEnabled = false\n      )\n    )\n    val target = mockImageViewTarget()\n    RequestCreator(picasso, URI_1, 0).noPlaceholder().into(target)\n    verifyNoMoreInteractions(target)\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(ImageViewAction::class.java)\n  }\n\n  @Test fun intoImageViewSetsPlaceholderWithResourceId() {\n    val cache = PlatformLruCache(0)\n    val picasso = spy(\n      Picasso(\n        RuntimeEnvironment.application, mock(Dispatcher::class.java), UNUSED_CALL_FACTORY,\n        null, cache, null, NO_TRANSFORMERS, NO_HANDLERS, NO_EVENT_LISTENERS, ARGB_8888,\n        indicatorsEnabled = false, isLoggingEnabled = false\n      )\n    )\n    val target = mockImageViewTarget()\n    RequestCreator(picasso, URI_1, 0).placeholder(android.R.drawable.picture_frame).into(target)\n    val drawableCaptor = ArgumentCaptor.forClass(Drawable::class.java)\n    verify(target).setImageDrawable(drawableCaptor.capture())\n    assertThat(shadowOf(drawableCaptor.value).createdFromResId)\n      .isEqualTo(android.R.drawable.picture_frame)\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(ImageViewAction::class.java)\n  }\n\n  @Test fun cancelNotOnMainThreadCrashes() {\n    doCallRealMethod().`when`(picasso).cancelRequest(any(BitmapTarget::class.java))\n    val latch = CountDownLatch(1)\n    Thread {\n      try {\n        RequestCreator(picasso, null, 0).into(mockBitmapTarget())\n        fail(\"Should have thrown IllegalStateException\")\n      } catch (ignored: IllegalStateException) {\n      } finally {\n        latch.countDown()\n      }\n    }.start()\n    latch.await()\n  }\n\n  @Test fun intoNotOnMainThreadCrashes() {\n    doCallRealMethod().`when`(picasso).enqueueAndSubmit(any(Action::class.java))\n    val latch = CountDownLatch(1)\n    Thread {\n      try {\n        RequestCreator(picasso, URI_1, 0).into(mockImageViewTarget())\n        fail(\"Should have thrown IllegalStateException\")\n      } catch (ignored: IllegalStateException) {\n      } finally {\n        latch.countDown()\n      }\n    }.start()\n    latch.await()\n  }\n\n  @Test fun intoImageViewAndNotInCacheSubmitsImageViewRequest() {\n    val target = mockImageViewTarget()\n    RequestCreator(picasso, URI_1, 0).into(target)\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(ImageViewAction::class.java)\n  }\n\n  @Test fun intoImageViewWithFitAndNoDimensionsQueuesDeferredImageViewRequest() {\n    val target = mockFitImageViewTarget(true)\n    `when`(target.width).thenReturn(0)\n    `when`(target.height).thenReturn(0)\n    RequestCreator(picasso, URI_1, 0).fit().into(target)\n    verify(picasso, never()).enqueueAndSubmit(any(Action::class.java))\n    verify(picasso).defer(eq(target), any(DeferredRequestCreator::class.java))\n  }\n\n  @Test fun intoImageViewWithFitAndDimensionsQueuesImageViewRequest() {\n    val target = mockFitImageViewTarget(true)\n    `when`(target.width).thenReturn(100)\n    `when`(target.height).thenReturn(100)\n    RequestCreator(picasso, URI_1, 0).fit().into(target)\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(ImageViewAction::class.java)\n  }\n\n  @Test fun intoImageViewWithSkipMemoryCachePolicy() {\n    val target = mockImageViewTarget()\n    RequestCreator(picasso, URI_1, 0).memoryPolicy(NO_CACHE).into(target)\n    verify(picasso, never()).quickMemoryCacheCheck(URI_KEY_1)\n  }\n\n  @Test fun intoImageViewWithFitAndResizeThrows() {\n    try {\n      val target = mockImageViewTarget()\n      RequestCreator(picasso, URI_1, 0).fit().resize(10, 10).into(target)\n      fail(\"Calling into() ImageView with fit() and resize() should throw exception\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun imageViewActionWithDefaultPriority() {\n    RequestCreator(picasso, URI_1, 0).into(mockImageViewTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(NORMAL)\n  }\n\n  @Test fun imageViewActionWithCustomPriority() {\n    RequestCreator(picasso, URI_1, 0).priority(HIGH).into(mockImageViewTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(HIGH)\n  }\n\n  @Test fun imageViewActionWithDefaultTag() {\n    RequestCreator(picasso, URI_1, 0).into(mockImageViewTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.tag).isEqualTo(actionCaptor.value)\n  }\n\n  @Test fun imageViewActionWithCustomTag() {\n    RequestCreator(picasso, URI_1, 0).tag(\"tag\").into(mockImageViewTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.tag).isEqualTo(\"tag\")\n  }\n\n  @Test fun intoRemoteViewsWidgetQueuesAppWidgetAction() {\n    RequestCreator(picasso, URI_1, 0).into(mockRemoteViews(), 0, intArrayOf(1, 2, 3))\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(AppWidgetAction::class.java)\n  }\n\n  @Test fun intoRemoteViewsNotificationQueuesNotificationAction() {\n    RequestCreator(picasso, URI_1, 0).into(mockRemoteViews(), 0, 0, mockNotification())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value).isInstanceOf(NotificationAction::class.java)\n  }\n\n  @Test fun intoRemoteViewsWidgetWithPlaceholderDrawableThrows() {\n    try {\n      RequestCreator(picasso, URI_1, 0).placeholder(ColorDrawable(0))\n        .into(mockRemoteViews(), 0, intArrayOf(1, 2, 3))\n      fail(\"Calling into() with placeholder drawable should throw exception\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n  }\n\n  @Test fun intoRemoteViewsWidgetWithErrorDrawableThrows() {\n    try {\n      RequestCreator(picasso, URI_1, 0).error(ColorDrawable(0))\n        .into(mockRemoteViews(), 0, intArrayOf(1, 2, 3))\n      fail(\"Calling into() with error drawable should throw exception\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n  }\n\n  @Test fun intoRemoteViewsNotificationWithPlaceholderDrawableThrows() {\n    try {\n      RequestCreator(picasso, URI_1, 0).placeholder(ColorDrawable(0))\n        .into(mockRemoteViews(), 0, 0, mockNotification())\n      fail(\"Calling into() with error drawable should throw exception\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n  }\n\n  @Test fun intoRemoteViewsNotificationWithErrorDrawableThrows() {\n    try {\n      RequestCreator(picasso, URI_1, 0).error(ColorDrawable(0))\n        .into(mockRemoteViews(), 0, 0, mockNotification())\n      fail(\"Calling into() with error drawable should throw exception\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n  }\n\n  @Test fun intoRemoteViewsWidgetWithFitThrows() {\n    try {\n      val remoteViews = mockRemoteViews()\n      RequestCreator(picasso, URI_1, 0).fit().into(remoteViews, 1, intArrayOf(1, 2, 3))\n      fail(\"Calling fit() into remote views should throw exception\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun intoRemoteViewsNotificationWithFitThrows() {\n    try {\n      val remoteViews = mockRemoteViews()\n      RequestCreator(picasso, URI_1, 0).fit().into(remoteViews, 1, 1, mockNotification())\n      fail(\"Calling fit() into remote views should throw exception\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun intoTargetNoResizeWithCenterInsideOrCenterCropThrows() {\n    try {\n      RequestCreator(picasso, URI_1, 0).centerInside().into(mockBitmapTarget())\n      fail(\"Center inside with unknown width should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n    try {\n      RequestCreator(picasso, URI_1, 0).centerCrop().into(mockBitmapTarget())\n      fail(\"Center inside with unknown height should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun appWidgetActionWithDefaultPriority() {\n    RequestCreator(picasso, URI_1, 0).into(mockRemoteViews(), 0, intArrayOf(1, 2, 3))\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(NORMAL)\n  }\n\n  @Test fun appWidgetActionWithCustomPriority() {\n    RequestCreator(picasso, URI_1, 0).priority(HIGH).into(mockRemoteViews(), 0, intArrayOf(1, 2, 3))\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(HIGH)\n  }\n\n  @Test fun notificationActionWithDefaultPriority() {\n    RequestCreator(picasso, URI_1, 0).into(mockRemoteViews(), 0, 0, mockNotification())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(NORMAL)\n  }\n\n  @Test fun notificationActionWithCustomPriority() {\n    RequestCreator(picasso, URI_1, 0).priority(HIGH)\n      .into(mockRemoteViews(), 0, 0, mockNotification())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.priority).isEqualTo(HIGH)\n  }\n\n  @Test fun appWidgetActionWithDefaultTag() {\n    RequestCreator(picasso, URI_1, 0).into(mockRemoteViews(), 0, intArrayOf(1, 2, 3))\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.tag).isEqualTo(actionCaptor.value)\n  }\n\n  @Test fun appWidgetActionWithCustomTag() {\n    RequestCreator(picasso, URI_1, 0).tag(\"tag\")\n      .into(remoteViews = mockRemoteViews(), viewId = 0, appWidgetIds = intArrayOf(1, 2, 3))\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.tag).isEqualTo(\"tag\")\n  }\n\n  @Test fun notificationActionWithDefaultTag() {\n    RequestCreator(picasso, URI_1, 0)\n      .into(\n        remoteViews = mockRemoteViews(),\n        viewId = 0,\n        notificationId = 0,\n        notification = mockNotification()\n      )\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.tag).isEqualTo(actionCaptor.value)\n  }\n\n  @Test fun notificationActionWithCustomTag() {\n    RequestCreator(picasso, URI_1, 0).tag(\"tag\")\n      .into(mockRemoteViews(), 0, 0, mockNotification())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.tag).isEqualTo(\"tag\")\n  }\n\n  @Test fun invalidResize() {\n    try {\n      mockRequestCreator(picasso).resize(-1, 10)\n      fail(\"Negative width should throw exception.\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n    try {\n      mockRequestCreator(picasso).resize(10, -1)\n      fail(\"Negative height should throw exception.\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n    try {\n      mockRequestCreator(picasso).resize(0, 0)\n      fail(\"Zero dimensions should throw exception.\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n  }\n\n  @Test fun invalidCenterCrop() {\n    try {\n      mockRequestCreator(picasso).resize(10, 10).centerInside().centerCrop()\n      fail(\"Calling center crop after center inside should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun invalidCenterInside() {\n    try {\n      mockRequestCreator(picasso).resize(10, 10).centerCrop().centerInside()\n      fail(\"Calling center inside after center crop should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun invalidPlaceholderImage() {\n    try {\n      mockRequestCreator(picasso).placeholder(0)\n      fail(\"Resource ID of zero should throw exception.\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n    try {\n      mockRequestCreator(picasso).placeholder(1).placeholder(ColorDrawable(0))\n      fail(\"Two placeholders should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n    try {\n      mockRequestCreator(picasso).placeholder(ColorDrawable(0)).placeholder(1)\n      fail(\"Two placeholders should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun invalidNoPlaceholder() {\n    try {\n      mockRequestCreator(picasso).noPlaceholder().placeholder(ColorDrawable(0))\n      fail(\"Placeholder after no placeholder should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n    try {\n      mockRequestCreator(picasso).noPlaceholder().placeholder(1)\n      fail(\"Placeholder after no placeholder should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n    try {\n      mockRequestCreator(picasso).placeholder(1).noPlaceholder()\n      fail(\"No placeholder after placeholder should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n    try {\n      mockRequestCreator(picasso).placeholder(ColorDrawable(0)).noPlaceholder()\n      fail(\"No placeholder after placeholder should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun invalidErrorImage() {\n    try {\n      mockRequestCreator(picasso).error(0)\n      fail(\"Resource ID of zero should throw exception.\")\n    } catch (ignored: IllegalArgumentException) {\n    }\n    try {\n      mockRequestCreator(picasso).error(1).error(ColorDrawable(0))\n      fail(\"Two error placeholders should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n    try {\n      mockRequestCreator(picasso).error(ColorDrawable(0)).error(1)\n      fail(\"Two error placeholders should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun invalidPriority() {\n    try {\n      mockRequestCreator(picasso).priority(LOW).priority(HIGH)\n      fail(\"Two priorities should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun alreadySetTagThrows() {\n    try {\n      mockRequestCreator(picasso).tag(\"tag1\").tag(\"tag2\")\n      fail(\"Two tags should throw exception.\")\n    } catch (ignored: IllegalStateException) {\n    }\n  }\n\n  @Test fun transformationListImplementationValid() {\n    val transformations = listOf(TestTransformation(\"test\"))\n    mockRequestCreator(picasso).transform(transformations)\n    // TODO verify something!\n  }\n\n  @Test fun imageViewActionWithStableKey() {\n    RequestCreator(picasso, URI_1, 0).stableKey(STABLE_1).into(mockImageViewTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.key).isEqualTo(STABLE_URI_KEY_1)\n  }\n\n  @Test fun imageViewActionWithCustomHeaders() {\n    RequestCreator(picasso, URI_1, 0)\n      .addHeader(CUSTOM_HEADER_NAME, CUSTOM_HEADER_VALUE)\n      .into(mockImageViewTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n    assertThat(actionCaptor.value.request.headers!![CUSTOM_HEADER_NAME])\n      .isEqualTo(CUSTOM_HEADER_VALUE)\n  }\n\n  @Test fun imageViewActionWithCustomHeadersCopiesHeaders() {\n    RequestCreator(picasso, URI_1, 0)\n      .addHeader(CUSTOM_HEADER_NAME, CUSTOM_HEADER_VALUE)\n      .into(mockImageViewTarget())\n    verify(picasso).enqueueAndSubmit(actionCaptor.capture())\n\n    val newRequest = actionCaptor.value.request.newBuilder().build()\n\n    assertThat(newRequest.headers!![CUSTOM_HEADER_NAME]).isEqualTo(CUSTOM_HEADER_VALUE)\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/Shadows.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.ContentResolver\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.provider.MediaStore\nimport com.squareup.picasso3.TestUtils.makeBitmap\nimport org.robolectric.annotation.Implementation\nimport org.robolectric.annotation.Implements\n\nobject Shadows {\n  @Implements(MediaStore.Video.Thumbnails::class)\n  object ShadowVideoThumbnails {\n    @Implementation\n    @JvmStatic\n    fun getThumbnail(\n      cr: ContentResolver,\n      origId: Long,\n      kind: Int,\n      options: BitmapFactory.Options\n    ): Bitmap = makeBitmap()\n  }\n\n  @Implements(MediaStore.Images.Thumbnails::class)\n  object ShadowImageThumbnails {\n    @Implementation\n    @JvmStatic\n    fun getThumbnail(\n      cr: ContentResolver,\n      origId: Long,\n      kind: Int,\n      options: BitmapFactory.Options\n    ): Bitmap = makeBitmap(20, 20)\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/TestContentProvider.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.content.ContentProvider\nimport android.content.ContentValues\nimport android.database.Cursor\nimport android.net.Uri\n\nclass TestContentProvider : ContentProvider() {\n  override fun onCreate(): Boolean = true\n\n  override fun query(\n    uri: Uri,\n    projection: Array<out String>?,\n    selection: String?,\n    selectionArgs: Array<out String>?,\n    sortOrder: String?\n  ): Cursor? = null\n\n  override fun getType(uri: Uri): String? {\n    val path = uri.path\n    return when {\n      path == null -> null\n      path.contains(\"video\") -> \"video/\"\n      path.contains(\"images\") -> \"image/png\"\n      else -> throw IllegalArgumentException()\n    }\n  }\n\n  override fun insert(\n    uri: Uri,\n    values: ContentValues?\n  ): Uri = TODO(\"Not yet implemented\")\n\n  override fun delete(\n    uri: Uri,\n    selection: String?,\n    selectionArgs: Array<out String>?\n  ): Int = TODO(\"Not yet implemented\")\n\n  override fun update(\n    uri: Uri,\n    values: ContentValues?,\n    selection: String?,\n    selectionArgs: Array<out String>?\n  ): Int = TODO(\"Not yet implemented\")\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/TestTransformation.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config.ARGB_8888\n\ninternal class TestTransformation(\n  private val key: String,\n  private val result: Bitmap? = Bitmap.createBitmap(10, 10, ARGB_8888)\n) : Transformation {\n  override fun transform(source: RequestHandler.Result.Bitmap): RequestHandler.Result.Bitmap {\n    val bitmap = source.bitmap\n    bitmap.recycle()\n    return RequestHandler.Result.Bitmap(result!!, source.loadedFrom, source.exifRotation)\n  }\n\n  override fun key(): String = key\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/TestUtils.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport android.app.Notification\nimport android.content.ContentResolver\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.content.pm.PackageManager.NameNotFoundException\nimport android.content.res.Resources\nimport android.graphics.Bitmap.Config.ALPHA_8\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport android.graphics.drawable.Drawable\nimport android.net.NetworkInfo\nimport android.net.Uri\nimport android.os.IBinder\nimport android.provider.ContactsContract.Contacts.CONTENT_URI\nimport android.provider.ContactsContract.Contacts.Photo\nimport android.provider.MediaStore.Images\nimport android.provider.MediaStore.Video\nimport android.util.TypedValue\nimport android.view.ViewTreeObserver\nimport android.widget.ImageView\nimport android.widget.RemoteViews\nimport com.squareup.picasso3.BitmapHunterTest.TestableBitmapHunter\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Picasso.Priority\nimport com.squareup.picasso3.Picasso.RequestTransformer\nimport com.squareup.picasso3.RequestHandler.Result\nimport com.squareup.picasso3.RequestHandler.Result.Bitmap\nimport okhttp3.Call\nimport okhttp3.Response\nimport okio.Timeout\nimport org.mockito.ArgumentCaptor\nimport org.mockito.ArgumentMatchers.anyBoolean\nimport org.mockito.ArgumentMatchers.anyInt\nimport org.mockito.Mockito\nimport org.mockito.Mockito.doAnswer\nimport org.mockito.Mockito.doReturn\nimport org.mockito.Mockito.mock\nimport org.mockito.Mockito.`when`\nimport org.mockito.invocation.InvocationOnMock\nimport java.io.File\nimport java.io.IOException\nimport java.util.concurrent.Callable\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Future\nimport java.util.concurrent.TimeUnit\n\ninternal object TestUtils {\n  val URI_1: Uri = Uri.parse(\"http://example.com/1.png\")\n  val URI_2: Uri = Uri.parse(\"http://example.com/2.png\")\n  const val STABLE_1 = \"stableExampleKey1\"\n  val SIMPLE_REQUEST: Request = Request.Builder(URI_1).build()\n  val URI_KEY_1: String = SIMPLE_REQUEST.key\n  val URI_KEY_2: String = Request.Builder(URI_2).build().key\n  val STABLE_URI_KEY_1: String = Request.Builder(URI_1).stableKey(STABLE_1).build().key\n  private val FILE_1 = File(\"C:\\\\windows\\\\system32\\\\logo.exe\")\n  val FILE_KEY_1: String = Request.Builder(Uri.fromFile(FILE_1)).build().key\n  val FILE_1_URL: Uri = Uri.parse(\"file:///\" + FILE_1.path)\n  val FILE_1_URL_NO_AUTHORITY: Uri = Uri.parse(\"file:/\" + FILE_1.parent)\n  val MEDIA_STORE_CONTENT_1_URL: Uri = Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendPath(\"1\").build()\n  val MEDIA_STORE_CONTENT_2_URL: Uri = Video.Media.EXTERNAL_CONTENT_URI.buildUpon().appendPath(\"1\").build()\n  val MEDIA_STORE_CONTENT_KEY_1: String = Request.Builder(MEDIA_STORE_CONTENT_1_URL).build().key\n  val MEDIA_STORE_CONTENT_KEY_2: String = Request.Builder(MEDIA_STORE_CONTENT_2_URL).build().key\n  val CONTENT_1_URL: Uri = Uri.parse(\"content://zip/zap/zoop.jpg\")\n  val CONTENT_KEY_1: String = Request.Builder(CONTENT_1_URL).build().key\n  val CONTACT_URI_1: Uri = CONTENT_URI.buildUpon().appendPath(\"1234\").build()\n  val CONTACT_KEY_1: String = Request.Builder(CONTACT_URI_1).build().key\n  val CONTACT_PHOTO_URI_1: Uri =\n    CONTENT_URI.buildUpon().appendPath(\"1234\").appendPath(Photo.CONTENT_DIRECTORY).build()\n  val CONTACT_PHOTO_KEY_1: String = Request.Builder(CONTACT_PHOTO_URI_1).build().key\n  const val RESOURCE_ID_1 = 1\n  val RESOURCE_ID_KEY_1: String = Request.Builder(RESOURCE_ID_1).build().key\n  val ASSET_URI_1: Uri = Uri.parse(\"file:///android_asset/foo/bar.png\")\n  val ASSET_KEY_1: String = Request.Builder(ASSET_URI_1).build().key\n  private const val RESOURCE_PACKAGE = \"com.squareup.picasso3\"\n  private const val RESOURCE_TYPE = \"drawable\"\n  private const val RESOURCE_NAME = \"foo\"\n  val RESOURCE_ID_URI: Uri = Uri.Builder()\n    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)\n    .authority(RESOURCE_PACKAGE)\n    .appendPath(RESOURCE_ID_1.toString())\n    .build()\n  val RESOURCE_ID_URI_KEY: String = Request.Builder(RESOURCE_ID_URI).build().key\n  val RESOURCE_TYPE_URI: Uri = Uri.Builder()\n    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)\n    .authority(RESOURCE_PACKAGE)\n    .appendPath(RESOURCE_TYPE)\n    .appendPath(RESOURCE_NAME)\n    .build()\n  val RESOURCE_TYPE_URI_KEY: String = Request.Builder(RESOURCE_TYPE_URI).build().key\n  val CUSTOM_URI: Uri = Uri.parse(\"foo://bar\")\n  val CUSTOM_URI_KEY: String = Request.Builder(CUSTOM_URI).build().key\n  const val BITMAP_RESOURCE_VALUE = \"foo.png\"\n  const val XML_RESOURCE_VALUE = \"foo.xml\"\n  private val DEFAULT_CONFIG = ARGB_8888\n  private const val DEFAULT_CACHE_SIZE = 123\n  const val CUSTOM_HEADER_NAME = \"Cache-Control\"\n  const val CUSTOM_HEADER_VALUE = \"no-cache\"\n\n  fun mockPackageResourceContext(): Context {\n    val context = mock(Context::class.java)\n    val pm = mock(PackageManager::class.java)\n    val res = mock(Resources::class.java)\n\n    doReturn(pm).`when`(context).packageManager\n    try {\n      doReturn(res).`when`(pm).getResourcesForApplication(RESOURCE_PACKAGE)\n    } catch (e: NameNotFoundException) {\n      throw RuntimeException(e)\n    }\n    doReturn(RESOURCE_ID_1).`when`(res)\n      .getIdentifier(RESOURCE_NAME, RESOURCE_TYPE, RESOURCE_PACKAGE)\n    return context\n  }\n\n  fun mockResources(resValueString: String): Resources {\n    val resources = mock(Resources::class.java)\n    doAnswer { invocation: InvocationOnMock ->\n      val args = invocation.arguments\n      (args[1] as TypedValue).string = resValueString\n      null\n    }.`when`(resources).getValue(anyInt(), any(TypedValue::class.java), anyBoolean())\n\n    return resources\n  }\n\n  fun mockRequest(uri: Uri): Request = Request.Builder(uri).build()\n\n  fun mockAction(\n    picasso: Picasso,\n    key: String,\n    uri: Uri? = null,\n    target: Any = mockBitmapTarget(),\n    resourceId: Int = 0,\n    priority: Priority? = null,\n    tag: String? = null,\n    headers: Map<String, String> = emptyMap()\n  ): FakeAction {\n    val builder = Request.Builder(uri, resourceId, DEFAULT_CONFIG).stableKey(key)\n    if (priority != null) {\n      builder.priority(priority)\n    }\n    if (tag != null) {\n      builder.tag(tag)\n    }\n    headers.forEach { (key, value) ->\n      builder.addHeader(key, value)\n    }\n    val request = builder.build()\n    return mockAction(picasso, request, target)\n  }\n\n  fun mockAction(picasso: Picasso, request: Request, target: Any = mockBitmapTarget()) =\n    FakeAction(picasso, request, target)\n\n  fun mockImageViewTarget(): ImageView = mock(ImageView::class.java)\n\n  fun mockRemoteViews(): RemoteViews = mock(RemoteViews::class.java)\n\n  fun mockNotification(): Notification = mock(Notification::class.java)\n\n  fun mockFitImageViewTarget(alive: Boolean): ImageView {\n    val observer = mock(ViewTreeObserver::class.java)\n    `when`(observer.isAlive).thenReturn(alive)\n    val mock = mock(ImageView::class.java)\n    `when`(mock.windowToken).thenReturn(mock(IBinder::class.java))\n    `when`(mock.viewTreeObserver).thenReturn(observer)\n    return mock\n  }\n\n  fun mockBitmapTarget(): BitmapTarget = mock(BitmapTarget::class.java)\n\n  fun mockDrawableTarget(): DrawableTarget = mock(DrawableTarget::class.java)\n\n  fun mockCallback(): Callback = mock(Callback::class.java)\n\n  fun mockDeferredRequestCreator(\n    creator: RequestCreator?,\n    target: ImageView\n  ): DeferredRequestCreator {\n    val observer = mock(ViewTreeObserver::class.java)\n    `when`(target.viewTreeObserver).thenReturn(observer)\n    return DeferredRequestCreator(creator!!, target, null)\n  }\n\n  fun mockRequestCreator(picasso: Picasso) = RequestCreator(picasso, null, 0)\n\n  fun mockNetworkInfo(isConnected: Boolean = false): NetworkInfo {\n    val mock = mock(NetworkInfo::class.java)\n    `when`(mock.isConnected).thenReturn(isConnected)\n    `when`(mock.isConnectedOrConnecting).thenReturn(isConnected)\n    return mock\n  }\n\n  fun mockHunter(\n    picasso: Picasso,\n    result: Result,\n    action: Action,\n    e: Exception? = null,\n    shouldRetry: Boolean = false,\n    supportsReplay: Boolean = false,\n    dispatcher: Dispatcher = mock(Dispatcher::class.java)\n  ): BitmapHunter =\n    TestableBitmapHunter(\n      picasso = picasso,\n      dispatcher = dispatcher,\n      cache = PlatformLruCache(0),\n      action = action,\n      result = (result as Bitmap).bitmap,\n      exception = e,\n      shouldRetry = shouldRetry,\n      supportsReplay = supportsReplay\n    )\n\n  fun mockPicasso(context: Context): Picasso {\n    // Inject a RequestHandler that can handle any request.\n    val requestHandler: RequestHandler = object : RequestHandler() {\n      override fun canHandleRequest(data: Request): Boolean {\n        return true\n      }\n\n      override fun load(picasso: Picasso, request: Request, callback: Callback) {\n        val defaultResult = makeBitmap()\n        val result = RequestHandler.Result.Bitmap(defaultResult, MEMORY)\n        callback.onSuccess(result)\n      }\n    }\n\n    return mockPicasso(context, requestHandler)\n  }\n\n  fun mockPicasso(context: Context, requestHandler: RequestHandler): Picasso {\n    return Picasso.Builder(context)\n      .callFactory(UNUSED_CALL_FACTORY)\n      .withCacheSize(0)\n      .addRequestHandler(requestHandler)\n      .build()\n  }\n\n  fun makeBitmap(\n    width: Int = 10,\n    height: Int = 10\n  ): android.graphics.Bitmap = android.graphics.Bitmap.createBitmap(width, height, ALPHA_8)\n\n  fun makeLoaderWithDrawable(drawable: Drawable?): DrawableLoader = DrawableLoader { drawable }\n\n  internal class FakeAction(\n    picasso: Picasso,\n    request: Request,\n    private val target: Any\n  ) : Action(picasso, request) {\n    var completedResult: Result? = null\n    var errorException: Exception? = null\n\n    override fun complete(result: Result) {\n      completedResult = result\n    }\n\n    override fun error(e: Exception) {\n      errorException = e\n    }\n\n    override fun getTarget(): Any = target\n  }\n\n  val UNUSED_CALL_FACTORY = Call.Factory { throw AssertionError() }\n  val NOOP_REQUEST_HANDLER: RequestHandler = object : RequestHandler() {\n    override fun canHandleRequest(data: Request): Boolean = false\n    override fun load(picasso: Picasso, request: Request, callback: Callback) = Unit\n  }\n  val NOOP_TRANSFORMER = RequestTransformer { Request.Builder(0).build() }\n  private val NOOP_LISTENER = Picasso.Listener { _: Picasso, _: Uri?, _: Exception -> }\n  val NO_TRANSFORMERS: List<RequestTransformer> = emptyList()\n  val NO_HANDLERS: List<RequestHandler> = emptyList()\n  val NO_EVENT_LISTENERS: List<EventListener> = emptyList()\n\n  fun defaultPicasso(\n    context: Context,\n    hasRequestHandlers: Boolean,\n    hasTransformers: Boolean\n  ): Picasso {\n    val builder = Picasso.Builder(context)\n\n    if (hasRequestHandlers) {\n      builder.addRequestHandler(NOOP_REQUEST_HANDLER)\n    }\n    if (hasTransformers) {\n      builder.addRequestTransformer(NOOP_TRANSFORMER)\n    }\n    return builder\n      .callFactory(UNUSED_CALL_FACTORY)\n      .defaultBitmapConfig(DEFAULT_CONFIG)\n      .executor(PicassoExecutorService())\n      .indicatorsEnabled(true)\n      .listener(NOOP_LISTENER)\n      .loggingEnabled(true)\n      .withCacheSize(DEFAULT_CACHE_SIZE)\n      .build()\n  }\n\n  internal class EventRecorder : EventListener {\n    var maxCacheSize = 0\n    var cacheSize = 0\n    var cacheHits = 0\n    var cacheMisses = 0\n    var downloadSize: Long = 0\n    var decodedBitmap: android.graphics.Bitmap? = null\n    var transformedBitmap: android.graphics.Bitmap? = null\n    var closed = false\n\n    override fun cacheMaxSize(maxSize: Int) {\n      maxCacheSize = maxSize\n    }\n\n    override fun cacheSize(size: Int) {\n      cacheSize = size\n    }\n\n    override fun cacheHit() {\n      cacheHits++\n    }\n\n    override fun cacheMiss() {\n      cacheMisses++\n    }\n\n    override fun downloadFinished(size: Long) {\n      downloadSize = size\n    }\n\n    override fun bitmapDecoded(bitmap: android.graphics.Bitmap) {\n      decodedBitmap = bitmap\n    }\n\n    override fun bitmapTransformed(bitmap: android.graphics.Bitmap) {\n      transformedBitmap = bitmap\n    }\n\n    override fun close() {\n      closed = true\n    }\n  }\n\n  internal class PremadeCall(\n    private val request: okhttp3.Request,\n    private val response: Response\n  ) : Call {\n    override fun request(): okhttp3.Request = request\n    override fun execute(): Response = response\n    override fun enqueue(responseCallback: okhttp3.Callback) {\n      try {\n        responseCallback.onResponse(this, response)\n      } catch (e: IOException) {\n        throw AssertionError(e)\n      }\n    }\n    override fun cancel(): Unit = throw AssertionError()\n    override fun isExecuted(): Boolean = throw AssertionError()\n    override fun isCanceled(): Boolean = throw AssertionError()\n    override fun clone(): Call = throw AssertionError()\n    override fun timeout(): Timeout = throw AssertionError()\n  }\n\n  class TestDelegatingService(private val delegate: ExecutorService) : ExecutorService {\n    var submissions = 0\n\n    override fun shutdown() = delegate.shutdown()\n    override fun shutdownNow(): List<Runnable> = throw AssertionError(\"Not implemented.\")\n    override fun isShutdown(): Boolean = delegate.isShutdown\n    override fun isTerminated(): Boolean = throw AssertionError(\"Not implemented.\")\n\n    override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean =\n      delegate.awaitTermination(timeout, unit)\n\n    override fun <T> submit(task: Callable<T>): Future<T> =\n      throw AssertionError(\"Not implemented.\")\n\n    override fun <T> submit(task: Runnable, result: T): Future<T> =\n      throw AssertionError(\"Not implemented.\")\n\n    override fun submit(task: Runnable): Future<*> {\n      submissions++\n      return delegate.submit(task)\n    }\n\n    override fun <T> invokeAll(tasks: Collection<Callable<T>?>): List<Future<T>> =\n      throw AssertionError(\"Not implemented.\")\n\n    override fun <T> invokeAll(\n      tasks: Collection<Callable<T>?>,\n      timeout: Long,\n      unit: TimeUnit\n    ): List<Future<T>> = throw AssertionError(\"Not implemented.\")\n\n    override fun <T> invokeAny(tasks: Collection<Callable<T>?>): T =\n      throw AssertionError(\"Not implemented.\")\n\n    override fun <T> invokeAny(tasks: Collection<Callable<T>?>, timeout: Long, unit: TimeUnit): T =\n      throw AssertionError(\"Not implemented.\")\n\n    override fun execute(command: Runnable) = delegate.execute(command)\n  }\n\n  fun <T> any(type: Class<T>): T = Mockito.any(type)\n\n  fun <T : Any> eq(value: T): T = Mockito.eq(value) ?: value\n\n  inline fun <reified T : Any> argumentCaptor(): KArgumentCaptor<T> {\n    return KArgumentCaptor(ArgumentCaptor.forClass(T::class.java))\n  }\n\n  class KArgumentCaptor<T>(\n    private val captor: ArgumentCaptor<T>\n  ) {\n    val value: T\n      get() = captor.value\n\n    fun capture(): T = captor.capture()\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/UtilsTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3\n\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.TestUtils.RESOURCE_ID_1\nimport com.squareup.picasso3.TestUtils.RESOURCE_ID_URI\nimport com.squareup.picasso3.TestUtils.RESOURCE_TYPE_URI\nimport com.squareup.picasso3.TestUtils.URI_1\nimport com.squareup.picasso3.TestUtils.mockPackageResourceContext\nimport com.squareup.picasso3.Utils.isWebPFile\nimport okio.Buffer\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.robolectric.RobolectricTestRunner\n\n@RunWith(RobolectricTestRunner::class)\nclass UtilsTest {\n  @Test fun matchingRequestsHaveSameKey() {\n    val request = Request.Builder(URI_1).build()\n    val request2 = Request.Builder(URI_1).build()\n    assertThat(request.key).isEqualTo(request2.key)\n\n    val t1 = TestTransformation(\"foo\", null)\n    val t2 = TestTransformation(\"foo\", null)\n    val requestTransform1 = Request.Builder(URI_1).transform(t1).build()\n    val requestTransform2 = Request.Builder(URI_1).transform(t2).build()\n    assertThat(requestTransform1.key).isEqualTo(requestTransform2.key)\n\n    val t3 = TestTransformation(\"foo\", null)\n    val t4 = TestTransformation(\"bar\", null)\n    val requestTransform3 = Request.Builder(URI_1).transform(t3).transform(t4).build()\n    val requestTransform4 = Request.Builder(URI_1).transform(t3).transform(t4).build()\n    assertThat(requestTransform3.key).isEqualTo(requestTransform4.key)\n\n    val t5 = TestTransformation(\"foo\", null)\n    val t6 = TestTransformation(\"bar\", null)\n    val requestTransform5 = Request.Builder(URI_1).transform(t5).transform(t6).build()\n    val requestTransform6 = Request.Builder(URI_1).transform(t6).transform(t5).build()\n    assertThat(requestTransform5.key).isNotEqualTo(requestTransform6.key)\n  }\n\n  @Test fun detectedWebPFile() {\n    assertThat(isWebPFile(Buffer().writeUtf8(\"RIFFxxxxWEBP\"))).isTrue()\n    assertThat(isWebPFile(Buffer().writeUtf8(\"RIFFxxxxxWEBP\"))).isFalse()\n    assertThat(isWebPFile(Buffer().writeUtf8(\"ABCDxxxxWEBP\"))).isFalse()\n    assertThat(isWebPFile(Buffer().writeUtf8(\"RIFFxxxxABCD\"))).isFalse()\n    assertThat(isWebPFile(Buffer().writeUtf8(\"RIFFxxWEBP\"))).isFalse()\n  }\n\n  @Test fun ensureBuilderIsCleared() {\n    Request.Builder(RESOURCE_ID_URI).build()\n    assertThat(Utils.MAIN_THREAD_KEY_BUILDER.length).isEqualTo(0)\n    Request.Builder(URI_1).build()\n    assertThat(Utils.MAIN_THREAD_KEY_BUILDER.length).isEqualTo(0)\n  }\n\n  @Test fun getResourceById() {\n    val request = Request.Builder(RESOURCE_ID_URI).build()\n    val res = Utils.getResources(mockPackageResourceContext(), request)\n    val id = Utils.getResourceId(res, request)\n    assertThat(id).isEqualTo(RESOURCE_ID_1)\n  }\n\n  @Test fun getResourceByTypeAndName() {\n    val request = Request.Builder(RESOURCE_TYPE_URI).build()\n    val res = Utils.getResources(mockPackageResourceContext(), request)\n    val id = Utils.getResourceId(res, request)\n    assertThat(id).isEqualTo(RESOURCE_ID_1)\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/_JavaConsumerIdeCheck.java",
    "content": "package com.squareup.picasso3;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.mockito.Mock;\n\nimport static android.graphics.Bitmap.Config.ALPHA_8;\nimport static com.squareup.picasso3.Picasso.LoadedFrom.DISK;\n\npublic class _JavaConsumerIdeCheck {\n  @Mock Context context;\n\n  @Test\n  @Ignore(\"Quick IDE check for compile-time access to Kotlin internal methods from Java callers\")\n  public void name() {\n    Picasso picasso = new Picasso.Builder(context).build();\n    picasso.setLoggingEnabled(true);\n\n    RequestCreator requestCreator = picasso.load(\"\");\n    requestCreator.fit();\n\n    AssetRequestHandler assetRequestHandler = new AssetRequestHandler(context);\n    assetRequestHandler.getRetryCount();\n\n    Request.Builder requestBuilder = new Request.Builder(0);\n    requestBuilder.getRotationDegrees();\n\n    Request request = requestBuilder.build();\n\n    MatrixTransformation matrixTransformation = new MatrixTransformation(request);\n\n    Bitmap bitmap = Bitmap.createBitmap(0, 0, ALPHA_8);\n    RequestHandler.Result.Bitmap transform =\n      matrixTransformation.transform(new RequestHandler.Result.Bitmap(bitmap, DISK, 0));\n    Picasso.LoadedFrom loadedFrom = transform.getLoadedFrom();\n    Picasso.RequestTransformer requestTransformer = request1 -> request1;\n\n    Dispatcher.Companion companion1 = Dispatcher.Companion;\n    MatrixTransformation.Companion companion = MatrixTransformation.Companion;\n    Picasso.Companion companion2 = Picasso.Companion;\n    ResourceDrawableRequestHandler.Companion companion3 = ResourceDrawableRequestHandler.Companion;\n  }\n}\n"
  },
  {
    "path": "picasso/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker",
    "content": "mock-maker-inline"
  },
  {
    "path": "picasso/src/test/resources/robolectric.properties",
    "content": "sdk: 21\nconstants: com.squareup.picasso3.BuildConfig\nmanifest: --default\n"
  },
  {
    "path": "picasso-compose/README.md",
    "content": "Picasso Compose Ui\n====================================\n\nA [Painter] which wraps a [RequestCreator]\n\nUsage\n-----\n\nCreate a `Painter` using the rememberPainter extension on a Picasso instance.\n\n```kotlin\nval picasso = Picasso.Builder(context).build()\nval painter = picasso.rememberPainter(key = url) {\n  it.load(url).placeholder(placeholderDrawable).error(errorDrawable)\n}\n```"
  },
  {
    "path": "picasso-compose/api/picasso-compose.api",
    "content": "public final class com/squareup/picasso3/compose/PicassoPainterKt {\n\tpublic static final fun rememberPainter (Lcom/squareup/picasso3/Picasso;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Landroidx/compose/ui/graphics/painter/Painter;\n}\n\n"
  },
  {
    "path": "picasso-compose/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'org.jetbrains.kotlin.plugin.compose'\napply plugin: 'com.vanniktech.maven.publish'\n\nandroid {\n  namespace 'com.squareup.picasso3.compose'\n\n  compileSdkVersion libs.versions.compileSdk.get() as int\n\n  defaultConfig {\n    minSdkVersion libs.versions.minSdk.get() as int\n\n    testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'\n  }\n\n  buildFeatures {\n    compose true\n  }\n\n  compileOptions {\n    sourceCompatibility libs.versions.javaTarget.get()\n    targetCompatibility libs.versions.javaTarget.get()\n  }\n\n  kotlinOptions {\n    jvmTarget = libs.versions.javaTarget.get()\n  }\n\n  lintOptions {\n    textOutput 'stdout'\n    textReport true\n    lintConfig rootProject.file('lint.xml')\n  }\n}\n\ndependencies {\n  api projects.picasso\n\n  implementation libs.drawablePainter\n  implementation libs.composeUi\n  implementation libs.composeUi.foundation\n  implementation libs.composeRuntime\n\n  debugImplementation libs.composeUi.testManifest\n\n  androidTestImplementation libs.composeUi.test\n  androidTestImplementation libs.truth\n\n  compileOnly libs.androidx.annotations\n}\n"
  },
  {
    "path": "picasso-compose/gradle.properties",
    "content": "POM_ARTIFACT_ID=picasso-compose\nPOM_NAME=Picasso Compose\nPOM_DESCRIPTION=Compose UI support for Picasso.\nPOM_PACKAGING=aar\n"
  },
  {
    "path": "picasso-compose/src/androidTest/java/com/squareup/picasso3/compose/PicassoPainterTest.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3.compose\n\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config.ARGB_8888\nimport androidx.compose.foundation.Canvas\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.requiredSize\nimport androidx.compose.runtime.CompositionLocalProvider\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.layout.onSizeChanged\nimport androidx.compose.ui.platform.LocalDensity\nimport androidx.compose.ui.test.junit4.createComposeRule\nimport androidx.compose.ui.unit.Density\nimport androidx.compose.ui.unit.IntSize\nimport androidx.compose.ui.unit.dp\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport androidx.test.platform.app.InstrumentationRegistry\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.Picasso\nimport com.squareup.picasso3.Picasso.LoadedFrom\nimport com.squareup.picasso3.Request\nimport com.squareup.picasso3.RequestHandler\nimport org.junit.Rule\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport kotlinx.coroutines.Dispatchers\n\n@RunWith(AndroidJUnit4::class)\nclass PicassoPainterTest {\n\n  @get:Rule\n  val rule = createComposeRule()\n\n  @Test\n  fun firstFrameConsumesStateFromLayout() {\n    lateinit var lastRequest: Request\n    val context = InstrumentationRegistry.getInstrumentation().targetContext\n\n    val picasso = Picasso.Builder(context)\n      .callFactory { throw RuntimeException() }\n      .dispatchers(Dispatchers.Unconfined, Dispatchers.Unconfined)\n      .addRequestHandler(object : RequestHandler() {\n        override fun canHandleRequest(data: Request): Boolean = true\n        override fun load(picasso: Picasso, request: Request, callback: Callback) {\n          lastRequest = request\n          callback.onSuccess(Result.Bitmap(Bitmap.createBitmap(1, 1, ARGB_8888), LoadedFrom.MEMORY))\n        }\n      })\n      .build()\n    var size: IntSize by mutableStateOf(IntSize.Zero)\n    var drawn = false\n\n    rule.setContent {\n      CompositionLocalProvider(LocalDensity provides Density(1f)) {\n        val painter = picasso.rememberPainter {\n          it.load(\"http://example.com/\")\n            // Headers are not part of a cache key, using a stable key to break cache\n            .stableKey(\"http://example.com/$size\")\n            .addHeader(\"width\", size.width.toString())\n            .addHeader(\"height\", size.height.toString())\n        }\n        Canvas(\n          Modifier\n            .requiredSize(9.dp)\n            .onSizeChanged { size = it }\n        ) {\n          val canvasSize = this.size\n\n          with(painter) {\n            draw(canvasSize)\n          }\n          drawn = true\n        }\n      }\n    }\n\n    rule.waitUntil { drawn }\n\n    // Draw triggers request was made with size.\n    assertThat(lastRequest.headers?.toMultimap()).containsAtLeastEntriesIn(\n      mapOf(\n        \"width\" to listOf(\"9\"),\n        \"height\" to listOf(\"9\")\n      )\n    )\n  }\n\n  @Test\n  fun redrawDoesNotReexecuteUnchangedRequest() {\n    var requestCount = 0\n    val context = InstrumentationRegistry.getInstrumentation().targetContext\n    val picasso = Picasso.Builder(context)\n      .callFactory { throw RuntimeException() }\n      .dispatchers(Dispatchers.Unconfined, Dispatchers.Unconfined)\n      .addRequestHandler(object : RequestHandler() {\n        override fun canHandleRequest(data: Request): Boolean = true\n        override fun load(picasso: Picasso, request: Request, callback: Callback) {\n          requestCount++\n          callback.onSuccess(Result.Bitmap(Bitmap.createBitmap(1, 1, ARGB_8888), LoadedFrom.MEMORY))\n        }\n      })\n      .build()\n\n    var drawInvalidator by mutableStateOf(0)\n    var drawCount = 0\n    rule.setContent {\n      CompositionLocalProvider(LocalDensity provides Density(1f)) {\n        val painter = picasso.rememberPainter {\n          it.load(\"http://example.com/\")\n        }\n        Canvas(Modifier.fillMaxSize()) {\n          drawCount++\n          drawInvalidator = 1\n\n          val canvasSize = this.size\n          with(painter) {\n            draw(canvasSize)\n          }\n        }\n      }\n    }\n\n    rule.waitUntil { drawCount == 2 }\n    assertThat(requestCount).isEqualTo(1)\n  }\n\n  @Test\n  fun newRequestLoaded_whenRequestDependenciesChangedAfterFirstFrame() {\n    var lastRequest: Request? = null\n    val context = InstrumentationRegistry.getInstrumentation().targetContext\n    val picasso = Picasso.Builder(context)\n      .callFactory { throw RuntimeException() }\n      .dispatchers(Dispatchers.Unconfined, Dispatchers.Unconfined)\n      .addRequestHandler(object : RequestHandler() {\n        override fun canHandleRequest(data: Request): Boolean = true\n        override fun load(picasso: Picasso, request: Request, callback: Callback) {\n          lastRequest = request\n          callback.onSuccess(Result.Bitmap(Bitmap.createBitmap(1, 1, ARGB_8888), LoadedFrom.MEMORY))\n        }\n      })\n      .build()\n    var testHeader by mutableStateOf(\"one\")\n\n    rule.setContent {\n      CompositionLocalProvider(LocalDensity provides Density(1f)) {\n        val painter = picasso.rememberPainter {\n          it.load(\"http://example.com/\")\n            // Headers are not part of a cache key, using a stable key to break cache\n            .stableKey(\"http://example.com/$testHeader\")\n            .addHeader(\"testHeader\", testHeader)\n        }\n        Canvas(Modifier.fillMaxSize()) {\n          val canvasSize = this.size\n\n          with(painter) {\n            draw(canvasSize)\n          }\n        }\n      }\n    }\n\n    rule.waitUntil { lastRequest != null }\n    assertThat(lastRequest!!.headers?.get(\"testHeader\")).isEqualTo(\"one\")\n\n    var currentRequest = lastRequest\n    testHeader = \"two\"\n\n    // On API 21 runOnIdle runs before the composition recomposes :-(\n    // Waiting until the request updates, then asserting\n    rule.waitUntil { currentRequest != lastRequest }\n    assertThat(lastRequest!!.headers?.get(\"testHeader\")).isEqualTo(\"two\")\n\n    currentRequest = lastRequest\n    testHeader = \"three\"\n\n    rule.waitUntil { currentRequest != lastRequest }\n    assertThat(lastRequest!!.headers?.get(\"testHeader\")).isEqualTo(\"three\")\n  }\n}\n"
  },
  {
    "path": "picasso-compose/src/main/java/com/squareup/picasso3/compose/PicassoPainter.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3.compose\n\nimport android.graphics.drawable.Drawable\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.RememberObserver\nimport androidx.compose.runtime.derivedStateOf\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.setValue\nimport androidx.compose.runtime.snapshots.Snapshot\nimport androidx.compose.ui.geometry.Size\nimport androidx.compose.ui.graphics.ColorFilter\nimport androidx.compose.ui.graphics.DefaultAlpha\nimport androidx.compose.ui.graphics.drawscope.DrawScope\nimport androidx.compose.ui.graphics.painter.Painter\nimport com.google.accompanist.drawablepainter.DrawablePainter\nimport com.squareup.picasso3.DrawableTarget\nimport com.squareup.picasso3.Picasso\nimport com.squareup.picasso3.Picasso.LoadedFrom\nimport com.squareup.picasso3.RequestCreator\n\n@Composable\nfun Picasso.rememberPainter(\n  key: Any? = null,\n  onError: ((Exception) -> Unit)? = null,\n  request: (Picasso) -> RequestCreator\n): Painter {\n  return remember(key) { PicassoPainter(this, request, onError) }\n}\n\ninternal class PicassoPainter(\n  private val picasso: Picasso,\n  private val request: (Picasso) -> RequestCreator,\n  private val onError: ((Exception) -> Unit)? = null\n) : Painter(), RememberObserver, DrawableTarget {\n\n  private var lastRequestCreator: RequestCreator? by mutableStateOf(null)\n  private val requestCreator: RequestCreator by derivedStateOf { request(picasso) }\n  private var painter: Painter by mutableStateOf(EmptyPainter)\n  private var alpha: Float by mutableStateOf(DefaultAlpha)\n  private var colorFilter: ColorFilter? by mutableStateOf(null)\n\n  override val intrinsicSize: Size\n    get() {\n      // Make sure we're using the latest request. If the request function reads any state, it will\n      // invalidate whatever scope this property is being read from.\n      load()\n      return painter.intrinsicSize\n    }\n\n  override fun applyAlpha(alpha: Float): Boolean {\n    this.alpha = alpha\n    return true\n  }\n\n  override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {\n    this.colorFilter = colorFilter\n    return true\n  }\n\n  override fun DrawScope.onDraw() {\n    // Make sure we're using the latest request. If the request function reads any state, it will\n    // invalidate this draw scope when it changes.\n    load()\n    with(painter) {\n      draw(size, alpha, colorFilter)\n    }\n  }\n\n  override fun onRemembered() {\n    // This is called from composition, but if the request provider function reads any state we\n    // don't want that to invalidate composition. It will invalidate draw, later.\n    Snapshot.withoutReadObservation { load() }\n  }\n\n  override fun onAbandoned() {\n    (painter as? RememberObserver)?.onAbandoned()\n    painter = EmptyPainter\n    picasso.cancelRequest(this)\n  }\n\n  override fun onForgotten() {\n    (painter as? RememberObserver)?.onForgotten()\n    painter = EmptyPainter\n    picasso.cancelRequest(this)\n  }\n\n  override fun onPrepareLoad(placeHolderDrawable: Drawable?) {\n    placeHolderDrawable?.let(::setPainter)\n  }\n\n  override fun onDrawableLoaded(drawable: Drawable, from: LoadedFrom) {\n    setPainter(drawable)\n  }\n\n  override fun onDrawableFailed(e: Exception, errorDrawable: Drawable?) {\n    onError?.invoke(e)\n    errorDrawable?.let(::setPainter)\n  }\n\n  private fun load() {\n    // This derived state read will return the same instance of RequestCreator if one has been\n    // cached and none of the state dependencies have since changed.\n    val requestCreator = requestCreator\n    // lastRequestCreator is just used for diffing, we don't want it to invalidate anything.\n    val lastRequestCreator = Snapshot.withoutReadObservation { lastRequestCreator }\n\n    // Only launch a new request if anything has actually changed. RequestCreator does not\n    // currently implement an equals method, relying here on reference equality, future improvement\n    // will be to implement equals which can prevent further re-requests.\n    if (requestCreator != lastRequestCreator) {\n      this.lastRequestCreator = requestCreator\n      requestCreator.into(this)\n    }\n  }\n\n  private fun setPainter(drawable: Drawable) {\n    (painter as? RememberObserver)?.onForgotten()\n    painter = DrawablePainter(drawable).apply(DrawablePainter::onRemembered)\n  }\n}\n\nprivate object EmptyPainter : Painter() {\n  override val intrinsicSize = Size.Unspecified\n  override fun DrawScope.onDraw() = Unit\n}\n"
  },
  {
    "path": "picasso-paparazzi-sample/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'app.cash.paparazzi'\n\nandroid {\n  namespace 'com.example.picasso.paparazzi'\n\n  compileSdkVersion libs.versions.compileSdk.get() as int\n\n  defaultConfig {\n    minSdkVersion libs.versions.minSdk.get() as int\n  }\n\n  compileOptions {\n    sourceCompatibility libs.versions.javaTarget.get()\n    targetCompatibility libs.versions.javaTarget.get()\n  }\n\n  kotlinOptions {\n    jvmTarget = libs.versions.javaTarget.get()\n  }\n\n  lintOptions {\n    textOutput 'stdout'\n    textReport true\n    lintConfig rootProject.file('lint.xml')\n  }\n\n  testOptions {\n    unitTests {\n      includeAndroidResources = true\n    }\n  }\n}\n\ndependencies {\n  testImplementation libs.junit\n\n  testImplementation projects.picasso\n}\n\n// https://github.com/diffplug/spotless/issues/1572\ntasks.withType(com.diffplug.gradle.spotless.SpotlessTask).configureEach {\n  dependsOn(tasks.withType(Test))\n}\n"
  },
  {
    "path": "picasso-paparazzi-sample/src/test/java/com/example/picasso/paparazzi/PicassoPaparazziTest.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso.paparazzi\n\nimport android.graphics.BitmapFactory\nimport android.widget.ImageView\nimport android.widget.ImageView.ScaleType.CENTER\nimport app.cash.paparazzi.Paparazzi\nimport com.squareup.picasso3.Picasso\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Request\nimport com.squareup.picasso3.RequestHandler\nimport org.junit.Rule\nimport org.junit.Test\nimport kotlinx.coroutines.Dispatchers\n\nclass PicassoPaparazziTest {\n  @get:Rule val paparazzi = Paparazzi()\n\n  @Test\n  fun loadsUrlIntoImageView() {\n    val picasso = Picasso.Builder(paparazzi.context)\n      .callFactory { throw AssertionError() } // Removes network\n      .dispatchers(\n        mainContext = Dispatchers.Unconfined,\n        backgroundContext = Dispatchers.Unconfined\n      )\n      .addRequestHandler(FakeRequestHandler())\n      .build()\n\n    paparazzi.snapshot(\n      ImageView(paparazzi.context).apply {\n        scaleType = CENTER\n        picasso.load(\"fake:///zkaAooq.png\")\n          .resize(200, 200)\n          .centerInside()\n          .onlyScaleDown()\n          .into(this)\n      }\n    )\n  }\n\n  class FakeRequestHandler : RequestHandler() {\n    override fun canHandleRequest(data: Request): Boolean {\n      return \"fake\" == data.uri!!.scheme\n    }\n\n    override fun load(picasso: Picasso, request: Request, callback: Callback) {\n      val imagePath = request.uri!!.lastPathSegment!!\n      callback.onSuccess(Result.Bitmap(loadBitmap(imagePath)!!, MEMORY))\n    }\n\n    private fun loadBitmap(imagePath: String): android.graphics.Bitmap? {\n      val resourceAsStream = javaClass.classLoader!!.getResourceAsStream(imagePath)\n      return BitmapFactory.decodeStream(resourceAsStream)\n    }\n  }\n}\n"
  },
  {
    "path": "picasso-pollexor/README.md",
    "content": "Picasso Pollexor Request Transformer\n====================================\n\nA request transformer which uses a remote [Thumbor][1] install to perform\nimage transformation on the server.\n\n\nUsage\n-----\n\nCreate a `PollexorRequestTransformer` using the remote host and optional encryption key.\n\n```java\nRequestTransformer transformer =\n    new PollexorRequestTransformer(\"http://example.com\", \"secretpassword\");\n```\n\nPass the transformer when creating a `Picasso` instance.\n\n```java\nPicasso p = new Picasso.Builder(context)\n    .requestTransformer(transformer)\n    .build();\n```\n\n_Note: This can only be used with an instance you create yourself. You cannot set a request\ntransformer on the global singleton instance (`Picasso.get`)._\n\n\n\n [1]: https://github.com/globocom/thumbor\n"
  },
  {
    "path": "picasso-pollexor/api/picasso-pollexor.api",
    "content": "public final class com/squareup/picasso3/pollexor/PollexorRequestTransformer : com/squareup/picasso3/Picasso$RequestTransformer {\n\tpublic static final field Companion Lcom/squareup/picasso3/pollexor/PollexorRequestTransformer$Companion;\n\tpublic fun <init> (Lcom/squareup/pollexor/Thumbor;)V\n\tpublic fun <init> (Lcom/squareup/pollexor/Thumbor;Lcom/squareup/picasso3/pollexor/PollexorRequestTransformer$Callback;)V\n\tpublic fun <init> (Lcom/squareup/pollexor/Thumbor;Z)V\n\tpublic fun <init> (Lcom/squareup/pollexor/Thumbor;ZLcom/squareup/picasso3/pollexor/PollexorRequestTransformer$Callback;)V\n\tpublic synthetic fun <init> (Lcom/squareup/pollexor/Thumbor;ZLcom/squareup/picasso3/pollexor/PollexorRequestTransformer$Callback;ILkotlin/jvm/internal/DefaultConstructorMarker;)V\n\tpublic fun transformRequest (Lcom/squareup/picasso3/Request;)Lcom/squareup/picasso3/Request;\n}\n\npublic abstract interface class com/squareup/picasso3/pollexor/PollexorRequestTransformer$Callback {\n\tpublic abstract fun configure (Lcom/squareup/pollexor/ThumborUrlBuilder;)V\n}\n\npublic final class com/squareup/picasso3/pollexor/PollexorRequestTransformer$Companion {\n}\n\n"
  },
  {
    "path": "picasso-pollexor/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'com.vanniktech.maven.publish'\n\nandroid {\n  namespace 'com.squareup.picasso3.pollexor'\n\n  compileSdkVersion libs.versions.compileSdk.get() as int\n\n  defaultConfig {\n    minSdkVersion libs.versions.minSdk.get() as int\n  }\n\n  compileOptions {\n    sourceCompatibility libs.versions.javaTarget.get()\n    targetCompatibility libs.versions.javaTarget.get()\n  }\n\n  kotlinOptions {\n    jvmTarget = libs.versions.javaTarget.get()\n  }\n\n  lintOptions {\n    textOutput 'stdout'\n    textReport true\n    lintConfig rootProject.file('lint.xml')\n  }\n}\n\ndependencies {\n  api projects.picasso\n  api libs.pollexor\n  compileOnly libs.androidx.annotations\n  testImplementation libs.junit\n  testImplementation libs.robolectric\n  testImplementation libs.truth\n  testImplementation libs.pollexor\n}\n"
  },
  {
    "path": "picasso-pollexor/gradle.properties",
    "content": "POM_ARTIFACT_ID=picasso-pollexor\nPOM_NAME=Picasso Pollexor Transformer\nPOM_DESCRIPTION=A request transformer which uses a remote Thumbor install to perform image transformation on the server.\nPOM_PACKAGING=aar\n"
  },
  {
    "path": "picasso-pollexor/src/main/java/com/squareup/picasso3/pollexor/PollexorRequestTransformer.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3.pollexor\n\nimport android.net.Uri\nimport com.squareup.picasso3.Picasso.RequestTransformer\nimport com.squareup.picasso3.Request\nimport com.squareup.picasso3.pollexor.PollexorRequestTransformer.Callback\nimport com.squareup.pollexor.Thumbor\nimport com.squareup.pollexor.ThumborUrlBuilder\nimport com.squareup.pollexor.ThumborUrlBuilder.ImageFormat.WEBP\n\n/**\n * A [RequestTransformer] that changes requests to use [Thumbor] for some remote\n * transformations.\n * By default images are only transformed with Thumbor if they have a size set,\n * unless alwaysTransform is set to true\n */\nclass PollexorRequestTransformer @JvmOverloads constructor(\n  private val thumbor: Thumbor,\n  private val alwaysTransform: Boolean = false,\n  private val callback: Callback = NONE\n) : RequestTransformer {\n  constructor(thumbor: Thumbor, callback: Callback) : this(thumbor, false, callback)\n\n  override fun transformRequest(request: Request): Request {\n    if (request.resourceId != 0) {\n      return request // Don't transform resource requests.\n    }\n    val uri = requireNotNull(request.uri) { \"Null uri passed to ${javaClass.canonicalName}\" }\n\n    val scheme = uri.scheme\n    if (\"https\" != scheme && \"http\" != scheme) {\n      return request // Thumbor only supports remote images.\n    }\n\n    // Only transform requests that have resizes unless `alwaysTransform` is set.\n    if (!request.hasSize() && !alwaysTransform) {\n      return request\n    }\n\n    // Start building a new request for us to mutate.\n    val newRequest = request.newBuilder()\n\n    // Create the url builder to use.\n    val urlBuilder = thumbor.buildImage(uri.toString())\n    callback.configure(urlBuilder)\n\n    // Resize the image to the target size if it has a size.\n    if (request.hasSize()) {\n      urlBuilder.resize(request.targetWidth, request.targetHeight)\n      newRequest.clearResize()\n    }\n\n    // If the center inside flag is set, perform that with Thumbor as well.\n    if (request.centerInside) {\n      urlBuilder.fitIn()\n      newRequest.clearCenterInside()\n    }\n\n    // Use WebP for downloading.\n    urlBuilder.filter(ThumborUrlBuilder.format(WEBP))\n\n    // Update the request with the completed Thumbor URL.\n    newRequest.setUri(Uri.parse(urlBuilder.toUrl()))\n    return newRequest.build()\n  }\n\n  fun interface Callback {\n    fun configure(builder: ThumborUrlBuilder)\n  }\n\n  companion object {\n    private val NONE = Callback { }\n  }\n}\n"
  },
  {
    "path": "picasso-pollexor/src/test/java/com/squareup/picasso3/pollexor/PollexorRequestTransformerTest.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3.pollexor\n\nimport android.net.Uri\nimport com.google.common.truth.Truth.assertThat\nimport com.squareup.picasso3.Request.Builder\nimport com.squareup.pollexor.Thumbor\nimport com.squareup.pollexor.ThumborUrlBuilder\nimport com.squareup.pollexor.ThumborUrlBuilder.ImageFormat.WEBP\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.robolectric.RobolectricTestRunner\n\n@RunWith(RobolectricTestRunner::class)\nclass PollexorRequestTransformerTest {\n  private val transformer = PollexorRequestTransformer(Thumbor.create(HOST))\n  private val secureTransformer = PollexorRequestTransformer(Thumbor.create(HOST, KEY))\n  private val alwaysResizeTransformer = PollexorRequestTransformer(\n    Thumbor.create(HOST),\n    alwaysTransform = true\n  )\n  private val callbackTransformer = PollexorRequestTransformer(\n    Thumbor.create(HOST),\n    callback = { it.filter(\"custom\") }\n  )\n\n  @Test fun resourceIdRequestsAreNotTransformed() {\n    val input = Builder(12).build()\n    val output = transformer.transformRequest(input)\n    assertThat(output).isSameInstanceAs(input)\n  }\n\n  @Test fun resourceIdRequestsAreNotTransformedWhenAlwaysTransformIsTrue() {\n    val input = Builder(12).build()\n    val output = alwaysResizeTransformer.transformRequest(input)\n    assertThat(output).isSameInstanceAs(input)\n  }\n\n  @Test fun nonHttpRequestsAreNotTransformed() {\n    val input = Builder(IMAGE_URI).build()\n    val output = transformer.transformRequest(input)\n    assertThat(output).isSameInstanceAs(input)\n  }\n\n  @Test fun nonResizedRequestsAreNotTransformed() {\n    val input = Builder(IMAGE_URI).build()\n    val output = transformer.transformRequest(input)\n    assertThat(output).isSameInstanceAs(input)\n  }\n\n  @Test fun nonResizedRequestsAreTransformedWhenAlwaysTransformIsSet() {\n    val input = Builder(IMAGE_URI).build()\n    val output = alwaysResizeTransformer.transformRequest(input)\n    assertThat(output).isNotSameInstanceAs(input)\n    assertThat(output.hasSize()).isFalse()\n\n    val expected = Thumbor.create(HOST)\n      .buildImage(IMAGE)\n      .filter(ThumborUrlBuilder.format(WEBP))\n      .toUrl()\n    assertThat(output.uri.toString()).isEqualTo(expected)\n  }\n\n  @Test fun simpleResize() {\n    val input = Builder(IMAGE_URI).resize(50, 50).build()\n    val output = transformer.transformRequest(input)\n    assertThat(output).isNotSameInstanceAs(input)\n    assertThat(output.hasSize()).isFalse()\n\n    val expected = Thumbor.create(HOST)\n      .buildImage(IMAGE)\n      .resize(50, 50)\n      .filter(ThumborUrlBuilder.format(WEBP))\n      .toUrl()\n    assertThat(output.uri.toString()).isEqualTo(expected)\n  }\n\n  @Test fun simpleResizeWithCenterCrop() {\n    val input = Builder(IMAGE_URI).resize(50, 50).centerCrop().build()\n    val output = transformer.transformRequest(input)\n    assertThat(output).isNotSameInstanceAs(input)\n    assertThat(output.hasSize()).isFalse()\n    assertThat(output.centerCrop).isFalse()\n\n    val expected = Thumbor.create(HOST)\n      .buildImage(IMAGE)\n      .resize(50, 50)\n      .filter(ThumborUrlBuilder.format(WEBP))\n      .toUrl()\n    assertThat(output.uri.toString()).isEqualTo(expected)\n  }\n\n  @Test fun simpleResizeWithCenterInside() {\n    val input = Builder(IMAGE_URI).resize(50, 50).centerInside().build()\n    val output = transformer.transformRequest(input)\n    assertThat(output).isNotSameInstanceAs(input)\n    assertThat(output.hasSize()).isFalse()\n    assertThat(output.centerInside).isFalse()\n\n    val expected = Thumbor.create(HOST)\n      .buildImage(IMAGE)\n      .resize(50, 50)\n      .filter(ThumborUrlBuilder.format(WEBP))\n      .fitIn()\n      .toUrl()\n    assertThat(output.uri.toString()).isEqualTo(expected)\n  }\n\n  @Test fun simpleResizeWithEncryption() {\n    val input = Builder(IMAGE_URI).resize(50, 50).build()\n    val output = secureTransformer.transformRequest(input)\n    assertThat(output).isNotSameInstanceAs(input)\n    assertThat(output.hasSize()).isFalse()\n\n    val expected = Thumbor.create(HOST, KEY)\n      .buildImage(IMAGE)\n      .resize(50, 50)\n      .filter(ThumborUrlBuilder.format(WEBP))\n      .toUrl()\n    assertThat(output.uri.toString()).isEqualTo(expected)\n  }\n\n  @Test fun simpleResizeWithCenterInsideAndEncryption() {\n    val input = Builder(IMAGE_URI).resize(50, 50).centerInside().build()\n    val output = secureTransformer.transformRequest(input)\n    assertThat(output).isNotSameInstanceAs(input)\n    assertThat(output.hasSize()).isFalse()\n    assertThat(output.centerInside).isFalse()\n\n    val expected = Thumbor.create(HOST, KEY)\n      .buildImage(IMAGE)\n      .resize(50, 50)\n      .filter(ThumborUrlBuilder.format(WEBP))\n      .fitIn()\n      .toUrl()\n    assertThat(output.uri.toString()).isEqualTo(expected)\n  }\n\n  @Test fun configureCallback() {\n    val input = Builder(IMAGE_URI).resize(50, 50).build()\n    val output = callbackTransformer.transformRequest(input)\n    assertThat(output).isNotSameInstanceAs(input)\n    assertThat(output.hasSize()).isFalse()\n    val expected = Thumbor.create(HOST)\n      .buildImage(IMAGE)\n      .resize(50, 50)\n      .filter(\"custom\")\n      .filter(ThumborUrlBuilder.format(WEBP))\n      .toUrl()\n    assertThat(output.uri.toString()).isEqualTo(expected)\n  }\n\n  companion object {\n    private const val HOST = \"http://example.com/\"\n    private const val KEY = \"omgsecretpassword\"\n    private const val IMAGE = \"http://google.com/logo.png\"\n    private val IMAGE_URI = Uri.parse(IMAGE)\n  }\n}\n"
  },
  {
    "path": "picasso-sample/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'org.jetbrains.kotlin.plugin.compose'\n\nandroid {\n  namespace 'com.example.picasso'\n\n  compileSdkVersion libs.versions.compileSdk.get() as int\n\n  defaultConfig {\n    minSdkVersion libs.versions.minSdk.get() as int\n    applicationId 'com.example.picasso'\n  }\n\n  buildFeatures {\n    compose true\n  }\n\n  compileOptions {\n    sourceCompatibility libs.versions.javaTarget.get()\n    targetCompatibility libs.versions.javaTarget.get()\n  }\n\n  kotlinOptions {\n    jvmTarget = libs.versions.javaTarget.get()\n  }\n\n  lintOptions {\n    lintConfig file('lint.xml')\n    textOutput 'stdout'\n    textReport true\n\n    // https://github.com/square/okhttp/issues/896\n    ignore 'InvalidPackage'\n  }\n}\n\ndependencies {\n  compileOnly libs.androidx.annotations\n  implementation libs.androidx.core\n  implementation libs.androidx.cursorAdapter\n  implementation libs.androidx.fragment\n  implementation libs.androidx.startup\n\n  implementation libs.drawablePainter\n  implementation libs.composeUi\n  implementation libs.composeRuntime\n  implementation libs.composeUi.foundation\n  implementation libs.composeUi.material\n  implementation libs.composeUi.uiTooling\n\n  implementation projects.picasso\n  implementation projects.picassoStats\n  implementation projects.picassoCompose\n}\n"
  },
  {
    "path": "picasso-sample/lint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<lint>\n  <issue id=\"NewApi\">\n    <ignore path=\"src/main/res/values/styles.xml\" />\n  </issue>\n  <issue id=\"IconColors\" severity=\"ignore\"/>\n  <issue id=\"IconDensities\" severity=\"ignore\"/>\n  <issue id=\"IconLocation\" severity=\"ignore\"/>\n</lint>\n"
  },
  {
    "path": "picasso-sample/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n  <!-- This is required for Picasso to work. -->\n  <uses-permission android:name=\"android.permission.INTERNET\"/>\n\n  <!-- The following permissions are OPTIONAL. -->\n\n  <!-- Used to adjust the work load depending on the type of network the device is using. -->\n  <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>\n  <!-- Used to load images from the gallery content provider. -->\n  <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n  <!-- Used to load images for contact photos. -->\n  <uses-permission android:name=\"android.permission.READ_CONTACTS\"/>\n  <!-- Used to post notifications. -->\n  <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n\n  <application\n      android:label=\"@string/app_name\"\n      android:icon=\"@drawable/icon\"\n      android:allowBackup=\"false\"\n      android:supportsRtl=\"false\"\n      android:theme=\"@style/Theme.PicassoSample\"\n      tools:ignore=\"GoogleAppIndexingWarning\">\n\n    <activity\n        android:name=\".SampleGridViewActivity\"\n        android:exported=\"true\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\"/>\n        <category android:name=\"android.intent.category.LAUNCHER\"/>\n        <category android:name=\"android.intent.category.DEFAULT\"/>\n      </intent-filter>\n    </activity>\n\n    <activity android:name=\".SampleComposeActivity\"/>\n    <activity android:name=\".SampleContactsActivity\"/>\n    <activity android:name=\".SampleGalleryActivity\"/>\n    <activity android:name=\".SampleListDetailActivity\"/>\n\n    <receiver\n        android:name=\"SampleWidgetProvider\"\n        android:exported=\"true\">\n      <intent-filter>\n        <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\"/>\n      </intent-filter>\n      <meta-data android:name=\"android.appwidget.provider\"\n          android:resource=\"@xml/sample_widget_info\"/>\n    </receiver>\n\n    <provider\n      android:name=\"androidx.startup.InitializationProvider\"\n      android:authorities=\"${applicationId}.androidx-startup\"\n      android:exported=\"false\"\n      tools:node=\"merge\">\n\n      <meta-data\n        android:name=\"com.example.picasso.PicassoInitializer\"\n        android:value=\"androidx.startup\" />\n    </provider>\n\n  </application>\n</manifest>\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/Data.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\ninternal object Data {\n  private const val BASE = \"https://i.imgur.com/\"\n  private const val EXT = \".jpg\"\n\n  @JvmField\n  val URLS = arrayOf(\n    BASE + \"CqmBjo5\" + EXT, BASE + \"zkaAooq\" + EXT, BASE + \"0gqnEaY\" + EXT,\n    BASE + \"9gbQ7YR\" + EXT, BASE + \"aFhEEby\" + EXT, BASE + \"0E2tgV7\" + EXT,\n    BASE + \"P5JLfjk\" + EXT, BASE + \"nz67a4F\" + EXT, BASE + \"dFH34N5\" + EXT,\n    BASE + \"FI49ftb\" + EXT, BASE + \"DvpvklR\" + EXT, BASE + \"DNKnbG8\" + EXT,\n    BASE + \"yAdbrLp\" + EXT, BASE + \"55w5Km7\" + EXT, BASE + \"NIwNTMR\" + EXT,\n    BASE + \"DAl0KB8\" + EXT, BASE + \"xZLIYFV\" + EXT, BASE + \"HvTyeh3\" + EXT,\n    BASE + \"Ig9oHCM\" + EXT, BASE + \"7GUv9qa\" + EXT, BASE + \"i5vXmXp\" + EXT,\n    BASE + \"glyvuXg\" + EXT, BASE + \"u6JF6JZ\" + EXT, BASE + \"ExwR7ap\" + EXT,\n    BASE + \"Q54zMKT\" + EXT, BASE + \"9t6hLbm\" + EXT, BASE + \"F8n3Ic6\" + EXT,\n    BASE + \"P5ZRSvT\" + EXT, BASE + \"jbemFzr\" + EXT, BASE + \"8B7haIK\" + EXT,\n    BASE + \"aSeTYQr\" + EXT, BASE + \"OKvWoTh\" + EXT, BASE + \"zD3gT4Z\" + EXT,\n    BASE + \"z77CaIt\" + EXT\n  )\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/GrayscaleTransformation.kt",
    "content": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.graphics.Bitmap.createBitmap\nimport android.graphics.BitmapShader\nimport android.graphics.Canvas\nimport android.graphics.ColorMatrix\nimport android.graphics.ColorMatrixColorFilter\nimport android.graphics.Paint\nimport android.graphics.Paint.ANTI_ALIAS_FLAG\nimport android.graphics.PorterDuff.Mode.MULTIPLY\nimport android.graphics.PorterDuffXfermode\nimport android.graphics.Shader.TileMode.REPEAT\nimport com.squareup.picasso3.Picasso\nimport com.squareup.picasso3.RequestHandler.Result\nimport com.squareup.picasso3.Transformation\nimport java.io.IOException\n\nclass GrayscaleTransformation(private val picasso: Picasso) : Transformation {\n  override fun transform(source: Result.Bitmap): Result.Bitmap {\n    val bitmap = source.bitmap\n\n    val result = createBitmap(bitmap.width, bitmap.height, bitmap.config)\n    val noise = try {\n      picasso.load(R.drawable.noise).get()!!\n    } catch (e: IOException) {\n      throw RuntimeException(\"Failed to apply transformation! Missing resource.\")\n    }\n\n    val colorMatrix = ColorMatrix().apply { setSaturation(0f) }\n\n    val paint = Paint(ANTI_ALIAS_FLAG).apply { colorFilter = ColorMatrixColorFilter(colorMatrix) }\n\n    val canvas = Canvas(result)\n    canvas.drawBitmap(bitmap, 0f, 0f, paint)\n\n    paint.apply {\n      colorFilter = null\n      shader = BitmapShader(noise, REPEAT, REPEAT)\n      xfermode = PorterDuffXfermode(MULTIPLY)\n    }\n\n    canvas.drawRect(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat(), paint)\n\n    bitmap.recycle()\n    noise.recycle()\n\n    return Result.Bitmap(result, source.loadedFrom, source.exifRotation)\n  }\n\n  override fun key() = \"grayscaleTransformation()\"\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/PicassoInitializer.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.content.Context\nimport androidx.startup.Initializer\nimport com.squareup.picasso3.Picasso\nimport com.squareup.picasso3.stats.StatsEventListener\n\nclass PicassoInitializer : Initializer<Unit> {\n  override fun create(context: Context) {\n    appContext = context\n  }\n\n  override fun dependencies() = emptyList<Class<Initializer<*>>>()\n\n  companion object {\n    private lateinit var appContext: Context\n    private val instance: Picasso by lazy {\n      Picasso\n        .Builder(appContext)\n        .addEventListener(StatsEventListener())\n        .build()\n    }\n    fun get() = instance\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/PicassoSampleActivity.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.os.Bundle\nimport android.view.View\nimport android.view.ViewGroup.LayoutParams\nimport android.widget.AdapterView.OnItemClickListener\nimport android.widget.FrameLayout\nimport android.widget.ListView\nimport android.widget.ToggleButton\nimport androidx.fragment.app.FragmentActivity\n\nabstract class PicassoSampleActivity : FragmentActivity() {\n  private lateinit var sampleContent: FrameLayout\n  private lateinit var showHide: ToggleButton\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    super.setContentView(R.layout.picasso_sample_activity)\n\n    sampleContent = findViewById(R.id.sample_content)\n\n    val activityList = findViewById<ListView>(R.id.activity_list)\n    val adapter = PicassoSampleAdapter(this)\n    activityList.adapter = adapter\n    activityList.onItemClickListener = OnItemClickListener { _, _, position, _ ->\n      adapter.getItem(position).launch(this@PicassoSampleActivity)\n    }\n\n    showHide = findViewById(R.id.faux_action_bar_control)\n    showHide.setOnCheckedChangeListener { _, checked ->\n      activityList.visibility = if (checked) View.VISIBLE else View.GONE\n    }\n\n    lifecycle.addObserver(PicassoInitializer.get())\n  }\n\n  override fun onBackPressed() {\n    if (showHide.isChecked) {\n      showHide.isChecked = false\n    } else {\n      super.onBackPressed()\n    }\n  }\n\n  override fun setContentView(layoutResID: Int) {\n    layoutInflater.inflate(layoutResID, sampleContent)\n  }\n\n  override fun setContentView(view: View) {\n    sampleContent.addView(view)\n  }\n\n  override fun setContentView(view: View, params: LayoutParams) {\n    sampleContent.addView(view, params)\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/PicassoSampleAdapter.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.Manifest.permission.POST_NOTIFICATIONS\nimport android.app.Activity\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager.PERMISSION_GRANTED\nimport android.os.Build.VERSION\nimport android.os.Build.VERSION_CODES\nimport android.os.Build.VERSION_CODES.TIRAMISU\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.BaseAdapter\nimport android.widget.RemoteViews\nimport android.widget.TextView\nimport androidx.core.app.ActivityCompat.checkSelfPermission\nimport androidx.core.app.ActivityCompat.requestPermissions\nimport androidx.core.app.NotificationChannelCompat\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport java.util.Random\n\ninternal class PicassoSampleAdapter(context: Context?) : BaseAdapter() {\n  internal enum class Sample(\n    val label: String,\n    private val activityClass: Class<out Activity>?\n  ) {\n    GRID_VIEW(\"Image Grid View\", SampleGridViewActivity::class.java),\n    COMPOSE_UI(\"Compose UI\", SampleComposeActivity::class.java),\n    GALLERY(\"Load from Gallery\", SampleGalleryActivity::class.java),\n    CONTACTS(\"Contact Photos\", SampleContactsActivity::class.java),\n    LIST_DETAIL(\"List / Detail View\", SampleListDetailActivity::class.java),\n    SHOW_NOTIFICATION(\"Sample Notification\", null) {\n      override fun launch(activity: Activity) {\n        val remoteViews = RemoteViews(activity.packageName, R.layout.notification_view)\n\n        val intent = Intent(activity, SampleGridViewActivity::class.java)\n\n        val flags = if (VERSION.SDK_INT >= VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0\n        val notification =\n          NotificationCompat.Builder(activity, CHANNEL_ID)\n            .setSmallIcon(R.drawable.icon)\n            .setContentIntent(PendingIntent.getActivity(activity, -1, intent, flags))\n            .setContent(remoteViews)\n            .setAutoCancel(true)\n            .setChannelId(CHANNEL_ID)\n            .build()\n\n        val notificationManager = NotificationManagerCompat.from(activity)\n\n        val channel = NotificationChannelCompat\n          .Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_DEFAULT)\n          .setName(\"Picasso Notification Channel\")\n        notificationManager.createNotificationChannel(channel.build())\n\n        if (VERSION.SDK_INT >= TIRAMISU &&\n          checkSelfPermission(activity, POST_NOTIFICATIONS) != PERMISSION_GRANTED\n        ) {\n          requestPermissions(activity, arrayOf(POST_NOTIFICATIONS), 200)\n          return\n        }\n        notificationManager.notify(NOTIFICATION_ID, notification)\n\n        // Now load an image for this notification.\n        PicassoInitializer.get()\n          .load(Data.URLS[Random().nextInt(Data.URLS.size)])\n          .resizeDimen(\n            R.dimen.notification_icon_width_height,\n            R.dimen.notification_icon_width_height\n          )\n          .into(remoteViews, R.id.photo, NOTIFICATION_ID, notification)\n      }\n    };\n\n    open fun launch(activity: Activity) {\n      activity.startActivity(Intent(activity, activityClass))\n      activity.finish()\n    }\n  }\n\n  private val inflater: LayoutInflater = LayoutInflater.from(context)\n\n  override fun getCount(): Int = Sample.values().size\n\n  override fun getItem(position: Int): Sample = Sample.values()[position]\n\n  override fun getItemId(position: Int): Long = position.toLong()\n\n  override fun getView(\n    position: Int,\n    convertView: View?,\n    parent: ViewGroup\n  ): View {\n    val view = if (convertView == null) {\n      inflater.inflate(R.layout.picasso_sample_activity_item, parent, false) as TextView\n    } else {\n      convertView as TextView\n    }\n\n    view.text = getItem(position).label\n    return view\n  }\n\n  companion object {\n    private const val NOTIFICATION_ID = 666\n    private const val CHANNEL_ID = \"channel-id\"\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleComposeActivity.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.graphics.Bitmap\nimport android.graphics.Bitmap.Config\nimport android.graphics.Canvas\nimport android.os.Bundle\nimport androidx.compose.foundation.Image\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.aspectRatio\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.lazy.grid.GridCells.Adaptive\nimport androidx.compose.foundation.lazy.grid.LazyVerticalGrid\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.foundation.text.BasicText\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.draw.clip\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.graphics.toArgb\nimport androidx.compose.ui.layout.ContentScale\nimport androidx.compose.ui.platform.ComposeView\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.IntSize\nimport androidx.compose.ui.unit.dp\nimport com.squareup.picasso3.Picasso\nimport com.squareup.picasso3.Picasso.LoadedFrom.MEMORY\nimport com.squareup.picasso3.Request\nimport com.squareup.picasso3.RequestHandler\nimport com.squareup.picasso3.compose.rememberPainter\nimport kotlinx.coroutines.Dispatchers\n\nclass SampleComposeActivity : PicassoSampleActivity() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    val composeView = ComposeView(this)\n\n    val urls = Data.URLS.toMutableList().shuffled() +\n      Data.URLS.toMutableList().shuffled() +\n      Data.URLS.toMutableList().shuffled()\n\n    composeView.setContent {\n      Content(urls)\n    }\n\n    setContentView(composeView)\n  }\n}\n\n@Composable\nfun Content(urls: List<String>, picasso: Picasso = PicassoInitializer.get()) {\n  var contentScale by remember { mutableStateOf(ContentScale.Inside) }\n  var alignment by remember { mutableStateOf(Alignment.Center) }\n\n  Column {\n    ImageGrid(\n      modifier = Modifier.weight(1F),\n      urls = urls,\n      contentScale = contentScale,\n      alignment = alignment,\n      picasso = picasso\n    )\n\n    Options(\n      modifier = Modifier\n        .background(Color.DarkGray)\n        .padding(vertical = 4.dp),\n      onContentScaleSelected = { contentScale = it },\n      onAlignmentSelected = { alignment = it }\n    )\n  }\n}\n\n@Composable\nfun ImageGrid(\n  modifier: Modifier = Modifier,\n  urls: List<String>,\n  contentScale: ContentScale,\n  alignment: Alignment,\n  picasso: Picasso = PicassoInitializer.get()\n) {\n  LazyVerticalGrid(\n    columns = Adaptive(150.dp),\n    modifier = modifier\n  ) {\n    items(urls.size) {\n      val url = urls[it]\n      Image(\n        painter = picasso.rememberPainter(key = url) {\n          it.load(url).placeholder(R.drawable.placeholder).error(R.drawable.error)\n        },\n        contentDescription = null,\n        contentScale = contentScale,\n        alignment = alignment,\n        modifier = Modifier\n          .fillMaxWidth()\n          .aspectRatio(1f)\n      )\n    }\n  }\n}\n\n@Composable\nfun Options(\n  modifier: Modifier = Modifier,\n  onContentScaleSelected: (ContentScale) -> Unit,\n  onAlignmentSelected: (Alignment) -> Unit\n) {\n  var contentScaleKey by remember { mutableStateOf(\"Inside\") }\n  var alignmentKey by remember { mutableStateOf(\"Center\") }\n  Column(modifier = modifier) {\n    CONTENT_SCALES.entries.chunked(4).forEach { entries ->\n      Row(\n        modifier = Modifier\n          .padding(2.dp)\n          .fillMaxWidth(),\n        horizontalArrangement = Arrangement.SpaceEvenly\n      ) {\n        entries.forEach { (key, value) ->\n          OptionText(\n            modifier = Modifier.weight(1F),\n            key = key,\n            selected = contentScaleKey == key,\n            onClick = {\n              contentScaleKey = key\n              onContentScaleSelected(value)\n            }\n          )\n        }\n      }\n    }\n\n    Spacer(modifier = Modifier.height(8.dp))\n\n    ALIGNMENTS.entries.chunked(3).forEach { entries ->\n      Row(\n        modifier = Modifier\n          .padding(2.dp)\n          .fillMaxWidth(),\n        horizontalArrangement = Arrangement.SpaceEvenly\n      ) {\n        entries.forEach { (key, value) ->\n          OptionText(\n            modifier = Modifier.weight(1F),\n            key = key,\n            selected = alignmentKey == key,\n            onClick = {\n              alignmentKey = key\n              onAlignmentSelected(value)\n            }\n          )\n        }\n      }\n    }\n  }\n}\n\n@Composable\nprivate fun OptionText(modifier: Modifier, key: String, selected: Boolean, onClick: () -> Unit) {\n  Box(modifier = modifier) {\n    BasicText(\n      text = key,\n      modifier = Modifier\n        .align(Alignment.Center)\n        .clip(RoundedCornerShape(8.dp))\n        .clickable(onClick = onClick)\n        .background(if (selected) Color.Blue else Color.White)\n        .padding(horizontal = 8.dp, vertical = 4.dp)\n    )\n  }\n}\n\nprivate val CONTENT_SCALES = mapOf(\n  Pair(\"Crop\", ContentScale.Crop),\n  Pair(\"Fit\", ContentScale.Fit),\n  Pair(\"Inside\", ContentScale.Inside),\n  Pair(\"Fill Width\", ContentScale.FillWidth),\n  Pair(\"Fill Height\", ContentScale.FillHeight),\n  Pair(\"Fill Bounds\", ContentScale.FillBounds),\n  Pair(\"None\", ContentScale.None)\n)\n\nprivate val ALIGNMENTS = mapOf(\n  Pair(\"TopStart\", Alignment.TopStart),\n  Pair(\"TopCenter\", Alignment.TopCenter),\n  Pair(\"TopEnd\", Alignment.TopEnd),\n  Pair(\"CenterStart\", Alignment.CenterStart),\n  Pair(\"Center\", Alignment.Center),\n  Pair(\"CenterEnd\", Alignment.CenterEnd),\n  Pair(\"BottomStart\", Alignment.BottomStart),\n  Pair(\"BottomCenter\", Alignment.BottomCenter),\n  Pair(\"BottomEnd\", Alignment.BottomEnd)\n)\n\n@Preview\n@Composable\nprivate fun ContentPreview() {\n  val images = listOf(\n    Color.Blue.toArgb() to IntSize(200, 100),\n    Color.Red.toArgb() to IntSize(100, 200),\n    Color.Green.toArgb() to IntSize(100, 100),\n    Color.Yellow.toArgb() to IntSize(300, 100),\n    Color.Black.toArgb() to IntSize(100, 300),\n    Color.LightGray.toArgb() to IntSize(400, 100),\n    Color.Cyan.toArgb() to IntSize(100, 100),\n    Color.White.toArgb() to IntSize(100, 400)\n  ).associateBy { (color) -> \"https://cash.app/$color.png\" }\n\n  val context = LocalContext.current\n  Content(\n    urls = images.keys.toList(),\n    picasso = remember {\n      Picasso.Builder(context)\n        .callFactory { throw AssertionError() } // Removes network\n        .dispatchers(\n          mainContext = Dispatchers.Unconfined,\n          backgroundContext = Dispatchers.Unconfined\n        )\n        .addRequestHandler(\n          object : RequestHandler() {\n            override fun canHandleRequest(data: Request) = data.uri?.toString()?.run(images::containsKey) == true\n            override fun load(picasso: Picasso, request: Request, callback: Callback) {\n              val (color, size) = images[request.uri!!.toString()]!!\n              val bitmap = Bitmap.createBitmap(size.width, size.height, Config.ARGB_8888).apply {\n                Canvas(this).apply {\n                  drawColor(color)\n                }\n              }\n\n              callback.onSuccess(Result.Bitmap(bitmap, MEMORY))\n            }\n          }\n        )\n        .build()\n    }\n  )\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleContactsActivity.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.Manifest.permission.READ_CONTACTS\nimport android.content.pm.PackageManager.PERMISSION_GRANTED\nimport android.database.Cursor\nimport android.net.Uri\nimport android.os.Bundle\nimport android.provider.ContactsContract.Contacts\nimport android.widget.ListView\nimport android.widget.Toast\nimport androidx.core.app.ActivityCompat.checkSelfPermission\nimport androidx.core.app.ActivityCompat.requestPermissions\nimport androidx.loader.app.LoaderManager\nimport androidx.loader.app.LoaderManager.LoaderCallbacks\nimport androidx.loader.content.CursorLoader\nimport androidx.loader.content.Loader\n\nclass SampleContactsActivity : PicassoSampleActivity(), LoaderCallbacks<Cursor> {\n  private lateinit var adapter: SampleContactsAdapter\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.sample_contacts_activity)\n\n    adapter = SampleContactsAdapter(this)\n\n    findViewById<ListView>(android.R.id.list).apply {\n      adapter = this@SampleContactsActivity.adapter\n      setOnScrollListener(SampleScrollListener(this@SampleContactsActivity))\n    }\n\n    if (checkSelfPermission(this, READ_CONTACTS) == PERMISSION_GRANTED) {\n      loadContacts()\n    } else {\n      requestPermissions(this, arrayOf(READ_CONTACTS), REQUEST_READ_CONTACTS)\n    }\n  }\n\n  private fun loadContacts() {\n    LoaderManager.getInstance(this).initLoader(ContactsQuery.QUERY_ID, null, this)\n  }\n\n  override fun onRequestPermissionsResult(\n    requestCode: Int,\n    permissions: Array<String>,\n    grantResults: IntArray\n  ) {\n    if (requestCode == REQUEST_READ_CONTACTS) {\n      if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED) {\n        loadContacts()\n      } else {\n        Toast\n          .makeText(this, \"Read contacts permission denied\", Toast.LENGTH_LONG)\n          .show()\n        finish()\n      }\n    } else {\n      super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n    }\n  }\n\n  override fun onCreateLoader(\n    id: Int,\n    args: Bundle?\n  ): Loader<Cursor> {\n    return if (id == ContactsQuery.QUERY_ID) {\n      CursorLoader(\n        this,\n        ContactsQuery.CONTENT_URI,\n        ContactsQuery.PROJECTION,\n        ContactsQuery.SELECTION,\n        null,\n        ContactsQuery.SORT_ORDER\n      )\n    } else {\n      throw RuntimeException(\"this shouldn't happen\")\n    }\n  }\n\n  override fun onLoadFinished(\n    loader: Loader<Cursor>,\n    data: Cursor\n  ) {\n    adapter.swapCursor(data)\n  }\n\n  override fun onLoaderReset(loader: Loader<Cursor>) {\n    adapter.swapCursor(null)\n  }\n\n  internal interface ContactsQuery {\n    companion object {\n      const val QUERY_ID = 1\n\n      val CONTENT_URI: Uri = Contacts.CONTENT_URI\n\n      const val SELECTION =\n        \"${Contacts.DISPLAY_NAME_PRIMARY}<>'' AND ${Contacts.IN_VISIBLE_GROUP}=1\"\n\n      const val SORT_ORDER = Contacts.SORT_KEY_PRIMARY\n\n      val PROJECTION = arrayOf(\n        Contacts._ID,\n        Contacts.LOOKUP_KEY,\n        Contacts.DISPLAY_NAME_PRIMARY,\n        Contacts.PHOTO_THUMBNAIL_URI,\n        SORT_ORDER\n      )\n\n      const val ID = 0\n      const val LOOKUP_KEY = 1\n      const val DISPLAY_NAME = 2\n    }\n  }\n\n  companion object {\n    private const val REQUEST_READ_CONTACTS = 123\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleContactsAdapter.kt",
    "content": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.content.Context\nimport android.database.Cursor\nimport android.provider.ContactsContract.Contacts\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.QuickContactBadge\nimport android.widget.TextView\nimport androidx.cursoradapter.widget.CursorAdapter\nimport com.example.picasso.SampleContactsActivity.ContactsQuery\n\ninternal class SampleContactsAdapter(context: Context) : CursorAdapter(context, null, 0) {\n  private val inflater = LayoutInflater.from(context)\n\n  override fun newView(\n    context: Context,\n    cursor: Cursor,\n    viewGroup: ViewGroup\n  ): View {\n    val itemLayout = inflater.inflate(R.layout.sample_contacts_activity_item, viewGroup, false)\n    itemLayout.tag = ViewHolder(\n      text1 = itemLayout.findViewById(android.R.id.text1),\n      icon = itemLayout.findViewById(android.R.id.icon)\n    )\n    return itemLayout\n  }\n\n  override fun bindView(\n    view: View,\n    context: Context,\n    cursor: Cursor\n  ) {\n    val contactUri = Contacts.getLookupUri(\n      cursor.getLong(ContactsQuery.ID),\n      cursor.getString(ContactsQuery.LOOKUP_KEY)\n    )\n    val holder = (view.tag as ViewHolder).apply {\n      text1.text = cursor.getString(ContactsQuery.DISPLAY_NAME)\n      icon.assignContactUri(contactUri)\n    }\n\n    PicassoInitializer.get()\n      .load(contactUri)\n      .placeholder(R.drawable.contact_picture_placeholder)\n      .tag(context)\n      .into(holder.icon)\n  }\n\n  override fun getCount(): Int {\n    return if (cursor == null) 0 else super.getCount()\n  }\n\n  private class ViewHolder(\n    val text1: TextView,\n    val icon: QuickContactBadge\n  )\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleGalleryActivity.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.os.Bundle\nimport android.provider.MediaStore.Images.Media\nimport android.view.View\nimport android.widget.ImageView\nimport android.widget.ViewAnimator\nimport com.squareup.picasso3.Callback.EmptyCallback\n\nclass SampleGalleryActivity : PicassoSampleActivity() {\n  private lateinit var imageView: ImageView\n  lateinit var animator: ViewAnimator\n\n  private var image: String? = null\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.sample_gallery_activity)\n\n    animator = findViewById(R.id.animator)\n    imageView = findViewById(R.id.image)\n\n    findViewById<View>(R.id.go).setOnClickListener {\n      val gallery = Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI)\n      startActivityForResult(gallery, GALLERY_REQUEST)\n    }\n\n    if (savedInstanceState != null) {\n      image = savedInstanceState.getString(KEY_IMAGE)\n      if (image != null) {\n        loadImage()\n      }\n    }\n  }\n\n  override fun onSaveInstanceState(outState: Bundle) {\n    super.onSaveInstanceState(outState)\n    outState.putString(KEY_IMAGE, image)\n  }\n\n  override fun onActivityResult(\n    requestCode: Int,\n    resultCode: Int,\n    data: Intent?\n  ) {\n    if (requestCode == GALLERY_REQUEST && resultCode == Activity.RESULT_OK && data != null) {\n      image = data.data.toString()\n      loadImage()\n    } else {\n      super.onActivityResult(requestCode, resultCode, data)\n    }\n  }\n\n  private fun loadImage() {\n    // Index 1 is the progress bar. Show it while we're loading the image.\n    animator.displayedChild = 1\n\n    PicassoInitializer.get()\n      .load(image)\n      .fit()\n      .centerInside()\n      .into(\n        imageView,\n        object : EmptyCallback() {\n          override fun onSuccess() {\n            // Index 0 is the image view.\n            animator.displayedChild = 0\n          }\n        }\n      )\n  }\n\n  companion object {\n    private const val GALLERY_REQUEST = 9391\n    private const val KEY_IMAGE = \"com.example.picasso:image\"\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleGridViewActivity.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.os.Bundle\nimport android.widget.GridView\n\nclass SampleGridViewActivity : PicassoSampleActivity() {\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.sample_gridview_activity)\n\n    findViewById<GridView>(R.id.grid_view).apply {\n      adapter = SampleGridViewAdapter(this@SampleGridViewActivity)\n      setOnScrollListener(SampleScrollListener(this@SampleGridViewActivity))\n    }\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleGridViewAdapter.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.content.Context\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.BaseAdapter\nimport android.widget.ImageView.ScaleType.CENTER_CROP\n\ninternal class SampleGridViewAdapter(private val context: Context) : BaseAdapter() {\n  private val urls: List<String>\n\n  init {\n    // Ensure we get a different ordering of images on each run.\n    val tmpList = Data.URLS.toMutableList()\n    tmpList.shuffle()\n\n    // Triple up the list.\n    urls = listOf(tmpList, tmpList, tmpList).flatten()\n  }\n\n  override fun getView(\n    position: Int,\n    convertView: View?,\n    parent: ViewGroup\n  ): View {\n    val view = convertView as? SquaredImageView ?: SquaredImageView(context).apply {\n      scaleType = CENTER_CROP\n    }\n\n    // Get the image URL for the current position.\n    val url = getItem(position)\n\n    // Trigger the download of the URL asynchronously into the image view.\n    PicassoInitializer.get()\n      .load(url)\n      .placeholder(R.drawable.placeholder)\n      .error(R.drawable.error)\n      .fit()\n      .tag(context)\n      .into(view)\n\n    return view\n  }\n\n  override fun getCount(): Int = urls.size\n\n  override fun getItem(position: Int): String = urls[position]\n\n  override fun getItemId(position: Int): Long = position.toLong()\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleListDetailActivity.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.AdapterView.OnItemClickListener\nimport android.widget.ImageView\nimport android.widget.ListView\nimport android.widget.TextView\nimport androidx.fragment.app.Fragment\n\nclass SampleListDetailActivity : PicassoSampleActivity() {\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n\n    if (savedInstanceState == null) {\n      supportFragmentManager\n        .beginTransaction()\n        .add(R.id.sample_content, ListFragment.newInstance())\n        .commit()\n    }\n  }\n\n  fun showDetails(url: String) {\n    supportFragmentManager\n      .beginTransaction()\n      .replace(R.id.sample_content, DetailFragment.newInstance(url))\n      .addToBackStack(null)\n      .commit()\n  }\n\n  class ListFragment : Fragment() {\n    override fun onCreateView(\n      inflater: LayoutInflater,\n      container: ViewGroup?,\n      savedInstanceState: Bundle?\n    ): View? {\n      val activity = activity as SampleListDetailActivity\n      val adapter = SampleListDetailAdapter(activity)\n      val listView = LayoutInflater.from(activity)\n        .inflate(R.layout.sample_list_detail_list, container, false) as ListView\n\n      listView.adapter = adapter\n      listView.setOnScrollListener(SampleScrollListener(activity))\n      listView.onItemClickListener = OnItemClickListener { _, _, position, _ ->\n        val url = adapter.getItem(position)\n        activity.showDetails(url)\n      }\n\n      return listView\n    }\n\n    companion object {\n      fun newInstance(): ListFragment {\n        return ListFragment()\n      }\n    }\n  }\n\n  class DetailFragment : Fragment() {\n    override fun onCreateView(\n      inflater: LayoutInflater,\n      container: ViewGroup?,\n      savedInstanceState: Bundle?\n    ): View? {\n      val activity = activity as SampleListDetailActivity\n      val view = LayoutInflater.from(activity)\n        .inflate(R.layout.sample_list_detail_detail, container, false)\n\n      val urlView = view.findViewById<TextView>(R.id.url)\n      val imageView = view.findViewById<ImageView>(R.id.photo)\n\n      val url = requireArguments().getString(KEY_URL)\n      urlView.text = url\n      PicassoInitializer.get()\n        .load(url)\n        .fit()\n        .tag(activity)\n        .into(imageView)\n\n      return view\n    }\n\n    companion object {\n      private const val KEY_URL = \"picasso:url\"\n\n      fun newInstance(url: String): DetailFragment {\n        return DetailFragment().apply {\n          arguments = Bundle().apply { putString(KEY_URL, url) }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleListDetailAdapter.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.BaseAdapter\nimport android.widget.ImageView\nimport android.widget.TextView\n\ninternal class SampleListDetailAdapter(private val context: Context) : BaseAdapter() {\n  private val layoutInflater = LayoutInflater.from(context)\n  private val urls = Data.URLS.toList()\n\n  override fun getView(\n    position: Int,\n    view: View?,\n    parent: ViewGroup\n  ): View {\n    val newView: View\n    val holder: ViewHolder\n    if (view == null) {\n      newView = layoutInflater.inflate(R.layout.sample_list_detail_item, parent, false)\n      holder = ViewHolder(\n        image = newView.findViewById(R.id.photo),\n        text = newView.findViewById(R.id.url)\n      )\n      newView.tag = holder\n    } else {\n      newView = view\n      holder = newView.tag as ViewHolder\n    }\n\n    // Get the image URL for the current position.\n    val url = getItem(position)\n    holder.text.text = url\n\n    // Trigger the download of the URL asynchronously into the image view.\n    PicassoInitializer.get()\n      .load(url)\n      .placeholder(R.drawable.placeholder)\n      .error(R.drawable.error)\n      .resizeDimen(R.dimen.list_detail_image_size, R.dimen.list_detail_image_size)\n      .centerInside()\n      .tag(context)\n      .into(holder.image)\n\n    return newView\n  }\n\n  override fun getCount(): Int = urls.size\n\n  override fun getItem(position: Int): String = urls[position]\n\n  override fun getItemId(position: Int): Long = position.toLong()\n\n  internal class ViewHolder(\n    val image: ImageView,\n    val text: TextView\n  )\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleScrollListener.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.content.Context\nimport android.widget.AbsListView\nimport android.widget.AbsListView.OnScrollListener.SCROLL_STATE_IDLE\nimport android.widget.AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL\n\nclass SampleScrollListener(private val context: Context) : AbsListView.OnScrollListener {\n\n  override fun onScrollStateChanged(\n    view: AbsListView,\n    scrollState: Int\n  ) {\n    val picasso = PicassoInitializer.get()\n    when (scrollState) {\n      SCROLL_STATE_IDLE, SCROLL_STATE_TOUCH_SCROLL -> picasso.resumeTag(context)\n      else -> picasso.pauseTag(context)\n    }\n  }\n\n  override fun onScroll(\n    view: AbsListView,\n    firstVisibleItem: Int,\n    visibleItemCount: Int,\n    totalItemCount: Int\n  ) = Unit\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleWidgetProvider.kt",
    "content": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.appwidget.AppWidgetManager\nimport android.appwidget.AppWidgetProvider\nimport android.content.Context\nimport android.widget.RemoteViews\nimport java.util.Random\n\nclass SampleWidgetProvider : AppWidgetProvider() {\n\n  override fun onUpdate(\n    context: Context,\n    appWidgetManager: AppWidgetManager,\n    appWidgetIds: IntArray\n  ) {\n    val updateViews = RemoteViews(context.packageName, R.layout.sample_widget)\n\n    // Load image for all appWidgetIds.\n    val picasso = PicassoInitializer.get()\n    picasso.load(Data.URLS[Random().nextInt(Data.URLS.size)])\n      .placeholder(R.drawable.placeholder)\n      .error(R.drawable.error)\n      .transform(GrayscaleTransformation(picasso))\n      .into(updateViews, R.id.image, appWidgetIds)\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SquaredImageView.kt",
    "content": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.example.picasso\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.widget.ImageView\n\n/** An image view which always remains square with respect to its width.  */\nclass SquaredImageView @JvmOverloads constructor(\n  context: Context,\n  attrs: AttributeSet? = null\n) : ImageView(context, attrs) {\n  override fun onMeasure(\n    widthMeasureSpec: Int,\n    heightMeasureSpec: Int\n  ) {\n    super.onMeasure(widthMeasureSpec, heightMeasureSpec)\n    setMeasuredDimension(measuredWidth, measuredWidth)\n  }\n}\n"
  },
  {
    "path": "picasso-sample/src/main/res/drawable/button_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item android:state_window_focused=\"false\" android:state_enabled=\"true\"\n      android:drawable=\"@drawable/button_normal\"/>\n  <item android:state_window_focused=\"false\" android:state_enabled=\"false\"\n      android:drawable=\"@drawable/button_disabled\"/>\n  <item android:state_pressed=\"true\"\n      android:drawable=\"@drawable/button_pressed\"/>\n  <item android:state_focused=\"true\" android:state_enabled=\"true\"\n      android:drawable=\"@drawable/button_focused\"/>\n  <item android:state_enabled=\"true\"\n      android:drawable=\"@drawable/button_normal\"/>\n  <item android:state_focused=\"true\"\n      android:drawable=\"@drawable/button_disabled_focused\"/>\n  <item\n      android:drawable=\"@drawable/button_disabled\"/>\n</selector>\n"
  },
  {
    "path": "picasso-sample/src/main/res/drawable/list_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item android:state_window_focused=\"false\" android:drawable=\"@android:color/transparent\"/>\n\n  <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->\n  <item android:state_focused=\"true\" android:state_enabled=\"false\" android:state_pressed=\"true\"\n      android:drawable=\"@drawable/list_selector_disabled\"/>\n  <item android:state_focused=\"true\" android:state_enabled=\"false\"\n      android:drawable=\"@drawable/list_selector_disabled\"/>\n  <item android:state_focused=\"true\" android:state_pressed=\"true\"\n      android:drawable=\"@drawable/list_pressed\"/>\n  <item android:state_focused=\"false\" android:state_pressed=\"true\"\n      android:drawable=\"@drawable/list_pressed\"/>\n  <item android:state_focused=\"true\" android:drawable=\"@drawable/list_focused\"/>\n</selector>\n"
  },
  {
    "path": "picasso-sample/src/main/res/drawable/overlay_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item android:state_pressed=\"true\" android:drawable=\"@color/overlay_selector_pressed\"/>\n  <item android:drawable=\"@android:color/transparent\"/>\n</selector>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/notification_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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:orientation=\"horizontal\"\n    tools:ignore=\"UseCompoundDrawables\"\n    >\n  <ImageView\n      android:id=\"@+id/photo\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:contentDescription=\"@string/sample_notification\"\n      />\n  <TextView\n      android:layout_width=\"0dp\"\n      android:layout_height=\"wrap_content\"\n      android:layout_weight=\"1\"\n      android:layout_marginLeft=\"8dp\"\n      android:layout_marginStart=\"8dp\"\n      android:layout_gravity=\"center_vertical\"\n      android:textAppearance=\"@style/TextAppearance.Compat.Notification\"\n      android:text=\"@string/sample_notification\"\n      />\n</LinearLayout>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/picasso_sample_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<merge xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\">\n  <FrameLayout\n      android:id=\"@+id/sample_content\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      />\n  <ListView\n      android:id=\"@+id/activity_list\"\n      android:orientation=\"vertical\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:paddingTop=\"@dimen/faux_action_bar_size\"\n      android:listSelector=\"@drawable/overlay_selector\"\n      android:divider=\"@null\"\n      android:visibility=\"gone\"\n      style=\"@style/Widget.PicassoSample.Overlay\"\n      />\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"@dimen/faux_action_bar_size\"\n      android:orientation=\"horizontal\"\n      style=\"@style/Widget.PicassoSample.Overlay\">\n    <TextView\n        android:layout_width=\"0dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:text=\"@string/app_name\"\n        style=\"@style/Widget.PicassoSample.ActionBarTitle\"\n        />\n    <ToggleButton\n        android:id=\"@+id/faux_action_bar_control\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:textOff=\"@string/more\"\n        android:textOn=\"@string/hide\"\n        style=\"@style/Widget.PicassoSample.ActionBarButton\"\n        />\n  </LinearLayout>\n</merge>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/picasso_sample_activity_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    style=\"@style/Widget.PicassoSample.ListItem\"/>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_contacts_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@android:id/list\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingTop=\"@dimen/faux_action_bar_size\"\n    android:clipToPadding=\"false\"/>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_contacts_activity_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright (C) 2013 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=\"?android:attr/listPreferredItemHeight\"\n    android:orientation=\"horizontal\">\n\n  <QuickContactBadge android:id=\"@android:id/icon\"\n      android:layout_height=\"?android:attr/listPreferredItemHeight\"\n      android:layout_width=\"?android:attr/listPreferredItemHeight\"\n      android:scaleType=\"centerCrop\"/>\n\n  <TextView android:id=\"@android:id/text1\"\n      android:paddingLeft=\"8dp\"\n      android:paddingRight=\"8dp\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:gravity=\"start|center_vertical\"\n      android:fontFamily=\"sans-serif-light\"\n      android:singleLine=\"true\"\n      android:ellipsize=\"end\"\n      android:textAppearance=\"?android:attr/textAppearanceLarge\"\n      tools:ignore=\"UnusedAttribute\"\n      />\n\n</LinearLayout>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_gallery_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<merge xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n  <ViewAnimator\n      android:id=\"@+id/animator\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"match_parent\"\n      android:background=\"#ffc0c0c0\"\n      android:animateFirstView=\"false\"\n      >\n    <ImageView\n        android:id=\"@+id/image\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:contentDescription=\"@string/sample_gallery\"\n        />\n    <ProgressBar\n        android:id=\"@+id/progress\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        />\n  </ViewAnimator>\n\n  <Button\n      android:id=\"@+id/go\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:layout_gravity=\"bottom\"\n      android:layout_marginLeft=\"4dp\"\n      android:layout_marginRight=\"4dp\"\n      android:layout_marginBottom=\"4dp\"\n      android:text=\"@string/select_picture\"\n      />\n</merge>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_gridview_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<GridView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/grid_view\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:numColumns=\"@integer/column_count\"\n    android:scrollbarStyle=\"insideOverlay\"\n    android:scrollbars=\"none\"\n    android:listSelector=\"@null\"\n    />\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_list_detail_detail.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<ScrollView 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/faux_action_bar_size\">\n  <LinearLayout\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:orientation=\"vertical\"\n      android:padding=\"16dp\"\n      >\n    <TextView\n        android:id=\"@+id/url\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"16dp\"\n        android:gravity=\"center\"\n        style=\"@style/Widget.PicassoSample.DescriptionUrl\"\n        />\n    <com.example.picasso.SquaredImageView\n        android:id=\"@+id/photo\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        />\n  </LinearLayout>\n</ScrollView>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_list_detail_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\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:orientation=\"horizontal\"\n    android:padding=\"8dp\"\n    tools:ignore=\"UseCompoundDrawables\"\n    >\n  <ImageView\n      android:id=\"@+id/photo\"\n      android:layout_width=\"@dimen/list_detail_image_size\"\n      android:layout_height=\"@dimen/list_detail_image_size\"\n      android:contentDescription=\"@string/sample_list_item\"\n      />\n  <TextView\n      android:id=\"@+id/url\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"wrap_content\"\n      android:layout_weight=\"1\"\n      android:layout_marginLeft=\"8dp\"\n      android:layout_marginStart=\"8dp\"\n      android:layout_gravity=\"center_vertical\"\n      />\n</LinearLayout>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_list_detail_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<ListView 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/faux_action_bar_size\"\n    android:clipToPadding=\"false\"/>\n"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_widget.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/image\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:contentDescription=\"@string/sample_widget\"\n    />\n"
  },
  {
    "path": "picasso-sample/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"overlay_selector_pressed\">#40000000</color>\n  <color name=\"window_background\">#ff202020</color>\n  <color name=\"list_divider\">#ff555555</color>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <dimen name=\"faux_action_bar_size\">48dp</dimen>\n  <dimen name=\"list_detail_image_size\">60dp</dimen>\n  <dimen name=\"widget_min_width\">110dp</dimen>\n  <dimen name=\"widget_min_height\">110dp</dimen>\n  <dimen name=\"notification_icon_width_height\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values/integers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <integer name=\"column_count\">2</integer>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <string name=\"app_name\">Picasso Samples</string>\n  <string name=\"hide\">HIDE</string>\n  <string name=\"more\">MORE</string>\n  <string name=\"sample_gallery\">Picasso Sample Gallery</string>\n  <string name=\"sample_list_item\">Picasso Sample List Item</string>\n  <string name=\"sample_widget\">Picasso Sample Widget</string>\n  <string name=\"sample_notification\">Picasso Sample Notification</string>\n  <string name=\"select_picture\">Select Picture</string>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n  <style name=\"Widget.PicassoSample.Button\" parent=\"android:Widget.Button\">\n    <item name=\"android:background\">@drawable/button_selector</item>\n    <item name=\"android:minHeight\">48dip</item>\n    <item name=\"android:minWidth\">64dip</item>\n    <item name=\"android:textColor\">#000000</item>\n  </style>\n\n  <style name=\"Widget.PicassoSample.Overlay\" parent=\"android:Widget\">\n    <item name=\"android:background\">#90000000</item>\n  </style>\n\n  <style name=\"Widget.PicassoSample.ActionBarTitle\" parent=\"android:Widget.TextView\">\n    <item name=\"android:paddingLeft\">8dp</item>\n    <item name=\"android:paddingRight\">8dp</item>\n    <!-- Use 'dp' so that the user's font preference doesn't affect the action bar. -->\n    <item name=\"android:textSize\" tools:ignore=\"SpUsage\">19dp</item>\n    <item name=\"android:textColor\">#ffffffff</item>\n    <item name=\"android:gravity\">center_vertical</item>\n    <item name=\"android:singleLine\">true</item>\n    <item name=\"android:ellipsize\">end</item>\n    <item name=\"android:fontFamily\">sans-serif-light</item>\n    <item name=\"android:textStyle\">italic</item>\n  </style>\n\n  <style name=\"Widget.PicassoSample.ActionBarButton\" parent=\"android:Widget.Button\">\n    <item name=\"android:gravity\">center_vertical</item>\n    <item name=\"android:paddingLeft\">16dp</item>\n    <item name=\"android:paddingRight\">16dp</item>\n    <item name=\"android:textColor\">#ffffffff</item>\n    <!-- Use 'dp' so that the user's font preference doesn't affect the action bar. -->\n    <item name=\"android:textSize\" tools:ignore=\"SpUsage\">13dp</item>\n    <item name=\"android:background\">@drawable/overlay_selector</item>\n  </style>\n\n  <style name=\"Widget.PicassoSample.ListView\" parent=\"android:Widget.ListView\">\n    <item name=\"android:listSelector\">@drawable/list_selector</item>\n    <item name=\"android:divider\">@color/list_divider</item>\n  </style>\n\n  <style name=\"Widget.PicassoSample.ListItem\" parent=\"android:Widget.TextView\">\n    <item name=\"android:minHeight\">50dp</item>\n    <item name=\"android:padding\">12dp</item>\n    <item name=\"android:gravity\">left|center_vertical</item>\n    <item name=\"android:textSize\">16sp</item>\n    <item name=\"android:textColor\">#ffffffff</item>\n  </style>\n\n  <style name=\"Widget.PicassoSample.DescriptionUrl\" parent=\"android:Widget.TextView\">\n    <item name=\"android:textSize\">15sp</item>\n  </style>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<resources>\n  <style name=\"Theme.PicassoSample\" parent=\"android:Theme.NoTitleBar\">\n    <item name=\"android:windowBackground\">@color/window_background</item>\n    <item name=\"android:buttonStyle\">@style/Widget.PicassoSample.Button</item>\n    <item name=\"android:listViewStyle\">@style/Widget.PicassoSample.ListView</item>\n    <item name=\"android:textColor\">#ffe0e0e0</item>\n  </style>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values-land/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <dimen name=\"faux_action_bar_size\">40dp</dimen>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values-w500dp/integers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <integer name=\"column_count\">3</integer>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values-w600dp/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <dimen name=\"faux_action_bar_size\">56dp</dimen>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values-w600dp/integers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <integer name=\"column_count\">4</integer>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/values-w700dp/integers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <integer name=\"column_count\">5</integer>\n</resources>\n"
  },
  {
    "path": "picasso-sample/src/main/res/xml/sample_widget_info.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:minWidth=\"@dimen/widget_min_width\"\n    android:minHeight=\"@dimen/widget_min_height\"\n    android:updatePeriodMillis=\"86400000\"\n    android:initialLayout=\"@layout/sample_widget\"\n    android:widgetCategory=\"home_screen\"\n    tools:ignore=\"UnusedAttribute\"/>\n"
  },
  {
    "path": "picasso-stats/api/picasso-stats.api",
    "content": "public final class com/squareup/picasso3/stats/StatsEventListener : com/squareup/picasso3/EventListener {\n\tpublic fun <init> ()V\n\tpublic fun bitmapDecoded (Landroid/graphics/Bitmap;)V\n\tpublic fun bitmapTransformed (Landroid/graphics/Bitmap;)V\n\tpublic fun cacheHit ()V\n\tpublic fun cacheMaxSize (I)V\n\tpublic fun cacheMiss ()V\n\tpublic fun cacheSize (I)V\n\tpublic fun close ()V\n\tpublic fun downloadFinished (J)V\n\tpublic final fun getSnapshot ()Lcom/squareup/picasso3/stats/StatsEventListener$Snapshot;\n}\n\npublic final class com/squareup/picasso3/stats/StatsEventListener$Snapshot {\n\tpublic fun <init> (IIJJJJJDDDIIIJ)V\n\tpublic final fun component1 ()I\n\tpublic final fun component10 ()D\n\tpublic final fun component11 ()I\n\tpublic final fun component12 ()I\n\tpublic final fun component13 ()I\n\tpublic final fun component14 ()J\n\tpublic final fun component2 ()I\n\tpublic final fun component3 ()J\n\tpublic final fun component4 ()J\n\tpublic final fun component5 ()J\n\tpublic final fun component6 ()J\n\tpublic final fun component7 ()J\n\tpublic final fun component8 ()D\n\tpublic final fun component9 ()D\n\tpublic final fun copy (IIJJJJJDDDIIIJ)Lcom/squareup/picasso3/stats/StatsEventListener$Snapshot;\n\tpublic static synthetic fun copy$default (Lcom/squareup/picasso3/stats/StatsEventListener$Snapshot;IIJJJJJDDDIIIJILjava/lang/Object;)Lcom/squareup/picasso3/stats/StatsEventListener$Snapshot;\n\tpublic final fun dump ()V\n\tpublic final fun dump (Lokio/BufferedSink;)V\n\tpublic fun equals (Ljava/lang/Object;)Z\n\tpublic final fun getAverageDownloadSize ()D\n\tpublic final fun getAverageOriginalBitmapSize ()D\n\tpublic final fun getAverageTransformedBitmapSize ()D\n\tpublic final fun getCacheHits ()J\n\tpublic final fun getCacheMisses ()J\n\tpublic final fun getDownloadCount ()I\n\tpublic final fun getMaxSize ()I\n\tpublic final fun getOriginalBitmapCount ()I\n\tpublic final fun getSize ()I\n\tpublic final fun getTimeStamp ()J\n\tpublic final fun getTotalDownloadSize ()J\n\tpublic final fun getTotalOriginalBitmapSize ()J\n\tpublic final fun getTotalTransformedBitmapSize ()J\n\tpublic final fun getTransformedBitmapCount ()I\n\tpublic fun hashCode ()I\n\tpublic fun toString ()Ljava/lang/String;\n}\n\n"
  },
  {
    "path": "picasso-stats/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'com.vanniktech.maven.publish'\n\nandroid {\n  namespace 'com.squareup.picasso3.stats'\n\n  compileSdkVersion libs.versions.compileSdk.get() as int\n\n  defaultConfig {\n    minSdkVersion libs.versions.minSdk.get() as int\n  }\n\n  compileOptions {\n    sourceCompatibility libs.versions.javaTarget.get()\n    targetCompatibility libs.versions.javaTarget.get()\n  }\n\n  kotlinOptions {\n    jvmTarget = libs.versions.javaTarget.get()\n  }\n\n  lintOptions {\n    textOutput 'stdout'\n    textReport true\n    lintConfig rootProject.file('lint.xml')\n  }\n}\n\ndependencies {\n  implementation libs.androidx.core\n  api libs.okio\n\n  api projects.picasso\n}\n"
  },
  {
    "path": "picasso-stats/gradle.properties",
    "content": "POM_ARTIFACT_ID=picasso-stats\nPOM_NAME=Picasso Stats Event Listener\nPOM_DESCRIPTION=An event listener which records Picasso stats\nPOM_PACKAGING=aar\n"
  },
  {
    "path": "picasso-stats/src/main/java/com/squareup/picasso3/stats/StatsEventListener.kt",
    "content": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.squareup.picasso3.stats\n\nimport android.graphics.Bitmap\nimport android.util.Log\nimport com.squareup.picasso3.EventListener\nimport com.squareup.picasso3.TAG\nimport okio.Buffer\nimport okio.BufferedSink\nimport java.io.IOException\nimport kotlin.math.ceil\n\nclass StatsEventListener : EventListener {\n  private var maxCacheSize = 0\n  private var cacheSize = 0\n\n  private var cacheHits = 0L\n  private var cacheMisses = 0L\n  private var totalDownloadSize = 0L\n  private var totalOriginalBitmapSize = 0L\n  private var totalTransformedBitmapSize = 0L\n\n  private var averageDownloadSize = 0.0\n  private var averageOriginalBitmapSize = 0.0\n  private var averageTransformedBitmapSize = 0.0\n\n  private var downloadCount = 0\n  private var originalBitmapCount = 0\n  private var transformedBitmapCount = 0\n\n  override fun cacheMaxSize(maxSize: Int) {\n    maxCacheSize = maxSize\n  }\n\n  override fun cacheSize(size: Int) {\n    cacheSize = size\n  }\n\n  override fun cacheHit() {\n    cacheHits++\n  }\n\n  override fun cacheMiss() {\n    cacheMisses++\n  }\n\n  override fun downloadFinished(size: Long) {\n    downloadCount++\n    totalDownloadSize += size\n    averageDownloadSize = average(downloadCount, totalDownloadSize)\n  }\n\n  override fun bitmapDecoded(bitmap: Bitmap) {\n    val bitmapSize = bitmap.allocationByteCount\n\n    originalBitmapCount++\n    totalOriginalBitmapSize += bitmapSize\n    averageOriginalBitmapSize = average(originalBitmapCount, totalOriginalBitmapSize)\n  }\n\n  override fun bitmapTransformed(bitmap: Bitmap) {\n    val bitmapSize = bitmap.allocationByteCount\n\n    transformedBitmapCount++\n    totalTransformedBitmapSize += bitmapSize\n    averageTransformedBitmapSize = average(originalBitmapCount, totalTransformedBitmapSize)\n  }\n\n  fun getSnapshot() = Snapshot(\n    maxCacheSize, cacheSize, cacheHits, cacheMisses,\n    totalDownloadSize, totalOriginalBitmapSize, totalTransformedBitmapSize, averageDownloadSize,\n    averageOriginalBitmapSize, averageTransformedBitmapSize, downloadCount, originalBitmapCount,\n    transformedBitmapCount, System.currentTimeMillis()\n  )\n\n  private fun average(\n    count: Int,\n    totalSize: Long\n  ): Double = totalSize * 1.0 / count\n\n  data class Snapshot(\n    val maxSize: Int,\n    val size: Int,\n    val cacheHits: Long,\n    val cacheMisses: Long,\n    val totalDownloadSize: Long,\n    val totalOriginalBitmapSize: Long,\n    val totalTransformedBitmapSize: Long,\n    val averageDownloadSize: Double,\n    val averageOriginalBitmapSize: Double,\n    val averageTransformedBitmapSize: Double,\n    val downloadCount: Int,\n    val originalBitmapCount: Int,\n    val transformedBitmapCount: Int,\n    val timeStamp: Long\n  ) {\n    /** Prints out this [Snapshot] into log.  */\n    fun dump() {\n      val buffer = Buffer()\n      try {\n        dump(buffer)\n      } catch (e: IOException) {\n        throw AssertionError(e)\n      }\n\n      Log.i(TAG, buffer.readUtf8())\n    }\n\n    /** Writes this [Snapshot] to the provided [BufferedSink].  */\n    @Throws(IOException::class)\n    fun dump(sink: BufferedSink) {\n      sink.writeUtf8(\"===============BEGIN PICASSO STATS ===============\")\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"Memory Cache Stats\")\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Max Cache Size: \")\n      sink.writeUtf8(maxSize.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Cache Size: \")\n      sink.writeUtf8(size.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Cache % Full: \")\n      sink.writeUtf8(ceil((size.toDouble() / maxSize * 100)).toInt().toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Cache Hits: \")\n      sink.writeUtf8(cacheHits.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Cache Misses: \")\n      sink.writeUtf8(cacheMisses.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"Network Stats\")\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Download Count: \")\n      sink.writeUtf8(downloadCount.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Total Download Size: \")\n      sink.writeUtf8(totalDownloadSize.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Average Download Size: \")\n      sink.writeUtf8(averageDownloadSize.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"Bitmap Stats\")\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Total Bitmaps Decoded: \")\n      sink.writeUtf8(originalBitmapCount.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Total Bitmap Size: \")\n      sink.writeUtf8(totalOriginalBitmapSize.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Total Transformed Bitmaps: \")\n      sink.writeUtf8(transformedBitmapCount.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Total Transformed Bitmap Size: \")\n      sink.writeUtf8(totalTransformedBitmapSize.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Average Bitmap Size: \")\n      sink.writeUtf8(averageOriginalBitmapSize.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"  Average Transformed Bitmap Size: \")\n      sink.writeUtf8(averageTransformedBitmapSize.toString())\n      sink.writeUtf8(\"\\n\")\n      sink.writeUtf8(\"===============END PICASSO STATS ===============\")\n      sink.writeUtf8(\"\\n\")\n    }\n  }\n}\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:base\"\n  ]\n}\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = 'picasso-root'\n\ninclude 'picasso'\ninclude 'picasso-compose'\ninclude 'picasso-paparazzi-sample'\ninclude 'picasso-pollexor'\ninclude 'picasso-sample'\ninclude 'picasso-stats'\n\nenableFeaturePreview('TYPESAFE_PROJECT_ACCESSORS')\n"
  },
  {
    "path": "website/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Picasso</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"A powerful image downloading and caching library for Android\">\n    <link href=\"static/bootstrap-combined.min.css\" rel=\"stylesheet\">\n    <link href=\"static/app.css\" rel=\"stylesheet\">\n    <link href=\"static/app-theme.css\" rel=\"stylesheet\">\n    <link href=\"http://fonts.googleapis.com/css?family=Roboto:400,300italic,100,100italic,300\" rel=\"stylesheet\" type=\"text/css\">\n    <!--[if lt IE 9]><script src=\"static/html5shiv.min.js\"></script><![endif]-->\n  </head>\n  <body data-target=\".content-nav\">\n    <header>\n      <div class=\"container\">\n        <div class=\"row\">\n          <div class=\"span5\">\n            <h1>Picasso</h1>\n          </div>\n          <div class=\"span7\">\n            <menu>\n              <ul>\n                <li><a href=\"#download\" class=\"menu download\">Download <span class=\"version-tag\">Latest</span></a></li>\n                <li><a href=\"http://github.com/square/picasso\" data-title=\"View GitHub Project\" class=\"menu github\"><img src=\"static/icon-github.png\" alt=\"GitHub\"/></a></li>\n                <li><a href=\"http://square.github.io/\" data-title=\"Square Open Source Portal\" class=\"menu square\"><img src=\"static/icon-square.png\" alt=\"Square\"/></a></li>\n              </ul>\n            </menu>\n          </div>\n      </div>\n    </header>\n    <section id=\"subtitle\">\n      <div class=\"container\">\n        <div class=\"row\">\n          <div class=\"span12\">\n            <h2>A powerful <strong>image downloading</strong> and <strong>caching</strong> library for Android</h2>\n          </div>\n        </div>\n      </div>\n    </section>\n    <section id=\"body\">\n      <div class=\"container\">\n        <div class=\"row\">\n          <div class=\"span9\">\n            <h3 id=\"introduction\">Introduction</h3>\n            <p>Images add much-needed context and visual flair to Android applications. Picasso allows for hassle-free image loading in your application&mdash;often in one line of code!</p>\n            <pre class=\"prettyprint\">Picasso.get().load(\"https://i.imgur.com/DvpvklR.png\").into(imageView);</pre>\n            <p>Many common pitfalls of image loading on Android are handled automatically by Picasso:</p>\n            <ul>\n              <li>Handling <code>ImageView</code> recycling and download cancelation in an adapter.</li>\n              <li>Complex image transformations with minimal memory use.</li>\n              <li>Automatic memory and disk caching.</li>\n            </ul>\n            <p class=\"screenshot\"><img src=\"static/sample.png\" alt=\"Sample application screenshot.\"></p>\n\n            <h3 id=\"features\">Features</h3>\n\n            <h4>Adapter Downloads</h4>\n            <p>Adapter re-use is automatically detected and the previous download canceled.</p>\n            <pre class=\"prettyprint\">@Override public void getView(int position, View convertView, ViewGroup parent) {\n  SquaredImageView view = (SquaredImageView) convertView;\n  if (view == null) {\n    view = new SquaredImageView(context);\n  }\n  String url = getItem(position);\n\n  Picasso.get().load(url).into(view);\n}</pre>\n\n            <h4>Image Transformations</h4>\n            <p>Transform images to better fit into layouts and to reduce memory size.</p>\n            <pre class=\"prettyprint\">Picasso.get()\n  .load(url)\n  .resize(50, 50)\n  .centerCrop()\n  .into(imageView)</pre>\n            <p>You can also specify custom transformations for more advanced effects.</p>\n            <pre class=\"prettyprint\">public class CropSquareTransformation implements Transformation {\n  @Override public Bitmap transform(Bitmap source) {\n    int size = Math.min(source.getWidth(), source.getHeight());\n    int x = (source.getWidth() - size) / 2;\n    int y = (source.getHeight() - size) / 2;\n    Bitmap result = Bitmap.createBitmap(source, x, y, size, size);\n    if (result != source) {\n      source.recycle();\n    }\n    return result;\n  }\n\n  @Override public String key() { return \"square()\"; }\n}</pre>\n            <p>Pass an instance of this class to the <code>transform</code> method.</p>\n\n            <h4>Place Holders</h4>\n            <p>Picasso supports both download and error placeholders as optional features.</p>\n            <pre class-\"prettyprint\">Picasso.get()\n    .load(url)\n    .placeholder(R.drawable.user_placeholder)\n    .error(R.drawable.user_placeholder_error)\n    .into(imageView);</pre>\n            <p>A request will be retried three times before the error placeholder is shown.</p>\n\n\n            <h4>Resource Loading</h4>\n            <p>Resources, assets, files, content providers are all supported as image sources.</p>\n            <pre class=\"prettyprint\">Picasso.get().load(R.drawable.landing_screen).into(imageView1);\nPicasso.get().load(\"file:///android_asset/DvpvklR.png\").into(imageView2);\nPicasso.get().load(new File(...)).into(imageView3);</pre>\n\n            <h4>Debug Indicators</h4>\n            <p>For development you can enable the display of a colored ribbon which indicates the image source. Call <code>setIndicatorsEnabled(true)</code> on the Picasso instance.</p>\n            <p class=\"screenshot\"><img src=\"static/debug.png\" alt=\"Debug ribbon indicators\"></p>\n\n            <h3 id=\"download\">Download</h3>\n            <p><a href=\"https://search.maven.org/remote_content?g=com.squareup.picasso&a=picasso&v=2.8&e=aar\" class=\"dl version-href\">&darr; <span class=\"version-tag\">Latest</span> AAR</a></p>\n            <p>The source code to the Picasso, its samples, and this website is <a href=\"http://github.com/square/picasso\">available on GitHub</a>.</p>\n\n            <h4>Maven</h4>\n            <pre class=\"prettyprint\">&lt;dependency>\n  &lt;groupId>com.squareup.picasso3&lt;/groupId>\n  &lt;artifactId>picasso&lt;/artifactId>\n  &lt;version><span class=\"version pln\"><em>(insert latest version)</em></span>&lt;/version>\n&lt;/dependency></pre>\n\n            <h4>Gradle</h4>\n            <pre class=\"prettyprint\">implementation 'com.squareup.picasso:picasso:<span class=\"version pln\"><em>(insert latest version)</em></span>'</pre>\n\n            <h3 id=\"contributing\">Contributing</h3>\n            <p>If you would like to contribute code you can do so through GitHub by forking the repository and sending a pull request.</p>\n            <p>When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. Please also make sure your code compiles by running <code>mvn clean verify</code>.</p>\n            <p>Before your code can be accepted into the project you must also sign the <a href=\"http://squ.re/sign-the-cla\">Individual Contributor License Agreement (CLA)</a>.</p>\n\n            <h3 id=\"license\">License</h3>\n            <pre>Copyright 2013 Square, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the 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,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.</pre>\n          </div>\n          <div class=\"span3\">\n            <div class=\"content-nav\" data-spy=\"affix\" data-offset-top=\"80\">\n              <ul class=\"nav nav-tabs nav-stacked primary\">\n                <li><a href=\"#introduction\">Introduction</a></li>\n                <li><a href=\"#features\">Features</a></li>\n                <li><a href=\"#download\">Download</a></li>\n                <li><a href=\"#contributing\">Contributing</a></li>\n                <li><a href=\"#license\">License</a></li>\n              </ul>\n              <ul class=\"nav nav-pills nav-stacked secondary\">\n                <li><a href=\"2.x/picasso/\">Javadoc</a></li>\n                <li><a href=\"http://stackoverflow.com/questions/tagged/picasso?sort=active\">StackOverflow</a></li>\n              </ul>\n            </div>\n          </div>\n        </div>\n        <div class=\"row\">\n          <div class=\"span12 logo\">\n            <a href=\"https://squareup.com\"><img src=\"static/logo-square.png\" alt=\"Square, Inc.\"/></a>\n          </div>\n        </div>\n      </div>\n    </section>\n    <script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js\"></script>\n    <script src=\"static/bootstrap.min.js\"></script>\n    <script src=\"static/jquery.smooth-scroll.min.js\"></script>\n    <script src=\"static/jquery-maven-artifact.min.js\"></script>\n    <script src=\"static/prettify.js\"></script>\n    <script type=\"text/javascript\">\n      $(function() {\n        // Syntax highlight code blocks.\n        prettyPrint();\n\n        // Spy on scroll position for real-time updating of current section.\n        $('body').scrollspy();\n\n        // Use smooth-scroll for internal links.\n        $('a').smoothScroll();\n\n        // Enable tooltips on the header nav image items.\n        $('.menu').tooltip({\n          placement: 'bottom',\n          trigger: 'hover',\n          container: 'body',\n          delay: {\n            show: 500,\n            hide: 0\n          }\n        });\n\n        // Look up the latest version of the library.\n        $.fn.artifactVersion({\n          'groupId': 'com.squareup.picasso',\n          'artifactId': 'picasso',\n          'packaging': 'aar'\n        }, function (version, url) {\n            $('.version').text(version);\n            $('.version-tag').text('v' + version);\n            $('.version-href').attr('href', url);\n          });\n        });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "website/static/app-theme.css",
    "content": "/* http://www.colorhexa.com/b94948 */\n\n/*** Primary ***/\n\nheader,\n#subtitle,\na.dl {\n  background-color: #b94948;\n}\n\n.content-nav li.active a,\n.content-nav li.active a:hover {\n  border-left-color: #b94948;\n}\n\n/*** One step left on the monochromatic scale ***/\n\nheader menu li a:hover,\na.dl:hover {\n  background-color: #a74140;\n}\na {\n  color: #a74140;\n}\n\n/*** Three steps left on the monochromatic scale ***/\n\na:hover {\n  color: #833332;\n}\n\n\n/****************************************************************\\\n **** Syntax highlighting styles ********************************\n\\****************************************************************/\n\n.pln { color: #000; }\n.str { color: #953a39; }\n.kwd { color: #666; }\n.com { color: #953a39; }\n.typ { color: #222; }\n.lit { color: #953a39; }\n.pun { color: #888; }\n.opn { color: #888; }\n.clo { color: #888; }\n.tag { color: #953a39; }\n.atn { color: #606; }\n.atv { color: #080; }\n.dec { color: #606; }\n.var { color: #606; }\n.fun { color: #f00; }\n"
  },
  {
    "path": "website/static/app.css",
    "content": "html, body {\n  font-family: 'Roboto', sans-serif;\n  font-size: 15px;\n}\nbody {\n  background-color: #f6f6f6;\n  padding-bottom: 50px;\n  padding-top: 80px;\n}\n\nheader {\n  min-height: 80px;\n  color: #f6f6f6;\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  z-index: 99;\n}\nheader h1 {\n  margin: 10px 0;\n  font-size: 50px;\n  line-height: 60px;\n  font-weight: 100;\n  text-rendering: auto;\n}\nheader menu {\n  margin: 20px 0 0;\n  padding: 0;\n  height: 40px;\n}\nheader menu ul {\n  margin: 0;\n  padding: 0;\n  float: right;\n}\nheader menu li {\n  list-style: none;\n  float: left;\n  margin: 0;\n  padding: 0;\n}\nheader menu li a {\n  display: inline-block;\n  height: 40px;\n  font-size: 17px;\n  line-height: 40px;\n  padding: 0 20px;\n  color: #f6f6f6;\n}\nheader menu li a:hover {\n  color: #f6f6f6;\n  text-decoration: none;\n}\nheader menu li a img {\n  margin: 0;\n  padding: 5px 0;\n  vertical-align: bottom;\n  width: 30px;\n  height: 30px;\n}\n\n#subtitle {\n  position: absolute;\n  top: 80px;\n  left: 0;\n  width: 100%;\n}\nh2 {\n  font-weight: 200;\n  font-size: 26px;\n  line-height: 30px;\n  padding: 15px 0;\n  margin: 0;\n  color: #eee;\n}\nh2 strong {\n  font-weight: 300;\n}\n\na.dl {\n  font-weight: 300;\n  font-size: 30px;\n  line-height: 40px;\n  padding: 3px 10px;\n  display: inline-block;\n  border-radius: 6px;\n  color: #f0f0f0;\n  margin: 5px 0;\n}\na.dl:hover {\n  color: #f0f0f0;\n  text-decoration: none;\n}\n\n.content-nav {\n  margin-top: 130px;\n  width: 220px;\n}\n.content-nav.affix {\n  top: 0;\n}\n.content-nav li.active a, .content-nav li.active a:hover {\n  background-color: transparent;\n  color: #555;\n  border-left-width: 2px;\n}\n.content-nav .secondary a {\n  color: #aaa;\n}\n.content-nav .secondary a:hover {\n  color: #888;\n}\n\nh3 {\n  font-weight: 300;\n  font-style: italic;\n  color: #888;\n  font-size: 20px;\n  padding-top: 115px;\n  margin-top: 0;\n}\n\nh4 {\n  font-weight: 400;\n  text-transform: uppercase;\n  color: #888;\n  font-size: 15px;\n  padding-top: 20px;\n}\n\np.license {\n  font-family: fixed-width;\n}\n\n.row .logo {\n  text-align: center;\n  margin-top: 150px;\n}\n.row .logo img {\n  height: 30px;\n}\n\npre, code {\n  color: #666;\n}\ncode {\n  border: 0;\n  background-color: transparent;\n}\n\n.screenshot {\n  text-align: center;\n}\n\n/* Widescreen desktop. */\n@media (min-width: 1200px) {\n  .content-nav {\n    width: 270px;\n  }\n}\n\n/* Smaller width browser, tablets. */\n@media (max-width: 979px) {\n  .content-nav {\n    width: 166px;\n  }\n}\n\n/* One-column mobile display. */\n@media (max-width: 767px) {\n  header {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 100%;\n    padding-left: 20px;\n  }\n  header menu {\n    display: none;\n  }\n  #subtitle {\n    position: absolute;\n    top: 80px;\n    left: 0;\n    width: 100%;\n    padding-left: 20px;\n  }\n  .content-nav {\n    display: none;\n  }\n}"
  },
  {
    "path": "website/static/prettify.js",
    "content": "!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;\n(function(){function S(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:\"0\"<=a&&a<=\"7\"?parseInt(e.substring(1),8):a===\"u\"||a===\"x\"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?\"\\\\x0\":\"\\\\x\")+e.toString(16);e=String.fromCharCode(e);return e===\"\\\\\"||e===\"-\"||e===\"]\"||e===\"^\"?\"\\\\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\\\u[\\dA-Fa-f]{4}|\\\\x[\\dA-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\S\\s]|[^\\\\]/g),e=[],a=\nb[0]===\"^\",c=[\"[\"];a&&c.push(\"^\");for(var a=a?1:0,f=b.length;a<f;++a){var h=b[a];if(/\\\\[bdsw]/i.test(h))c.push(h);else{var h=d(h),l;a+2<f&&\"-\"===b[a+1]?(l=d(b[a+2]),a+=2):l=h;e.push([h,l]);l<65||h>122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;a<e.length;++a)h=e[a],h[0]<=f[1]+1?f[1]=Math.max(f[1],h[1]):b.push(f=h);for(a=0;a<b.length;++a)h=b[a],c.push(g(h[0])),\nh[1]>h[0]&&(h[1]+1>h[0]&&c.push(\"-\"),c.push(g(h[1])));c.push(\"]\");return c.join(\"\")}function s(e){for(var a=e.source.match(/\\[(?:[^\\\\\\]]|\\\\[\\S\\s])*]|\\\\u[\\dA-Fa-f]{4}|\\\\x[\\dA-Fa-f]{2}|\\\\\\d+|\\\\[^\\dux]|\\(\\?[!:=]|[()^]|[^()[\\\\^]+/g),c=a.length,d=[],f=0,h=0;f<c;++f){var l=a[f];l===\"(\"?++h:\"\\\\\"===l.charAt(0)&&(l=+l.substring(1))&&(l<=h?d[l]=-1:a[f]=g(l))}for(f=1;f<d.length;++f)-1===d[f]&&(d[f]=++x);for(h=f=0;f<c;++f)l=a[f],l===\"(\"?(++h,d[h]||(a[f]=\"(?:\")):\"\\\\\"===l.charAt(0)&&(l=+l.substring(1))&&l<=h&&\n(a[f]=\"\\\\\"+d[l]);for(f=0;f<c;++f)\"^\"===a[f]&&\"^\"!==a[f+1]&&(a[f]=\"\");if(e.ignoreCase&&m)for(f=0;f<c;++f)l=a[f],e=l.charAt(0),l.length>=2&&e===\"[\"?a[f]=b(l):e!==\"\\\\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return\"[\"+String.fromCharCode(a&-33,a|32)+\"]\"}));return a.join(\"\")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k<c;++k){var i=a[k];if(i.ignoreCase)j=!0;else if(/[a-z]/i.test(i.source.replace(/\\\\u[\\da-f]{4}|\\\\x[\\da-f]{2}|\\\\[^UXux]/gi,\"\"))){m=!0;j=!1;break}}for(var r={b:8,t:9,n:10,v:11,\nf:12,r:13},n=[],k=0,c=a.length;k<c;++k){i=a[k];if(i.global||i.multiline)throw Error(\"\"+i);n.push(\"(?:\"+s(i)+\")\")}return RegExp(n.join(\"|\"),j?\"gi\":\"g\")}function T(a,d){function g(a){var c=a.nodeType;if(c==1){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)g(c);c=a.nodeName.toLowerCase();if(\"br\"===c||\"li\"===c)s[j]=\"\\n\",m[j<<1]=x++,m[j++<<1|1]=a}}else if(c==3||c==4)c=a.nodeValue,c.length&&(c=d?c.replace(/\\r\\n?/g,\"\\n\"):c.replace(/[\\t\\n\\r ]+/g,\" \"),s[j]=c,m[j<<1]=x,x+=c.length,m[j++<<1|1]=\na)}var b=/(?:^|\\s)nocode(?:\\s|$)/,s=[],x=0,m=[],j=0;g(a);return{a:s.join(\"\").replace(/\\n$/,\"\"),d:m}}function H(a,d,g,b){d&&(a={a:d,e:a},g(a),b.push.apply(b,a.g))}function U(a){for(var d=void 0,g=a.firstChild;g;g=g.nextSibling)var b=g.nodeType,d=b===1?d?a:g:b===3?V.test(g.nodeValue)?a:d:d;return d===a?void 0:d}function C(a,d){function g(a){for(var j=a.e,k=[j,\"pln\"],c=0,i=a.a.match(s)||[],r={},n=0,e=i.length;n<e;++n){var z=i[n],w=r[z],t=void 0,f;if(typeof w===\"string\")f=!1;else{var h=b[z.charAt(0)];\nif(h)t=z.match(h[1]),w=h[0];else{for(f=0;f<x;++f)if(h=d[f],t=z.match(h[1])){w=h[0];break}t||(w=\"pln\")}if((f=w.length>=5&&\"lang-\"===w.substring(0,5))&&!(t&&typeof t[1]===\"string\"))f=!1,w=\"src\";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c<i;++c){var r=\ng[c],n=r[3];if(n)for(var e=n.length;--e>=0;)b[n.charAt(e)]=r;r=r[1];n=\"\"+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\\S\\s]/);s=S(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push([\"str\",/^(?:'''(?:[^'\\\\]|\\\\[\\S\\s]|''?(?=[^']))*(?:'''|$)|\"\"\"(?:[^\"\\\\]|\\\\[\\S\\s]|\"\"?(?=[^\"]))*(?:\"\"\"|$)|'(?:[^'\\\\]|\\\\[\\S\\s])*(?:'|$)|\"(?:[^\"\\\\]|\\\\[\\S\\s])*(?:\"|$))/,q,\"'\\\"\"]):a.multiLineStrings?d.push([\"str\",/^(?:'(?:[^'\\\\]|\\\\[\\S\\s])*(?:'|$)|\"(?:[^\"\\\\]|\\\\[\\S\\s])*(?:\"|$)|`(?:[^\\\\`]|\\\\[\\S\\s])*(?:`|$))/,\nq,\"'\\\"`\"]):d.push([\"str\",/^(?:'(?:[^\\n\\r'\\\\]|\\\\.)*(?:'|$)|\"(?:[^\\n\\r\"\\\\]|\\\\.)*(?:\"|$))/,q,\"\\\"'\"]);a.verbatimStrings&&g.push([\"str\",/^@\"(?:[^\"]|\"\")*(?:\"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push([\"com\",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,\"#\"]):d.push([\"com\",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\\b|[^\\n\\r]*)/,q,\"#\"]),g.push([\"str\",/^<(?:(?:(?:\\.\\.\\/)*|\\/?)(?:[\\w-]+(?:\\/[\\w-]+)+)?[\\w-]+\\.h(?:h|pp|\\+\\+)?|[a-z]\\w*)>/,q])):d.push([\"com\",\n/^#[^\\n\\r]*/,q,\"#\"]));a.cStyleComments&&(g.push([\"com\",/^\\/\\/[^\\n\\r]*/,q]),g.push([\"com\",/^\\/\\*[\\S\\s]*?(?:\\*\\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?\"\":\"\\n\\r\")?\".\":\"[\\\\S\\\\s]\";g.push([\"lang-regex\",RegExp(\"^(?:^^\\\\.?|[+-]|[!=]=?=?|\\\\#|%=?|&&?=?|\\\\(|\\\\*=?|[+\\\\-]=|->|\\\\/=?|::?|<<?=?|>>?>?=?|,|;|\\\\?|@|\\\\[|~|{|\\\\^\\\\^?=?|\\\\|\\\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\\\s*(\"+(\"/(?=[^/*\"+b+\"])(?:[^/\\\\x5B\\\\x5C\"+b+\"]|\\\\x5C\"+s+\"|\\\\x5B(?:[^\\\\x5C\\\\x5D\"+b+\"]|\\\\x5C\"+\ns+\")*(?:\\\\x5D|$))+/\")+\")\")])}(b=a.types)&&g.push([\"typ\",b]);b=(\"\"+a.keywords).replace(/^ | $/g,\"\");b.length&&g.push([\"kwd\",RegExp(\"^(?:\"+b.replace(/[\\s,]+/g,\"|\")+\")\\\\b\"),q]);d.push([\"pln\",/^\\s+/,q,\" \\r\\n\\t\\u00a0\"]);b=\"^.[^\\\\s\\\\w.$@'\\\"`/\\\\\\\\]*\";a.regexLiterals&&(b+=\"(?!s*/)\");g.push([\"lit\",/^@[$_a-z][\\w$@]*/i,q],[\"typ\",/^(?:[@_]?[A-Z]+[a-z][\\w$@]*|\\w+_t\\b)/,q],[\"pln\",/^[$_a-z][\\w$@]*/i,q],[\"lit\",/^(?:0x[\\da-f]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+-]?\\d+)?)[a-z]*/i,q,\"0123456789\"],[\"pln\",/^\\\\[\\S\\s]?/,\nq],[\"pun\",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if(\"br\"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d=\nc?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\\s)nocode(?:\\s|$)/,m=/\\r\\n?|\\n/,j=a.ownerDocument,k=j.createElement(\"li\");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute(\"value\",d);var r=j.createElement(\"ol\");\nr.className=\"linenums\";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className=\"L\"+(i+d)%10,k.firstChild||k.appendChild(j.createTextNode(\"\\u00a0\")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn(\"cannot override language handler %s\",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\\s*</.test(d)?\"default-markup\":\"default-code\";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;\na.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\\bMSIE\\s(\\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display=\"none\";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g,\nt))){s&&(G=G.replace(d,\"\\r\"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement(\"span\");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=[\"break,continue,do,else,for,if,return,while\"],E=[[y,\"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile\"],\n\"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof\"],M=[E,\"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where\"],N=[E,\"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient\"],\nO=[N,\"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where\"],E=[E,\"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN\"],P=[y,\"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None\"],\nQ=[y,\"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END\"],W=[y,\"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use\"],y=[y,\"case,done,elif,esac,eval,fi,function,in,local,set,then,until\"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/,\nV=/\\S/,X=v({keywords:[M,O,E,\"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END\",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,[\"default-code\"]);p(C([],[[\"pln\",/^[^<?]+/],[\"dec\",/^<!\\w[^>]*(?:>|$)/],[\"com\",/^<\\!--[\\S\\s]*?(?:--\\>|$)/],[\"lang-\",/^<\\?([\\S\\s]+?)(?:\\?>|$)/],[\"lang-\",/^<%([\\S\\s]+?)(?:%>|$)/],[\"pun\",/^(?:<[%?]|[%?]>)/],[\"lang-\",\n/^<xmp\\b[^>]*>([\\S\\s]+?)<\\/xmp\\b[^>]*>/i],[\"lang-js\",/^<script\\b[^>]*>([\\S\\s]*?)(<\\/script\\b[^>]*>)/i],[\"lang-css\",/^<style\\b[^>]*>([\\S\\s]*?)(<\\/style\\b[^>]*>)/i],[\"lang-in.tag\",/^(<\\/?[a-z][^<>]*>)/i]]),[\"default-markup\",\"htm\",\"html\",\"mxml\",\"xhtml\",\"xml\",\"xsl\"]);p(C([[\"pln\",/^\\s+/,q,\" \\t\\r\\n\"],[\"atv\",/^(?:\"[^\"]*\"?|'[^']*'?)/,q,\"\\\"'\"]],[[\"tag\",/^^<\\/?[a-z](?:[\\w-.:]*\\w)?|\\/?>$/i],[\"atn\",/^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],[\"lang-uq.val\",/^=\\s*([^\\s\"'>]*(?:[^\\s\"'/>]|\\/(?=\\s)))/],[\"pun\",/^[/<->]+/],\n[\"lang-js\",/^on\\w+\\s*=\\s*\"([^\"]+)\"/i],[\"lang-js\",/^on\\w+\\s*=\\s*'([^']+)'/i],[\"lang-js\",/^on\\w+\\s*=\\s*([^\\s\"'>]+)/i],[\"lang-css\",/^style\\s*=\\s*\"([^\"]+)\"/i],[\"lang-css\",/^style\\s*=\\s*'([^']+)'/i],[\"lang-css\",/^style\\s*=\\s*([^\\s\"'>]+)/i]]),[\"in.tag\"]);p(C([],[[\"atv\",/^[\\S\\s]+/]]),[\"uq.val\"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:R}),[\"c\",\"cc\",\"cpp\",\"cxx\",\"cyc\",\"m\"]);p(v({keywords:\"null,true,false\"}),[\"json\"]);p(v({keywords:O,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:R}),\n[\"cs\"]);p(v({keywords:N,cStyleComments:!0}),[\"java\"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),[\"bash\",\"bsh\",\"csh\",\"sh\"]);p(v({keywords:P,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),[\"cv\",\"py\",\"python\"]);p(v({keywords:\"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END\",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),[\"perl\",\"pl\",\"pm\"]);p(v({keywords:Q,\nhashComments:!0,multiLineStrings:!0,regexLiterals:!0}),[\"rb\",\"ruby\"]);p(v({keywords:E,cStyleComments:!0,regexLiterals:!0}),[\"javascript\",\"js\"]);p(v({keywords:\"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes\",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),[\"coffee\"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),[\"rc\",\"rs\",\"rust\"]);\np(C([],[[\"str\",/^[\\S\\s]+/]]),[\"regex\"]);var Y=D.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:\"atn\",PR_ATTRIB_VALUE:\"atv\",PR_COMMENT:\"com\",PR_DECLARATION:\"dec\",PR_KEYWORD:\"kwd\",PR_LITERAL:\"lit\",PR_NOCODE:\"nocode\",PR_PLAIN:\"pln\",PR_PUNCTUATION:\"pun\",PR_SOURCE:\"src\",PR_STRING:\"str\",PR_TAG:\"tag\",PR_TYPE:\"typ\",prettyPrintOne:D.prettyPrintOne=function(a,d,g){var b=document.createElement(\"div\");b.innerHTML=\"<pre>\"+a+\"</pre>\";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1});\nreturn b.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i<p.length&&c.now()<b;i++){for(var d=p[i],j=h,k=d;k=k.previousSibling;){var m=k.nodeType,o=(m===7||m===8)&&k.nodeValue;if(o?!/^\\??prettify\\b/.test(o):m!==3||/\\S/.test(k.nodeValue))break;if(o){j={};o.replace(/\\b(\\w+)=([\\w%+\\-.:]+)/g,function(a,b,c){j[b]=c});break}}k=d.className;if((j!==h||e.test(k))&&!v.test(k)){m=!1;for(o=d.parentNode;o;o=o.parentNode)if(f.test(o.tagName)&&\no.className&&e.test(o.className)){m=!0;break}if(!m){d.className+=\" prettyprinted\";m=j.lang;if(!m){var m=k.match(n),y;if(!m&&(y=U(d))&&t.test(y.tagName))m=y.className.match(n);m&&(m=m[1])}if(w.test(d.tagName))o=1;else var o=d.currentStyle,u=s.defaultView,o=(o=o?o.whiteSpace:u&&u.getComputedStyle?u.getComputedStyle(d,q).getPropertyValue(\"white-space\"):0)&&\"pre\"===o.substring(0,3);u=j.linenums;if(!(u=u===\"true\"||+u))u=(u=k.match(/\\blinenums\\b(?::(\\d+))?/))?u[1]&&u[1].length?+u[1]:!0:!1;u&&J(d,u,o);r=\n{h:m,c:d,j:u,i:o};K(r)}}}i<p.length?setTimeout(g,250):\"function\"===typeof a&&a()}for(var b=d||document.body,s=b.ownerDocument||document,b=[b.getElementsByTagName(\"pre\"),b.getElementsByTagName(\"code\"),b.getElementsByTagName(\"xmp\")],p=[],m=0;m<b.length;++m)for(var j=0,k=b[m].length;j<k;++j)p.push(b[m][j]);var b=q,c=Date;c.now||(c={now:function(){return+new Date}});var i=0,r,n=/\\blang(?:uage)?-([\\w.]+)(?!\\S)/,e=/\\bprettyprint\\b/,v=/\\bprettyprinted\\b/,w=/pre|xmp/i,t=/^code$/i,f=/^(?:pre|code|xmp)$/i,\nh={};g()}};typeof define===\"function\"&&define.amd&&define(\"google-code-prettify\",[],function(){return Y})})();}()\n"
  }
]