Full Code of square/picasso for AI

master e94d6116e3ff cached
161 files
598.4 KB
153.6k tokens
13 symbols
1 requests
Download .txt
Showing preview only (648K chars total). Download the full file or copy to clipboard to get everything.
Repository: square/picasso
Branch: master
Commit: e94d6116e3ff
Files: 161
Total size: 598.4 KB

Directory structure:
gitextract_m46ss2gs/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       ├── build.yaml
│       └── release.yaml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── RELEASING.md
├── build.gradle
├── deploy_website.sh
├── gradle/
│   ├── libs.versions.toml
│   ├── license-header.txt
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── lint.xml
├── picasso/
│   ├── api/
│   │   └── picasso.api
│   ├── build.gradle
│   ├── consumer-proguard-rules.txt
│   ├── gradle.properties
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── com/
│       │           └── squareup/
│       │               └── picasso3/
│       │                   ├── AssetRequestHandlerTest.kt
│       │                   ├── BitmapUtilsTest.kt
│       │                   ├── PicassoDrawableTest.kt
│       │                   ├── PlatformLruCacheTest.kt
│       │                   └── TestUtils.kt
│       ├── main/
│       │   └── java/
│       │       └── com/
│       │           └── squareup/
│       │               └── picasso3/
│       │                   ├── Action.kt
│       │                   ├── AssetRequestHandler.kt
│       │                   ├── BaseDispatcher.kt
│       │                   ├── BitmapHunter.kt
│       │                   ├── BitmapTarget.kt
│       │                   ├── BitmapTargetAction.kt
│       │                   ├── BitmapUtils.kt
│       │                   ├── Callback.kt
│       │                   ├── ContactsPhotoRequestHandler.kt
│       │                   ├── ContentStreamRequestHandler.kt
│       │                   ├── DeferredRequestCreator.kt
│       │                   ├── Dispatcher.kt
│       │                   ├── DrawableLoader.kt
│       │                   ├── DrawableTarget.kt
│       │                   ├── DrawableTargetAction.kt
│       │                   ├── EventListener.kt
│       │                   ├── FetchAction.kt
│       │                   ├── FileRequestHandler.kt
│       │                   ├── GetAction.kt
│       │                   ├── HandlerDispatcher.kt
│       │                   ├── ImageViewAction.kt
│       │                   ├── Initializer.kt
│       │                   ├── InternalCoroutineDispatcher.kt
│       │                   ├── MatrixTransformation.kt
│       │                   ├── MediaStoreRequestHandler.kt
│       │                   ├── MemoryPolicy.kt
│       │                   ├── NetworkPolicy.kt
│       │                   ├── NetworkRequestHandler.kt
│       │                   ├── Picasso.kt
│       │                   ├── PicassoDrawable.kt
│       │                   ├── PicassoExecutorService.kt
│       │                   ├── PlatformLruCache.kt
│       │                   ├── RemoteViewsAction.kt
│       │                   ├── Request.kt
│       │                   ├── RequestCreator.kt
│       │                   ├── RequestHandler.kt
│       │                   ├── ResourceDrawableRequestHandler.kt
│       │                   ├── ResourceRequestHandler.kt
│       │                   ├── Transformation.kt
│       │                   └── Utils.kt
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── squareup/
│           │           └── picasso3/
│           │               ├── BaseDispatcherTest.kt
│           │               ├── BitmapHunterTest.kt
│           │               ├── BitmapTargetActionTest.kt
│           │               ├── DeferredRequestCreatorTest.kt
│           │               ├── DrawableTargetActionTest.kt
│           │               ├── HandlerDispatcherTest.kt
│           │               ├── ImageViewActionTest.kt
│           │               ├── InternalCoroutineDispatcherTest.kt
│           │               ├── MediaStoreRequestHandlerTest.kt
│           │               ├── MemoryPolicyTest.kt
│           │               ├── NetworkRequestHandlerTest.kt
│           │               ├── PicassoTest.kt
│           │               ├── RemoteViewsActionTest.kt
│           │               ├── RequestCreatorTest.kt
│           │               ├── Shadows.kt
│           │               ├── TestContentProvider.kt
│           │               ├── TestTransformation.kt
│           │               ├── TestUtils.kt
│           │               ├── UtilsTest.kt
│           │               └── _JavaConsumerIdeCheck.java
│           └── resources/
│               ├── mockito-extensions/
│               │   └── org.mockito.plugins.MockMaker
│               └── robolectric.properties
├── picasso-compose/
│   ├── README.md
│   ├── api/
│   │   └── picasso-compose.api
│   ├── build.gradle
│   ├── gradle.properties
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── squareup/
│       │               └── picasso3/
│       │                   └── compose/
│       │                       └── PicassoPainterTest.kt
│       └── main/
│           └── java/
│               └── com/
│                   └── squareup/
│                       └── picasso3/
│                           └── compose/
│                               └── PicassoPainter.kt
├── picasso-paparazzi-sample/
│   ├── build.gradle
│   └── src/
│       └── test/
│           └── java/
│               └── com/
│                   └── example/
│                       └── picasso/
│                           └── paparazzi/
│                               └── PicassoPaparazziTest.kt
├── picasso-pollexor/
│   ├── README.md
│   ├── api/
│   │   └── picasso-pollexor.api
│   ├── build.gradle
│   ├── gradle.properties
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── com/
│       │           └── squareup/
│       │               └── picasso3/
│       │                   └── pollexor/
│       │                       └── PollexorRequestTransformer.kt
│       └── test/
│           └── java/
│               └── com/
│                   └── squareup/
│                       └── picasso3/
│                           └── pollexor/
│                               └── PollexorRequestTransformerTest.kt
├── picasso-sample/
│   ├── build.gradle
│   ├── lint.xml
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── example/
│           │           └── picasso/
│           │               ├── Data.kt
│           │               ├── GrayscaleTransformation.kt
│           │               ├── PicassoInitializer.kt
│           │               ├── PicassoSampleActivity.kt
│           │               ├── PicassoSampleAdapter.kt
│           │               ├── SampleComposeActivity.kt
│           │               ├── SampleContactsActivity.kt
│           │               ├── SampleContactsAdapter.kt
│           │               ├── SampleGalleryActivity.kt
│           │               ├── SampleGridViewActivity.kt
│           │               ├── SampleGridViewAdapter.kt
│           │               ├── SampleListDetailActivity.kt
│           │               ├── SampleListDetailAdapter.kt
│           │               ├── SampleScrollListener.kt
│           │               ├── SampleWidgetProvider.kt
│           │               └── SquaredImageView.kt
│           └── res/
│               ├── drawable/
│               │   ├── button_selector.xml
│               │   ├── list_selector.xml
│               │   └── overlay_selector.xml
│               ├── layout/
│               │   ├── notification_view.xml
│               │   ├── picasso_sample_activity.xml
│               │   ├── picasso_sample_activity_item.xml
│               │   ├── sample_contacts_activity.xml
│               │   ├── sample_contacts_activity_item.xml
│               │   ├── sample_gallery_activity.xml
│               │   ├── sample_gridview_activity.xml
│               │   ├── sample_list_detail_detail.xml
│               │   ├── sample_list_detail_item.xml
│               │   ├── sample_list_detail_list.xml
│               │   └── sample_widget.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── integers.xml
│               │   ├── strings.xml
│               │   ├── styles.xml
│               │   └── themes.xml
│               ├── values-land/
│               │   └── dimens.xml
│               ├── values-w500dp/
│               │   └── integers.xml
│               ├── values-w600dp/
│               │   ├── dimens.xml
│               │   └── integers.xml
│               ├── values-w700dp/
│               │   └── integers.xml
│               └── xml/
│                   └── sample_widget_info.xml
├── picasso-stats/
│   ├── api/
│   │   └── picasso-stats.api
│   ├── build.gradle
│   ├── gradle.properties
│   └── src/
│       └── main/
│           └── java/
│               └── com/
│                   └── squareup/
│                       └── picasso3/
│                           └── stats/
│                               └── StatsEventListener.kt
├── renovate.json
├── settings.gradle
└── website/
    ├── index.html
    └── static/
        ├── app-theme.css
        ├── app.css
        └── prettify.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_size = 2
indent_style = space
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf

[*.{kt, kts}]
ktlint_code_style = intellij_idea
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,kotlinx.**,^
ij_kotlin_allow_trailing_comma = false
ij_kotlin_allow_trailing_comma_on_call_site = false

ktlint_standard_argument-list-wrapping = disabled
ktlint_function_naming_ignore_when_annotated_with = Composable

================================================
FILE: .gitattributes
================================================
**/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text


================================================
FILE: .github/workflows/build.yaml
================================================
name: build

on:
  pull_request: {}

  push:
    branches:
      - '**'
    tags-ignore:
      - '**'

env:
  GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false -Dkotlin.incremental=false"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          lfs: true

      - name: Configure JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          validate-wrappers: true

      - name: Run Tests
        run: ./gradlew check picasso-paparazzi-sample:verifyPaparazziDebug

      - name: Upload Test Failures
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: test-failures
          path: |
            **/build/reports/tests/test/

  instrumentation-tests:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        api-level: [21, 27, 28]

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3
        with:
          validate-wrappers: true

      - run: ./gradlew assembleAndroidTest

      - name: Enable KVM
        run: |
          echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
          sudo udevadm control --reload-rules
          sudo udevadm trigger --name-match=kvm

      - uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: ${{ matrix.api-level }}
          script: ./gradlew connectedCheck

  publish:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/master'
    needs:
      - build
      - instrumentation-tests

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Publish Artifacts
        run: ./gradlew publishMavenPublicationToMavenCentralRepository
        env:
          ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }}
          ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
          ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ARTIFACT_SIGNING_PRIVATE_KEY }}


================================================
FILE: .github/workflows/release.yaml
================================================
name: release

on:
  push:
    tags:
      - '**'

env:
  GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false -Dkotlin.incremental=false"

jobs:
  release:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure JDK
        uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: 17

      - name: Publish Artifacts
        run: ./gradlew publishMavenPublicationToMavenCentralRepository
        env:
          ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }}
          ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
          ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ARTIFACT_SIGNING_PRIVATE_KEY }}


================================================
FILE: .gitignore
================================================
# Eclipse
.classpath
.project
.settings
eclipsebin

# Ant
bin
gen
build
out
lib

# Maven
target
pom.xml.*
release.properties
coverage.ec

# IntelliJ
.idea
*.iml
*.iws
*.ipr
classes
gen-external-apklibs

# Robolectric
tmp

.DS_Store

# Gradle
.gradle
jniLibs
build
local.properties
reports


================================================
FILE: CHANGELOG.md
================================================
Change Log
==========

Version 2.71828 *(2018-03-07)*
------------------------------

This version is not fully backwards compatible with previous 2.x releases!
It is intended to be a stable, pre-3.0 release that users of 3.0.0-SNAPSHOT can use in the mean time.

Its changes are many, as evidenced by the nearly 3 years since 2.5.2. If you are interested
in them you can browse the commits here: https://github.com/square/picasso/compare/picasso-parent-2.5.2...2.71828

Otherwise, stay tuned for 3.0 whose change log will be in relation to 2.5.2 and thus encompass any
changes present in this release.


Version 2.5.2 *(2015-03-20)*
----------------------------

 * Fix: Correct problems with adapter-based recycling of drawables and interop with external libraries like RoundImageView.


Version 2.5.1 *(2015-03-19)*
----------------------------

 * Specifying transformations in a request now accepts a list.
 * Fix: Correctly handle `null` values from content providers.
 * Fix: Ensure contact photo thumbnail Uris are loaded with the correct request handler.
 * Fix: Eliminate potential (albeit temporary) memory leak on pre-5.0 Android due to message pooling.
 * Fix: Prevent placeholder image aspect ratio from changing while crossfading in image.


