Commit 89229d97 by lmf

增加图片插件webp

优化产品主图显示
评论默认隐藏
parent 932207d2
...@@ -189,3 +189,13 @@ $isFilterApplied = $displayedCollection->getFlag(\Amasty\AdvancedReview\Model\To ...@@ -189,3 +189,13 @@ $isFilterApplied = $displayedCollection->getFlag(\Amasty\AdvancedReview\Model\To
} }
} }
</script> </script>
<script>
require([
'jquery'
], function ($) {
console.log("helo!");
$(".amreview-add-new").on(click,function () {
$(".block.review-add.amreview-submit-form").show();
});
});
</script>
...@@ -203,6 +203,8 @@ $thumbSizes = $responsiveImageHelper->getSizes('product_page_image_small'); ...@@ -203,6 +203,8 @@ $thumbSizes = $responsiveImageHelper->getSizes('product_page_image_small');
$(".thumbnails > a").mouseover(function (s) { $(".thumbnails > a").mouseover(function (s) {
var main_img = $(this).attr("name"); var main_img = $(this).attr("name");
$(".main-image").attr("src",main_img); $(".main-image").attr("src",main_img);
$(".main-image-wrapper > picture > source:first ").attr("srcset",main_img);
$(".main-image-wrapper > picture > source:last ").attr("srcset",main_img);
$(".thumbnails > a").removeClass("active"); $(".thumbnails > a").removeClass("active");
$(this).addClass("active"); $(this).addClass("active");
}); });
...@@ -219,6 +221,8 @@ $thumbSizes = $responsiveImageHelper->getSizes('product_page_image_small'); ...@@ -219,6 +221,8 @@ $thumbSizes = $responsiveImageHelper->getSizes('product_page_image_small');
sd = $(".thumbnails > a:first").attr('name'); sd = $(".thumbnails > a:first").attr('name');
} }
$(".main-image").attr("src",sd); $(".main-image").attr("src",sd);
$(".main-image-wrapper > picture > source:first ").attr("srcset",sd);
$(".main-image-wrapper > picture > source:last ").attr("srcset",sd);
}); });
$("a.prev ").on('click',function () { $("a.prev ").on('click',function () {
...@@ -233,6 +237,8 @@ $thumbSizes = $responsiveImageHelper->getSizes('product_page_image_small'); ...@@ -233,6 +237,8 @@ $thumbSizes = $responsiveImageHelper->getSizes('product_page_image_small');
sd = $(".thumbnails > a:last").attr('name'); sd = $(".thumbnails > a:last").attr('name');
} }
$(".main-image").attr("src",sd); $(".main-image").attr("src",sd);
$(".main-image-wrapper > picture > source:first ").attr("srcset",sd);
$(".main-image-wrapper > picture > source:last ").attr("srcset",sd);
}); });
}); });
</script> </script>
......
...@@ -1688,6 +1688,9 @@ button.action.submit.primary { ...@@ -1688,6 +1688,9 @@ button.action.submit.primary {
bottom: 0; bottom: 0;
z-index: 11; z-index: 11;
} }
.breeze-gallery .stage .main-image-wrapper > picture{
display: none;
}
} }
//详情页修改 //详情页修改
@media (min-width: 768px){ @media (min-width: 768px){
...@@ -1824,5 +1827,8 @@ background-color: #000; ...@@ -1824,5 +1827,8 @@ background-color: #000;
flex-direction: inherit !important; flex-direction: inherit !important;
} }
} }
.block.review-add.amreview-submit-form{
display: none;
}
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
"composer/composer": "^1.9 || ^2.0", "composer/composer": "^1.9 || ^2.0",
"elasticsearch/elasticsearch": "~7.11.0", "elasticsearch/elasticsearch": "~7.11.0",
"guzzlehttp/guzzle": "^6.3.3", "guzzlehttp/guzzle": "^6.3.3",
"jajuma/module-webpimages": "^2.1",
"laminas/laminas-captcha": "^2.10", "laminas/laminas-captcha": "^2.10",
"laminas/laminas-code": "^3.5.1", "laminas/laminas-code": "^3.5.1",
"laminas/laminas-crypt": "^3.4.0", "laminas/laminas-crypt": "^3.4.0",
...@@ -73,6 +74,7 @@ ...@@ -73,6 +74,7 @@
"magento/magento-composer-installer": ">=0.1.11", "magento/magento-composer-installer": ">=0.1.11",
"magento/zendframework1": "~1.14.2", "magento/zendframework1": "~1.14.2",
"mageside/module-subscribe-at-checkout": "1.1.7", "mageside/module-subscribe-at-checkout": "1.1.7",
"mobiledetect/mobiledetectlib": "^2.8",
"monolog/monolog": "^1.17", "monolog/monolog": "^1.17",
"paragonie/sodium_compat": "^1.6", "paragonie/sodium_compat": "^1.6",
"pelago/emogrifier": "^5.0.0", "pelago/emogrifier": "^5.0.0",
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "96d54abdc29e1aeacfdc595d5d248fb3", "content-hash": "3e6bf64bfbd2224fc8f617fcd165743f",
"packages": [ "packages": [
{ {
"name": "airwallex/payments-plugin-magento", "name": "airwallex/payments-plugin-magento",
...@@ -1545,6 +1545,34 @@ ...@@ -1545,6 +1545,34 @@
"time": "2022-06-20T21:43:03+00:00" "time": "2022-06-20T21:43:03+00:00"
}, },
{ {
"name": "jajuma/module-webpimages",
"version": "2.1.11",
"dist": {
"type": "zip",
"url": "https://repo.magento.com/archives/jajuma/module-webpimages/jajuma-module-webpimages-2.1.11.0.zip",
"shasum": "acc0eddedb94f5b235bcaeceddb215e3ed339cfb"
},
"type": "magento2-module",
"autoload": {
"psr-4": {
"Jajuma\\WebpImages\\": ""
},
"files": [
"registration.php"
]
},
"license": [
"MIT"
],
"authors": [
{
"name": "JaJuMa",
"email": "info@jajuma.de"
}
],
"description": "WebP Optimized Images"
},
{
"name": "justinrainbow/json-schema", "name": "justinrainbow/json-schema",
"version": "5.2.12", "version": "5.2.12",
"source": { "source": {
......
...@@ -130,6 +130,7 @@ return array( ...@@ -130,6 +130,7 @@ return array(
'940abd8fb01ee76a36b44f35dcf9783b' => $vendorDir . '/weew/helpers-array/src/array.php', '940abd8fb01ee76a36b44f35dcf9783b' => $vendorDir . '/weew/helpers-array/src/array.php',
'b598380463d27491e4810196bf363d15' => $vendorDir . '/airwallex/payments-plugin-magento/registration.php', 'b598380463d27491e4810196bf363d15' => $vendorDir . '/airwallex/payments-plugin-magento/registration.php',
'8592c7b0947d8a0965a9e8c3d16f9c24' => $vendorDir . '/elasticsearch/elasticsearch/src/autoload.php', '8592c7b0947d8a0965a9e8c3d16f9c24' => $vendorDir . '/elasticsearch/elasticsearch/src/autoload.php',
'0b2ea8cc52669e97f3bdd7d78dcd8eb5' => $vendorDir . '/jajuma/module-webpimages/registration.php',
'eda65932675b68b5aee4503e0762d64d' => $vendorDir . '/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/_bootstrap.php', 'eda65932675b68b5aee4503e0762d64d' => $vendorDir . '/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/_bootstrap.php',
'88ede69c0babb90b8d3e9e7a95ad0eb5' => $vendorDir . '/mageside/module-subscribe-at-checkout/registration.php', '88ede69c0babb90b8d3e9e7a95ad0eb5' => $vendorDir . '/mageside/module-subscribe-at-checkout/registration.php',
'3109cb1a231dcd04bee1f9f620d46975' => $vendorDir . '/paragonie/sodium_compat/autoload.php', '3109cb1a231dcd04bee1f9f620d46975' => $vendorDir . '/paragonie/sodium_compat/autoload.php',
......
...@@ -124,6 +124,7 @@ return array( ...@@ -124,6 +124,7 @@ return array(
'Jose\\Component\\Core\\Util\\Ecc\\' => array($vendorDir . '/web-token/jwt-framework/src/Ecc'), 'Jose\\Component\\Core\\Util\\Ecc\\' => array($vendorDir . '/web-token/jwt-framework/src/Ecc'),
'Jose\\' => array($vendorDir . '/web-token/jwt-framework/src'), 'Jose\\' => array($vendorDir . '/web-token/jwt-framework/src'),
'JmesPath\\' => array($vendorDir . '/mtdowling/jmespath.php/src'), 'JmesPath\\' => array($vendorDir . '/mtdowling/jmespath.php/src'),
'Jajuma\\WebpImages\\' => array($vendorDir . '/jajuma/module-webpimages'),
'JMS\\Serializer\\' => array($vendorDir . '/jms/serializer/src'), 'JMS\\Serializer\\' => array($vendorDir . '/jms/serializer/src'),
'Hoa\\Ustring\\' => array($vendorDir . '/hoa/ustring'), 'Hoa\\Ustring\\' => array($vendorDir . '/hoa/ustring'),
'Hoa\\Stream\\' => array($vendorDir . '/hoa/stream'), 'Hoa\\Stream\\' => array($vendorDir . '/hoa/stream'),
......
...@@ -131,6 +131,7 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf ...@@ -131,6 +131,7 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf
'940abd8fb01ee76a36b44f35dcf9783b' => __DIR__ . '/..' . '/weew/helpers-array/src/array.php', '940abd8fb01ee76a36b44f35dcf9783b' => __DIR__ . '/..' . '/weew/helpers-array/src/array.php',
'b598380463d27491e4810196bf363d15' => __DIR__ . '/..' . '/airwallex/payments-plugin-magento/registration.php', 'b598380463d27491e4810196bf363d15' => __DIR__ . '/..' . '/airwallex/payments-plugin-magento/registration.php',
'8592c7b0947d8a0965a9e8c3d16f9c24' => __DIR__ . '/..' . '/elasticsearch/elasticsearch/src/autoload.php', '8592c7b0947d8a0965a9e8c3d16f9c24' => __DIR__ . '/..' . '/elasticsearch/elasticsearch/src/autoload.php',
'0b2ea8cc52669e97f3bdd7d78dcd8eb5' => __DIR__ . '/..' . '/jajuma/module-webpimages/registration.php',
'eda65932675b68b5aee4503e0762d64d' => __DIR__ . '/..' . '/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/_bootstrap.php', 'eda65932675b68b5aee4503e0762d64d' => __DIR__ . '/..' . '/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/_bootstrap.php',
'88ede69c0babb90b8d3e9e7a95ad0eb5' => __DIR__ . '/..' . '/mageside/module-subscribe-at-checkout/registration.php', '88ede69c0babb90b8d3e9e7a95ad0eb5' => __DIR__ . '/..' . '/mageside/module-subscribe-at-checkout/registration.php',
'3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php', '3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php',
...@@ -290,6 +291,7 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf ...@@ -290,6 +291,7 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf
'Jose\\Component\\Core\\Util\\Ecc\\' => 29, 'Jose\\Component\\Core\\Util\\Ecc\\' => 29,
'Jose\\' => 5, 'Jose\\' => 5,
'JmesPath\\' => 9, 'JmesPath\\' => 9,
'Jajuma\\WebpImages\\' => 18,
'JMS\\Serializer\\' => 15, 'JMS\\Serializer\\' => 15,
), ),
'H' => 'H' =>
...@@ -846,6 +848,10 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf ...@@ -846,6 +848,10 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf
array ( array (
0 => __DIR__ . '/..' . '/mtdowling/jmespath.php/src', 0 => __DIR__ . '/..' . '/mtdowling/jmespath.php/src',
), ),
'Jajuma\\WebpImages\\' =>
array (
0 => __DIR__ . '/..' . '/jajuma/module-webpimages',
),
'JMS\\Serializer\\' => 'JMS\\Serializer\\' =>
array ( array (
0 => __DIR__ . '/..' . '/jms/serializer/src', 0 => __DIR__ . '/..' . '/jms/serializer/src',
......
...@@ -3426,6 +3426,37 @@ ...@@ -3426,6 +3426,37 @@
"install-path": "../hoa/ustring" "install-path": "../hoa/ustring"
}, },
{ {
"name": "jajuma/module-webpimages",
"version": "2.1.11",
"version_normalized": "2.1.11.0",
"dist": {
"type": "zip",
"url": "https://repo.magento.com/archives/jajuma/module-webpimages/jajuma-module-webpimages-2.1.11.0.zip",
"shasum": "acc0eddedb94f5b235bcaeceddb215e3ed339cfb"
},
"type": "magento2-module",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Jajuma\\WebpImages\\": ""
},
"files": [
"registration.php"
]
},
"license": [
"MIT"
],
"authors": [
{
"name": "JaJuMa",
"email": "info@jajuma.de"
}
],
"description": "WebP Optimized Images",
"install-path": "../jajuma/module-webpimages"
},
{
"name": "jms/metadata", "name": "jms/metadata",
"version": "2.6.1", "version": "2.6.1",
"version_normalized": "2.6.1.0", "version_normalized": "2.6.1.0",
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
'name' => 'magento/magento2ce', 'name' => 'magento/magento2ce',
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'reference' => '2e6888fd835e9bf29c26ecb13cab664e7a994ade', 'reference' => '932207d218c95c847882fd23a97bf06d6f69ff1d',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
...@@ -487,6 +487,15 @@ ...@@ -487,6 +487,15 @@
'aliases' => array(), 'aliases' => array(),
'dev_requirement' => true, 'dev_requirement' => true,
), ),
'jajuma/module-webpimages' => array(
'pretty_version' => '2.1.11',
'version' => '2.1.11.0',
'reference' => NULL,
'type' => 'magento2-module',
'install_path' => __DIR__ . '/../jajuma/module-webpimages',
'aliases' => array(),
'dev_requirement' => false,
),
'jms/metadata' => array( 'jms/metadata' => array(
'pretty_version' => '2.6.1', 'pretty_version' => '2.6.1',
'version' => '2.6.1.0', 'version' => '2.6.1.0',
...@@ -949,7 +958,7 @@ ...@@ -949,7 +958,7 @@
'magento/magento2ce' => array( 'magento/magento2ce' => array(
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'reference' => '2e6888fd835e9bf29c26ecb13cab664e7a994ade', 'reference' => '932207d218c95c847882fd23a97bf06d6f69ff1d',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
......
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Block\Adminhtml\ConversionTool\Test;
use Magento\Framework\View\Element\Template;
use Magento\Framework\App\Filesystem\DirectoryList;
use Symfony\Component\Process\Process as SymfonyProcess;
use Symfony\Component\Process\Exception\ProcessFailedException as SymfonyProcessFailedException;
class Result extends \Magento\Framework\View\Element\Template
{
protected $productCollection;
protected $productRepository;
protected $directoryList;
protected $helper;
protected $moduleReader;
protected $error = null;
public function __construct(
Template\Context $context,
\Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection,
\Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
\Jajuma\WebpImages\Helper\Data $helper,
DirectoryList $directoryList,
\Magento\Framework\Module\Dir\Reader $moduleReader,
array $data = []
) {
$this->productCollection = $productCollection;
$this->productRepository = $productRepository;
$this->directoryList = $directoryList;
$this->helper = $helper;
$this->moduleReader = $moduleReader;
parent::__construct($context, $data);
}
public function getImageFromLastProduct()
{
$productId = $this->getRequest()->getParam('product');
if ($productId) {
try {
$product = $this->productRepository->getById($productId);
} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) {
return null;
}
} else {
$lastProductSku = $this->productCollection->getLastItem()->getSku();
$product = $this->productRepository->get($lastProductSku);
}
return $product->getImage();
}
public function convert()
{
$convertTool = $this->getRequest()->getParam('convert_tool');
$productImage = $this->getImageFromLastProduct();
$this->helper->clearTestWebpFolder();
$this->helper->createFolderIfNotExist($this->getMediaPath() . '/webp_image/test/');
$t = time();
if ($productImage) {
$productOriginalImagePath = $this->getMediaPath() . '/catalog/product' . $productImage;
$webpImage = preg_replace('/\.(png|jpg|jpeg)$/i', $t . '.webp', $productImage);
$webpImage = explode('/', $webpImage);
$webpImage = end($webpImage);
$webpPath = $this->getMediaPath() . '/webp_image/test/' . $webpImage;
} else {
$modulePath = $this->moduleReader->getModuleDir(
\Magento\Framework\Module\Dir::MODULE_VIEW_DIR,
'Jajuma_WebpImages'
);
$productOriginalImagePath = $modulePath . '/adminhtml/web/images/test.png';
$webpPath = $this->getMediaPath() . '/webp_image/test/'. $t .'.webp';
}
if ($this->helper->hasCheckTransparency() && $this->helper->hasAlphaTransparency($productOriginalImagePath)) {
return __('Can not convert transparency image!');
}
switch ($convertTool) {
case 'cwebp':
$newFile = $this->convertToWebpViaCwebp($productOriginalImagePath, $webpPath);
break;
case 'convert':
$newFile = $this->convertToWebpViaImageMagick($productOriginalImagePath, $webpPath);
break;
case 'gd':
$newFile = $this->convertToWebpViaGd($productOriginalImagePath, $webpPath);
break;
default:
$newFile = false;
break;
}
if ($newFile) {
$originalUrl = $productImage
? $this->helper->getImageUrlFromPath($productOriginalImagePath)
: $this->_assetRepo->getUrl("Jajuma_WebpImages::images/test.png");
$webpUrl = $this->helper->getImageUrlFromPath($newFile);
return ['original' => $originalUrl, 'webp' => $webpUrl];
} else {
return false;
}
}
public function getMediaPath()
{
return $this->directoryList->getPath(DirectoryList::MEDIA);
}
/**
* Method to convert an image to WebP using the GD method
*
* @param $imagePath
* @param $webpPath
*
* @return bool
*/
private function convertToWebpViaCwebp($imagePath, $webpPath)
{
$customCommand = $this->getRequest()->getParam('cwebp_command');
$pathCommand = $this->getRequest()->getParam('path_to_cwebp');
$cmd = $pathCommand != null ? $pathCommand : 'cwebp';
if (!preg_match(\Jajuma\WebpImages\Helper\Data::REGX_CWEBP_PATH, $cmd)) {
$this->error = __('Invalid Cwepb Path. Path must only include
underscore (_), minus (-), dot (.), slash(/) and alphanumeric characters.');
return false;
}
try {
if ($customCommand != null) {
if (!preg_match(\Jajuma\WebpImages\Helper\Data::REGX_CWEBP, $customCommand)) {
$this->error = __('Invalid Cwepb Custom Command. Custom Command must only include
underscore (_), minus (-), space ( ) and alphanumeric characters.');
return false;
} else {
$process = new SymfonyProcess(
escapeshellarg($cmd) . ' '
. $imagePath . ' '
. $customCommand . ' '
. $webpPath
);
}
} else {
$process = new SymfonyProcess(
escapeShellArg($cmd) . ' '
. $imagePath . ' -q '
. $this->getRequest()->getParam('quality')
. ' -alpha_q 100 -z 9 -m 6 -segments 4 -sns 80 -f 25 -sharpness 0 -strong -pass 10'
. ' -mt -alpha_method 1 -alpha_filter fast -o '
. $webpPath
);
}
$process->mustRun();
} catch (SymfonyProcessFailedException $exception) {
$this->error = __('Conversion Failed. Please make sure your custom path and
command are correct and your quality configuration value is between 0 and 100!');
return false;
}
if (file_exists($webpPath)) {
return $webpPath;
} else {
return false;
}
}
/**
* Method to convert an image to WebP using the Imagemagick command
*
* @param $imagePath
* @param $webpPath
* @return string
*/
private function convertToWebpViaImageMagick($imagePath, $webpPath)
{
if ($this->helper->isLoadedImageMagick()) {
$customCommand = $this->getRequest()->getParam('imagemagick_command');
$pathCommand = $this->getRequest()->getParam('path_to_imagemagick');
$cmd = $pathCommand != null ? $pathCommand : 'convert';
if (!preg_match(\Jajuma\WebpImages\Helper\Data::REGX_IMAGEMAGICK_PATH, $cmd)) {
$this->error = __('Invalid ImageMagick Path. Path must only include
underscore (_), minus (-), dot (.), slash(/) and alphanumeric characters.');
return false;
}
try {
if ($customCommand != null) {
if (!preg_match(\Jajuma\WebpImages\Helper\Data::REGX_IMAGEMAGICK, $customCommand)) {
$this->error = __('Invalid ImageMagick Custom Command. Custom Command must only include
underscore (_), minus (-), space ( ), comma (,), colon (:),
equals sign (=) and alphanumeric characters.');
return false;
} else {
$process = new SymfonyProcess(
escapeshellarg($cmd) . ' '
. $imagePath . ' '
. $customCommand . ' '
. $webpPath
);
}
} else {
$process = new SymfonyProcess(
escapeshellarg($cmd) . ' ' . $imagePath
. ' -quality ' . $this->getRequest()->getParam('quality')
. ' -define webp:lossless=false,method=6,segments=4,sns-strength=80,auto-filter=true,'
. ' filter-sharpness=0,filter-strength=25,filter-type=1,'
. ' alpha-compression=1,alpha-filtering=fast,alpha-quality=100 '
. $webpPath
);
}
$process->mustRun();
} catch (SymfonyProcessFailedException $exception) {
$this->error = __('Conversion Failed. Please make sure your custom path and command are
correct and your quality configuration value is between 0 and 100!');
return false;
}
if (file_exists($webpPath)) {
return $webpPath;
} else {
return false;
}
} else {
return false;
}
}
/**
* Method to convert an image to WebP using the GD method
*
* @param $imagePath
* @param $webpPath
*
* @return bool
*/
private function convertToWebpViaGd($imagePath, $webpPath)
{
if ($this->helper->hasGdSupport() == false) {
return false;
}
$imageData = file_get_contents($imagePath);
try {
$image = imagecreatefromstring($imageData);
imagepalettetotruecolor($image);
} catch (\Exception $ex) {
return false;
}
imagewebp($image, $webpPath, $this->getRequest()->getParam('quality'));
return $webpPath;
}
public function getUnsupportWebpImage()
{
return $this->getViewFileUrl('Jajuma_WebpImages::images/unsupport_webp.jpg');
}
public function getError()
{
return $this->error;
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Block\Adminhtml\System\Config;
class AdvancedConfiguration extends \Magento\Config\Block\System\Config\Form\Field
{
/**
* Render text
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element
*
* @return string
*/
public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
$html = '';
if ($element->getComment()) {
$html .= '<div style="margin: auto; padding: 10px;">';
$html .= $element->getComment() . '</div>';
}
return $html;
}
/**
* Return element html
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element
*
* @return string
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
return $this->_toHtml();
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Block\Adminhtml\System\Config;
class ClearButton extends \Magento\Config\Block\System\Config\Form\Field
{
/** @var UrlInterface */
protected $_urlBuilder;
/**
* Constructor
*
* @param \Magento\Backend\Block\Template\Context $context
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
array $data = []
) {
$this->_urlBuilder = $context->getUrlBuilder();
parent::__construct($context, $data);
}
/**
* Set template
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->setTemplate('Jajuma_WebpImages::system/config/clearbutton.phtml');
}
/**
* Generate button html
*
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function getButtonHtml()
{
$button = $this->getLayout()->createBlock(
\Magento\Backend\Block\Widget\Button::class
)->setData(
[
'id' => 'jajuma_webp_test_button',
'label' => __('Clear all webp image'),
'onclick' => 'javascript:clearWebpImage(); return false;',
]
);
return $button->toHtml();
}
/**
* Get admin url
*
* @return string
*/
public function getAdminUrl()
{
return $this->_urlBuilder->getUrl('webp/clear', ['store' => $this->_request->getParam('store')]);
}
/**
* Render button
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
// Remove scope label
$element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
return parent::render($element);
}
/**
* Return element html
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element
* @return string
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
return $this->_toHtml();
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Block\Adminhtml\System\Config;
class TestButton extends \Magento\Config\Block\System\Config\Form\Field
{
/** @var UrlInterface */
protected $_urlBuilder;
/**
* @var \Magento\Catalog\Model\ResourceModel\Product\Collection
*/
protected $productCollection;
/**
* TestButton constructor.
*
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection,
array $data = []
) {
$this->_urlBuilder = $context->getUrlBuilder();
$this->productCollection = $productCollection;
parent::__construct($context, $data);
}
/**
* Set template
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->setTemplate('Jajuma_WebpImages::system/config/testbutton.phtml');
}
/**
* Generate button html
*
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function getButtonHtml()
{
$button = $this->getLayout()->createBlock(
\Magento\Backend\Block\Widget\Button::class
)->setData(
[
'id' => 'jajuma_webp_test_button',
'label' => __('Test Conversion Tool'),
'onclick' => 'javascript:conversionToolTest(); return false;',
]
);
return $button->toHtml();
}
/**
* Get admin url
*
* @return string
*/
public function getAdminUrl()
{
return $this->_urlBuilder->getUrl('webp/test', ['store' => $this->_request->getParam('store')]);
}
/**
* Render button
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
// Remove scope label
$element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
return parent::render($element);
}
/**
* Return element html
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element
* @return string
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
return $this->_toHtml();
}
/**
* Get lastest product id
*
* @return int|null
*/
public function getLatestProductId()
{
if ($lastItem = $this->productCollection->getLastItem()) {
return $lastItem->getId();
}
return null;
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Block;
use Jajuma\WebpImages\Helper\Data as HelperModule;
class Picture extends \Magento\Framework\View\Element\Template
{
protected $_template = "picture-tag-format.phtml";
/**
* @var string
*/
private $webpImage = '';
/**
* @var string
*/
private $originalImage = '';
/**
* @var string
*/
private $originalTag = '';
/**
* @var string
*/
private $customSrcTag = '';
/**
* @var string
*/
private $customSrcSetTag = '';
/**
* Module helper data
*
* @var HelperModule
*/
protected $helper;
/**
* Picture constructor.
*
* @param \Magento\Framework\View\Element\Template\Context $context
* @param HelperModule $helperData
* @param array $data
*/
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
HelperModule $helperData,
array $data = []
) {
$this->helper = $helperData;
parent::__construct($context, $data);
}
/**
* Seti original image
*
* @param string $originalImage
*
* @return Picture
*/
public function setOriginalImage($originalImage)
{
$this->originalImage = $originalImage;
return $this;
}
/**
* Get original image
*
* @return string
*/
public function getOriginalImage()
{
return $this->originalImage;
}
/**
* Set Webp Image
*
* @param string $webpImage
*
* @return Picture
*/
public function setWebpImage($webpImage)
{
$this->webpImage = $webpImage;
return $this;
}
/**
* Get Webp Image
*
* @return string
*/
public function getWebpImage()
{
return $this->webpImage;
}
/**
* Set Original Tag
*
* @param string $originalTag
*
* @return Picture
*/
public function setOriginalTag($originalTag)
{
$this->originalTag = $originalTag;
return $this;
}
/**
* Get Original Tag
*
* @return string
*/
public function getOriginalTag()
{
return $this->originalTag;
}
/**
* Set custom src tag
*
* @param string $customSrcTag
*
* @return $this
*/
public function setCustomSrcTag($customSrcTag)
{
$this->customSrcTag = $customSrcTag;
return $this;
}
/**
* Get Custom Src Tag
*
* @return string
*/
public function getCustomSrcTag()
{
return $this->customSrcTag;
}
/**
* Set Custom Src Set Tag
*
* @param mixed $customSrcSetTag
*
* @return $this
*/
public function setCustomSrcSetTag($customSrcSetTag)
{
$this->customSrcSetTag = $customSrcSetTag;
return $this;
}
/**
* Get Custom Src Set Tag
*
* @return mixed
*/
public function getCustomSrcSetTag()
{
return $this->customSrcSetTag;
}
/**
* Get Original Image Type
*
* @return string
*/
public function getOriginalImageType()
{
if (preg_match('/\.(jpg|jpeg)$/i', $this->getOriginalImage())) {
return 'image/jpg';
}
if (preg_match('/\.(png)$/i', $this->getOriginalImage())) {
return 'image/png';
}
return '';
}
/**
* Is Native Lazy Loading Enabled
*
* @return bool
*/
public function isNativeLazyLoadingEnabled()
{
return $this->helper->isNativeLazyLoadingEnabled();
}
/**
* Get Exclude Native Lazy load Image Attributes
*
* @return mixed
*/
public function getExcludeNativeLazyloadImageAttributes()
{
return $this->helper->getExcludeNativeLazyloadImageAttributes();
}
}
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Block\System\Config\Form\Jajuma;
class Module extends \Magento\Config\Block\System\Config\Form\Field
{
/**
* Render text
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element
*
* @return string
*/
public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
$html = '';
if ($element->getComment()) {
$html = $element->getComment();
}
return $html;
}
/**
* Return element html
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element
*
* @return string
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
return $this->_toHtml();
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Controller\Adminhtml\Clear;
use Magento\Backend\App\Action;
use Magento\Framework\Controller\ResultFactory;
use Magento\Backend\App\Action\Context;
use Jajuma\WebpImages\Helper\Data;
class Index extends Action
{
/**
* Module helper
*
* @var Data
*/
protected $helper;
/**
* Constructor
*
* @param Data $helper
* @param Context $context
*/
public function __construct(
Data $helper,
Context $context
) {
$this->helper = $helper;
parent::__construct($context);
}
/**
* Execute
*
* @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
$resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
if ($this->helper->clearWebp() == 'nowebpFolder') {
$this->messageManager->addSuccessMessage(__('WebP Image Cache is empty'));
} elseif ($this->helper->clearWebp()) {
$this->messageManager->addSuccessMessage(
__('All WebP images have been removed (please also clear FPC to recreate WebP images)')
);
} else {
$this->messageManager->addErrorMessage(
__('Can not remove the webp_image folder (please check folder permissions)')
);
}
$resultRedirect->setUrl($this->_redirect->getRefererUrl());
return $resultRedirect;
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Controller\Adminhtml\Test;
use Magento\Backend\App\Action;
use Magento\Framework\Controller\ResultFactory;
use Magento\Backend\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;
class Index extends Action
{
/**
* PageFactory
*
* @var PageFactory
*/
protected $resultPageFactory;
/**
* Test controller constructor
*
* @param Context $context
* @param PageFactory $resultPageFactory
*/
public function __construct(
Context $context,
PageFactory $resultPageFactory
) {
parent::__construct($context);
$this->resultPageFactory = $resultPageFactory;
}
/**
* Product list page
*
* @return \Magento\Backend\Model\View\Result\Page
*/
public function execute()
{
/** @var \Magento\Backend\Model\View\Result\Page $resultPage */
$resultPage = $this->resultPageFactory->create();
return $resultPage;
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Controller\Image;
use function GuzzleHttp\json_encode;
use Magento\Framework\App\Action\Context;
use Jajuma\WebpImages\Helper\Data;
use Magento\Framework\Controller\Result\JsonFactory;
class Convert extends \Magento\Framework\App\Action\Action
{
/**
* Context
*
* @var Context
*/
protected $context;
/**
* Module helper Data
*
* @var Data
*/
protected $helper;
/**
* JsonFactory
*
* @var JsonFactory
*/
protected $resultJsonFactory;
/**
* Constructor
*
* @param Context $context
* @param Data $helper
* @param JsonFactory $resultJsonFactory
*/
public function __construct(
Context $context,
Data $helper,
JsonFactory $resultJsonFactory
) {
$this->helper = $helper;
$this->resultJsonFactory = $resultJsonFactory;
parent::__construct($context);
}
/**
* Execute
*
* @return JsonFactory
*/
public function execute()
{
$resultJson = $this->resultJsonFactory->create();
$images = $this->getRequest()->getParam('images');
$isInProductView = $this->getRequest()->getParam('isInProductView');
if ($images) {
$webpUrls = [];
foreach ($images as $imageUrl) {
if (array_key_exists('thumb', $imageUrl)) {
$webpUrlThumb = $this->helper->convert($imageUrl['thumb']);
if ($webpUrlThumb) {
$imageUrl['thumb'] = $webpUrlThumb;
}
}
if (array_key_exists('img', $imageUrl)) {
$webpUrlImg = $this->helper->convert($imageUrl['img']);
if ($webpUrlImg) {
$imageUrl['img'] = $webpUrlImg;
}
}
if (array_key_exists('full', $imageUrl)) {
$webpUrlFull = $this->helper->convert($imageUrl['full']);
if ($webpUrlFull) {
$imageUrl['full'] = $webpUrlFull;
}
}
if (!empty($imageUrl)) {
array_push($webpUrls, $imageUrl);
}
}
}
return $resultJson->setData(['webpUrls' => $webpUrls]);
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Magento\Framework\Filesystem;
use Magento\Framework\ObjectManager\ObjectManager;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem\Driver\File as DriverFile;
use Symfony\Component\Process\Process as SymfonyProcess;
use Symfony\Component\Process\Exception\ProcessFailedException as SymfonyProcessFailedException;
class Data extends AbstractHelper
{
/** Regx */
const REGX_CWEBP = '/^[a-zA-Z0-9-_\s]+$/mi';
const REGX_IMAGEMAGICK = '/^[a-zA-Z0-9-_\s,=:]+$/mi';
const REGX_CWEBP_PATH = '/(^[a-zA-Z0-9\/_\-\.]+cwebp$|^cwebp$)/mi';
const REGX_IMAGEMAGICK_PATH = '/(^[a-zA-Z0-9\/_\-\.]+convert$|^convert$)/mi';
/**
* StoreManager Interface
*
* @var StoreManagerInterface
*/
protected $storeManager;
/**
* Filesystem
*
* @var Filesystem
*/
protected $filesystem;
/**
* Driver file
*
* @var DriverFile
*/
protected $driverFile;
/**
* @var string|null
*/
protected $newFile;
/**
* IO file
*
* @var Filesystem\Io\File
*/
protected $ioFile;
/**
* @var null
*/
protected $imageQuality;
/**
* Module file helper
*
* @var File
*/
protected $fileHelper;
/**
* Constructor
*
* @param Context $context
* @param ObjectManager $objectManager
* @param StoreManagerInterface $storeManager
* @param Filesystem $filesystem
* @param DriverFile $driverFile
* @param Filesystem\Io\File $ioFile
* @param File $fileHelper
*/
public function __construct(
Context $context,
ObjectManager $objectManager,
StoreManagerInterface $storeManager,
Filesystem $filesystem,
DriverFile $driverFile,
Filesystem\Io\File $ioFile,
File $fileHelper
) {
$this->ioFile = $ioFile;
$this->storeManager = $storeManager;
$this->filesystem = $filesystem;
$this->driverFile = $driverFile;
$this->fileHelper = $fileHelper;
parent::__construct($context);
}
/**
* Convert Image to Webp Image
*
* @param string $imageUrl
*
* @return string
*/
public function convert($imageUrl)
{
$webpUrl = $this->getWebpNameFromImage($imageUrl);
$webpPath = $this->getImagePathFromUrl($webpUrl);
$this->newFile = $webpPath;
$folder = $this->driverFile->getParentDirectory($webpPath);
$this->createFolderIfNotExist($folder);
$imagePath = $this->getImagePathFromUrl($imageUrl);
if (empty($imagePath)) {
return $imageUrl;
}
if (!$this->isFileExists($imagePath)) {
return $imageUrl;
}
if (!$this->isEnabled()) {
return $imageUrl;
}
if ($this->isFileExists($webpPath)) {
// check if modified date of converted image is older than original image.
// then delete the old converted image.
$checkIsOldConvertedImage = $this->checkIsOldConvertedImage($imagePath, $webpPath);
if (!$checkIsOldConvertedImage) {
return $webpUrl;
}
}
// Detect alpha-transparency in PNG-images and skip it
if ($this->hasCheckTransparency() && $this->hasAlphaTransparency($imagePath)) {
return $imageUrl;
}
switch ($this->scopeConfig->getValue(
'webp/advance_mode/convert_tool',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
)) {
case 'cwebp':
$this->newFile = $this->convertToWebpViaCwebp($imagePath, $webpPath);
break;
case 'convert':
$this->newFile = $this->convertToWebpViaImageMagick($imagePath, $webpPath);
break;
case 'gd':
$this->newFile = $this->convertToWebpViaGd($imagePath, $webpPath);
break;
}
$webpUrl = $this->getImageUrlFromPath($this->newFile);
return $webpUrl;
}
/**
* Check Is Old Converted Image
*
* @param $imagePath
* @param $webpPath
*
* @return bool
* @throws \Magento\Framework\Exception\FileSystemException
* @throws \Magento\Framework\Exception\NoSuchEntityException
*/
public function checkIsOldConvertedImage($imagePath, $webpPath)
{
// Get converted file modified date
$convertedFileModifiedDate = $this->driverFile->stat($webpPath)['mtime'];
// Get original file modified date
$originfileModifiedDate = $this->driverFile->stat($imagePath)['mtime'];
// check if modified date of converted image is older than original image.
if ($originfileModifiedDate && $convertedFileModifiedDate && $originfileModifiedDate > $convertedFileModifiedDate) {
// remove old converted file.
$this->driverFile->deleteFile($webpPath);
return true;
}
return false;
}
/**
* Method to convert an image to WebP using the GD method
*
* @param string $imagePath
* @param string $webpPath
*
* @return bool
*/
public function convertToWebpViaGd($imagePath, $webpPath)
{
if ($this->hasGdSupport() == false) {
return $imagePath;
}
$imageData = $this->fileGetContent($imagePath);
try {
$image = imagecreatefromstring($imageData);
imagepalettetotruecolor($image);
} catch (\Exception $ex) {
return false;
}
imagewebp($image, $webpPath, $this->imageQuality());
return $webpPath;
}
/**
* Method to convert an image to WebP using the Imagemagick command
*
* @param string $imagePath
* @param string $webpPath
*
* @return string
*/
public function convertToWebpViaImageMagick($imagePath, $webpPath)
{
if ($this->isLoadedImageMagick()) {
$customCommand = $this->scopeConfig->getValue(
'webp/advance_mode/imagemagick_command',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
$pathCommand = $this->scopeConfig->getValue(
'webp/advance_mode/path_to_imagemagick',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
$cmd = $pathCommand != null ? $pathCommand : 'convert';
try {
if ($customCommand != null) {
if (!preg_match(\Jajuma\WebpImages\Helper\Data::REGX_IMAGEMAGICK, $customCommand)) {
$this->error = __('Invalid ImageMagick Custom Command. Custom Command must only include
underscore (_), minus (-), space ( ), comma (,), colon (:),
equals sign (=) and alphanumeric characters.');
return false;
} else {
$process = new SymfonyProcess(
$this->escapeshellarg($cmd) . ' '
. $imagePath . ' '
. $customCommand . ' '
. $webpPath
);
}
} else {
$process = new SymfonyProcess(
$this->escapeShellArg($cmd) . ' '
. $imagePath
. ' -quality '
. $this->imageQuality()
. ' -define webp:lossless=false,method=6,segments=4,sns-strength=80,auto-filter=true,'
. ' filter-sharpness=0,filter-strength=25,filter-type=1,'
. ' alpha-compression=1,alpha-filtering=fast,alpha-quality=100 '
. $webpPath
);
}
$process->mustRun();
} catch (SymfonyProcessFailedException $exception) {
return $imagePath;
}
if ($this->isFileExists($webpPath)) {
return $webpPath;
}
}
return $imagePath;
}
/**
* Method to convert an image to WebP using the Cwebp command
*
* @param string $imagePath
* @param string $webpPath
*
* @return string
*/
public function convertToWebpViaCwebp($imagePath, $webpPath)
{
$customCommand = $this->scopeConfig->getValue(
'webp/advance_mode/cwebp_command',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
$pathCommand = $this->scopeConfig->getValue(
'webp/advance_mode/path_to_cwebp',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
$cmd = $pathCommand != null ? $pathCommand : 'cwebp';
try {
if ($customCommand != null) {
if (!preg_match(\Jajuma\WebpImages\Helper\Data::REGX_CWEBP, $customCommand)) {
$this->error = __('Invalid Cwepb Custom Command. Custom Command must only include
underscore (_), minus (-), space ( ) and alphanumeric characters.');
return false;
} else {
$process = new SymfonyProcess(
$this->escapeshellarg($cmd) . ' '
. $imagePath . ' '
. $customCommand . ' '
. $webpPath
);
}
} else {
$process = new SymfonyProcess(
$this->escapeShellArg($cmd) . ' '
. $imagePath . ' -q '
. $this->imageQuality()
. ' -alpha_q 100 -z 9 -m 6 -segments 4 -sns 80 -f 25 -sharpness 0 -strong -pass 10'
. ' -mt -alpha_method 1 -alpha_filter fast -o '
. $webpPath
);
}
$process->mustRun();
} catch (SymfonyProcessFailedException $exception) {
return $imagePath;
}
if ($this->isFileExists($webpPath)) {
return $webpPath;
}
return $imagePath;
}
/**
* Is Enabled
*
* @param int|null $store
*
* @return bool
*/
public function isEnabled($store = null)
{
return $this->scopeConfig->getValue(
'webp/setting/enable',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$store
);
}
/**
* Image Quality
*
* @param int|null $store
*
* @return int
*/
public function imageQuality($store = null)
{
if (!$this->imageQuality) {
$this->imageQuality = $this->scopeConfig->getValue(
'webp/advance_mode/quality',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$store
);
}
return (int)$this->imageQuality;
}
/**
* Has Gd Support
*
* @return bool
*/
public function hasGdSupport()
{
if (!function_exists('imagewebp')) {
return false;
}
return true;
}
/**
* Is Loaded Image Magick
*
* @return bool
*/
public function isLoadedImageMagick()
{
if (extension_loaded('imagick')) {
return true;
} else {
return false;
}
}
/**
* Get the WebP path equivalent of an image path
*
* @param mixed $image
*
* @return mixed
*/
public function getWebpNameFromImage($image)
{
$image = preg_replace('/\.(png|jpg|jpeg)$/i', '.webp', $image);
$image = str_replace('media/', 'media/webp_image/', $image);
return $image;
}
/**
* Get System Paths
*
* @return array
*/
public function getSystemPaths()
{
$baseUrl = $this->storeManager->getStore()->getBaseUrl();
$mediaUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
$systemPaths = [
'pub' => [
'url' => $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA),
'urlWithoutBaseUrl' => str_replace($baseUrl, '', $mediaUrl),
'path' => $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath()
]
];
return $systemPaths;
}
/**
* Get Image Path From Url
*
* @param string $imageUrl
*
* @return mixed
*/
public function getImagePathFromUrl($imageUrl)
{
$systemPaths = $this->getSystemPaths();
foreach ($systemPaths as $systemPath) {
if (strstr($imageUrl, $systemPath['url'])) {
// if url have base url. ex: https://example.com/pub/media/..
return str_replace($systemPath['url'], $systemPath['path'], $imageUrl);
} elseif (strstr($imageUrl, $systemPath['urlWithoutBaseUrl'])) {
// if url don't have base url. ex: /pub/media/..
if (strpos($imageUrl, '/media/') !== false) {
$imageUrl = str_replace('/media/', 'media/', $imageUrl);
}
// replace pub/media with system path
return str_replace($systemPath['urlWithoutBaseUrl'], $systemPath['path'], $imageUrl);
}
}
return false;
}
/**
* Get Image Url From Path
*
* @param string $imagePath
*
* @return mixed
*/
public function getImageUrlFromPath($imagePath)
{
$systemPaths = $this->getSystemPaths();
if (!preg_match('/^http/', $imagePath)) {
foreach ($systemPaths as $systemPath) {
if (strstr($imagePath, $systemPath['path'])) {
return str_replace($systemPath['path'], $systemPath['url'], $imagePath);
}
}
}
return false;
}
/**
* Has Check Transparency
*
* @param int|null $store
*
* @return mixed
*/
public function hasCheckTransparency($store = null)
{
return $this->scopeConfig->getValue(
'webp/setting/check_transparency',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$store
);
}
/**
* Detect whether an image has PNG alpha transparency
*
* @param mixed $image
*
* @return bool
*/
public function hasAlphaTransparency($image)
{
if (empty($image)) {
return false;
}
if ($this->isFileExists($image) == false) {
return false;
}
if (preg_match('/\.(jpg|jpeg)$/', $image)) {
return false;
}
$fileIo = $this->fileHelper;
$fileIo->setCwd($this->driverFile->getParentDirectory($image));
$fileIo->setIwd($this->driverFile->getParentDirectory($image));
$imageContents = $fileIo->read($image);
$colorType = ord(substr($imageContents, 25, 1));
if ($colorType == 6 || $colorType == 4) {
return true;
} elseif (stripos($imageContents, 'PLTE') !== false && stripos($imageContents, 'tRNS') !== false) {
return true;
}
return false;
}
/**
* Create Folder If Not Exist
*
* @param string $path
*/
public function createFolderIfNotExist($path)
{
if (!$this->driverFile->isDirectory($path)) {
$ioAdapter = $this->ioFile;
$ioAdapter->mkdir($path, 0775);
}
}
/**
* Delete file
*
* @param string $filePath
*/
public function deleteFile($filePath)
{
if ($this->isFileExists($filePath)) {
$ioAdapter = $this->ioFile;
$ioAdapter->rm($filePath);
}
}
/**
* Remove Folder
*
* @param string $folderPath
*
* @return bool|string
*/
public function removeFolder($folderPath)
{
if ($this->driverFile->isDirectory($folderPath)) {
if ($this->driverFile->isWritable($folderPath)) {
$ioAdapter = $this->ioFile;
$ioAdapter->rmdir($folderPath, true);
} else {
return false;
}
} else {
return 'nowebpFolder';
}
}
/**
* Clear Test Webp Folder
*
* @return mixed
*/
public function clearTestWebpFolder()
{
$webpFolder = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath() . 'webp_image/test';
return $this->removeFolder($webpFolder) ;
}
/**
* Clear webp
*
* @return mixed
*/
public function clearWebp()
{
$webpFolder = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath() . 'webp_image';
return $this->removeFolder($webpFolder) ;
}
/**
* Get Exclude Image Attribute
*
* @param int|null $store
*
* @return mixed
*/
public function getExcludeImageAttribute($store = null)
{
return $this->scopeConfig->getValue(
'webp/professional_mode/exclude_img',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$store
);
}
/**
* Get custom src tag
*
* @param int|null $store
*
* @return mixed
*/
public function getCustomSrcTag($store = null)
{
return $this->scopeConfig->getValue(
'webp/professional_mode/src_tag',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$store
);
}
/**
* Get Custom Src Set Tag
*
* @param int|null $store
*
* @return mixed
*/
public function getCustomSrcSetTag($store = null)
{
return $this->scopeConfig->getValue(
'webp/professional_mode/srcset_tag',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$store
);
}
/**
* Is Native Lazy Loading Enabled
*
* @param int|null $store
*
* @return mixed
*/
public function isNativeLazyLoadingEnabled($store = null)
{
return $this->scopeConfig->getValue(
'webp/native_lazy/enable_native_lazy',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$store
);
}
/**
* Get Exclude Native Lazy load Image Attribute
*
* @param int|null $store
*
* @return mixed
*/
public function getExcludeNativeLazyloadImageAttribute($store = null)
{
return $this->scopeConfig->getValue(
'webp/native_lazy/exclude_native_lazy',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$store
);
}
/**
* Get Exclude Native Lazy load Image Attributes
*
* @return string
*/
public function getExcludeNativeLazyloadImageAttributes()
{
$excludeImageAttributes = $this->getExcludeNativeLazyloadImageAttribute();
if ($excludeImageAttributes) {
// Make sure unescaped slashes in blacklist get escaped.
$excludeImageAttributes = preg_replace('/([^\\\\]\\K\\/|^\\/)/', '\\/', $excludeImageAttributes);
$excludeImageAttributes = explode(',', $excludeImageAttributes);
$excludeImageAttributes = array_map('trim', $excludeImageAttributes);
$excludeImageAttributes = implode(".*|.*", $excludeImageAttributes);
$excludeImageAttributes = '/(.*data-nowebp=\"true\".*|.*' . $excludeImageAttributes . '.*)/mi';
} else {
$excludeImageAttributes = '/(.*data-nowebp=\"true\".*)/mi';
}
return $excludeImageAttributes;
}
/**
* Is File Exists
*
* @param string $path
*
* @return bool
*/
public function isFileExists($path)
{
return $this->ioFile->fileExists($path);
}
/**
* File Get Content
*
* @param string $path
*
* @return false|string
*/
public function fileGetContent($path)
{
return $this->driverFile->fileGetContents($path);
}
/**
* Escape Shell Arg
*
* @param string $str
*
* @return string
*/
public function escapeShellArg($str)
{
return escapeshellarg($str);
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Helper;
class File extends \Magento\Framework\Filesystem\Io\File
{
/**
* Set iwd
*
* @param mixed $iwd
*
* @return $this
*/
public function setIwd($iwd)
{
$this->_iwd = $iwd;
}
/**
* Set cwd
*
* @param mixed $cwd
*
* @return $this
*/
public function setCwd($cwd)
{
$this->_cwd = $cwd;
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Model\Config;
class Comment implements \Magento\Config\Model\Config\CommentInterface
{
/**
* @var $dir
*/
protected $dir;
/**
* Constructor
*
* @param \Magento\Framework\Filesystem\DirectoryList $dir
*/
public function __construct(
\Magento\Framework\Filesystem\DirectoryList $dir
) {
$this->dir = $dir;
}
/**
* Get comment text
*
* @param string $elementValue
*
* @return string
*/
public function getCommentText($elementValue)
{
return 'Define the specify path of cwebp command or leave it empty to use global command "cwebp". Example: '
. $this->dir->getPath('app') . '/code/Jajuma/WebpImages/bin/cwebp';
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Model\Config\Source;
class Tool implements \Magento\Framework\Option\ArrayInterface
{
/**
* Options getter
*
* @return array
*/
public function toOptionArray()
{
return [
['value' => 'cwebp', 'label' => __('Cwebp')],
['value' => 'convert', 'label' => __('Imagemagick')],
['value' => 'gd', 'label' => __('GD')]
];
}
}
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2022-present JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Plugin\Backend\Block\Menu;
use Magento\Backend\Block\Menu;
class AddLinkJs
{
/**
* @param Menu $subject
* @param string $html
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function afterToHtml(Menu $subject, $html)
{
$js = $subject->getLayout()->createBlock(\Magento\Backend\Block\Template::class)
->setTemplate('Jajuma_WebpImages::backend/menu/link_blank.phtml')
->toHtml();
return $html . $js;
}
}
\ No newline at end of file
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2022-present JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Plugin\Backend\Model\Menu\Item;
use Magento\Backend\Model\Menu\Item;
class ExtensionsLinkPlugin
{
/**
* @param Item $subject
* @param string $url
* @return string
*/
public function afterGetUrl(Item $subject, $url)
{
if ($subject->getId() === 'Jajuma_Extensions::extensions_link') {
return 'https://www.jajuma.de/en/jajuma-develop/magento-extensions?mtm_campaign=Extensions-Menu';
}
return $url;
}
}
\ No newline at end of file
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Plugin;
use Magento\Framework\Message\ManagerInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
class ConfigPlugin
{
/**
* Manager Interface
*
* @var ManagerInterface
*/
protected $messageManager;
/**
* Scope Config Interface
*
* @var ScopeConfigInterface
*/
protected $scopeConfig;
/**
* ConfigPlugin constructor.
*
* @param ManagerInterface $messageManager
* @param ScopeConfigInterface $scopeConfig
*/
public function __construct(
ManagerInterface $messageManager,
ScopeConfigInterface $scopeConfig
) {
$this->messageManager = $messageManager;
$this->scopeConfig = $scopeConfig;
}
/**
* Around save method
*
* @param \Magento\Config\Model\Config $subject
* @param \Closure $proceed
*
* @return \Closure $proceed
*/
public function aroundSave(
\Magento\Config\Model\Config $subject,
\Closure $proceed
) {
$data = $subject->getData();
if (isset($data['section']) && $data['section'] === 'webp') {
if (isset($data['groups']['advance_mode']['fields']['cwebp_command']['value'])
&& $data['groups']['advance_mode']['fields']['cwebp_command']['value'] !== '') {
$regexCwebp = \Jajuma\WebpImages\Helper\Data::REGX_CWEBP;
if (!preg_match(
$regexCwebp,
$data['groups']['advance_mode']['fields']['cwebp_command']['value']
)
) {
$this->messageManager->addNoticeMessage(__('Invalid Cwepb Custom Command. Custom Command
must only include underscore (_), minus (-), space ( ) and alphanumeric characters.'));
$data['groups']['advance_mode']['fields']['cwebp_command']['value']
= $this->scopeConfig->getValue('webp/advance_mode/cwebp_command');
}
}
if (isset($data['groups']['advance_mode']['fields']['imagemagick_command']['value'])
&& $data['groups']['advance_mode']['fields']['imagemagick_command']['value'] !== '') {
$regexImagemagick = \Jajuma\WebpImages\Helper\Data::REGX_IMAGEMAGICK;
if (!preg_match(
$regexImagemagick,
$data['groups']['advance_mode']['fields']['imagemagick_command']['value']
)
) {
$this->messageManager->addNoticeMessage(__('Invalid Imagemagick Custom Command.
Custom Command must only include underscore (_), minus (-), space ( ), comma (,), colon (:),
equals sign (=) and alphanumeric characters.'));
$data['groups']['advance_mode']['fields']['imagemagick_command']['value']
= $this->scopeConfig->getValue('webp/advance_mode/imagemagick_command');
}
}
if (isset($data['groups']['advance_mode']['fields']['path_to_cwebp']['value'])
&& $data['groups']['advance_mode']['fields']['path_to_cwebp']['value'] !== '') {
$regexCwebpPath = \Jajuma\WebpImages\Helper\Data::REGX_CWEBP_PATH;
if (!preg_match($regexCwebpPath, $data['groups']['advance_mode']['fields']['path_to_cwebp']['value'])) {
$this->messageManager->addNoticeMessage(__('Invalid Cwebp Path. Path must only include
underscore (_), minus (-), dot (.), slash(/) and alphanumeric characters.'));
$data['groups']['advance_mode']['fields']['path_to_cwebp']['value']
= $this->scopeConfig->getValue('webp/advance_mode/path_to_cwebp');
}
}
if (isset($data['groups']['advance_mode']['fields']['path_to_imagemagick']['value'])
&& $data['groups']['advance_mode']['fields']['path_to_imagemagick']['value'] !== '') {
$regexImageMagickPath = \Jajuma\WebpImages\Helper\Data::REGX_IMAGEMAGICK_PATH;
if (!preg_match(
$regexImageMagickPath,
$data['groups']['advance_mode']['fields']['path_to_imagemagick']['value']
)
) {
$this->messageManager->addNoticeMessage(__('Invalid ImageMagick Path.
Path must only include underscore (_), minus (-), dot (.),
slash(/) and alphanumeric characters.'));
$data['groups']['advance_mode']['fields']['path_to_imagemagick']['value']
= $this->scopeConfig->getValue('webp/advance_mode/path_to_imagemagick');
}
}
$subject->setData($data);
}
return $proceed();
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Plugin\Product\View;
use Jajuma\WebpImages\Helper\Data;
use Magento\Framework\Json\Helper\Data as JsonHelper;
class GalleryPlugin
{
/**
* Module helper data
*
* @var Data
*/
protected $helperWebp;
/**
* Json Helper
*
* @var JsonHelper
*/
protected $jsonHelper;
/**
* Constructor
*
* @param Data $webpImagesHelper
* @param JsonHelper $jsonHelper
*/
public function __construct(
Data $webpImagesHelper,
JsonHelper $jsonHelper
) {
$this->helperWebp = $webpImagesHelper;
$this->jsonHelper = $jsonHelper;
}
/**
* After Get Gallery Images Json
*
* @param \Magento\Catalog\Block\Product\View\Gallery $subject
* @param mixed $result
*/
public function afterGetGalleryImagesJson(\Magento\Catalog\Block\Product\View\Gallery $subject, $result)
{
$newImagesItems = [];
$imagesItems = $this->jsonHelper->jsonDecode($result);
foreach ($imagesItems as $itemImage) {
$thumbImage = $itemImage['thumb'];
$imgImage = $itemImage['img'];
$fullImage = $itemImage['full'];
$webpThumbImageUrl = $this->helperWebp->convert($thumbImage);
$itemImage['thumb_webp'] = $webpThumbImageUrl;
$webpImgImageUrl = $this->helperWebp->convert($imgImage);
$itemImage['img_webp'] = $webpImgImageUrl;
$webpFullImageUrl = $this->helperWebp->convert($fullImage);
$itemImage['full_webp'] = $webpFullImageUrl;
$newImagesItems[] = $itemImage;
}
return $this->jsonHelper->jsonEncode($newImagesItems);
}
}
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Plugin;
use Magento\Framework\View\LayoutInterface;
use Jajuma\WebpImages\Block\Picture;
use Jajuma\WebpImages\Helper\Data;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;
class ReplaceImageTag
{
/**
* Module helper Data
*
* @var Data
*/
protected $helper;
/**
* StoreManagerInterface
*
* @var StoreManagerInterface
*/
protected $storeManager;
/**
* Constructor
*
* @param Data $helper
* @param StoreManagerInterface $storeManager
*/
public function __construct(
Data $helper,
StoreManagerInterface $storeManager,
LoggerInterface $logger
) {
$this->helper = $helper;
$this->storeManager = $storeManager;
$this->logger = $logger;
}
/**
* After get output
*
* @param LayoutInterface $layout
* @param string $output
*
* @return string
*/
public function afterGetOutput(LayoutInterface $layout, $output)
{
if (!$this->helper->isEnabled()) {
return $output;
}
$regex = '/<img([^<]+\s|\s)src=(\"|' . "\')([^<]+?\.(png|jpg|jpeg))[^<]+>(?!(<\/pic|\s*<\/pic))/mi";
if (preg_match_all($regex, $output, $images, PREG_OFFSET_CAPTURE) === false) {
return $output;
}
$accumulatedChange = 0;
$baseUrl = $this->storeManager->getStore()->getBaseUrl();
$mediaUrl = $this->storeManager->getStore()->getBaseUrl(
\Magento\Framework\UrlInterface::URL_TYPE_MEDIA
);
$mediaUrlWithoutBaseUrl = str_replace($baseUrl, '', $mediaUrl);
$excludeImageAttributes = $this->getExcludeImageAttributes();
$customSrcSetTag = $this->helper->getCustomSrcSetTag() ? $this->helper->getCustomSrcSetTag() : '';
foreach ($images[0] as $index => $image) {
$offset = $image[1] + $accumulatedChange;
$htmlTag = $images[0][$index][0];
$imageUrl = $images[3][$index][0];
/**
* Skip when image is not from same server
*/
if (strpos($imageUrl, $mediaUrl) === false && strpos($imageUrl, $mediaUrlWithoutBaseUrl) === false) {
continue;
}
/**
* Skip when image contains an excluded attribute
*/
$isValidRegex = false;
try {
preg_match($excludeImageAttributes, '');
$isValidRegex = true;
} catch (\Exception $e) {
$this->logger->info("Conversion Blacklist Configuration is invalid:" . $excludeImageAttributes);
$this->logger->info("Detail: " . $e->getMessage());
}
if ($isValidRegex) {
if (preg_match_all($excludeImageAttributes, $htmlTag)) {
continue;
}
}
$pictureTag = $this->convertImage($imageUrl, $htmlTag, $customSrcSetTag, $layout);
if (!$pictureTag) {
continue;
}
$output = substr_replace($output, $pictureTag, $offset, strlen($htmlTag));
$accumulatedChange = $accumulatedChange + (strlen($pictureTag) - strlen($htmlTag));
}
return $output;
}
/**
* Get picture tag format
*
* @param LayoutInterface $layout
*
* @return Picture
*/
private function getPicture(LayoutInterface $layout)
{
/** @var Picture $block */
$block = $layout->createBlock(Picture::class);
return $block;
}
/**
* Get exclude image attributes
*
* @return string
*/
private function getExcludeImageAttributes()
{
$excludeImageAttributes = $this->helper->getExcludeImageAttribute();
if ($excludeImageAttributes) {
// Make sure unescaped slashes in blacklist get escaped.
$excludeImageAttributes = preg_replace('/([^\\\\]\\K\\/|^\\/)/', '\\/', $excludeImageAttributes);
$excludeImageAttributes = explode(',', $excludeImageAttributes);
$excludeImageAttributes = array_map('trim', $excludeImageAttributes);
$excludeImageAttributes = implode(".*|.*", $excludeImageAttributes);
$excludeImageAttributes = '/(.*data-nowebp=\"true\".*|.*\/media\/captcha\/.*|.*' .
$excludeImageAttributes . '.*)/mi';
} else {
$excludeImageAttributes = '/(.*data-nowebp=\"true\".*|.*\/media\/captcha\/.*)/mi';
}
return $excludeImageAttributes;
}
/**
* Convert Image
*
* @param string $imageUrl
* @param string $htmlTag
* @param string $customSrcSetTag
* @param LayoutInterface $layout
*
* @return bool|string
*/
private function convertImage($imageUrl, $htmlTag, $customSrcSetTag, LayoutInterface $layout)
{
$lazyload = false;
if ($customSrcTag = $this->helper->getCustomSrcTag()) {
$expression = '/('.$customSrcTag.')=(\"|' . "\')([^<]+\.(png|jpg|jpeg))/mU";
if (preg_match_all($expression, $htmlTag, $match, PREG_OFFSET_CAPTURE)) {
$lazyload = true;
$imageUrl = $match[3][0][0];
}
}
$webpUrl = $this->helper->convert($imageUrl);
/**
* Skip when extension can not convert the image
*/
if ($webpUrl === $imageUrl) {
return false;
}
if ($lazyload) {
$pictureTag = $this->getPicture($layout)
->setOriginalImage($imageUrl)
->setWebpImage($webpUrl)
->setOriginalTag($htmlTag)
->setCustomSrcTag($customSrcTag)
->setCustomSrcSetTag($customSrcSetTag)
->toHtml();
} else {
$pictureTag = $this->getPicture($layout)
->setOriginalImage($imageUrl)
->setWebpImage($webpUrl)
->setOriginalTag($htmlTag)
->toHtml();
}
return $pictureTag;
}
}
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
namespace Jajuma\WebpImages\Setup\Patch\Data;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\App\Config\Storage\WriterInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Module\Dir;
class SetCwebpBinaryPath implements DataPatchInterface
{
/**
* @var ModuleDataSetupInterface
*/
private $moduleDataSetup;
/**
* @var WriterInterface
*/
protected $configWriter;
/**
* @var ScopeConfigInterface
*/
protected $scopeConfig;
/**
* @var Dir
*/
protected $dir;
/**
* PatchInitial constructor.
* @param ModuleDataSetupInterface $moduleDataSetup
* @param WriterInterface $configWriter
* @param ScopeConfigInterface $scopeConfig
* @param Dir $dir
*/
public function __construct(
ModuleDataSetupInterface $moduleDataSetup,
WriterInterface $configWriter,
ScopeConfigInterface $scopeConfig,
Dir $dir
) {
$this->moduleDataSetup = $moduleDataSetup;
$this->configWriter = $configWriter;
$this->scopeConfig = $scopeConfig;
$this->dir = $dir;
}
/**
* {@inheritdoc}
*/
public function apply()
{
if(!$this->scopeConfig->getValue('webp/advance_mode/path_to_cwebp')) {
$this->configWriter->save(
'webp/advance_mode/path_to_cwebp',
$this->dir->getDir('Jajuma_WebpImages') . '/bin/cwebp'
);
}
}
/**
* {@inheritdoc}
*/
public static function getDependencies()
{
return [];
}
/**
* {@inheritdoc}
*/
public function getAliases()
{
return [];
}
}
{
"name": "jajuma/module-webpimages",
"description": "WebP Optimized Images",
"type": "magento2-module",
"license": "MIT",
"version": "2.1.11",
"authors": [
{
"name": "JaJuMa",
"email": "info@jajuma.de"
}
],
"minimum-stability": "dev",
"require": {},
"autoload": {
"psr-4": {
"Jajuma\\WebpImages\\": ""
},
"files": [
"registration.php"
]
}
}
\ No newline at end of file
<?xml version="1.0" ?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Backend::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Jajuma_General::jajuma_extensions" title="JaJuMa Extensions">
<resource id="Jajuma_WebpImages::config_jajuma_webp" title="JaJuMa - WebP Images" sortOrder="500"/>
</resource>
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>
</config>
\ No newline at end of file
<?xml version="1.0"?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Config\Model\Config">
<plugin name="validate_webp_custom_command_before_save" type="Jajuma\WebpImages\Plugin\ConfigPlugin" sortOrder="1"/>
</type>
<type name="Magento\Backend\Model\Menu\Item">
<plugin name="jajumaExtensionsLink" type="Jajuma\WebpImages\Plugin\Backend\Model\Menu\Item\ExtensionsLinkPlugin"/>
</type>
<type name="Magento\Backend\Block\Menu">
<plugin name="jajumaExtensionsLinkJs" type="Jajuma\WebpImages\Plugin\Backend\Block\Menu\AddLinkJs"/>
</type>
</config>
\ No newline at end of file
<?xml version="1.0" ?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2022-present JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd">
<menu>
<update id="Jajuma::top_level_extensions"
module="Jajuma_WebpImages"
resource="Jajuma_General::jajuma_extensions"
sortOrder="65"
title="JaJuMa"/>
<add id="Jajuma_WebpImages::jajuma_webp_images"
title="WebP Optimized Images"
module="Jajuma_WebpImages"
sortOrder="500"
resource="Jajuma_WebpImages::config_jajuma_webp"
parent="Jajuma::top_level_extensions"/>
<add id="Jajuma_WebpImages::jajuma_webp_images_configuration"
title="Configuration"
module="Jajuma_WebpImages"
sortOrder="510"
parent="Jajuma_WebpImages::jajuma_webp_images"
action="admin/system_config/edit/section/webp"
resource="Jajuma_WebpImages::config_jajuma_webp"/>
<update id="Jajuma::extensions"
module="Jajuma_WebpImages"
resource="Jajuma_General::jajuma_extensions"
sortOrder="10000"
parent="Jajuma::top_level_extensions"
title="JaJuMa Extensions"/>
<update id="Jajuma_Extensions::extensions_link"
title="More JaJuMa Extensions" module="Jajuma_WebpImages"
sortOrder="10010"
action="webpimages/extensions"
parent="Jajuma::extensions"
resource="Jajuma_General::jajuma_extensions"/>
</menu>
</config>
\ No newline at end of file
<?xml version="1.0"?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="admin">
<route id="webp" frontName="webp">
<module name="Jajuma_WebpImages" before="Magento_Backend" />
</route>
</router>
</config>
<?xml version="1.0" ?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<tab id="jajuma" sortOrder="400" class="jajuma-tab" translate="label">
<label>Jajuma</label>
</tab>
<section id="webp" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="1" translate="label">
<label>WebP Image Optimization</label>
<tab>jajuma</tab>
<resource>Jajuma_WebpImages::config_jajuma_webp</resource>
<group id="extension_info" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Extension Information</label>
<attribute type="expanded">1</attribute>
<field id="extension_info_text" translate="label comment" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1" type="text">
<frontend_model>Jajuma\WebpImages\Block\System\Config\Form\Jajuma\Module</frontend_model>
<comment><![CDATA[
<div style="margin:auto;padding:10px;background-color:#f1f1f1;display:inline-block;width:97%;">
<div class="box-img" style="width: 20%;float: left;">
<a href="https://www.jajuma.de/en" title="Magento 2 WebP Optimized Images Extension" target="_blank">
<div class="jajuma-extlogo"></div>
</a>
<strong style="font-size: 10px;">Copyright ©
<script>var today = new Date();
document.write(today.getFullYear());</script>
<a href="https://www.jajuma.de/en" target="_blank">www.jajuma.de</a>
</strong>
<div style="margin-top: 5px;">
<a href="https://www.jajuma.de/en/jajuma-shop/online-shop-with-magento-2-and-hyva-themes" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 400 400"
class="w-10 h-10" width="25" height="25" style="position: relative;top: 5px;">
<rect width="400" height="400" fill="#F6F7FF"></rect>
<path d="M222.131 112.458L237.41 66.8783H290.403L275.043 112.458H222.131Z" fill="#14FFAF"></path>
<path fill-rule="evenodd" clip-rule="evenodd" d="M158.026 174.716C172.966 162.84 191.165
155.37 211.659 155.37C253.609 155.37 294.409 182.196 294.409
250.953V336H240.776V250.953C240.776 215.516 223.929 202.107 200.933 202.107C181.969
202.107 168.181 213.026 160.516 224.517V336H106.692V115.336H74L91.2077
64H158.026V174.716ZM272.988 109.567L286.407 69.7565H239.485L226.132
109.567H272.988ZM235.338 64H294.409L277.112 115.336H218.13L235.338 64Z"
fill="#0A23B9"></path>
</svg>
<span style="font-size: 16px;font-weight: 900;"> Theme Compatible</span>
</a>
</div>
</div>
<div style="width: 77%;float: left;padding-left: 3%;">
<div class="name" style="font-size: 16px;">
<b>Magento 2 WebP Optimized Images</b> by <a href="https://www.jajuma.de/en" target="_blank"><b>JaJuMa</b></a>
<div class="jajuma-minilogo"></div>
</div>
<hr>
<br>
<div class="more"><b>More Information About This Extension:</b>
<br>
<div><a href="https://www.jajuma.de/en/jajuma-develop/extensions/webp-optimized-images-extension-for-magento-2"
target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor"
viewBox="0 0 576 512" class="w-10 h-10" width="15" height="15"
style="position: relative;top: 2px;">
<!--! Font Awesome Free 6.0.0 by @fontawesome - https://fontawesome.com License -
https://fontawesome.com/license/free (Icons: CC BY 4.0,
Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. -->
<path d="M575.8 255.5C575.8 273.5 560.8 287.6 543.8 287.6H511.8L512.5 447.7C512.5
450.5 512.3 453.1 512 455.8V472C512 494.1 494.1 512 472 512H456C454.9 512 453.8
511.1 452.7 511.9C451.3 511.1 449.9 512 448.5 512H392C369.9 512 352 494.1 352
472V384C352 366.3 337.7 352 320 352H256C238.3 352 224 366.3 224 384V472C224 494.1
206.1 512 184 512H128.1C126.6 512 125.1 511.9 123.6 511.8C122.4 511.9 121.2 512 120
512H104C81.91 512 64 494.1 64 472V360C64 359.1 64.03 358.1 64.09 357.2V287.6H32.05C14.02
287.6 0 273.5 0 255.5C0 246.5 3.004 238.5 10.01 231.5L266.4 8.016C273.4 1.002 281.4 0
288.4 0C295.4 0 303.4 2.004 309.5 7.014L564.8 231.5C572.8 238.5 576.9 246.5 575.8
255.5L575.8 255.5z"></path></svg> Website</a> |
<a href="https://www.jajuma.de/sites/default/files/ckfinder/userfiles/images/jajuma-develop/webp-optimized-images-magento/JaJuMa_WebP_Optimized_Images_Manual_v003.pdf"
target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor"
viewBox="0 0 448 512" class="w-10 h-10" width="15" height="15"
style="top: 2px;position: relative;">
<!--! Font Awesome Free 6.0.0 by @fontawesome - https://fontawesome.com License -
https://fontawesome.com/license/free (Icons: CC BY 4.0,
Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. -->
<path d="M448 336v-288C448 21.49 426.5 0 400 0H96C42.98 0 0 42.98 0 96v320c0 53.02
42.98 96 96 96h320c17.67 0 32-14.33 32-31.1c0-11.72-6.607-21.52-16-27.1v-81.36C441.8
362.8 448 350.2 448 336zM143.1 128h192C344.8 128 352 135.2 352 144C352 152.8 344.8 160
336 160H143.1C135.2 160 128 152.8 128 144C128 135.2 135.2 128 143.1 128zM143.1
192h192C344.8 192 352 199.2 352 208C352 216.8 344.8 224 336 224H143.1C135.2 224 128
216.8 128 208C128 199.2 135.2 192 143.1 192zM384 448H96c-17.67 0-32-14.33-32-32c0-17.67
14.33-32 32-32h288V448z"></path></svg> Manual</a> |
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/webp-optimized-images-extension-for-magento-2/webp-images-faq"
target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor"
viewBox="0 0 512 512" class="w-10 h-10" width="15" height="15"
style="position: relative;top: 2px;">
<!--! Font Awesome Free 6.0.0 by @fontawesome - https://fontawesome.com License -
https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1,
Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M256 0C114.6 0 0 114.6 0
256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 464c-114.7
0-208-93.31-208-208S141.3 48 256 48s208 93.31 208 208S370.7 464 256 464zM256 336c-18
0-32 14-32 32s13.1 32 32 32c17.1 0 32-14 32-32S273.1 336 256 336zM289.1 128h-51.1C199
128 168 159 168 198c0 13 11 24 24 24s24-11 24-24C216 186 225.1 176 237.1 176h51.1C301.1
176 312 186 312 198c0 8-4 14.1-11 18.1L244 251C236 256 232 264 232 272V288c0 13 11 24
24 24S280 301 280 288V286l45.1-28c21-13 34-36 34-60C360 159 329 128 289.1 128z"></path>
</svg> FAQ</a> |
<a href="https://demo.extension.jajuma.de/"
target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor"
viewBox="0 0 512 512" class="w-10 h-10" width="15" height="15"
style="position: relative;top: 2px;"><!--! Font Awesome Free 6.0.0 by @fontawesome -
https://fontawesome.com License - https://fontawesome.com/license/free
(Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons,
Inc. --><path d="M500.3 443.7l-119.7-119.7c27.22-40.41 40.65-90.9 33.46-144.7C401.8
87.79 326.8 13.32 235.2 1.723C99.01-15.51-15.51 99.01 1.724 235.2c11.6 91.64 86.08
166.7 177.6 178.9c53.8 7.189 104.3-6.236 144.7-33.46l119.7 119.7c15.62 15.62 40.95
15.62 56.57 0C515.9 484.7 515.9 459.3 500.3 443.7zM79.1 208c0-70.58 57.42-128
128-128s128 57.42 128 128c0 70.58-57.42 128-128 128S79.1 278.6 79.1 208z">
</path></svg> Luma Demo</a> |
<a href="https://hyva.extension.jajuma.de/"
target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor"
viewBox="0 0 400 400" class="w-10 h-10" width="20" height="20" style="position:
relative;top: 5px;"> <rect fill="#fff"></rect> <path d="M222.131 112.458L237.41
66.8783H290.403L275.043 112.458H222.131Z"></path> <path fill-rule="evenodd"
clip-rule="evenodd" d="M158.026 174.716C172.966 162.84 191.165 155.37 211.659
155.37C253.609 155.37 294.409 182.196 294.409 250.953V336H240.776V250.953C240.776
215.516 223.929 202.107 200.933 202.107C181.969 202.107 168.181 213.026 160.516
224.517V336H106.692V115.336H74L91.2077 64H158.026V174.716ZM272.988 109.567L286.407
69.7565H239.485L226.132 109.567H272.988ZM235.338 64H294.409L277.112
115.336H218.13L235.338 64Z"></path></svg> Hyvä Theme Demo</a>
<div style="float: right;">Installed Version: <b>2.1.11</b></div>
</div>
</div>
<hr>
<div class="info"><b>Discover More Ideas To Improve Your Store:</b>
<div class="more-ideas-list">
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/ultimate-image-optimizer-extension-for-magento-2"
target="_blank">Ultimate Image Optimizer</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/shariff-social-share-buttons-extension-for-magento-2"
target="_blank">Shariff Social Share Buttons</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/prg-pattern-link-masking-for-magento-2"
target="_blank">PRG Pattern Link Masking</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/video-widget-gdpr-extension-for-magento-2"
target="_blank">Video Widget</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/page-preload-extension-for-magento-2"
target="_blank">Page Preload</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/matomo-analytics-extension-for-magento-2"
target="_blank">Matomo Analytics</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/honey-spam-anti-spam-extension-for-magento-2"
target="_blank">Honey Spam Anti-Spam</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/customer-registration-reminder-and-cleanup-extension-for-magento-2"
target="_blank">Customer Registration Reminder & Cleanup</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/category-grid-callouts-extension-for-magento-2"
target="_blank">Category Grid Callouts</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/customer-satisfaction-feedback-extension-for-magento-2"
target="_blank">Customer Satisfaction Feedback</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/customer-navigation-manager-extension-for-magento-2"
target="_blank"><b>Free:</b> Customer Navigation Manager</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/font-awesome-icons-for-hyva-themes-extension"
target="_blank"><b>Free:</b> Awesome Hyvä</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/dynamic-shipping-tax-extension-for-magento-2"
target="_blank"><b>Free:</b> Dynamic Shipping Tax</a>
<a href="https://www.jajuma.de/en/jajuma-develop/extensions/hyva-faq-widget-extension-for-hyva-themes"
target="_blank"><b>Free:</b> Hyvä FAQ Widget</a>
</div>
</div>
<hr>
</div>
</div>
]]></comment>
</field>
</group>
<group id="setting" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="10" translate="label">
<label>General Configuration</label>
<field id="enable" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="10" translate="label" type="select">
<label>Optimize Image</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="check_transparency" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="15" translate="label" type="select">
<label>Disable with transparent images</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="clear_cache_webp" translate="label comment" type="button" sortOrder="1000" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Clear Webp Image</label>
<comment><![CDATA[This button will clear all the generated webp images.]]></comment>
<frontend_model>Jajuma\WebpImages\Block\Adminhtml\System\Config\ClearButton</frontend_model>
</field>
</group>
<group id="advance_mode" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="20" translate="label">
<label>Conversion Configuration</label>
<field id="convert_tool" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="20" translate="label" type="select">
<label>Conversion Tool</label>
<comment>Select the tool to be used for WebP image conversion</comment>
<source_model>Jajuma\WebpImages\Model\Config\Source\Tool</source_model>
</field>
<field id="path_to_cwebp" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="20" translate="label" type="text">
<label>Path to cwebp</label>
<validate>validate-cwebp-path</validate>
<comment><model>Jajuma\WebpImages\Model\Config\Comment</model></comment>
<depends>
<field id="convert_tool">cwebp</field>
</depends>
</field>
<field id="path_to_imagemagick" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="20" translate="label" type="text">
<label>Path to imagemagick</label>
<validate>validate-imagemagick-path</validate>
<comment>Define the path of imagemagick command or leave it empty to use global command "convert". Example: "/usr/local/bin/convert"</comment>
<depends>
<field id="convert_tool">convert</field>
</depends>
</field>
<field id="quality" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="30" translate="label" type="text">
<label>WebP Quality</label>
<validate>validate-number validate-zero-or-greater validate-digits</validate>
<comment>Define the compression factor applied for webp conversion (from 0 to 100)</comment>
</field>
<field id="cwebp_command" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="100" translate="label" type="text">
<label>Cwebp Custom Command</label>
<validate>validate-cwebp-command</validate>
<comment><![CDATA[Example command: -alpha_q 100 -z 9 -m 6 -segments 4 -sns 80 -f 25 -sharpness 0 -strong -pass 10 -mt -alpha_method 1 -alpha_filter fast -o]]></comment>
<depends>
<field id="convert_tool">cwebp</field>
</depends>
</field>
<field id="imagemagick_command" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="200" translate="label" type="text">
<label>Imagemagick Custom Command</label>
<validate>validate-imagemagick-command</validate>
<comment><![CDATA[Example command: -quality 100 -define webp:lossless=true,method=6]]></comment>
<depends>
<field id="convert_tool">convert</field>
</depends>
</field>
<field id="test_button" translate="label comment" type="button" sortOrder="1000" showInDefault="1" showInWebsite="1" showInStore="1">
<frontend_model>Jajuma\WebpImages\Block\Adminhtml\System\Config\TestButton</frontend_model>
</field>
</group>
<group id="native_lazy" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="30" translate="label">
<label>Native Lazy Loading</label>
<field id="enable_native_lazy" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="10" translate="label" type="select">
<label>Enable Native Lazy Loading</label>
<comment><![CDATA[If enabled, ' loading="lazy" ' will be added for images converted.]]></comment>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="exclude_native_lazy" translate="label comment" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="1" type="text">
<label>Native Lazy Loading Blacklist</label>
<comment><![CDATA[<span><b>Exclude images from Native Lazy Loading</b> by a list of comma separated strings (or RegEx).<br>
If the img tag match with any of the strings above, the ' loading="lazy" ' won't be added to that img tag.</span>]]></comment>
</field>
</group>
<group id="professional_mode" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="40" translate="label">
<label>Advanced Configuration</label>
<field id="message" translate="label comment" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1" type="text">
<frontend_model>Jajuma\WebpImages\Block\Adminhtml\System\Config\AdvancedConfiguration</frontend_model>
<comment><![CDATA[
<div class="messages">
<div class="message message-warning message-demo-mode">
<b>Note: </b><br><span>For most sites following configs are not needed.<br>
Please use only after checking the manual <a href="https://www.jajuma.de/en/jajuma-develop/extensions/webp-optimized-images-extension-for-magento-2" target="_blank">(Link)</a> and understand what you are doing.
</span> </div>
</div>
]]></comment>
</field>
<field id="exclude_img" translate="label comment" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="1" type="text">
<label>Blacklist</label>
<comment><![CDATA[<span><b>Exclude images</b> from WebP Conversion by a list of comma separated strings (or RegEx).<br>
If the img tag match with any of the strings above, that img tag won't be converted.<br>
Note: img-tags with <i>data-nowebp="true"</i> are excluded from conversion by default.</span>]]></comment>
</field>
<field id="src_tag" translate="label comment" sortOrder="200" showInDefault="1" showInWebsite="1" showInStore="1" type="text">
<label>Custom src-tag</label>
<comment><![CDATA[<span>By default we look at the <b>src</b> attribute to get the image URL and use this for WebP conversion.<br>
If you use some custom attribute for img URL, e. g. in case you are using lazyload on your site, you can use this config to have this converted first.<br>
Example: If your lazyload function uses <b>data-src</b>, just input <i>data-src</i> into this config.<br>
For img tags having a data-src we will then use the data-src image URL for WebP conversion.<br>
For img tags having no data-src, we will still use src attribute for conversion.
</span>]]></comment>
</field>
<field id="srcset_tag" translate="label comment" sortOrder="300" showInDefault="1" showInWebsite="1" showInStore="1" type="text">
<label>Custom srcset-tag</label>
<comment><![CDATA[<span>By default we add picture tags using <b>srcset</b> tags.<br>
You can use this config to change this behaviour, e. g. in case you are using lazyload on your site.<br>
Example: If your lazyload function uses <b>data-srcset</b>, just input <i>data-srcset</i> into this config.<br>
The extension will then add picture tags using data-srcset.<br>
!!! Please ensure your lazyload script does support lazyloading for picture-tags !!!
</span>]]></comment>
</field>
</group>
</section>
</system>
</config>
\ No newline at end of file
<?xml version="1.0" ?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<webp>
<setting>
<enable>1</enable>
<quality>75</quality>
</setting>
</webp>
</default>
</config>
\ No newline at end of file
<?xml version="1.0"?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Block\Product\View\Gallery">
<plugin name="jajuma-webpimages-product-view-gallery" type="Jajuma\WebpImages\Plugin\Product\View\GalleryPlugin" sortOrder="5"/>
</type>
<type name="Magento\Framework\View\LayoutInterface">
<plugin name="jajuma-webpimages-replace-image-tag" type="Jajuma\WebpImages\Plugin\ReplaceImageTag"/>
</type>
</config>
\ No newline at end of file
<?xml version="1.0"?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd">
<router id="standard">
<route id="webp" frontName="webp">
<module name="Jajuma_WebpImages" />
</route>
</router>
</config>
\ No newline at end of file
<?xml version="1.0" ?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Jajuma_WebpImages" setup_version="2.1.4"/>
</config>
<?php declare(strict_types = 1);
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Jajuma_WebpImages',
__DIR__
);
<?xml version="1.0"?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="header">
<block class="Magento\Backend\Block\Template" template="Jajuma_WebpImages::system/config/js.phtml"/>
</referenceContainer>
</body>
</page>
\ No newline at end of file
<?xml version="1.0"?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<css src="Jajuma_WebpImages::css/main.css"/>
</head>
</page>
<?xml version="1.0"?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<css src="Jajuma_WebpImages::css/twentytwenty.css"/>
</head>
<body>
<referenceContainer name="header" remove="true"/>
<referenceContainer name="page.menu" remove="true"/>
<referenceContainer name="page.breadcrumbs" remove="true"/>
<referenceContainer name="footer" remove="true"/>
<referenceContainer name="content">
<block class="Jajuma\WebpImages\Block\Adminhtml\ConversionTool\Test\Result" name="conversion.tool.test.result" template="Jajuma_WebpImages::conversion_tool/test/result.phtml"/>
</referenceContainer>
</body>
</page>
var config = {
paths: {
'twentytwenty': 'Jajuma_WebpImages/js/lib/jquery.twentytwenty',
'eventmove': 'Jajuma_WebpImages/js/lib/jquery.event.move',
},
shim: {
'twentytwenty': {
deps: ['jquery', 'eventmove']
}
}
};
\ No newline at end of file
<script>
require([
'jquery'
], function ($) {
$(document).ready(function () {
$('a[href*="https://www.jajuma.de"]').attr('target', '_blank');
});
});
</script>
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
?>
<style>
body .menu-wrapper {
display: none;
}
.webp-container-compare {
max-width: 700px;
margin: 0 auto;
}
body {
background: #ffffff;
}
</style>
<?php
/**
* @var $block \Jajuma\WebpImages\Block\Adminhtml\ConversionTool\Test\Result
*/
$result = $block->convert();
if (is_array($result)):
?>
<script type="text/javascript">
require([
'jquery',
'twentytwenty',
], function () {
jQuery(document).ready(function() {
jQuery("#compare-image").twentytwenty({
default_offset_pct: 0.5,
orientation: 'horizontal',
before_label: 'ORIGINAL',
after_label: 'WEBP',
no_overlay: false,
move_slider_on_hover: false,
move_with_handle_only: true,
click_to_move: false
});
});
});
</script>
<div id="test-success-message">
<div class="messages">
<div class="message message-success success">
<div data-ui-id="messages-message-success">
<p><?= /* @noEscape */ __('Success!') ?></p>
<p><?= /* @noEscape */ __('Selected conversion tool works.') ?></p>
<p><?= /* @noEscape */__('WebP Image File was created
using configured quality level / custom conversion command.') ?></p>
<p><?= /* @noEscape */ __('See below for comparison Original vs WebP:') ?></p>
</div>
</div>
</div>
</div>
<?php if (strpos($result['original'], 'Jajuma_WebpImages/images/test.png') !== false): ?>
<div id="test-notice-message">
<div class="messages">
<div class="message message-notice notice">
<div data-ui-id="messages-message-notice">
<p><?= /* @noEscape */__('Product ID used for testing
is invalid or that product has no image.<br>') ?>
<?= /* @noEscape */__('Hence, below we can only show some sample image.<br>') ?>
<?= /* @noEscape */ __('Please use another Product ID,
so we can show the conversion result with your own image.') ?></p>
</div>
</div>
</div>
</div>
<?php endif; ?>
<div class="webp-container-compare">
<div id="compare-image" class="twentytwenty-container">
<!-- The before image is first -->
<img src="<?= /* @noEscape */ $result['original'] ?>" />
<!-- The after image is last -->
<picture>
<source srcset="<?= /* @noEscape */ $result['webp'] ?>" type="image/webp">
<img src="<?= /* @noEscape */ $block->getUnsupportWebpImage() ?>" />
</picture>
</div>
</div>
<?php else: ?>
<div id="test-notice-message">
<div class="messages">
<div class="message message-warning">
<div data-ui-id="message message-warning">
<?php if ($message = $block->getError()): ?>
<p><?= /* @noEscape */ $message ?></p>
<?php else: ?>
<p><?= /* @noEscape */ __('Sorry, Image conversion failed.') ?></p>
<p><?= /* @noEscape */__('Seems selected conversion tool is not available on your server.') ?></p>
<p><?= /* @noEscape */ __('Can you please:') ?></p>
<ul style="margin-left:20px;">
<li><?= /* @noEscape */ __('Try another conversion tool') ?></li>
<li><?= /* @noEscape */ __('And/or test with another image') ?></li>
<li><?= /* @noEscape */ __('Check the extension manual
regrading conversion tool requirements') ?></li>
</ul>
<a
href="https://www.jajuma.de/en/jajuma-develop/
extensions/webp-optimized-images-extension-for-magento-2"
target="_blank">
Link To Manual
</a>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
?>
<script type="text/javascript">
require([
'jquery',
'Magento_Ui/js/modal/confirm'
], function ($, confirm) {
window.clearWebpImage = function() {
confirm({
title: '<?= /* @noEscape */__("Clear Image") ?>',
content: '<?= /* @noEscape */__("Do you want to delete all generated webp images") ?>',
actions: {
confirm: function(){ window.location.href = "<?= /* @noEscape */ $block->getAdminUrl() ?>"},
cancel: function(){ return false },
always: function(){ return false }
}
});
}
});
</script>
<?= $block->getButtonHtml() ?>
\ No newline at end of file
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
?>
<script type="text/javascript">
requirejs([
'jquery',
'jquery/ui',
'jquery/validate',
'mage/translate'
], function($){
'use strict';
$.validator.addMethod(
"validate-cwebp-command",
function(value, element) {
return this.optional(element) || <?= \Jajuma\WebpImages\Helper\Data::REGX_CWEBP ?>.test(value);
},
$.mage.__("Incorrect cwebp custom command. Custom Command must only include " +
"underscore (_), minus (-), " +
"space ( ) and alphanumeric characters.")
);
$.validator.addMethod(
"validate-imagemagick-command",
function(value, element) {
return this.optional(element) || <?= \Jajuma\WebpImages\Helper\Data::REGX_IMAGEMAGICK ?>.test(value);
},
$.mage.__("Incorrect ImageMagick custom command. Custom Command must only include " +
"underscore (_), minus (-), space ( ), comma (,), colon (:), " +
"equals sign (=) and alphanumeric characters.")
);
$.validator.addMethod(
"validate-cwebp-path",
function(value, element) {
return this.optional(element) || <?= \Jajuma\WebpImages\Helper\Data::REGX_CWEBP_PATH ?>.test(value);
},
$.mage.__("Incorrect cwebp path. Path must only include " +
"underscore (_), minus (-), dot (.), slash(/) and alphanumeric characters.")
);
$.validator.addMethod(
"validate-imagemagick-path",
function(value, element) {
return this.optional(element)
|| <?= \Jajuma\WebpImages\Helper\Data::REGX_IMAGEMAGICK_PATH ?>.test(value);
},
$.mage.__("Incorrect ImageMagick path. Path must only include " +
"underscore (_), minus (-), dot (.), slash(/) and alphanumeric characters.")
);
});
</script>
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
/**
* @var $block Jajuma\WebpPlus\Block\Adminhtml\System\Config\TestButton
*/
?>
<style>
.test-conversion-tool-wrapper {
display: flex;
}
.test-conversion-tool-wrapper .product-input-wrapper {
margin-left: 10px;
display: flex;
}
.test-conversion-tool-wrapper .product-input-wrapper .product {
width: 80px;
}
.test-conversion-tool-wrapper .product-input-wrapper .tooltip {
line-height: 26px;
}
</style>
<script type="text/javascript">
require([
'jquery',
'Magento_Ui/js/modal/modal',
'Magento_Ui/js/modal/alert'
], function ($, modal, alert) {
window.conversionToolTest = function() {
if (!$.isNumeric($('#webp_advance_mode_quality').val())) {
alert({
title: 'Error',
content: "<?= /* @noEscape */ __('Quality should be a numeric value') ?>",
actions: {
always: function(){}
}
});
return;
}
$('body').trigger('processStart');
$('#iFrame').remove();
let productId = $('.product-input-wrapper .product').val();
let postData = {form_key: FORM_KEY, product: productId};
configForm.find('[id^=webp_advance_mode]').find(':input').serializeArray().map(function(field) {
var name = field.name.match(/groups\[advance_mode\]?(\[groups\]\[debug\])?\[fields\]\[(.*)\]\[value]/);
if(name && name.length === 3){
postData[name[2]] = field.value;
}
});
let options ={
type: 'popup',
title: '<?= /* @noEscape */ __('Test Conversion Tool') ?>',
responsive: true,
innerScroll: false,
buttons: [{
text: $.mage.__('Close'),
class: 'close-modal',
click: function () {
this.closeModal();
}
}]
};
let popup = modal(options, $('#quickViewContainer'));
let modalContainer = $("#quickViewContainer");
let iframe = $('<iframe />', {
id: 'iFrame',
src: "<?= /* @noEscape */ $block->getAdminUrl() ?>?" + $.param( postData, true )
});
modalContainer.html(iframe);
$('#iFrame').on("load", function () {
$('body').trigger('processStop');
modalContainer.addClass("quick-view-image");
modalContainer.modal('openModal');
this.style.height = this.contentWindow.document.body.scrollHeight+ 10 + 'px';
this.style.border = '0';
this.style.width = '100%';
});
}
});
</script>
<div class="test-conversion-tool-wrapper">
<div class="button-wrapper">
<?= $block->getButtonHtml() ?>
</div>
<div class="product-input-wrapper">
<input type="text" name="product_id" class="product" value="<?= /* @noEscape */ $block->getLatestProductId()?>">
<div class="tooltip">
<span class="help"><span></span></span>
<div class="tooltip-content">Fill your product id to test the conversion tool</div>
</div>
</div>
</div>
<div id="quickViewContainer">
</div>
li#menu-jajuma-top-level-extensions > a:before {
background-image: url('data:image/png;base64,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');
background-size: contain;
background-repeat: no-repeat;
margin-bottom: 10px;
content: '';
background-position: center;
filter: brightness(1.7);
opacity: .65;
}
li#menu-jajuma-top-level-extensions:hover > a:before {
opacity: 1;
}
li[class^=item-jajuma] strong.submenu-group-title {
display: block!important;
}
li.item-extensions.parent.level-1 {
border-top: 1px solid #aaa6a0;
}
#menu-jajuma-top-level-extensions .item-extensions-link span:before {
background-image: url(../images/idea.svg);
display: inline-block;
content: '';
width: 25px;
height: 25px;
margin-right: 15px;
vertical-align: middle;
background-size: contain;
background-repeat: no-repeat;
}
#nav li#menu-jajuma-top-level-extensions .submenu .submenu-title {
background-image: url('data:image/png;base64,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');
background-size: contain;
background-repeat: no-repeat;
height: 55px;
font-size: 0px;
margin-bottom: 15px;
filter: brightness(1.3);
}
li.item-jajuma-webp-images.parent.level-1 {
min-width: 280px;
}
.config-nav-block.jajuma-tab strong:before, .admin__menu [data-ui-id^=menu-jajuma-].item-jajuma-webp-images.parent.level-1 .submenu-group-title span:before {
background-image: url(../images/images.svg);
display: inline-block;
content: '';
width: 30px;
height: 30px;
margin-right: 15px;
vertical-align: middle;
background-size: contain;
background-repeat: no-repeat;
position: relative;
top: -2px;
}
.config-nav-block.jajuma-tab strong:before, .admin__menu [data-ui-id^=menu-jajuma-] .submenu-group-title span:before {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAAH5FsI7AAAACXBIWXMAAAsTAAALEwEAmpwYAABhJWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMwMTQgNzkuMTU2Nzk3LCAyMDE0LzA4LzIwLTA5OjUzOjAyICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgICAgICAgICAgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICAgICAgICAgIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgICAgICAgICB4bWxuczppbGx1c3RyYXRvcj0iaHR0cDovL25zLmFkb2JlLmNvbS9pbGx1c3RyYXRvci8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBUUGc9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC90L3BnLyIKICAgICAgICAgICAgeG1sbnM6c3REaW09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9EaW1lbnNpb25zIyIKICAgICAgICAgICAgeG1sbnM6eG1wRz0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL2cvIgogICAgICAgICAgICB4bWxuczpwZGY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGRmLzEuMy8iCiAgICAgICAgICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9wbmc8L2RjOmZvcm1hdD4KICAgICAgICAgPGRjOnRpdGxlPgogICAgICAgICAgICA8cmRmOkFsdD4KICAgICAgICAgICAgICAgPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ij5EcnVjazwvcmRmOmxpPgogICAgICAgICAgICA8L3JkZjpBbHQ+CiAgICAgICAgIDwvZGM6dGl0bGU+CiAgICAgICAgIDx4bXA6TWV0YWRhdGFEYXRlPjIwMTgtMDgtMTVUMTU6NDQ6NDgrMDI6MDA8L3htcDpNZXRhZGF0YURhdGU+CiAgICAgICAgIDx4bXA6TW9kaWZ5RGF0ZT4yMDE4LTA4LTE1VDE1OjQ0OjQ4KzAyOjAwPC94bXA6TW9kaWZ5RGF0ZT4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTQtMDMtMThUMTg6MjE6NTUrMDE6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOkNyZWF0b3JUb29sPkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE0IChXaW5kb3dzKTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8eG1wTU06SW5zdGFuY2VJRD54bXAuaWlkOmI4MDlmMGY4LWJiMWYtNzM0OS04ZGYxLTg5ODBmYmMzOTAxZjwveG1wTU06SW5zdGFuY2VJRD4KICAgICAgICAgPHhtcE1NOkRvY3VtZW50SUQ+YWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjUxYzAzNjBiLWEwOTEtMTFlOC04ZDlhLWU1ZGE1ZDQyZjY5ZjwveG1wTU06RG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD51dWlkOjVEMjA4OTI0OTNCRkRCMTE5MTRBODU5MEQzMTUwOEM4PC94bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpSZW5kaXRpb25DbGFzcz5wcm9vZjpwZGY8L3htcE1NOlJlbmRpdGlvbkNsYXNzPgogICAgICAgICA8eG1wTU06RGVyaXZlZEZyb20gcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICA8c3RSZWY6aW5zdGFuY2VJRD54bXAuaWlkOjlmZTY5OTI3LTRjMGUtNmI0MC05NTA0LWMxZTk2NTA3ODA5Njwvc3RSZWY6aW5zdGFuY2VJRD4KICAgICAgICAgICAgPHN0UmVmOmRvY3VtZW50SUQ+eG1wLmRpZDo5ZmU2OTkyNy00YzBlLTZiNDAtOTUwNC1jMWU5NjUwNzgwOTY8L3N0UmVmOmRvY3VtZW50SUQ+CiAgICAgICAgICAgIDxzdFJlZjpvcmlnaW5hbERvY3VtZW50SUQ+dXVpZDo1RDIwODkyNDkzQkZEQjExOTE0QTg1OTBEMzE1MDhDODwvc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPgogICAgICAgICAgICA8c3RSZWY6cmVuZGl0aW9uQ2xhc3M+cHJvb2Y6cGRmPC9zdFJlZjpyZW5kaXRpb25DbGFzcz4KICAgICAgICAgPC94bXBNTTpEZXJpdmVkRnJvbT4KICAgICAgICAgPHhtcE1NOkhpc3Rvcnk+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOjAyODAxMTc0MDcyMDY4MTE4QzE0ODlBRUFGMzU2MUFEPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDEzLTEyLTA5VDE5OjIxOjMxKzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkY3N0YxMTc0MDcyMDY4MTE4MDgzRDBGM0M4OTJGRDY0PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDEzLTEyLTMwVDE4OjQ0OjA4KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkY4N0YxMTc0MDcyMDY4MTE4MDgzRDBGM0M4OTJGRDY0PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDEzLTEyLTMwVDE5OjE0OjQ3KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkY3N0YxMTc0MDcyMDY4MTE4QzE0RjRBQjAzREM1NzAwPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTAzLTA4VDIyOjEwOjM4KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkY4N0YxMTc0MDcyMDY4MTE4QzE0RjRBQjAzREM1NzAwPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTAzLTA4VDIyOjI5OjE3KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkY4N0YxMTc0MDcyMDY4MTE4QzE0Rjc1RTg2RDIyNUM5PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTAzLTE4VDE3OjMwOjQ2KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkY5N0YxMTc0MDcyMDY4MTE4QzE0Rjc1RTg2RDIyNUM5PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTAzLTE4VDE3OjUxOjU0KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkZCN0YxMTc0MDcyMDY4MTE4QzE0Rjc1RTg2RDIyNUM5PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTAzLTE4VDE3OjUzOjI4KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkZDN0YxMTc0MDcyMDY4MTE4QzE0Rjc1RTg2RDIyNUM5PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTAzLTE4VDE3OjUzOjQ5KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkZEN0YxMTc0MDcyMDY4MTE4QzE0Rjc1RTg2RDIyNUM5PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTAzLTE4VDE4OjIxOjM3KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOkZFN0YxMTc0MDcyMDY4MTE4QzE0Rjc1RTg2RDIyNUM5PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE0LTAzLTE4VDE4OjIxOjU2KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBJbGx1c3RyYXRvciBDUzU8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jb252ZXJ0ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnBhcmFtZXRlcnM+ZnJvbSBhcHBsaWNhdGlvbi9wb3N0c2NyaXB0IHRvIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5pbGx1c3RyYXRvcjwvc3RFdnQ6cGFyYW1ldGVycz4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNvbnZlcnRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6cGFyYW1ldGVycz5mcm9tIGFwcGxpY2F0aW9uL3Bvc3RzY3JpcHQgdG8gYXBwbGljYXRpb24vdm5kLmFkb2JlLmlsbHVzdHJhdG9yPC9zdEV2dDpwYXJhbWV0ZXJzPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+Y29udmVydGVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpwYXJhbWV0ZXJzPmZyb20gYXBwbGljYXRpb24vcG9zdHNjcmlwdCB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wPC9zdEV2dDpwYXJhbWV0ZXJzPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDo5ZmU2OTkyNy00YzBlLTZiNDAtOTUwNC1jMWU5NjUwNzgwOTY8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTctMDEtMDNUMTA6NTM6NDkrMDE6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE0IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNvbnZlcnRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6cGFyYW1ldGVycz5mcm9tIGFwcGxpY2F0aW9uL3Bvc3RzY3JpcHQgdG8gaW1hZ2UvcG5nPC9zdEV2dDpwYXJhbWV0ZXJzPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+ZGVyaXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6cGFyYW1ldGVycz5jb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZzwvc3RFdnQ6cGFyYW1ldGVycz4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6OGY5NTdiZTctZDI3ZC1jNjQwLTllYTItYWFlZjcwZTNhNDgyPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE3LTAxLTAzVDEwOjUzOjQ5KzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoV2luZG93cyk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOmI4MDlmMGY4LWJiMWYtNzM0OS04ZGYxLTg5ODBmYmMzOTAxZjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxOC0wOC0xNVQxNTo0NDo0OCswMjowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICAgICA8c3RFdnQ6Y2hhbmdlZD4vPC9zdEV2dDpjaGFuZ2VkPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICA8L3htcE1NOkhpc3Rvcnk+CiAgICAgICAgIDxpbGx1c3RyYXRvcjpTdGFydHVwUHJvZmlsZT5QcmludDwvaWxsdXN0cmF0b3I6U3RhcnR1cFByb2ZpbGU+CiAgICAgICAgIDx4bXBUUGc6SGFzVmlzaWJsZU92ZXJwcmludD5GYWxzZTwveG1wVFBnOkhhc1Zpc2libGVPdmVycHJpbnQ+CiAgICAgICAgIDx4bXBUUGc6SGFzVmlzaWJsZVRyYW5zcGFyZW5jeT5UcnVlPC94bXBUUGc6SGFzVmlzaWJsZVRyYW5zcGFyZW5jeT4KICAgICAgICAgPHhtcFRQZzpOUGFnZXM+MTwveG1wVFBnOk5QYWdlcz4KICAgICAgICAgPHhtcFRQZzpNYXhQYWdlU2l6ZSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdERpbTp3PjEyMC4wMDAwODM8L3N0RGltOnc+CiAgICAgICAgICAgIDxzdERpbTpoPjUwLjAwMDA0OTwvc3REaW06aD4KICAgICAgICAgICAgPHN0RGltOnVuaXQ+TWlsbGltZXRlcnM8L3N0RGltOnVuaXQ+CiAgICAgICAgIDwveG1wVFBnOk1heFBhZ2VTaXplPgogICAgICAgICA8eG1wVFBnOlBsYXRlTmFtZXM+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpPkN5YW48L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaT5NYWdlbnRhPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGk+WWVsbG93PC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGk+QmxhY2s8L3JkZjpsaT4KICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICA8L3htcFRQZzpQbGF0ZU5hbWVzPgogICAgICAgICA8eG1wVFBnOlN3YXRjaEdyb3Vwcz4KICAgICAgICAgICAgPHJkZjpTZXE+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8eG1wRzpncm91cE5hbWU+U3RhbmRhcmQtRmFyYmZlbGRncnVwcGU8L3htcEc6Z3JvdXBOYW1lPgogICAgICAgICAgICAgICAgICA8eG1wRzpncm91cFR5cGU+MDwveG1wRzpncm91cFR5cGU+CiAgICAgICAgICAgICAgICAgIDx4bXBHOkNvbG9yYW50cz4KICAgICAgICAgICAgICAgICAgICAgPHJkZjpTZXE+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8eG1wRzpzd2F0Y2hOYW1lPldlacOfPC94bXBHOnN3YXRjaE5hbWU+CiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4bXBHOm1vZGU+UkdCPC94bXBHOm1vZGU+CiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4bXBHOnR5cGU+UFJPQ0VTUzwveG1wRzp0eXBlPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8eG1wRzpyZWQ+MjU1PC94bXBHOnJlZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhtcEc6Z3JlZW4+MjU1PC94bXBHOmdyZWVuPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8eG1wRzpibHVlPjI1NTwveG1wRzpibHVlPgogICAgICAgICAgICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4bXBHOnN3YXRjaE5hbWU+U2Nod2FyejwveG1wRzpzd2F0Y2hOYW1lPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8eG1wRzptb2RlPlJHQjwveG1wRzptb2RlPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8eG1wRzp0eXBlPlBST0NFU1M8L3htcEc6dHlwZT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhtcEc6cmVkPjI2PC94bXBHOnJlZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhtcEc6Z3JlZW4+MjM8L3htcEc6Z3JlZW4+CiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4bXBHOmJsdWU+Mjc8L3htcEc6Ymx1ZT4KICAgICAgICAgICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8eG1wRzpzd2F0Y2hOYW1lPlI9MCBHPTE1OCBCPTIyNDwveG1wRzpzd2F0Y2hOYW1lPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8eG1wRzp0eXBlPlBST0NFU1M8L3htcEc6dHlwZT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhtcEc6dGludD4xMDAuMDAwMDAwPC94bXBHOnRpbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4bXBHOm1vZGU+UkdCPC94bXBHOm1vZGU+CiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4bXBHOnJlZD4wPC94bXBHOnJlZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhtcEc6Z3JlZW4+MTU4PC94bXBHOmdyZWVuPgogICAgICAgICAgICAgICAgICAgICAgICAgICA8eG1wRzpibHVlPjIyNDwveG1wRzpibHVlPgogICAgICAgICAgICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICAgICAgICAgICA8L3htcEc6Q29sb3JhbnRzPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICA8L3htcFRQZzpTd2F0Y2hHcm91cHM+CiAgICAgICAgIDxwZGY6UHJvZHVjZXI+QWRvYmUgUERGIGxpYnJhcnkgOS45MDwvcGRmOlByb2R1Y2VyPgogICAgICAgICA8cGhvdG9zaG9wOkNvbG9yTW9kZT4zPC9waG90b3Nob3A6Q29sb3JNb2RlPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+ODA8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+ODA8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PqVjY/YAAAAgY0hSTQAAeicAAICDAAD6ZAAAgNIAAHaGAADs6QAAOZ4AABX+xn7TOgAAKrtJREFUeNpUkD8oxAEcxT/vy6YrRXeDxYpRV6cok/EGtrtipK5uZUInyXS5xeBfZLTc2Sw2xWVz6iZKSilyCr/u3Nfw+x0ZXr33/b76vu8zSY8yNWRqSBE63OyXGyKGE4MIHa1IRzvDQRI4AKSSKQZ26qH2aCgwgP7KF8untwympqiclvl8qOHuxOY2qVavaQYB5u4U304opEe4vzwjnkjwWphGEu+HiySTo3TP72KSyGYzeLvNcGaJLvdOCkpbJSYXVtBBLjwtM8yM2vEGrfwePcUrho7qjI1P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') no-repeat center;
width: 30px;
height: 30px;
content: '';
display: inline-block;
margin-right: 15px;
vertical-align: middle;
background-size: contain;
}
#webp_extension_info .jajuma-extlogo {
background-image: url('data:image/png;base64,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');
width: 185px;
height: 185px;
background-size: cover;
}
.jajuma-minilogo {
background-image: url('data:image/png;base64,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');
width: 75px;
height: 25px;
background-size: cover;
margin-left: 10px;
float: right;
}
.more-ideas-list {
display: flex;
flex-wrap: wrap;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-gap: 3px;
}
.twentytwenty-horizontal .twentytwenty-handle:before, .twentytwenty-horizontal .twentytwenty-handle:after, .twentytwenty-vertical .twentytwenty-handle:before, .twentytwenty-vertical .twentytwenty-handle:after {
content: " ";
display: block;
background: white;
position: absolute;
z-index: 30;
-webkit-box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
-moz-box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5); }
.twentytwenty-horizontal .twentytwenty-handle:before, .twentytwenty-horizontal .twentytwenty-handle:after {
width: 3px;
height: 9999px;
left: 50%;
margin-left: -1.5px; }
.twentytwenty-vertical .twentytwenty-handle:before, .twentytwenty-vertical .twentytwenty-handle:after {
width: 9999px;
height: 3px;
top: 50%;
margin-top: -1.5px; }
.twentytwenty-before-label, .twentytwenty-after-label, .twentytwenty-overlay {
position: absolute;
top: 0;
width: 100%;
height: 100%; }
.twentytwenty-before-label, .twentytwenty-after-label, .twentytwenty-overlay {
-webkit-transition-duration: 0.5s;
-moz-transition-duration: 0.5s;
transition-duration: 0.5s; }
.twentytwenty-before-label, .twentytwenty-after-label {
-webkit-transition-property: opacity;
-moz-transition-property: opacity;
transition-property: opacity; }
.twentytwenty-before-label:before, .twentytwenty-after-label:before {
color: white;
font-size: 13px;
letter-spacing: 0.1em; }
.twentytwenty-before-label:before, .twentytwenty-after-label:before {
position: absolute;
background: rgba(255, 255, 255, 0.2);
line-height: 38px;
padding: 0 20px;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px; }
.twentytwenty-horizontal .twentytwenty-before-label:before, .twentytwenty-horizontal .twentytwenty-after-label:before {
top: 50%;
margin-top: -19px; }
.twentytwenty-vertical .twentytwenty-before-label:before, .twentytwenty-vertical .twentytwenty-after-label:before {
left: 50%;
margin-left: -45px;
text-align: center;
width: 90px; }
.twentytwenty-left-arrow, .twentytwenty-right-arrow, .twentytwenty-up-arrow, .twentytwenty-down-arrow {
width: 0;
height: 0;
border: 6px inset transparent;
position: absolute; }
.twentytwenty-left-arrow, .twentytwenty-right-arrow {
top: 50%;
margin-top: -6px; }
.twentytwenty-up-arrow, .twentytwenty-down-arrow {
left: 50%;
margin-left: -6px; }
.twentytwenty-container {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
z-index: 0;
overflow: hidden;
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none; }
.twentytwenty-container img {
max-width: 100%;
position: absolute;
top: 0;
display: block; }
.twentytwenty-container.active .twentytwenty-overlay, .twentytwenty-container.active :hover.twentytwenty-overlay {
background: rgba(0, 0, 0, 0); }
.twentytwenty-container.active .twentytwenty-overlay .twentytwenty-before-label,
.twentytwenty-container.active .twentytwenty-overlay .twentytwenty-after-label, .twentytwenty-container.active :hover.twentytwenty-overlay .twentytwenty-before-label,
.twentytwenty-container.active :hover.twentytwenty-overlay .twentytwenty-after-label {
opacity: 0; }
.twentytwenty-container * {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box; }
.twentytwenty-before-label {
opacity: 0; }
.twentytwenty-before-label:before {
content: attr(data-content); }
.twentytwenty-after-label {
opacity: 0; }
.twentytwenty-after-label:before {
content: attr(data-content); }
.twentytwenty-horizontal .twentytwenty-before-label:before {
left: 10px; }
.twentytwenty-horizontal .twentytwenty-after-label:before {
right: 10px; }
.twentytwenty-vertical .twentytwenty-before-label:before {
top: 10px; }
.twentytwenty-vertical .twentytwenty-after-label:before {
bottom: 10px; }
.twentytwenty-overlay {
-webkit-transition-property: background;
-moz-transition-property: background;
transition-property: background;
background: rgba(0, 0, 0, 0);
z-index: 25; }
.twentytwenty-overlay:hover {
background: rgba(0, 0, 0, 0.5); }
.twentytwenty-overlay:hover .twentytwenty-after-label {
opacity: 1; }
.twentytwenty-overlay:hover .twentytwenty-before-label {
opacity: 1; }
.twentytwenty-before {
z-index: 20; }
.twentytwenty-after {
z-index: 10; }
.twentytwenty-handle {
height: 38px;
width: 38px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -22px;
margin-top: -22px;
border: 3px solid white;
-webkit-border-radius: 1000px;
-moz-border-radius: 1000px;
border-radius: 1000px;
-webkit-box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
-moz-box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
box-shadow: 0px 0px 12px rgba(51, 51, 51, 0.5);
z-index: 40;
cursor: pointer; }
.twentytwenty-horizontal .twentytwenty-handle:before {
bottom: 50%;
margin-bottom: 22px;
-webkit-box-shadow: 0 3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
-moz-box-shadow: 0 3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
box-shadow: 0 3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5); }
.twentytwenty-horizontal .twentytwenty-handle:after {
top: 50%;
margin-top: 22px;
-webkit-box-shadow: 0 -3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
-moz-box-shadow: 0 -3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
box-shadow: 0 -3px 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5); }
.twentytwenty-vertical .twentytwenty-handle:before {
left: 50%;
margin-left: 22px;
-webkit-box-shadow: 3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
-moz-box-shadow: 3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
box-shadow: 3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5); }
.twentytwenty-vertical .twentytwenty-handle:after {
right: 50%;
margin-right: 22px;
-webkit-box-shadow: -3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
-moz-box-shadow: -3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5);
box-shadow: -3px 0 0 white, 0px 0px 12px rgba(51, 51, 51, 0.5); }
.twentytwenty-left-arrow {
border-right: 6px solid white;
left: 50%;
margin-left: -17px; }
.twentytwenty-right-arrow {
border-left: 6px solid white;
right: 50%;
margin-right: -17px; }
.twentytwenty-up-arrow {
border-bottom: 6px solid white;
top: 50%;
margin-top: -17px; }
.twentytwenty-down-arrow {
border-top: 6px solid white;
bottom: 50%;
margin-bottom: -17px; }
<svg xmlns="http://www.w3.org/2000/svg" fill="#fff" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M112.1 454.3c0 6.297 1.816 12.44 5.284 17.69l17.14 25.69c5.25 7.875 17.17 14.28 26.64 14.28h61.67c9.438 0 21.36-6.401 26.61-14.28l17.08-25.68c2.938-4.438 5.348-12.37 5.348-17.7L272 415.1h-160L112.1 454.3zM192 0C90.02 .3203 16 82.97 16 175.1c0 44.38 16.44 84.84 43.56 115.8c16.53 18.84 42.34 58.23 52.22 91.45c.0313 .25 .0938 .5166 .125 .7823h160.2c.0313-.2656 .0938-.5166 .125-.7823c9.875-33.22 35.69-72.61 52.22-91.45C351.6 260.8 368 220.4 368 175.1C368 78.8 289.2 .0039 192 0zM288.4 260.1c-15.66 17.85-35.04 46.3-49.05 75.89h-94.61c-14.01-29.59-33.39-58.04-49.04-75.88C75.24 236.8 64 206.1 64 175.1C64 113.3 112.1 48.25 191.1 48C262.6 48 320 105.4 320 175.1C320 206.1 308.8 236.8 288.4 260.1zM176 80C131.9 80 96 115.9 96 160c0 8.844 7.156 16 16 16S128 168.8 128 160c0-26.47 21.53-48 48-48c8.844 0 16-7.148 16-15.99S184.8 80 176 80z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" fill="#a79d95" viewBox="0 0 576 512" class="w-10 h-10" width="25" height="25"><!--! Font Awesome Free 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M512 32H160c-35.35 0-64 28.65-64 64v224c0 35.35 28.65 64 64 64H512c35.35 0 64-28.65 64-64V96C576 60.65 547.3 32 512 32zM528 320c0 8.822-7.178 16-16 16h-16l-109.3-160.9C383.7 170.7 378.7 168 373.3 168c-5.352 0-10.35 2.672-13.31 7.125l-62.74 94.11L274.9 238.6C271.9 234.4 267.1 232 262 232c-5.109 0-9.914 2.441-12.93 6.574L176 336H160c-8.822 0-16-7.178-16-16V96c0-8.822 7.178-16 16-16H512c8.822 0 16 7.178 16 16V320zM224 112c-17.67 0-32 14.33-32 32s14.33 32 32 32c17.68 0 32-14.33 32-32S241.7 112 224 112zM456 480H120C53.83 480 0 426.2 0 360v-240C0 106.8 10.75 96 24 96S48 106.8 48 120v240c0 39.7 32.3 72 72 72h336c13.25 0 24 10.75 24 24S469.3 480 456 480z"></path></svg>
\ No newline at end of file
// DOM.event.move
//
// 2.0.0
//
// Stephen Band
//
// Triggers 'movestart', 'move' and 'moveend' events after
// mousemoves following a mousedown cross a distance threshold,
// similar to the native 'dragstart', 'drag' and 'dragend' events.
// Move events are throttled to animation frames. Move event objects
// have the properties:
//
// pageX:
// pageY: Page coordinates of pointer.
// startX:
// startY: Page coordinates of pointer at movestart.
// distX:
// distY: Distance the pointer has moved since movestart.
// deltaX:
// deltaY: Distance the finger has moved since last event.
// velocityX:
// velocityY: Average velocity over last few events.
(function(fn) {
if (typeof define === 'function' && define.amd) {
define([], fn);
} else if ((typeof module !== "undefined" && module !== null) && module.exports) {
module.exports = fn;
} else {
fn();
}
})(function(){
var assign = Object.assign || window.jQuery && jQuery.extend;
// Number of pixels a pressed pointer travels before movestart
// event is fired.
var threshold = 8;
// Shim for requestAnimationFrame, falling back to timer. See:
// see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
var requestFrame = (function(){
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(fn, element){
return window.setTimeout(function(){
fn();
}, 25);
}
);
})();
// Shim for customEvent
// see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
(function () {
if ( typeof window.CustomEvent === "function" ) return false;
function CustomEvent ( event, params ) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent( 'CustomEvent' );
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
})();
var ignoreTags = {
textarea: true,
input: true,
select: true,
button: true
};
var mouseevents = {
move: 'mousemove',
cancel: 'mouseup dragstart',
end: 'mouseup'
};
var touchevents = {
move: 'touchmove',
cancel: 'touchend',
end: 'touchend'
};
var rspaces = /\s+/;
// DOM Events
var eventOptions = { bubbles: true, cancelable: true };
var eventsSymbol = typeof Symbol === "function" ? Symbol('events') : {};
function createEvent(type) {
return new CustomEvent(type, eventOptions);
}
function getEvents(node) {
return node[eventsSymbol] || (node[eventsSymbol] = {});
}
function on(node, types, fn, data, selector) {
types = types.split(rspaces);
var events = getEvents(node);
var i = types.length;
var handlers, type;
function handler(e) { fn(e, data); }
while (i--) {
type = types[i];
handlers = events[type] || (events[type] = []);
handlers.push([fn, handler]);
node.addEventListener(type, handler);
}
}
function off(node, types, fn, selector) {
types = types.split(rspaces);
var events = getEvents(node);
var i = types.length;
var type, handlers, k;
if (!events) { return; }
while (i--) {
type = types[i];
handlers = events[type];
if (!handlers) { continue; }
k = handlers.length;
while (k--) {
if (handlers[k][0] === fn) {
node.removeEventListener(type, handlers[k][1]);
handlers.splice(k, 1);
}
}
}
}
function trigger(node, type, properties) {
// Don't cache events. It prevents you from triggering an event of a
// given type from inside the handler of another event of that type.
var event = createEvent(type);
if (properties) { assign(event, properties); }
node.dispatchEvent(event);
}
// Constructors
function Timer(fn){
var callback = fn,
active = false,
running = false;
function trigger(time) {
if (active){
callback();
requestFrame(trigger);
running = true;
active = false;
}
else {
running = false;
}
}
this.kick = function(fn) {
active = true;
if (!running) { trigger(); }
};
this.end = function(fn) {
var cb = callback;
if (!fn) { return; }
// If the timer is not running, simply call the end callback.
if (!running) {
fn();
}
// If the timer is running, and has been kicked lately, then
// queue up the current callback and the end callback, otherwise
// just the end callback.
else {
callback = active ?
function(){ cb(); fn(); } :
fn ;
active = true;
}
};
}
// Functions
function noop() {}
function preventDefault(e) {
e.preventDefault();
}
function isIgnoreTag(e) {
return !!ignoreTags[e.target.tagName.toLowerCase()];
}
function isPrimaryButton(e) {
// Ignore mousedowns on any button other than the left (or primary)
// mouse button, or when a modifier key is pressed.
return (e.which === 1 && !e.ctrlKey && !e.altKey);
}
function identifiedTouch(touchList, id) {
var i, l;
if (touchList.identifiedTouch) {
return touchList.identifiedTouch(id);
}
// touchList.identifiedTouch() does not exist in
// webkit yet… we must do the search ourselves...
i = -1;
l = touchList.length;
while (++i < l) {
if (touchList[i].identifier === id) {
return touchList[i];
}
}
}
function changedTouch(e, data) {
var touch = identifiedTouch(e.changedTouches, data.identifier);
// This isn't the touch you're looking for.
if (!touch) { return; }
// Chrome Android (at least) includes touches that have not
// changed in e.changedTouches. That's a bit annoying. Check
// that this touch has changed.
if (touch.pageX === data.pageX && touch.pageY === data.pageY) { return; }
return touch;
}
// Handlers that decide when the first movestart is triggered
function mousedown(e){
// Ignore non-primary buttons
if (!isPrimaryButton(e)) { return; }
// Ignore form and interactive elements
if (isIgnoreTag(e)) { return; }
on(document, mouseevents.move, mousemove, e);
on(document, mouseevents.cancel, mouseend, e);
}
function mousemove(e, data){
checkThreshold(e, data, e, removeMouse);
}
function mouseend(e, data) {
removeMouse();
}
function removeMouse() {
off(document, mouseevents.move, mousemove);
off(document, mouseevents.cancel, mouseend);
}
function touchstart(e) {
// Don't get in the way of interaction with form elements
if (ignoreTags[e.target.tagName.toLowerCase()]) { return; }
var touch = e.changedTouches[0];
// iOS live updates the touch objects whereas Android gives us copies.
// That means we can't trust the touchstart object to stay the same,
// so we must copy the data. This object acts as a template for
// movestart, move and moveend event objects.
var data = {
target: touch.target,
pageX: touch.pageX,
pageY: touch.pageY,
identifier: touch.identifier,
// The only way to make handlers individually unbindable is by
// making them unique.
touchmove: function(e, data) { touchmove(e, data); },
touchend: function(e, data) { touchend(e, data); }
};
on(document, touchevents.move, data.touchmove, data);
on(document, touchevents.cancel, data.touchend, data);
}
function touchmove(e, data) {
var touch = changedTouch(e, data);
if (!touch) { return; }
checkThreshold(e, data, touch, removeTouch);
}
function touchend(e, data) {
var touch = identifiedTouch(e.changedTouches, data.identifier);
if (!touch) { return; }
removeTouch(data);
}
function removeTouch(data) {
off(document, touchevents.move, data.touchmove);
off(document, touchevents.cancel, data.touchend);
}
function checkThreshold(e, data, touch, fn) {
var distX = touch.pageX - data.pageX;
var distY = touch.pageY - data.pageY;
// Do nothing if the threshold has not been crossed.
if ((distX * distX) + (distY * distY) < (threshold * threshold)) { return; }
triggerStart(e, data, touch, distX, distY, fn);
}
function triggerStart(e, data, touch, distX, distY, fn) {
var touches = e.targetTouches;
var time = e.timeStamp - data.timeStamp;
// Create a movestart object with some special properties that
// are passed only to the movestart handlers.
var template = {
altKey: e.altKey,
ctrlKey: e.ctrlKey,
shiftKey: e.shiftKey,
startX: data.pageX,
startY: data.pageY,
distX: distX,
distY: distY,
deltaX: distX,
deltaY: distY,
pageX: touch.pageX,
pageY: touch.pageY,
velocityX: distX / time,
velocityY: distY / time,
identifier: data.identifier,
targetTouches: touches,
finger: touches ? touches.length : 1,
enableMove: function() {
this.moveEnabled = true;
this.enableMove = noop;
e.preventDefault();
}
};
// Trigger the movestart event.
trigger(data.target, 'movestart', template);
// Unbind handlers that tracked the touch or mouse up till now.
fn(data);
}
// Handlers that control what happens following a movestart
function activeMousemove(e, data) {
var timer = data.timer;
data.touch = e;
data.timeStamp = e.timeStamp;
timer.kick();
}
function activeMouseend(e, data) {
var target = data.target;
var event = data.event;
var timer = data.timer;
removeActiveMouse();
endEvent(target, event, timer, function() {
// Unbind the click suppressor, waiting until after mouseup
// has been handled.
setTimeout(function(){
off(target, 'click', preventDefault);
}, 0);
});
}
function removeActiveMouse() {
off(document, mouseevents.move, activeMousemove);
off(document, mouseevents.end, activeMouseend);
}
function activeTouchmove(e, data) {
var event = data.event;
var timer = data.timer;
var touch = changedTouch(e, event);
if (!touch) { return; }
// Stop the interface from gesturing
e.preventDefault();
event.targetTouches = e.targetTouches;
data.touch = touch;
data.timeStamp = e.timeStamp;
timer.kick();
}
function activeTouchend(e, data) {
var target = data.target;
var event = data.event;
var timer = data.timer;
var touch = identifiedTouch(e.changedTouches, event.identifier);
// This isn't the touch you're looking for.
if (!touch) { return; }
removeActiveTouch(data);
endEvent(target, event, timer);
}
function removeActiveTouch(data) {
off(document, touchevents.move, data.activeTouchmove);
off(document, touchevents.end, data.activeTouchend);
}
// Logic for triggering move and moveend events
function updateEvent(event, touch, timeStamp) {
var time = timeStamp - event.timeStamp;
event.distX = touch.pageX - event.startX;
event.distY = touch.pageY - event.startY;
event.deltaX = touch.pageX - event.pageX;
event.deltaY = touch.pageY - event.pageY;
// Average the velocity of the last few events using a decay
// curve to even out spurious jumps in values.
event.velocityX = 0.3 * event.velocityX + 0.7 * event.deltaX / time;
event.velocityY = 0.3 * event.velocityY + 0.7 * event.deltaY / time;
event.pageX = touch.pageX;
event.pageY = touch.pageY;
}
function endEvent(target, event, timer, fn) {
timer.end(function(){
trigger(target, 'moveend', event);
return fn && fn();
});
}
// Set up the DOM
function movestart(e) {
if (e.defaultPrevented) { return; }
if (!e.moveEnabled) { return; }
var event = {
startX: e.startX,
startY: e.startY,
pageX: e.pageX,
pageY: e.pageY,
distX: e.distX,
distY: e.distY,
deltaX: e.deltaX,
deltaY: e.deltaY,
velocityX: e.velocityX,
velocityY: e.velocityY,
identifier: e.identifier,
targetTouches: e.targetTouches,
finger: e.finger
};
var data = {
target: e.target,
event: event,
timer: new Timer(update),
touch: undefined,
timeStamp: e.timeStamp
};
function update(time) {
updateEvent(event, data.touch, data.timeStamp);
trigger(data.target, 'move', event);
}
if (e.identifier === undefined) {
// We're dealing with a mouse event.
// Stop clicks from propagating during a move
on(e.target, 'click', preventDefault);
on(document, mouseevents.move, activeMousemove, data);
on(document, mouseevents.end, activeMouseend, data);
}
else {
// In order to unbind correct handlers they have to be unique
data.activeTouchmove = function(e, data) { activeTouchmove(e, data); };
data.activeTouchend = function(e, data) { activeTouchend(e, data); };
// We're dealing with a touch.
on(document, touchevents.move, data.activeTouchmove, data);
on(document, touchevents.end, data.activeTouchend, data);
}
}
on(document, 'mousedown', mousedown);
on(document, 'touchstart', touchstart);
on(document, 'movestart', movestart);
// jQuery special events
//
// jQuery event objects are copies of DOM event objects. They need
// a little help copying the move properties across.
if (!window.jQuery) { return; }
var properties = ("startX startY pageX pageY distX distY deltaX deltaY velocityX velocityY").split(' ');
function enableMove1(e) { e.enableMove(); }
function enableMove2(e) { e.enableMove(); }
function enableMove3(e) { e.enableMove(); }
function add(handleObj) {
var handler = handleObj.handler;
handleObj.handler = function(e) {
// Copy move properties across from originalEvent
var i = properties.length;
var property;
while(i--) {
property = properties[i];
e[property] = e.originalEvent[property];
}
handler.apply(this, arguments);
};
}
jQuery.event.special.movestart = {
setup: function() {
// Movestart must be enabled to allow other move events
on(this, 'movestart', enableMove1);
// Do listen to DOM events
return false;
},
teardown: function() {
off(this, 'movestart', enableMove1);
return false;
},
add: add
};
jQuery.event.special.move = {
setup: function() {
on(this, 'movestart', enableMove2);
return false;
},
teardown: function() {
off(this, 'movestart', enableMove2);
return false;
},
add: add
};
jQuery.event.special.moveend = {
setup: function() {
on(this, 'movestart', enableMove3);
return false;
},
teardown: function() {
off(this, 'movestart', enableMove3);
return false;
},
add: add
};
});
(function($){
$.fn.twentytwenty = function(options) {
var options = $.extend({
default_offset_pct: 0.5,
orientation: 'horizontal',
before_label: 'Before',
after_label: 'After',
no_overlay: false,
move_slider_on_hover: false,
move_with_handle_only: true,
click_to_move: false
}, options);
return this.each(function() {
var sliderPct = options.default_offset_pct;
var container = $(this);
var sliderOrientation = options.orientation;
var beforeDirection = (sliderOrientation === 'vertical') ? 'down' : 'left';
var afterDirection = (sliderOrientation === 'vertical') ? 'up' : 'right';
container.wrap("<div class='twentytwenty-wrapper twentytwenty-" + sliderOrientation + "'></div>");
if(!options.no_overlay) {
container.append("<div class='twentytwenty-overlay'></div>");
var overlay = container.find(".twentytwenty-overlay");
overlay.append("<div class='twentytwenty-before-label' data-content='"+options.before_label+"'></div>");
overlay.append("<div class='twentytwenty-after-label' data-content='"+options.after_label+"'></div>");
}
var beforeImg = container.find("img:first");
var afterImg = container.find("img:last");
container.append("<div class='twentytwenty-handle'></div>");
var slider = container.find(".twentytwenty-handle");
slider.append("<span class='twentytwenty-" + beforeDirection + "-arrow'></span>");
slider.append("<span class='twentytwenty-" + afterDirection + "-arrow'></span>");
container.addClass("twentytwenty-container");
beforeImg.addClass("twentytwenty-before");
afterImg.addClass("twentytwenty-after");
var calcOffset = function(dimensionPct) {
var w = beforeImg.width();
var h = beforeImg.height();
return {
w: w+"px",
h: h+"px",
cw: (dimensionPct*w)+"px",
ch: (dimensionPct*h)+"px"
};
};
var adjustContainer = function(offset) {
if (sliderOrientation === 'vertical') {
beforeImg.css("clip", "rect(0,"+offset.w+","+offset.ch+",0)");
afterImg.css("clip", "rect("+offset.ch+","+offset.w+","+offset.h+",0)");
}
else {
beforeImg.css("clip", "rect(0,"+offset.cw+","+offset.h+",0)");
afterImg.css("clip", "rect(0,"+offset.w+","+offset.h+","+offset.cw+")");
}
container.css("height", offset.h);
};
var adjustSlider = function(pct) {
var offset = calcOffset(pct);
slider.css((sliderOrientation==="vertical") ? "top" : "left", (sliderOrientation==="vertical") ? offset.ch : offset.cw);
adjustContainer(offset);
};
// Return the number specified or the min/max number if it outside the range given.
var minMaxNumber = function(num, min, max) {
return Math.max(min, Math.min(max, num));
};
// Calculate the slider percentage based on the position.
var getSliderPercentage = function(positionX, positionY) {
var sliderPercentage = (sliderOrientation === 'vertical') ?
(positionY-offsetY)/imgHeight :
(positionX-offsetX)/imgWidth;
return minMaxNumber(sliderPercentage, 0, 1);
};
$(window).on("resize.twentytwenty", function(e) {
adjustSlider(sliderPct);
});
var offsetX = 0;
var offsetY = 0;
var imgWidth = 0;
var imgHeight = 0;
var onMoveStart = function(e) {
if (((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) && sliderOrientation !== 'vertical') {
e.preventDefault();
}
else if (((e.distX < e.distY && e.distX < -e.distY) || (e.distX > e.distY && e.distX > -e.distY)) && sliderOrientation === 'vertical') {
e.preventDefault();
}
container.addClass("active");
offsetX = container.offset().left;
offsetY = container.offset().top;
imgWidth = beforeImg.width();
imgHeight = beforeImg.height();
};
var onMove = function(e) {
if (container.hasClass("active")) {
sliderPct = getSliderPercentage(e.pageX, e.pageY);
adjustSlider(sliderPct);
}
};
var onMoveEnd = function() {
container.removeClass("active");
};
var moveTarget = options.move_with_handle_only ? slider : container;
moveTarget.on("movestart",onMoveStart);
moveTarget.on("move",onMove);
moveTarget.on("moveend",onMoveEnd);
if (options.move_slider_on_hover) {
container.on("mouseenter", onMoveStart);
container.on("mousemove", onMove);
container.on("mouseleave", onMoveEnd);
}
slider.on("touchmove", function(e) {
e.preventDefault();
});
container.find("img").on("mousedown", function(event) {
event.preventDefault();
});
if (options.click_to_move) {
container.on('click', function(e) {
offsetX = container.offset().left;
offsetY = container.offset().top;
imgWidth = beforeImg.width();
imgHeight = beforeImg.height();
sliderPct = getSliderPercentage(e.pageX, e.pageY);
adjustSlider(sliderPct);
});
}
$(window).trigger("resize.twentytwenty");
});
};
})(jQuery);
<?xml version="1.0"?>
<!--
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<css src="Jajuma_WebpImages::css/web.css"/>
</head>
</page>
var config = {
deps: ["Jajuma_WebpImages/js/webpimages"],
config: {
mixins: {
'mage/gallery/gallery': {
'Jajuma_WebpImages/js/gallery/gallery-mixin': true
},
'Magento_Swatches/js/swatch-renderer': {
'Jajuma_WebpImages/js/swatch-renderer-mixin': true
},
}
}
};
\ No newline at end of file
<?php
/**
* @author JaJuMa GmbH <info@jajuma.de>
* @copyright Copyright (c) 2020 JaJuMa GmbH <https://www.jajuma.de>. All rights reserved.
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
/** @var $block \Jajuma\WebpImages\Block\Picture */
$customSrcTag = $block->getCustomSrcTag();
$customSrcSetTag = $block->getCustomSrcSetTag();
$originalTag = $block->getOriginalTag();
$isLazyLoadEnabled = $block->isNativeLazyLoadingEnabled();
$excludeNativeLazyloadImageAttributes = $block->getExcludeNativeLazyloadImageAttributes();
$isImageInExcludeList = preg_match_all($excludeNativeLazyloadImageAttributes, $originalTag);
if ($isLazyLoadEnabled && !$isImageInExcludeList) {
// add loading="lazy" at the end of the img tag
$originalTag = preg_replace('/>$/', ' loading="lazy" />', $originalTag);
}
?>
<?php if ($customSrcTag): ?>
<picture>
<source type="image/webp" <?= /* @noEscape */ $customSrcSetTag ? $customSrcSetTag : 'srcset' ?>="
<?= /* @noEscape */ $block->getWebpImage() ?>">
<source type="<?= /* @noEscape */ $block->getOriginalImageType() ?>"
<?= /* @noEscape */ $customSrcSetTag ? $customSrcSetTag : 'srcset' ?>="
<?= /* @noEscape */ $block->getOriginalImage() ?>">
<?= /* @noEscape */ $originalTag ?>
</picture>
<?php else: ?>
<picture>
<source type="image/webp" srcset="<?= /* @noEscape */ $block->getWebpImage() ?>">
<source type="<?= /* @noEscape */ $block->getOriginalImageType() ?>"
srcset="<?= /* @noEscape */ $block->getOriginalImage() ?>">
<?= /* @noEscape */ $originalTag ?>
</picture>
<?php endif; ?>
.swatch-option-loading-webp {
content: url(../../images/loader-2.gif);
}
\ No newline at end of file
define(['jquery','mage/utils/wrapper','Jajuma_WebpImages/js/lib/modernizr-webp'], function ($, wrapper) {
'use strict';
return function (initialize) {
return wrapper.wrap(initialize, function (initialize, config, element) {
ModernizrJajuma.on('webp', function(result) {
if (result) {
$.each(config.data, function (key, value) {
value.full = value.full_webp;
value.thumb = value.thumb_webp;
value.img = value.img_webp;
config.data[key] = value;
});
}
initialize(config, element);
});
});
};
});
\ No newline at end of file
/*! modernizr 3.6.0 (Custom Build) | MIT *
* https://modernizr.com/download/?-webp-setclasses !*/
!function(e,n,A){function o(e,n){return typeof e===n}function t(){var e,n,A,t,a,i,l;for(var f in r)if(r.hasOwnProperty(f)){if(e=[],n=r[f],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(A=0;A<n.options.aliases.length;A++)e.push(n.options.aliases[A].toLowerCase());for(t=o(n.fn,"function")?n.fn():n.fn,a=0;a<e.length;a++)i=e[a],l=i.split("."),1===l.length?ModernizrJajuma[l[0]]=t:(!ModernizrJajuma[l[0]]||ModernizrJajuma[l[0]]instanceof Boolean||(ModernizrJajuma[l[0]]=new Boolean(ModernizrJajuma[l[0]])),ModernizrJajuma[l[0]][l[1]]=t),s.push((t?"":"no-")+l.join("-"))}}function a(e){var n=u.className,A=ModernizrJajuma._config.classPrefix||"";if(c&&(n=n.baseVal),ModernizrJajuma._config.enableJSClass){var o=new RegExp("(^|\\s)"+A+"no-js(\\s|$)");n=n.replace(o,"$1"+A+"js$2")}ModernizrJajuma._config.enableClasses&&(n+=" "+A+e.join(" "+A),c?u.className.baseVal=n:u.className=n)}function i(e,n){if("object"==typeof e)for(var A in e)f(e,A)&&i(A,e[A]);else{e=e.toLowerCase();var o=e.split("."),t=ModernizrJajuma[o[0]];if(2==o.length&&(t=t[o[1]]),"undefined"!=typeof t)return ModernizrJajuma;n="function"==typeof n?n():n,1==o.length?ModernizrJajuma[o[0]]=n:(!ModernizrJajuma[o[0]]||ModernizrJajuma[o[0]]instanceof Boolean||(ModernizrJajuma[o[0]]=new Boolean(ModernizrJajuma[o[0]])),ModernizrJajuma[o[0]][o[1]]=n),a([(n&&0!=n?"":"no-")+o.join("-")]),ModernizrJajuma._trigger(e,n)}return ModernizrJajuma}var s=[],r=[],l={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,n){var A=this;setTimeout(function(){n(A[e])},0)},addTest:function(e,n,A){r.push({name:e,fn:n,options:A})},addAsyncTest:function(e){r.push({name:null,fn:e})}},ModernizrJajuma=function(){};ModernizrJajuma.prototype=l,ModernizrJajuma=new ModernizrJajuma;var f,u=n.documentElement,c="svg"===u.nodeName.toLowerCase();!function(){var e={}.hasOwnProperty;f=o(e,"undefined")||o(e.call,"undefined")?function(e,n){return n in e&&o(e.constructor.prototype[n],"undefined")}:function(n,A){return e.call(n,A)}}(),l._l={},l.on=function(e,n){this._l[e]||(this._l[e]=[]),this._l[e].push(n),ModernizrJajuma.hasOwnProperty(e)&&setTimeout(function(){ModernizrJajuma._trigger(e,ModernizrJajuma[e])},0)},l._trigger=function(e,n){if(this._l[e]){var A=this._l[e];setTimeout(function(){var e,o;for(e=0;e<A.length;e++)(o=A[e])(n)},0),delete this._l[e]}},ModernizrJajuma._q.push(function(){l.addTest=i}),ModernizrJajuma.addAsyncTest(function(){function e(e,n,A){function o(n){var o=n&&"load"===n.type?1==t.width:!1,a="webp"===e;i(e,a&&o?new Boolean(o):o),A&&A(n)}var t=new Image;t.onerror=o,t.onload=o,t.src=n}var n=[{uri:"data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=",name:"webp"},{uri:"data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==",name:"webp.alpha"},{uri:"data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA",name:"webp.animation"},{uri:"data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=",name:"webp.lossless"}],A=n.shift();e(A.name,A.uri,function(A){if(A&&"load"===A.type)for(var o=0;o<n.length;o++)e(n[o].name,n[o].uri)})}),t(),a(s),delete l.addTest,delete l.addAsyncTest;for(var p=0;p<ModernizrJajuma._q.length;p++)ModernizrJajuma._q[p]();e.ModernizrJajuma=ModernizrJajuma}(window,document);
\ No newline at end of file
define([
'jquery',
'jquery/ui',
"domReady!",
'Jajuma_WebpImages/js/lib/modernizr-webp'
], function ($) {
'use strict';
return function (widget) {
$.widget('mage.SwatchRenderer', widget, {
_OnClick: function ($this, $widget) {
var $parent = $this.parents('.' + $widget.options.classes.attributeClass),
$wrapper = $this.parents('.' + $widget.options.classes.attributeOptionsWrapper),
$label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass),
attributeId = (typeof $parent.attr('attribute-id') != 'undefined') ? $parent.attr('attribute-id') : (typeof $parent.attr('data-attribute-id') != 'undefined') ? $parent.attr('data-attribute-id') : false,
optionId = (typeof $this.attr('option-id') != 'undefined') ? $this.attr('option-id') : (typeof $this.attr('data-option-id') != 'undefined') ? $this.attr('data-option-id') : false,
optionLabel = (typeof $this.attr('option-label') != 'undefined') ? $this.attr('option-label') : (typeof $this.attr('data-option-label') != 'undefined') ? $this.attr('data-option-label') : false,
$input = $parent.find('.' + $widget.options.classes.attributeInput);
if (typeof this.options.jsonSwatchConfig[attributeId]['additional_data'] != 'undefined') {
var checkAdditionalData = JSON.parse(this.options.jsonSwatchConfig[attributeId]['additional_data']);
}
if ($widget.inProductList) {
$input = $widget.productForm.find(
'.' + $widget.options.classes.attributeInput + '[name="super_attribute[' + attributeId + ']"]'
);
}
if ($this.hasClass('disabled')) {
return;
}
if ($this.hasClass('selected')) {
$parent.removeAttr('option-selected').find('.selected').removeClass('selected');
$input.val('');
$label.text('');
$this.attr('aria-checked', false);
} else {
if ((typeof $this.attr('option-id') != 'undefined') ) {
$parent.attr('option-selected', $this.attr('option-id')).find('.selected').removeClass('selected');
}
if ((typeof $this.attr('data-option-id') != 'undefined') ) {
$parent.attr('data-option-selected', $this.attr('data-option-id')).find('.selected').removeClass('selected');
}
$label.text(optionLabel);
$input.val(optionId);
$input.attr('data-attr-name', this._getAttributeCodeById(attributeId));
$this.addClass('selected');
$widget._toggleCheckedAttributes($this, $wrapper);
}
$widget._Rebuild();
if ($widget.element.parents($widget.options.selectorProduct)
.find(this.options.selectorProductPrice).is(':data(mage-priceBox)')
) {
$widget._UpdatePrice();
}
$(document).trigger('updateMsrpPriceBlock',
[
parseInt($this.attr('index'), 10) + 1,
$widget.options.jsonConfig.optionPrices
]);
if (typeof checkAdditionalData != 'undefined') {
if (checkAdditionalData['update_product_preview_image'] == '1') {
$widget._loadMedia();
}
} else {
$widget._loadMedia();
}
$input.trigger('change');
},
updateBaseImage: function (images, context, isInProductView) {
var justAnImage = images[0],
initialImages = this.options.mediaGalleryInitial,
imagesToUpdate,
gallery = context.find(this.options.mediaGallerySelector).data('gallery'),
isInitial,
self = this;
if (isInProductView) {
imagesToUpdate = images.length ? this._setImageType($.extend(true, [], images)) : [];
isInitial = _.isEqual(imagesToUpdate, initialImages);
if (this.options.gallerySwitchStrategy === 'prepend' && !isInitial) {
imagesToUpdate = imagesToUpdate.concat(initialImages);
}
imagesToUpdate = this._setImageIndex(imagesToUpdate);
if (!_.isUndefined(gallery)) {
ModernizrJajuma.on('webp', function(result) {
if (result) {
// custom replace images with webp images
self.convertImgToWebp(imagesToUpdate, context, isInProductView, justAnImage);
}
});
} else {
context.find(this.options.mediaGallerySelector).on('gallery:loaded', function (loadedGallery) {
loadedGallery = context.find(this.options.mediaGallerySelector).data('gallery');
loadedGallery.updateData(imagesToUpdate);
}.bind(this));
}
if (isInitial) {
$(this.options.mediaGallerySelector).AddFotoramaVideoEvents();
} else {
$(this.options.mediaGallerySelector).AddFotoramaVideoEvents({
selectedOption: this.getProduct(),
dataMergeStrategy: this.options.gallerySwitchStrategy
});
}
gallery.first();
} else if (justAnImage && justAnImage.img) {
ModernizrJajuma.on('webp', function(result) {
if (result) {
// custom replace images with webp images
self.convertImgToWebp(images, context, isInProductView, justAnImage);
} else {
context.find('.product-image-photo').attr('src', justAnImage.img);
context.find('[type="image/jpg"]').attr('srcset', justAnImage.img);
}
});
}
},
convertImgToWebp: function (images, context, isInProductView, justAnImage) {
var gallery = context.find(this.options.mediaGallerySelector).data('gallery');
if (justAnImage.img.indexOf('.webp') !== -1) {
if (!isInProductView) {
context.find('[type="image/webp"]').attr('srcset', justAnImage.img);
}
} else {
$.ajax({
url: BASE_URL + 'webp/image/convert',
data: {
images: images,
isInProductView: isInProductView
},
type: 'POST',
beforeSend: function () {
// add loading
if (isInProductView) {
// add loading for main .fotorama__active
$('.fotorama__stage .fotorama__img').addClass('swatch-option-loading-webp');
// add loading for thumb .fotorama__active
$('.fotorama__thumb img').addClass('swatch-option-loading-webp');
} else {
// add loading for main image in category page
context.find('.product-image-photo').addClass('swatch-option-loading-webp');
}
},
success: function (response) {
if (response.webpUrls.length != 0) {
// replace jpg/png image with webp image in category page only
if (!isInProductView) {
// remove loading for main image in category page
context.find('.product-image-photo').removeClass('swatch-option-loading-webp');
// load image
context.find('[type="image/webp"]').attr('srcset', response.webpUrls[0]['img']);
}
// replace jpg/png image with webp image in fotorama images in product page only
if (isInProductView) {
// load image
gallery.updateData(response.webpUrls);
// remove loading for main .fotorama__active
$('.fotorama__stage .fotorama__img').removeClass('swatch-option-loading-webp');
// remove loading for thumb .fotorama__active
$('.fotorama__thumb img').removeClass('swatch-option-loading-webp');
}
}
}
});
}
}
});
return $.mage.SwatchRenderer;
}
});
require([
'jquery',
'Jajuma_WebpImages/js/lib/modernizr-webp'
],function($){
$(document).ready(function() {
ModernizrJajuma.on('webp', function(result) {
if (!result) {
$('body').addClass('no-webp');
}
});
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment