From 6450c85ef17dfee06f883577c3d07cf12696d44e Mon Sep 17 00:00:00 2001 From: pini-girit Date: Tue, 12 Feb 2019 18:02:46 +0200 Subject: [PATCH 1/8] CLOUDINARY-85: Added new product attribute named cloudinary_date and saved the free transformations on that as json as well in order to reduce queries on frontend --- .../Cloudinary/Cloudinary/Helper/Image.php | 14 ++++- .../Cloudinary/Model/AdminProductObserver.php | 22 ++++++- .../Model/Catalog/Product/Image.php | 5 +- .../Model/Catalog/Product/Media/Config.php | 33 +++++++---- .../Cloudinary/Model/Transformation.php | 58 ++++++++++++++----- .../Cloudinary/Cloudinary/etc/config.xml | 3 +- .../cloudinary_setup/upgrade-2.9.6-2.9.7.php | 24 ++++++++ 7 files changed, 130 insertions(+), 29 deletions(-) create mode 100644 app/code/community/Cloudinary/Cloudinary/sql/cloudinary_setup/upgrade-2.9.6-2.9.7.php diff --git a/app/code/community/Cloudinary/Cloudinary/Helper/Image.php b/app/code/community/Cloudinary/Cloudinary/Helper/Image.php index 307f832..ffe375d 100644 --- a/app/code/community/Cloudinary/Cloudinary/Helper/Image.php +++ b/app/code/community/Cloudinary/Cloudinary/Helper/Image.php @@ -81,7 +81,9 @@ public function init(Mage_Catalog_Model_Product $product, $attributeName, $image */ public function resize($width, $height = null) { - $this->_dimensions = Dimensions::fromWidthAndHeight($width, $height); + if ($this->_configuration->isEnabled()) { + $this->_dimensions = Dimensions::fromWidthAndHeight($width, $height); + } return parent::resize($width, $height); } @@ -104,16 +106,22 @@ public function getImageUrlForCategory(Mage_Catalog_Model_Category $category) */ public function __toString() { + if (!$this->_configuration->isEnabled()) { + return parent::__toString(); + } $image = $this->_imageFactory->build( $this->_getRequestedImageFile(), - function() { return parent::__toString();} + function () { + return parent::__toString(); + } ); return $this->_urlGenerator->generateFor( $image, $this->_transformation->addFreeformTransformationForImage( $this->createTransformation(), - $this->_getRequestedImageFile() + $this->_getRequestedImageFile(), + $this->getProduct() ) ); } diff --git a/app/code/community/Cloudinary/Cloudinary/Model/AdminProductObserver.php b/app/code/community/Cloudinary/Cloudinary/Model/AdminProductObserver.php index 65eaa63..ed1fb19 100644 --- a/app/code/community/Cloudinary/Cloudinary/Model/AdminProductObserver.php +++ b/app/code/community/Cloudinary/Cloudinary/Model/AdminProductObserver.php @@ -37,7 +37,7 @@ private function filterUpdatedImages(array $imageData, array $imageUpdated) { return array_filter( $imageData, - function($id) use ($imageUpdated) { + function ($id) use ($imageUpdated) { return $imageUpdated[$id]; }, ARRAY_FILTER_USE_KEY @@ -71,12 +71,32 @@ private function storeFreeTransformFields(array $imageData, Mage_Catalog_Model_P { $mediaImages = $this->getMediaGalleryImages($product); + // TODO: Should be removed on future releases foreach ($imageData as $id => $freeTransform) { Mage::getModel('cloudinary_cloudinary/transformation') ->setImageName($this->getImageNameForId($id, $mediaImages)) ->setFreeTransformation($freeTransform) ->save(); + + $cloudinaryData = json_decode((string)$product->getCloudinaryData(), true) ?: array(); + $cloudinaryData['transformation'] = (isset($cloudinaryData['transformation']))? (array) $cloudinaryData['transformation'] : array(); + $cloudinaryData['transformation'][md5($this->getImageNameForId($id, $mediaImages))] = (string) $freeTransform; + $product->setCloudinaryData(json_encode($cloudinaryData)); + } + + + /*foreach ($mediaImages as &$image) { + if (isset($imageData[$image["value_id"]])) { + $image['cloudinary_transformation'] = $imageData[$image["value_id"]]; + } } + + $productPost = Mage::app()->getRequest()->getPost("product"); + $productPost['media_gallery']['images'] = json_encode($mediaImages); + Mage::app()->getRequest()->setPost("product", $productPost); + $mediaGallery = $product->getMediaGallery(); + $mediaGallery['images'] = $productPost['media_gallery']['images']; + $product->setData('media_gallery', $mediaGallery);*/ } /** diff --git a/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Image.php b/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Image.php index 7072ffd..4a74278 100644 --- a/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Image.php +++ b/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Image.php @@ -24,7 +24,10 @@ public function __construct() public function getUrl() { return (string) $this->_imageFactory->build( - $this->_newFile, function() { return parent::getUrl();} + $this->_newFile, + function () { + return parent::getUrl(); + } ); } diff --git a/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Media/Config.php b/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Media/Config.php index 49e58c2..78e3ae5 100644 --- a/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Media/Config.php +++ b/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Media/Config.php @@ -16,19 +16,26 @@ class Cloudinary_Cloudinary_Model_Catalog_Product_Media_Config extends Mage_Cata */ private $_urlGenerator; + /** + * @var Configuration + */ + private $_configuration; + public function __construct() { - $configuration = Mage::getModel('cloudinary_cloudinary/configuration'); + $this->_configuration = Mage::getModel('cloudinary_cloudinary/configuration'); - $this->_imageFactory = new ImageFactory( - $configuration, - Mage::getModel('cloudinary_cloudinary/synchronizationChecker') - ); + if ($this->_configuration->isEnabled()) { + $this->_imageFactory = new ImageFactory( + $this->_configuration, + Mage::getModel('cloudinary_cloudinary/synchronizationChecker') + ); - $this->_urlGenerator = new UrlGenerator( - $configuration, - CloudinaryImageProvider::fromConfiguration($configuration) - ); + $this->_urlGenerator = new UrlGenerator( + $this->_configuration, + CloudinaryImageProvider::fromConfiguration($this->_configuration) + ); + } } /** @@ -37,7 +44,13 @@ public function __construct() */ public function getMediaUrl($file) { - $image = $this->_imageFactory->build($file, function() use($file) { return parent::getMediaUrl($file); }); + if (!$this->_configuration->isEnabled()) { + return parent::getMediaUrl($file); + } + + $image = $this->_imageFactory->build($file, function () use ($file) { + return parent::getMediaUrl($file); + }); return $this->_urlGenerator->generateFor( $image, diff --git a/app/code/community/Cloudinary/Cloudinary/Model/Transformation.php b/app/code/community/Cloudinary/Cloudinary/Model/Transformation.php index afac07d..a577334 100644 --- a/app/code/community/Cloudinary/Cloudinary/Model/Transformation.php +++ b/app/code/community/Cloudinary/Cloudinary/Model/Transformation.php @@ -28,33 +28,65 @@ protected function _construct() * @param string $imageFile * @return Transformation */ - public function transformationForImage($imageFile) + public function transformationForImage($imageFile, Mage_Catalog_Model_Product $product = null) { return $this->addFreeformTransformationForImage( $this->configuration->getDefaultTransformation(), - $imageFile + $imageFile, + $product ); } /** * @param Transformation $transformation * @param string $imageFile + * @param Mage_Catalog_Model_Product|null $product * @return Transformation */ - public function addFreeformTransformationForImage(Transformation $transformation, $imageFile) + public function addFreeformTransformationForImage(Transformation $transformation, $imageFile, Mage_Catalog_Model_Product $product = null) { - $transformationString = $this->cache->loadCache( - $this->getTransformCacheKeyFromImageFile($imageFile), - function () use ($imageFile) { - $this->warmTransformationCache(); + $transformationString = false; + if ($product) { + $cloudinaryData = json_decode((string)$product->getCloudinaryData(), true) ?: array(); + if (isset($cloudinaryData['transformation']) && isset($cloudinaryData['transformation'][md5($imageFile)])) { + $transformationString = $cloudinaryData['transformation'][md5($imageFile)]; + } else { + $updateProduct = true; + $transformationString = $this->cache->loadCache( + $this->getTransformCacheKeyFromImageFile($imageFile), + function () use ($imageFile) { + $this->warmTransformationCache(); - $this->load($imageFile); - if (($this->getImageName() === $imageFile) && $this->hasFreeTransformation()) { - return $this->getFreeTransformation(); - } - return ''; + $this->load($imageFile); + if (($this->getImageName() === $imageFile) && $this->hasFreeTransformation()) { + return $this->getFreeTransformation(); + } + return ''; + } + ); } - ); + } else { + /*$transformationString = $this->cache->loadCache( + $this->getTransformCacheKeyFromImageFile($imageFile), + function () use ($imageFile) { + $this->warmTransformationCache(); + + $this->load($imageFile); + if (($this->getImageName() === $imageFile) && $this->hasFreeTransformation()) { + return $this->getFreeTransformation(); + } + return ''; + } + );*/ + } + + if (isset($updateProduct)) { + //$initialEnvironmentInfo = Mage::getSingleton('core/app_emulation')->startEnvironmentEmulation(Mage_Core_Model_App::ADMIN_STORE_ID); + $cloudinaryData['transformation'][md5($imageFile)] = $transformationString; + $product->setCloudinaryData(json_encode($cloudinaryData)); + $product->getResource()->saveAttribute($product, 'cloudinary_data'); + //Mage::getSingleton('core/app_emulation')->stopEnvironmentEmulation($initialEnvironmentInfo); + } if ($transformationString != false) { $transformation->withFreeform(Freeform::fromString($transformationString)); diff --git a/app/code/community/Cloudinary/Cloudinary/etc/config.xml b/app/code/community/Cloudinary/Cloudinary/etc/config.xml index cad3e20..002fd96 100644 --- a/app/code/community/Cloudinary/Cloudinary/etc/config.xml +++ b/app/code/community/Cloudinary/Cloudinary/etc/config.xml @@ -2,7 +2,7 @@ - 2.9.5 + 2.9.7 @@ -119,6 +119,7 @@ Cloudinary_Cloudinary + Mage_Eav_Model_Entity_Setup diff --git a/app/code/community/Cloudinary/Cloudinary/sql/cloudinary_setup/upgrade-2.9.6-2.9.7.php b/app/code/community/Cloudinary/Cloudinary/sql/cloudinary_setup/upgrade-2.9.6-2.9.7.php new file mode 100644 index 0000000..4c0c99c --- /dev/null +++ b/app/code/community/Cloudinary/Cloudinary/sql/cloudinary_setup/upgrade-2.9.6-2.9.7.php @@ -0,0 +1,24 @@ +startSetup(); + +$installer->addAttribute('catalog_product', 'cloudinary_data', array( + 'group' => 'General', + 'label' => 'Cloudinary Data', + 'input' => 'text', + 'type' => 'text', + 'required' => 0, + 'visible_on_front' => 0, + 'filterable' => 0, + 'searchable' => 0, + 'comparable' => 0, + 'user_defined' => 0, + 'is_configurable' => 0, + 'used_in_product_listing' => '1', + 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, + 'note' => '', +)); + +$installer->endSetup(); From 8cb5c083465705933126a841858f4da6149d2bda Mon Sep 17 00:00:00 2001 From: pini-girit Date: Tue, 12 Feb 2019 18:04:44 +0200 Subject: [PATCH 2/8] CLOUDINARY-85: Added new product attribute named cloudinary_date and saved the free transformations on that as json as well in order to reduce queries on frontend --- var/connect/Cloudinary_Cloudinary.xml | 6 +++--- var/package/package.xml | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/var/connect/Cloudinary_Cloudinary.xml b/var/connect/Cloudinary_Cloudinary.xml index afc0245..83aeda5 100644 --- a/var/connect/Cloudinary_Cloudinary.xml +++ b/var/connect/Cloudinary_Cloudinary.xml @@ -1,5 +1,5 @@ <_> - 4PxTwwcoXimxtiy4 + Eij95mpfQEtkC7Y2 Cloudinary_Cloudinary community @@ -9,7 +9,7 @@ Cloudinary supercharges your images! Upload images to the cloud, deliver optimized via a fast CDN, perform smart resizing and apply effects. MIT License (MITL) - 2.9.6 + 2.9.7 stable - Match MEQP1 coding standards @@ -41,7 +41,7 @@ - + diff --git a/var/package/package.xml b/var/package/package.xml index acc0631..8f294a9 100644 --- a/var/package/package.xml +++ b/var/package/package.xml @@ -1,7 +1,7 @@ Cloudinary_Cloudinary - 2.9.6 + 2.9.7 stable MIT License (MITL) community @@ -11,9 +11,9 @@ - Match MEQP1 coding standards Cloudinarycloudinaryaccounts+magento@cloudinary.com - 2019-01-08 - - + 2019-02-12 + + 5.4.07.2.2 From 8ba769a2f0d2623294d7105e31542ab1f621bbde Mon Sep 17 00:00:00 2001 From: pini-girit Date: Thu, 14 Feb 2019 16:18:08 +0200 Subject: [PATCH 3/8] CLOUDINARY-96: Fixed WYSIWYG images not delivered from Cloudinary on catalog descriptions --- app/code/community/Cloudinary/Cloudinary/etc/config.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/community/Cloudinary/Cloudinary/etc/config.xml b/app/code/community/Cloudinary/Cloudinary/etc/config.xml index 002fd96..fccb9d6 100644 --- a/app/code/community/Cloudinary/Cloudinary/etc/config.xml +++ b/app/code/community/Cloudinary/Cloudinary/etc/config.xml @@ -20,6 +20,7 @@ Cloudinary_Cloudinary_Model_Catalog_Product_Image Cloudinary_Cloudinary_Model_Catalog_Product_Media_Config + Cloudinary_Cloudinary_Model_Catalog_Template_Filter From 1cc5776977c001305fd23b93dbb5cebf656c147c Mon Sep 17 00:00:00 2001 From: pini-girit Date: Thu, 14 Feb 2019 16:18:16 +0200 Subject: [PATCH 4/8] CLOUDINARY-96: Fixed WYSIWYG images not delivered from Cloudinary on catalog descriptions --- .../Model/Catalog/Template/Filter.php | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 app/code/community/Cloudinary/Cloudinary/Model/Catalog/Template/Filter.php diff --git a/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Template/Filter.php b/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Template/Filter.php new file mode 100644 index 0000000..f827add --- /dev/null +++ b/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Template/Filter.php @@ -0,0 +1,79 @@ + + * @todo Needs to be reimplemented to get rid of the copypasted methods + */ +class Cloudinary_Cloudinary_Model_Catalog_Template_Filter extends Mage_Catalog_Model_Template_Filter +{ + /** + * @var ImageFactory + */ + private $imageFactory; + + /** + * @var UrlGenerator + */ + private $urlGenerator; + + /** + * @var Configuration + */ + private $configuration; + + public function __construct() + { + $this->configuration = Mage::getModel('cloudinary_cloudinary/configuration'); + if ($this->configuration->isEnabled()) { + $this->imageFactory = new ImageFactory( + $this->configuration, + Mage::getModel('cloudinary_cloudinary/synchronizationChecker') + ); + + $this->urlGenerator = new UrlGenerator( + $this->configuration, + CloudinaryImageProvider::fromConfiguration($this->configuration) + ); + } + } + + /** + * Retrieve media file URL directive + * + * @param array $construction + * @return string + * @see Mage_Core_Model_Email_Template_Filter::mediaDirective() method has been copypasted + */ + public function mediaDirective($construction) + { + if (!$this->configuration->isEnabled()) { + return parent::mediaDirective($construction); + } + + $imagePath = $this->getImagePath($construction[2]); + + $image = $this->imageFactory->build( + $imagePath, + function () use ($construction) { + return parent::mediaDirective($construction); + } + ); + + return $this->urlGenerator->generateFor($image); + } + + private function getImagePath($directiveParams) + { + $params = $this->_getIncludeParameters($directiveParams); + return $params['url']; + } +} From 007c1a8ab8a95af6ddaa28224ac77f3d8c5c6ece Mon Sep 17 00:00:00 2001 From: pini-girit Date: Thu, 14 Feb 2019 16:20:03 +0200 Subject: [PATCH 5/8] CLOUDINARY-96: Fixed WYSIWYG images not delivered from Cloudinary on catalog descriptions --- var/connect/Cloudinary_Cloudinary.xml | 8 ++------ var/package/package.xml | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/var/connect/Cloudinary_Cloudinary.xml b/var/connect/Cloudinary_Cloudinary.xml index 83aeda5..952c057 100644 --- a/var/connect/Cloudinary_Cloudinary.xml +++ b/var/connect/Cloudinary_Cloudinary.xml @@ -1,5 +1,5 @@ <_> - Eij95mpfQEtkC7Y2 + sYNY6KfwpHEJpnWx Cloudinary_Cloudinary community @@ -41,7 +41,7 @@ - + @@ -108,8 +108,4 @@ - 1 - 200 - - diff --git a/var/package/package.xml b/var/package/package.xml index 8f294a9..ae8d085 100644 --- a/var/package/package.xml +++ b/var/package/package.xml @@ -11,9 +11,9 @@ - Match MEQP1 coding standards Cloudinarycloudinaryaccounts+magento@cloudinary.com - 2019-02-12 - - + 2019-02-14 + + 5.4.07.2.2 From 62796fe7dca6c62a1a85dc0b20a13685026a3a3d Mon Sep 17 00:00:00 2001 From: pini-girit Date: Sun, 17 Mar 2019 13:57:15 +0200 Subject: [PATCH 6/8] CLOUDINARY-114: Applied fix-suggestion from Github PR#46 --- .../Cloudinary/Cloudinary/Model/Catalog/Product/Media.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Media.php b/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Media.php index a4cdb7c..f84bb7a 100644 --- a/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Media.php +++ b/app/code/community/Cloudinary/Cloudinary/Model/Catalog/Product/Media.php @@ -2,12 +2,11 @@ class Cloudinary_Cloudinary_Model_Catalog_Product_Media extends Mage_Core_Model_Abstract { - private $_newImages; public function newImagesForProduct(Mage_Catalog_Model_Product $product) { - $this->_setNewImages($product->getData('media_gallery')); + $this->_setNewImages((array)$product->getData('media_gallery')); return $this->_getNewImages($product); } @@ -52,4 +51,4 @@ private function _isImageRemoved($toFilter) { return is_array($toFilter) && array_key_exists('removed', $toFilter) && $toFilter['removed'] === 1; } -} \ No newline at end of file +} From ca45f81bf637b3aad4d27b9591fb6bcfb4cd41cc Mon Sep 17 00:00:00 2001 From: pini-girit Date: Sun, 17 Mar 2019 14:33:53 +0200 Subject: [PATCH 7/8] CLOUDINARY-103: Fixed curl on validateImageUrl() & made if less strict on configuration save (show message without exception) --- .../Cloudinary/Model/System/Config/Free.php | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/app/code/community/Cloudinary/Cloudinary/Model/System/Config/Free.php b/app/code/community/Cloudinary/Cloudinary/Model/System/Config/Free.php index 937e9d0..0d6499e 100644 --- a/app/code/community/Cloudinary/Cloudinary/Model/System/Config/Free.php +++ b/app/code/community/Cloudinary/Cloudinary/Model/System/Config/Free.php @@ -8,7 +8,7 @@ class Cloudinary_Cloudinary_Model_System_Config_Free extends Mage_Core_Model_Config_Data { - const ERROR_FORMAT = 'Incorrect custom transform - %s'; + const ERROR_FORMAT = 'Incorrect Cloudinary Transformation - %s'; const ERROR_DEFAULT = 'please update'; /** @@ -43,25 +43,41 @@ protected function _beforeSave() ->getDefaultTransformation() ->withFreeform(Freeform::fromString($this->getValue())); - $this->validateImageUrl($this->sampleImageUrl($transform)); + $this->validateImageUrl($this->sampleImageUrl($transform), false); return $this; } /** * @param string $url + * @param bool $strict Throw exception on errors + * @return bool */ - public function validateImageUrl($url) + public function validateImageUrl($url, $strict = true) { try { $response = $this->httpRequest($url); } catch (Exception $e) { - throw new Mage_Core_Exception(sprintf(self::ERROR_FORMAT, self::ERROR_DEFAULT)); + $this->setValue(null); + if ($strict) { + throw new Mage_Core_Exception(sprintf(self::ERROR_FORMAT, self::ERROR_DEFAULT)); + } else { + Mage::getSingleton('adminhtml/session')->addError(sprintf(self::ERROR_FORMAT, self::ERROR_DEFAULT)); + } + return false; } - if ($response->isError()) { - throw new Mage_Core_Exception($this->formatError($response)); + if (is_object($response) && ($response->error || !in_array($response->code, [200,301,302]))) { + $this->setValue(null); + if ($strict) { + throw new Mage_Core_Exception($this->formatError($response)); + } else { + Mage::getSingleton('adminhtml/session')->addError($this->formatError($response)); + } + return false; } + + return true; } /** @@ -79,11 +95,11 @@ public function defaultTransform($freeTransform) * @param Zend_Http_Response $response * @return string */ - public function formatError(Zend_Http_Response $response) + public function formatError($response) { return sprintf( self::ERROR_FORMAT, - $response->getStatus() == 400 ? $response->getHeader('x-cld-error') : self::ERROR_DEFAULT + (is_object($response) && isset($response->headers['x-cld-error']) && $response->headers['x-cld-error']) ? $response->headers['x-cld-error'] : self::ERROR_DEFAULT ); } @@ -93,9 +109,16 @@ public function formatError(Zend_Http_Response $response) */ public function httpRequest($url) { - $client = new Varien_Http_Client($url); - $client->setMethod(Varien_Http_Client::GET); - return $client->request(); + $curl = new Varien_Http_Adapter_Curl(); + $curl->write(Zend_Http_Client::GET, $url); + $response = $curl->read(); + $response = (object)[ + "code" => Zend_Http_Response::extractCode($response), + "body" => Zend_Http_Response::extractBody($response), + "headers" => (array) Zend_Http_Response::extractHeaders($response), + "error" => $curl->getError() + ]; + return $response; } /** From a3f0430ff57c886f76e66f267fdf07391664ccb1 Mon Sep 17 00:00:00 2001 From: pini-girit Date: Sun, 17 Mar 2019 14:35:27 +0200 Subject: [PATCH 8/8] Updated package XMLs --- var/connect/Cloudinary_Cloudinary.xml | 4 ++-- var/package/package.xml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/var/connect/Cloudinary_Cloudinary.xml b/var/connect/Cloudinary_Cloudinary.xml index 952c057..3b17ac3 100644 --- a/var/connect/Cloudinary_Cloudinary.xml +++ b/var/connect/Cloudinary_Cloudinary.xml @@ -1,5 +1,5 @@ <_> - sYNY6KfwpHEJpnWx + 3uENH8mYhOhm4EWZ Cloudinary_Cloudinary community @@ -41,7 +41,7 @@ - + diff --git a/var/package/package.xml b/var/package/package.xml index ae8d085..7060a78 100644 --- a/var/package/package.xml +++ b/var/package/package.xml @@ -11,9 +11,9 @@ - Match MEQP1 coding standards Cloudinarycloudinaryaccounts+magento@cloudinary.com - 2019-02-14 - - + 2019-03-17 + + 5.4.07.2.2