PHPackages                             68publishers/image-storage - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Image &amp; Media](/categories/media)
4. /
5. 68publishers/image-storage

ActiveLibrary[Image &amp; Media](/categories/media)

68publishers/image-storage
==========================

Extension for 68publishers/file-storage that can generate images on-the-fly and more!

v1.8.1(2mo ago)16.8k↓45.2%[1 PRs](https://github.com/68publishers/image-storage/pulls)2MITPHPPHP ^8.1CI passing

Since Jun 10Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/68publishers/image-storage)[ Packagist](https://packagist.org/packages/68publishers/image-storage)[ Fund](https://www.buymeacoffee.com/68publishers)[ RSS](/packages/68publishers-image-storage/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (42)Versions (48)Used By (2)

Image Storage
=============

[](#image-storage)

🌆 Extension for [68publishers/file-storage](https://github.com/68publishers/file-storage) that can generate images on-the-fly and more!

Based on [thephpleague/flysystem](https://github.com/thephpleague/flysystem) and [intervention/image](https://github.com/Intervention/image)

[![Checks](https://camo.githubusercontent.com/3c7289eafa994c26ca58969487c730e95354fd9382def91a5e6e31d05b30cff7/68747470733a2f2f62616467656e2e6e65742f6769746875622f636865636b732f36387075626c6973686572732f696d6167652d73746f726167652f6d6173746572)](https://github.com/68publishers/image-storage/actions)[![Coverage Status](https://camo.githubusercontent.com/5096a24366e5d63673e03042f70a2f8e80f790576d61395bb3f39f3e825e0866/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f36387075626c6973686572732f696d6167652d73746f726167652f62616467652e7376673f6272616e63683d6d6173746572)](https://coveralls.io/github/68publishers/image-storage?branch=master)[![Total Downloads](https://camo.githubusercontent.com/3417bf9aa44b6d6e7f6aa6cb90fd9773cd383357010afb21c69b3ef6c7d7aa55/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f64742f36387075626c6973686572732f696d6167652d73746f72616765)](https://packagist.org/packages/68publishers/image-storage)[![Latest Version](https://camo.githubusercontent.com/08275eaedd415e9111a15eb698c8edc32eca12f569a25f26190deeb14bef573b/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f762f36387075626c6973686572732f696d6167652d73746f72616765)](https://packagist.org/packages/68publishers/image-storage)[![PHP Version](https://camo.githubusercontent.com/33b095ce74c2e311f46962475032a8e173d0cc5119a5087123e88de860d2b35e/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f7068702f36387075626c6973686572732f696d6167652d73746f72616765)](https://packagist.org/packages/68publishers/image-storage)

Installation
------------

[](#installation)

The best way to install 68publishers/image-storage is using Composer:

```
$ composer require 68publishers/image-storage
```

Integration into Nette Framework
--------------------------------

[](#integration-into-nette-framework)

Firstly, please read a documentation of [68publishers/file-storage](https://github.com/68publishers/file-storage/blob/master/README.md).

### File storage configuration example

[](#file-storage-configuration-example)

Each image-storage is based on file-storage. so firstly we need to register our storage under the file-storage extension. Here is an example configuration:

```
68publishers.file_storage:
    storages:
        local:
            config:
                base_path: /images
                signature_key: my-arbitrary-private-key
                allowed_pixel_density: [ 1, 2, 3 ]
                allowed_resolutions: [ 50x50, 200x200, 300x300, 200x, x200 ]
                allowed_qualities: [ 50, 80, 100 ]
                encode_quality: 90
                cache_max_age: 31536000
            filesystem:
                adapter: League\Flysystem\Local\LocalFilesystemAdapter(%wwwDir%/images)
            assets:
                assets/image/noimage.png: noimage/default.png # copy the default no-image
                assets/image/noimage_user.png: noimage/user.png # copy the default no-image for users
```

#### Storage config options

[](#storage-config-options)

NameTypeDefaultDescriptionbase\_pathstring`''`Base path to a directory where the files are accessible.hostnull or string`null`Hostname, use if the files are not stored locally or if you want to generate an absolute linksversion\_parameter\_namestring`_v`A query parameter's name used for a file's version (just for a cache).signature\_parameter\_namestring`_s`A query parameter's name used for a signature token.signature\_keynull or string`null`Your private signature key used for a token encryption. Signatures in requests are checked and validated only if this parameter is set.signature\_algorithmstring`sha256`An algorithm used for encryption of signatures (HMAC).modifier\_separatorstring`,`A separator for modifier definitions in a path. For example if you set this parameter as `;` then a modifier string in a path will look like this: `w:100;o:auto`.modifier\_assignerstring`:`An assigner for modifier definitions in a path. For example if you set this parameter as `=` then a modifier string in a path will look like this: `w=100,o=auto`.allowed\_pixel\_densityarray or array`[]`An array of allowed pixed densities. The validation is enabled when the array is not empty.allowed\_resolutionsarray`[]`An array of allowed resolutions like `100x`, `x200` or `100x200`. The validation is enabled when the array is not empty.allowed\_qualitiesarray`[]`An array of allowed qualities. The validation is enabled when the array is not empty.encode\_qualityint`90`An encode quality for cached images.cache\_max\_ageint`31536000`The maximum cache age in seconds. The value is used for HTTP headers Cache-Control and Expires.### Image storage configuration example

[](#image-storage-configuration-example)

Now we can register the `ImageStorageExtension` and define the `local` image-storage:

```
extensions:
    68publishers.image_storage: SixtyEightPublishers\ImageStorage\Bridge\Nette\DI\ImageStorageExtension

68publishers.image_storage:
    driver: gd # "gd" or "imagick" or "68publishers.imagick", the default is "gd"
    storages:
        local:
            source_filesystem:
                adapter: League\Flysystem\Local\LocalFilesystemAdapter(%appDir%/../private-data/images)
                config: [] # an optional config for source filesystem adapter
            server: local # "local" or "external", the default is "local"
            route: yes # registers automatically ImageServer presenter into your Router. The option can be applied only if the "server" option is set to "local" and the option "base_path" is set in the FileStorage config
            no_image:
                default: noimage/default.png
                user: noimage/user.png
            no_image_patterns:
                user: '^user_avatar\/' # the noimage "user" will be used for missing files with paths that matches this regex
            presets:
                my_preset:
                    modifiers:
                      w: 150
                      ar: '2x1.5'
                my_preset_2:
                    modifiers:
                        ar: 1x2
                    w: [300, 600, 900]
                    defaultW: 600
```

### Animated GIFs

[](#animated-gifs)

Animated GIFs are not supported by [intervention/image](https://github.com/Intervention/image) but this package comes with a custom `imagick` driver that supports it. The driver is used when you pass a value `68publishers.imagick` into a `driver` option.

### Basic usage

[](#basic-usage)

Basic usage is similar to usage of the `file-storage`.

#### Persisting files

[](#persisting-files)

Files persisting is almost the same as persisting in the `file-storage` but source images are stored without a file extension.

```
use SixtyEightPublishers\ImageStorage\ImageStorageInterface;

/** @var ImageStorageInterface $storage */

# Create resource from local file or url:
$resource = $storage->createResourceFromFile(
    $storage->createPathInfo('test/my-image.jpeg'),
    __DIR__ . '/path/to/my-image.jpeg'
);

$storage->save($resource);

# Create resource from a file that is stored in storage:
$resource = $storage->createResource(
    $storage->createPathInfo('test/my-image')
);

# Copy to the new location
$storage->save($resource->withPathInfo(
    $storage->createPathInfo('test/my-image-2')
));
```

#### Check a file existence

[](#check-a-file-existence)

```
use SixtyEightPublishers\ImageStorage\ImageStorageInterface;

/** @var ImageStorageInterface $storage */

$pathInfo = $storage->createPathInfo('test/my-image');

if ($storage->exists($pathInfo)) {
    echo 'source image exists!';
}

if ($storage->exists($pathInfo->withModifiers(['w' => 150]))) {
    echo 'cached image with width 150 in JPEG (default) format exists!';
}

if ($storage->exists($pathInfo->withModifiers(['w' => 150])->withExtension('webp'))) {
    echo 'cached image with width 150 in WEBP format exists!';
}
```

#### Deleting files

[](#deleting-files)

```
use SixtyEightPublishers\ImageStorage\ImageStorageInterface;
use SixtyEightPublishers\ImageStorage\Persistence\ImagePersisterInterface;

/** @var ImageStorageInterface $storage */

# delete all cached images only:
$storage->delete($storage->createPathInfo('test/my-image'), [
    ImagePersisterInterface::OPTION_DELETE_CACHE_ONLY => TRUE,
]);

# delete cached images and source image:
$storage->delete($storage->createPathInfo('test/my-image'));

# delete only cached image with 200px width in PNG format
$storage->delete($storage->createPathInfo('test/my-image.png')->withModifiers(['w' => 200]));
```

#### Create links to images

[](#create-links-to-images)

An original images are not accessible. If you want to access an original image you must request it with a modifier `['original' => TRUE]`.

```
use SixtyEightPublishers\ImageStorage\ImageStorageInterface;

/** @var ImageStorageInterface $storage */

$pathInfo = $storage->createPathInfo('test/my-image.png')
    ->withModifiers(['original' => TRUE])
    ->withVersion(time());

# /images/test/original/my-image.png?_v=1611837352
echo $storage->link($pathInfo);

# /images/test/original/my-image.webp?_v=1611837352
echo $storage->link($pathInfo->withExtension('webp'));

# /images/test/ar:2x1,w:200/my-image.webp?_v=1611837352&_s={GENERATED_SIGNATURE_TOKEN}
echo $storage->link($pathInfo->withExtension('webp')->withModifiers(['w' => 200, 'ar' => '2x1']));

# you can also wrap PathInfo to FileInfo object:
$fileInfo = $storage->createFileInfo($pathInfo);

# /images/test/original/my-image.png?_v=1611837352
echo $fileInfo->link();

# /images/test/original/my-image.webp?_v=1611837352
echo $fileInfo->withExtension('webp')->link();

# /images/test/ar:2x1,w:200/my-image.webp?_v=1611837352&_s={GENERATED_SIGNATURE_TOKEN}
echo $fileInfo->withExtension('webp')->withModifiers(['w' => 200, 'ar' => '2x1'])->link();
```

The HTML attribute `srcset` can be also generated:

```
use SixtyEightPublishers\ImageStorage\ImageStorageInterface;
use SixtyEightPublishers\ImageStorage\Responsive\Descriptor\XDescriptor;
use SixtyEightPublishers\ImageStorage\Responsive\Descriptor\WDescriptor;

/** @var ImageStorageInterface $storage */

$pathInfo = $storage->createPathInfo('test/my-image.png')
    ->withModifiers(['w' => 200, 'ar' => '2x1'])
    ->withVersion(time());

/*
/images/test/ar:2x1,pd:1,w:200/my-image.png?_v=1611837352&_s={TOKEN} ,
/images/test/ar:2x1,pd:2,w:200/my-image.png?_v=1611837352&_s={TOKEN} 2.0x,
/images/test/ar:2x1,pd:3,w:200/my-image.png?_v=1611837352&_s={TOKEN} 3.0x
*/
echo $storage->srcSet($pathInfo, new XDescriptor(1, 2, 3));

/*
/images/test/ar:2x1,w:200/my-image.png?_v=1611837352&_s={TOKEN} 200w,
/images/test/ar:2x1,w:400/my-image.png?_v=1611837352&_s={TOKEN} 400w,
/images/test/ar:2x1,w:600/my-image.png?_v=1611837352&_s={TOKEN} 600w,
/images/test/ar:2x1,w:800/my-image.png?_v=1611837352&_s={TOKEN} 800w
*/
echo $storage->srcSet($pathInfo, new WDescriptor(200, 400, 600, 800));

# you can also wrap PathInfo to FileInfo object:
$fileInfo = $storage->createFileInfo($pathInfo);

echo $fileInfo->srcSet(new XDescriptor(1, 2, 3));
echo $fileInfo->srcSet(new WDescriptor(200, 400, 600, 800));
```

### Usage with Latte

[](#usage-with-latte)

```
extensions:
    68publishers.image_storage.latte: SixtyEightPublishers\ImageStorage\Bridge\Nette\DI\ImageStorageLatteExtension
```

The extension adds these functions into the Latte:

- `w_descriptor(...)` - a shortcut for `new SixtyEightPublishers\ImageStorage\Responsive\Descriptor\XDescriptor(...)`
- `x_descriptor(...)` - a shortcut for `new SixtyEightPublishers\ImageStorage\Responsive\Descriptor\WDescriptor(...)`
- `w_descriptor_range(int $min, int $max, int $step)` - a shortcut for `SixtyEightPublishers\ImageStorage\Responsive\Descriptor\WDescriptor::fromRange($min, $max, $step)`
- `no_image(?string $noImageName = NULL, ?string $storageName = NULL)` - creates a FilInfo object that contains path to no-image file

Basic usage:

```
{varType SixtyEightPublishers\ImageStorage\FileInfoInterface $fileInfo}

{* Note: method FileInfo::__toString() calls ::link() internally *}

{* Create FileInfo from string *}
{var $fileInfo = file_info('test/my-image.png')->withModifiers(['o' => 90, 'ar' => '2x1'])}

{* Create default NoImage if the variable doesn't exists *}
{var $fileInfo = ($fileInfo ?? no_image())->withModifiers(['o' => 90, 'ar' => '2x1'])}

```

An advanced example with a tag ``:

```
{var $large = file_info('test/my-image.jpeg')->withModifiers([w => 1172, ar => '1x0.29'])}
{var $medium = $large->withModifiers([w => 768, ar => '1x0.59'])}

```

### Symfony Console commands

[](#symfony-console-commands)

The image-storage extends a command `file-storage:clean` with an option `cache-only` so the command now looks like this:

```
$ bin/console file-storage:clean [] [--namespace ] [--cache-only]
```

Supported image formats and modifiers
-------------------------------------

[](#supported-image-formats-and-modifiers)

### Image formats

[](#image-formats)

- JPEG - `.jpeg` or `.jpg`
- Progressive JPEG - `.pjpg`
- PNG - `.png`
- GIF - `.gif`
- WEBP - `.webp`
- AVIF - `.avif`

### Modifiers

[](#modifiers)

NameShortcutTypeNoteOriginaloriginal-A modifier without a value, use it if you want to return the original imageHeighthIntegerCan be restricted by parameter `AllowedResolutions`WidthwIntegerCan be restricted by parameter `AllowedResolutions`Pixel densitypdInteger or FloatCan be restricted by parameter `AllowedPixelDensity`Aspect ratioarStringRequired format is `{Int or Float}x{Int or Float}` and a height or a width (not both) must be also defined. For example `w:200,ar:1x2` is an equivalent of `w:200,h:400`FitfStringSee [supported fits](#supported-fits) for the list of supported valuesOrientationoInteger or StringAllowed values are `auto, 0, 90, -90, 180, -180, 270, -270`QualityqIntegerCan be restricted by parameter `AllowedQualities`### Supported fits

[](#supported-fits)

- `contain` - Preserving aspect ratio, resize the image to be as large as possible while ensuring its dimensions are less than or equal to both those specified.
- `stretch` - Ignore the aspect ratio of the input and stretch to both provided dimensions.
- `fill` - Preserving aspect ratio, contain within both provided dimensions using "letterboxing" where necessary.
- `crop-*` - Preserving aspect ratio, ensure the image covers both provided dimensions by cropping to fit.
    - `crop-center`
    - `crop-left`
    - `crop-right`
    - `crop-top`
    - `crop-top-left`
    - `crop-top-right`
    - `crop-bottom`
    - `crop-bottom-left`
    - `crop-bottom-right`

Image server
------------

[](#image-server)

### Local image server

[](#local-image-server)

The default image server for each storage is `local`. That means your application will handle requests and generate, store and serve modified images. The extension automatically registers [ImageStoragePresenter](src/Bridge/Nette/Application/ImageServerPresenter.php) and Routes for local storages if the `route: true` option is set for the storage. If you have this setting disabled, you must register the Presenter yourself.

Now you must modify the configuration of a web server. For example, if the webserver is Apache then modify a file `.htaccess` that is located in your www directory.

```
# locale images
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(images\/)(.+) index.php [L]
```

The Application will be called only if a static file has not yet been generated. Otherwise, the server will serve the static file.

### External image server: an integration with AWS S3 and image-storage-lambda

[](#external-image-server-an-integration-with-aws-s3-and-image-storage-lambda)

The image storage can be integrated with the Amazon S3 object storage and the package [68publishers/image-storage-lambda](https://github.com/68publishers/image-storage-lambda). So your image storage can be completely serverless! Of course, you can deploy the `image-storage-lambda` application manually and also synchronize options from the `image-storage` with the `image-storage-lambda` manually.

At least you can follow these simple steps for a partial integration:

1. Create a deployment bucket on the S3

When you deploy the AWS SAM application in guide mode (`sam deploy --guided`) the deployment bucket will be created automatically. But the application will be built in a non-guided mode so we must create the bucket manually. If you don't know how to create an S3 bucket please follow the [Amazon documentation](https://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html). We recommend to enable versioning on this bucket.

2. Required packages `league/flysystem-aws-s3-v3` (the S3 adapter for Flysystem) and `yosymfony/toml` (suggested by this package) in your application

```
$ composer require league/flysystem-aws-s3-v3 yosymfony/toml
```

3. Configure the image storage with the S3 filesystem (an example with a minimal configuration):

```
services:
    s3_client:
        class: Aws\S3\S3Client([... your S3 config ...])
        autowired: no

68publishers.file_storage:
    storages:
        s3_images:
            config:
                # configure what you want but omit the `host` option for now
            filesystem:
                adapter: League\Flysystem\AwsS3V3\AwsS3V3Adapter(@s3_client, my-awesome-cache-bucket) # the bucket doesn't exists at this point
            # if you have your own no-images:
            assets:
                %assetsDir%/noimage: noimage

68publishers.image_storage:
    storages:
        s3_images:
            source_filesystem:
                adapter: League\Flysystem\AwsS3V3\AwsS3V3Adapter(@s3_client, my-awesome-source-bucket) # the bucket doesn't exists at this point
            server: external
            # if you have your own no-images:
            no_image:
                default: noimage/default.png
                user: noimage/user.png
            no_image_patterns:
                user: '^user_avatar\/'
```

4. Register and configure the compiler extension `ImageStorageLambdaExtension`

```
extensions:
    68publishers.image_storage.lambda: SixtyEightPublishers\ImageStorage\Bridge\Nette\DI\ImageStorageLambdaExtension

68publishers.image_storage.lambda:
    output_dir: %appDir%/config/image-storage-lambda # the default path
    stacks:
        s3_images:
            s3_bucket: {NAME OF YOUR DEPLOYMENT BUCKET FROM THE STEP 1}
            region: eu-central-1

            # optional settings:
            stack_name: my-awesome-image-storage # the storage name is used by default
            version: 2.0 # default is 1.0
            s3_prefix: custom-prefix # the stack_name is used by default
            confirm_changeset: yes # must be changeset manually confirmed during deploy? the default value is false
            capabilities: CAPABILITY_IAM # default, CAPABILITY_IAM or CAPABILITY_NAMED_IAM

            # optional, automatically detected from AwsS3V3Adapter by default
            source_bucket_name: source-bucket-name
            cache_bucket_name: cache-bucket-name
```

5. Generate configuration for the `image-storage-lambda`

```
$ php bin/console image-storage:lambda:dump-config
```

The configuration file will be placed by default in a directory `app/config/image-storage-lambda/my-awesome-image-storage/samconfig.toml`. Keep this file versioned in the Git.

6. Download `image-storage-lambda`, build and deploy!

Firstly setup your local environment by requirements defined [here](https://github.com/68publishers/image-storage-lambda#requirements). Then download the package outside your project.

```
$ git clone https://github.com/68publishers/image-storage-lambda.git image-storage-lambda
$ cd ./image-storage-lambda
```

Unfortunately SAM CLI doesn't allow you to define a path to your `samconfig.toml` file (related issue [aws/aws-sam-cli#1615](https://github.com/aws/aws-sam-cli/issues/1615)) at this moment. So you must copy the config to the root of the `image-storage-lambda` application. And then you can build and deploy the application!

```
$ cp ../my-project/app/config/image-storage-lambda/my-awesome-image-storage/samconfig.toml samconfig.toml
$ sam build
$ sam deploy
```

7. Set the CloudFront URL as a host in the image storage config

The URL of your CloudFront distribution is listed in Outputs after a successful deployment. More information are [here](https://github.com/68publishers/image-storage-lambda#what-is-the-url-of-my-api).

```
# ...
68publishers.image_storage:
    storages:
        s3_images:
            config:
                host: {CLOUDFRONT URL}
# ...
```

Contributing
------------

[](#contributing)

Before opening a pull request, please check your changes using the following commands

```
$ make init # to pull and start all docker images

$ make cs.check
$ make stan
$ make tests.all
```

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance85

Actively maintained with recent releases

Popularity25

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity81

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 97.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~58 days

Recently: every ~69 days

Total

43

Last Release

75d ago

Major Versions

v0.5.8 → v1.0.02023-01-03

PHP version history (3 changes)v0.1PHP ~7.1

v0.5PHP ^7.3

v1.0.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/609005caba54757716c3c037c381376ab298714003da87c9e20aa8c501c97df8?d=identicon)[Jelen](/maintainers/Jelen)

---

Top Contributors

[![tg666](https://avatars.githubusercontent.com/u/24430186?v=4)](https://github.com/tg666 "tg666 (91 commits)")[![jelen07](https://avatars.githubusercontent.com/u/2346295?v=4)](https://github.com/jelen07 "jelen07 (2 commits)")

---

Tags

bundleextensionimageimage-storagenettenette-extensionphpnetteimageimagesimage storage68publishers

###  Code Quality

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/68publishers-image-storage/health.svg)

```
[![Health](https://phpackages.com/badges/68publishers-image-storage/health.svg)](https://phpackages.com/packages/68publishers-image-storage)
```

###  Alternatives

[jbzoo/image

A PHP class that simplifies working with images

171126.9k3](/packages/jbzoo-image)[andrewgjohnson/imagettftextblur

imagettftextblur is a drop in replacement for imagettftext with added parameters to add blur, glow and shadow effects to your PHP GD images

27198.4k1](/packages/andrewgjohnson-imagettftextblur)[brabijan/images

Image storage for Nette Framework

5617.7k](/packages/brabijan-images)[pavlista/nette-palette

Palette support for Nette Framework and Latte template engine

1657.4k](/packages/pavlista-nette-palette)[kollarovic/thumbnail

Generating image thumbnails

1035.5k2](/packages/kollarovic-thumbnail)[ayvazyan10/nova-imagic

Imagic is a Laravel Nova field package that allows for image manipulation capabilities, such as cropping, resizing, quality adjustment, and WebP conversion. It utilizes the powerful Intervention Image class for image manipulation.

144.3k1](/packages/ayvazyan10-nova-imagic)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