Version 2.5.0 *(2015-02-06)*
--------------------------

 * 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.
 * Memory and Network policy API controls reading and storing bitmaps in memory and/or disk cache.
 * Allow returning `InputStream` from `RequestHandler`.
 * Allow removing items from memory cache using `clearKeyUri`.
 * `fetch()` can now accept a `Callback`.
 * Provide option with `onlyScaleDown` to perform scaling only if the source bitmap is larger than the target.
 * Fix: Potential workaround handling improperly cached responses with unknown `Content-Length`. (#632)
 * Fix: Ensure resized images completely fill ImageView (#769)
 * Fix: Properly report correct exception when disk cache fails to load (504 gateway error).
 * Fix: Resize now properly maintains aspect ratio if width or height is 0.
 * Fix: Update debug indicators for the visually impaired (blue color instead of yellow for disk cache hits).


Version 2.4.0 *(2014-11-04)*
--------------------------

 * New `RequestHandler` beta API adds support for custom bitmap loading.
 * `priority` API for setting request priority. By default `fetch()` requests are set to `Priority.LOW`.
 * Requests can now be grouped with a `tag` and can be batch paused, resumed, or canceled.
 * Resizing with either height or width of 0 will now maintain aspect ratio.
 * `Picasso.setSingletonInstance` allows setting the global Picasso instance returned from `Picasso.with`.
 * Request `stableKey` provides an override value for the URI or resource ID when caching.
 * Fix: Properly calculate sample size for requests with `centerInside()`.
 * Fix: `ConcurrentModificationException` could occur in the `Dispatcher` when submitting a request.
 * Fix: Correctly log when a request was canceled due to garbage collection.
 * Fix: Provide correct target for `RemoteViews` requests.
 * Fix: Propagate exceptions thrown from custom transformations.
 * Fix: Invoking `shutdown()` now will close the disk cache.


Version 2.3.4 *(2014-08-25)*
----------------------------

 * Fix: Revert fail fast when missing internet permission.
 * Fix: Account for null paths when naming a Request.
 * Add API to allow canceling of remote views requests.


Version 2.3.3 *(2014-07-21)*
----------------------------

 * Fix: Crash when attempting to swap dimension for EXIF transformation.
 * Fix: Properly honor alpha value in PicassoDrawable.
 * Fix: Use `getWidth()` and `getHeight()` instead of `getMeasuredWidth()` and `getMeasuredHeight()` during `fit()`.


Version 2.3.2 *(2014-06-05)*
----------------------------

 * Fix: Correctly invalidate PicassoDrawable for GB.
 * Fix: Attempt to decode responses with missing `Content-Length` header.
 * Fix: Prevent race condition to initial `with()` call.


Version 2.3.1 *(2014-05-29)*
----------------------------

 * Fix: Deprecated Response constructor used 0 for content-length.
 

Version 2.3.0 *(2014-05-29)*
----------------------------

 * Requests will now be automatically replayed if they failed due to network errors.
 * Add API for logging. This is mostly useful for debugging Picasso itself.
 * Add API for loading images into remote views (notifications and widgets).
 * Stats now provide download statistics.
 * Updated to use Pollexor 2.0.
 * When using OkHttp version 1.6 or newer (including 2.0+) is now required.
 * `MediaStoreBitmapHunter` now properly returns video thumbnails if requested URI is for a video.
 * All API calls now properly validate the current thread they must run on.
 * Performance: Various optimizations for reducing object allocations.
 * Fix: Stats were incorrectly invoked even if the bitmap failed to decode.
 * Fix: Handle `null` intent case in network broadcast receiver extras.
 * Fix: `Target` now correctly invokes bitmap failed if an error drawable or resource is supplied.


Version 2.2.0 *(2014-01-31)*
----------------------------

 * Add support decoding various contact photo URIs. 
 * Add support for loading `android.resource` URIs (e.g. load assets from other packages).
 * Add support for MICRO/MINI thumbnails for media images.
 * Add API to supply custom `Bitmap.Config` for decoding.
 * Performance: Reduce GC by reusing same `StringBuilder` instance on main thread for key creation.
 * Performance: Reduce default buffer allocation to 4k for `MarkableInputStream`.
 * Fix: Detect and decode WebP streams from byte array.
 * Fix: Non-200 HTTP responses will now display error drawable if supplied.
 * Fix: All exceptions during decode will now dispatch a failure.
 * Fix: Catch `OutOfMemory` errors, dispatch a failure, and output stats in logcat.
 * Fix: `fit()` now handles cases where either width or height was not zero.
 * Fix: Prevent crash from `null` intent on `NetworkBroadcastReceiver`.
 * Fix: Honor exif orientation when no custom transformations supplied.
 * Fix: Exceptions during transformations propagate to the main thread. 
 * Fix: Correct skia decoding problem during underflow.
 * Fix: Placeholder uses full bounds.


Version 2.1.1 *(2013-10-04)*
----------------------------

 * `Target` now has callback for applying placeholder. This makes it symmetric with image views when
   using `into()`.
 * Fix: Another work around for Android's header decoding algorthm readin more than 4K of image data
   when decoding bounds.
 * Fix: Ensure default network-based executor is unregistered when instance is shut down.
 * Fix: Ensure connection is always closed for non-2xx response codes.


Version 2.1.0 *(2013-10-01)*
----------------------------

*Duplicate of v2.0.2. Do not use.*


Version 2.0.2 *(2013-09-11)*
----------------------------

 * Fix: Additional work around for Android's header decoding algorithm reading more than 4K of image
   data when decoding bounds.


Version 2.0.1 *(2013-09-04)*
----------------------------

 * Enable filtered bitmaps for higher transform quality.
 * Fix: Using callbacks with `into()` on `fit()` requests are now always invoked.
 * Fix: Ensure final frame of cross-fade between place holder and image renders correctly.
 * Fix: Work around Android's behavior of reading more than 1K of image header data when decoding
   bounds for some images.


Version 2.0.0 *(2013-08-30)*
----------------------------

 * New architecture distances Picasso further from the main thread using a dedicated dispatcher
   thread to manage requests.
 * Request merging. Two requests on the same key will be combined and the result will be delivered
   to both at the same time.
 * `fetch()` requests are now properly wired up to be used as "warm up the cache" type of requests
   without a target.
 * `fit()` will now automatically wait for the view to be measured before executing the request.
 * `shutdown()` API added. Clears the memory cache and stops all threads. Submitting new requests
   will cause a crash after `shutdown()` has been called.
 * Batch completed requests to the main thread to reduce main thread re-layout/draw calls.
 * Variable thread count depending on network connectivity. The faster the network the more threads
   and vice versa.
 * Ability to specify a callback with `ImageView` requests.
 * Picasso will now decode the bounds of the target bitmap over the network. This helps avoid
   decoding 2000x2000 images meant for 100x100 views.
 * Support loading asset URIs in the form `file:///android_asset/...`.
 * BETA: Ability to rewrite requests on the fly. This is useful if you want to add custom logic for
   wiring up requests differently.


Version 1.1.1 *(2013-06-14)*
----------------------------

 * Fix: Ensure old requests for targets are cancelled when using a `null` image.


Version 1.1.0 *(2013-06-13)*
----------------------------

 * `load` method can now take a `Uri`.
 * Support loading contact photos given a contact `Uri`.
 * Add `centerInside()` image transformation.
 * Fix: Prevent network stream decodes from blocking each other.


Version 1.0.2 *(2013-05-23)*
----------------------------

 * Auto-scale disk cache based on file system size.
 * `placeholder` now accepts `null` for clearing an existing image when used in an adapter and
   without an explicit placeholder image.
 * New global failure listener for reporting load errors to a remote analytics or crash service.
 * Fix: Ensure disk cache folder is created before initialization.
 * Fix: Only use the built-in disk cache on API 14+ (but you're all using [OkHttp][1] anyways,
   right?).


Version 1.0.1 *(2013-05-14)*
----------------------------

 * Fix: Properly set priority for download threads.
 * Fix: Ensure stats thread is always initialized.


Version 1.0.0 *(2013-05-14)*
----------------------------

Initial release.




 [1]: http://square.github.io/okhttp/


================================================
FILE: CONTRIBUTING.md
================================================
Contributing
============

If you would like to contribute code to this project you can do so through GitHub by
forking the repository and sending a pull request.

When submitting code, please make every effort to follow existing conventions
and style in order to keep the code as readable as possible.

Before your code can be accepted into the project you must also sign the
[Individual Contributor License Agreement (CLA)][1].


 [1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1


================================================
FILE: LICENSE.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
Picasso
=======

**Attention**: This library is deprecated.
Please 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.
Existing versions will continue to function, but no new work is planned.
While 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.

Thank you to all who used and/or contributed to Picasso over its decade of image loading.

---

A powerful image downloading and caching library for Android

![](website/static/sample.png)

For more information please see [the website][1]



Download
--------

Download the latest AAR from [Maven Central][2] or grab via Gradle:
```groovy
implementation 'com.squareup.picasso:picasso:2.8'
```
or Maven:
```xml
<dependency>
  <groupId>com.squareup.picasso</groupId>
  <artifactId>picasso</artifactId>
  <version>2.8</version>
</dependency>
```

Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap].

Picasso requires at minimum Java 8 and API 21.


ProGuard
--------

If you are using ProGuard you might need to add OkHttp's rules: https://github.com/square/okhttp/#r8--proguard



License
--------

    Copyright 2013 Square, Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

       https://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.


 [1]: https://square.github.io/picasso/
 [2]: https://search.maven.org/search?q=g:com.squareup.picasso%20AND%20a:picasso
 [snap]: https://s01.oss.sonatype.org/content/repositories/snapshots/


================================================
FILE: RELEASING.md
================================================
Releasing
========

 1. Update `VERSION_NAME` in `gradle.properties` to the release (non-SNAPSHOT) version.
 2. Update `CHANGELOG.md` for the impending release.
 3. Update the `README.md` with the new version.
 4. `git commit -am "Prepare for release X.Y.Z"` (where X.Y.Z is the new version)
 5. `git tag -a X.Y.Z -m "X.Y.Z"` (where X.Y.Z is the new version)
 6. Update `VERSION_NAME` in `gradle.properties` to the next SNAPSHOT version.
 7. `git commit -am "Prepare next development version"`
 8. `git push && git push --tags`

This will trigger a GitHub Action workflow which will upload the release artifacts to Maven Central.


================================================
FILE: build.gradle
================================================
buildscript {
  ext.isCi = "true" == System.getenv('CI')

  repositories {
    mavenCentral()
    google()
    gradlePluginPortal()
  }

  dependencies {
    classpath libs.plugin.android
    classpath libs.plugin.kotlin
    classpath libs.plugin.kotlin.compose
    classpath libs.plugin.publish
    classpath libs.plugin.spotless
    classpath libs.plugin.binaryCompatibilityValidator
    classpath libs.plugin.paparazzi
  }
}

apply plugin: 'binary-compatibility-validator'

apiValidation {
  ignoredProjects += ['picasso-sample', 'picasso-paparazzi-sample']
}

subprojects {
  repositories {
    mavenCentral()
    google()
  }

  tasks.withType(Test).configureEach {
    testLogging {
      events "failed"
      exceptionFormat "full"
      showExceptions true
      showStackTraces true
      showCauses true
    }
  }

  plugins.withId('com.vanniktech.maven.publish') {
    publishing {
      repositories {
        /**
         * Want to push to an internal repository for testing?
         * Set the following properties in ~/.gradle/gradle.properties.
         *
         * internalUrl=YOUR_INTERNAL_URL
         * internalUsername=YOUR_USERNAME
         * internalPassword=YOUR_PASSWORD
         */
        maven {
          name = "internal"
          url = providers.gradleProperty("internalUrl")
          credentials(PasswordCredentials)
        }
      }
    }
  }

  apply plugin: 'com.diffplug.spotless'
  spotless {
    kotlin {
      target('**/*.kt')
      licenseHeaderFile(rootProject.file('gradle/license-header.txt'))
      ktlint(libs.versions.ktlint.get())
        .setEditorConfigPath(rootProject.file(".editorconfig"))
    }
  }

  group = GROUP
  version = VERSION_NAME
}

tasks.named('wrapper').configure {
  distributionType = Wrapper.DistributionType.ALL
}

configurations {
  osstrich
}

dependencies {
  osstrich 'com.squareup.osstrich:osstrich:1.4.0'
}

tasks.register('deployJavadoc', JavaExec) {
  classpath = configurations.osstrich
  main = 'com.squareup.osstrich.JavadocPublisher'
  args "$buildDir/osstrich", 'git@github.com:square/picasso.git', 'com.squareup.picasso'
}


================================================
FILE: deploy_website.sh
================================================
#!/bin/bash

set -ex

REPO="git@github.com:square/picasso.git"
DIR=temp-clone

# Delete any existing temporary website clone
rm -rf $DIR

# Clone the current repo into temp folder
git clone $REPO $DIR

# Move working directory into temp folder
cd $DIR

# Checkout and track the gh-pages branch
git checkout -t origin/gh-pages

# Delete everything that isn't versioned (1.x, 2.x)
ls | grep -E -v '^\d+\.x$' | xargs rm -rf

# Copy website files from real repo
cp -R ../website/* .

# Stage all files in git and create a commit
git add .
git add -u
git commit -m "Website at $(date)"

# Push the new files up to GitHub
git push origin gh-pages

# Delete our temp folder
cd ..
rm -rf $DIR


================================================
FILE: gradle/libs.versions.toml
================================================
[versions]
agp = '8.7.2'
coroutines = '1.8.1'
composeUi = '1.6.8'
javaTarget = '1.8'
kotlin = '2.0.0'
ktlint = '1.2.1'
okhttp = '4.12.0'
okio = '3.2.0'
paparazzi = '1.3.4'

minSdk = '21'
compileSdk = '34'

[libraries]
androidx-annotations = { module = 'androidx.annotation:annotation', version = '1.9.1' }
androidx-core = { module = 'androidx.core:core', version = '1.13.1' }
androidx-cursorAdapter = { module = 'androidx.cursoradapter:cursoradapter', version = '1.0.0' }
androidx-exifInterface = { module = 'androidx.exifinterface:exifinterface', version = '1.3.7' }
androidx-fragment = { module = 'androidx.fragment:fragment', version = '1.8.1' }
androidx-junit = { module = 'androidx.test.ext:junit', version = '1.2.1' }
androidx-lifecycle = { module = 'androidx.lifecycle:lifecycle-common', version = '2.8.7' }
androidx-startup = { module = 'androidx.startup:startup-runtime', version = '1.1.1' }
androidx-testRunner = { module = 'androidx.test:runner', version = '1.6.2' }

coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = 'coroutines' }

composeUi = { module = 'androidx.compose.ui:ui', version.ref = 'composeUi' }
composeRuntime = { module = 'androidx.compose.runtime:runtime', version.ref = 'composeUi' }
composeUi-foundation = { module = 'androidx.compose.foundation:foundation', version.ref = 'composeUi' }
composeUi-material = { module = 'androidx.compose.material:material', version.ref = 'composeUi' }
composeUi-uiTooling = { module = 'androidx.compose.ui:ui-tooling', version.ref = 'composeUi' }
composeUi-test = { module = 'androidx.compose.ui:ui-test-junit4', version.ref = 'composeUi' }
composeUi-testManifest = { module = 'androidx.compose.ui:ui-test-manifest', version.ref = 'composeUi' }

drawablePainter = { module = 'com.google.accompanist:accompanist-drawablepainter', version = '0.34.0' }

okio = { module = "com.squareup.okio:okio", version = '3.9.0' }

okhttp = { module = 'com.squareup.okhttp3:okhttp', version.ref = 'okhttp' }
okhttp-mockWebServer = { module = 'com.squareup.okhttp3:mockwebserver', version.ref = 'okhttp' }

pollexor = { module = 'com.squareup:pollexor', version = '3.0.0' }

# Test libraries
junit = { module = 'junit:junit', version = '4.13.2' }
truth = { module = 'com.google.truth:truth', version = '1.4.4' }
robolectric = { module = 'org.robolectric:robolectric', version = '4.7' }
mockito = { module = 'org.mockito:mockito-core', version = '5.12.0' }

# Plugins
plugin-android = { module = 'com.android.tools.build:gradle', version.ref = 'agp' }
plugin-binaryCompatibilityValidator = { module = "org.jetbrains.kotlinx:binary-compatibility-validator", version = '0.16.3' }
plugin-kotlin = { module = 'org.jetbrains.kotlin:kotlin-gradle-plugin', version.ref = 'kotlin' }
plugin-kotlin-compose = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
plugin-paparazzi = { module = 'app.cash.paparazzi:paparazzi-gradle-plugin', version.ref = 'paparazzi' }
plugin-publish = { module = "com.vanniktech:gradle-maven-publish-plugin", version = '0.29.0' }
plugin-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = '6.25.0' }
plugin-test-aggregation = { module = "io.github.gmazzo.test.aggregation:plugin", version = '2.2.1' }


================================================
FILE: gradle/license-header.txt
================================================
/*
 * Copyright (C) $YEAR Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: gradle.properties
================================================
GROUP=com.squareup.picasso3
VERSION_NAME=3.0.0-SNAPSHOT

POM_URL=https://github.com/square/picasso/
POM_SCM_URL=https://github.com/square/picasso/
POM_SCM_CONNECTION=scm:git:git://github.com/square/picasso.git
POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/square/picasso.git

POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo

POM_DEVELOPER_ID=square
POM_DEVELOPER_NAME=Square, Inc.

org.gradle.jvmargs=-Xmx1536M

android.useAndroidX=true

android.defaults.buildfeatures.buildconfig=false
android.defaults.buildfeatures.aidl=false
android.defaults.buildfeatures.renderscript=false
android.defaults.buildfeatures.resvalues=false
android.defaults.buildfeatures.shaders=false

SONATYPE_HOST=S01
RELEASE_SIGNING_ENABLED=true
SONATYPE_AUTOMATIC_RELEASE=true


================================================
FILE: gradlew
================================================
#!/bin/sh

#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#

##############################################################################
#
#   Gradle start up script for POSIX generated by Gradle.
#
#   Important for running:
#
#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
#       noncompliant, but you have some other compliant shell such as ksh or
#       bash, then to run this script, type that shell name before the whole
#       command line, like:
#
#           ksh Gradle
#
#       Busybox and similar reduced shells will NOT work, because this script
#       requires all of these POSIX shell features:
#         * functions;
#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
#         * compound commands having a testable exit status, especially «case»;
#         * various built-in commands including «command», «set», and «ulimit».
#
#   Important for patching:
#
#   (2) This script targets any POSIX shell, so it avoids extensions provided
#       by Bash, Ksh, etc; in particular arrays are avoided.
#
#       The "traditional" practice of packing multiple parameters into a
#       space-separated string is a well documented source of bugs and security
#       problems, so this is (mostly) avoided, by progressively accumulating
#       options in "$@", and eventually passing that to Java.
#
#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
#       see the in-line comments for details.
#
#       There are tweaks for specific operating systems such as AIX, CygWin,
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################

# Attempt to set APP_HOME

# Resolve links: $0 may be a link
app_path=$0

# Need this for daisy-chained symlinks.
while
    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
    [ -h "$app_path" ]
do
    ls=$( ls -ld "$app_path" )
    link=${ls#*' -> '}
    case $link in             #(
      /*)   app_path=$link ;; #(
      *)    app_path=$APP_HOME$link ;;
    esac
done

# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

warn () {
    echo "$*"
} >&2

die () {
    echo
    echo "$*"
    echo
    exit 1
} >&2

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in                #(
  CYGWIN* )         cygwin=true  ;; #(
  Darwin* )         darwin=true  ;; #(
  MSYS* | MINGW* )  msys=true    ;; #(
  NONSTOP* )        nonstop=true ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar


# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD=$JAVA_HOME/jre/sh/java
    else
        JAVACMD=$JAVA_HOME/bin/java
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD=java
    if ! command -v java >/dev/null 2>&1
    then
        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC2039,SC3045
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC2039,SC3045
        ulimit -n "$MAX_FD" ||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
    esac
fi

# Collect all arguments for the java command, stacking in reverse order:
#   * args from the command line
#   * the main class name
#   * -classpath
#   * -D...appname settings
#   * --module-path (only if needed)
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.

# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )

    JAVACMD=$( cygpath --unix "$JAVACMD" )

    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    for arg do
        if
            case $arg in                                #(
              -*)   false ;;                            # don't mess with options #(
              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
                    [ -e "$t" ] ;;                      #(
              *)    false ;;
            esac
        then
            arg=$( cygpath --path --ignore --mixed "$arg" )
        fi
        # Roll the args list around exactly as many times as the number of
        # args, so each arg winds up back in the position where it started, but
        # possibly modified.
        #
        # NB: a `for` loop captures its iteration list before it begins, so
        # changing the positional parameters here affects neither the number of
        # iterations, nor the values presented in `arg`.
        shift                   # remove old arg
        set -- "$@" "$arg"      # push replacement arg
    done
fi


# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Collect all arguments for the java command:
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
#     and any embedded shellness will be escaped.
#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
#     treated as '${Hostname}' itself on the command line.

set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -classpath "$CLASSPATH" \
        org.gradle.wrapper.GradleWrapperMain \
        "$@"

# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
    die "xargs is not available"
fi

# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
#   set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#

eval "set -- $(
        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
        xargs -n1 |
        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
        tr '\n' ' '
    )" '"$@"'

exec "$JAVACMD" "$@"


================================================
FILE: gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem      https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem

@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute

echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2

goto fail

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar


@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: lint.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<lint>
  <issue id="KotlinPropertyAccess" severity="error"/>
  <issue id="LambdaLast" severity="error"/>
  <issue id="NoHardKeywords" severity="error"/>
  <issue id="UnknownNullness" severity="error"/>
  <issue id="SyntheticAccessor" severity="error"/>
</lint>


================================================
FILE: picasso/api/picasso.api
================================================
public abstract interface class com/squareup/picasso3/BitmapTarget {
	public abstract fun onBitmapFailed (Ljava/lang/Exception;Landroid/graphics/drawable/Drawable;)V
	public abstract fun onBitmapLoaded (Landroid/graphics/Bitmap;Lcom/squareup/picasso3/Picasso$LoadedFrom;)V
	public abstract fun onPrepareLoad (Landroid/graphics/drawable/Drawable;)V
}

public abstract interface class com/squareup/picasso3/Callback {
	public abstract fun onError (Ljava/lang/Throwable;)V
	public abstract fun onSuccess ()V
}

public class com/squareup/picasso3/Callback$EmptyCallback : com/squareup/picasso3/Callback {
	public fun <init> ()V
	public fun onError (Ljava/lang/Throwable;)V
	public fun onSuccess ()V
}

public abstract interface class com/squareup/picasso3/DrawableTarget {
	public abstract fun onDrawableFailed (Ljava/lang/Exception;Landroid/graphics/drawable/Drawable;)V
	public abstract fun onDrawableLoaded (Landroid/graphics/drawable/Drawable;Lcom/squareup/picasso3/Picasso$LoadedFrom;)V
	public abstract fun onPrepareLoad (Landroid/graphics/drawable/Drawable;)V
}

public abstract interface class com/squareup/picasso3/EventListener : java/io/Closeable {
	public abstract fun bitmapDecoded (Landroid/graphics/Bitmap;)V
	public abstract fun bitmapTransformed (Landroid/graphics/Bitmap;)V
	public abstract fun cacheHit ()V
	public abstract fun cacheMaxSize (I)V
	public abstract fun cacheMiss ()V
	public abstract fun cacheSize (I)V
	public abstract fun close ()V
	public abstract fun downloadFinished (J)V
}

public final class com/squareup/picasso3/EventListener$DefaultImpls {
	public static fun close (Lcom/squareup/picasso3/EventListener;)V
}

public abstract interface annotation class com/squareup/picasso3/Initializer : java/lang/annotation/Annotation {
}

public final class com/squareup/picasso3/MemoryPolicy : java/lang/Enum {
	public static final field Companion Lcom/squareup/picasso3/MemoryPolicy$Companion;
	public static final field NO_CACHE Lcom/squareup/picasso3/MemoryPolicy;
	public static final field NO_STORE Lcom/squareup/picasso3/MemoryPolicy;
	public static fun getEntries ()Lkotlin/enums/EnumEntries;
	public final fun getIndex ()I
	public static final fun shouldReadFromMemoryCache (I)Z
	public static final fun shouldWriteToMemoryCache (I)Z
	public static fun valueOf (Ljava/lang/String;)Lcom/squareup/picasso3/MemoryPolicy;
	public static fun values ()[Lcom/squareup/picasso3/MemoryPolicy;
}

public final class com/squareup/picasso3/MemoryPolicy$Companion {
	public final fun shouldReadFromMemoryCache (I)Z
	public final fun shouldWriteToMemoryCache (I)Z
}

public final class com/squareup/picasso3/NetworkPolicy : java/lang/Enum {
	public static final field Companion Lcom/squareup/picasso3/NetworkPolicy$Companion;
	public static final field NO_CACHE Lcom/squareup/picasso3/NetworkPolicy;
	public static final field NO_STORE Lcom/squareup/picasso3/NetworkPolicy;
	public static final field OFFLINE Lcom/squareup/picasso3/NetworkPolicy;
	public static fun getEntries ()Lkotlin/enums/EnumEntries;
	public final fun getIndex ()I
	public static final fun isOfflineOnly (I)Z
	public static final fun shouldReadFromDiskCache (I)Z
	public static final fun shouldWriteToDiskCache (I)Z
	public static fun valueOf (Ljava/lang/String;)Lcom/squareup/picasso3/NetworkPolicy;
	public static fun values ()[Lcom/squareup/picasso3/NetworkPolicy;
}

public final class com/squareup/picasso3/NetworkPolicy$Companion {
	public final fun isOfflineOnly (I)Z
	public final fun shouldReadFromDiskCache (I)Z
	public final fun shouldWriteToDiskCache (I)Z
}

public final class com/squareup/picasso3/Picasso : androidx/lifecycle/DefaultLifecycleObserver {
	public final fun cancelRequest (Landroid/widget/ImageView;)V
	public final fun cancelRequest (Landroid/widget/RemoteViews;I)V
	public final fun cancelRequest (Lcom/squareup/picasso3/BitmapTarget;)V
	public final fun cancelRequest (Lcom/squareup/picasso3/DrawableTarget;)V
	public final fun cancelTag (Ljava/lang/Object;)V
	public final fun evictAll ()V
	public final fun getIndicatorsEnabled ()Z
	public final fun invalidate (Landroid/net/Uri;)V
	public final fun invalidate (Ljava/io/File;)V
	public final fun invalidate (Ljava/lang/String;)V
	public final fun isLoggingEnabled ()Z
	public final fun load (I)Lcom/squareup/picasso3/RequestCreator;
	public final fun load (Landroid/net/Uri;)Lcom/squareup/picasso3/RequestCreator;
	public final fun load (Ljava/io/File;)Lcom/squareup/picasso3/RequestCreator;
	public final fun load (Ljava/lang/String;)Lcom/squareup/picasso3/RequestCreator;
	public final fun newBuilder ()Lcom/squareup/picasso3/Picasso$Builder;
	public fun onDestroy (Landroidx/lifecycle/LifecycleOwner;)V
	public fun onStart (Landroidx/lifecycle/LifecycleOwner;)V
	public fun onStop (Landroidx/lifecycle/LifecycleOwner;)V
	public final fun pauseTag (Ljava/lang/Object;)V
	public final fun resumeTag (Ljava/lang/Object;)V
	public final fun setIndicatorsEnabled (Z)V
	public final fun setLoggingEnabled (Z)V
	public final fun shutdown ()V
}

public final class com/squareup/picasso3/Picasso$Builder {
	public fun <init> (Landroid/content/Context;)V
	public final fun addEventListener (Lcom/squareup/picasso3/EventListener;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun addRequestHandler (Lcom/squareup/picasso3/RequestHandler;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun addRequestTransformer (Lcom/squareup/picasso3/Picasso$RequestTransformer;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun build ()Lcom/squareup/picasso3/Picasso;
	public final fun callFactory (Lokhttp3/Call$Factory;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun client (Lokhttp3/OkHttpClient;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun defaultBitmapConfig (Landroid/graphics/Bitmap$Config;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun dispatchers (Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;)Lcom/squareup/picasso3/Picasso$Builder;
	public static synthetic fun dispatchers$default (Lcom/squareup/picasso3/Picasso$Builder;Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;ILjava/lang/Object;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun executor (Ljava/util/concurrent/ExecutorService;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun indicatorsEnabled (Z)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun listener (Lcom/squareup/picasso3/Picasso$Listener;)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun loggingEnabled (Z)Lcom/squareup/picasso3/Picasso$Builder;
	public final fun withCacheSize (I)Lcom/squareup/picasso3/Picasso$Builder;
}

public abstract interface class com/squareup/picasso3/Picasso$Listener {
	public abstract fun onImageLoadFailed (Lcom/squareup/picasso3/Picasso;Landroid/net/Uri;Ljava/lang/Exception;)V
}

public final class com/squareup/picasso3/Picasso$LoadedFrom : java/lang/Enum {
	public static final field DISK Lcom/squareup/picasso3/Picasso$LoadedFrom;
	public static final field MEMORY Lcom/squareup/picasso3/Picasso$LoadedFrom;
	public static final field NETWORK Lcom/squareup/picasso3/Picasso$LoadedFrom;
	public static fun getEntries ()Lkotlin/enums/EnumEntries;
	public static fun valueOf (Ljava/lang/String;)Lcom/squareup/picasso3/Picasso$LoadedFrom;
	public static fun values ()[Lcom/squareup/picasso3/Picasso$LoadedFrom;
}

public final class com/squareup/picasso3/Picasso$Priority : java/lang/Enum {
	public static final field HIGH Lcom/squareup/picasso3/Picasso$Priority;
	public static final field LOW Lcom/squareup/picasso3/Picasso$Priority;
	public static final field NORMAL Lcom/squareup/picasso3/Picasso$Priority;
	public static fun getEntries ()Lkotlin/enums/EnumEntries;
	public static fun valueOf (Ljava/lang/String;)Lcom/squareup/picasso3/Picasso$Priority;
	public static fun values ()[Lcom/squareup/picasso3/Picasso$Priority;
}

public abstract interface class com/squareup/picasso3/Picasso$RequestTransformer {
	public abstract fun transformRequest (Lcom/squareup/picasso3/Request;)Lcom/squareup/picasso3/Request;
}

public final class com/squareup/picasso3/PicassoExecutorService : java/util/concurrent/ThreadPoolExecutor {
	public fun <init> ()V
	public fun <init> (ILjava/util/concurrent/ThreadFactory;)V
	public synthetic fun <init> (ILjava/util/concurrent/ThreadFactory;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
	public fun submit (Ljava/lang/Runnable;)Ljava/util/concurrent/Future;
}

public final class com/squareup/picasso3/PicassoKt {
	public static final field TAG Ljava/lang/String;
}

public final class com/squareup/picasso3/Request {
	public static final field KEY_SEPARATOR C
	public final field centerCrop Z
	public final field centerCropGravity I
	public final field centerInside Z
	public final field config Landroid/graphics/Bitmap$Config;
	public final field hasRotationPivot Z
	public final field headers Lokhttp3/Headers;
	public field id I
	public field key Ljava/lang/String;
	public final field memoryPolicy I
	public final field networkPolicy I
	public final field onlyScaleDown Z
	public final field priority Lcom/squareup/picasso3/Picasso$Priority;
	public final field resourceId I
	public final field rotationDegrees F
	public final field rotationPivotX F
	public final field rotationPivotY F
	public field started J
	public final field targetHeight I
	public final field targetWidth I
	public field transformations Ljava/util/List;
	public final field uri Landroid/net/Uri;
	public final fun getName ()Ljava/lang/String;
	public final fun getStableKey ()Ljava/lang/String;
	public final fun getTag ()Ljava/lang/Object;
	public final fun hasSize ()Z
	public final fun logId ()Ljava/lang/String;
	public final fun needsMatrixTransform ()Z
	public final fun newBuilder ()Lcom/squareup/picasso3/Request$Builder;
	public final fun plainId ()Ljava/lang/String;
	public fun toString ()Ljava/lang/String;
}

public final class com/squareup/picasso3/Request$Builder {
	public fun <init> (I)V
	public fun <init> (Landroid/net/Uri;)V
	public final fun addHeader (Ljava/lang/String;Ljava/lang/String;)Lcom/squareup/picasso3/Request$Builder;
	public final fun build ()Lcom/squareup/picasso3/Request;
	public final fun centerCrop ()Lcom/squareup/picasso3/Request$Builder;
	public final fun centerCrop (I)Lcom/squareup/picasso3/Request$Builder;
	public static synthetic fun centerCrop$default (Lcom/squareup/picasso3/Request$Builder;IILjava/lang/Object;)Lcom/squareup/picasso3/Request$Builder;
	public final fun centerInside ()Lcom/squareup/picasso3/Request$Builder;
	public final fun clearCenterCrop ()Lcom/squareup/picasso3/Request$Builder;
	public final fun clearCenterInside ()Lcom/squareup/picasso3/Request$Builder;
	public final fun clearOnlyScaleDown ()Lcom/squareup/picasso3/Request$Builder;
	public final fun clearResize ()Lcom/squareup/picasso3/Request$Builder;
	public final fun clearRotation ()Lcom/squareup/picasso3/Request$Builder;
	public final fun clearTag ()Lcom/squareup/picasso3/Request$Builder;
	public final fun config (Landroid/graphics/Bitmap$Config;)Lcom/squareup/picasso3/Request$Builder;
	public final fun getCenterCrop ()Z
	public final fun getCenterCropGravity ()I
	public final fun getCenterInside ()Z
	public final fun getConfig ()Landroid/graphics/Bitmap$Config;
	public final fun getHasRotationPivot ()Z
	public final fun getHeaders ()Lokhttp3/Headers;
	public final fun getMemoryPolicy ()I
	public final fun getNetworkPolicy ()I
	public final fun getOnlyScaleDown ()Z
	public final fun getPriority ()Lcom/squareup/picasso3/Picasso$Priority;
	public final fun getResourceId ()I
	public final fun getRotationDegrees ()F
	public final fun getRotationPivotX ()F
	public final fun getRotationPivotY ()F
	public final fun getStableKey ()Ljava/lang/String;
	public final fun getTag ()Ljava/lang/Object;
	public final fun getTargetHeight ()I
	public final fun getTargetWidth ()I
	public final fun getTransformations ()Ljava/util/List;
	public final fun getUri ()Landroid/net/Uri;
	public final fun hasImage ()Z
	public final fun hasPriority ()Z
	public final fun hasSize ()Z
	public final fun memoryPolicy (Lcom/squareup/picasso3/MemoryPolicy;[Lcom/squareup/picasso3/MemoryPolicy;)Lcom/squareup/picasso3/Request$Builder;
	public final fun networkPolicy (Lcom/squareup/picasso3/NetworkPolicy;[Lcom/squareup/picasso3/NetworkPolicy;)Lcom/squareup/picasso3/Request$Builder;
	public final fun onlyScaleDown ()Lcom/squareup/picasso3/Request$Builder;
	public final fun priority (Lcom/squareup/picasso3/Picasso$Priority;)Lcom/squareup/picasso3/Request$Builder;
	public final fun resize (II)Lcom/squareup/picasso3/Request$Builder;
	public final fun rotate (F)Lcom/squareup/picasso3/Request$Builder;
	public final fun rotate (FFF)Lcom/squareup/picasso3/Request$Builder;
	public final fun setCenterCrop (Z)V
	public final fun setCenterCropGravity (I)V
	public final fun setCenterInside (Z)V
	public final fun setConfig (Landroid/graphics/Bitmap$Config;)V
	public final fun setHasRotationPivot (Z)V
	public final fun setHeaders (Lokhttp3/Headers;)V
	public final fun setMemoryPolicy (I)V
	public final fun setNetworkPolicy (I)V
	public final fun setOnlyScaleDown (Z)V
	public final fun setPriority (Lcom/squareup/picasso3/Picasso$Priority;)V
	public final fun setResourceId (I)Lcom/squareup/picasso3/Request$Builder;
	public final fun setResourceId (I)V
	public final fun setRotationDegrees (F)V
	public final fun setRotationPivotX (F)V
	public final fun setRotationPivotY (F)V
	public final fun setStableKey (Ljava/lang/String;)V
	public final fun setTag (Ljava/lang/Object;)V
	public final fun setTargetHeight (I)V
	public final fun setTargetWidth (I)V
	public final fun setTransformations (Ljava/util/List;)V
	public final fun setUri (Landroid/net/Uri;)Lcom/squareup/picasso3/Request$Builder;
	public final fun setUri (Landroid/net/Uri;)V
	public final fun stableKey (Ljava/lang/String;)Lcom/squareup/picasso3/Request$Builder;
	public final fun tag (Ljava/lang/Object;)Lcom/squareup/picasso3/Request$Builder;
	public final fun transform (Lcom/squareup/picasso3/Transformation;)Lcom/squareup/picasso3/Request$Builder;
	public final fun transform (Ljava/util/List;)Lcom/squareup/picasso3/Request$Builder;
}

public final class com/squareup/picasso3/RequestCreator {
	public final fun addHeader (Ljava/lang/String;Ljava/lang/String;)Lcom/squareup/picasso3/RequestCreator;
	public final fun centerCrop ()Lcom/squareup/picasso3/RequestCreator;
	public final fun centerCrop (I)Lcom/squareup/picasso3/RequestCreator;
	public final fun centerInside ()Lcom/squareup/picasso3/RequestCreator;
	public final fun config (Landroid/graphics/Bitmap$Config;)Lcom/squareup/picasso3/RequestCreator;
	public final fun error (I)Lcom/squareup/picasso3/RequestCreator;
	public final fun error (Landroid/graphics/drawable/Drawable;)Lcom/squareup/picasso3/RequestCreator;
	public final fun fetch ()V
	public final fun fetch (Lcom/squareup/picasso3/Callback;)V
	public static synthetic fun fetch$default (Lcom/squareup/picasso3/RequestCreator;Lcom/squareup/picasso3/Callback;ILjava/lang/Object;)V
	public final fun fit ()Lcom/squareup/picasso3/RequestCreator;
	public final fun get ()Landroid/graphics/Bitmap;
	public final fun into (Landroid/widget/ImageView;)V
	public final fun into (Landroid/widget/ImageView;Lcom/squareup/picasso3/Callback;)V
	public final fun into (Landroid/widget/RemoteViews;IILandroid/app/Notification;)V
	public final fun into (Landroid/widget/RemoteViews;IILandroid/app/Notification;Ljava/lang/String;)V
	public final fun into (Landroid/widget/RemoteViews;IILandroid/app/Notification;Ljava/lang/String;Lcom/squareup/picasso3/Callback;)V
	public final fun into (Landroid/widget/RemoteViews;IILcom/squareup/picasso3/Callback;)V
	public final fun into (Landroid/widget/RemoteViews;I[I)V
	public final fun into (Landroid/widget/RemoteViews;I[ILcom/squareup/picasso3/Callback;)V
	public final fun into (Lcom/squareup/picasso3/BitmapTarget;)V
	public final fun into (Lcom/squareup/picasso3/DrawableTarget;)V
	public static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/ImageView;Lcom/squareup/picasso3/Callback;ILjava/lang/Object;)V
	public 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
	public static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/RemoteViews;IILcom/squareup/picasso3/Callback;ILjava/lang/Object;)V
	public static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/RemoteViews;I[ILcom/squareup/picasso3/Callback;ILjava/lang/Object;)V
	public final fun memoryPolicy (Lcom/squareup/picasso3/MemoryPolicy;[Lcom/squareup/picasso3/MemoryPolicy;)Lcom/squareup/picasso3/RequestCreator;
	public final fun networkPolicy (Lcom/squareup/picasso3/NetworkPolicy;[Lcom/squareup/picasso3/NetworkPolicy;)Lcom/squareup/picasso3/RequestCreator;
	public final fun noFade ()Lcom/squareup/picasso3/RequestCreator;
	public final fun noPlaceholder ()Lcom/squareup/picasso3/RequestCreator;
	public final fun onlyScaleDown ()Lcom/squareup/picasso3/RequestCreator;
	public final fun placeholder (I)Lcom/squareup/picasso3/RequestCreator;
	public final fun placeholder (Landroid/graphics/drawable/Drawable;)Lcom/squareup/picasso3/RequestCreator;
	public final fun priority (Lcom/squareup/picasso3/Picasso$Priority;)Lcom/squareup/picasso3/RequestCreator;
	public final fun resize (II)Lcom/squareup/picasso3/RequestCreator;
	public final fun resizeDimen (II)Lcom/squareup/picasso3/RequestCreator;
	public final fun rotate (F)Lcom/squareup/picasso3/RequestCreator;
	public final fun rotate (FFF)Lcom/squareup/picasso3/RequestCreator;
	public final fun stableKey (Ljava/lang/String;)Lcom/squareup/picasso3/RequestCreator;
	public final fun tag (Ljava/lang/Object;)Lcom/squareup/picasso3/RequestCreator;
	public final fun transform (Lcom/squareup/picasso3/Transformation;)Lcom/squareup/picasso3/RequestCreator;
	public final fun transform (Ljava/util/List;)Lcom/squareup/picasso3/RequestCreator;
}

public abstract class com/squareup/picasso3/RequestHandler {
	public fun <init> ()V
	public abstract fun canHandleRequest (Lcom/squareup/picasso3/Request;)Z
	public fun getRetryCount ()I
	public abstract fun load (Lcom/squareup/picasso3/Picasso;Lcom/squareup/picasso3/Request;Lcom/squareup/picasso3/RequestHandler$Callback;)V
	public fun shouldRetry (ZLandroid/net/NetworkInfo;)Z
	public fun supportsReplay ()Z
}

public abstract interface class com/squareup/picasso3/RequestHandler$Callback {
	public abstract fun onError (Ljava/lang/Throwable;)V
	public abstract fun onSuccess (Lcom/squareup/picasso3/RequestHandler$Result;)V
}

public abstract class com/squareup/picasso3/RequestHandler$Result {
	public synthetic fun <init> (Lcom/squareup/picasso3/Picasso$LoadedFrom;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
	public synthetic fun <init> (Lcom/squareup/picasso3/Picasso$LoadedFrom;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
	public final fun getExifRotation ()I
	public final fun getLoadedFrom ()Lcom/squareup/picasso3/Picasso$LoadedFrom;
}

public final class com/squareup/picasso3/RequestHandler$Result$Bitmap : com/squareup/picasso3/RequestHandler$Result {
	public fun <init> (Landroid/graphics/Bitmap;Lcom/squareup/picasso3/Picasso$LoadedFrom;I)V
	public synthetic fun <init> (Landroid/graphics/Bitmap;Lcom/squareup/picasso3/Picasso$LoadedFrom;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
	public final fun getBitmap ()Landroid/graphics/Bitmap;
}

public final class com/squareup/picasso3/RequestHandler$Result$Drawable : com/squareup/picasso3/RequestHandler$Result {
	public fun <init> (Landroid/graphics/drawable/Drawable;Lcom/squareup/picasso3/Picasso$LoadedFrom;I)V
	public synthetic fun <init> (Landroid/graphics/drawable/Drawable;Lcom/squareup/picasso3/Picasso$LoadedFrom;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
	public final fun getDrawable ()Landroid/graphics/drawable/Drawable;
}

public abstract interface class com/squareup/picasso3/Transformation {
	public abstract fun key ()Ljava/lang/String;
	public abstract fun transform (Lcom/squareup/picasso3/RequestHandler$Result$Bitmap;)Lcom/squareup/picasso3/RequestHandler$Result$Bitmap;
}



================================================
FILE: picasso/build.gradle
================================================
apply plugin: 'com.android.library'
apply plugin: 'org.jetbrains.kotlin.android'
apply plugin: 'com.vanniktech.maven.publish'

android {
  namespace 'com.squareup.picasso3'

  compileSdkVersion libs.versions.compileSdk.get() as int

  defaultConfig {
    minSdkVersion libs.versions.minSdk.get() as int
    consumerProguardFiles 'consumer-proguard-rules.txt'

    testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
  }

  compileOptions {
    sourceCompatibility libs.versions.javaTarget.get()
    targetCompatibility libs.versions.javaTarget.get()
  }

  kotlinOptions {
    jvmTarget = libs.versions.javaTarget.get()
  }

  lintOptions {
    textOutput 'stdout'
    textReport true
    lintConfig rootProject.file('lint.xml')
  }

  testOptions {
    unitTests {
      includeAndroidResources = true
    }
  }
}

dependencies {
  api libs.okhttp
  api libs.okio
  api libs.androidx.lifecycle
  implementation libs.androidx.annotations
  implementation libs.androidx.core
  implementation libs.androidx.exifInterface

  testImplementation libs.coroutines.test
  testImplementation libs.junit
  testImplementation libs.truth
  testImplementation libs.robolectric
  testImplementation libs.mockito
  testImplementation libs.okhttp.mockWebServer

  androidTestImplementation libs.androidx.junit
  androidTestImplementation libs.androidx.testRunner
  androidTestImplementation libs.truth
}

spotless {
  kotlin {
    targetExclude(
      // Non-Square licensed files
      "src/test/java/com/squareup/picasso3/PlatformLruCacheTest.kt",
    )
  }
}


================================================
FILE: picasso/consumer-proguard-rules.txt
================================================
### OKHTTP

# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote okhttp3.internal.Platform


### OKIO

# java.nio.file.* usage which cannot be used at runtime. Animal sniffer annotation.
-dontwarn okio.Okio
# JDK 7-only method which is @hide on Android. Animal sniffer annotation.
-dontwarn okio.DeflaterSink


================================================
FILE: picasso/gradle.properties
================================================
POM_ARTIFACT_ID=picasso
POM_NAME=Picasso
POM_DESCRIPTION=A powerful image downloading and caching library for Android
POM_PACKAGING=aar


================================================
FILE: picasso/src/androidTest/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

</manifest>


================================================
FILE: picasso/src/androidTest/java/com/squareup/picasso3/AssetRequestHandlerTest.kt
================================================
/*
 * Copyright (C) 2022 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.net.Uri
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class AssetRequestHandlerTest {
  @Test fun truncatesFilePrefix() {
    val uri = Uri.parse("file:///android_asset/foo/bar.png")
    val request = Request.Builder(uri).build()

    val actual = AssetRequestHandler.getFilePath(request)
    assertThat(actual).isEqualTo("foo/bar.png")
  }
}


================================================
FILE: picasso/src/androidTest/java/com/squareup/picasso3/BitmapUtilsTest.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.Bitmap
import android.graphics.Bitmap.Config.RGB_565
import android.graphics.BitmapFactory
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import com.squareup.picasso3.BitmapUtils.calculateInSampleSize
import com.squareup.picasso3.BitmapUtils.createBitmapOptions
import com.squareup.picasso3.BitmapUtils.requiresInSampleSize
import com.squareup.picasso3.TestUtils.URI_1
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class BitmapUtilsTest {

  @Test fun bitmapConfig() {
    for (config in Bitmap.Config.values()) {
      val data = Request.Builder(URI_1).config(config).build()
      val copy = data.newBuilder().build()

      assertThat(createBitmapOptions(data)!!.inPreferredConfig).isSameInstanceAs(config)
      assertThat(createBitmapOptions(copy)!!.inPreferredConfig).isSameInstanceAs(config)
    }
  }

  @Test fun requiresComputeInSampleSize() {
    assertThat(requiresInSampleSize(null)).isFalse()

    val defaultOptions = BitmapFactory.Options()
    assertThat(requiresInSampleSize(defaultOptions)).isFalse()

    val justBounds = BitmapFactory.Options().apply { inJustDecodeBounds = true }
    assertThat(requiresInSampleSize(justBounds)).isTrue()
  }

  @Test fun calculateInSampleSizeNoResize() {
    val options = BitmapFactory.Options()
    val data = Request.Builder(URI_1).build()
    calculateInSampleSize(100, 100, 150, 150, options, data)
    assertThat(options.inSampleSize).isEqualTo(1)
  }

  @Test fun calculateInSampleSizeResize() {
    val options = BitmapFactory.Options()
    val data = Request.Builder(URI_1).build()
    calculateInSampleSize(100, 100, 200, 200, options, data)
    assertThat(options.inSampleSize).isEqualTo(2)
  }

  @Test fun calculateInSampleSizeResizeCenterInside() {
    val options = BitmapFactory.Options()
    val data = Request.Builder(URI_1).centerInside().resize(100, 100).build()
    calculateInSampleSize(data.targetWidth, data.targetHeight, 400, 200, options, data)
    assertThat(options.inSampleSize).isEqualTo(4)
  }

  @Test fun calculateInSampleSizeKeepAspectRatioWithWidth() {
    val options = BitmapFactory.Options()
    val data = Request.Builder(URI_1).resize(400, 0).build()
    calculateInSampleSize(data.targetWidth, data.targetHeight, 800, 200, options, data)
    assertThat(options.inSampleSize).isEqualTo(2)
  }

  @Test fun calculateInSampleSizeKeepAspectRatioWithHeight() {
    val options = BitmapFactory.Options()
    val data = Request.Builder(URI_1).resize(0, 100).build()
    calculateInSampleSize(data.targetWidth, data.targetHeight, 800, 200, options, data)
    assertThat(options.inSampleSize).isEqualTo(2)
  }

  @Test fun nullBitmapOptionsIfNoResizing() {
    // No resize must return no bitmap options
    val noResize = Request.Builder(URI_1).build()
    val noResizeOptions = createBitmapOptions(noResize)
    assertThat(noResizeOptions).isNull()
  }

  @Test fun inJustDecodeBoundsIfResizing() {
    // Resize must return bitmap options with inJustDecodeBounds = true
    val requiresResize = Request.Builder(URI_1).resize(20, 15).build()
    val resizeOptions = createBitmapOptions(requiresResize)
    assertThat(resizeOptions).isNotNull()
    assertThat(resizeOptions!!.inJustDecodeBounds).isTrue()
  }

  @Test fun createWithConfigAndNotInJustDecodeBounds() {
    // Given a config, must return bitmap options and false inJustDecodeBounds
    val config = Request.Builder(URI_1).config(RGB_565).build()
    val configOptions = createBitmapOptions(config)
    assertThat(configOptions).isNotNull()
    assertThat(configOptions!!.inJustDecodeBounds).isFalse()
  }
}


================================================
FILE: picasso/src/androidTest/java/com/squareup/picasso3/PicassoDrawableTest.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.Bitmap
import android.graphics.Color.RED
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import com.squareup.picasso3.Picasso.LoadedFrom.DISK
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class PicassoDrawableTest {
  private val placeholder: Drawable = ColorDrawable(RED)
  private val bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8)

  @Test fun createWithNoPlaceholderAnimation() {
    val pd = PicassoDrawable(
      placeholder = null,
      context = ApplicationProvider.getApplicationContext(),
      bitmap = bitmap,
      loadedFrom = DISK,
      noFade = false,
      debugging = false
    )
    assertThat(pd.bitmap).isSameInstanceAs(bitmap)
    assertThat(pd.placeholder).isNull()
    assertThat(pd.animating).isTrue()
  }

  @Test fun createWithPlaceholderAnimation() {
    val pd = PicassoDrawable(
      context = ApplicationProvider.getApplicationContext(),
      bitmap = bitmap,
      placeholder,
      loadedFrom = DISK,
      noFade = false,
      debugging = false
    )
    assertThat(pd.bitmap).isSameInstanceAs(bitmap)
    assertThat(pd.placeholder).isSameInstanceAs(placeholder)
    assertThat(pd.animating).isTrue()
  }

  @Test fun createWithBitmapCacheHit() {
    val pd = PicassoDrawable(
      context = ApplicationProvider.getApplicationContext(),
      bitmap = bitmap,
      placeholder,
      loadedFrom = Picasso.LoadedFrom.MEMORY,
      noFade = false,
      debugging = false
    )
    assertThat(pd.bitmap).isSameInstanceAs(bitmap)
    assertThat(pd.placeholder).isNull()
    assertThat(pd.animating).isFalse()
  }
}


================================================
FILE: picasso/src/androidTest/java/com/squareup/picasso3/PlatformLruCacheTest.kt
================================================
/*
 * Copyright (C) 2011 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.Bitmap
import android.graphics.Bitmap.Config.ALPHA_8
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class PlatformLruCacheTest {
  // The use of ALPHA_8 simplifies the size math in tests since only one byte is used per-pixel.
  private val bitmapA = Bitmap.createBitmap(1, 1, ALPHA_8)
  private val bitmapB = Bitmap.createBitmap(1, 1, ALPHA_8)
  private val bitmapC = Bitmap.createBitmap(1, 1, ALPHA_8)
  private val bitmapD = Bitmap.createBitmap(1, 1, ALPHA_8)
  private val bitmapE = Bitmap.createBitmap(1, 1, ALPHA_8)

  private var expectedPutCount = 0
  private var expectedHitCount = 0
  private var expectedMissCount = 0
  private var expectedEvictionCount = 0

  @Test fun testStatistics() {
    val cache = PlatformLruCache(3)
    assertStatistics(cache)

    cache["a"] = bitmapA
    expectedPutCount++
    assertStatistics(cache)
    assertHit(cache, "a", bitmapA)

    cache["b"] = bitmapB
    expectedPutCount++
    assertStatistics(cache)
    assertHit(cache, "a", bitmapA)
    assertHit(cache, "b", bitmapB)
    assertSnapshot(cache, "a", bitmapA, "b", bitmapB)

    cache["c"] = bitmapC
    expectedPutCount++
    assertStatistics(cache)
    assertHit(cache, "a", bitmapA)
    assertHit(cache, "b", bitmapB)
    assertHit(cache, "c", bitmapC)
    assertSnapshot(cache, "a", bitmapA, "b", bitmapB, "c", bitmapC)

    cache["d"] = bitmapD
    expectedPutCount++
    expectedEvictionCount++ // a should have been evicted
    assertStatistics(cache)
    assertMiss(cache, "a")
    assertHit(cache, "b", bitmapB)
    assertHit(cache, "c", bitmapC)
    assertHit(cache, "d", bitmapD)
    assertHit(cache, "b", bitmapB)
    assertHit(cache, "c", bitmapC)
    assertSnapshot(cache, "d", bitmapD, "b", bitmapB, "c", bitmapC)

    cache["e"] = bitmapE
    expectedPutCount++
    expectedEvictionCount++ // d should have been evicted
    assertStatistics(cache)
    assertMiss(cache, "d")
    assertMiss(cache, "a")
    assertHit(cache, "e", bitmapE)
    assertHit(cache, "b", bitmapB)
    assertHit(cache, "c", bitmapC)
    assertSnapshot(cache, "e", bitmapE, "b", bitmapB, "c", bitmapC)
  }

  @Test fun evictionWithSingletonCache() {
    val cache = PlatformLruCache(1)
    cache["a"] = bitmapA
    cache["b"] = bitmapB
    assertSnapshot(cache, "b", bitmapB)
  }

  /**
   * Replacing the value for a key doesn't cause an eviction but it does bring the replaced entry to
   * the front of the queue.
   */
  @Test fun putCauseEviction() {
    val cache = PlatformLruCache(3)

    cache["a"] = bitmapA
    cache["b"] = bitmapB
    cache["c"] = bitmapC
    cache["b"] = bitmapD
    assertSnapshot(cache, "a", bitmapA, "c", bitmapC, "b", bitmapD)
  }

  @Test fun evictAll() {
    val cache = PlatformLruCache(4)
    cache["a"] = bitmapA
    cache["b"] = bitmapB
    cache["c"] = bitmapC
    cache.clear()
    assertThat(cache.cache.snapshot()).isEmpty()
  }

  @Test fun clearPrefixedKey() {
    val cache = PlatformLruCache(3)

    cache["Hello\nAlice!"] = bitmapA
    cache["Hello\nBob!"] = bitmapB
    cache["Hello\nEve!"] = bitmapC
    cache["Hellos\nWorld!"] = bitmapD

    cache.clearKeyUri("Hello")
    assertThat(cache.cache.snapshot()).hasSize(1)
    assertThat(cache.cache.snapshot()).containsKey("Hellos\nWorld!")
  }

  @Test fun invalidate() {
    val cache = PlatformLruCache(3)
    cache["Hello\nAlice!"] = bitmapA
    assertThat(cache.size()).isEqualTo(1)
    cache.clearKeyUri("Hello")
    assertThat(cache.size()).isEqualTo(0)
  }

  @Test fun overMaxSizeDoesNotClear() {
    val cache = PlatformLruCache(16)
    val size4 = Bitmap.createBitmap(2, 2, ALPHA_8)
    val size16 = Bitmap.createBitmap(4, 4, ALPHA_8)
    val size25 = Bitmap.createBitmap(5, 5, ALPHA_8)
    cache["4"] = size4
    expectedPutCount++
    assertHit(cache, "4", size4)
    cache["16"] = size16
    expectedPutCount++
    expectedEvictionCount++ // size4 was evicted.
    assertMiss(cache, "4")
    assertHit(cache, "16", size16)
    cache["25"] = size25
    assertHit(cache, "16", size16)
    assertMiss(cache, "25")
    assertThat(cache.size()).isEqualTo(16)
  }

  @Test fun overMaxSizeRemovesExisting() {
    val cache = PlatformLruCache(20)
    val size4 = Bitmap.createBitmap(2, 2, ALPHA_8)
    val size16 = Bitmap.createBitmap(4, 4, ALPHA_8)
    val size25 = Bitmap.createBitmap(5, 5, ALPHA_8)
    cache["small"] = size4
    expectedPutCount++
    assertHit(cache, "small", size4)
    cache["big"] = size16
    expectedPutCount++
    assertHit(cache, "small", size4)
    assertHit(cache, "big", size16)
    cache["big"] = size25
    assertHit(cache, "small", size4)
    assertMiss(cache, "big")
    assertThat(cache.size()).isEqualTo(4)
  }

  private fun assertHit(cache: PlatformLruCache, key: String, value: Bitmap) {
    assertThat(cache[key]).isEqualTo(value)
    expectedHitCount++
    assertStatistics(cache)
  }

  private fun assertMiss(cache: PlatformLruCache, key: String) {
    assertThat(cache[key]).isNull()
    expectedMissCount++
    assertStatistics(cache)
  }

  private fun assertStatistics(cache: PlatformLruCache) {
    assertThat(cache.putCount()).isEqualTo(expectedPutCount)
    assertThat(cache.hitCount()).isEqualTo(expectedHitCount)
    assertThat(cache.missCount()).isEqualTo(expectedMissCount)
    assertThat(cache.evictionCount()).isEqualTo(expectedEvictionCount)
  }

  @OptIn(ExperimentalStdlibApi::class)
  private fun assertSnapshot(cache: PlatformLruCache, vararg keysAndValues: Any) {
    val actualKeysAndValues = buildList {
      cache.cache.snapshot().forEach { (key, value) ->
        add(key)
        add(value.bitmap)
      }
    }

    // assert using lists because order is important for LRUs
    assertThat(actualKeysAndValues).isEqualTo(listOf(*keysAndValues))
  }
}


================================================
FILE: picasso/src/androidTest/java/com/squareup/picasso3/TestUtils.kt
================================================
/*
 * Copyright (C) 2022 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.net.Uri

object TestUtils {
  val URI_1: Uri = Uri.parse("http://example.com/1.png")
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/Action.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import com.squareup.picasso3.RequestHandler.Result

internal abstract class Action(
  val picasso: Picasso,
  val request: Request
) {
  var willReplay = false
  var cancelled = false

  abstract fun complete(result: Result)
  abstract fun error(e: Exception)

  abstract fun getTarget(): Any?

  open fun cancel() {
    cancelled = true
  }

  val tag: Any
    get() = request.tag ?: this
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/AssetRequestHandler.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.content.ContentResolver
import android.content.Context
import android.content.res.AssetManager
import com.squareup.picasso3.BitmapUtils.decodeStream
import com.squareup.picasso3.Picasso.LoadedFrom.DISK
import okio.source

internal class AssetRequestHandler(private val context: Context) : RequestHandler() {
  private val lock = Any()

  @Volatile
  private var assetManager: AssetManager? = null

  override fun canHandleRequest(data: Request): Boolean {
    val uri = data.uri
    return uri != null &&
      ContentResolver.SCHEME_FILE == uri.scheme &&
      uri.pathSegments.isNotEmpty() &&
      ANDROID_ASSET == uri.pathSegments[0]
  }

  override fun load(
    picasso: Picasso,
    request: Request,
    callback: Callback
  ) {
    initializeIfFirstTime()
    var signaledCallback = false
    try {
      assetManager!!.open(getFilePath(request))
        .source()
        .use { source ->
          val bitmap = decodeStream(source, request)
          signaledCallback = true
          callback.onSuccess(Result.Bitmap(bitmap, DISK))
        }
    } catch (e: Exception) {
      if (!signaledCallback) {
        callback.onError(e)
      }
    }
  }

  @Initializer private fun initializeIfFirstTime() {
    if (assetManager == null) {
      synchronized(lock) {
        if (assetManager == null) {
          assetManager = context.assets
        }
      }
    }
  }

  companion object {
    private const val ANDROID_ASSET = "android_asset"
    private const val ASSET_PREFIX_LENGTH =
      "${ContentResolver.SCHEME_FILE}:///$ANDROID_ASSET/".length

    fun getFilePath(request: Request): String {
      val uri = checkNotNull(request.uri)
      return uri.toString()
        .substring(ASSET_PREFIX_LENGTH)
    }
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/BaseDispatcher.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.Manifest.permission.ACCESS_NETWORK_STATE
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_AIRPLANE_MODE_CHANGED
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.ConnectivityManager.CONNECTIVITY_ACTION
import android.net.NetworkInfo
import android.os.Handler
import android.util.Log
import androidx.annotation.CallSuper
import androidx.annotation.MainThread
import androidx.core.content.ContextCompat
import com.squareup.picasso3.BitmapHunter.Companion.forRequest
import com.squareup.picasso3.MemoryPolicy.Companion.shouldWriteToMemoryCache
import com.squareup.picasso3.NetworkPolicy.NO_CACHE
import com.squareup.picasso3.NetworkRequestHandler.ContentLengthException
import com.squareup.picasso3.RequestHandler.Result.Bitmap
import com.squareup.picasso3.Utils.OWNER_DISPATCHER
import com.squareup.picasso3.Utils.VERB_CANCELED
import com.squareup.picasso3.Utils.VERB_DELIVERED
import com.squareup.picasso3.Utils.VERB_ENQUEUED
import com.squareup.picasso3.Utils.VERB_IGNORED
import com.squareup.picasso3.Utils.VERB_PAUSED
import com.squareup.picasso3.Utils.VERB_REPLAYING
import com.squareup.picasso3.Utils.VERB_RETRYING
import com.squareup.picasso3.Utils.getLogIdsForHunter
import com.squareup.picasso3.Utils.hasPermission
import com.squareup.picasso3.Utils.isAirplaneModeOn
import com.squareup.picasso3.Utils.log
import java.util.WeakHashMap

internal abstract class BaseDispatcher internal constructor(
  private val context: Context,
  private val mainThreadHandler: Handler,
  private val cache: PlatformLruCache
) : Dispatcher {
  @get:JvmName("-hunterMap")
  internal val hunterMap = mutableMapOf<String, BitmapHunter>()

  @get:JvmName("-failedActions")
  internal val failedActions = WeakHashMap<Any, Action>()

  @get:JvmName("-pausedActions")
  internal val pausedActions = WeakHashMap<Any, Action>()

  @get:JvmName("-pausedTags")
  internal val pausedTags = mutableSetOf<Any>()

  @get:JvmName("-receiver")
  internal val receiver: NetworkBroadcastReceiver

  @get:JvmName("-airplaneMode")
  @set:JvmName("-airplaneMode")
  internal var airplaneMode = isAirplaneModeOn(context)

  private val scansNetworkChanges: Boolean

  init {
    scansNetworkChanges = hasPermission(context, ACCESS_NETWORK_STATE)
    receiver = NetworkBroadcastReceiver(this)
    receiver.register()
  }

  @CallSuper override fun shutdown() {
    // Unregister network broadcast receiver on the main thread.
    mainThreadHandler.post { receiver.unregister() }
  }

  fun performSubmit(action: Action, dismissFailed: Boolean = true) {
    if (action.tag in pausedTags) {
      pausedActions[action.getTarget()] = action
      if (action.picasso.isLoggingEnabled) {
        log(
          owner = OWNER_DISPATCHER,
          verb = VERB_PAUSED,
          logId = action.request.logId(),
          extras = "because tag '${action.tag}' is paused"
        )
      }
      return
    }

    var hunter = hunterMap[action.request.key]
    if (hunter != null) {
      hunter.attach(action)
      return
    }

    if (isShutdown()) {
      if (action.picasso.isLoggingEnabled) {
        log(
          owner = OWNER_DISPATCHER,
          verb = VERB_IGNORED,
          logId = action.request.logId(),
          extras = "because shut down"
        )
      }
      return
    }

    hunter = forRequest(action.picasso, this, cache, action)
    dispatchSubmit(hunter)
    hunterMap[action.request.key] = hunter
    if (dismissFailed) {
      failedActions.remove(action.getTarget())
    }

    if (action.picasso.isLoggingEnabled) {
      log(owner = OWNER_DISPATCHER, verb = VERB_ENQUEUED, logId = action.request.logId())
    }
  }

  fun performCancel(action: Action) {
    val key = action.request.key
    val hunter = hunterMap[key]
    if (hunter != null) {
      hunter.detach(action)
      if (hunter.cancel()) {
        hunterMap.remove(key)
        if (action.picasso.isLoggingEnabled) {
          log(OWNER_DISPATCHER, VERB_CANCELED, action.request.logId())
        }
      }
    }

    if (action.tag in pausedTags) {
      pausedActions.remove(action.getTarget())
      if (action.picasso.isLoggingEnabled) {
        log(
          owner = OWNER_DISPATCHER,
          verb = VERB_CANCELED,
          logId = action.request.logId(),
          extras = "because paused request got canceled"
        )
      }
    }

    val remove = failedActions.remove(action.getTarget())
    if (remove != null && remove.picasso.isLoggingEnabled) {
      log(OWNER_DISPATCHER, VERB_CANCELED, remove.request.logId(), "from replaying")
    }
  }

  fun performPauseTag(tag: Any) {
    // Trying to pause a tag that is already paused.
    if (!pausedTags.add(tag)) {
      return
    }

    // Go through all active hunters and detach/pause the requests
    // that have the paused tag.
    val iterator = hunterMap.values.iterator()
    while (iterator.hasNext()) {
      val hunter = iterator.next()
      val loggingEnabled = hunter.picasso.isLoggingEnabled

      val single = hunter.action
      val joined = hunter.actions
      val hasMultiple = !joined.isNullOrEmpty()

      // Hunter has no requests, bail early.
      if (single == null && !hasMultiple) {
        continue
      }

      if (single != null && single.tag == tag) {
        hunter.detach(single)
        pausedActions[single.getTarget()] = single
        if (loggingEnabled) {
          log(
            owner = OWNER_DISPATCHER,
            verb = VERB_PAUSED,
            logId = single.request.logId(),
            extras = "because tag '$tag' was paused"
          )
        }
      }

      if (joined != null) {
        for (i in joined.indices.reversed()) {
          val action = joined[i]
          if (action.tag != tag) {
            continue
          }
          hunter.detach(action)
          pausedActions[action.getTarget()] = action
          if (loggingEnabled) {
            log(
              owner = OWNER_DISPATCHER,
              verb = VERB_PAUSED,
              logId = action.request.logId(),
              extras = "because tag '$tag' was paused"
            )
          }
        }
      }

      // Check if the hunter can be cancelled in case all its requests
      // had the tag being paused here.
      if (hunter.cancel()) {
        iterator.remove()
        if (loggingEnabled) {
          log(
            owner = OWNER_DISPATCHER,
            verb = VERB_CANCELED,
            logId = getLogIdsForHunter(hunter),
            extras = "all actions paused"
          )
        }
      }
    }
  }

  fun performResumeTag(tag: Any) {
    // Trying to resume a tag that is not paused.
    if (!pausedTags.remove(tag)) {
      return
    }

    val batch = mutableListOf<Action>()
    val iterator = pausedActions.values.iterator()
    while (iterator.hasNext()) {
      val action = iterator.next()
      if (action.tag == tag) {
        batch += action
        iterator.remove()
      }
    }

    if (batch.isNotEmpty()) {
      dispatchBatchResumeMain(batch)
    }
  }

  @SuppressLint("MissingPermission")
  fun performRetry(hunter: BitmapHunter) {
    if (hunter.isCancelled) return

    if (isShutdown()) {
      performError(hunter)
      return
    }

    var networkInfo: NetworkInfo? = null
    if (scansNetworkChanges) {
      val connectivityManager =
        ContextCompat.getSystemService(context, ConnectivityManager::class.java)
      if (connectivityManager != null) {
        networkInfo = connectivityManager.activeNetworkInfo
      }
    }

    if (hunter.shouldRetry(airplaneMode, networkInfo)) {
      if (hunter.picasso.isLoggingEnabled) {
        log(
          owner = OWNER_DISPATCHER,
          verb = VERB_RETRYING,
          logId = getLogIdsForHunter(hunter)
        )
      }
      if (hunter.exception is ContentLengthException) {
        hunter.data = hunter.data.newBuilder().networkPolicy(NO_CACHE).build()
      }
      dispatchSubmit(hunter)
    } else {
      performError(hunter)
      // Mark for replay only if we observe network info changes and support replay.
      if (scansNetworkChanges && hunter.supportsReplay()) {
        markForReplay(hunter)
      }
    }
  }

  fun performComplete(hunter: BitmapHunter) {
    if (shouldWriteToMemoryCache(hunter.data.memoryPolicy)) {
      val result = hunter.result
      if (result != null) {
        if (result is Bitmap) {
          val bitmap = result.bitmap
          cache[hunter.key] = bitmap
        }
      }
    }
    hunterMap.remove(hunter.key)
    deliver(hunter)
  }

  fun performError(hunter: BitmapHunter) {
    hunterMap.remove(hunter.key)
    deliver(hunter)
  }

  fun performAirplaneModeChange(airplaneMode: Boolean) {
    this.airplaneMode = airplaneMode
  }

  fun performNetworkStateChange(info: NetworkInfo?) {
    // Intentionally check only if isConnected() here before we flush out failed actions.
    if (info != null && info.isConnected) {
      flushFailedActions()
    }
  }

  @MainThread
  fun performCompleteMain(hunter: BitmapHunter) {
    hunter.picasso.complete(hunter)
  }

  @MainThread
  fun performBatchResumeMain(batch: List<Action>) {
    for (i in batch.indices) {
      val action = batch[i]
      action.picasso.resumeAction(action)
    }
  }

  private fun flushFailedActions() {
    if (failedActions.isNotEmpty()) {
      val iterator = failedActions.values.iterator()
      while (iterator.hasNext()) {
        val action = iterator.next()
        iterator.remove()
        if (action.picasso.isLoggingEnabled) {
          log(
            owner = OWNER_DISPATCHER,
            verb = VERB_REPLAYING,
            logId = action.request.logId()
          )
        }
        performSubmit(action, false)
      }
    }
  }

  private fun markForReplay(hunter: BitmapHunter) {
    hunter.action?.let { markForReplay(it) }
    hunter.actions?.forEach { markForReplay(it) }
  }

  private fun markForReplay(action: Action) {
    val target = action.getTarget()
    action.willReplay = true
    failedActions[target] = action
  }

  private fun deliver(hunter: BitmapHunter) {
    if (hunter.isCancelled) {
      return
    }
    val result = hunter.result
    if (result != null) {
      if (result is Bitmap) {
        val bitmap = result.bitmap
        bitmap.prepareToDraw()
      }
    }

    dispatchCompleteMain(hunter)
    logDelivery(hunter)
  }

  private fun logDelivery(bitmapHunter: BitmapHunter) {
    val picasso = bitmapHunter.picasso
    if (picasso.isLoggingEnabled) {
      log(
        owner = OWNER_DISPATCHER,
        verb = VERB_DELIVERED,
        logId = getLogIdsForHunter(bitmapHunter)
      )
    }
  }

  internal class NetworkBroadcastReceiver(
    private val dispatcher: BaseDispatcher
  ) : BroadcastReceiver() {
    fun register() {
      val filter = IntentFilter()
      filter.addAction(ACTION_AIRPLANE_MODE_CHANGED)
      if (dispatcher.scansNetworkChanges) {
        filter.addAction(CONNECTIVITY_ACTION)
      }
      dispatcher.context.registerReceiver(this, filter)
    }

    fun unregister() {
      dispatcher.context.unregisterReceiver(this)
    }

    @SuppressLint("MissingPermission")
    override fun onReceive(context: Context, intent: Intent?) {
      // On some versions of Android this may be called with a null Intent,
      // also without extras (getExtras() == null), in such case we use defaults.
      if (intent == null) {
        return
      }
      when (intent.action) {
        ACTION_AIRPLANE_MODE_CHANGED -> {
          if (!intent.hasExtra(EXTRA_AIRPLANE_STATE)) {
            return // No airplane state, ignore it. Should we query Utils.isAirplaneModeOn?
          }
          dispatcher.dispatchAirplaneModeChange(intent.getBooleanExtra(EXTRA_AIRPLANE_STATE, false))
        }
        CONNECTIVITY_ACTION -> {
          val connectivityManager =
            ContextCompat.getSystemService(context, ConnectivityManager::class.java)
          val networkInfo = try {
            connectivityManager!!.activeNetworkInfo
          } catch (re: RuntimeException) {
            Log.w(TAG, "System UI crashed, ignoring attempt to change network state.")
            return
          }
          if (networkInfo == null) {
            Log.w(
              TAG,
              "No default network is currently active, ignoring attempt to change network state."
            )
            return
          }
          dispatcher.dispatchNetworkStateChange(networkInfo)
        }
      }
    }

    internal companion object {
      const val EXTRA_AIRPLANE_STATE = "state"
    }
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/BitmapHunter.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.net.NetworkInfo
import com.squareup.picasso3.MemoryPolicy.Companion.shouldReadFromMemoryCache
import com.squareup.picasso3.Picasso.LoadedFrom
import com.squareup.picasso3.RequestHandler.Result.Bitmap
import com.squareup.picasso3.Utils.OWNER_HUNTER
import com.squareup.picasso3.Utils.THREAD_PREFIX
import com.squareup.picasso3.Utils.VERB_DECODED
import com.squareup.picasso3.Utils.VERB_EXECUTING
import com.squareup.picasso3.Utils.VERB_JOINED
import com.squareup.picasso3.Utils.VERB_REMOVED
import com.squareup.picasso3.Utils.VERB_TRANSFORMED
import com.squareup.picasso3.Utils.getLogIdsForHunter
import com.squareup.picasso3.Utils.log
import java.io.IOException
import java.io.InterruptedIOException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Future
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReference
import kotlinx.coroutines.Job

internal open class BitmapHunter(
  val picasso: Picasso,
  private val dispatcher: Dispatcher,
  private val cache: PlatformLruCache,
  action: Action,
  val requestHandler: RequestHandler
) : Runnable {
  val sequence: Int = SEQUENCE_GENERATOR.incrementAndGet()
  var priority: Picasso.Priority = action.request.priority
  var data: Request = action.request
  val key: String = action.request.key
  var retryCount: Int = requestHandler.retryCount

  var action: Action? = action
    private set
  var actions: MutableList<Action>? = null
    private set

  var future: Future<*>? = null

  var job: Job? = null

  var result: RequestHandler.Result? = null
    private set
  var exception: Exception? = null
    private set

  val isCancelled: Boolean
    get() = future?.isCancelled ?: job?.isCancelled ?: false

  override fun run() {
    val originalName = Thread.currentThread().name
    try {
      Thread.currentThread().name = getName()

      if (picasso.isLoggingEnabled) {
        log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this))
      }

      result = hunt()
      dispatcher.dispatchComplete(this)
    } catch (e: IOException) {
      exception = e
      if (retryCount > 0) {
        dispatcher.dispatchRetry(this)
      } else {
        dispatcher.dispatchFailed(this)
      }
    } catch (e: Exception) {
      exception = e
      dispatcher.dispatchFailed(this)
    } finally {
      Thread.currentThread().name = originalName
    }
  }

  fun getName() = NAME_BUILDER.get()!!.also {
    val name = data.name
    it.ensureCapacity(THREAD_PREFIX.length + name.length)
    it.replace(THREAD_PREFIX.length, it.length, name)
  }.toString()

  fun hunt(): Bitmap? {
    if (shouldReadFromMemoryCache(data.memoryPolicy)) {
      cache[key]?.let { bitmap ->
        picasso.cacheHit()
        if (picasso.isLoggingEnabled) {
          log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache")
        }

        return Bitmap(bitmap, LoadedFrom.MEMORY)
      }
    }

    if (retryCount == 0) {
      data = data.newBuilder().networkPolicy(NetworkPolicy.OFFLINE).build()
    }

    val resultReference = AtomicReference<RequestHandler.Result?>()
    val exceptionReference = AtomicReference<Throwable>()

    val latch = CountDownLatch(1)
    try {
      requestHandler.load(
        picasso = picasso,
        request = data,
        callback = object : RequestHandler.Callback {
          override fun onSuccess(result: RequestHandler.Result?) {
            resultReference.set(result)
            latch.countDown()
          }

          override fun onError(t: Throwable) {
            exceptionReference.set(t)
            latch.countDown()
          }
        }
      )

      latch.await()
    } catch (ie: InterruptedException) {
      val interruptedIoException = InterruptedIOException()
      interruptedIoException.initCause(ie)
      throw interruptedIoException
    }

    exceptionReference.get()?.let { throwable ->
      when (throwable) {
        is IOException, is Error, is RuntimeException -> throw throwable
        else -> throw RuntimeException(throwable)
      }
    }

    val result = resultReference.get() as? Bitmap ?: return null
    val bitmap = result.bitmap
    if (picasso.isLoggingEnabled) {
      log(OWNER_HUNTER, VERB_DECODED, data.logId())
    }
    picasso.bitmapDecoded(bitmap)

    val transformations = ArrayList<Transformation>(data.transformations.size + 1)
    if (data.needsMatrixTransform() || result.exifRotation != 0) {
      transformations += MatrixTransformation(data)
    }
    transformations += data.transformations

    val transformedResult =
      applyTransformations(picasso, data, transformations, result) ?: return null
    val transformedBitmap = transformedResult.bitmap
    picasso.bitmapTransformed(transformedBitmap)

    return transformedResult
  }

  fun attach(action: Action) {
    val loggingEnabled = picasso.isLoggingEnabled
    val request = action.request
    if (this.action == null) {
      this.action = action
      if (loggingEnabled) {
        if (actions.isNullOrEmpty()) {
          log(OWNER_HUNTER, VERB_JOINED, request.logId(), "to empty hunter")
        } else {
          log(OWNER_HUNTER, VERB_JOINED, request.logId(), getLogIdsForHunter(this, "to "))
        }
      }

      return
    }

    if (actions == null) {
      actions = ArrayList(3)
    }
    actions!!.add(action)

    if (loggingEnabled) {
      log(OWNER_HUNTER, VERB_JOINED, request.logId(), getLogIdsForHunter(this, "to "))
    }

    val actionPriority = action.request.priority
    if (actionPriority.ordinal > priority.ordinal) {
      priority = actionPriority
    }
  }

  fun detach(action: Action) {
    val detached = when {
      this.action === action -> {
        this.action = null
        true
      }
      else -> actions?.remove(action) ?: false
    }

    // The action being detached had the highest priority. Update this
    // hunter's priority with the remaining actions.
    if (detached && action.request.priority == priority) {
      priority = computeNewPriority()
    }

    if (picasso.isLoggingEnabled) {
      log(OWNER_HUNTER, VERB_REMOVED, action.request.logId(), getLogIdsForHunter(this, "from "))
    }
  }

  fun cancel(): Boolean =
    action == null && actions.isNullOrEmpty() && future?.cancel(false)
      ?: job?.let {
        it.cancel()
        true
      }
      ?: false

  fun shouldRetry(airplaneMode: Boolean, info: NetworkInfo?): Boolean {
    val hasRetries = retryCount > 0
    if (!hasRetries) {
      return false
    }
    retryCount--

    return requestHandler.shouldRetry(airplaneMode, info)
  }

  fun supportsReplay(): Boolean = requestHandler.supportsReplay()

  private fun computeNewPriority(): Picasso.Priority {
    val hasMultiple = actions?.isNotEmpty() ?: false
    val hasAny = action != null || hasMultiple

    // Hunter has no requests, low priority.
    if (!hasAny) {
      return Picasso.Priority.LOW
    }

    var newPriority = action?.request?.priority ?: Picasso.Priority.LOW

    actions?.let { actions ->
      // Index-based loop to avoid allocating an iterator.
      for (i in actions.indices) {
        val priority = actions[i].request.priority
        if (priority.ordinal > newPriority.ordinal) {
          newPriority = priority
        }
      }
    }

    return newPriority
  }

  companion object {
    internal val NAME_BUILDER: ThreadLocal<StringBuilder> = object : ThreadLocal<StringBuilder>() {
      override fun initialValue(): StringBuilder = StringBuilder(THREAD_PREFIX)
    }
    val SEQUENCE_GENERATOR = AtomicInteger()
    internal val ERRORING_HANDLER: RequestHandler = object : RequestHandler() {
      override fun canHandleRequest(data: Request): Boolean = true

      override fun load(picasso: Picasso, request: Request, callback: Callback) {
        callback.onError(IllegalStateException("Unrecognized type of request: $request"))
      }
    }

    fun forRequest(
      picasso: Picasso,
      dispatcher: Dispatcher,
      cache: PlatformLruCache,
      action: Action
    ): BitmapHunter {
      val request = action.request
      val requestHandlers = picasso.requestHandlers

      // Index-based loop to avoid allocating an iterator.
      for (i in requestHandlers.indices) {
        val requestHandler = requestHandlers[i]
        if (requestHandler.canHandleRequest(request)) {
          return BitmapHunter(picasso, dispatcher, cache, action, requestHandler)
        }
      }

      return BitmapHunter(picasso, dispatcher, cache, action, ERRORING_HANDLER)
    }

    fun applyTransformations(
      picasso: Picasso,
      data: Request,
      transformations: List<Transformation>,
      result: Bitmap
    ): Bitmap? {
      var res = result

      for (i in transformations.indices) {
        val transformation = transformations[i]
        val newResult = try {
          val transformedResult = transformation.transform(res)
          if (picasso.isLoggingEnabled) {
            log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from transformations")
          }

          transformedResult
        } catch (e: RuntimeException) {
          Picasso.HANDLER.post {
            throw RuntimeException(
              "Transformation ${transformation.key()} crashed with exception.",
              e
            )
          }

          return null
        }

        val bitmap = newResult.bitmap
        if (bitmap.isRecycled) {
          Picasso.HANDLER.post {
            throw IllegalStateException(
              "Transformation ${transformation.key()} returned a recycled Bitmap."
            )
          }

          return null
        }

        res = newResult
      }

      return res
    }
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/BitmapTarget.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import com.squareup.picasso3.Picasso.LoadedFrom

/**
 * Represents an arbitrary listener for image loading.
 *
 * Objects implementing this class **must** have a working implementation of
 * [Object.equals] and [Object.hashCode] for proper storage internally.
 * Instances of this interface will also be compared to determine if view recycling is occurring.
 * It is recommended that you add this interface directly on to a custom view type when using in an
 * adapter to ensure correct recycling behavior.
 */
interface BitmapTarget {
  /**
   * Callback when an image has been successfully loaded.
   *
   * **Note:** You must not recycle the bitmap.
   */
  fun onBitmapLoaded(
    bitmap: Bitmap,
    from: LoadedFrom
  )

  /**
   * Callback indicating the image could not be successfully loaded.
   *
   * **Note:** The passed [Drawable] may be `null` if none has been
   * specified via [RequestCreator.error] or [RequestCreator.error].
   */
  fun onBitmapFailed(
    e: Exception,
    errorDrawable: Drawable?
  )

  /**
   * Callback invoked right before your request is submitted.
   *
   *
   * **Note:** The passed [Drawable] may be `null` if none has been
   * specified via [RequestCreator.placeholder] or [RequestCreator.placeholder].
   */
  fun onPrepareLoad(placeHolderDrawable: Drawable?)
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/BitmapTargetAction.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.squareup.picasso3.RequestHandler.Result
import com.squareup.picasso3.RequestHandler.Result.Bitmap
import java.lang.ref.WeakReference

internal class BitmapTargetAction(
  picasso: Picasso,
  target: BitmapTarget,
  data: Request,
  private val errorDrawable: Drawable?,
  @DrawableRes val errorResId: Int
) : Action(picasso, data) {
  private val targetReference = WeakReference(target)

  override fun complete(result: Result) {
    val target = targetReference.get() ?: return

    if (result is Bitmap) {
      val bitmap = result.bitmap
      target.onBitmapLoaded(bitmap, result.loadedFrom)
      check(!bitmap.isRecycled) { "Target callback must not recycle bitmap!" }
    }
  }

  override fun error(e: Exception) {
    val target = targetReference.get() ?: return

    val drawable = if (errorResId != 0) {
      ContextCompat.getDrawable(picasso.context, errorResId)
    } else {
      errorDrawable
    }

    target.onBitmapFailed(e, drawable)
  }

  override fun getTarget(): BitmapTarget? {
    return targetReference.get()
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/BitmapUtils.kt
================================================
/*
 * Copyright (C) 2014 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.os.Build.VERSION
import android.util.TypedValue
import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi
import okio.Buffer
import okio.BufferedSource
import okio.ForwardingSource
import okio.Source
import okio.buffer
import java.io.IOException
import java.nio.ByteBuffer
import kotlin.math.max
import kotlin.math.min

internal object BitmapUtils {
  /**
   * Lazily create [BitmapFactory.Options] based in given
   * [Request], only instantiating them if needed.
   */
  fun createBitmapOptions(data: Request): BitmapFactory.Options? {
    val justBounds = data.hasSize()
    return if (justBounds || data.config != null) {
      BitmapFactory.Options().apply {
        inJustDecodeBounds = justBounds
        if (data.config != null) {
          inPreferredConfig = data.config
        }
      }
    } else {
      null
    }
  }

  fun requiresInSampleSize(options: BitmapFactory.Options?): Boolean {
    return options != null && options.inJustDecodeBounds
  }

  fun calculateInSampleSize(
    reqWidth: Int,
    reqHeight: Int,
    options: BitmapFactory.Options,
    request: Request
  ) {
    calculateInSampleSize(
      reqWidth,
      reqHeight,
      options.outWidth,
      options.outHeight,
      options,
      request
    )
  }

  fun shouldResize(
    onlyScaleDown: Boolean,
    inWidth: Int,
    inHeight: Int,
    targetWidth: Int,
    targetHeight: Int
  ): Boolean {
    return (
      !onlyScaleDown || targetWidth != 0 && inWidth > targetWidth ||
        targetHeight != 0 && inHeight > targetHeight
      )
  }

  fun calculateInSampleSize(
    requestWidth: Int,
    requestHeight: Int,
    width: Int,
    height: Int,
    options: BitmapFactory.Options,
    request: Request
  ) {
    options.inSampleSize = ratio(requestWidth, requestHeight, width, height, request)
    options.inJustDecodeBounds = false
  }

  /**
   * Decode a byte stream into a Bitmap. This method will take into account additional information
   * about the supplied request in order to do the decoding efficiently (such as through leveraging
   * `inSampleSize`).
   */
  fun decodeStream(source: Source, request: Request): Bitmap {
    val exceptionCatchingSource = ExceptionCatchingSource(source)
    val bufferedSource = exceptionCatchingSource.buffer()
    val bitmap =
      if (VERSION.SDK_INT >= 28) {
        decodeStreamP(request, bufferedSource)
      } else {
        decodeStreamPreP(request, bufferedSource)
      }
    exceptionCatchingSource.throwIfCaught()
    return bitmap
  }

  @RequiresApi(28)
  @SuppressLint("Override")
  private fun decodeStreamP(request: Request, bufferedSource: BufferedSource): Bitmap {
    val imageSource = ImageDecoder.createSource(ByteBuffer.wrap(bufferedSource.readByteArray()))
    return decodeImageSource(imageSource, request)
  }

  private fun decodeStreamPreP(request: Request, bufferedSource: BufferedSource): Bitmap {
    val isWebPFile = Utils.isWebPFile(bufferedSource)
    val options = createBitmapOptions(request)
    val calculateSize = requiresInSampleSize(options)
    // We decode from a byte array because, when decoding a WebP network stream, BitmapFactory
    // throws a JNI Exception, so we workaround by decoding a byte array.
    val bitmap = if (isWebPFile) {
      val bytes = bufferedSource.readByteArray()
      if (calculateSize) {
        BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)
        calculateInSampleSize(request.targetWidth, request.targetHeight, options!!, request)
      }
      BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)
    } else {
      if (calculateSize) {
        BitmapFactory.decodeStream(bufferedSource.peek().inputStream(), null, options)
        calculateInSampleSize(request.targetWidth, request.targetHeight, options!!, request)
      }
      BitmapFactory.decodeStream(bufferedSource.inputStream(), null, options)
    }
    if (bitmap == null) {
      // Treat null as an IO exception, we will eventually retry.
      throw IOException("Failed to decode bitmap.")
    }
    return bitmap
  }

  fun decodeResource(context: Context, request: Request): Bitmap {
    val resources = Utils.getResources(context, request)
    val id = Utils.getResourceId(resources, request)
    return if (VERSION.SDK_INT >= 28) {
      decodeResourceP(resources, id, request)
    } else {
      decodeResourcePreP(resources, id, request)
    }
  }

  @RequiresApi(28)
  private fun decodeResourceP(resources: Resources, @DrawableRes id: Int, request: Request): Bitmap {
    val imageSource = ImageDecoder.createSource(resources, id)
    return decodeImageSource(imageSource, request)
  }

  private fun decodeResourcePreP(resources: Resources, @DrawableRes id: Int, request: Request): Bitmap {
    val options = createBitmapOptions(request)
    if (requiresInSampleSize(options)) {
      BitmapFactory.decodeResource(resources, id, options)
      calculateInSampleSize(request.targetWidth, request.targetHeight, options!!, request)
    }
    return BitmapFactory.decodeResource(resources, id, options)
  }

  @RequiresApi(28)
  private fun decodeImageSource(imageSource: ImageDecoder.Source, request: Request): Bitmap {
    return ImageDecoder.decodeBitmap(imageSource) { imageDecoder, imageInfo, source ->
      imageDecoder.isMutableRequired = true
      if (request.hasSize()) {
        val size = imageInfo.size
        val width = size.width
        val height = size.height
        val targetWidth = request.targetWidth
        val targetHeight = request.targetHeight
        if (shouldResize(request.onlyScaleDown, width, height, targetWidth, targetHeight)) {
          val ratio = ratio(targetWidth, targetHeight, width, height, request)
          imageDecoder.setTargetSize(width / ratio, height / ratio)
        }
      }
    }
  }

  private fun ratio(
    requestWidth: Int,
    requestHeight: Int,
    width: Int,
    height: Int,
    request: Request
  ): Int =
    if (height > requestHeight || width > requestWidth) {
      val ratio = if (requestHeight == 0) {
        width / requestWidth
      } else if (requestWidth == 0) {
        height / requestHeight
      } else {
        val heightRatio = height / requestHeight
        val widthRatio = width / requestWidth
        if (request.centerInside) {
          max(heightRatio, widthRatio)
        } else {
          min(heightRatio, widthRatio)
        }
      }
      if (ratio != 0) ratio else 1
    } else {
      1
    }

  fun isXmlResource(resources: Resources, @DrawableRes drawableId: Int): Boolean {
    val typedValue = TypedValue()
    resources.getValue(drawableId, typedValue, true)
    val file = typedValue.string
    return file != null && file.toString().endsWith(".xml")
  }

  internal class ExceptionCatchingSource(delegate: Source) : ForwardingSource(delegate) {
    var thrownException: IOException? = null

    override fun read(sink: Buffer, byteCount: Long): Long {
      return try {
        super.read(sink, byteCount)
      } catch (e: IOException) {
        thrownException = e
        throw e
      }
    }

    fun throwIfCaught() {
      if (thrownException is IOException) {
        // TODO: Log when Android returns a non-null Bitmap after swallowing an IOException.
        // TODO: https://github.com/square/picasso/issues/2003/
        throw thrownException as IOException
      }
    }
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/Callback.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

interface Callback {
  fun onSuccess()
  fun onError(t: Throwable)
  open class EmptyCallback : Callback {
    override fun onSuccess() = Unit
    override fun onError(t: Throwable) = Unit
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/ContactsPhotoRequestHandler.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.content.ContentResolver
import android.content.Context
import android.content.UriMatcher
import android.net.Uri
import android.provider.ContactsContract
import android.provider.ContactsContract.Contacts
import com.squareup.picasso3.BitmapUtils.decodeStream
import com.squareup.picasso3.Picasso.LoadedFrom.DISK
import okio.Source
import okio.source
import java.io.FileNotFoundException
import java.io.IOException

internal class ContactsPhotoRequestHandler(private val context: Context) : RequestHandler() {
  companion object {
    /** A lookup uri (e.g. content://com.android.contacts/contacts/lookup/3570i61d948d30808e537) */
    private const val ID_LOOKUP = 1

    /** A contact thumbnail uri (e.g. content://com.android.contacts/contacts/38/photo) */
    private const val ID_THUMBNAIL = 2

    /** A contact uri (e.g. content://com.android.contacts/contacts/38) */
    private const val ID_CONTACT = 3

    /**
     * A contact display photo (high resolution) uri
     * (e.g. content://com.android.contacts/display_photo/5)
     */
    private const val ID_DISPLAY_PHOTO = 4

    private val matcher: UriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
      addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", ID_LOOKUP)
      addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", ID_LOOKUP)
      addURI(ContactsContract.AUTHORITY, "contacts/#/photo", ID_THUMBNAIL)
      addURI(ContactsContract.AUTHORITY, "contacts/#", ID_CONTACT)
      addURI(ContactsContract.AUTHORITY, "display_photo/#", ID_DISPLAY_PHOTO)
    }
  }

  override fun canHandleRequest(data: Request): Boolean {
    val uri = data.uri
    return uri != null &&
      ContentResolver.SCHEME_CONTENT == uri.scheme &&
      Contacts.CONTENT_URI.host == uri.host &&
      matcher.match(data.uri) != UriMatcher.NO_MATCH
  }

  override fun load(
    picasso: Picasso,
    request: Request,
    callback: Callback
  ) {
    var signaledCallback = false
    try {
      val requestUri = checkNotNull(request.uri)
      val source = getSource(requestUri)
      val bitmap = decodeStream(source, request)
      signaledCallback = true
      callback.onSuccess(Result.Bitmap(bitmap, DISK))
    } catch (e: Exception) {
      if (!signaledCallback) {
        callback.onError(e)
      }
    }
  }

  private fun getSource(uri: Uri): Source {
    val contentResolver = context.contentResolver
    val input = when (matcher.match(uri)) {
      ID_LOOKUP -> {
        val contactUri =
          Contacts.lookupContact(contentResolver, uri) ?: throw IOException("no contact found")
        Contacts.openContactPhotoInputStream(contentResolver, contactUri, true)
      }
      ID_CONTACT -> Contacts.openContactPhotoInputStream(contentResolver, uri, true)
      ID_THUMBNAIL, ID_DISPLAY_PHOTO -> contentResolver.openInputStream(uri)
      else -> throw IllegalStateException("Invalid uri: $uri")
    } ?: throw FileNotFoundException("can't open input stream, uri: $uri")

    return input.source()
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/ContentStreamRequestHandler.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import androidx.exifinterface.media.ExifInterface
import androidx.exifinterface.media.ExifInterface.ORIENTATION_NORMAL
import androidx.exifinterface.media.ExifInterface.TAG_ORIENTATION
import com.squareup.picasso3.Picasso.LoadedFrom.DISK
import okio.Source
import okio.source
import java.io.FileNotFoundException

internal open class ContentStreamRequestHandler(val context: Context) : RequestHandler() {
  override fun canHandleRequest(data: Request): Boolean =
    ContentResolver.SCHEME_CONTENT == data.uri?.scheme ?: false

  override fun load(
    picasso: Picasso,
    request: Request,
    callback: Callback
  ) {
    var signaledCallback = false
    try {
      val requestUri = checkNotNull(request.uri)
      val source = getSource(requestUri)
      val bitmap = BitmapUtils.decodeStream(source, request)
      val exifRotation = getExifOrientation(requestUri)
      signaledCallback = true
      callback.onSuccess(Result.Bitmap(bitmap, DISK, exifRotation))
    } catch (e: Exception) {
      if (!signaledCallback) {
        callback.onError(e)
      }
    }
  }

  fun getSource(uri: Uri): Source {
    val contentResolver = context.contentResolver
    val inputStream = contentResolver.openInputStream(uri)
      ?: throw FileNotFoundException("can't open input stream, uri: $uri")
    return inputStream.source()
  }

  protected open fun getExifOrientation(uri: Uri): Int {
    val contentResolver = context.contentResolver
    contentResolver.openInputStream(uri)?.use { input ->
      return ExifInterface(input).getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL)
    } ?: throw FileNotFoundException("can't open input stream, uri: $uri")
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/DeferredRequestCreator.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.view.View
import android.view.View.OnAttachStateChangeListener
import android.view.ViewTreeObserver
import android.widget.ImageView
import java.lang.ref.WeakReference

internal class DeferredRequestCreator(
  private val creator: RequestCreator,
  target: ImageView,
  internal var callback: Callback?
) : ViewTreeObserver.OnPreDrawListener, OnAttachStateChangeListener {
  private val targetReference = WeakReference(target)

  init {
    target.addOnAttachStateChangeListener(this)

    // Only add the pre-draw listener if the view is already attached.
    // See: https://github.com/square/picasso/issues/1321
    if (target.windowToken != null) {
      onViewAttachedToWindow(target)
    }
  }

  override fun onViewAttachedToWindow(view: View) {
    view.viewTreeObserver.addOnPreDrawListener(this)
  }

  override fun onViewDetachedFromWindow(view: View) {
    view.viewTreeObserver.removeOnPreDrawListener(this)
  }

  override fun onPreDraw(): Boolean {
    val target = targetReference.get() ?: return true

    val vto = target.viewTreeObserver
    if (!vto.isAlive) {
      return true
    }

    val width = target.width
    val height = target.height

    if (width <= 0 || height <= 0) {
      return true
    }

    target.removeOnAttachStateChangeListener(this)
    vto.removeOnPreDrawListener(this)
    targetReference.clear()

    creator.unfit().resize(width, height).into(target, callback)
    return true
  }

  fun cancel() {
    creator.clearTag()
    callback = null

    val target = targetReference.get() ?: return
    targetReference.clear()
    target.removeOnAttachStateChangeListener(this)

    val vto = target.viewTreeObserver
    if (vto.isAlive) {
      vto.removeOnPreDrawListener(this)
    }
  }

  val tag: Any?
    get() = creator.tag
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/Dispatcher.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.net.NetworkInfo

internal interface Dispatcher {
  fun shutdown()

  fun dispatchSubmit(action: Action)

  fun dispatchCancel(action: Action)

  fun dispatchPauseTag(tag: Any)

  fun dispatchResumeTag(tag: Any)

  fun dispatchComplete(hunter: BitmapHunter)

  fun dispatchRetry(hunter: BitmapHunter)

  fun dispatchFailed(hunter: BitmapHunter)

  fun dispatchNetworkStateChange(info: NetworkInfo)

  fun dispatchAirplaneModeChange(airplaneMode: Boolean)

  fun dispatchSubmit(hunter: BitmapHunter)

  fun dispatchCompleteMain(hunter: BitmapHunter)

  fun dispatchBatchResumeMain(batch: MutableList<Action>)

  fun isShutdown(): Boolean

  companion object {
    const val RETRY_DELAY = 500L
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/DrawableLoader.kt
================================================
/*
 * Copyright (C) 2018 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes

internal fun interface DrawableLoader {
  fun load(@DrawableRes resId: Int): Drawable?
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/DrawableTarget.kt
================================================
/*
 * Copyright (C) 2022 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.drawable.Drawable
import com.squareup.picasso3.Picasso.LoadedFrom

/**
 * Represents an arbitrary listener for image loading.
 *
 * Objects implementing this class **must** have a working implementation of
 * [Object.equals] and [Object.hashCode] for proper storage internally.
 * Instances of this interface will also be compared to determine if view recycling is occurring.
 * It is recommended that you add this interface directly on to a custom view type when using in an
 * adapter to ensure correct recycling behavior.
 */
interface DrawableTarget {
  /**
   * Callback when an image has been successfully loaded.
   *
   */
  fun onDrawableLoaded(
    drawable: Drawable,
    from: LoadedFrom
  )

  /**
   * Callback indicating the image could not be successfully loaded.
   *
   * **Note:** The passed [Drawable] may be `null` if none has been
   * specified via [RequestCreator.error].
   */
  fun onDrawableFailed(
    e: Exception,
    errorDrawable: Drawable?
  )

  /**
   * Callback invoked right before your request is submitted.
   *
   *
   * **Note:** The passed [Drawable] may be `null` if none has been
   * specified via [RequestCreator.placeholder].
   */
  fun onPrepareLoad(placeHolderDrawable: Drawable?)
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/DrawableTargetAction.kt
================================================
/*
 * Copyright (C) 2022 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.squareup.picasso3.RequestHandler.Result
import com.squareup.picasso3.RequestHandler.Result.Bitmap

internal class DrawableTargetAction(
  picasso: Picasso,
  private val target: DrawableTarget,
  data: Request,
  private val noFade: Boolean,
  private val placeholderDrawable: Drawable?,
  private val errorDrawable: Drawable?,
  @DrawableRes val errorResId: Int
) : Action(picasso, data) {
  override fun complete(result: Result) {
    if (result is Bitmap) {
      val bitmap = result.bitmap
      target.onDrawableLoaded(
        PicassoDrawable(
          context = picasso.context,
          bitmap = bitmap,
          placeholder = placeholderDrawable,
          loadedFrom = result.loadedFrom,
          noFade = noFade,
          debugging = picasso.indicatorsEnabled
        ),
        result.loadedFrom
      )
      check(!bitmap.isRecycled) { "Target callback must not recycle bitmap!" }
    }
  }

  override fun error(e: Exception) {
    val drawable = if (errorResId != 0) {
      ContextCompat.getDrawable(picasso.context, errorResId)
    } else {
      errorDrawable
    }

    target.onDrawableFailed(e, drawable)
  }

  override fun getTarget(): Any {
    return target
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/EventListener.kt
================================================
/*
 * Copyright (C) 2019 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.Bitmap
import java.io.Closeable

interface EventListener : Closeable {
  fun cacheMaxSize(maxSize: Int)
  fun cacheSize(size: Int)
  fun cacheHit()
  fun cacheMiss()
  fun downloadFinished(size: Long)
  fun bitmapDecoded(bitmap: Bitmap)
  fun bitmapTransformed(bitmap: Bitmap)
  override fun close() = Unit
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/FetchAction.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import com.squareup.picasso3.RequestHandler.Result

internal class FetchAction(
  picasso: Picasso,
  data: Request,
  private var callback: Callback?
) : Action(picasso, data) {
  override fun complete(result: Result) {
    callback?.onSuccess()
  }

  override fun error(e: Exception) {
    callback?.onError(e)
  }

  override fun getTarget() = this

  override fun cancel() {
    super.cancel()
    callback = null
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/FileRequestHandler.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import androidx.exifinterface.media.ExifInterface
import com.squareup.picasso3.BitmapUtils.decodeStream
import com.squareup.picasso3.Picasso.LoadedFrom.DISK
import java.io.FileNotFoundException

internal class FileRequestHandler(context: Context) : ContentStreamRequestHandler(context) {
  override fun canHandleRequest(data: Request): Boolean {
    val uri = data.uri
    return uri != null && ContentResolver.SCHEME_FILE == uri.scheme
  }

  override fun load(
    picasso: Picasso,
    request: Request,
    callback: Callback
  ) {
    var signaledCallback = false
    try {
      val requestUri = checkNotNull(request.uri)
      val source = getSource(requestUri)
      val bitmap = decodeStream(source, request)
      val exifRotation = getExifOrientation(requestUri)
      signaledCallback = true
      callback.onSuccess(Result.Bitmap(bitmap, DISK, exifRotation))
    } catch (e: Exception) {
      if (!signaledCallback) {
        callback.onError(e)
      }
    }
  }

  override fun getExifOrientation(uri: Uri): Int {
    val path = uri.path ?: throw FileNotFoundException("path == null, uri: $uri")
    return ExifInterface(path).getAttributeInt(
      ExifInterface.TAG_ORIENTATION,
      ExifInterface.ORIENTATION_NORMAL
    )
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/GetAction.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import com.squareup.picasso3.RequestHandler.Result

internal class GetAction(
  picasso: Picasso,
  data: Request
) : Action(picasso, data) {
  override fun complete(result: Result) = Unit
  override fun error(e: Exception) = Unit
  override fun getTarget() = throw AssertionError()
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/HandlerDispatcher.kt
================================================
/*
 * Copyright (C) 2023 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.content.Context
import android.net.NetworkInfo
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.os.Message
import android.os.Process.THREAD_PRIORITY_BACKGROUND
import com.squareup.picasso3.Picasso.Priority.HIGH
import com.squareup.picasso3.Utils.flushStackLocalLeaks
import java.util.concurrent.ExecutorService

internal class HandlerDispatcher internal constructor(
  context: Context,
  @get:JvmName("-service") val service: ExecutorService,
  mainThreadHandler: Handler,
  cache: PlatformLruCache
) : BaseDispatcher(context, mainThreadHandler, cache) {

  private val dispatcherThread: DispatcherThread
  private val handler: Handler
  private val mainHandler: Handler

  init {
    dispatcherThread = DispatcherThread()
    dispatcherThread.start()
    val dispatcherThreadLooper = dispatcherThread.looper
    flushStackLocalLeaks(dispatcherThreadLooper)
    handler = DispatcherHandler(dispatcherThreadLooper, this)
    mainHandler = MainDispatcherHandler(mainThreadHandler.looper, this)
  }

  override fun shutdown() {
    super.shutdown()
    // Shutdown the thread pool only if it is the one created by Picasso.
    (service as? PicassoExecutorService)?.shutdown()

    dispatcherThread.quit()
  }

  override fun dispatchSubmit(action: Action) {
    handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action))
  }

  override fun dispatchCancel(action: Action) {
    handler.sendMessage(handler.obtainMessage(REQUEST_CANCEL, action))
  }

  override fun dispatchPauseTag(tag: Any) {
    handler.sendMessage(handler.obtainMessage(TAG_PAUSE, tag))
  }

  override fun dispatchResumeTag(tag: Any) {
    handler.sendMessage(handler.obtainMessage(TAG_RESUME, tag))
  }

  override fun dispatchComplete(hunter: BitmapHunter) {
    handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter))
  }

  override fun dispatchRetry(hunter: BitmapHunter) {
    handler.sendMessageDelayed(handler.obtainMessage(HUNTER_RETRY, hunter), RETRY_DELAY)
  }

  override fun dispatchFailed(hunter: BitmapHunter) {
    handler.sendMessage(handler.obtainMessage(HUNTER_DECODE_FAILED, hunter))
  }

  override fun dispatchNetworkStateChange(info: NetworkInfo) {
    handler.sendMessage(handler.obtainMessage(NETWORK_STATE_CHANGE, info))
  }

  override fun dispatchAirplaneModeChange(airplaneMode: Boolean) {
    handler.sendMessage(
      handler.obtainMessage(
        AIRPLANE_MODE_CHANGE,
        if (airplaneMode) AIRPLANE_MODE_ON else AIRPLANE_MODE_OFF,
        0
      )
    )
  }

  override fun dispatchSubmit(hunter: BitmapHunter) {
    hunter.future = service.submit(hunter)
  }

  override fun dispatchCompleteMain(hunter: BitmapHunter) {
    val message = mainHandler.obtainMessage(HUNTER_COMPLETE, hunter)
    if (hunter.priority == HIGH) {
      mainHandler.sendMessageAtFrontOfQueue(message)
    } else {
      mainHandler.sendMessage(message)
    }
  }

  override fun dispatchBatchResumeMain(batch: MutableList<Action>) {
    mainHandler.sendMessage(mainHandler.obtainMessage(REQUEST_BATCH_RESUME, batch))
  }
  override fun isShutdown() = service.isShutdown

  private class DispatcherHandler(
    looper: Looper,
    private val dispatcher: HandlerDispatcher
  ) : Handler(looper) {
    override fun handleMessage(msg: Message) {
      when (msg.what) {
        REQUEST_SUBMIT -> {
          val action = msg.obj as Action
          dispatcher.performSubmit(action)
        }
        REQUEST_CANCEL -> {
          val action = msg.obj as Action
          dispatcher.performCancel(action)
        }
        TAG_PAUSE -> {
          val tag = msg.obj
          dispatcher.performPauseTag(tag)
        }
        TAG_RESUME -> {
          val tag = msg.obj
          dispatcher.performResumeTag(tag)
        }
        HUNTER_COMPLETE -> {
          val hunter = msg.obj as BitmapHunter
          dispatcher.performComplete(hunter)
        }
        HUNTER_RETRY -> {
          val hunter = msg.obj as BitmapHunter
          dispatcher.performRetry(hunter)
        }
        HUNTER_DECODE_FAILED -> {
          val hunter = msg.obj as BitmapHunter
          dispatcher.performError(hunter)
        }
        NETWORK_STATE_CHANGE -> {
          val info = msg.obj as NetworkInfo
          dispatcher.performNetworkStateChange(info)
        }
        AIRPLANE_MODE_CHANGE -> {
          dispatcher.performAirplaneModeChange(msg.arg1 == AIRPLANE_MODE_ON)
        }
        else -> {
          dispatcher.mainHandler.post {
            throw AssertionError("Unknown handler message received: ${msg.what}")
          }
        }
      }
    }
  }

  private class MainDispatcherHandler(
    looper: Looper,
    val dispatcher: HandlerDispatcher
  ) : Handler(looper) {
    override fun handleMessage(msg: Message) {
      when (msg.what) {
        HUNTER_COMPLETE -> {
          val hunter = msg.obj as BitmapHunter
          dispatcher.performCompleteMain(hunter)
        }
        REQUEST_BATCH_RESUME -> {
          val batch = msg.obj as List<Action>
          dispatcher.performBatchResumeMain(batch)
        }
        else -> throw AssertionError("Unknown handler message received: " + msg.what)
      }
    }
  }

  internal class DispatcherThread : HandlerThread(
    Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME,
    THREAD_PRIORITY_BACKGROUND
  )
  internal companion object {
    private const val RETRY_DELAY = 500L
    private const val AIRPLANE_MODE_ON = 1
    private const val AIRPLANE_MODE_OFF = 0
    private const val REQUEST_SUBMIT = 1
    private const val REQUEST_CANCEL = 2
    private const val HUNTER_COMPLETE = 4
    private const val HUNTER_RETRY = 5
    private const val HUNTER_DECODE_FAILED = 6
    private const val NETWORK_STATE_CHANGE = 9
    private const val AIRPLANE_MODE_CHANGE = 10
    private const val TAG_PAUSE = 11
    private const val TAG_RESUME = 12
    private const val REQUEST_BATCH_RESUME = 13
    private const val DISPATCHER_THREAD_NAME = "Dispatcher"
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/ImageViewAction.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable
import android.widget.ImageView
import androidx.annotation.DrawableRes
import com.squareup.picasso3.RequestHandler.Result
import java.lang.ref.WeakReference

internal class ImageViewAction(
  picasso: Picasso,
  target: ImageView,
  data: Request,
  val errorDrawable: Drawable?,
  @DrawableRes val errorResId: Int,
  val noFade: Boolean,
  var callback: Callback?
) : Action(picasso, data) {
  private val targetReference = WeakReference(target)

  override fun complete(result: Result) {
    val target = targetReference.get() ?: return

    PicassoDrawable.setResult(target, picasso.context, result, noFade, picasso.indicatorsEnabled)
    callback?.onSuccess()
  }

  override fun error(e: Exception) {
    val target = targetReference.get() ?: return

    val placeholder = target.drawable
    if (placeholder is Animatable) {
      (placeholder as Animatable).stop()
    }
    if (errorResId != 0) {
      target.setImageResource(errorResId)
    } else if (errorDrawable != null) {
      target.setImageDrawable(errorDrawable)
    }
    callback?.onError(e)
  }

  override fun getTarget(): ImageView? {
    return targetReference.get()
  }

  override fun cancel() {
    super.cancel()
    callback = null
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/Initializer.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import androidx.annotation.RestrictTo
import androidx.annotation.RestrictTo.Scope.LIBRARY
import kotlin.annotation.AnnotationRetention.SOURCE

@Retention(SOURCE)
@RestrictTo(LIBRARY)
annotation class Initializer


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/InternalCoroutineDispatcher.kt
================================================
/*
 * Copyright (C) 2023 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.content.Context
import android.net.NetworkInfo
import android.os.Handler
import com.squareup.picasso3.Dispatcher.Companion.RETRY_DELAY
import com.squareup.picasso3.Picasso.Priority.HIGH
import com.squareup.picasso3.Utils.OWNER_DISPATCHER
import com.squareup.picasso3.Utils.VERB_CANCELED
import com.squareup.picasso3.Utils.log
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

internal class InternalCoroutineDispatcher internal constructor(
  context: Context,
  mainThreadHandler: Handler,
  cache: PlatformLruCache,
  val mainContext: CoroutineContext,
  val backgroundContext: CoroutineContext
) : BaseDispatcher(context, mainThreadHandler, cache) {

  private val scope = CoroutineScope(SupervisorJob() + backgroundContext)
  private val channel = Channel<() -> Unit>(capacity = Channel.UNLIMITED)

  init {
    // Using a channel to enforce sequential access for this class' internal state
    scope.launch {
      channel.receiveAsFlow().collect {
        it.invoke()
      }
    }
  }

  override fun shutdown() {
    super.shutdown()
    channel.close()
    scope.cancel()
  }

  override fun dispatchSubmit(action: Action) {
    channel.trySend {
      performSubmit(action)
    }
  }

  override fun dispatchCancel(action: Action) {
    channel.trySend {
      performCancel(action)
    }
  }

  override fun dispatchPauseTag(tag: Any) {
    channel.trySend {
      performPauseTag(tag)
    }
  }

  override fun dispatchResumeTag(tag: Any) {
    channel.trySend {
      performResumeTag(tag)
    }
  }

  override fun dispatchComplete(hunter: BitmapHunter) {
    channel.trySend {
      performComplete(hunter)
    }
  }

  override fun dispatchRetry(hunter: BitmapHunter) {
    scope.launch {
      delay(RETRY_DELAY)
      channel.send {
        performRetry(hunter)
      }
    }
  }

  override fun dispatchFailed(hunter: BitmapHunter) {
    channel.trySend {
      performError(hunter)
    }
  }

  override fun dispatchNetworkStateChange(info: NetworkInfo) {
    channel.trySend {
      performNetworkStateChange(info)
    }
  }

  override fun dispatchAirplaneModeChange(airplaneMode: Boolean) {
    channel.trySend {
      performAirplaneModeChange(airplaneMode)
    }
  }

  override fun dispatchCompleteMain(hunter: BitmapHunter) {
    scope.launch(mainContext) {
      performCompleteMain(hunter)
    }
  }

  override fun dispatchBatchResumeMain(batch: MutableList<Action>) {
    scope.launch(mainContext) {
      performBatchResumeMain(batch)
    }
  }

  override fun dispatchSubmit(hunter: BitmapHunter) {
    val highPriority = hunter.action?.request?.priority == HIGH
    val context = if (highPriority) EmptyCoroutineContext else mainContext

    scope.launch(context) {
      channel.trySend {
        if (hunter.action != null) {
          hunter.job = scope.launch(CoroutineName(hunter.getName())) {
            hunter.run()
          }
        } else {
          hunterMap.remove(hunter.key)
          if (hunter.picasso.isLoggingEnabled) {
            log(OWNER_DISPATCHER, VERB_CANCELED, hunter.key)
          }
        }
      }
    }
  }

  override fun isShutdown() = !scope.isActive
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/MatrixTransformation.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.graphics.Bitmap.createBitmap
import android.graphics.Matrix
import android.os.Build.VERSION
import android.view.Gravity
import androidx.annotation.VisibleForTesting
import androidx.exifinterface.media.ExifInterface.ORIENTATION_FLIP_HORIZONTAL
import androidx.exifinterface.media.ExifInterface.ORIENTATION_FLIP_VERTICAL
import androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_180
import androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_270
import androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_90
import androidx.exifinterface.media.ExifInterface.ORIENTATION_TRANSPOSE
import androidx.exifinterface.media.ExifInterface.ORIENTATION_TRANSVERSE
import com.squareup.picasso3.BitmapUtils.shouldResize
import com.squareup.picasso3.RequestHandler.Result.Bitmap
import kotlin.math.ceil
import kotlin.math.cos
import kotlin.math.floor
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sin

internal class MatrixTransformation(private val data: Request) : Transformation {
  override fun transform(source: Bitmap): Bitmap {
    val sourceBitmap = source.bitmap
    val transformedBitmap = transformResult(data, sourceBitmap, source.exifRotation)
    return Bitmap(transformedBitmap, source.loadedFrom, source.exifRotation)
  }

  override fun key() = "matrixTransformation()"

  internal companion object {
    @VisibleForTesting
    @JvmName("-transformResult")
    internal fun transformResult(
      data: Request,
      result: android.graphics.Bitmap,
      exifOrientation: Int
    ): android.graphics.Bitmap {
      val inWidth = result.width
      val inHeight = result.height
      val onlyScaleDown = data.onlyScaleDown

      var drawX = 0
      var drawY = 0
      var drawWidth = inWidth
      var drawHeight = inHeight

      val matrix = Matrix()

      if (data.needsMatrixTransform() || exifOrientation != 0) {
        var targetWidth = data.targetWidth
        var targetHeight = data.targetHeight

        val targetRotation = data.rotationDegrees
        if (targetRotation != 0f) {
          val cosR = cos(Math.toRadians(targetRotation.toDouble()))
          val sinR = sin(Math.toRadians(targetRotation.toDouble()))
          if (data.hasRotationPivot) {
            matrix.setRotate(targetRotation, data.rotationPivotX, data.rotationPivotY)
            // Recalculate dimensions after rotation around pivot point
            val x1T = data.rotationPivotX * (1.0 - cosR) + data.rotationPivotY * sinR
            val y1T = data.rotationPivotY * (1.0 - cosR) - data.rotationPivotX * sinR
            val x2T = x1T + data.targetWidth * cosR
            val y2T = y1T + data.targetWidth * sinR
            val x3T = x1T + data.targetWidth * cosR - data.targetHeight * sinR
            val y3T = y1T + data.targetWidth * sinR + data.targetHeight * cosR
            val x4T = x1T - data.targetHeight * sinR
            val y4T = y1T + data.targetHeight * cosR

            val maxX = max(x4T, max(x3T, max(x1T, x2T)))
            val minX = min(x4T, min(x3T, min(x1T, x2T)))
            val maxY = max(y4T, max(y3T, max(y1T, y2T)))
            val minY = min(y4T, min(y3T, min(y1T, y2T)))
            targetWidth = floor(maxX - minX).toInt()
            targetHeight = floor(maxY - minY).toInt()
          } else {
            matrix.setRotate(targetRotation)
            // Recalculate dimensions after rotation (around origin)
            val x1T = 0.0
            val y1T = 0.0
            val x2T = data.targetWidth * cosR
            val y2T = data.targetWidth * sinR
            val x3T = data.targetWidth * cosR - data.targetHeight * sinR
            val y3T = data.targetWidth * sinR + data.targetHeight * cosR
            val x4T = -(data.targetHeight * sinR)
            val y4T = data.targetHeight * cosR

            val maxX = max(x4T, max(x3T, max(x1T, x2T)))
            val minX = min(x4T, min(x3T, min(x1T, x2T)))
            val maxY = max(y4T, max(y3T, max(y1T, y2T)))
            val minY = min(y4T, min(y3T, min(y1T, y2T)))
            targetWidth = floor(maxX - minX).toInt()
            targetHeight = floor(maxY - minY).toInt()
          }
        }

        // EXIf interpretation should be done before cropping in case the dimensions need to
        // be recalculated; SDK 28+ uses ImageDecoder which handles EXIF orientation
        if (exifOrientation != 0 && VERSION.SDK_INT < 28) {
          val exifRotation = getExifRotation(exifOrientation)
          val exifTranslation = getExifTranslation(exifOrientation)
          if (exifRotation != 0) {
            matrix.preRotate(exifRotation.toFloat())
            if (exifRotation == 90 || exifRotation == 270) {
              // Recalculate dimensions after exif rotation
              val tmpHeight = targetHeight
              targetHeight = targetWidth
              targetWidth = tmpHeight
            }
          }
          if (exifTranslation != 1) {
            matrix.postScale(exifTranslation.toFloat(), 1f)
          }
        }

        if (data.centerCrop) {
          // Keep aspect ratio if one dimension is set to 0
          val widthRatio = if (targetWidth != 0) {
            targetWidth / inWidth.toFloat()
          } else {
            targetHeight / inHeight.toFloat()
          }
          val heightRatio = if (targetHeight != 0) {
            targetHeight / inHeight.toFloat()
          } else {
            targetWidth / inWidth.toFloat()
          }
          val scaleX: Float
          val scaleY: Float
          if (widthRatio > heightRatio) {
            val newSize = ceil((inHeight * (heightRatio / widthRatio)).toDouble()).toInt()
            drawY = if (data.centerCropGravity and Gravity.TOP == Gravity.TOP) {
              0
            } else if (data.centerCropGravity and Gravity.BOTTOM == Gravity.BOTTOM) {
              inHeight - newSize
            } else {
              (inHeight - newSize) / 2
            }
            drawHeight = newSize
            scaleX = widthRatio
            scaleY = targetHeight / drawHeight.toFloat()
          } else if (widthRatio < heightRatio) {
            val newSize = ceil((inWidth * (widthRatio / heightRatio)).toDouble()).toInt()
            drawX = if (data.centerCropGravity and Gravity.LEFT == Gravity.LEFT) {
              0
            } else if (data.centerCropGravity and Gravity.RIGHT == Gravity.RIGHT) {
              inWidth - newSize
            } else {
              (inWidth - newSize) / 2
            }
            drawWidth = newSize
            scaleX = targetWidth / drawWidth.toFloat()
            scaleY = heightRatio
          } else {
            drawX = 0
            drawWidth = inWidth
            scaleY = heightRatio
            scaleX = scaleY
          }
          if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {
            matrix.preScale(scaleX, scaleY)
          }
        } else if (data.centerInside) {
          // Keep aspect ratio if one dimension is set to 0
          val widthRatio =
            if (targetWidth != 0) targetWidth / inWidth.toFloat() else targetHeight / inHeight.toFloat()
          val heightRatio =
            if (targetHeight != 0) targetHeight / inHeight.toFloat() else targetWidth / inWidth.toFloat()
          val scale = if (widthRatio < heightRatio) widthRatio else heightRatio
          if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {
            matrix.preScale(scale, scale)
          }
        } else if ((targetWidth != 0 || targetHeight != 0) && //
          (targetWidth != inWidth || targetHeight != inHeight)
        ) {
          // If an explicit target size has been specified and they do not match the results bounds,
          // pre-scale the existing matrix appropriately.
          // Keep aspect ratio if one dimension is set to 0.
          val sx =
            if (targetWidth != 0) targetWidth / inWidth.toFloat() else targetHeight / inHeight.toFloat()
          val sy =
            if (targetHeight != 0) targetHeight / inHeight.toFloat() else targetWidth / inWidth.toFloat()
          if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {
            matrix.preScale(sx, sy)
          }
        }
      }

      val transformedResult = createBitmap(result, drawX, drawY, drawWidth, drawHeight, matrix, true)
      if (transformedResult != result) {
        result.recycle()
      }
      return transformedResult
    }

    @Suppress("MemberVisibilityCanBePrivate")
    @JvmName("-getExifRotation")
    internal fun getExifRotation(orientation: Int) =
      when (orientation) {
        ORIENTATION_ROTATE_90, ORIENTATION_TRANSPOSE -> 90
        ORIENTATION_ROTATE_180, ORIENTATION_FLIP_VERTICAL -> 180
        ORIENTATION_ROTATE_270, ORIENTATION_TRANSVERSE -> 270
        else -> 0
      }

    @Suppress("MemberVisibilityCanBePrivate")
    @JvmName("-getExifTranslation")
    internal fun getExifTranslation(orientation: Int) =
      when (orientation) {
        ORIENTATION_FLIP_HORIZONTAL, ORIENTATION_FLIP_VERTICAL,
        ORIENTATION_TRANSPOSE, ORIENTATION_TRANSVERSE -> -1
        else -> 1
      }
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/MediaStoreRequestHandler.kt
================================================
/*
 * Copyright (C) 2014 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.provider.MediaStore
import android.provider.MediaStore.Video
import com.squareup.picasso3.BitmapUtils.calculateInSampleSize
import com.squareup.picasso3.BitmapUtils.createBitmapOptions
import com.squareup.picasso3.BitmapUtils.decodeStream
import com.squareup.picasso3.Picasso.LoadedFrom

internal class MediaStoreRequestHandler(context: Context) : ContentStreamRequestHandler(context) {
  override fun canHandleRequest(data: Request): Boolean {
    val uri = data.uri
    return uri != null &&
      ContentResolver.SCHEME_CONTENT == uri.scheme &&
      MediaStore.AUTHORITY == uri.authority
  }

  override fun load(picasso: Picasso, request: Request, callback: Callback) {
    var signaledCallback = false
    try {
      val contentResolver = context.contentResolver
      val requestUri = checkNotNull(request.uri, { "request.uri == null" })
      val exifOrientation = getExifOrientation(requestUri)

      val mimeType = contentResolver.getType(requestUri)
      val isVideo = mimeType != null && mimeType.startsWith("video/")

      if (request.hasSize()) {
        val picassoKind = getPicassoKind(request.targetWidth, request.targetHeight)
        if (!isVideo && picassoKind == PicassoKind.FULL) {
          val source = getSource(requestUri)
          val bitmap = decodeStream(source, request)
          signaledCallback = true
          callback.onSuccess(Result.Bitmap(bitmap, LoadedFrom.DISK, exifOrientation))
          return
        }

        val id = ContentUris.parseId(requestUri)

        val options = checkNotNull(createBitmapOptions(request), { "options == null" })
        options.inJustDecodeBounds = true

        calculateInSampleSize(
          request.targetWidth,
          request.targetHeight,
          picassoKind.width,
          picassoKind.height,
          options,
          request
        )

        val bitmap = if (isVideo) {
          // Since MediaStore doesn't provide the full screen kind thumbnail, we use the mini kind
          // instead which is the largest thumbnail size can be fetched from MediaStore.
          val kind =
            if (picassoKind == PicassoKind.FULL) Video.Thumbnails.MINI_KIND else picassoKind.androidKind
          Video.Thumbnails.getThumbnail(contentResolver, id, kind, options)
        } else {
          MediaStore.Images.Thumbnails.getThumbnail(
            contentResolver,
            id,
            picassoKind.androidKind,
            options
          )
        }

        if (bitmap != null) {
          signaledCallback = true
          callback.onSuccess(Result.Bitmap(bitmap, LoadedFrom.DISK, exifOrientation))
          return
        }
      }

      val source = getSource(requestUri)
      val bitmap = decodeStream(source, request)
      signaledCallback = true
      callback.onSuccess(Result.Bitmap(bitmap, LoadedFrom.DISK, exifOrientation))
    } catch (e: Exception) {
      if (!signaledCallback) {
        callback.onError(e)
      }
    }
  }

  internal enum class PicassoKind(val androidKind: Int, val width: Int, val height: Int) {
    MICRO(MediaStore.Images.Thumbnails.MICRO_KIND, 96, 96),
    MINI(MediaStore.Images.Thumbnails.MINI_KIND, 512, 384),
    FULL(MediaStore.Images.Thumbnails.FULL_SCREEN_KIND, -1, -1)
  }

  companion object {
    fun getPicassoKind(targetWidth: Int, targetHeight: Int): PicassoKind {
      return if (targetWidth <= PicassoKind.MICRO.width && targetHeight <= PicassoKind.MICRO.height) {
        PicassoKind.MICRO
      } else if (targetWidth <= PicassoKind.MINI.width && targetHeight <= PicassoKind.MINI.height) {
        PicassoKind.MINI
      } else {
        PicassoKind.FULL
      }
    }
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/MemoryPolicy.kt
================================================
/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

/** Designates the policy to use when dealing with memory cache.  */
enum class MemoryPolicy(val index: Int) {
  /** Skips memory cache lookup when processing a request.  */
  NO_CACHE(1 shl 0),

  /**
   * Skips storing the final result into memory cache. Useful for one-off requests
   * to avoid evicting other bitmaps from the cache.
   */
  NO_STORE(1 shl 1);

  companion object {
    @JvmStatic fun shouldReadFromMemoryCache(memoryPolicy: Int) =
      memoryPolicy and NO_CACHE.index == 0

    @JvmStatic fun shouldWriteToMemoryCache(memoryPolicy: Int) =
      memoryPolicy and NO_STORE.index == 0
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/NetworkPolicy.kt
================================================
/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

/** Designates the policy to use for network requests.  */
enum class NetworkPolicy(val index: Int) {
  /**
   * Skips checking the disk cache and forces loading through the network.
   */
  NO_CACHE(1 shl 0),

  /**
   * Skips storing the result into the disk cache.
   */
  NO_STORE(1 shl 1),

  /**
   * Forces the request through the disk cache only, skipping network.
   */
  OFFLINE(1 shl 2);

  companion object {
    @JvmStatic fun shouldReadFromDiskCache(networkPolicy: Int) =
      networkPolicy and NO_CACHE.index == 0

    @JvmStatic fun shouldWriteToDiskCache(networkPolicy: Int) =
      networkPolicy and NO_STORE.index == 0

    @JvmStatic fun isOfflineOnly(networkPolicy: Int) =
      networkPolicy and OFFLINE.index != 0
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/NetworkRequestHandler.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.net.NetworkInfo
import com.squareup.picasso3.BitmapUtils.decodeStream
import com.squareup.picasso3.NetworkPolicy.Companion.isOfflineOnly
import com.squareup.picasso3.NetworkPolicy.Companion.shouldReadFromDiskCache
import com.squareup.picasso3.NetworkPolicy.Companion.shouldWriteToDiskCache
import com.squareup.picasso3.Picasso.LoadedFrom.DISK
import com.squareup.picasso3.Picasso.LoadedFrom.NETWORK
import okhttp3.CacheControl
import okhttp3.Call
import okhttp3.Response
import java.io.IOException

internal class NetworkRequestHandler(
  private val callFactory: Call.Factory
) : RequestHandler() {
  override fun canHandleRequest(data: Request): Boolean {
    val uri = data.uri ?: return false
    val scheme = uri.scheme
    return SCHEME_HTTP.equals(scheme, ignoreCase = true) ||
      SCHEME_HTTPS.equals(scheme, ignoreCase = true)
  }

  override fun load(picasso: Picasso, request: Request, callback: Callback) {
    val callRequest = createRequest(request)
    callFactory
      .newCall(callRequest)
      .enqueue(object : okhttp3.Callback {
        override fun onResponse(call: Call, response: Response) {
          if (!response.isSuccessful) {
            callback.onError(ResponseException(response.code, request.networkPolicy))
            return
          }

          // Cache response is only null when the response comes fully from the network. Both
          // completely cached and conditionally cached responses will have a non-null cache
          // response.
          val loadedFrom = if (response.cacheResponse == null) NETWORK else DISK

          // Sometimes response content length is zero when requests are being replayed.
          // Haven't found root cause to this but retrying the request seems safe to do so.
          val body = response.body
          if (loadedFrom == DISK && body!!.contentLength() == 0L) {
            body.close()
            callback.onError(
              ContentLengthException("Received response with 0 content-length header.")
            )
            return
          }
          if (loadedFrom == NETWORK && body!!.contentLength() > 0) {
            picasso.downloadFinished(body.contentLength())
          }
          try {
            val bitmap = decodeStream(body!!.source(), request)
            callback.onSuccess(Result.Bitmap(bitmap, loadedFrom))
          } catch (e: IOException) {
            body!!.close()
            callback.onError(e)
          }
        }

        override fun onFailure(call: Call, e: IOException) {
          callback.onError(e)
        }
      })
  }

  override val retryCount: Int
    get() = 2

  override fun shouldRetry(airplaneMode: Boolean, info: NetworkInfo?): Boolean =
    info == null || info.isConnected

  override fun supportsReplay(): Boolean = true

  private fun createRequest(request: Request): okhttp3.Request {
    var cacheControl: CacheControl? = null
    val networkPolicy = request.networkPolicy
    if (networkPolicy != 0) {
      cacheControl = if (isOfflineOnly(networkPolicy)) {
        CacheControl.FORCE_CACHE
      } else {
        val builder = CacheControl.Builder()
        if (!shouldReadFromDiskCache(networkPolicy)) {
          builder.noCache()
        }
        if (!shouldWriteToDiskCache(networkPolicy)) {
          builder.noStore()
        }
        builder.build()
      }
    }

    val uri = checkNotNull(request.uri) { "request.uri == null" }
    val builder = okhttp3.Request.Builder().url(uri.toString())
    if (cacheControl != null) {
      builder.cacheControl(cacheControl)
    }
    val requestHeaders = request.headers
    if (requestHeaders != null) {
      builder.headers(requestHeaders)
    }
    return builder.build()
  }

  internal class ContentLengthException(message: String) : RuntimeException(message)
  internal class ResponseException(
    val code: Int,
    val networkPolicy: Int
  ) : RuntimeException("HTTP $code")

  private companion object {
    private const val SCHEME_HTTP = "http"
    private const val SCHEME_HTTPS = "https"
  }
}


================================================
FILE: picasso/src/main/java/com/squareup/picasso3/Picasso.kt
================================================
/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso3

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.Config
import android.graphics.Color
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.widget.ImageView
import android.widget.RemoteViews
import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.squareup.picasso3.MemoryPolicy.Companion.shouldReadFromMemoryCache
import com.squareup.picasso3.Picasso.LoadedFrom.MEMORY
import com.squareup.picasso3.RemoteViewsAction.RemoteViewsTarget
import com.squareup.picasso3.RequestHandler.Result
import com.squareup.picasso3.Utils.OWNER_MAIN
import com.squareup.picasso3.Utils.VERB_COMPLETED
import com.squareup.picasso3.Utils.VERB_ERRORED
import com.squareup.picasso3.Utils.VERB_RESUMED
import com.squareup.picasso3.Utils.calculateDiskCacheSize
import com.squareup.picasso3.Utils.calculateMemoryCacheSize
import com.squareup.picasso3.Utils.checkMain
import com.squareup.picasso3.Utils.createDefaultCacheDir
import com.squareup.picasso3.Utils.log
import okhttp3.Cache
import okhttp3.Call
import okhttp3.OkHttpClient
import java.io.File
import java.io.IOException
import java.util.WeakHashMap
import java.util.concurrent.ExecutorService
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.Dispatchers

/**
 * Image downloading, transformation, and caching manager.
 *
 * Use [PicassoProvider.get] for a global singleton instance
 * or construct your own instance with [Picasso.Builder].
 */
@OptIn(ExperimentalStdlibApi::class)
class Picasso internal constructor(
  @get:JvmName("-context") internal val context: Context,
  @get:JvmName("-dispatcher") internal val dispatcher: Dispatcher,
  @get:JvmName("-callFactory") internal val callFactory: Call.Factory,
  private val closeableCache: Cache?,
  @get:JvmName("-cache") internal val cache: PlatformLruCache,
  @get:JvmName("-listener") internal val listener: Listener?,
  requestTransformers: List<RequestTransformer>,
  extraRequestHandlers: List<RequestHandler>,
  eventListeners: List<EventListener>,
  @get:JvmName("-defaultBitmapConfig") internal val defaultBitmapConfig: Config?,
  /** Toggle whether to display debug indicators on images.  */
  var indicatorsEnabled: Boolean,
  /**
   * Toggle whether debug logging is enabled.
   *
   * **WARNING:** Enabling this will result in excessive object allocation. This should be only
   * be used for debugging purposes. Do NOT pass `BuildConfig.DEBUG`.
   */
  @Volatile var isLoggingEnabled: Boolean
) : DefaultLifecycleObserver {
  @get:JvmName("-requestTransformers")
  internal val requestTransformers: List<RequestTransformer> = requestTransformers.toList()

  @get:JvmName("-requestHandlers")
  internal val requestHandlers: List<RequestHandler>

  @get:JvmName("-eventListeners")
  internal val eventListeners: List<EventListener> = eventListeners.toList()

  @get:JvmName("-targetToAction")
  internal val targetToAction = WeakHashMap<Any, Action>()

  @get:JvmName("-targetToDeferredRequestCreator")
  internal val targetToDeferredRequestCreator = WeakHashMap<ImageView, DeferredRequestCreator>()

  @get:JvmName("-shutdown")
  @set:JvmName("-shutdown")
  internal var shutdown = false

  init {
    // Adjust this and Builder(Picasso) as internal handlers are added or removed.
    val builtInHandlers = 8

    requestHandlers = buildList(builtInHandlers + extraRequestHandlers.size) {
      // ResourceRequestHandler needs to be the first in the list to avoid
      // forcing other RequestHandlers to perform null checks on request.uri
      // to cover the (request.resourceId != 0) case.
      add(ResourceDrawableRequestHandler.create(context))
      add(ResourceRequestHandler(context))
      addAll(extraRequestHandlers)
      add(ContactsPhotoRequestHandler(context))
      add(MediaStoreRequestHandler(context))
      add(ContentStreamRequestHandler(context))
      add(AssetRequestHandler(context))
      add(FileRequestHandler(context))
      add(NetworkRequestHandler(callFactory))
    }
  }

  override fun onDestroy(owner: LifecycleOwner) {
    super.onDestroy(owner)
    cancelAll()
  }

  @JvmName("-cancelAll")
  internal fun cancelAll() {
    checkMain()

    val actions = targetToAction.values.toList()
    for (i in actions.indices) {
      val target = actions[i].getTarget() ?: continue
      cancelExistingRequest(target)
    }

    val deferredRequestCreators = targetToDeferredRequestCreator.values.toList()
    for (i in deferredRequestCreators.indices) {
      deferredRequestCreators[i].cancel()
    }
  }

  /** Cancel any existing requests for the specified target [ImageView]. */
  fun cancelRequest(view: ImageView) {
    // checkMain() is called from cancelExistingRequest()
    cancelExistingRequest(view)
  }

  /** Cancel any existing requests for the specified [BitmapTarget] instance. */
  fun cancelRequest(target: BitmapTarget) {
    // checkMain() is called from cancelExistingRequest()
    cancelExistingRequest(target)
  }

  /** Cancel any existing requests for the specified [DrawableTarget] instance. */
  fun cancelRequest(target: DrawableTarget) {
    // checkMain() is called from cancelExistingRequest()
    cancelExistingRequest(target)
  }

  /**
   * Cancel any existing requests for the specified [RemoteViews] target with the given [viewId].
   */
  fun cancelRequest(remoteViews: RemoteViews, @IdRes viewId: Int) {
    // checkMain() is called from cancelExistingRequest()
    cancelExistingRequest(RemoteViewsTarget(remoteViews, viewId))
  }

  /**
   * Cancel any existing requests with given tag. You can set a tag
   * on new requests with [RequestCreator.tag].
   *
   * @see RequestCreator.tag
   */
  fun cancelTag(tag: Any) {
    checkMain()

    val actions = targetToAction.values.toList()
    for (i in actions.indices) {
      val action = actions[i]
      if (tag == action.tag) {
        val target = action.getTarget() ?: continue
        cancelExistingRequest(target)
      }
    }

    val deferredRequestCreators = targetToDeferredRequestCreator.values.toList()
    for (i in deferredRequestCreators.indices) {
      val deferredRequestCreator = deferredRequestCreators[i]
      if (tag == deferredRequestCreator.tag) {
        deferredRequestCreator.cancel()
      }
    }
  }

  override fun onStop(owner: LifecycleOwner) {
    super.onStop(owner)
    pauseAll()
  }

  @JvmName("-pauseAll")
  internal fun pauseAll() {
    checkMain()

    val actions = targetToAction.values.toList()
    for (i in actions.indices) {
      dispatcher.dispatchPauseTag(actions[i].tag)
    }

    val deferredRequestCreators = targetToDeferredRequestCreator.values.toList()
    for (i in deferredRequestCreators.indices) {
      val tag = deferredRequestCreators[i].tag
      if (tag != null) {
        dispatcher.dispatchPauseTag(tag)
      }
    }
  }

  /**
   * Pause existing requests with the given tag. Use [resumeTag]
   * to resume requests with the given tag.
   *
   * @see [resumeTag]
   * @see RequestCreator.tag
   */
  fun pauseTag(tag: Any) {
    dispatcher.dispatchPauseTag(tag)
  }

  override fun onStart(owner: LifecycleOwner) {
    resumeAll()
  }

  @JvmName("-resumeAll")
  internal fun resumeAll() {
    checkMain()

    val actions = targetToAction.values.toList()
    for (i in actions.indices) {
      dispatcher.dispatchResumeTag(actions[i].tag)
    }

    val deferredRequestCreators = targetToDeferredRequestCreator.values.toList()
    for (i in deferredRequestCreators.indices) {
      val tag = deferredRequestCreators[i].tag
      if (tag != null) {
        dispatcher.dispatchResumeTag(tag)
      }
    }
  }

  /**
   * Resume paused requests with the given tag. Use [pauseTag]
   * to pause requests with the given tag.
   *
   * @see [pauseTag]
   * @see RequestCreator.tag
   */
  fun resumeTag(tag: Any) {
    dispatcher.dispatchResumeTag(tag)
  }

  /**
   * Start an image request using the specified URI.
   *
   * Passing `null` as a [uri] will not trigger any request but will set a placeholder,
   * if one is specified.
   *
   * @see #load(File)
   * @see #load(String)
   * @see #load(int)
   */
  fun load(uri: Uri?): RequestCreator {
    return RequestCreator(this, uri, 0)
  }

  /**
   * Start an image request using the specified path. This is a convenience method for calling
   * [load].
   *
   * This path may be a remote URL, file resource (prefixed with `file:`), content resource
   * (prefixed with `content:`), or android resource (prefixed with `android.resource:`.
   *
   * Passing `null` as a [path] will not trigger any request but will set a
   * placeholder, if one is specified.
   *
   * @throws IllegalArgumentException if [path] is empty or blank string.
   * @see #load(Uri)
   * @see #load(File)
   * @see #load(int)
   */
  fun load(path: String?): RequestCreator {
    if (path == null) {
      return RequestCreator(this, null, 0)
    }
    require(path.isNotBlank()) { "Path must not be empty." }
    return load(Uri.parse(path))
  }

  /**
   * Start an image request using the specified image file. This is a convenience method for
   * calling [load].
   *
   * Passing `null` as a [file] will not trigger any request but will set a
   * placeholder, if one is specified.
   *
   * Equivalent to calling [load(Uri.fromFile(file))][load].
   *
   * @see #load(Uri)
   * @see #load(String)
   * @see #load(int)
   */
  fun load(file: File?): RequestCreator {
    return if (file == null) {
      RequestCreator(this, null, 0)
    } else {
      load(Uri.fromFile(file))
    }
  }

  /**
   * Start an image request using the specified drawable resource ID.
   *
   * @see #load(Uri)
   * @see #load(String)
   * @see #load(File)
   */
  fun load(@DrawableRes resourceId: Int): RequestCreator {
    require(resourceId != 0) { "Resource ID must not be zero." }
    return RequestCreator(this, null, resourceId)
  }

  /**
   * Clear a
Download .txt
gitextract_m46ss2gs/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       ├── build.yaml
│       └── release.yaml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── RELEASING.md
├── build.gradle
├── deploy_website.sh
├── gradle/
│   ├── libs.versions.toml
│   ├── license-header.txt
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── lint.xml
├── picasso/
│   ├── api/
│   │   └── picasso.api
│   ├── build.gradle
│   ├── consumer-proguard-rules.txt
│   ├── gradle.properties
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   └── java/
│       │       └── com/
│       │           └── squareup/
│       │               └── picasso3/
│       │                   ├── AssetRequestHandlerTest.kt
│       │                   ├── BitmapUtilsTest.kt
│       │                   ├── PicassoDrawableTest.kt
│       │                   ├── PlatformLruCacheTest.kt
│       │                   └── TestUtils.kt
│       ├── main/
│       │   └── java/
│       │       └── com/
│       │           └── squareup/
│       │               └── picasso3/
│       │                   ├── Action.kt
│       │                   ├── AssetRequestHandler.kt
│       │                   ├── BaseDispatcher.kt
│       │                   ├── BitmapHunter.kt
│       │                   ├── BitmapTarget.kt
│       │                   ├── BitmapTargetAction.kt
│       │                   ├── BitmapUtils.kt
│       │                   ├── Callback.kt
│       │                   ├── ContactsPhotoRequestHandler.kt
│       │                   ├── ContentStreamRequestHandler.kt
│       │                   ├── DeferredRequestCreator.kt
│       │                   ├── Dispatcher.kt
│       │                   ├── DrawableLoader.kt
│       │                   ├── DrawableTarget.kt
│       │                   ├── DrawableTargetAction.kt
│       │                   ├── EventListener.kt
│       │                   ├── FetchAction.kt
│       │                   ├── FileRequestHandler.kt
│       │                   ├── GetAction.kt
│       │                   ├── HandlerDispatcher.kt
│       │                   ├── ImageViewAction.kt
│       │                   ├── Initializer.kt
│       │                   ├── InternalCoroutineDispatcher.kt
│       │                   ├── MatrixTransformation.kt
│       │                   ├── MediaStoreRequestHandler.kt
│       │                   ├── MemoryPolicy.kt
│       │                   ├── NetworkPolicy.kt
│       │                   ├── NetworkRequestHandler.kt
│       │                   ├── Picasso.kt
│       │                   ├── PicassoDrawable.kt
│       │                   ├── PicassoExecutorService.kt
│       │                   ├── PlatformLruCache.kt
│       │                   ├── RemoteViewsAction.kt
│       │                   ├── Request.kt
│       │                   ├── RequestCreator.kt
│       │                   ├── RequestHandler.kt
│       │                   ├── ResourceDrawableRequestHandler.kt
│       │                   ├── ResourceRequestHandler.kt
│       │                   ├── Transformation.kt
│       │                   └── Utils.kt
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── squareup/
│           │           └── picasso3/
│           │               ├── BaseDispatcherTest.kt
│           │               ├── BitmapHunterTest.kt
│           │               ├── BitmapTargetActionTest.kt
│           │               ├── DeferredRequestCreatorTest.kt
│           │               ├── DrawableTargetActionTest.kt
│           │               ├── HandlerDispatcherTest.kt
│           │               ├── ImageViewActionTest.kt
│           │               ├── InternalCoroutineDispatcherTest.kt
│           │               ├── MediaStoreRequestHandlerTest.kt
│           │               ├── MemoryPolicyTest.kt
│           │               ├── NetworkRequestHandlerTest.kt
│           │               ├── PicassoTest.kt
│           │               ├── RemoteViewsActionTest.kt
│           │               ├── RequestCreatorTest.kt
│           │               ├── Shadows.kt
│           │               ├── TestContentProvider.kt
│           │               ├── TestTransformation.kt
│           │               ├── TestUtils.kt
│           │               ├── UtilsTest.kt
│           │               └── _JavaConsumerIdeCheck.java
│           └── resources/
│               ├── mockito-extensions/
│               │   └── org.mockito.plugins.MockMaker
│               └── robolectric.properties
├── picasso-compose/
│   ├── README.md
│   ├── api/
│   │   └── picasso-compose.api
│   ├── build.gradle
│   ├── gradle.properties
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── squareup/
│       │               └── picasso3/
│       │                   └── compose/
│       │                       └── PicassoPainterTest.kt
│       └── main/
│           └── java/
│               └── com/
│                   └── squareup/
│                       └── picasso3/
│                           └── compose/
│                               └── PicassoPainter.kt
├── picasso-paparazzi-sample/
│   ├── build.gradle
│   └── src/
│       └── test/
│           └── java/
│               └── com/
│                   └── example/
│                       └── picasso/
│                           └── paparazzi/
│                               └── PicassoPaparazziTest.kt
├── picasso-pollexor/
│   ├── README.md
│   ├── api/
│   │   └── picasso-pollexor.api
│   ├── build.gradle
│   ├── gradle.properties
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── com/
│       │           └── squareup/
│       │               └── picasso3/
│       │                   └── pollexor/
│       │                       └── PollexorRequestTransformer.kt
│       └── test/
│           └── java/
│               └── com/
│                   └── squareup/
│                       └── picasso3/
│                           └── pollexor/
│                               └── PollexorRequestTransformerTest.kt
├── picasso-sample/
│   ├── build.gradle
│   ├── lint.xml
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── example/
│           │           └── picasso/
│           │               ├── Data.kt
│           │               ├── GrayscaleTransformation.kt
│           │               ├── PicassoInitializer.kt
│           │               ├── PicassoSampleActivity.kt
│           │               ├── PicassoSampleAdapter.kt
│           │               ├── SampleComposeActivity.kt
│           │               ├── SampleContactsActivity.kt
│           │               ├── SampleContactsAdapter.kt
│           │               ├── SampleGalleryActivity.kt
│           │               ├── SampleGridViewActivity.kt
│           │               ├── SampleGridViewAdapter.kt
│           │               ├── SampleListDetailActivity.kt
│           │               ├── SampleListDetailAdapter.kt
│           │               ├── SampleScrollListener.kt
│           │               ├── SampleWidgetProvider.kt
│           │               └── SquaredImageView.kt
│           └── res/
│               ├── drawable/
│               │   ├── button_selector.xml
│               │   ├── list_selector.xml
│               │   └── overlay_selector.xml
│               ├── layout/
│               │   ├── notification_view.xml
│               │   ├── picasso_sample_activity.xml
│               │   ├── picasso_sample_activity_item.xml
│               │   ├── sample_contacts_activity.xml
│               │   ├── sample_contacts_activity_item.xml
│               │   ├── sample_gallery_activity.xml
│               │   ├── sample_gridview_activity.xml
│               │   ├── sample_list_detail_detail.xml
│               │   ├── sample_list_detail_item.xml
│               │   ├── sample_list_detail_list.xml
│               │   └── sample_widget.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── integers.xml
│               │   ├── strings.xml
│               │   ├── styles.xml
│               │   └── themes.xml
│               ├── values-land/
│               │   └── dimens.xml
│               ├── values-w500dp/
│               │   └── integers.xml
│               ├── values-w600dp/
│               │   ├── dimens.xml
│               │   └── integers.xml
│               ├── values-w700dp/
│               │   └── integers.xml
│               └── xml/
│                   └── sample_widget_info.xml
├── picasso-stats/
│   ├── api/
│   │   └── picasso-stats.api
│   ├── build.gradle
│   ├── gradle.properties
│   └── src/
│       └── main/
│           └── java/
│               └── com/
│                   └── squareup/
│                       └── picasso3/
│                           └── stats/
│                               └── StatsEventListener.kt
├── renovate.json
├── settings.gradle
└── website/
    ├── index.html
    └── static/
        ├── app-theme.css
        ├── app.css
        └── prettify.js
Download .txt
SYMBOL INDEX (13 symbols across 2 files)

FILE: picasso/src/test/java/com/squareup/picasso3/_JavaConsumerIdeCheck.java
  class _JavaConsumerIdeCheck (line 12) | public class _JavaConsumerIdeCheck {
    method name (line 15) | @Test

FILE: website/static/prettify.js
  function S (line 2) | function S(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var...
  function T (line 6) | function T(a,d){function g(a){var c=a.nodeType;if(c==1){if(!b.test(a.cla...
  function H (line 7) | function H(a,d,g,b){d&&(a={a:d,e:a},g(a),b.push.apply(b,a.g))}
  function U (line 7) | function U(a){for(var d=void 0,g=a.firstChild;g;g=g.nextSibling)var b=g....
  function C (line 7) | function C(a,d){function g(a){for(var j=a.e,k=[j,"pln"],c=0,i=a.a.match(...
  function v (line 9) | function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''...
  function J (line 13) | function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.clas...
  function p (line 15) | function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(...
  function I (line 15) | function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-m...
  function K (line 15) | function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;
  function g (line 27) | function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity...
Condensed preview — 161 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (647K chars).
[
  {
    "path": ".editorconfig",
    "chars": 469,
    "preview": "root = true\n\n[*]\nindent_size = 2\nindent_style = space\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newli"
  },
  {
    "path": ".gitattributes",
    "chars": 58,
    "preview": "**/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text\n"
  },
  {
    "path": ".github/workflows/build.yaml",
    "chars": 2577,
    "preview": "name: build\n\non:\n  pull_request: {}\n\n  push:\n    branches:\n      - '**'\n    tags-ignore:\n      - '**'\n\nenv:\n  GRADLE_OPT"
  },
  {
    "path": ".github/workflows/release.yaml",
    "chars": 795,
    "preview": "name: release\n\non:\n  push:\n    tags:\n      - '**'\n\nenv:\n  GRADLE_OPTS: \"-Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon="
  },
  {
    "path": ".gitignore",
    "chars": 289,
    "preview": "# Eclipse\n.classpath\n.project\n.settings\neclipsebin\n\n# Ant\nbin\ngen\nbuild\nout\nlib\n\n# Maven\ntarget\npom.xml.*\nrelease.proper"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 10095,
    "preview": "Change Log\n==========\n\nVersion 2.71828 *(2018-03-07)*\n------------------------------\n\nThis version is not fully backward"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 542,
    "preview": "Contributing\n============\n\nIf you would like to contribute code to this project you can do so through GitHub by\nforking "
  },
  {
    "path": "LICENSE.txt",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 2087,
    "preview": "Picasso\n=======\n\n**Attention**: This library is deprecated.\nPlease use alternatives like [Coil](https://coil-kt.github.i"
  },
  {
    "path": "RELEASING.md",
    "chars": 630,
    "preview": "Releasing\n========\n\n 1. Update `VERSION_NAME` in `gradle.properties` to the release (non-SNAPSHOT) version.\n 2. Update `"
  },
  {
    "path": "build.gradle",
    "chars": 2113,
    "preview": "buildscript {\n  ext.isCi = \"true\" == System.getenv('CI')\n\n  repositories {\n    mavenCentral()\n    google()\n    gradlePlu"
  },
  {
    "path": "deploy_website.sh",
    "chars": 685,
    "preview": "#!/bin/bash\n\nset -ex\n\nREPO=\"git@github.com:square/picasso.git\"\nDIR=temp-clone\n\n# Delete any existing temporary website c"
  },
  {
    "path": "gradle/libs.versions.toml",
    "chars": 3276,
    "preview": "[versions]\nagp = '8.7.2'\ncoroutines = '1.8.1'\ncomposeUi = '1.6.8'\njavaTarget = '1.8'\nkotlin = '2.0.0'\nktlint = '1.2.1'\no"
  },
  {
    "path": "gradle/license-header.txt",
    "chars": 601,
    "preview": "/*\n * Copyright (C) $YEAR Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 253,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "gradle.properties",
    "chars": 852,
    "preview": "GROUP=com.squareup.picasso3\nVERSION_NAME=3.0.0-SNAPSHOT\n\nPOM_URL=https://github.com/square/picasso/\nPOM_SCM_URL=https://"
  },
  {
    "path": "gradlew",
    "chars": 8739,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "gradlew.bat",
    "chars": 2966,
    "preview": "@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 (th"
  },
  {
    "path": "lint.xml",
    "chars": 300,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lint>\n  <issue id=\"KotlinPropertyAccess\" severity=\"error\"/>\n  <issue id=\"LambdaL"
  },
  {
    "path": "picasso/api/picasso.api",
    "chars": 20328,
    "preview": "public abstract interface class com/squareup/picasso3/BitmapTarget {\n\tpublic abstract fun onBitmapFailed (Ljava/lang/Exc"
  },
  {
    "path": "picasso/build.gradle",
    "chars": 1562,
    "preview": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'com.vanniktech.maven.pub"
  },
  {
    "path": "picasso/consumer-proguard-rules.txt",
    "chars": 359,
    "preview": "### OKHTTP\n\n# Platform calls Class.forName on types which do not exist on Android to determine platform.\n-dontnote okhtt"
  },
  {
    "path": "picasso/gradle.properties",
    "chars": 136,
    "preview": "POM_ARTIFACT_ID=picasso\nPOM_NAME=Picasso\nPOM_DESCRIPTION=A powerful image downloading and caching library for Android\nPO"
  },
  {
    "path": "picasso/src/androidTest/AndroidManifest.xml",
    "chars": 162,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n  <uses-permission android:name=\"android.permissi"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/AssetRequestHandlerTest.kt",
    "chars": 1131,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/BitmapUtilsTest.kt",
    "chars": 4310,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/PicassoDrawableTest.kt",
    "chars": 2456,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/PlatformLruCacheTest.kt",
    "chars": 6514,
    "preview": "/*\n * Copyright (C) 2011 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/androidTest/java/com/squareup/picasso3/TestUtils.kt",
    "chars": 734,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Action.kt",
    "chars": 1024,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/AssetRequestHandler.kt",
    "chars": 2380,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BaseDispatcher.kt",
    "chars": 13277,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BitmapHunter.kt",
    "chars": 10277,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BitmapTarget.kt",
    "chars": 2016,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BitmapTargetAction.kt",
    "chars": 1810,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/BitmapUtils.kt",
    "chars": 8205,
    "preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Callback.kt",
    "chars": 827,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ContactsPhotoRequestHandler.kt",
    "chars": 3621,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ContentStreamRequestHandler.kt",
    "chars": 2391,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/DeferredRequestCreator.kt",
    "chars": 2423,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Dispatcher.kt",
    "chars": 1344,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/DrawableLoader.kt",
    "chars": 803,
    "preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/DrawableTarget.kt",
    "chars": 1889,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/DrawableTargetAction.kt",
    "chars": 1962,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/EventListener.kt",
    "chars": 965,
    "preview": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/FetchAction.kt",
    "chars": 1057,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/FileRequestHandler.kt",
    "chars": 1973,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/GetAction.kt",
    "chars": 917,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/HandlerDispatcher.kt",
    "chars": 6614,
    "preview": "/*\n * Copyright (C) 2023 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ImageViewAction.kt",
    "chars": 1936,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Initializer.kt",
    "chars": 844,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/InternalCoroutineDispatcher.kt",
    "chars": 4153,
    "preview": "/*\n * Copyright (C) 2023 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/MatrixTransformation.kt",
    "chars": 9773,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/MediaStoreRequestHandler.kt",
    "chars": 4395,
    "preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/MemoryPolicy.kt",
    "chars": 1243,
    "preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/NetworkPolicy.kt",
    "chars": 1376,
    "preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/NetworkRequestHandler.kt",
    "chars": 4668,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Picasso.kt",
    "chars": 25121,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/PicassoDrawable.kt",
    "chars": 5005,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/PicassoExecutorService.kt",
    "chars": 2442,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/PlatformLruCache.kt",
    "chars": 2531,
    "preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/RemoteViewsAction.kt",
    "chars": 3404,
    "preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Request.kt",
    "chars": 16944,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/RequestCreator.kt",
    "chars": 22548,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/RequestHandler.kt",
    "chars": 2789,
    "preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ResourceDrawableRequestHandler.kt",
    "chars": 1769,
    "preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/ResourceRequestHandler.kt",
    "chars": 1608,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Transformation.kt",
    "chars": 1252,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/main/java/com/squareup/picasso3/Utils.kt",
    "chars": 8468,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/BaseDispatcherTest.kt",
    "chars": 2991,
    "preview": "/*\n * Copyright (C) 2023 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/BitmapHunterTest.kt",
    "chars": 44704,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/BitmapTargetActionTest.kt",
    "chars": 4168,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/DeferredRequestCreatorTest.kt",
    "chars": 5389,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/DrawableTargetActionTest.kt",
    "chars": 4826,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/HandlerDispatcherTest.kt",
    "chars": 22279,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/ImageViewActionTest.kt",
    "chars": 5354,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/InternalCoroutineDispatcherTest.kt",
    "chars": 26483,
    "preview": "/*\n * Copyright (C) 2023 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/MediaStoreRequestHandlerTest.kt",
    "chars": 4812,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/MemoryPolicyTest.kt",
    "chars": 1614,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/NetworkRequestHandlerTest.kt",
    "chars": 9540,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/PicassoTest.kt",
    "chars": 21153,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/RemoteViewsActionTest.kt",
    "chars": 4259,
    "preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/RequestCreatorTest.kt",
    "chars": 27946,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/Shadows.kt",
    "chars": 1495,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/TestContentProvider.kt",
    "chars": 1701,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/TestTransformation.kt",
    "chars": 1145,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/TestUtils.kt",
    "chars": 15332,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/UtilsTest.kt",
    "chars": 3548,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso/src/test/java/com/squareup/picasso3/_JavaConsumerIdeCheck.java",
    "chars": 1640,
    "preview": "package com.squareup.picasso3;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport org.junit.Ignore;"
  },
  {
    "path": "picasso/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker",
    "chars": 17,
    "preview": "mock-maker-inline"
  },
  {
    "path": "picasso/src/test/resources/robolectric.properties",
    "chars": 73,
    "preview": "sdk: 21\nconstants: com.squareup.picasso3.BuildConfig\nmanifest: --default\n"
  },
  {
    "path": "picasso-compose/README.md",
    "chars": 375,
    "preview": "Picasso Compose Ui\n====================================\n\nA [Painter] which wraps a [RequestCreator]\n\nUsage\n-----\n\nCreate"
  },
  {
    "path": "picasso-compose/api/picasso-compose.api",
    "chars": 311,
    "preview": "public final class com/squareup/picasso3/compose/PicassoPainterKt {\n\tpublic static final fun rememberPainter (Lcom/squar"
  },
  {
    "path": "picasso-compose/build.gradle",
    "chars": 1167,
    "preview": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'org.jetbrains.kotlin.plu"
  },
  {
    "path": "picasso-compose/gradle.properties",
    "chars": 123,
    "preview": "POM_ARTIFACT_ID=picasso-compose\nPOM_NAME=Picasso Compose\nPOM_DESCRIPTION=Compose UI support for Picasso.\nPOM_PACKAGING=a"
  },
  {
    "path": "picasso-compose/src/androidTest/java/com/squareup/picasso3/compose/PicassoPainterTest.kt",
    "chars": 6843,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-compose/src/main/java/com/squareup/picasso3/compose/PicassoPainter.kt",
    "chars": 5094,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-paparazzi-sample/build.gradle",
    "chars": 952,
    "preview": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'app.cash.paparazzi'\n\nand"
  },
  {
    "path": "picasso-paparazzi-sample/src/test/java/com/example/picasso/paparazzi/PicassoPaparazziTest.kt",
    "chars": 2325,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-pollexor/README.md",
    "chars": 775,
    "preview": "Picasso Pollexor Request Transformer\n====================================\n\nA request transformer which uses a remote [Th"
  },
  {
    "path": "picasso-pollexor/api/picasso-pollexor.api",
    "chars": 1140,
    "preview": "public final class com/squareup/picasso3/pollexor/PollexorRequestTransformer : com/squareup/picasso3/Picasso$RequestTran"
  },
  {
    "path": "picasso-pollexor/build.gradle",
    "chars": 869,
    "preview": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'com.vanniktech.maven.pub"
  },
  {
    "path": "picasso-pollexor/gradle.properties",
    "chars": 210,
    "preview": "POM_ARTIFACT_ID=picasso-pollexor\nPOM_NAME=Picasso Pollexor Transformer\nPOM_DESCRIPTION=A request transformer which uses "
  },
  {
    "path": "picasso-pollexor/src/main/java/com/squareup/picasso3/pollexor/PollexorRequestTransformer.kt",
    "chars": 3036,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-pollexor/src/test/java/com/squareup/picasso3/pollexor/PollexorRequestTransformerTest.kt",
    "chars": 6031,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/build.gradle",
    "chars": 1346,
    "preview": "apply plugin: 'com.android.application'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'org.jetbrains.kotlin"
  },
  {
    "path": "picasso-sample/lint.xml",
    "chars": 281,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<lint>\n  <issue id=\"NewApi\">\n    <ignore path=\"src/main/res/values/styles.xml\" /"
  },
  {
    "path": "picasso-sample/src/main/AndroidManifest.xml",
    "chars": 2409,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:t"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/Data.kt",
    "chars": 1640,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/GrayscaleTransformation.kt",
    "chars": 2285,
    "preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/PicassoInitializer.kt",
    "chars": 1231,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/PicassoSampleActivity.kt",
    "chars": 2294,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/PicassoSampleAdapter.kt",
    "chars": 4571,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleComposeActivity.kt",
    "chars": 8401,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleContactsActivity.kt",
    "chars": 3874,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleContactsAdapter.kt",
    "chars": 2279,
    "preview": "/*\n * Copyright (C) 2013 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleGalleryActivity.kt",
    "chars": 2709,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleGridViewActivity.kt",
    "chars": 1100,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleGridViewAdapter.kt",
    "chars": 1903,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleListDetailActivity.kt",
    "chars": 3262,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleListDetailAdapter.kt",
    "chars": 2273,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleScrollListener.kt",
    "chars": 1359,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SampleWidgetProvider.kt",
    "chars": 1384,
    "preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/java/com/example/picasso/SquaredImageView.kt",
    "chars": 1140,
    "preview": "/*\n * Copyright (C) 2022 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "picasso-sample/src/main/res/drawable/button_selector.xml",
    "chars": 829,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item an"
  },
  {
    "path": "picasso-sample/src/main/res/drawable/list_selector.xml",
    "chars": 963,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item an"
  },
  {
    "path": "picasso-sample/src/main/res/drawable/overlay_selector.xml",
    "chars": 268,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item an"
  },
  {
    "path": "picasso-sample/src/main/res/layout/notification_view.xml",
    "chars": 919,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xml"
  },
  {
    "path": "picasso-sample/src/main/res/layout/picasso_sample_activity.xml",
    "chars": 1553,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<merge xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:la"
  },
  {
    "path": "picasso-sample/src/main/res/layout/picasso_sample_activity_item.xml",
    "chars": 241,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_contacts_activity.xml",
    "chars": 313,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_contacts_activity_item.xml",
    "chars": 1613,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright (C) 2013 The Android Open Source Project\n\n  Licensed under the A"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_gallery_activity.xml",
    "chars": 1164,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<merge xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:la"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_gridview_activity.xml",
    "chars": 382,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<GridView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_list_detail_detail.xml",
    "chars": 906,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andro"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_list_detail_item.xml",
    "chars": 882,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xml"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_list_detail_list.xml",
    "chars": 279,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android"
  },
  {
    "path": "picasso-sample/src/main/res/layout/sample_widget.xml",
    "chars": 281,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    androi"
  },
  {
    "path": "picasso-sample/src/main/res/values/colors.xml",
    "chars": 222,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"overlay_selector_pressed\">#40000000</color>\n  <color n"
  },
  {
    "path": "picasso-sample/src/main/res/values/dimens.xml",
    "chars": 321,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <dimen name=\"faux_action_bar_size\">48dp</dimen>\n  <dimen name=\"list"
  },
  {
    "path": "picasso-sample/src/main/res/values/integers.xml",
    "chars": 107,
    "preview": "<?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",
    "chars": 511,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <string name=\"app_name\">Picasso Samples</string>\n  <string name=\"hi"
  },
  {
    "path": "picasso-sample/src/main/res/values/styles.xml",
    "chars": 2449,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n  <style name=\"Widget."
  },
  {
    "path": "picasso-sample/src/main/res/values/themes.xml",
    "chars": 435,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<resources>\n  <style name=\"Theme.PicassoSample\" parent=\"android:Theme.NoTitleBar"
  },
  {
    "path": "picasso-sample/src/main/res/values-land/dimens.xml",
    "chars": 114,
    "preview": "<?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",
    "chars": 107,
    "preview": "<?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",
    "chars": 114,
    "preview": "<?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",
    "chars": 107,
    "preview": "<?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",
    "chars": 107,
    "preview": "<?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",
    "chars": 436,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
  },
  {
    "path": "picasso-stats/api/picasso-stats.api",
    "chars": 2150,
    "preview": "public final class com/squareup/picasso3/stats/StatsEventListener : com/squareup/picasso3/EventListener {\n\tpublic fun <i"
  },
  {
    "path": "picasso-stats/build.gradle",
    "chars": 722,
    "preview": "apply plugin: 'com.android.library'\napply plugin: 'org.jetbrains.kotlin.android'\napply plugin: 'com.vanniktech.maven.pub"
  },
  {
    "path": "picasso-stats/gradle.properties",
    "chars": 148,
    "preview": "POM_ARTIFACT_ID=picasso-stats\nPOM_NAME=Picasso Stats Event Listener\nPOM_DESCRIPTION=An event listener which records Pica"
  },
  {
    "path": "picasso-stats/src/main/java/com/squareup/picasso3/stats/StatsEventListener.kt",
    "chars": 5836,
    "preview": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "renovate.json",
    "chars": 107,
    "preview": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:base\"\n  ]\n}\n"
  },
  {
    "path": "settings.gradle",
    "chars": 242,
    "preview": "rootProject.name = 'picasso-root'\n\ninclude 'picasso'\ninclude 'picasso-compose'\ninclude 'picasso-paparazzi-sample'\ninclud"
  },
  {
    "path": "website/index.html",
    "chars": 9736,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Picasso</title>\n    <meta name=\"viewport"
  },
  {
    "path": "website/static/app-theme.css",
    "chars": 983,
    "preview": "/* http://www.colorhexa.com/b94948 */\n\n/*** Primary ***/\n\nheader,\n#subtitle,\na.dl {\n  background-color: #b94948;\n}\n\n.con"
  },
  {
    "path": "website/static/app.css",
    "chars": 2754,
    "preview": "html, body {\n  font-family: 'Roboto', sans-serif;\n  font-size: 15px;\n}\nbody {\n  background-color: #f6f6f6;\n  padding-bot"
  },
  {
    "path": "website/static/prettify.js",
    "chars": 14551,
    "preview": "!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;\n(function(){function S(a){function d(e){var b=e.charCodeAt("
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the square/picasso GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 161 files (598.4 KB), approximately 153.6k tokens, and a symbol index with 13 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!