From 834e12cb094d7103ff17327d7c2097dc6581224b Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 25 Aug 2026 16:56:54 +0200 Subject: [PATCH 01/68] Init onboarding --- src/class-tiny-onboarding.php | 92 +++++++++++++++++++++++++++++++++++ src/class-tiny-plugin.php | 1 + src/views/onboarding-1.php | 6 +++ tiny-compress-images.php | 1 + 4 files changed, 100 insertions(+) create mode 100644 src/class-tiny-onboarding.php create mode 100644 src/views/onboarding-1.php diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php new file mode 100644 index 00000000..85bd0372 --- /dev/null +++ b/src/class-tiny-onboarding.php @@ -0,0 +1,92 @@ +settings = $settings; + } + + function admin_init() { + // $this->set_is_onboarded( 0 ); + if ( $this->is_new_user() && !$this->is_onboarded() ) { + // if user is new and not onboarded + $this->set_is_onboarded( 1 ); + wp_safe_redirect( admin_url( 'options-general.php?page=' . $this->onboarding_url ) ); + exit(); + } + } + + function admin_menu() { + add_submenu_page( + null, + 'Onboarding TinyPNG', + 'Welcome to TinyPNG', + 'manage_options', + $this->onboarding_url, + array( $this, 'render_onboarding_page'), + ); + } + + function render_onboarding_page() { + include __DIR__ . '/views/onboarding-1.php'; + } + + /** + * Checks if user is 'new' + * + * @return bool true if user has no compressions or api key + */ + function is_new_user() { + $api_key = $this->settings->get_api_key(); + $compression_count = $this->settings->get_compression_count(); + return empty( $api_key ) && empty($compression_count); + } + + function is_onboarded() { + $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); + return get_option( $onboarding_status_field ); + } + + /** + * Sets the onboarding status + * + * @param int $is_onboarded status + */ + function set_is_onboarded( $is_onboarded ) { + $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); + return update_option( $onboarding_status_field, $is_onboarded ); + } +} \ No newline at end of file diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index ff0708e0..9761272b 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -82,6 +82,7 @@ public function init() { ); $this->tiny_compatibility(); + new Tiny_Onboarding( $this->settings ); } public function cli_init() { diff --git a/src/views/onboarding-1.php b/src/views/onboarding-1.php new file mode 100644 index 00000000..b9bc033a --- /dev/null +++ b/src/views/onboarding-1.php @@ -0,0 +1,6 @@ +
+

Tinify Account

+

Increase performance and save space with the best + compression algorithm in WordPress.

+ settings->render_account_status(); ?> +
\ No newline at end of file diff --git a/tiny-compress-images.php b/tiny-compress-images.php index 37ccc7e0..561158f7 100644 --- a/tiny-compress-images.php +++ b/tiny-compress-images.php @@ -28,6 +28,7 @@ require dirname( __FILE__ ) . '/src/class-tiny-conversion.php'; require dirname( __FILE__ ) . '/src/class-tiny-picture.php'; require dirname( __FILE__ ) . '/src/class-tiny-apache-rewrite.php'; +require dirname( __FILE__ ) . '/src/class-tiny-onboarding.php'; require dirname( __FILE__ ) . '/src/compatibility/wpml/class-tiny-wpml.php'; require dirname( __FILE__ ) . '/src/compatibility/as3cf/class-tiny-as3cf.php'; require dirname( __FILE__ ) . '/src/compatibility/woocommerce/class-tiny-woocommerce.php'; From 858e24815398163b2054b8f3bb442c33f37b927c Mon Sep 17 00:00:00 2001 From: tijmen Date: Thu, 27 Aug 2026 11:40:14 +0200 Subject: [PATCH 02/68] onboarding scaffolding --- src/class-tiny-onboarding.php | 74 +++++++++++++++++++++++++++-------- src/class-tiny-settings.php | 10 +++++ src/css/admin.css | 7 ++++ src/js/admin.js | 12 ++++++ src/views/onboarding-1.php | 6 ++- src/views/onboarding-2.php | 1 + 6 files changed, 91 insertions(+), 19 deletions(-) create mode 100644 src/views/onboarding-2.php diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index 85bd0372..01260404 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -24,6 +24,8 @@ class Tiny_Onboarding extends Tiny_WP_Base { private $onboarding_url = 'tiny-onboarding'; + private $steps = array(1, 2); + /** * Tiny settings * @@ -40,28 +42,37 @@ public function __construct( $settings ) { } function admin_init() { - // $this->set_is_onboarded( 0 ); - if ( $this->is_new_user() && !$this->is_onboarded() ) { + if ( $this->is_onboarded() ) { // if user is new and not onboarded $this->set_is_onboarded( 1 ); - wp_safe_redirect( admin_url( 'options-general.php?page=' . $this->onboarding_url ) ); + wp_safe_redirect( $this->get_step_url( 1 ) ); exit(); } } function admin_menu() { - add_submenu_page( - null, - 'Onboarding TinyPNG', - 'Welcome to TinyPNG', - 'manage_options', - $this->onboarding_url, - array( $this, 'render_onboarding_page'), - ); - } - - function render_onboarding_page() { - include __DIR__ . '/views/onboarding-1.php'; + $title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); + + foreach ( $this->steps as $step ) { + $slug = $this->get_step_slug( $step ); + + $hook = add_submenu_page( + 'options-general.php', + $title, + $title, + 'manage_options', + $slug, + function () use ( $step ) { + include __DIR__ . '/views/onboarding-' . $step . '.php'; + } + ); + + if ( ! $hook ) { + continue; + } + + remove_submenu_page( 'options-general.php', $slug ); + } } /** @@ -70,9 +81,9 @@ function render_onboarding_page() { * @return bool true if user has no compressions or api key */ function is_new_user() { - $api_key = $this->settings->get_api_key(); + $has_api_key = $this->settings->has_api_key(); $compression_count = $this->settings->get_compression_count(); - return empty( $api_key ) && empty($compression_count); + return ! $has_api_key && empty($compression_count); } function is_onboarded() { @@ -80,6 +91,26 @@ function is_onboarded() { return get_option( $onboarding_status_field ); } + /** + * Returns the page slug of the given onboarding step + * + * @param int $step + * @return string + */ + private function get_step_slug( $step ) { + return $this->onboarding_url . '-' . $step; + } + + /** + * Retrieves the url of the given onboarding step + * + * @param int $step + * @return string + */ + public function get_step_url( $step ) { + return admin_url( 'options-general.php?page=' . $this->get_step_slug( $step ) ); + } + /** * Sets the onboarding status * @@ -89,4 +120,13 @@ function set_is_onboarded( $is_onboarded ) { $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); return update_option( $onboarding_status_field, $is_onboarded ); } + + function render_register() { + $compressor = $this->settings->get_compressor(); + if ( $compressor->can_create_key() ) { + include __DIR__ . '/views/account-status-create-advanced.php'; + } else { + include __DIR__ . '/views/account-status-create-simple.php'; + } + } } \ No newline at end of file diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 342f9d8e..dba27600 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -227,6 +227,16 @@ protected function get_api_key_pending() { } } + public function has_api_key() { + $api_key = $this->get_api_key(); + if ( empty($api_key) ) { + return false; + } + + $pending_key = $this->get_api_key_pending(); + return !empty( $pending_key ); + } + protected function clear_api_key_pending() { delete_option( self::get_prefixed_name( 'api_key_pending' ) ); } diff --git a/src/css/admin.css b/src/css/admin.css index 977dadf1..1992d8e5 100644 --- a/src/css/admin.css +++ b/src/css/admin.css @@ -481,4 +481,11 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-mt-2 { margin-top: 10px; +} + +.tiny-onboarding { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; } \ No newline at end of file diff --git a/src/js/admin.js b/src/js/admin.js index 03312c0a..180dd4b2 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -170,6 +170,13 @@ var status = jQuery.parseJSON(json); if (status.ok) { + // when in onboarding + const nextStep = jQuery('#tiny-onboarding-step').data('next-step'); + if (nextStep) { + window.location = nextStep; + return; + } + var target = jQuery('#tiny-account-status'); if (target.length) { jQuery.get(ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_account_status', function(data) { @@ -295,6 +302,7 @@ }); } + console.log('adminpage:', adminpage); switch (adminpage) { case 'upload-php': eventOn('click', 'button.tiny-compress', compressImage); @@ -312,6 +320,10 @@ case 'post-php': eventOn('click', 'button.tiny-compress', compressImage); break; + case 'settings_page_tiny-onboarding': + eventOn('click', '[data-tiny-action=create-key]', submitKey); + eventOn('click', '[data-tiny-action=update-key]', submitKey); + break; case 'settings_page_tinify': changeEnterKeyTarget('div.tiny-account-status create', '[data-tiny-action=create-key]'); changeEnterKeyTarget('div.tiny-account-status update', '[data-tiny-action=update-key]'); diff --git a/src/views/onboarding-1.php b/src/views/onboarding-1.php index b9bc033a..3b3882df 100644 --- a/src/views/onboarding-1.php +++ b/src/views/onboarding-1.php @@ -1,6 +1,8 @@ -
+

Tinify Account

Increase performance and save space with the best compression algorithm in WordPress.

- settings->render_account_status(); ?> +
+ settings->render_account_status(); ?> +
\ No newline at end of file diff --git a/src/views/onboarding-2.php b/src/views/onboarding-2.php new file mode 100644 index 00000000..89435c7c --- /dev/null +++ b/src/views/onboarding-2.php @@ -0,0 +1 @@ +

test

\ No newline at end of file From 57eda31ca6a917cb79eda125d36bcc5b455b803e Mon Sep 17 00:00:00 2001 From: tijmen Date: Thu, 27 Aug 2026 12:12:48 +0200 Subject: [PATCH 03/68] format --- src/class-tiny-settings.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index dba27600..d24823ac 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -229,12 +229,12 @@ protected function get_api_key_pending() { public function has_api_key() { $api_key = $this->get_api_key(); - if ( empty($api_key) ) { + if ( empty( $api_key ) ) { return false; } $pending_key = $this->get_api_key_pending(); - return !empty( $pending_key ); + return ! empty( $pending_key ); } protected function clear_api_key_pending() { From 20e022126662dce204a02f685301e64d84a4e7de Mon Sep 17 00:00:00 2001 From: tijmen Date: Thu, 27 Aug 2026 12:13:59 +0200 Subject: [PATCH 04/68] use onboarding flag --- src/class-tiny-onboarding.php | 179 +++++++++++++++++----------------- src/views/onboarding-1.php | 12 +-- tiny-compress-images.php | 2 + 3 files changed, 97 insertions(+), 96 deletions(-) diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index 01260404..382b863c 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -21,112 +21,111 @@ /** * Class responsible for onboarding a new user */ - class Tiny_Onboarding extends Tiny_WP_Base { +class Tiny_Onboarding extends Tiny_WP_Base { + + private $onboarding_url = 'tiny-onboarding'; + private $steps = array( 1, 2 ); - private $onboarding_url = 'tiny-onboarding'; - private $steps = array(1, 2); - /** * Tiny settings * * @var Tiny_Settings */ - private $settings; + private $settings; /** * @param Tiny_Settings $settings */ - public function __construct( $settings ) { - parent::__construct(); - $this->settings = $settings; - } - - function admin_init() { - if ( $this->is_onboarded() ) { - // if user is new and not onboarded - $this->set_is_onboarded( 1 ); - wp_safe_redirect( $this->get_step_url( 1 ) ); - exit(); - } - } - - function admin_menu() { - $title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); - - foreach ( $this->steps as $step ) { - $slug = $this->get_step_slug( $step ); - - $hook = add_submenu_page( - 'options-general.php', - $title, - $title, - 'manage_options', - $slug, - function () use ( $step ) { - include __DIR__ . '/views/onboarding-' . $step . '.php'; - } - ); - - if ( ! $hook ) { - continue; - } - - remove_submenu_page( 'options-general.php', $slug ); - } - } + public function __construct( $settings ) { + parent::__construct(); + $this->settings = $settings; + } + + function admin_init() { + if ( $this->is_onboarded() ) { + // if user is not onboarded + $this->set_is_onboarded( 1 ); + wp_safe_redirect( $this->get_step_url( 1 ) ); + exit(); + } + } + + function admin_menu() { + $title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); + + foreach ( $this->steps as $step ) { + $slug = $this->get_step_slug( $step ); + + $hook = add_submenu_page( + 'options-general.php', + $title, + $title, + 'manage_options', + $slug, + function () use ( $step ) { + include __DIR__ . '/views/onboarding-' . $step . '.php'; + } + ); + + if ( ! $hook ) { + continue; + } + + remove_submenu_page( 'options-general.php', $slug ); + } + } /** - * Checks if user is 'new' + * Checks wether user is onboarded + * defaults to true * - * @return bool true if user has no compressions or api key + * @return boolean true if onboarded */ - function is_new_user() { - $has_api_key = $this->settings->has_api_key(); - $compression_count = $this->settings->get_compression_count(); - return ! $has_api_key && empty($compression_count); - } - - function is_onboarded() { - $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); - return get_option( $onboarding_status_field ); - } - - /** - * Returns the page slug of the given onboarding step - * - * @param int $step - * @return string - */ - private function get_step_slug( $step ) { - return $this->onboarding_url . '-' . $step; - } - - /** - * Retrieves the url of the given onboarding step - * - * @param int $step - * @return string - */ - public function get_step_url( $step ) { - return admin_url( 'options-general.php?page=' . $this->get_step_slug( $step ) ); - } + function is_onboarded() { + $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); + return 1 === get_option( $onboarding_status_field, 1 ); + } + + /** + * Returns the page slug of the given onboarding step + * + * @param int $step + * @return string + */ + private function get_step_slug( $step ) { + return $this->onboarding_url . '-' . $step; + } + + /** + * Retrieves the url of the given onboarding step + * + * @param int $step + * @return string + */ + public function get_step_url( $step ) { + return admin_url( 'options-general.php?page=' . $this->get_step_slug( $step ) ); + } /** * Sets the onboarding status * - * @param int $is_onboarded status + * @param int $is_onboarded status */ - function set_is_onboarded( $is_onboarded ) { - $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); - return update_option( $onboarding_status_field, $is_onboarded ); - } - - function render_register() { - $compressor = $this->settings->get_compressor(); - if ( $compressor->can_create_key() ) { - include __DIR__ . '/views/account-status-create-advanced.php'; - } else { - include __DIR__ . '/views/account-status-create-simple.php'; - } - } -} \ No newline at end of file + static function set_is_onboarded( $is_onboarded ) { + $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); + return update_option( $onboarding_status_field, $is_onboarded ); + } + + function render_register() { + $compressor = $this->settings->get_compressor(); + if ( $compressor->can_create_key() ) { + include __DIR__ . '/views/account-status-create-advanced.php'; + } else { + include __DIR__ . '/views/account-status-create-simple.php'; + } + } + + static function on_activate() { + self::set_is_onboarded( 0 ); + } +} diff --git a/src/views/onboarding-1.php b/src/views/onboarding-1.php index 3b3882df..d25e4ce9 100644 --- a/src/views/onboarding-1.php +++ b/src/views/onboarding-1.php @@ -1,8 +1,8 @@
-

Tinify Account

-

Increase performance and save space with the best - compression algorithm in WordPress.

-
- settings->render_account_status(); ?> -
+

Tinify Account

+

Increase performance and save space with the best + compression algorithm in WordPress.

+
+ settings->render_account_status(); ?> +
\ No newline at end of file diff --git a/tiny-compress-images.php b/tiny-compress-images.php index 561158f7..ca34d7ce 100644 --- a/tiny-compress-images.php +++ b/tiny-compress-images.php @@ -47,3 +47,5 @@ __FILE__, array( 'Tiny_Plugin', 'uninstall' ) ); + +register_activation_hook(__FILE__, array('Tiny_Onboarding', 'on_activate') ); \ No newline at end of file From fccfe39a1626025539901bc6d4097485349f5172 Mon Sep 17 00:00:00 2001 From: tijmen Date: Thu, 27 Aug 2026 13:18:17 +0200 Subject: [PATCH 05/68] transport to step 2 on api key registration --- src/class-tiny-onboarding.php | 24 ++++++++++++++++++------ src/js/admin.js | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index 382b863c..48cc29bc 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -43,11 +43,12 @@ public function __construct( $settings ) { function admin_init() { if ( $this->is_onboarded() ) { - // if user is not onboarded - $this->set_is_onboarded( 1 ); - wp_safe_redirect( $this->get_step_url( 1 ) ); - exit(); + return; } + + $this->set_is_onboarded( 1 ); + wp_safe_redirect( $this->get_step_url( 1 ) ); + exit(); } function admin_menu() { @@ -83,7 +84,7 @@ function () use ( $step ) { */ function is_onboarded() { $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); - return 1 === get_option( $onboarding_status_field, 1 ); + return 1 === (int) get_option( $onboarding_status_field, 1 ); } /** @@ -125,7 +126,18 @@ function render_register() { } } + /** + * Decides on activation whether this site still needs onboarding. + * + * A site that already has a key, or that has compressed before, keeps the + * default onboarded state so it is never sent through onboarding again. + */ static function on_activate() { - self::set_is_onboarded( 0 ); + $api_key = get_option( self::get_prefixed_name( 'api_key' ) ); + $compression_count = get_option( self::get_prefixed_name( 'status' ) ); + + if ( empty( $api_key ) && empty( $compression_count ) ) { + self::set_is_onboarded( 0 ); + } } } diff --git a/src/js/admin.js b/src/js/admin.js index 180dd4b2..fb4a1369 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -320,7 +320,7 @@ case 'post-php': eventOn('click', 'button.tiny-compress', compressImage); break; - case 'settings_page_tiny-onboarding': + case 'settings_page_tiny-onboarding-1': eventOn('click', '[data-tiny-action=create-key]', submitKey); eventOn('click', '[data-tiny-action=update-key]', submitKey); break; From c0860e075025b83d5b95972bd8ae47ad2fe3de1a Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 1 Sep 2026 17:33:50 +0200 Subject: [PATCH 06/68] onboarding --- src/class-tiny-onboarding.php | 63 +++++++++++++++++++++++++++++---- src/class-tiny-settings.php | 2 +- src/css/admin.css | 10 ++++++ src/js/admin.js | 30 ++++++++++++---- src/views/onboarding-1.php | 22 +++++++++--- src/views/onboarding-2.php | 65 ++++++++++++++++++++++++++++++++++- 6 files changed, 172 insertions(+), 20 deletions(-) diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index 48cc29bc..97887def 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -23,8 +23,17 @@ */ class Tiny_Onboarding extends Tiny_WP_Base { - private $onboarding_url = 'tiny-onboarding'; - private $steps = array( 1, 2 ); + /** + * Prefix of every onboarding step page slug. + * + * @var string + */ + const PAGE_SLUG = 'tiny-onboarding'; + + /** + * @var string + */ + private $page_title; /** * Tiny settings @@ -47,20 +56,34 @@ function admin_init() { } $this->set_is_onboarded( 1 ); + + if ( self::is_bulk_activation() ) { + return; + } + wp_safe_redirect( $this->get_step_url( 1 ) ); exit(); } + /** + * Onboarding is skipped when activating multiple plugins + * + * @return bool + */ + private static function is_bulk_activation() { + return filter_has_var( INPUT_GET, 'activate-multi' ); + } + function admin_menu() { - $title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); + $this->page_title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); foreach ( $this->steps as $step ) { $slug = $this->get_step_slug( $step ); $hook = add_submenu_page( 'options-general.php', - $title, - $title, + $this->page_title, + $this->page_title, 'manage_options', $slug, function () use ( $step ) { @@ -73,9 +96,24 @@ function () use ( $step ) { } remove_submenu_page( 'options-general.php', $slug ); + + /** + * because title is retrieved from submenu, which is not part of the menu, + * resolve it through globals + */ + add_action( 'load-' . $hook, $this->get_method( 'set_page_title' ) ); } } + /** + * Supplies the title of a page that is not listed in the menu. + * + * Hooked to `load-{$hook}` of every onboarding step. + */ + public function set_page_title() { + $GLOBALS['title'] = $this->page_title; + } + /** * Checks wether user is onboarded * defaults to true @@ -94,7 +132,20 @@ function is_onboarded() { * @return string */ private function get_step_slug( $step ) { - return $this->onboarding_url . '-' . $step; + return self::PAGE_SLUG . '-' . $step; + } + + /** + * Whether the current admin request is one of the onboarding steps. + * + * Reads the page WordPress itself resolved, so no request input is touched. + * + * @return bool + */ + public static function is_onboarding_page() { + $page = isset( $GLOBALS['plugin_page'] ) ? $GLOBALS['plugin_page'] : ''; + + return 0 === strpos( $page, self::PAGE_SLUG . '-' ); } /** diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index d24823ac..39ebe67f 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -108,7 +108,7 @@ public function admin_init() { ); } - if ( current_user_can( 'manage_options' ) ) { + if ( current_user_can( 'manage_options' ) && ! Tiny_Onboarding::is_onboarding_page() ) { $this->setup_incomplete_checks(); } diff --git a/src/css/admin.css b/src/css/admin.css index 1992d8e5..acd2a259 100644 --- a/src/css/admin.css +++ b/src/css/admin.css @@ -488,4 +488,14 @@ fieldset.tinypng_convert_fields[disabled] { flex-direction: column; justify-content: center; align-items: center; +} + +.tiny-card { + background: #fff; + border: 1px solid #E1E1E1; + border-radius: 8px; + padding: 12px; +} +.tiny-text-center { + text-align: center; } \ No newline at end of file diff --git a/src/js/admin.js b/src/js/admin.js index fb4a1369..8c2f7033 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -135,6 +135,22 @@ return false; } + /** + * Does nothing outside of onboarding + * If key is active, shows continue button + */ + function updateOnboardingContinue() { + const button = jQuery('#tiny-onboarding-continue'); + if (!button.length) { + return; + } + + const status = jQuery('#tiny-account-status p.status').closest('div.status'); + const valid = status.hasClass('status-success') || status.hasClass('status-pending'); + + button.toggle(valid); + } + function submitKey(event) { event.preventDefault(); jQuery(event.target).attr({disabled: true}).addClass('loading'); @@ -170,18 +186,13 @@ var status = jQuery.parseJSON(json); if (status.ok) { - // when in onboarding - const nextStep = jQuery('#tiny-onboarding-step').data('next-step'); - if (nextStep) { - window.location = nextStep; - return; - } - var target = jQuery('#tiny-account-status'); if (target.length) { jQuery.get(ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_account_status', function(data) { jQuery(event.target).attr({disabled: false}).removeClass('loading'); target.replaceWith(data); + // The refreshed markup reports whether the key actually works. + updateOnboardingContinue(); }); } jQuery('div.tiny-notice[data-name="setting"]').remove(); @@ -321,8 +332,13 @@ eventOn('click', 'button.tiny-compress', compressImage); break; case 'settings_page_tiny-onboarding-1': + changeEnterKeyTarget('div.tiny-account-status create', '[data-tiny-action=create-key]'); + changeEnterKeyTarget('div.tiny-account-status update', '[data-tiny-action=update-key]'); + eventOn('click', '[data-tiny-action=create-key]', submitKey); eventOn('click', '[data-tiny-action=update-key]', submitKey); + + updateOnboardingContinue(); break; case 'settings_page_tinify': changeEnterKeyTarget('div.tiny-account-status create', '[data-tiny-action=create-key]'); diff --git a/src/views/onboarding-1.php b/src/views/onboarding-1.php index d25e4ce9..c6b8fa3c 100644 --- a/src/views/onboarding-1.php +++ b/src/views/onboarding-1.php @@ -1,8 +1,20 @@
-

Tinify Account

-

Increase performance and save space with the best - compression algorithm in WordPress.

-
+

+

+ +

+
settings->render_account_status(); ?>
-
\ No newline at end of file + +
diff --git a/src/views/onboarding-2.php b/src/views/onboarding-2.php index 89435c7c..c933515f 100644 --- a/src/views/onboarding-2.php +++ b/src/views/onboarding-2.php @@ -1 +1,64 @@ -

test

\ No newline at end of file + + +
+

+

+ +
+ +

+ +
+

+ + > + +

+

+ + > + +

+
+ +

+ + + +

+

+ + + +

+
From 873a8444fe1e894f0a1f8b944313fac3212b2980 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 8 Sep 2026 12:48:59 +0200 Subject: [PATCH 07/68] simplify menu registration --- src/class-tiny-onboarding.php | 60 ++++++++++++++++++++--------------- src/js/admin.js | 1 - 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index 97887def..36674ada 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -74,35 +74,43 @@ private static function is_bulk_activation() { return filter_has_var( INPUT_GET, 'activate-multi' ); } - function admin_menu() { - $this->page_title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); - - foreach ( $this->steps as $step ) { - $slug = $this->get_step_slug( $step ); - - $hook = add_submenu_page( - 'options-general.php', - $this->page_title, - $this->page_title, - 'manage_options', - $slug, - function () use ( $step ) { - include __DIR__ . '/views/onboarding-' . $step . '.php'; - } - ); - - if ( ! $hook ) { - continue; + /** + * Set the sub menu pages + * + * @param int $step onboarding step + */ + private function add_sub_menu( $step ) { + $slug = $this->get_step_slug( $step ); + + $hook = add_submenu_page( + 'options-general.php', + $this->page_title, + $this->page_title, + 'manage_options', + $slug, + function () use ( $step ) { + include __DIR__ . '/views/onboarding-' . $step . '.php'; } + ); - remove_submenu_page( 'options-general.php', $slug ); - - /** - * because title is retrieved from submenu, which is not part of the menu, - * resolve it through globals - */ - add_action( 'load-' . $hook, $this->get_method( 'set_page_title' ) ); + if ( ! $hook ) { + return; } + + remove_submenu_page( 'options-general.php', $slug ); + + /** + * because title is retrieved from submenu, which is not part of the menu, + * resolve it through globals + */ + add_action( 'load-' . $hook, $this->get_method( 'set_page_title' ) ); + } + + function admin_menu() { + $this->page_title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); + + $this->add_sub_menu(1); + $this->add_sub_menu(2); } /** diff --git a/src/js/admin.js b/src/js/admin.js index 8c2f7033..f971aa75 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -313,7 +313,6 @@ }); } - console.log('adminpage:', adminpage); switch (adminpage) { case 'upload-php': eventOn('click', 'button.tiny-compress', compressImage); From e7cdf578ced87cb6f7bb4c84a9d1660da8b6f376 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 23 Sep 2026 09:22:33 +0200 Subject: [PATCH 08/68] update dashboard widget --- src/class-tiny-dashboard.php | 111 ++++++++++++++++++ src/class-tiny-plugin.php | 55 +-------- src/css/admin.css | 4 + src/css/dashboard-widget.css | 179 ++++++++++++++---------------- src/js/dashboard-widget.js | 125 --------------------- src/views/dashboard-widget.php | 167 ++++++++++++---------------- src/views/progress-circle.php | 76 +++++++++++++ test/unit/Tiny_Dashboard_Test.php | 84 ++++++++++++++ tiny-compress-images.php | 1 + 9 files changed, 434 insertions(+), 368 deletions(-) create mode 100644 src/class-tiny-dashboard.php delete mode 100644 src/js/dashboard-widget.js create mode 100644 src/views/progress-circle.php create mode 100644 test/unit/Tiny_Dashboard_Test.php diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php new file mode 100644 index 00000000..79b77d07 --- /dev/null +++ b/src/class-tiny-dashboard.php @@ -0,0 +1,111 @@ +settings = $settings; + } + + public function admin_init() { + add_action( + 'wp_dashboard_setup', + $this->get_method( 'add_dashboard_widget' ) + ); + } + + public function add_dashboard_widget() { + wp_enqueue_style( + self::NAME . '_dashboard_widget', + plugins_url( '/css/dashboard-widget.css', __FILE__ ), + array(), + self::wp_version(), + ); + + wp_add_dashboard_widget( + $this->get_prefixed_name( 'dashboard_widget' ), + esc_html__( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' ), + $this->get_method( 'add_widget_view' ) + ); + } + + public function add_widget_view() { + $optimization_statistics = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); + $widget = self::get_widget_data( $optimization_statistics ); + include __DIR__ . '/views/dashboard-widget.php'; + } + + /** + * Logic for the view + * + * @param array $optimization_stats See Tiny_Bulk_Optimization::get_optimization_statistics(). + * @return array + */ + public static function get_widget_data( $optimization_stats ) { + $images_remaining = count( $optimization_stats['available-for-optimization'] ); + $bytes_total = $optimization_stats['unoptimized-library-size']; + $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); + + $images_optimized = $images_total - $images_remaining; + $images_optimized = max( 0, intval( $images_optimized ) ); + $images_remaining = max( 0, $images_total - $images_optimized ); + $bytes_saved = $bytes_total - $optimization_stats['optimized-library-size']; + + $percentage = $images_total > 0 + ? intval( floor( $images_optimized / $images_total * 100 ) ) + : 0; + $percentage = max( 0, min( 100, $percentage ) ); + + if ( 0 === $images_total ) { + $status = 'empty'; + $label = ''; + $panda = 'panda-waiting.png'; + } elseif ( 0 === $images_remaining ) { + $status = 'done'; + $label = __( 'all done', 'tiny-compress-images' ); + $panda = 'panda-laying.png'; + } else { + $status = 'in_progress'; + $label = $percentage >= 50 + ? __( 'almost there', 'tiny-compress-images' ) + : __( 'keep going', 'tiny-compress-images' ); + $panda = 'panda-eating.png'; + } + + return array( + 'status' => $status, + 'images_optimized' => $images_optimized, + 'images_total' => $images_total, + 'images_remaining' => $images_remaining, + 'bytes_saved' => max( 0, intval( $bytes_saved ) ), + 'percentage' => $percentage, + 'label' => $label, + 'panda' => $panda, + ); + } +} diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index 4c567bf7..0fc7ef7c 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -42,6 +42,7 @@ public function __construct() { parent::__construct(); $this->settings = new Tiny_Settings(); new Tiny_Conversion( $this->settings ); + new Tiny_Dashboard( $this->settings ); } public function set_compressor( $compressor ) { @@ -157,11 +158,6 @@ public function ajax_init() { } public function admin_init() { - add_action( - 'wp_dashboard_setup', - $this->get_method( 'add_dashboard_widget' ) - ); - add_action( 'admin_enqueue_scripts', $this->get_method( 'enqueue_scripts' ) @@ -819,55 +815,6 @@ public function render_bulk_optimization_page() { include __DIR__ . '/views/bulk-optimization.php'; } - public function add_dashboard_widget() { - wp_enqueue_style( - self::NAME . '_chart', - plugins_url( '/css/optimization-chart.css', __FILE__ ), - array(), - self::version() - ); - - wp_enqueue_style( - self::NAME . '_dashboard_widget', - plugins_url( '/css/dashboard-widget.css', __FILE__ ), - array(), - self::version() - ); - - wp_register_script( - self::NAME . '_dashboard_widget', - plugins_url( '/js/dashboard-widget.js', __FILE__ ), - array(), - self::version(), - true - ); - - /* - This might be deduplicated with the admin script localization, but - the order of including scripts is sometimes different. So in that - case we need to make sure that the order of inclusion is correct. */ - wp_localize_script( - self::NAME . '_dashboard_widget', - 'tinyCompressDashboard', - array( - 'nonce' => wp_create_nonce( 'tiny-compress' ), - ) - ); - - wp_enqueue_script( self::NAME . '_dashboard_widget' ); - - wp_add_dashboard_widget( - $this->get_prefixed_name( 'dashboard_widget' ), - esc_html__( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' ), - $this->get_method( 'add_widget_view' ) - ); - } - - public function add_widget_view() { - $admin_colors = self::retrieve_admin_colors(); - include __DIR__ . '/views/dashboard-widget.php'; - } - private static function retrieve_admin_colors() { global $_wp_admin_css_colors; $admin_colour_scheme = get_user_option( 'admin_color', get_current_user_id() ); diff --git a/src/css/admin.css b/src/css/admin.css index bad18a87..40b2a869 100644 --- a/src/css/admin.css +++ b/src/css/admin.css @@ -1,3 +1,7 @@ +:root { + --tiny-color-text-muted: #6a7282 +} + div.misc-pub-section.tiny-compress-images { border-top: 1px solid #e1e1e1; padding-bottom: 16px; diff --git a/src/css/dashboard-widget.css b/src/css/dashboard-widget.css index bf4b9a80..7e0d3ae8 100644 --- a/src/css/dashboard-widget.css +++ b/src/css/dashboard-widget.css @@ -1,129 +1,118 @@ -div.tiny_dashboard_widget div.inside { - min-height: 200px; +#tinypng_dashboard_widget .inside { margin: 0; - padding-bottom: 0; - overflow: hidden; + padding: 0; } -div.tiny_dashboard_widget div.inside div.spinner { - position: absolute; - visibility: visible; - z-index: 10; - top: 30%; - left: 50%; - margin-left: -12px; +.tiny-widget { + color: var(--tiny-color-text-muted); + font-size: 13px; + line-height: 20px; } -div.tiny_dashboard_widget div.inside div.sky { - position: absolute; - left: 0; - top: 0; - height: 100%; - width: 100%; - opacity: 0.3; - background: linear-gradient(180deg, #c6dde4 0%, #fefeff 100%); - /* ie6-9 */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#33C6DDE4', endColorstr='#33FEFEFF',GradientType=0 ); +.tiny-widget-bulk { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + padding: 20px; + text-align: center; } -div.tiny_dashboard_widget div.inside div.cloud { - position: absolute; - right: 0; - top: 0; - height: 240px; - width: 298px; - background-image: url("../images/cloud.png"); - background-size: cover; +.tiny-widget-bulk strong { + color: #1e1e1e; } -div.tiny_dashboard_widget div.inside div.grass { - position: absolute; - right: 0; - bottom: 0; - height: 24px; - width: 536px; - background-image: url("../images/grass.png"); - background-size: cover; +a.tiny-widget-bulk-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 10px; + width: 209px; + padding: 15px 0; + background: #3858e9; + color: #fff; + font-size: 15px; + font-weight: bold; + line-height: normal; + text-decoration: none; } -div.tiny_dashboard_widget div.inside div.panda { - position: absolute; - bottom: 0; - background-repeat: no-repeat; - -webkit-background-size: 100%; - background-size: cover; - background-position: bottom; +a.tiny-widget-bulk-button:hover, +a.tiny-widget-bulk-button:focus { + background: #2145e6; + color: #fff; } -div.tiny_dashboard_widget.full-optimized div.inside div.panda { - right: 10%; - width: 305px; - height: 105.5px; - margin-right: 0; - background-image: url("../images/panda-laying.png"); +.tiny-widget-body { + display: flex; + align-items: flex-end; + justify-content: space-between; } -div.tiny_dashboard_widget.half-optimized div.inside div.panda { - right: -230px; - width: 255px; - height: 203px; - margin-right: 45%; - background-image: url("../images/panda-eating.png"); +.tiny-widget-main { + display: flex; + flex-direction: column; + align-self: stretch; + justify-content: space-between; + min-width: 0; } -div.tiny_dashboard_widget.not-optimized div.inside div.panda, -div.tiny_dashboard_widget.no-images-uploaded div.inside div.panda { - right: -196px; - width: 241px; - height: 203px; - margin-right: 45%; - background-image: url("../images/panda-waiting.png"); +.tiny-widget-progress { + display: flex; + align-items: center; + gap: 20px; } -div.tiny_dashboard_widget.no-images-uploaded div.inside div.no-images, -div.tiny_dashboard_widget.not-optimized div.inside div.not-optimized, -div.tiny_dashboard_widget.half-optimized div.inside div.half-optimized, -div.tiny_dashboard_widget.full-optimized div.inside div.full-optimized { - display: block !important; - position: relative; - z-index: 1; +.tiny-widget-progress, +.tiny-widget-main > .tiny-widget-stats { + padding: 20px; } -div.tiny_dashboard_widget div.inside div#optimization-chart { - margin-top: 12px; - margin-bottom: 40px; - min-width: 160px; +.tiny-widget-stats { + display: flex; + flex-direction: column; + gap: 5px; + line-height: 17px; } -div.tiny_dashboard_widget.full-optimized div.inside.mobile div#optimization-chart { - width: 100%; - margin-top: -5px; - margin-bottom: 95px; +.tiny-widget-title { + color: #030712; + font-size: 16px; } -.ie8 div.tiny_dashboard_widget div.inside div.panda { - background: none; +.tiny-widget-nav { + display: flex; + align-items: center; + padding: 10px 20px; + font-size: 12px; + font-weight: bold; + line-height: 17px; } -.ie8 div.tiny_dashboard_widget div.inside div.grass { - width: 100%; - background-image: url("../images/grass-ie8.png"); - background-repeat: no-repeat; - background-position: bottom; +.tiny-widget-nav a { + color: #3858e9; + text-decoration: none; } -.ie8 div.tiny_dashboard_widget div.inside div#optimization-chart { - display: none; +.tiny-widget-nav a + a { + margin-left: 10px; + padding-left: 10px; + border-left: 1px solid #ccc; } -.ie8 div.tiny_dashboard_widget.no-images-uploaded div.inside div#ie8-compressed, -.ie8 div.tiny_dashboard_widget.not-optimized div.inside div#ie8-compressed, -.ie8 div.tiny_dashboard_widget.half-optimized div.inside div#ie8-compressed, -.ie8 div.tiny_dashboard_widget.full-optimized div.inside div#ie8-compressed { - display: block !important; - position: relative; - z-index: 1; +.tiny-widget-panda { + flex-shrink: 0; + width: 213px; + height: auto; + padding: 0 12px; } -#tinypng_dashboard_widget > button.handlediv { - margin-top: 0; +.tiny-widget-panda-eating { + transform: scaleX(-1); +} + +@media (max-width: 480px) { + .tiny-widget-panda { + display: none; + } } diff --git a/src/js/dashboard-widget.js b/src/js/dashboard-widget.js deleted file mode 100644 index 0bd39aa1..00000000 --- a/src/js/dashboard-widget.js +++ /dev/null @@ -1,125 +0,0 @@ -(function() { - function generateDashboardWidget(element) { - element = jQuery(element); - var container = element.find('.inside'); - jQuery('.chart').addClass('hidden'); - // Adding a class to the widget element so that classes are only used in the stylesheet - jQuery('#tinypng_dashboard_widget').addClass('tiny_dashboard_widget'); - attachHandlers(container); - retrieveStats(container); - } - - function retrieveStats(container) { - jQuery.ajax({ - url: ajaxurl, - type: 'POST', - data: { - _nonce: tinyCompressDashboard.nonce, - action: 'tiny_get_optimization_statistics', - id: '#tinypng_dashboard_widget' - }, - success: function(data) { - if (data === 0) { - container.append('

An error occured.

'); - } else { - renderWidget(data); - } - }, - error: function() { - container.append('

An error occured.

'); - } - }); - } - - function attachHandlers(container) { - setContainerClass(container); - jQuery(window).resize(function(){ - setContainerClass(container); - }); - jQuery('#tinypng_dashboard_widget .hndle').click(function() { - jQuery(this).siblings('.inside').removeClass('mobile'); - }); - } - - function setContainerClass(container) { - if (jQuery(container).width() < 400) { - jQuery(container).addClass('mobile'); - } else if (jQuery(container).width() < 490 && jQuery(container).width() >= 400) { - jQuery(container).addClass('tablet'); - jQuery(container).removeClass('mobile'); - } else if (jQuery(container).width() >= 490) { - jQuery(container).removeClass('tablet').removeClass('mobile'); - } - } - - function renderWidget(data) { - var stats = jQuery.parseJSON(data); - if (stats !== null) { - var savings = stats['display-percentage']; - var libraryOptimized = optimizedPercentage(stats); - renderContent(libraryOptimized, stats, savings); - renderChart(savings); - jQuery('#optimization-chart').show(); - } - jQuery('#widget-spinner').attr('class', 'hidden'); - } - - function renderPercentage(percentage) { - jQuery('#savings-percentage').find('span').html(percentage); - } - - function renderContent(percentage, stats, savingsPercentage) { - renderPercentage(savingsPercentage); - if ( 0 === stats['uploaded-images'] + stats['available-unoptimized-sizes'] ) { - jQuery('#tinypng_dashboard_widget').addClass('no-images-uploaded'); - } else if ( percentage === 0 ) { - jQuery('#tinypng_dashboard_widget').addClass('not-optimized'); - } else if ( percentage === 100 ) { - jQuery('#tinypng_dashboard_widget').addClass('full-optimized'); - } else { - jQuery('#uploaded-images').html( stats['uploaded-images'] ); - jQuery('#unoptimized-sizes').html( stats['available-unoptimized-sizes'] ); - jQuery('#tinypng_dashboard_widget').addClass('half-optimized'); - } - jQuery('#ie8-compressed').find('span').html(savingsPercentage); - } - - function chartOptions(percentage) { - var chart = {}; - chart.size = 160; - chart.radius = chart.size / 2 * 0.9; - chart['main-radius'] = chart.radius * 0.88; - chart['circle-size'] = 2 * Math.PI * chart['main-radius']; - chart['dash-array-size'] = percentage / 100 * chart['circle-size']; - return chart; - } - - function optimizedPercentage(stats) { - if ( 0 !== stats['unoptimized-library-size'] ) { - return Math.round((stats['optimized-image-sizes'] / (stats['optimized-image-sizes'] + stats['available-unoptimized-sizes']) * 100), 0); - } else { - return 0; - } - } - - function renderChart(savingsPercentage) { - var chart = chartOptions(savingsPercentage); - jQuery('#optimization-chart svg circle.main').css('stroke-dasharray', chart['dash-array-size'] + ' ' + chart['circle-size']); - var style = - ' @keyframes shwoosh {' + - ' from { stroke-dasharray: 0 ' + chart['circle-size'] + '}' + - ' to { stroke-dasharray:' + chart['dash-array-size'] + ' ' + chart['circle-size'] + '}}'; - - // JQuery bug where you cannot append to style tag https://bugs.jquery.com/ticket/9832 - try { - jQuery('#tinypng_dashboard_widget .inside style').append(style); - } catch(err) { - - } - } - - // Check if widget is loaded - if (jQuery('#tinypng_dashboard_widget').length) { - generateDashboardWidget('#tinypng_dashboard_widget'); - } -}).call(); diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index 5cc866b6..43cfc7b4 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -3,102 +3,81 @@ /** * Dashboard Widget * - * @var array $admin_colors + * @var array $widget See Tiny_Dashboard::get_widget_data(). * */ -$link = '' . esc_html__( 'bulk optimization', 'tiny-compress-images' ) . ''; +$percentage = $widget['percentage']; +$label = $widget['label']; + +$bulk_url = admin_url('upload.php?page=tiny-bulk-optimization'); +$settings_url = admin_url('options-general.php?page=tinify'); ?> - -
-
-
-
-
-
-

-
-
-

- friendly_user_name() ) ); - echo ' '; - printf( - wp_kses( - /* translators: %s: bulk optimization page */ - __( 'If you like you can to optimize your whole library in one go with the %s page.', 'tiny-compress-images' ), - array( - 'a' => array( - 'href' => array(), - ), - ) - ), - wp_kses( $link, array( 'a' => array( 'href' => array() ) ) ) - ); - ?> -

-
-
-

- friendly_user_name() ) ); - echo ' '; - /* translators: %s: number of optimizable sizes and number of uploaded images */ - printf( esc_html__( 'With your current settings you can still optimize %1$s image sizes from your %2$s uploaded JPEG, PNG, and WebP images.', 'tiny-compress-images' ), '', '' ); - echo ' '; - printf( - wp_kses( - /* translators: %s: bulk optimization link */ - __( 'Start the %s to optimize the remainder of your library.', 'tiny-compress-images' ), - array( - 'a' => array( - 'href' => array(), - ), - ) - ), - wp_kses( $link, array( 'a' => array( 'href' => array() ) ) ) - ); - ?> -

-
-
-

- friendly_user_name() ) ); - echo ' '; - require __DIR__ . '/request-review.php'; - ?> -

-
-
-

- saved %s of your media library size.', 'tiny-compress-images' ), - array( - 'span' => array(), - 'strong' => array(), - ) - ), - '%' - ); - ?> -

-
+
+ +
+ + + + + + + %s images.', 'tiny-compress-images'), array('strong' => array())), + esc_html(number_format_i18n($widget['images_remaining'])) + ); + ?> + +
+ + +
+
+ +
+ + +
+ +
+ +
+ + + + + + +
+
+ - + +
+ + +
+
diff --git a/src/views/progress-circle.php b/src/views/progress-circle.php new file mode 100644 index 00000000..687d3b14 --- /dev/null +++ b/src/views/progress-circle.php @@ -0,0 +1,76 @@ + + + +
+ +
+
%
+ +
+ +
+
diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php new file mode 100644 index 00000000..d98236cc --- /dev/null +++ b/test/unit/Tiny_Dashboard_Test.php @@ -0,0 +1,84 @@ + $uploaded, + 'optimized-image-sizes' => 0, + 'available-unoptimized-sizes' => 0, + 'optimized-library-size' => $optimized_size, + 'unoptimized-library-size' => $unoptimized_size, + 'estimated_credit_use' => 0, + 'available-for-optimization' => array_fill(0, $remaining, array('ID' => 1, 'post_title' => 'image')), + 'display-percentage' => 0, + )); + } + + public function test_is_empty_when_there_are_no_images() + { + $data = $this->widget_data(0, 0); + + $this->assertSame('empty', $data['status']); + $this->assertSame(0, $data['percentage']); + $this->assertSame(0, $data['images_remaining']); + $this->assertSame('panda-waiting.png', $data['panda']); + } + + public function test_is_in_progress_when_images_remain() + { + $data = $this->widget_data(1250, 330); + + $this->assertSame('in_progress', $data['status']); + $this->assertSame(920, $data['images_optimized']); + $this->assertSame(1250, $data['images_total']); + $this->assertSame(330, $data['images_remaining']); + $this->assertSame(73, $data['percentage']); + $this->assertSame('panda-eating.png', $data['panda']); + } + + public function test_is_done_when_no_images_remain() + { + $data = $this->widget_data(1250, 0); + + $this->assertSame('done', $data['status']); + $this->assertSame(1250, $data['images_optimized']); + $this->assertSame(100, $data['percentage']); + $this->assertSame('all done', $data['label']); + $this->assertSame('panda-laying.png', $data['panda']); + } + + public function test_labels_below_half_as_keep_going() + { + $this->assertSame('keep going', $this->widget_data(100, 51)['label']); + } + + public function test_labels_half_and_above_as_almost_there() + { + $this->assertSame('almost there', $this->widget_data(100, 50)['label']); + } + + public function test_does_not_show_100_percent_while_images_remain() + { + $data = $this->widget_data(1000, 1); + + $this->assertSame('in_progress', $data['status']); + $this->assertSame(99, $data['percentage']); + } + + public function test_bytes_saved_is_the_library_size_reduction() + { + $this->assertSame(2000, $this->widget_data(10, 3, 5000, 3000)['bytes_saved']); + } + + public function test_bytes_saved_is_never_negative() + { + $this->assertSame(0, $this->widget_data(10, 3, 3000, 5000)['bytes_saved']); + } +} diff --git a/tiny-compress-images.php b/tiny-compress-images.php index 37ccc7e0..daa13a5e 100644 --- a/tiny-compress-images.php +++ b/tiny-compress-images.php @@ -27,6 +27,7 @@ require dirname( __FILE__ ) . '/src/class-tiny-cli.php'; require dirname( __FILE__ ) . '/src/class-tiny-conversion.php'; require dirname( __FILE__ ) . '/src/class-tiny-picture.php'; +require dirname( __FILE__ ) . '/src/class-tiny-dashboard.php'; require dirname( __FILE__ ) . '/src/class-tiny-apache-rewrite.php'; require dirname( __FILE__ ) . '/src/compatibility/wpml/class-tiny-wpml.php'; require dirname( __FILE__ ) . '/src/compatibility/as3cf/class-tiny-as3cf.php'; From 07a033d1252dd86ac0c08cc46ce6dc103a117d3b Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 23 Sep 2026 14:44:08 +0200 Subject: [PATCH 09/68] refactor ui for dashboard widget --- src/class-tiny-dashboard.php | 69 +++++++++++--- src/class-tiny-settings.php | 4 + src/css/dashboard-widget.css | 147 ++++++++++++++++++------------ src/views/dashboard-widget.php | 134 +++++++++++++++++---------- src/views/progress-circle.php | 15 ++- test/unit/Tiny_Dashboard_Test.php | 63 ++++++++++++- 6 files changed, 306 insertions(+), 126 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 79b77d07..98552766 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -19,6 +19,14 @@ */ class Tiny_Dashboard extends Tiny_WP_Base { + /** + * Paying states whose accounts have a limited number of credits. + * TODO: confirm the header value the API sends for fixed pricing plans. + */ + const LIMITED_CREDIT_PLANS = array( 'free', 'fixed' ); + + const LOW_CREDITS_THRESHOLD = 100; + /** * @var Tiny_Settings settings */ @@ -44,7 +52,7 @@ public function add_dashboard_widget() { self::NAME . '_dashboard_widget', plugins_url( '/css/dashboard-widget.css', __FILE__ ), array(), - self::wp_version(), + self::wp_version() ); wp_add_dashboard_widget( @@ -56,17 +64,26 @@ public function add_dashboard_widget() { public function add_widget_view() { $optimization_statistics = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); - $widget = self::get_widget_data( $optimization_statistics ); + $widget = self::get_widget_data( + $optimization_statistics, + $this->settings->get_remaining_credits(), + $this->settings->get_paying_state(), + $this->settings->has_api_key() + ); + $email_address = $this->settings->get_email_address(); include __DIR__ . '/views/dashboard-widget.php'; } /** * Logic for the view * - * @param array $optimization_stats See Tiny_Bulk_Optimization::get_optimization_statistics(). + * @param array $optimization_stats See Tiny_Bulk_Optimization::get_optimization_statistics(). + * @param int|false $remaining_credits Stored account credits, false when unknown. + * @param string|false $paying_state Stored account paying state, false when unknown. + * @param bool $has_api_key * @return array */ - public static function get_widget_data( $optimization_stats ) { + public static function get_widget_data( $optimization_stats, $remaining_credits = false, $paying_state = false, $has_api_key = true ) { $images_remaining = count( $optimization_stats['available-for-optimization'] ); $bytes_total = $optimization_stats['unoptimized-library-size']; $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); @@ -81,20 +98,29 @@ public static function get_widget_data( $optimization_stats ) { : 0; $percentage = max( 0, min( 100, $percentage ) ); + $label = self::get_label_text($percentage); + if ( 0 === $images_total ) { - $status = 'empty'; - $label = ''; + $status = 'empty'; $panda = 'panda-waiting.png'; } elseif ( 0 === $images_remaining ) { $status = 'done'; - $label = __( 'all done', 'tiny-compress-images' ); $panda = 'panda-laying.png'; } else { $status = 'in_progress'; - $label = $percentage >= 50 - ? __( 'almost there', 'tiny-compress-images' ) - : __( 'keep going', 'tiny-compress-images' ); - $panda = 'panda-eating.png'; + $panda = 'panda-waiting.png'; + } + + $has_limited_credits = in_array( $paying_state, self::LIMITED_CREDIT_PLANS, true ) + && is_numeric( $remaining_credits ); + $remaining_credits = $has_limited_credits ? intval( $remaining_credits ) : null; + + if ( ! $has_api_key ) { + $notice = 'no_api_key'; + } elseif ( null !== $remaining_credits && $remaining_credits < self::LOW_CREDITS_THRESHOLD ) { + $notice = 'low_credits'; + } else { + $notice = null; } return array( @@ -106,6 +132,27 @@ public static function get_widget_data( $optimization_stats ) { 'percentage' => $percentage, 'label' => $label, 'panda' => $panda, + 'remaining_credits' => $remaining_credits, + 'notice' => $notice, ); } + + private static function get_label_text($percentage) { + if ($percentage > 99) { + return __( 'optimized', 'tiny-compress-images' ); + } + if ($percentage > 75) { + return __( 'amost there', 'tiny-compress-images' ); + } + + if ($percentage > 50) { + return __( 'halfway there', 'tiny-compress-images' ); + } + + if ($percentage === 0 ) { + return __( '', 'tiny-compress-images' ); + } + + return __( 'getting started', 'tiny-compress-images' ); + } } diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 342f9d8e..dbc0b355 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -219,6 +219,10 @@ protected function get_api_key() { } } + public function has_api_key() { + return (bool) $this->get_api_key(); + } + protected function get_api_key_pending() { if ( defined( 'TINY_API_KEY' ) ) { return false; diff --git a/src/css/dashboard-widget.css b/src/css/dashboard-widget.css index 7e0d3ae8..1aa76303 100644 --- a/src/css/dashboard-widget.css +++ b/src/css/dashboard-widget.css @@ -1,25 +1,68 @@ #tinypng_dashboard_widget .inside { margin: 0; padding: 0; + container-type: inline-size; } .tiny-widget { + display: flex; + min-height: 210px; + background: url("../images/grass.png") no-repeat right bottom / 398px 18px; color: var(--tiny-color-text-muted); font-size: 13px; - line-height: 20px; + line-height: 17px; } -.tiny-widget-bulk { +.tiny-widget-main { display: flex; + flex-shrink: 0; flex-direction: column; + justify-content: space-between; +} + +.tiny-widget-content { + display: flex; + flex: 1; align-items: center; - gap: 5px; - padding: 20px; - text-align: center; + gap: 20px; + padding: 20px 0 20px 20px; +} + +.tiny-widget-stats { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 20px; +} + +.tiny-widget-summary { + display: flex; + flex-direction: column; + gap: 4px; +} + +.tiny-widget-title { + color: #030712; + font-size: 16px; + white-space: nowrap; } -.tiny-widget-bulk strong { - color: #1e1e1e; +.tiny-widget-meta { + display: flex; + gap: 10px; + white-space: nowrap; + color: #989898; + font-size: 11px; +} + +.tiny-widget-meta span { + display: inline-flex; + align-items: center; + gap: 4px; +} + +.tiny-widget-meta svg { + opacity: 0.5; } a.tiny-widget-bulk-button { @@ -27,11 +70,11 @@ a.tiny-widget-bulk-button { align-items: center; justify-content: center; gap: 10px; - width: 209px; - padding: 15px 0; + width: 159px; + height: 37px; background: #3858e9; color: #fff; - font-size: 15px; + font-size: 13px; font-weight: bold; line-height: normal; text-decoration: none; @@ -43,50 +86,12 @@ a.tiny-widget-bulk-button:focus { color: #fff; } -.tiny-widget-body { - display: flex; - align-items: flex-end; - justify-content: space-between; -} - -.tiny-widget-main { - display: flex; - flex-direction: column; - align-self: stretch; - justify-content: space-between; - min-width: 0; -} - -.tiny-widget-progress { - display: flex; - align-items: center; - gap: 20px; -} - -.tiny-widget-progress, -.tiny-widget-main > .tiny-widget-stats { - padding: 20px; -} - -.tiny-widget-stats { - display: flex; - flex-direction: column; - gap: 5px; - line-height: 17px; -} - -.tiny-widget-title { - color: #030712; - font-size: 16px; -} - .tiny-widget-nav { display: flex; align-items: center; padding: 10px 20px; font-size: 12px; font-weight: bold; - line-height: 17px; } .tiny-widget-nav a { @@ -100,19 +105,49 @@ a.tiny-widget-bulk-button:focus { border-left: 1px solid #ccc; } +.tiny-widget-aside { + display: flex; + flex: 1; + flex-direction: column; + align-items: flex-end; + justify-content: flex-end; + gap: 10px; + min-width: 0; + padding: 20px 12px 0 20px; +} + +a.tiny-widget-notice { + display: block; + padding: 10px; + border-radius: 4px; + background: #fef3e8; + color: #40444f; + font-size: 11px; + text-decoration: none; + text-align: center; +} + +a.tiny-widget-notice:hover, +a.tiny-widget-notice:focus { + background: #fde6cf; + color: #40444f; +} + +.tiny-widget-notice-api-key { + text-align: center; +} + .tiny-widget-panda { - flex-shrink: 0; - width: 213px; + width: 179px; height: auto; - padding: 0 12px; } -.tiny-widget-panda-eating { - transform: scaleX(-1); -} +@container (max-width: 560px) { + .tiny-widget { + background: none; + } -@media (max-width: 480px) { - .tiny-widget-panda { + .tiny-widget-aside { display: none; } } diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index 43cfc7b4..e2b6e59b 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -3,7 +3,8 @@ /** * Dashboard Widget * - * @var array $widget See Tiny_Dashboard::get_widget_data(). + * @var array $widget See Tiny_Dashboard::get_widget_data(). + * @var string $email_address * */ $percentage = $widget['percentage']; @@ -11,72 +12,105 @@ $bulk_url = admin_url('upload.php?page=tiny-bulk-optimization'); $settings_url = admin_url('options-general.php?page=tinify'); +$upgrade_url = 'https://tinypng.com/dashboard/api?type=upgrade&mail=' . + str_replace('%20', '%2B', rawurlencode($email_address)) . + '&utm_source=wordpress-plugin&utm_medium=referral&utm_campaign=upgrade&utm_content=dashboard-widget'; +$strong = array('strong' => array()); +$database_icon = ''; ?>
- -
- - - - - - - %s images.', 'tiny-compress-images'), array('strong' => array())), - esc_html(number_format_i18n($widget['images_remaining'])) - ); - ?> - -
- - -
-
+
+
-
+
-
- -
- - - - + +
+
+ All images are optimized', 'tiny-compress-images'), $strong); + } else { + printf( + /* translators: %s: number of images that can still be optimized */ + wp_kses(_n('%s image needs optimization', '%s images need optimization', $widget['images_remaining'], 'tiny-compress-images'), $strong), + esc_html(number_format_i18n($widget['images_remaining'])) + ); + } ?> +
+ + %s saved', 'tiny-compress-images'), $strong), + esc_html(size_format($widget['bytes_saved'], 1)) + ); + ?> + + + + %s credit', '%s credits remaining', $widget['remaining_credits'], 'tiny-compress-images'), $strong), + esc_html(number_format_i18n($widget['remaining_credits'])) + ); + ?> + + +
+ + + + + +
- -
+ +
+ + diff --git a/src/views/progress-circle.php b/src/views/progress-circle.php index 687d3b14..b62d5f56 100644 --- a/src/views/progress-circle.php +++ b/src/views/progress-circle.php @@ -9,8 +9,8 @@
- %s credits remaining', $widget['remaining_credits'], 'tiny-compress-images'), $strong), esc_html(number_format_i18n($widget['remaining_credits'])) ); @@ -98,10 +98,7 @@ printf( wp_kses( /* translators: %s: number of remaining credits */ - __( - 'You are on a free plan with %s compressions left this month.', // WPCS: Needed for proper translation. - 'tiny-compress-images' - ), + __( 'You are on a free plan with %s compressions left.', 'tiny-compress-images' ), $strong ), intval( $widget['remaining_credits'] ) diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index af11be0c..f5715a1e 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -106,11 +106,6 @@ public function test_shows_remaining_credits_on_free_plan() $this->assertSame(210, $this->account_data('210', 'free')['remaining_credits']); } - public function test_shows_remaining_credits_on_fixed_plan() - { - $this->assertSame(210, $this->account_data(210, 'fixed')['remaining_credits']); - } - public function test_hides_remaining_credits_on_paid_plan() { $this->assertNull($this->account_data(210, 'paid')['remaining_credits']); @@ -130,7 +125,7 @@ public function test_has_no_notice_with_enough_credits() public function test_notifies_low_credits_below_100() { $this->assertSame('low_credits', $this->account_data(99, 'free')['notice']); - $this->assertSame('low_credits', $this->account_data(0, 'fixed')['notice']); + $this->assertSame('low_credits', $this->account_data(0, 'free')['notice']); } public function test_does_not_notify_low_credits_on_paid_plan() From 4bf80a7009312d5546e4c2795f5d986fb7d409a1 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 23 Sep 2026 15:46:17 +0200 Subject: [PATCH 14/68] resolve e2e tests --- test/integration/dashboardwidget.spec.ts | 64 +++++++++++++++++------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/test/integration/dashboardwidget.spec.ts b/test/integration/dashboardwidget.spec.ts index 50836014..5bf0df52 100644 --- a/test/integration/dashboardwidget.spec.ts +++ b/test/integration/dashboardwidget.spec.ts @@ -5,10 +5,23 @@ test.describe.configure({ mode: 'serial' }); let page: Page; +const widget = () => page.locator('#tinypng_dashboard_widget'); + +// The settings page fetches the account details over ajax after saving, +// so wait for that before the dashboard reads them. +async function setAccount(key: string) { + await setAPIKey(page, key); + await page.waitForURL(/settings-updated=true/); + await page.waitForLoadState('networkidle'); +} + test.describe('dashboardwidget', () => { test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); + // The widget hides its notices when narrower than 560px, which it is + // in the two column dashboard at the default 1280px viewport. + page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); await setAPIKey(page, ''); + await setCompressionTiming(page, 'auto'); await enableCompressionSizes(page, [], true); // enable all sizes }); @@ -17,46 +30,59 @@ test.describe('dashboardwidget', () => { }); test('show widget without images', async () => { + await setAPIKey(page, 'JPG123'); + await page.goto('/wp-admin/index.php'); - await expect(page.getByText('You do not seem to have uploaded any JPEG, PNG or WebP images yet.')).toBeVisible(); + + await expect(widget().getByText('George is hungry')).toBeVisible(); + await expect(widget().getByText('There are no images uploaded yet.')).toBeVisible(); }); - test('show widget without optimized images', async () => { - // It won't compress images without an API Key + test('show notice without api key', async () => { await setAPIKey(page, ''); - await setCompressionTiming(page, 'auto'); - - await uploadMedia(page, 'input-example.png'); await page.goto('/wp-admin/index.php'); - await expect( - page.getByText(`Hi Admin, you haven't compressed any images in your media library. If you like you can to optimize your whole library in one go with the bulk optimization page.`) - ).toBeVisible(); + + await expect(widget().getByText('Please register or provide an API key to start compressing images.')).toBeVisible(); }); - test('show widget with some images optimized', async () => { + test('show widget with images to optimize', async () => { + // It won't compress images without an API Key await setAPIKey(page, ''); + await uploadMedia(page, 'input-example.png'); - await setCompressionTiming(page, 'auto'); - - await uploadMedia(page, 'input-example.jpg'); + await page.goto('/wp-admin/index.php'); - await setAPIKey(page, 'JPG123'); + await expect(widget().getByText('1 image needs optimization')).toBeVisible(); + await expect(widget().getByText('Please register or provide an API key to start compressing images.')).toBeVisible(); + await expect(widget().getByRole('link', { name: 'Bulk Optimizer' })).toBeVisible(); + }); + test('show widget with all images optimized', async () => { + await setAPIKey(page, 'JPG123'); await uploadMedia(page, 'input-example.jpg'); await page.goto('/wp-admin/index.php'); - await expect(page.getByText('Admin, you are doing good. With your current settings you can still optimize')).toBeVisible(); + await expect(widget().getByText('All images are optimized')).toBeVisible(); + await expect(widget().getByText('100%')).toBeVisible(); + await expect(widget().getByRole('link', { name: 'Bulk Optimizer' })).not.toBeVisible(); }); - test('show widget with all images optimized', async () => { + test('show notice with low credits on free plan', async () => { + await setAccount('INSUFFICIENTCREDITS123'); + await page.goto('/wp-admin/index.php'); - await uploadMedia(page, 'input-example.jpg'); + await expect(widget().getByText('You are on a free plan with 1 compressions left.')).toBeVisible(); + }); + + test('not show credits on paid plan', async () => { + await setAccount('JPG123'); await page.goto('/wp-admin/index.php'); - await expect(page.getByText('Admin, this is great! Your entire library is optimized!')).toBeVisible(); + await expect(widget().getByText('George is hungry')).toBeVisible(); + await expect(widget().getByText('compressions left')).not.toBeVisible(); }); }); From eb3edbc3f53d0ae8926a31cc1f29a82c660de566 Mon Sep 17 00:00:00 2001 From: tijmen Date: Wed, 23 Sep 2026 15:47:28 +0200 Subject: [PATCH 15/68] format --- src/class-tiny-dashboard.php | 52 ++++++++++++++--------------- src/views/dashboard-widget.php | 60 +++++++++++++++++----------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 2dea3022..849782a6 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -58,13 +58,13 @@ public function add_dashboard_widget() { public function add_widget_view() { $optimization_statistics = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); - $widget = self::get_widget_data( + $widget = self::get_widget_data( $optimization_statistics, $this->settings->get_remaining_credits(), $this->settings->get_paying_state(), $this->settings->has_api_key() ); - $email_address = $this->settings->get_email_address(); + $email_address = $this->settings->get_email_address(); include __DIR__ . '/views/dashboard-widget.php'; } @@ -79,36 +79,36 @@ public function add_widget_view() { */ public static function get_widget_data( $optimization_stats, $remaining_credits = false, $paying_state = false, $has_api_key = true ) { $images_remaining = count( $optimization_stats['available-for-optimization'] ); - $bytes_total = $optimization_stats['unoptimized-library-size']; - $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); - + $bytes_total = $optimization_stats['unoptimized-library-size']; + $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); + $images_optimized = $images_total - $images_remaining; $images_optimized = max( 0, intval( $images_optimized ) ); $images_remaining = max( 0, $images_total - $images_optimized ); - $bytes_saved = $bytes_total - $optimization_stats['optimized-library-size']; + $bytes_saved = $bytes_total - $optimization_stats['optimized-library-size']; $percentage = $images_total > 0 ? intval( floor( $images_optimized / $images_total * 100 ) ) : 0; $percentage = max( 0, min( 100, $percentage ) ); - $label = self::get_label_text($percentage); + $label = self::get_label_text( $percentage ); if ( 0 === $images_total ) { - $status = 'empty'; - $panda = 'panda-waiting.png'; + $status = 'empty'; + $panda = 'panda-waiting.png'; } elseif ( 0 === $images_remaining ) { $status = 'done'; - $panda = 'panda-laying.png'; + $panda = 'panda-laying.png'; } else { $status = 'in_progress'; - $panda = 'panda-waiting.png'; + $panda = 'panda-waiting.png'; } // Only free accounts have a limited number of credits, including // free accounts that bought a credit bundle. $has_limited_credits = 'free' === $paying_state && is_numeric( $remaining_credits ); - $remaining_credits = $has_limited_credits ? intval( $remaining_credits ) : null; + $remaining_credits = $has_limited_credits ? intval( $remaining_credits ) : null; if ( ! $has_api_key ) { $notice = 'no_api_key'; @@ -119,32 +119,32 @@ public static function get_widget_data( $optimization_stats, $remaining_credits } return array( - 'status' => $status, - 'images_optimized' => $images_optimized, - 'images_total' => $images_total, - 'images_remaining' => $images_remaining, - 'bytes_saved' => max( 0, intval( $bytes_saved ) ), - 'percentage' => $percentage, - 'label' => $label, - 'panda' => $panda, + 'status' => $status, + 'images_optimized' => $images_optimized, + 'images_total' => $images_total, + 'images_remaining' => $images_remaining, + 'bytes_saved' => max( 0, intval( $bytes_saved ) ), + 'percentage' => $percentage, + 'label' => $label, + 'panda' => $panda, 'remaining_credits' => $remaining_credits, - 'notice' => $notice, + 'notice' => $notice, ); } - private static function get_label_text($percentage) { - if ($percentage > 99) { + private static function get_label_text( $percentage ) { + if ( $percentage > 99 ) { return __( 'optimized', 'tiny-compress-images' ); } - if ($percentage > 75) { + if ( $percentage > 75 ) { return __( 'amost there', 'tiny-compress-images' ); } - if ($percentage > 50) { + if ( $percentage > 50 ) { return __( 'halfway there', 'tiny-compress-images' ); } - if ($percentage === 0 ) { + if ( $percentage === 0 ) { return ''; } diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index 425ae5ab..7e0997cc 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -8,24 +8,24 @@ * */ $percentage = $widget['percentage']; -$label = $widget['label']; +$label = $widget['label']; -$bulk_url = admin_url('upload.php?page=tiny-bulk-optimization'); -$settings_url = admin_url('options-general.php?page=tinify'); -$upgrade_url = 'https://tinypng.com/dashboard/api?type=upgrade&mail=' . - str_replace('%20', '%2B', rawurlencode($email_address)) . +$bulk_url = admin_url( 'upload.php?page=tiny-bulk-optimization' ); +$settings_url = admin_url( 'options-general.php?page=tinify' ); +$upgrade_url = 'https://tinypng.com/dashboard/api?type=upgrade&mail=' . + str_replace( '%20', '%2B', rawurlencode( $email_address ) ) . '&utm_source=wordpress-plugin&utm_medium=referral&utm_campaign=upgrade&utm_content=dashboard-widget'; -$strong = array('strong' => array()); +$strong = array( 'strong' => array() ); $database_icon = ''; ?>
- +
- - + +
@@ -33,13 +33,13 @@
All images are optimized', 'tiny-compress-images'), $strong); + if ( 'done' === $widget['status'] ) { + echo wp_kses( __( 'All images are optimized', 'tiny-compress-images' ), $strong ); } else { printf( /* translators: %s: number of images that can still be optimized */ - wp_kses(_n('%s image needs optimization', '%s images need optimization', $widget['images_remaining'], 'tiny-compress-images'), $strong), - esc_html(number_format_i18n($widget['images_remaining'])) + wp_kses( _n( '%s image needs optimization', '%s images need optimization', $widget['images_remaining'], 'tiny-compress-images' ), $strong ), + esc_html( number_format_i18n( $widget['images_remaining'] ) ) ); } ?> @@ -50,28 +50,28 @@ echo $database_icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static markup. printf( /* translators: %s: bytes saved, e.g. 21.7 MB */ - wp_kses(__('%s saved', 'tiny-compress-images'), $strong), - esc_html(size_format($widget['bytes_saved'], 1)) + wp_kses( __( '%s saved', 'tiny-compress-images' ), $strong ), + esc_html( size_format( $widget['bytes_saved'], 1 ) ) ); ?> - + %s credit', '%s credits remaining', $widget['remaining_credits'], 'tiny-compress-images'), $strong), - esc_html(number_format_i18n($widget['remaining_credits'])) + wp_kses( _n( '%s credit', '%s credits remaining', $widget['remaining_credits'], 'tiny-compress-images' ), $strong ), + esc_html( number_format_i18n( $widget['remaining_credits'] ) ) ); ?>
- - - + + + @@ -82,18 +82,18 @@
From 41d65701099023fa92f6cd70f6bea22feb0d0766 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 29 Sep 2026 10:12:28 +0200 Subject: [PATCH 16/68] feat: update texts --- src/class-tiny-dashboard.php | 15 +++++++-------- src/views/dashboard-widget.php | 6 +++--- test/integration/dashboardwidget.spec.ts | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 849782a6..f595b40d 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -78,19 +78,18 @@ public function add_widget_view() { * @return array */ public static function get_widget_data( $optimization_stats, $remaining_credits = false, $paying_state = false, $has_api_key = true ) { - $images_remaining = count( $optimization_stats['available-for-optimization'] ); - $bytes_total = $optimization_stats['unoptimized-library-size']; $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); - + $images_remaining = min( + $images_total, + count( $optimization_stats['available-for-optimization'] ) + ); $images_optimized = $images_total - $images_remaining; - $images_optimized = max( 0, intval( $images_optimized ) ); - $images_remaining = max( 0, $images_total - $images_optimized ); - $bytes_saved = $bytes_total - $optimization_stats['optimized-library-size']; + $bytes_saved = $optimization_stats['unoptimized-library-size'] + - $optimization_stats['optimized-library-size']; $percentage = $images_total > 0 ? intval( floor( $images_optimized / $images_total * 100 ) ) : 0; - $percentage = max( 0, min( 100, $percentage ) ); $label = self::get_label_text( $percentage ); @@ -137,7 +136,7 @@ private static function get_label_text( $percentage ) { return __( 'optimized', 'tiny-compress-images' ); } if ( $percentage > 75 ) { - return __( 'amost there', 'tiny-compress-images' ); + return __( 'almost there', 'tiny-compress-images' ); } if ( $percentage > 50 ) { diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index 7e0997cc..f7e2b086 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -61,7 +61,7 @@ echo $database_icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static markup. printf( /* translators: %s: number of compression credits left */ - wp_kses( _n( '%s credit', '%s credits remaining', $widget['remaining_credits'], 'tiny-compress-images' ), $strong ), + wp_kses( _n( '%s credit remaining', '%s credits remaining', $widget['remaining_credits'], 'tiny-compress-images' ), $strong ), esc_html( number_format_i18n( $widget['remaining_credits'] ) ) ); ?> @@ -98,10 +98,10 @@ printf( wp_kses( /* translators: %s: number of remaining credits */ - __( 'You are on a free plan with %s compressions left.', 'tiny-compress-images' ), + _n( 'You are on a free plan with %s compression left.', 'You are on a free plan with %s compressions left.', $widget['remaining_credits'], 'tiny-compress-images' ), $strong ), - intval( $widget['remaining_credits'] ) + esc_html( number_format_i18n( $widget['remaining_credits'] ) ) ); ?> diff --git a/test/integration/dashboardwidget.spec.ts b/test/integration/dashboardwidget.spec.ts index 5bf0df52..8efe1d18 100644 --- a/test/integration/dashboardwidget.spec.ts +++ b/test/integration/dashboardwidget.spec.ts @@ -74,7 +74,7 @@ test.describe('dashboardwidget', () => { await page.goto('/wp-admin/index.php'); - await expect(widget().getByText('You are on a free plan with 1 compressions left.')).toBeVisible(); + await expect(widget().getByText('You are on a free plan with 1 compression left.')).toBeVisible(); }); test('not show credits on paid plan', async () => { From 2210523ebed7a22cf280ced6e6e388fc68cbeb35 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 09:43:02 +0200 Subject: [PATCH 17/68] set guard to only allow dashboard widget for users that can upload --- src/class-tiny-dashboard.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index f595b40d..fcb4ee31 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -35,10 +35,12 @@ public function __construct( $settings ) { } public function admin_init() { - add_action( - 'wp_dashboard_setup', - $this->get_method( 'add_dashboard_widget' ) - ); + if ( current_user_can('upload_files') ) { + add_action( + 'wp_dashboard_setup', + array( $this, 'add_dashboard_widget' ) + ); + } } public function add_dashboard_widget() { From 33fdc861af4393d276d37c08872d5b054e3896b8 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 09:43:40 +0200 Subject: [PATCH 18/68] convert to private funcs --- src/class-tiny-dashboard.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index fcb4ee31..9e6cd2b7 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -43,7 +43,7 @@ public function admin_init() { } } - public function add_dashboard_widget() { + private function add_dashboard_widget() { wp_enqueue_style( self::NAME . '_dashboard_widget', plugins_url( '/css/dashboard-widget.css', __FILE__ ), @@ -54,11 +54,11 @@ public function add_dashboard_widget() { wp_add_dashboard_widget( $this->get_prefixed_name( 'dashboard_widget' ), esc_html__( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' ), - $this->get_method( 'add_widget_view' ) + array($this, 'add_widget_view' ) ); } - public function add_widget_view() { + private function add_widget_view() { $optimization_statistics = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); $widget = self::get_widget_data( $optimization_statistics, @@ -79,7 +79,7 @@ public function add_widget_view() { * @param bool $has_api_key * @return array */ - public static function get_widget_data( $optimization_stats, $remaining_credits = false, $paying_state = false, $has_api_key = true ) { + private function get_widget_data( $optimization_stats, $remaining_credits = false, $has_api_key = true ) { $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); $images_remaining = min( $images_total, From 5d3035ae531f92f4c99bc3b7e82cbbe65ce44348 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 09:43:50 +0200 Subject: [PATCH 19/68] use settings get pay state --- src/class-tiny-dashboard.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 9e6cd2b7..4782ce07 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -60,10 +60,9 @@ private function add_dashboard_widget() { private function add_widget_view() { $optimization_statistics = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); - $widget = self::get_widget_data( + $widget = $this->get_widget_data( $optimization_statistics, $this->settings->get_remaining_credits(), - $this->settings->get_paying_state(), $this->settings->has_api_key() ); $email_address = $this->settings->get_email_address(); @@ -108,7 +107,7 @@ private function get_widget_data( $optimization_stats, $remaining_credits = fals // Only free accounts have a limited number of credits, including // free accounts that bought a credit bundle. - $has_limited_credits = 'free' === $paying_state && is_numeric( $remaining_credits ); + $has_limited_credits = $this->settings->is_on_free_plan() && is_numeric( $remaining_credits ); $remaining_credits = $has_limited_credits ? intval( $remaining_credits ) : null; if ( ! $has_api_key ) { From 3a4846a9229b786e1290b969afcb97d16ce41168 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 09:44:44 +0200 Subject: [PATCH 20/68] remove unused action and method --- src/class-tiny-plugin.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index 0fc7ef7c..c0751435 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -105,11 +105,6 @@ public function ajax_init() { $this->get_method( 'compress_image_for_bulk' ) ); - add_action( - 'wp_ajax_tiny_get_optimization_statistics', - $this->get_method( 'ajax_optimization_statistics' ) - ); - add_action( 'wp_ajax_tiny_get_compression_status', $this->get_method( 'ajax_compression_status' ) @@ -664,15 +659,6 @@ public function compress_image_for_bulk() { exit(); } - public function ajax_optimization_statistics() { - if ( check_ajax_referer( 'tiny-compress', '_nonce', false ) && - current_user_can( 'upload_files' ) ) { - $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); - echo json_encode( $stats ); - } - exit(); - } - public function ajax_compression_status() { $response = $this->validate_ajax_attachment_request(); From c63df81324082db33a1cb416184acf52f874d3cf Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 09:48:19 +0200 Subject: [PATCH 21/68] remove default valeus --- src/class-tiny-dashboard.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 4782ce07..e3d51717 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -74,11 +74,10 @@ private function add_widget_view() { * * @param array $optimization_stats See Tiny_Bulk_Optimization::get_optimization_statistics(). * @param int|false $remaining_credits Stored account credits, false when unknown. - * @param string|false $paying_state Stored account paying state, false when unknown. * @param bool $has_api_key * @return array */ - private function get_widget_data( $optimization_stats, $remaining_credits = false, $has_api_key = true ) { + private function get_widget_data( $optimization_stats, $remaining_credits, $has_api_key ) { $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); $images_remaining = min( $images_total, From da29255b1728a1c66a12ece6f515ea75156bb376 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 09:59:25 +0200 Subject: [PATCH 22/68] format and tests --- src/class-tiny-dashboard.php | 10 +- test/unit/Tiny_Dashboard_Test.php | 263 +++++++++++++++++++++++++----- 2 files changed, 230 insertions(+), 43 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index e3d51717..017fb781 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -35,7 +35,7 @@ public function __construct( $settings ) { } public function admin_init() { - if ( current_user_can('upload_files') ) { + if ( current_user_can( 'upload_files' ) ) { add_action( 'wp_dashboard_setup', array( $this, 'add_dashboard_widget' ) @@ -43,7 +43,7 @@ public function admin_init() { } } - private function add_dashboard_widget() { + public function add_dashboard_widget() { wp_enqueue_style( self::NAME . '_dashboard_widget', plugins_url( '/css/dashboard-widget.css', __FILE__ ), @@ -54,11 +54,11 @@ private function add_dashboard_widget() { wp_add_dashboard_widget( $this->get_prefixed_name( 'dashboard_widget' ), esc_html__( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' ), - array($this, 'add_widget_view' ) + array( $this, 'add_widget_view' ) ); } - private function add_widget_view() { + public function add_widget_view() { $optimization_statistics = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); $widget = $this->get_widget_data( $optimization_statistics, @@ -77,7 +77,7 @@ private function add_widget_view() { * @param bool $has_api_key * @return array */ - private function get_widget_data( $optimization_stats, $remaining_credits, $has_api_key ) { + public function get_widget_data( $optimization_stats, $remaining_credits, $has_api_key ) { $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); $images_remaining = min( $images_total, diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index f5715a1e..1741f9ff 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -5,11 +5,28 @@ class Tiny_Dashboard_Test extends Tiny_TestCase { /** - * Builds the widget data + * @var Tiny_Settings|\PHPUnit\Framework\MockObject\MockObject */ - private function widget_data($uploaded, $remaining, $unoptimized_size = 0, $optimized_size = 0) + private $settings; + + public function set_up() { - return Tiny_Dashboard::get_widget_data(array( + parent::set_up(); + $this->settings = $this->createMock(Tiny_Settings::class); + } + + /** + * helper to build optimization stats + * + * @param int $uploaded number of uploaded images + * @param int $remaining number of images remaining + * @param integer $unoptimized_size + * @param integer $optimized_size + * @return void + */ + private function stats($uploaded, $remaining, $unoptimized_size = 0, $optimized_size = 0) + { + return array( 'uploaded-images' => $uploaded, 'optimized-image-sizes' => 0, 'available-unoptimized-sizes' => 0, @@ -18,12 +35,19 @@ private function widget_data($uploaded, $remaining, $unoptimized_size = 0, $opti 'estimated_credit_use' => 0, 'available-for-optimization' => array_fill(0, $remaining, array('ID' => 1, 'post_title' => 'image')), 'display-percentage' => 0, - )); + ); } public function test_is_empty_when_there_are_no_images() { - $data = $this->widget_data(0, 0); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(0, 0), + 0, + false + ); $this->assertSame('empty', $data['status']); $this->assertSame(0, $data['percentage']); @@ -33,7 +57,14 @@ public function test_is_empty_when_there_are_no_images() public function test_is_in_progress_when_images_remain() { - $data = $this->widget_data(1250, 330); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(1250, 330), + 0, + false + ); $this->assertSame('in_progress', $data['status']); $this->assertSame(920, $data['images_optimized']); @@ -45,7 +76,14 @@ public function test_is_in_progress_when_images_remain() public function test_is_done_when_no_images_remain() { - $data = $this->widget_data(1250, 0); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(1250, 0), + 0, + false + ); $this->assertSame('done', $data['status']); $this->assertSame(1250, $data['images_optimized']); @@ -54,24 +92,93 @@ public function test_is_done_when_no_images_remain() $this->assertSame('panda-laying.png', $data['panda']); } - public function test_labels_below_half_as_keep_going() + public function test_labels_up_to_half_as_getting_started() { - $this->assertSame('getting started', $this->widget_data(100, 51)['label']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + + $one_percent = $dashboard->get_widget_data( + $this->stats(100, 99), + 0, + false + ); + $fifty_percent = $dashboard->get_widget_data( + $this->stats(100, 50), + 0, + false + ); + + $this->assertSame('getting started', $one_percent['label']); + $this->assertSame('getting started', $fifty_percent['label']); } - public function test_labels_half_and_above_as_almost_there() + public function test_labels_above_half_as_halfway_there() { - $this->assertSame('getting started', $this->widget_data(100, 50)['label']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + + $fifty_one_percent = $dashboard->get_widget_data( + $this->stats(100, 49), + 0, + false + ); + $seventy_five_percent = $dashboard->get_widget_data( + $this->stats(100, 25), + 0, + false + ); + + $this->assertSame('halfway there', $fifty_one_percent['label']); + $this->assertSame('halfway there', $seventy_five_percent['label']); + } + + public function test_labels_above_three_quarters_as_almost_there() + { + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + + $seventy_six_percent = $dashboard->get_widget_data( + $this->stats(100, 24), + 0, + false + ); + $ninety_nine_percent = $dashboard->get_widget_data( + $this->stats(1000, 1), + 0, + false + ); + + $this->assertSame('almost there', $seventy_six_percent['label']); + $this->assertSame('almost there', $ninety_nine_percent['label']); } public function test_has_no_label_when_nothing_is_optimized() { - $this->assertSame('', $this->widget_data(10, 10)['label']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 10), + 0, + false + ); + + $this->assertSame('', $data['label']); } public function test_does_not_show_100_percent_while_images_remain() { - $data = $this->widget_data(1000, 1); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(1000, 1), + 0, + false + ); $this->assertSame('in_progress', $data['status']); $this->assertSame(99, $data['percentage']); @@ -79,67 +186,147 @@ public function test_does_not_show_100_percent_while_images_remain() public function test_bytes_saved_is_the_library_size_reduction() { - $this->assertSame(2000, $this->widget_data(10, 3, 5000, 3000)['bytes_saved']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 3, 5000, 3000), + 0, + false + ); + + $this->assertSame(2000, $data['bytes_saved']); } public function test_bytes_saved_is_never_negative() { - $this->assertSame(0, $this->widget_data(10, 3, 3000, 5000)['bytes_saved']); - } + $this->settings->method('is_on_free_plan')->willReturn(true); - private function account_data($remaining_credits, $paying_state, $has_api_key = true) - { - return Tiny_Dashboard::get_widget_data(array( - 'uploaded-images' => 10, - 'optimized-image-sizes' => 0, - 'available-unoptimized-sizes' => 0, - 'optimized-library-size' => 0, - 'unoptimized-library-size' => 0, - 'estimated_credit_use' => 0, - 'available-for-optimization' => array(array('ID' => 1, 'post_title' => 'image')), - 'display-percentage' => 0, - ), $remaining_credits, $paying_state, $has_api_key); + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 3, 3000, 5000), + 0, + false + ); + + $this->assertSame(0, $data['bytes_saved']); } public function test_shows_remaining_credits_on_free_plan() { - $this->assertSame(210, $this->account_data('210', 'free')['remaining_credits']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 1), + '210', + true + ); + + $this->assertSame(210, $data['remaining_credits']); } public function test_hides_remaining_credits_on_paid_plan() { - $this->assertNull($this->account_data(210, 'paid')['remaining_credits']); + $this->settings->method('is_on_free_plan')->willReturn(false); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 1), + 210, + true + ); + + $this->assertNull($data['remaining_credits']); } public function test_hides_remaining_credits_when_unknown() { - $this->assertNull($this->account_data(false, 'free')['remaining_credits']); - $this->assertNull($this->account_data(210, false)['remaining_credits']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 1), + false, + true + ); + + $this->assertNull($data['remaining_credits']); } public function test_has_no_notice_with_enough_credits() { - $this->assertNull($this->account_data(100, 'free')['notice']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 1), + 100, + true + ); + + $this->assertNull($data['notice']); } public function test_notifies_low_credits_below_100() { - $this->assertSame('low_credits', $this->account_data(99, 'free')['notice']); - $this->assertSame('low_credits', $this->account_data(0, 'free')['notice']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $just_below = $dashboard->get_widget_data( + $this->stats(10, 1), + 99, + true + ); + $none_left = $dashboard->get_widget_data( + $this->stats(10, 1), + 0, + true + ); + + $this->assertSame('low_credits', $just_below['notice']); + $this->assertSame('low_credits', $none_left['notice']); } public function test_does_not_notify_low_credits_on_paid_plan() { - $this->assertNull($this->account_data(0, 'paid')['notice']); + $this->settings->method('is_on_free_plan')->willReturn(false); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 1), + 0, + true + ); + + $this->assertNull($data['notice']); } public function test_notifies_missing_api_key() { - $this->assertSame('no_api_key', $this->account_data(false, false, false)['notice']); + $this->settings->method('is_on_free_plan')->willReturn(false); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 1), + false, + false + ); + + $this->assertSame('no_api_key', $data['notice']); } public function test_missing_api_key_takes_precedence_over_low_credits() { - $this->assertSame('no_api_key', $this->account_data(10, 'free', false)['notice']); + $this->settings->method('is_on_free_plan')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data( + $this->stats(10, 1), + 10, + false + ); + + $this->assertSame('no_api_key', $data['notice']); } } From 1b50e802fad736d246948a5395abd7ec0165b324 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 10:13:10 +0200 Subject: [PATCH 23/68] read credits and api key from settings in widget data --- src/class-tiny-dashboard.php | 15 +-- test/unit/Tiny_Dashboard_Test.php | 184 +++++++++--------------------- 2 files changed, 56 insertions(+), 143 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 017fb781..3480e24b 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -60,11 +60,7 @@ public function add_dashboard_widget() { public function add_widget_view() { $optimization_statistics = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); - $widget = $this->get_widget_data( - $optimization_statistics, - $this->settings->get_remaining_credits(), - $this->settings->has_api_key() - ); + $widget = $this->get_widget_data( $optimization_statistics ); $email_address = $this->settings->get_email_address(); include __DIR__ . '/views/dashboard-widget.php'; } @@ -72,12 +68,10 @@ public function add_widget_view() { /** * Logic for the view * - * @param array $optimization_stats See Tiny_Bulk_Optimization::get_optimization_statistics(). - * @param int|false $remaining_credits Stored account credits, false when unknown. - * @param bool $has_api_key + * @param array $optimization_stats See Tiny_Bulk_Optimization::get_optimization_statistics(). * @return array */ - public function get_widget_data( $optimization_stats, $remaining_credits, $has_api_key ) { + public function get_widget_data( $optimization_stats ) { $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); $images_remaining = min( $images_total, @@ -106,10 +100,11 @@ public function get_widget_data( $optimization_stats, $remaining_credits, $has_a // Only free accounts have a limited number of credits, including // free accounts that bought a credit bundle. + $remaining_credits = $this->settings->get_remaining_credits(); $has_limited_credits = $this->settings->is_on_free_plan() && is_numeric( $remaining_credits ); $remaining_credits = $has_limited_credits ? intval( $remaining_credits ) : null; - if ( ! $has_api_key ) { + if ( ! $this->settings->has_api_key() ) { $notice = 'no_api_key'; } elseif ( null !== $remaining_credits && $remaining_credits < self::LOW_CREDITS_THRESHOLD ) { $notice = 'low_credits'; diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index 1741f9ff..a802b6fc 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -22,7 +22,7 @@ public function set_up() * @param int $remaining number of images remaining * @param integer $unoptimized_size * @param integer $optimized_size - * @return void + * @return array optimization stats */ private function stats($uploaded, $remaining, $unoptimized_size = 0, $optimized_size = 0) { @@ -40,14 +40,8 @@ private function stats($uploaded, $remaining, $unoptimized_size = 0, $optimized_ public function test_is_empty_when_there_are_no_images() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(0, 0), - 0, - false - ); + $data = $dashboard->get_widget_data($this->stats(0, 0)); $this->assertSame('empty', $data['status']); $this->assertSame(0, $data['percentage']); @@ -57,14 +51,8 @@ public function test_is_empty_when_there_are_no_images() public function test_is_in_progress_when_images_remain() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(1250, 330), - 0, - false - ); + $data = $dashboard->get_widget_data($this->stats(1250, 330)); $this->assertSame('in_progress', $data['status']); $this->assertSame(920, $data['images_optimized']); @@ -76,14 +64,8 @@ public function test_is_in_progress_when_images_remain() public function test_is_done_when_no_images_remain() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(1250, 0), - 0, - false - ); + $data = $dashboard->get_widget_data($this->stats(1250, 0)); $this->assertSame('done', $data['status']); $this->assertSame(1250, $data['images_optimized']); @@ -94,20 +76,10 @@ public function test_is_done_when_no_images_remain() public function test_labels_up_to_half_as_getting_started() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $one_percent = $dashboard->get_widget_data( - $this->stats(100, 99), - 0, - false - ); - $fifty_percent = $dashboard->get_widget_data( - $this->stats(100, 50), - 0, - false - ); + $one_percent = $dashboard->get_widget_data($this->stats(100, 99)); + $fifty_percent = $dashboard->get_widget_data($this->stats(100, 50)); $this->assertSame('getting started', $one_percent['label']); $this->assertSame('getting started', $fifty_percent['label']); @@ -115,20 +87,10 @@ public function test_labels_up_to_half_as_getting_started() public function test_labels_above_half_as_halfway_there() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $fifty_one_percent = $dashboard->get_widget_data( - $this->stats(100, 49), - 0, - false - ); - $seventy_five_percent = $dashboard->get_widget_data( - $this->stats(100, 25), - 0, - false - ); + $fifty_one_percent = $dashboard->get_widget_data($this->stats(100, 49)); + $seventy_five_percent = $dashboard->get_widget_data($this->stats(100, 25)); $this->assertSame('halfway there', $fifty_one_percent['label']); $this->assertSame('halfway there', $seventy_five_percent['label']); @@ -136,20 +98,10 @@ public function test_labels_above_half_as_halfway_there() public function test_labels_above_three_quarters_as_almost_there() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $seventy_six_percent = $dashboard->get_widget_data( - $this->stats(100, 24), - 0, - false - ); - $ninety_nine_percent = $dashboard->get_widget_data( - $this->stats(1000, 1), - 0, - false - ); + $seventy_six_percent = $dashboard->get_widget_data($this->stats(100, 24)); + $ninety_nine_percent = $dashboard->get_widget_data($this->stats(1000, 1)); $this->assertSame('almost there', $seventy_six_percent['label']); $this->assertSame('almost there', $ninety_nine_percent['label']); @@ -157,28 +109,16 @@ public function test_labels_above_three_quarters_as_almost_there() public function test_has_no_label_when_nothing_is_optimized() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 10), - 0, - false - ); + $data = $dashboard->get_widget_data($this->stats(10, 10)); $this->assertSame('', $data['label']); } public function test_does_not_show_100_percent_while_images_remain() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(1000, 1), - 0, - false - ); + $data = $dashboard->get_widget_data($this->stats(1000, 1)); $this->assertSame('in_progress', $data['status']); $this->assertSame(99, $data['percentage']); @@ -186,28 +126,16 @@ public function test_does_not_show_100_percent_while_images_remain() public function test_bytes_saved_is_the_library_size_reduction() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 3, 5000, 3000), - 0, - false - ); + $data = $dashboard->get_widget_data($this->stats(10, 3, 5000, 3000)); $this->assertSame(2000, $data['bytes_saved']); } public function test_bytes_saved_is_never_negative() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 3, 3000, 5000), - 0, - false - ); + $data = $dashboard->get_widget_data($this->stats(10, 3, 3000, 5000)); $this->assertSame(0, $data['bytes_saved']); } @@ -215,13 +143,11 @@ public function test_bytes_saved_is_never_negative() public function test_shows_remaining_credits_on_free_plan() { $this->settings->method('is_on_free_plan')->willReturn(true); + $this->settings->method('get_remaining_credits')->willReturn('210'); + $this->settings->method('has_api_key')->willReturn(true); $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 1), - '210', - true - ); + $data = $dashboard->get_widget_data($this->stats(10, 1)); $this->assertSame(210, $data['remaining_credits']); } @@ -229,13 +155,11 @@ public function test_shows_remaining_credits_on_free_plan() public function test_hides_remaining_credits_on_paid_plan() { $this->settings->method('is_on_free_plan')->willReturn(false); + $this->settings->method('get_remaining_credits')->willReturn(210); + $this->settings->method('has_api_key')->willReturn(true); $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 1), - 210, - true - ); + $data = $dashboard->get_widget_data($this->stats(10, 1)); $this->assertNull($data['remaining_credits']); } @@ -243,13 +167,11 @@ public function test_hides_remaining_credits_on_paid_plan() public function test_hides_remaining_credits_when_unknown() { $this->settings->method('is_on_free_plan')->willReturn(true); + $this->settings->method('get_remaining_credits')->willReturn(false); + $this->settings->method('has_api_key')->willReturn(true); $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 1), - false, - true - ); + $data = $dashboard->get_widget_data($this->stats(10, 1)); $this->assertNull($data['remaining_credits']); } @@ -257,13 +179,11 @@ public function test_hides_remaining_credits_when_unknown() public function test_has_no_notice_with_enough_credits() { $this->settings->method('is_on_free_plan')->willReturn(true); + $this->settings->method('get_remaining_credits')->willReturn(100); + $this->settings->method('has_api_key')->willReturn(true); $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 1), - 100, - true - ); + $data = $dashboard->get_widget_data($this->stats(10, 1)); $this->assertNull($data['notice']); } @@ -271,33 +191,35 @@ public function test_has_no_notice_with_enough_credits() public function test_notifies_low_credits_below_100() { $this->settings->method('is_on_free_plan')->willReturn(true); + $this->settings->method('get_remaining_credits')->willReturn(99); + $this->settings->method('has_api_key')->willReturn(true); $dashboard = new Tiny_Dashboard($this->settings); - $just_below = $dashboard->get_widget_data( - $this->stats(10, 1), - 99, - true - ); - $none_left = $dashboard->get_widget_data( - $this->stats(10, 1), - 0, - true - ); + $data = $dashboard->get_widget_data($this->stats(10, 1)); + + $this->assertSame('low_credits', $data['notice']); + } + + public function test_notifies_low_credits_when_none_are_left() + { + $this->settings->method('is_on_free_plan')->willReturn(true); + $this->settings->method('get_remaining_credits')->willReturn(0); + $this->settings->method('has_api_key')->willReturn(true); + + $dashboard = new Tiny_Dashboard($this->settings); + $data = $dashboard->get_widget_data($this->stats(10, 1)); - $this->assertSame('low_credits', $just_below['notice']); - $this->assertSame('low_credits', $none_left['notice']); + $this->assertSame('low_credits', $data['notice']); } public function test_does_not_notify_low_credits_on_paid_plan() { $this->settings->method('is_on_free_plan')->willReturn(false); + $this->settings->method('get_remaining_credits')->willReturn(0); + $this->settings->method('has_api_key')->willReturn(true); $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 1), - 0, - true - ); + $data = $dashboard->get_widget_data($this->stats(10, 1)); $this->assertNull($data['notice']); } @@ -305,13 +227,11 @@ public function test_does_not_notify_low_credits_on_paid_plan() public function test_notifies_missing_api_key() { $this->settings->method('is_on_free_plan')->willReturn(false); + $this->settings->method('get_remaining_credits')->willReturn(false); + $this->settings->method('has_api_key')->willReturn(false); $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 1), - false, - false - ); + $data = $dashboard->get_widget_data($this->stats(10, 1)); $this->assertSame('no_api_key', $data['notice']); } @@ -319,13 +239,11 @@ public function test_notifies_missing_api_key() public function test_missing_api_key_takes_precedence_over_low_credits() { $this->settings->method('is_on_free_plan')->willReturn(true); + $this->settings->method('get_remaining_credits')->willReturn(10); + $this->settings->method('has_api_key')->willReturn(false); $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data( - $this->stats(10, 1), - 10, - false - ); + $data = $dashboard->get_widget_data($this->stats(10, 1)); $this->assertSame('no_api_key', $data['notice']); } From da613b8ad1c893a264441207c5f3a0b258fb50fc Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 10:26:50 +0200 Subject: [PATCH 24/68] formatting --- src/class-tiny-dashboard.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 3480e24b..6d4f1ee9 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -59,9 +59,9 @@ public function add_dashboard_widget() { } public function add_widget_view() { - $optimization_statistics = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); - $widget = $this->get_widget_data( $optimization_statistics ); - $email_address = $this->settings->get_email_address(); + $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); + $widget = $this->get_widget_data( $stats ); + $email_address = $this->settings->get_email_address(); include __DIR__ . '/views/dashboard-widget.php'; } @@ -101,12 +101,14 @@ public function get_widget_data( $optimization_stats ) { // Only free accounts have a limited number of credits, including // free accounts that bought a credit bundle. $remaining_credits = $this->settings->get_remaining_credits(); - $has_limited_credits = $this->settings->is_on_free_plan() && is_numeric( $remaining_credits ); + $has_limited_credits = $this->settings->is_on_free_plan() && + is_numeric( $remaining_credits ); $remaining_credits = $has_limited_credits ? intval( $remaining_credits ) : null; if ( ! $this->settings->has_api_key() ) { $notice = 'no_api_key'; - } elseif ( null !== $remaining_credits && $remaining_credits < self::LOW_CREDITS_THRESHOLD ) { + } elseif ( null !== $remaining_credits && + $remaining_credits < self::LOW_CREDITS_THRESHOLD ) { $notice = 'low_credits'; } else { $notice = null; @@ -138,7 +140,7 @@ private static function get_label_text( $percentage ) { return __( 'halfway there', 'tiny-compress-images' ); } - if ( $percentage === 0 ) { + if ( 0 === $percentage ) { return ''; } From a58f8a46c0db5655ea4c920a5617838f92b8354b Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 6 Oct 2026 10:30:23 +0200 Subject: [PATCH 25/68] add doc --- src/class-tiny-dashboard.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 6d4f1ee9..7a06f5bd 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -128,6 +128,12 @@ public function get_widget_data( $optimization_stats ) { ); } + /** + * Returns a description based on the percentage of optimized library + * + * @param int $percentage + * @return string label + */ private static function get_label_text( $percentage ) { if ( $percentage > 99 ) { return __( 'optimized', 'tiny-compress-images' ); From eef72c895a00d798990af43176d9a08b8dc16961 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 12 Oct 2026 15:07:41 +0200 Subject: [PATCH 26/68] add media assets --- src/images/alert-circle.svg | 1 + src/images/panda-juggle.png | Bin 0 -> 33513 bytes src/images/panda-thumbs-up.png | Bin 0 -> 27520 bytes src/images/panda-unbox.png | Bin 0 -> 46063 bytes 4 files changed, 1 insertion(+) create mode 100644 src/images/alert-circle.svg create mode 100644 src/images/panda-juggle.png create mode 100644 src/images/panda-thumbs-up.png create mode 100644 src/images/panda-unbox.png diff --git a/src/images/alert-circle.svg b/src/images/alert-circle.svg new file mode 100644 index 00000000..9a6ad929 --- /dev/null +++ b/src/images/alert-circle.svg @@ -0,0 +1 @@ + diff --git a/src/images/panda-juggle.png b/src/images/panda-juggle.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1b5dbbe36a2c2b61f9d9761594fd5e1fce7aef GIT binary patch literal 33513 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 literal 0 HcmV?d00001 diff --git a/src/images/panda-thumbs-up.png b/src/images/panda-thumbs-up.png new file mode 100644 index 0000000000000000000000000000000000000000..66b5b74f37eb0dcc8da19e17775e1bb6d14eb506 GIT binary patch literal 27520 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 Y50~p1HZ4XK{{R3007*qoM6N<$f>C_#FaQ7m literal 0 HcmV?d00001 diff --git a/src/images/panda-unbox.png b/src/images/panda-unbox.png new file mode 100644 index 0000000000000000000000000000000000000000..1493639a5b723a18d351f285a94d7d66bfb564a5 GIT binary patch literal 46063 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 literal 0 HcmV?d00001 From c2b2694d78976662c25e22b487db9f71af446275 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 12 Oct 2026 16:10:58 +0200 Subject: [PATCH 27/68] UI for onboarding --- src/class-tiny-onboarding.php | 75 ++++- src/class-tiny-settings.php | 52 ++-- src/css/admin.css | 400 ++++++++++++++++++++++++++- src/js/admin.js | 113 ++++++-- src/views/account-status-connect.php | 95 +++++++ src/views/onboarding-1.php | 35 ++- src/views/onboarding-2.php | 89 +++--- src/views/onboarding-3.php | 194 +++++++++++++ src/views/onboarding-steps.php | 44 +++ test/unit/TinySettingsAdminTest.php | 2 - 10 files changed, 976 insertions(+), 123 deletions(-) create mode 100644 src/views/account-status-connect.php create mode 100644 src/views/onboarding-3.php create mode 100644 src/views/onboarding-steps.php diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index 36674ada..b70f7f54 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -51,6 +51,11 @@ public function __construct( $settings ) { } function admin_init() { + add_action( + 'admin_post_tiny_onboarding_save_settings', + $this->get_method( 'save_settings' ) + ); + if ( $this->is_onboarded() ) { return; } @@ -109,8 +114,9 @@ function () use ( $step ) { function admin_menu() { $this->page_title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); - $this->add_sub_menu(1); - $this->add_sub_menu(2); + $this->add_sub_menu( 1 ); + $this->add_sub_menu( 2 ); + $this->add_sub_menu( 3 ); } /** @@ -176,13 +182,68 @@ static function set_is_onboarded( $is_onboarded ) { return update_option( $onboarding_status_field, $is_onboarded ); } - function render_register() { - $compressor = $this->settings->get_compressor(); - if ( $compressor->can_create_key() ) { - include __DIR__ . '/views/account-status-create-advanced.php'; + /** + * Renders the onboarding progress with the given step as current. + * + * @param int $current_step + * @param bool $confirm_email false when connecting with an API key skipped that step + */ + public function render_steps( $current_step, $confirm_email = true ) { + include __DIR__ . '/views/onboarding-steps.php'; + } + + /** + * Saves settings from onboading page, + * redirects to bulk optimizer. + * + * Hooked to `admin_post_tiny_onboarding_save_settings`. + */ + public function save_settings() { + check_admin_referer( 'tiny-onboarding-save-settings' ); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( + esc_html__( + 'Sorry, you are not allowed to manage options for this site.', + 'tiny-compress-images' + ) + ); + } + + $convert_to = isset( $_POST['convert_to'] ) ? + sanitize_key( wp_unslash( $_POST['convert_to'] ) ) : ''; + if ( ! in_array( $convert_to, array( 'smallest', 'webp', 'avif' ), true ) ) { + $convert_to = 'smallest'; + } + + $delivery_method = isset( $_POST['delivery_method'] ) ? + sanitize_key( wp_unslash( $_POST['delivery_method'] ) ) : ''; + if ( ! in_array( $delivery_method, array( 'htaccess', 'picture' ), true ) ) { + $delivery_method = 'picture'; + } + + $convert_format = array( 'convert' => 'off' ); + if ( isset( $_POST['convert'] ) ) { + $convert_format = array( + 'convert' => 'on', + 'convert_to' => $convert_to, + 'delivery_method' => $delivery_method, + ); + } + + update_option( + self::get_prefixed_name( 'compression_timing' ), + isset( $_POST['auto_compress'] ) ? 'background' : 'manual' + ); + update_option( self::get_prefixed_name( 'convert_format' ), $convert_format ); + + $next = isset( $_POST['next'] ) ? sanitize_key( wp_unslash( $_POST['next'] ) ) : ''; + if ( 'settings' === $next ) { + wp_safe_redirect( admin_url( 'options-general.php?page=tinify' ) ); } else { - include __DIR__ . '/views/account-status-create-simple.php'; + wp_safe_redirect( admin_url( 'upload.php?page=tiny-bulk-optimization' ) ); } + exit(); } /** diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 39ebe67f..b88ab07e 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -227,18 +227,27 @@ protected function get_api_key_pending() { } } - public function has_api_key() { - $api_key = $this->get_api_key(); - if ( empty( $api_key ) ) { + protected function clear_api_key_pending() { + delete_option( self::get_prefixed_name( 'api_key_pending' ) ); + } + + /** + * Whether the API key of a new account still waits for its email to be + * confirmed. While pending, asks the API and clears it once the key works. + * + * @return bool + */ + public function is_api_key_pending() { + if ( ! $this->get_api_key_pending() ) { return false; } - $pending_key = $this->get_api_key_pending(); - return ! empty( $pending_key ); - } + if ( $this->compressor->get_status()->ok ) { + $this->clear_api_key_pending(); + return false; + } - protected function clear_api_key_pending() { - delete_option( self::get_prefixed_name( 'api_key_pending' ) ); + return true; } protected static function get_intermediate_size( $size ) { @@ -865,6 +874,17 @@ public function render_account_status() { } } + /** + * Renders the form to create a Tinify account or to connect one with an API key. + */ + public function render_account_connect() { + $can_create_key = $this->get_compressor()->can_create_key(); + $user = wp_get_current_user(); + $name = trim( $user->user_firstname . ' ' . $user->user_lastname ); + $email = trim( $user->user_email ); + include __DIR__ . '/views/account-status-connect.php'; + } + public function render_pending_status() { $key = $this->get_api_key(); if ( empty( $key ) ) { @@ -914,6 +934,8 @@ public function create_api_key() { } try { + $name = sanitize_text_field( wp_unslash( $_POST['name'] ) ); + $email = sanitize_email( wp_unslash( $_POST['email'] ) ); $site = str_replace( array( 'http://', 'https://' ), '', @@ -921,18 +943,16 @@ public function create_api_key() { ); $identifier = 'WordPress plugin for ' . $site; $link = $this->get_absolute_url(); - $compressor->create_key( - sanitize_email( wp_unslash( $_POST['email'] ) ), - array( - 'name' => sanitize_text_field( wp_unslash( $_POST['name'] ) ), - 'identifier' => $identifier, - 'link' => $link, - ) + $options = array( + 'name' => $name, + 'identifier' => $identifier, ); + $compressor->create_key( $email, $options ); update_option( self::get_prefixed_name( 'api_key_pending' ), true ); update_option( self::get_prefixed_name( 'api_key' ), $compressor->get_key() ); update_option( self::get_prefixed_name( 'status' ), 0 ); + update_option( self::get_prefixed_name( 'email_address' ), $email ); $status = (object) array( 'ok' => true, @@ -1030,7 +1050,7 @@ private static function render_radiobutton( /** * @return bool true if apache with mod_rewrite loaded */ - private static function can_render_delivery_method() { + public static function can_render_delivery_method() { global $is_apache; if ( ! $is_apache ) { return false; diff --git a/src/css/admin.css b/src/css/admin.css index acd2a259..8ac70ba7 100644 --- a/src/css/admin.css +++ b/src/css/admin.css @@ -483,19 +483,409 @@ fieldset.tinypng_convert_fields[disabled] { margin-top: 10px; } +/* Account connect */ +.tiny-account-connect { + box-sizing: border-box; + display: flex; + width: 100%; + background: #fff; + border: 1px solid #ededf1; + border-radius: 12px; +} + +.tiny-account-connect-column { + display: flex; + flex: 1 1 0%; + flex-direction: column; + gap: 16px; + min-width: 0; + padding: 24px; +} + +.tiny-account-connect-column + .tiny-account-connect-column { + border-left: 1px solid #ededf1; +} + +@media screen and (max-width: 600px) { + .tiny-account-connect { + flex-direction: column; + } + + .tiny-account-connect-column + .tiny-account-connect-column { + border-top: 1px solid #ededf1; + border-left: 0; + } +} + +.tiny-card-head h2 { + margin: 0; + padding: 0; + color: #12141d; + font-size: 16px; + font-weight: 600; + line-height: 24px; +} + +.tiny-card-head p { + margin: 4px 0 0; + color: #5b5b67; + font-size: 14px; + line-height: 20px; +} + +.tiny-field { + margin: 0; +} + +.tiny-field label { + display: block; + margin-bottom: 6px; + color: #4a4b56; + font-size: 14px; + font-weight: 500; + line-height: 20px; +} + +.tiny-field input[type="text"] { + box-sizing: border-box; + width: 100%; + height: auto; + margin: 0; + padding: 9px 14px; + color: #1e2029; + font-size: 16px; + line-height: 24px; + background-color: #fff; + border: 1px solid #b8b8c1; + border-radius: 2px; + box-shadow: 0 1px 2px rgba(18, 20, 29, 0.05); +} + +.tiny-field input[type="text"]::placeholder { + color: #7a7a86; +} + +.tiny-field input[type="text"]:focus { + border-color: var(--wp-admin-theme-color, #2271b1); + box-shadow: 0 0 0 1px var(--wp-admin-theme-color, #2271b1); + outline: 2px solid transparent; +} + +.tiny-field-invalid input[type="text"] { + padding-right: 38px; + background: #fff url("../images/alert-circle.svg") no-repeat right 14px center; + border-color: #fca5a5; +} + +.tiny-field-invalid input[type="text"]:focus { + border-color: #fca5a5; + box-shadow: 0 0 0 1px #fca5a5; +} + +.tiny-field-error { + display: none; + margin: 6px 0 0; + color: #ef4444; + font-size: 14px; + line-height: 20px; +} + +.tiny-field-error a { + color: inherit; +} + +.tiny-field-invalid .tiny-field-error { + display: block; +} + +.tiny-actions { + display: flex; + align-items: center; + gap: 16px; + margin: 0; +} + +.tiny-actions .button { + height: auto; + min-height: 40px; + padding: 9px 16px; + font-size: 14px; + font-weight: 600; + line-height: 20px; + border-radius: 2px; +} + +.tiny-actions a, +.tiny-actions .button-link { + color: var(--wp-admin-theme-color, #2271b1); + font-size: 14px; + font-weight: 600; + line-height: 20px; + text-decoration: none; +} + +.tiny-actions .spinner { + float: none; + margin: 0; +} + +/* Onboarding */ .tiny-onboarding { display: flex; flex-direction: column; + align-items: center; + gap: 24px; + max-width: 720px; + /* Matches #wpcontent's left padding, so the page centers between menu and window edge. */ + margin: 64px auto 0; + padding-right: 20px; +} + +.tiny-onboarding-steps { + display: flex; + flex-wrap: wrap; justify-content: center; align-items: center; + gap: 12px; + margin: 0; + padding: 0; + list-style: none; +} + +.tiny-onboarding-steps li { + display: flex; + align-items: center; + gap: 8px; + margin: 0; + color: #5b5b67; + font-size: 14px; + line-height: 20px; } -.tiny-card { +/* The connector to the previous step. */ +.tiny-onboarding-steps li + li:before { + content: ""; + width: 40px; + height: 2px; + margin-right: 4px; + background: #d4d4db; + border-radius: 1px; +} + +.tiny-onboarding-steps li.tiny-step-done + li:before { + background: var(--wp-admin-theme-color, #2271b1); +} + +@media screen and (max-width: 600px) { + .tiny-onboarding-steps li + li:before { + display: none; + } +} + +.tiny-step-dot { + box-sizing: border-box; + display: flex; + justify-content: center; + align-items: center; + width: 24px; + height: 24px; + color: #5b5b67; + font-size: 12px; + font-weight: 600; + line-height: 16px; + letter-spacing: 0.12px; background: #fff; - border: 1px solid #E1E1E1; - border-radius: 8px; - padding: 12px; + border: 1px solid #ededf1; + border-radius: 12px; +} + +.tiny-step-current { + color: #12141d; + font-weight: 600; +} + +.tiny-step-current .tiny-step-dot { + color: #fff; + background: var(--wp-admin-theme-color, #2271b1); + border: 0; } -.tiny-text-center { + +.tiny-step-done .tiny-step-dot { + color: var(--wp-admin-theme-color, #2271b1); + background: none; + border: 0; +} + +.tiny-onboarding-panda { + display: block; + width: 112px; + height: 112px; +} + +.tiny-onboarding-header { text-align: center; +} + +.tiny-onboarding-header h1 { + margin: 0 0 8px; + padding: 0; + color: #12141d; + font-size: 24px; + font-weight: 600; + line-height: 32px; +} + +.tiny-onboarding-header p { + margin: 0; + color: #5b5b67; + font-size: 14px; + line-height: 20px; +} + +.tiny-onboarding-card { + box-sizing: border-box; + width: 100%; + background: #fff; + border: 1px solid #ededf1; + border-radius: 12px; +} + +.tiny-card-section { + display: flex; + flex-direction: column; + gap: 16px; + padding: 24px; +} + +.tiny-card-section + .tiny-card-section { + border-top: 1px solid #ededf1; +} + +.tiny-card-section .notice { + margin: 0; +} + +.tiny-option { + display: flex; + align-items: flex-start; + gap: 12px; + margin: 0; + cursor: pointer; +} + +.tiny-option-text { + display: flex; + flex-direction: column; + gap: 2px; + color: #5b5b67; + font-size: 16px; + line-height: 24px; +} + +.tiny-option-label { + color: #4a4b56; + font-weight: 500; +} + +/* Toggle switch, drawn over WordPress' own checkbox styles. */ +.tiny-option input[type="checkbox"] { + box-sizing: border-box; + position: relative; + flex: none; + width: 44px; + min-width: 44px; + height: 24px; + margin: 0; + background: #ededf1; + border: 0; + border-radius: 12px; + box-shadow: none; + transition: background-color 0.15s; +} + +.tiny-option input[type="checkbox"]:before, +.tiny-option input[type="checkbox"]:checked:before { + content: ""; + position: absolute; + top: 2px; + left: 2px; + float: none; + width: 20px; + height: 20px; + margin: 0; + background: #fff; + border-radius: 50%; + box-shadow: 0 1px 2px rgba(18, 20, 29, 0.06); + transition: transform 0.15s; +} + +.tiny-option input[type="checkbox"]:checked { + background: var(--wp-admin-theme-color, #2271b1); +} + +.tiny-option input[type="checkbox"]:checked:before { + transform: translateX(20px); +} + +/* Radio button, drawn over WordPress' own radio styles. */ +.tiny-option input[type="radio"] { + box-sizing: border-box; + flex: none; + width: 20px; + min-width: 20px; + height: 20px; + margin: 2px 0 0; + background: #fff; + border: 1px solid #b8b8c1; + border-radius: 50%; + box-shadow: none; +} + +.tiny-option input[type="radio"]:checked { + background: var(--wp-admin-theme-color, #2271b1); + border-color: var(--wp-admin-theme-color, #2271b1); +} + +.tiny-option input[type="radio"]:checked:before { + content: ""; + display: block; + float: none; + width: 8px; + height: 8px; + margin: 5px; + text-indent: 0; + background: #fff; + border-radius: 50%; +} + +.tiny-option input[type="checkbox"]:focus, +.tiny-option input[type="radio"]:focus { + box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--wp-admin-theme-color, #2271b1); + outline: 2px solid transparent; +} + +.tiny-format-options { + display: flex; + flex-direction: column; + gap: 16px; + padding-left: 52px; +} + +.tiny-format-options[hidden] { + display: none; +} + +.tiny-option-group { + margin: 0; + color: #12141d; + font-size: 14px; + font-weight: 600; + line-height: 20px; +} + +.tiny-format-note { + margin: 0; + color: #5b5b67; + font-size: 14px; + line-height: 20px; } \ No newline at end of file diff --git a/src/js/admin.js b/src/js/admin.js index f971aa75..c2189265 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -136,19 +136,92 @@ } /** - * Does nothing outside of onboarding - * If key is active, shows continue button + * Creates an account or connects an API key from the account connect view, + * then opens the onboarding step in the page's data-create-key-next or + * data-update-key-next. A failure is shown under the field it is about. */ - function updateOnboardingContinue() { - const button = jQuery('#tiny-onboarding-continue'); - if (!button.length) { + async function submitAccountConnect(event) { + event.preventDefault(); + + const button = event.target; + const column = button.closest('.tiny-account-connect-column'); + const spinner = column.querySelector('.spinner'); + const action = button.dataset.tinyAction === 'create-key' ? 'create' : 'update'; + const name = document.querySelector('#tinypng_api_key_name')?.value ?? ''; + const email = document.querySelector('#tinypng_api_key_email')?.value ?? ''; + const key = document.querySelector('#tinypng_api_key').value; + let field; + + if (action === 'update') { + field = document.querySelector('#tinypng_api_key').closest('.tiny-field'); + } else if (!name) { + // The server only rejects the name when it is missing. + field = document.querySelector('#tinypng_api_key_name').closest('.tiny-field'); + } else { + field = document.querySelector('#tinypng_api_key_email').closest('.tiny-field'); + } + + column.querySelectorAll('.tiny-field').forEach((f) => f.classList.remove('tiny-field-invalid')); + + // The server saves a blank key as "no key", which is not a connection. + if (action === 'update' && !key) { + field.classList.add('tiny-field-invalid'); return; } - const status = jQuery('#tiny-account-status p.status').closest('div.status'); - const valid = status.hasClass('status-success') || status.hasClass('status-pending'); + const showError = (message) => { + button.disabled = false; + spinner.classList.remove('is-active'); + // The API key field keeps the invalid key message from the view. + if (action === 'create') { + field.querySelector('.tiny-field-error').textContent = message; + } + field.classList.add('tiny-field-invalid'); + }; + + button.disabled = true; + spinner.classList.add('is-active'); - button.toggle(valid); + try { + const response = await fetch(ajaxurl, { + method: 'POST', + body: new URLSearchParams({ + _nonce: tinyCompress.nonce, + action: `tiny_settings_${action}_api_key`, + key, + name, + email, + }), + }); + if (!response.ok) { + throw new Error(response.statusText); + } + const status = await response.json(); + if (status.ok) { + window.location.href = document.querySelector('.tiny-onboarding').dataset[`${action}KeyNext`]; + } else { + showError(status.message); + } + } catch (err) { + showError('Something went wrong, try again soon'); + } + } + + /** + * Opens the next onboarding step once the account is activated from the email. + * The account status markup has status-success once the key works. + */ + async function continueWhenActivated() { + const separator = ajaxurl.includes('?') ? '&' : '?'; + try { + const html = await fetch(`${ajaxurl}${separator}action=tiny_account_status`).then(r => r.text()); + const status = new DOMParser().parseFromString(html, 'text/html'); + if (status.querySelector('.status-success')) { + window.location.href = document.querySelector('.tiny-onboarding').dataset.activatedNext; + } + } finally { + setTimeout(continueWhenActivated, 5000); + } } function submitKey(event) { @@ -191,8 +264,6 @@ jQuery.get(ajaxurl + (ajaxurl.indexOf( '?' ) > 0 ? '&' : '?') + 'action=tiny_account_status', function(data) { jQuery(event.target).attr({disabled: false}).removeClass('loading'); target.replaceWith(data); - // The refreshed markup reports whether the key actually works. - updateOnboardingContinue(); }); } jQuery('div.tiny-notice[data-name="setting"]').remove(); @@ -331,17 +402,23 @@ eventOn('click', 'button.tiny-compress', compressImage); break; case 'settings_page_tiny-onboarding-1': - changeEnterKeyTarget('div.tiny-account-status create', '[data-tiny-action=create-key]'); - changeEnterKeyTarget('div.tiny-account-status update', '[data-tiny-action=update-key]'); + changeEnterKeyTarget('#tinypng_api_key_name, #tinypng_api_key_email', '[data-tiny-action=create-key]'); + changeEnterKeyTarget('#tinypng_api_key', '[data-tiny-action=update-key]'); - eventOn('click', '[data-tiny-action=create-key]', submitKey); - eventOn('click', '[data-tiny-action=update-key]', submitKey); - - updateOnboardingContinue(); + eventOn('click', '[data-tiny-action=create-key]', submitAccountConnect); + eventOn('click', '[data-tiny-action=update-key]', submitAccountConnect); + break; + case 'settings_page_tiny-onboarding-2': + setTimeout(continueWhenActivated, 5000); + break; + case 'settings_page_tiny-onboarding-3': + eventOn('change', '#tiny-convert', (event) => { + document.querySelector('#tiny-format-options').hidden = !event.target.checked; + }); break; case 'settings_page_tinify': - changeEnterKeyTarget('div.tiny-account-status create', '[data-tiny-action=create-key]'); - changeEnterKeyTarget('div.tiny-account-status update', '[data-tiny-action=update-key]'); + changeEnterKeyTarget('div.tiny-account-status div.create', '[data-tiny-action=create-key]'); + changeEnterKeyTarget('div.tiny-account-status div.update', '[data-tiny-action=update-key]'); eventOn('click', '[data-tiny-action=create-key]', submitKey); eventOn('click', '[data-tiny-action=update-key]', submitKey); diff --git a/src/views/account-status-connect.php b/src/views/account-status-connect.php new file mode 100644 index 00000000..0aa338ba --- /dev/null +++ b/src/views/account-status-connect.php @@ -0,0 +1,95 @@ +%s', + esc_html__( 'API dashboard', 'tiny-compress-images' ) +); +?> + diff --git a/src/views/onboarding-1.php b/src/views/onboarding-1.php index c6b8fa3c..4fca6b31 100644 --- a/src/views/onboarding-1.php +++ b/src/views/onboarding-1.php @@ -1,20 +1,19 @@ -
-

-

- -

-
- settings->render_account_status(); ?> +
+ render_steps( 1 ); ?> + +
+

+

+ +

- + settings->render_account_connect(); ?>
diff --git a/src/views/onboarding-2.php b/src/views/onboarding-2.php index c933515f..e3f791ec 100644 --- a/src/views/onboarding-2.php +++ b/src/views/onboarding-2.php @@ -1,64 +1,39 @@ -
-

-

- -
- -

- -
-

- - > - -

-

- - > - +

+ render_steps( 2 ); ?> + +
+

+

+

-

- - - -

-

- - - -

+
+
+
+

+

+
+

+ + + + + + +

+
+
diff --git a/src/views/onboarding-3.php b/src/views/onboarding-3.php new file mode 100644 index 00000000..cec0fa49 --- /dev/null +++ b/src/views/onboarding-3.php @@ -0,0 +1,194 @@ +settings->is_api_key_pending(); + +/* Stores the account's email and plan, which the connect request did not. */ +if ( ! $tiny_key_pending ) { + $this->settings->get_compressor()->get_status(); +} + +$tiny_stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); +$tiny_uncompressed = count( $tiny_stats['available-for-optimization'] ); +?> + +
+ + + + render_steps( 3, $tiny_confirm_email ); ?> + +
+

+

+ +

+
+ +
+
+
+

+ settings->get_email_address() ) + ); + ?> +

+ settings->is_on_free_plan() ) { ?> +

+ +
+ +
+

+ settings->get_email_address() ) + ); + ?> +

+
+ +
+ +
+
+

+
+ +
+ +
+
+

+
+ + +
> +

+ + + + + +

+ + + + +

+ +

+
+
+ +
+
+

+ 0 ) { + printf( + esc_html( + /* translators: %s: number of images */ + _n( + 'Your library has %s image that isn’t compressed yet.', + 'Your library has %s images that aren’t compressed yet.', + $tiny_uncompressed, + 'tiny-compress-images' + ) + ), + esc_html( number_format_i18n( $tiny_uncompressed ) ) + ); + } else { + esc_html_e( 'Your library has no images that need compressing.', 'tiny-compress-images' ); + } + ?> +

+

+
+

+ + +

+
+
+
diff --git a/src/views/onboarding-steps.php b/src/views/onboarding-steps.php new file mode 100644 index 00000000..2a33a1c6 --- /dev/null +++ b/src/views/onboarding-steps.php @@ -0,0 +1,44 @@ + __( 'Account', 'tiny-compress-images' ), + 2 => __( 'Confirm email', 'tiny-compress-images' ), + 3 => __( 'Settings', 'tiny-compress-images' ), +); +if ( ! $confirm_email ) { + unset( $tiny_steps[2] ); +} +$tiny_number = 0; +?> +
    + $tiny_label ) { ?> + + +
  1. + + + + +
  2. + +
  3. + + +
  4. + +
  5. + + +
  6. + + +
diff --git a/test/unit/TinySettingsAdminTest.php b/test/unit/TinySettingsAdminTest.php index 37a7c1f0..f29541ac 100644 --- a/test/unit/TinySettingsAdminTest.php +++ b/test/unit/TinySettingsAdminTest.php @@ -508,7 +508,5 @@ function apache_get_modules() { $this->subject->render_delivery_method(); $output = ob_get_clean(); $this->assertStringContainsString( 'Conversion delivery', $output ); - - } } From 4b470d1e7f16d4df216c4ee32e4c685690130957 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 12 Oct 2026 16:51:06 +0200 Subject: [PATCH 28/68] phpcs --- src/class-tiny-onboarding.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index b70f7f54..c08120aa 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -50,7 +50,7 @@ public function __construct( $settings ) { $this->settings = $settings; } - function admin_init() { + public function admin_init() { add_action( 'admin_post_tiny_onboarding_save_settings', $this->get_method( 'save_settings' ) @@ -111,7 +111,7 @@ function () use ( $step ) { add_action( 'load-' . $hook, $this->get_method( 'set_page_title' ) ); } - function admin_menu() { + public function admin_menu() { $this->page_title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); $this->add_sub_menu( 1 ); @@ -134,7 +134,7 @@ public function set_page_title() { * * @return boolean true if onboarded */ - function is_onboarded() { + private function is_onboarded() { $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); return 1 === (int) get_option( $onboarding_status_field, 1 ); } @@ -177,7 +177,7 @@ public function get_step_url( $step ) { * * @param int $is_onboarded status */ - static function set_is_onboarded( $is_onboarded ) { + public static function set_is_onboarded( $is_onboarded ) { $onboarding_status_field = self::get_prefixed_name( 'onboarding_status' ); return update_option( $onboarding_status_field, $is_onboarded ); } @@ -252,7 +252,7 @@ public function save_settings() { * A site that already has a key, or that has compressed before, keeps the * default onboarded state so it is never sent through onboarding again. */ - static function on_activate() { + public static function on_activate() { $api_key = get_option( self::get_prefixed_name( 'api_key' ) ); $compression_count = get_option( self::get_prefixed_name( 'status' ) ); From 6a53d2f7b9f97b58df2cc296c67ccc216c288ac1 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 12 Oct 2026 20:32:05 +0200 Subject: [PATCH 29/68] use css variables --- src/css/admin.css | 117 +++++++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/src/css/admin.css b/src/css/admin.css index 8ac70ba7..e4c12673 100644 --- a/src/css/admin.css +++ b/src/css/admin.css @@ -1,3 +1,22 @@ +body { + --tiny-theme-default: var(--wp-admin-theme-color, #2271b1); + --tiny-text-primary: #12141d; + --tiny-text-secondary: #5b5b67; + --tiny-text-inverse: #fff; + --tiny-surface-primary: #fff; + --tiny-surface-subtle: #ededf1; + --tiny-border-default: #ededf1; + --tiny-border-emphasis: #d4d4db; + --tiny-neutral-300: #b8b8c1; + --tiny-neutral-500: #7a7a86; + --tiny-neutral-700: #4a4b56; + --tiny-neutral-900: #1e2029; + --tiny-red-300: #fca5a5; + --tiny-red-500: #ef4444; + --tiny-shadow-xs: 0 1px 2px rgba(18, 20, 29, 0.05); + --tiny-shadow-sm: 0 1px 2px rgba(18, 20, 29, 0.06); +} + div.misc-pub-section.tiny-compress-images { border-top: 1px solid #e1e1e1; padding-bottom: 16px; @@ -488,8 +507,8 @@ fieldset.tinypng_convert_fields[disabled] { box-sizing: border-box; display: flex; width: 100%; - background: #fff; - border: 1px solid #ededf1; + background: var(--tiny-surface-primary); + border: 1px solid var(--tiny-border-default); border-radius: 12px; } @@ -503,7 +522,7 @@ fieldset.tinypng_convert_fields[disabled] { } .tiny-account-connect-column + .tiny-account-connect-column { - border-left: 1px solid #ededf1; + border-left: 1px solid var(--tiny-border-default); } @media screen and (max-width: 600px) { @@ -512,7 +531,7 @@ fieldset.tinypng_convert_fields[disabled] { } .tiny-account-connect-column + .tiny-account-connect-column { - border-top: 1px solid #ededf1; + border-top: 1px solid var(--tiny-border-default); border-left: 0; } } @@ -520,7 +539,7 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-card-head h2 { margin: 0; padding: 0; - color: #12141d; + color: var(--tiny-text-primary); font-size: 16px; font-weight: 600; line-height: 24px; @@ -528,7 +547,7 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-card-head p { margin: 4px 0 0; - color: #5b5b67; + color: var(--tiny-text-secondary); font-size: 14px; line-height: 20px; } @@ -540,7 +559,7 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-field label { display: block; margin-bottom: 6px; - color: #4a4b56; + color: var(--tiny-neutral-700); font-size: 14px; font-weight: 500; line-height: 20px; @@ -552,40 +571,40 @@ fieldset.tinypng_convert_fields[disabled] { height: auto; margin: 0; padding: 9px 14px; - color: #1e2029; + color: var(--tiny-neutral-900); font-size: 16px; line-height: 24px; - background-color: #fff; - border: 1px solid #b8b8c1; + background-color: var(--tiny-surface-primary); + border: 1px solid var(--tiny-neutral-300); border-radius: 2px; - box-shadow: 0 1px 2px rgba(18, 20, 29, 0.05); + box-shadow: var(--tiny-shadow-xs); } .tiny-field input[type="text"]::placeholder { - color: #7a7a86; + color: var(--tiny-neutral-500); } .tiny-field input[type="text"]:focus { - border-color: var(--wp-admin-theme-color, #2271b1); - box-shadow: 0 0 0 1px var(--wp-admin-theme-color, #2271b1); + border-color: var(--tiny-theme-default); + box-shadow: 0 0 0 1px var(--tiny-theme-default); outline: 2px solid transparent; } .tiny-field-invalid input[type="text"] { padding-right: 38px; - background: #fff url("../images/alert-circle.svg") no-repeat right 14px center; - border-color: #fca5a5; + background: var(--tiny-surface-primary) url("../images/alert-circle.svg") no-repeat right 14px center; + border-color: var(--tiny-red-300); } .tiny-field-invalid input[type="text"]:focus { - border-color: #fca5a5; - box-shadow: 0 0 0 1px #fca5a5; + border-color: var(--tiny-red-300); + box-shadow: 0 0 0 1px var(--tiny-red-300); } .tiny-field-error { display: none; margin: 6px 0 0; - color: #ef4444; + color: var(--tiny-red-500); font-size: 14px; line-height: 20px; } @@ -617,7 +636,7 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-actions a, .tiny-actions .button-link { - color: var(--wp-admin-theme-color, #2271b1); + color: var(--tiny-theme-default); font-size: 14px; font-weight: 600; line-height: 20px; @@ -657,7 +676,7 @@ fieldset.tinypng_convert_fields[disabled] { align-items: center; gap: 8px; margin: 0; - color: #5b5b67; + color: var(--tiny-text-secondary); font-size: 14px; line-height: 20px; } @@ -668,12 +687,12 @@ fieldset.tinypng_convert_fields[disabled] { width: 40px; height: 2px; margin-right: 4px; - background: #d4d4db; + background: var(--tiny-border-emphasis); border-radius: 1px; } .tiny-onboarding-steps li.tiny-step-done + li:before { - background: var(--wp-admin-theme-color, #2271b1); + background: var(--tiny-theme-default); } @media screen and (max-width: 600px) { @@ -689,29 +708,29 @@ fieldset.tinypng_convert_fields[disabled] { align-items: center; width: 24px; height: 24px; - color: #5b5b67; + color: var(--tiny-text-secondary); font-size: 12px; font-weight: 600; line-height: 16px; letter-spacing: 0.12px; - background: #fff; - border: 1px solid #ededf1; + background: var(--tiny-surface-primary); + border: 1px solid var(--tiny-border-default); border-radius: 12px; } .tiny-step-current { - color: #12141d; + color: var(--tiny-text-primary); font-weight: 600; } .tiny-step-current .tiny-step-dot { - color: #fff; - background: var(--wp-admin-theme-color, #2271b1); + color: var(--tiny-text-inverse); + background: var(--tiny-theme-default); border: 0; } .tiny-step-done .tiny-step-dot { - color: var(--wp-admin-theme-color, #2271b1); + color: var(--tiny-theme-default); background: none; border: 0; } @@ -729,7 +748,7 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-onboarding-header h1 { margin: 0 0 8px; padding: 0; - color: #12141d; + color: var(--tiny-text-primary); font-size: 24px; font-weight: 600; line-height: 32px; @@ -737,7 +756,7 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-onboarding-header p { margin: 0; - color: #5b5b67; + color: var(--tiny-text-secondary); font-size: 14px; line-height: 20px; } @@ -745,8 +764,8 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-onboarding-card { box-sizing: border-box; width: 100%; - background: #fff; - border: 1px solid #ededf1; + background: var(--tiny-surface-primary); + border: 1px solid var(--tiny-border-default); border-radius: 12px; } @@ -758,7 +777,7 @@ fieldset.tinypng_convert_fields[disabled] { } .tiny-card-section + .tiny-card-section { - border-top: 1px solid #ededf1; + border-top: 1px solid var(--tiny-border-default); } .tiny-card-section .notice { @@ -777,13 +796,13 @@ fieldset.tinypng_convert_fields[disabled] { display: flex; flex-direction: column; gap: 2px; - color: #5b5b67; + color: var(--tiny-text-secondary); font-size: 16px; line-height: 24px; } .tiny-option-label { - color: #4a4b56; + color: var(--tiny-neutral-700); font-weight: 500; } @@ -796,7 +815,7 @@ fieldset.tinypng_convert_fields[disabled] { min-width: 44px; height: 24px; margin: 0; - background: #ededf1; + background: var(--tiny-surface-subtle); border: 0; border-radius: 12px; box-shadow: none; @@ -813,14 +832,14 @@ fieldset.tinypng_convert_fields[disabled] { width: 20px; height: 20px; margin: 0; - background: #fff; + background: var(--tiny-surface-primary); border-radius: 50%; - box-shadow: 0 1px 2px rgba(18, 20, 29, 0.06); + box-shadow: var(--tiny-shadow-sm); transition: transform 0.15s; } .tiny-option input[type="checkbox"]:checked { - background: var(--wp-admin-theme-color, #2271b1); + background: var(--tiny-theme-default); } .tiny-option input[type="checkbox"]:checked:before { @@ -835,15 +854,15 @@ fieldset.tinypng_convert_fields[disabled] { min-width: 20px; height: 20px; margin: 2px 0 0; - background: #fff; - border: 1px solid #b8b8c1; + background: var(--tiny-surface-primary); + border: 1px solid var(--tiny-neutral-300); border-radius: 50%; box-shadow: none; } .tiny-option input[type="radio"]:checked { - background: var(--wp-admin-theme-color, #2271b1); - border-color: var(--wp-admin-theme-color, #2271b1); + background: var(--tiny-theme-default); + border-color: var(--tiny-theme-default); } .tiny-option input[type="radio"]:checked:before { @@ -854,13 +873,13 @@ fieldset.tinypng_convert_fields[disabled] { height: 8px; margin: 5px; text-indent: 0; - background: #fff; + background: var(--tiny-text-inverse); border-radius: 50%; } .tiny-option input[type="checkbox"]:focus, .tiny-option input[type="radio"]:focus { - box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--wp-admin-theme-color, #2271b1); + box-shadow: 0 0 0 2px var(--tiny-surface-primary), 0 0 0 4px var(--tiny-theme-default); outline: 2px solid transparent; } @@ -877,7 +896,7 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-option-group { margin: 0; - color: #12141d; + color: var(--tiny-text-primary); font-size: 14px; font-weight: 600; line-height: 20px; @@ -885,7 +904,7 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-format-note { margin: 0; - color: #5b5b67; + color: var(--tiny-text-secondary); font-size: 14px; line-height: 20px; } \ No newline at end of file From c32287c39b7f395a98151d48ecd8ed60124342e9 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 13 Oct 2026 09:03:01 +0200 Subject: [PATCH 30/68] do not redirect on admin_init --- src/class-tiny-onboarding.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index c08120aa..d03d8396 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -65,9 +65,6 @@ public function admin_init() { if ( self::is_bulk_activation() ) { return; } - - wp_safe_redirect( $this->get_step_url( 1 ) ); - exit(); } /** From aeafc66bf6e7732c03ae348ec424e4ba1f06cb50 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 13 Oct 2026 09:39:59 +0200 Subject: [PATCH 31/68] reuse rendering for modern formats --- src/class-tiny-settings.php | 37 +++++----- src/css/admin.css | 4 +- src/views/onboarding-3.php | 98 ++------------------------- src/views/onboarding-steps.php | 4 -- src/views/settings-modern-formats.php | 70 +++++++++++++++++++ 5 files changed, 94 insertions(+), 119 deletions(-) create mode 100644 src/views/settings-modern-formats.php diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index b88ab07e..176eeb1b 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -219,7 +219,7 @@ protected function get_api_key() { } } - protected function get_api_key_pending() { + public function get_api_key_pending() { if ( defined( 'TINY_API_KEY' ) ) { return false; } else { @@ -231,25 +231,6 @@ protected function clear_api_key_pending() { delete_option( self::get_prefixed_name( 'api_key_pending' ) ); } - /** - * Whether the API key of a new account still waits for its email to be - * confirmed. While pending, asks the API and clears it once the key works. - * - * @return bool - */ - public function is_api_key_pending() { - if ( ! $this->get_api_key_pending() ) { - return false; - } - - if ( $this->compressor->get_status()->ok ) { - $this->clear_api_key_pending(); - return false; - } - - return true; - } - protected static function get_intermediate_size( $size ) { /* Inspired by @@ -885,6 +866,22 @@ public function render_account_connect() { include __DIR__ . '/views/account-status-connect.php'; } + /** + * Renders the switch for WebP or AVIF versions, with the format and the delivery to use. + * Server rules are recommended, so they are selected when Apache can rewrite and + * no delivery was chosen yet. + */ + public function render_modern_formats() { + $convert = $this->get_conversion_enabled(); + $convert_to = self::get_convert_format_option( 'convert_to', 'smallest' ); + $server_rules = self::can_render_delivery_method(); + $delivery = self::get_convert_format_option( + 'delivery_method', + $server_rules ? 'htaccess' : 'picture' + ); + include __DIR__ . '/views/settings-modern-formats.php'; + } + public function render_pending_status() { $key = $this->get_api_key(); if ( empty( $key ) ) { diff --git a/src/css/admin.css b/src/css/admin.css index e4c12673..938d902d 100644 --- a/src/css/admin.css +++ b/src/css/admin.css @@ -795,7 +795,6 @@ fieldset.tinypng_convert_fields[disabled] { .tiny-option-text { display: flex; flex-direction: column; - gap: 2px; color: var(--tiny-text-secondary); font-size: 16px; line-height: 24px; @@ -806,7 +805,6 @@ fieldset.tinypng_convert_fields[disabled] { font-weight: 500; } -/* Toggle switch, drawn over WordPress' own checkbox styles. */ .tiny-option input[type="checkbox"] { box-sizing: border-box; position: relative; @@ -814,7 +812,7 @@ fieldset.tinypng_convert_fields[disabled] { width: 44px; min-width: 44px; height: 24px; - margin: 0; + margin: 4px 0; background: var(--tiny-surface-subtle); border: 0; border-radius: 12px; diff --git a/src/views/onboarding-3.php b/src/views/onboarding-3.php index cec0fa49..838d14c3 100644 --- a/src/views/onboarding-3.php +++ b/src/views/onboarding-3.php @@ -1,33 +1,6 @@ settings->is_api_key_pending(); - -/* Stores the account's email and plan, which the connect request did not. */ -if ( ! $tiny_key_pending ) { - $this->settings->get_compressor()->get_status(); -} - +$tiny_key_pending = $this->settings->get_api_key_pending(); +$tiny_auto_compress = $this->settings->get_compression_timing() === 'auto'; $tiny_stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); $tiny_uncompressed = count( $tiny_stats['available-for-optimization'] ); ?> @@ -36,7 +9,7 @@ - render_steps( 3, $tiny_confirm_email ); ?> + render_steps( 3 ); ?>
@@ -91,71 +64,12 @@ > - +
-
-
-

-
- - -
> -

- - - - - -

- - - - -

- -

-
-
+ settings->render_modern_formats(); ?>
@@ -183,7 +97,7 @@

+ = 1 ) { ?> + +

+

+ +

+ +
+ +
+

+
-
diff --git a/src/views/progress-circle.php b/src/views/progress-circle.php deleted file mode 100644 index b62d5f56..00000000 --- a/src/views/progress-circle.php +++ /dev/null @@ -1,75 +0,0 @@ - - - -
- -
-
%
- -
- -
-
diff --git a/test/integration/dashboardwidget.spec.ts b/test/integration/dashboardwidget.spec.ts index 8efe1d18..f672888c 100644 --- a/test/integration/dashboardwidget.spec.ts +++ b/test/integration/dashboardwidget.spec.ts @@ -1,5 +1,5 @@ import { Page, expect, test } from '@playwright/test'; -import { clearMediaLibrary, setAPIKey, setCompressionTiming, uploadMedia, enableCompressionSizes } from './utils'; +import { clearMediaLibrary, setAPIKey, setCompressionTiming, uploadImages, uploadMedia, enableCompressionSizes } from './utils'; test.describe.configure({ mode: 'serial' }); @@ -17,8 +17,6 @@ async function setAccount(key: string) { test.describe('dashboardwidget', () => { test.beforeAll(async ({ browser }) => { - // The widget hides its notices when narrower than 560px, which it is - // in the two column dashboard at the default 1280px viewport. page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); await setAPIKey(page, ''); await setCompressionTiming(page, 'auto'); @@ -27,62 +25,82 @@ test.describe('dashboardwidget', () => { test.beforeEach(async () => { await clearMediaLibrary(page); + await page.context().clearCookies({ name: /^tiny_test_/ }); }); - test('show widget without images', async () => { - await setAPIKey(page, 'JPG123'); + test('not connected without api key', async () => { + await setAPIKey(page, ''); + await uploadMedia(page, 'input-example.png'); await page.goto('/wp-admin/index.php'); - await expect(widget().getByText('George is hungry')).toBeVisible(); - await expect(widget().getByText('There are no images uploaded yet.')).toBeVisible(); + await expect(widget().getByText('Not connected')).toBeVisible(); + await expect(widget().getByText('0%')).toBeVisible(); + await expect(widget().getByText('1 to compress')).toBeVisible(); + await expect(widget().getByRole('link', { name: 'Connect Tinify' })).toHaveAttribute('href', /page=tinify/); }); - test('show notice without api key', async () => { - await setAPIKey(page, ''); + test('no images yet', async () => { + await setAPIKey(page, 'JPG123'); await page.goto('/wp-admin/index.php'); - await expect(widget().getByText('Please register or provide an API key to start compressing images.')).toBeVisible(); + await expect(widget().getByText('No images yet')).toBeVisible(); + await expect(widget().getByRole('link', { name: 'Upload images' })).toHaveAttribute('href', /media-new\.php/); }); - test('show widget with images to optimize', async () => { - // It won't compress images without an API Key - await setAPIKey(page, ''); - await uploadMedia(page, 'input-example.png'); + test('ready to compress', async () => { + await setAccount('JPG123'); + await setCompressionTiming(page, 'manual'); + await uploadImages(page, 'input-example.jpg'); await page.goto('/wp-admin/index.php'); - await expect(widget().getByText('1 image needs optimization')).toBeVisible(); - await expect(widget().getByText('Please register or provide an API key to start compressing images.')).toBeVisible(); - await expect(widget().getByRole('link', { name: 'Bulk Optimizer' })).toBeVisible(); + await expect(widget().getByText('Ready to compress')).toBeVisible(); + await expect(widget().getByRole('link', { name: 'Compress 1 image' })).toHaveAttribute('href', /page=tiny-bulk-optimization&start=1$/); }); - test('show widget with all images optimized', async () => { + test('all done', async () => { await setAPIKey(page, 'JPG123'); + await setCompressionTiming(page, 'auto'); await uploadMedia(page, 'input-example.jpg'); await page.goto('/wp-admin/index.php'); - await expect(widget().getByText('All images are optimized')).toBeVisible(); + await expect(widget().getByText('All done')).toBeVisible(); await expect(widget().getByText('100%')).toBeVisible(); - await expect(widget().getByRole('link', { name: 'Bulk Optimizer' })).not.toBeVisible(); + await expect(widget().getByText('1 compressed')).toBeVisible(); }); - test('show notice with low credits on free plan', async () => { - await setAccount('INSUFFICIENTCREDITS123'); + test('start flag starts the bulk optimization', async () => { + await setAPIKey(page, 'JPG123'); + await setCompressionTiming(page, 'manual'); + await uploadImages(page, 'input-example.jpg', 1, { generateSizes: false }); - await page.goto('/wp-admin/index.php'); + await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization&start=1'); - await expect(widget().getByText('You are on a free plan with 1 compression left.')).toBeVisible(); + await expect(page).toHaveURL(/page=tiny-bulk-optimization$/); + await expect(page.locator('#compression-progress-bar')).toHaveText('1 / 1 (100%)'); }); - test('not show credits on paid plan', async () => { - await setAccount('JPG123'); + test('upgrade shows how to get more credits', async () => { + await setAccount('INSUFFICIENTCREDITS123'); + await setCompressionTiming(page, 'auto'); + await uploadImages(page, 'input-example.jpg'); await page.goto('/wp-admin/index.php'); - await expect(widget().getByText('George is hungry')).toBeVisible(); - await expect(widget().getByText('compressions left')).not.toBeVisible(); + await expect(widget().getByText('Not enough credits')).toBeVisible(); + await widget().getByRole('button', { name: 'Upgrade' }).click(); + + await expect(widget().getByText('Get more credits')).toBeVisible(); + await expect(widget().getByText('Not enough credits')).not.toBeVisible(); + await expect(widget().getByRole('link', { name: 'Buy a credit bundle' })).toHaveAttribute('href', 'https://tinify.com/checkout/credits?utm_source=wordpress-plugin&utm_medium=referral&utm_campaign=upgrade&utm_content=dashboard-widget-credits'); + await expect(widget().getByRole('link', { name: 'Switch to pay per compression' })).toHaveAttribute('href', 'https://tinify.com/checkout/api?utm_source=wordpress-plugin&utm_medium=referral&utm_campaign=upgrade&utm_content=dashboard-widget-api'); + + await widget().getByRole('button', { name: 'Back' }).click(); + + await expect(widget().getByText('Not enough credits')).toBeVisible(); + await expect(widget().getByText('Get more credits')).not.toBeVisible(); }); }); diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index a802b6fc..5c0f8c0e 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -9,10 +9,16 @@ class Tiny_Dashboard_Test extends Tiny_TestCase */ private $settings; + /** + * @var Tiny_Background_Optimize|\PHPUnit\Framework\MockObject\MockObject + */ + private $background_optimizer; + public function set_up() { parent::set_up(); $this->settings = $this->createMock(Tiny_Settings::class); + $this->background_optimizer = $this->createMock(Tiny_Background_Optimize::class); } /** @@ -22,9 +28,10 @@ public function set_up() * @param int $remaining number of images remaining * @param integer $unoptimized_size * @param integer $optimized_size + * @param int $credit_use estimated credits the remaining images need * @return array optimization stats */ - private function stats($uploaded, $remaining, $unoptimized_size = 0, $optimized_size = 0) + private function stats($uploaded, $remaining, $unoptimized_size = 0, $optimized_size = 0, $credit_use = 0) { return array( 'uploaded-images' => $uploaded, @@ -32,219 +39,392 @@ private function stats($uploaded, $remaining, $unoptimized_size = 0, $optimized_ 'available-unoptimized-sizes' => 0, 'optimized-library-size' => $optimized_size, 'unoptimized-library-size' => $unoptimized_size, - 'estimated_credit_use' => 0, + 'estimated_credit_use' => $credit_use, 'available-for-optimization' => array_fill(0, $remaining, array('ID' => 1, 'post_title' => 'image')), 'display-percentage' => 0, ); } - public function test_is_empty_when_there_are_no_images() + /** + * helper to connect an account + * + * @param int|false $remaining_credits credits left, false when unknown + * @param bool $free whether the account is on the free plan + */ + private function connect($remaining_credits = false, $free = true) { - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(0, 0)); + $this->settings->method('has_api_key')->willReturn(true); + $this->settings->method('is_on_free_plan')->willReturn($free); + $this->settings->method('get_remaining_credits')->willReturn($remaining_credits); + } - $this->assertSame('empty', $data['status']); - $this->assertSame(0, $data['percentage']); - $this->assertSame(0, $data['images_remaining']); - $this->assertSame('panda-waiting.png', $data['panda']); + /** + * helper to mark a run as started + * + * @param int $seconds_ago when the run started + * @param int $remaining images the run started with + */ + private function start_run($seconds_ago, $remaining) + { + $this->background_optimizer->method('is_running')->willReturn(true); + $this->wp->addOption(Tiny_Background_Optimize::OPTION_STARTED, array( + 'time' => time() - $seconds_ago, + 'remaining' => $remaining, + )); } - public function test_is_in_progress_when_images_remain() + private function widget_data($stats) { - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(1250, 330)); + $dashboard = new Tiny_Dashboard($this->settings, $this->background_optimizer); + return $dashboard->get_widget_data($stats); + } + + public function test_is_not_connected_without_api_key() + { + $this->settings->method('has_api_key')->willReturn(false); - $this->assertSame('in_progress', $data['status']); + $data = $this->widget_data($this->stats(1250, 330)); + + $this->assertSame('not_connected', $data['state']); $this->assertSame(920, $data['images_optimized']); $this->assertSame(1250, $data['images_total']); $this->assertSame(330, $data['images_remaining']); $this->assertSame(73, $data['percentage']); - $this->assertSame('panda-waiting.png', $data['panda']); + } + + public function test_is_pending_while_api_key_waits_for_activation() + { + $this->connect(); + $this->settings->method('refresh_api_key_pending')->willReturn(true); + $this->settings->method('get_email_address')->willReturn('test@example.com'); + + $data = $this->widget_data($this->stats(10, 10)); + + $this->assertSame('pending', $data['state']); + $this->assertSame('test@example.com', $data['email_address']); + } + + public function test_is_empty_when_there_are_no_images() + { + $this->connect(); + + $data = $this->widget_data($this->stats(0, 0)); + + $this->assertSame('empty', $data['state']); + $this->assertSame(0, $data['percentage']); + } + + public function test_is_compressing_while_a_run_is_going() + { + $this->connect(); + $this->background_optimizer->method('is_running')->willReturn(true); + + $data = $this->widget_data($this->stats(10, 4)); + + $this->assertSame('compressing', $data['state']); + $this->assertNull($data['time_left']); } public function test_is_done_when_no_images_remain() { - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(1250, 0)); + $this->connect(); + + $data = $this->widget_data($this->stats(1250, 0, 5000, 3000)); - $this->assertSame('done', $data['status']); - $this->assertSame(1250, $data['images_optimized']); + $this->assertSame('done', $data['state']); $this->assertSame(100, $data['percentage']); - $this->assertSame('optimized', $data['label']); - $this->assertSame('panda-laying.png', $data['panda']); + $this->assertSame(2000, $data['bytes_saved']); } - public function test_labels_up_to_half_as_getting_started() + public function test_is_out_of_credits_when_none_are_left() { - $dashboard = new Tiny_Dashboard($this->settings); + $this->connect(0); - $one_percent = $dashboard->get_widget_data($this->stats(100, 99)); - $fifty_percent = $dashboard->get_widget_data($this->stats(100, 50)); + $data = $this->widget_data($this->stats(10, 4, 0, 0, 12)); - $this->assertSame('getting started', $one_percent['label']); - $this->assertSame('getting started', $fifty_percent['label']); + $this->assertSame('out_of_credits', $data['state']); } - public function test_labels_above_half_as_halfway_there() + public function test_is_short_of_credits_when_they_do_not_cover_the_remaining_images() { - $dashboard = new Tiny_Dashboard($this->settings); + $this->connect(10); - $fifty_one_percent = $dashboard->get_widget_data($this->stats(100, 49)); - $seventy_five_percent = $dashboard->get_widget_data($this->stats(100, 25)); + $data = $this->widget_data($this->stats(10, 4, 0, 0, 12)); - $this->assertSame('halfway there', $fifty_one_percent['label']); - $this->assertSame('halfway there', $seventy_five_percent['label']); + $this->assertSame('credits_short', $data['state']); + $this->assertSame(12, $data['estimated_credit_use']); } - public function test_labels_above_three_quarters_as_almost_there() + public function test_is_ready_when_credits_cover_the_remaining_images() { - $dashboard = new Tiny_Dashboard($this->settings); + $this->connect(12); - $seventy_six_percent = $dashboard->get_widget_data($this->stats(100, 24)); - $ninety_nine_percent = $dashboard->get_widget_data($this->stats(1000, 1)); + $data = $this->widget_data($this->stats(10, 4, 0, 0, 12)); - $this->assertSame('almost there', $seventy_six_percent['label']); - $this->assertSame('almost there', $ninety_nine_percent['label']); + $this->assertSame('ready', $data['state']); } - public function test_has_no_label_when_nothing_is_optimized() + public function test_is_ready_on_paid_plan_whatever_the_credits() { - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 10)); + $this->connect(0, false); + + $data = $this->widget_data($this->stats(10, 4, 0, 0, 12)); - $this->assertSame('', $data['label']); + $this->assertSame('ready', $data['state']); } - public function test_does_not_show_100_percent_while_images_remain() + public function test_pending_beats_empty() { - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(1000, 1)); + $this->connect(); + $this->settings->method('refresh_api_key_pending')->willReturn(true); - $this->assertSame('in_progress', $data['status']); - $this->assertSame(99, $data['percentage']); + $data = $this->widget_data($this->stats(0, 0)); + + $this->assertSame('pending', $data['state']); } - public function test_bytes_saved_is_the_library_size_reduction() + public function test_compressing_beats_done() { - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 3, 5000, 3000)); + $this->connect(); + $this->background_optimizer->method('is_running')->willReturn(true); - $this->assertSame(2000, $data['bytes_saved']); + $data = $this->widget_data($this->stats(10, 0)); + + $this->assertSame('compressing', $data['state']); + } + + public function test_compressing_beats_out_of_credits() + { + $this->connect(0); + $this->background_optimizer->method('is_running')->willReturn(true); + + $data = $this->widget_data($this->stats(10, 4, 0, 0, 12)); + + $this->assertSame('compressing', $data['state']); + } + + public function test_done_beats_out_of_credits() + { + $this->connect(0); + + $data = $this->widget_data($this->stats(10, 0)); + + $this->assertSame('done', $data['state']); + } + + public function test_does_not_show_100_percent_while_images_remain() + { + $this->connect(); + + $data = $this->widget_data($this->stats(1000, 1)); + + $this->assertSame(99, $data['percentage']); } public function test_bytes_saved_is_never_negative() { - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 3, 3000, 5000)); + $this->connect(); + + $data = $this->widget_data($this->stats(10, 3, 3000, 5000)); $this->assertSame(0, $data['bytes_saved']); } public function test_shows_remaining_credits_on_free_plan() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $this->settings->method('get_remaining_credits')->willReturn('210'); - $this->settings->method('has_api_key')->willReturn(true); + $this->connect('210'); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + $data = $this->widget_data($this->stats(10, 1)); $this->assertSame(210, $data['remaining_credits']); } + public function test_shows_remaining_credits_above_the_monthly_free_credits() + { + $this->connect(1200); + + $data = $this->widget_data($this->stats(10, 1)); + + $this->assertSame(1200, $data['remaining_credits']); + } + + public function test_shows_zero_remaining_credits() + { + $this->connect(0); + + $data = $this->widget_data($this->stats(10, 1)); + + $this->assertSame(0, $data['remaining_credits']); + } + public function test_hides_remaining_credits_on_paid_plan() { - $this->settings->method('is_on_free_plan')->willReturn(false); - $this->settings->method('get_remaining_credits')->willReturn(210); - $this->settings->method('has_api_key')->willReturn(true); + $this->connect(210, false); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + $data = $this->widget_data($this->stats(10, 1)); $this->assertNull($data['remaining_credits']); } public function test_hides_remaining_credits_when_unknown() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $this->settings->method('get_remaining_credits')->willReturn(false); - $this->settings->method('has_api_key')->willReturn(true); + $this->connect(false); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + $data = $this->widget_data($this->stats(10, 1)); $this->assertNull($data['remaining_credits']); } - public function test_has_no_notice_with_enough_credits() + public function test_images_affordable_is_what_the_credits_cover_at_the_average_cost() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $this->settings->method('get_remaining_credits')->willReturn(100); - $this->settings->method('has_api_key')->willReturn(true); + $this->connect(10); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + // 15 images need 30 credits, 2 each, so 10 credits cover 5 images. + $data = $this->widget_data($this->stats(20, 15, 0, 0, 30)); - $this->assertNull($data['notice']); + $this->assertSame(5, $data['images_affordable']); } - public function test_notifies_low_credits_below_100() + public function test_images_affordable_is_zero_without_estimated_credit_use() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $this->settings->method('get_remaining_credits')->willReturn(99); - $this->settings->method('has_api_key')->willReturn(true); + $this->connect(10); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + $data = $this->widget_data($this->stats(20, 15, 0, 0, 0)); - $this->assertSame('low_credits', $data['notice']); + $this->assertSame(0, $data['images_affordable']); } - public function test_notifies_low_credits_when_none_are_left() + public function test_images_affordable_is_zero_without_remaining_images() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $this->settings->method('get_remaining_credits')->willReturn(0); - $this->settings->method('has_api_key')->willReturn(true); + $this->connect(10); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + $data = $this->widget_data($this->stats(20, 0, 0, 0, 0)); - $this->assertSame('low_credits', $data['notice']); + $this->assertSame(0, $data['images_affordable']); } - public function test_does_not_notify_low_credits_on_paid_plan() + public function test_images_affordable_is_zero_without_limited_credits() { - $this->settings->method('is_on_free_plan')->willReturn(false); - $this->settings->method('get_remaining_credits')->willReturn(0); - $this->settings->method('has_api_key')->willReturn(true); + $this->connect(10, false); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + $data = $this->widget_data($this->stats(20, 15, 0, 0, 30)); - $this->assertNull($data['notice']); + $this->assertSame(0, $data['images_affordable']); } - public function test_notifies_missing_api_key() + public function test_time_left_is_unknown_in_the_first_30_seconds() { - $this->settings->method('is_on_free_plan')->willReturn(false); - $this->settings->method('get_remaining_credits')->willReturn(false); - $this->settings->method('has_api_key')->willReturn(false); + $this->connect(); + $this->start_run(29, 20); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + $data = $this->widget_data($this->stats(20, 10)); - $this->assertSame('no_api_key', $data['notice']); + $this->assertNull($data['time_left']); } - public function test_missing_api_key_takes_precedence_over_low_credits() + public function test_time_left_is_unknown_before_the_first_image_is_done() { - $this->settings->method('is_on_free_plan')->willReturn(true); - $this->settings->method('get_remaining_credits')->willReturn(10); - $this->settings->method('has_api_key')->willReturn(false); + $this->connect(); + $this->start_run(120, 20); + + $data = $this->widget_data($this->stats(20, 20)); - $dashboard = new Tiny_Dashboard($this->settings); - $data = $dashboard->get_widget_data($this->stats(10, 1)); + $this->assertNull($data['time_left']); + } - $this->assertSame('no_api_key', $data['notice']); + public function test_time_left_in_minutes() + { + $this->connect(); + $this->start_run(120, 30); + + // 10 done in 120 seconds, so the 20 left take 240 seconds. + $data = $this->widget_data($this->stats(30, 20)); + + $this->assertEqualWithinDelta(240, $data['time_left'], 12); + } + + public function test_time_left_under_a_minute() + { + $this->connect(); + $this->start_run(60, 20); + + // 19 done in 60 seconds, so the last one takes about 3 seconds. + $data = $this->widget_data($this->stats(20, 1)); + + $this->assertEqualWithinDelta(3, $data['time_left'], 1); + } + + public function test_time_left_in_hours() + { + $this->connect(); + $this->start_run(3600, 1000); + + // 10 done in an hour, so the 990 left take 99 hours. + $data = $this->widget_data($this->stats(1000, 990)); + + $this->assertEqualWithinDelta(99 * 3600, $data['time_left'], 100); + } + + public function test_ajax_widget_refuses_an_invalid_nonce_with_a_403() + { + $this->wp->stub('check_ajax_referer', function () { + return false; + }); + $this->wp->stub('current_user_can', function () { + return true; + }); + + $this->assert_ajax_widget_refuses_with_a_403(); + } + + public function test_ajax_widget_refuses_a_user_without_permission_with_a_403() + { + $this->wp->stub('current_user_can', function () { + return false; + }); + + $this->assert_ajax_widget_refuses_with_a_403(); + } + + private function assert_ajax_widget_refuses_with_a_403() + { + $this->wp->addMethod('status_header'); + $this->wp->addMethod('wp_die'); + $this->wp->stub('wp_die', function () { + throw new Exception('wp_die'); + }); + + $dashboard = new Tiny_Dashboard($this->settings, $this->background_optimizer); + try { + $dashboard->ajax_widget(); + } catch (Exception $e) { + // wp_die() ends the request. + } + + $this->assertEquals(array(array(403)), $this->wp->getCalls('status_header')); + $this->assertEquals(array(array(-1, 403)), $this->wp->getCalls('wp_die')); + } + + public function test_ajax_widget_sends_the_rendered_widget() + { + $this->wp->stub('current_user_can', function () { + return true; + }); + $this->wp->addMethod('wp_send_json_success'); + + $dashboard = $this->getMockBuilder(Tiny_Dashboard::class) + ->setConstructorArgs(array($this->settings, $this->background_optimizer)) + ->onlyMethods(array('add_widget_view')) + ->getMock(); + $dashboard->method('add_widget_view')->willReturnCallback(function () { + echo '
'; + }); + + $dashboard->ajax_widget(); + + $this->assertEquals( + array(array(array('html' => '
'))), + $this->wp->getCalls('wp_send_json_success') + ); } } From d2efee380e1615c0751c2f9f21a442f5952931b2 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 19 Oct 2026 21:40:57 +0200 Subject: [PATCH 35/68] style: lighten the widget badge --- src/css/dashboard-widget.css | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/css/dashboard-widget.css b/src/css/dashboard-widget.css index 84f644e9..d4201224 100644 --- a/src/css/dashboard-widget.css +++ b/src/css/dashboard-widget.css @@ -47,27 +47,24 @@ } .tiny-widget-badge { - padding: 4px 12px; - border: 1px solid; - border-radius: 8px; + padding: 2px 10px; + border-radius: 9999px; + font-size: 13px; font-weight: 600; } .tiny-widget-badge-red { background: #fef2f2; - border-color: #dc2626; color: #dc2626; } .tiny-widget-badge-amber { background: #fef3c7; - border-color: #b45309; color: #b45309; } .tiny-widget-badge-green { background: #e8faf0; - border-color: #00b075; color: #00b075; } From 2b7091daaa55b997fa2725863e66307f58104dc4 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 19 Oct 2026 21:55:49 +0200 Subject: [PATCH 36/68] refactor: remove dashboard widget polling --- src/class-tiny-dashboard.php | 31 --------------- src/js/dashboard-widget.js | 54 -------------------------- test/unit/Tiny_Dashboard_Test.php | 63 ------------------------------- 3 files changed, 148 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 059d336b..ca87a58e 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -39,13 +39,6 @@ public function __construct( $settings, $background_optimizer ) { $this->background_optimizer = $background_optimizer; } - public function ajax_init() { - add_action( - 'wp_ajax_tiny_dashboard_widget', - $this->get_method( 'ajax_widget' ) - ); - } - public function admin_init() { if ( current_user_can( 'upload_files' ) ) { add_action( @@ -71,15 +64,6 @@ public function add_dashboard_widget() { true ); - wp_localize_script( - self::NAME . '_dashboard_widget', - 'tinyDashboardWidget', - array( - 'nonce' => wp_create_nonce( 'tiny_dashboard_widget' ), - 'pollInterval' => 10000, - ) - ); - wp_add_dashboard_widget( $this->get_prefixed_name( 'dashboard_widget' ), esc_html__( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' ), @@ -93,21 +77,6 @@ public function add_widget_view() { include __DIR__ . '/views/dashboard-widget.php'; } - /** - * Render the widget again, for the dashboard to poll while compressing. - */ - public function ajax_widget() { - if ( ! check_ajax_referer( 'tiny_dashboard_widget', '_nonce', false ) || - ! current_user_can( 'upload_files' ) ) { - status_header( 403 ); - wp_die( -1, 403 ); - } - - ob_start(); - $this->add_widget_view(); - wp_send_json_success( array( 'html' => ob_get_clean() ) ); - } - /** * Logic for the view * diff --git a/src/js/dashboard-widget.js b/src/js/dashboard-widget.js index fbe9a835..9cb8cab7 100644 --- a/src/js/dashboard-widget.js +++ b/src/js/dashboard-widget.js @@ -4,11 +4,6 @@ return; } - const nonce = window.tinyDashboardWidget.nonce; - const pollInterval = Number(window.tinyDashboardWidget.pollInterval); - let timer = null; - let requesting = false; - // Get more credits is a second view in the same HTML. Nothing is stored, so // a reload shows the main view again. container.addEventListener('click', (event) => { @@ -20,53 +15,4 @@ container.querySelector('.tiny-widget-main').hidden = showCredits; container.querySelector('.tiny-widget-credits').hidden = !showCredits; }); - - const isCompressing = () => { - const widget = container.querySelector('.tiny-widget[data-state]'); - return widget !== null && widget.dataset.state === 'compressing'; - }; - - // Poll only while compressing. Any failure stops the polling and leaves the - // widget as it is. - const poll = async () => { - if (document.hidden || requesting) { - return; - } - requesting = true; - try { - const response = await fetch(ajaxurl, { - method: 'POST', - credentials: 'same-origin', - body: new URLSearchParams({ action: 'tiny_dashboard_widget', _nonce: nonce }), - }); - if (!response.ok) { - return; - } - const json = await response.json(); - if (!json.success) { - return; - } - container.innerHTML = json.data.html; - schedule(); - } catch (error) { - // Stop polling. - } finally { - requesting = false; - } - }; - - const schedule = () => { - clearTimeout(timer); - if (isCompressing()) { - timer = setTimeout(poll, pollInterval); - } - }; - - document.addEventListener('visibilitychange', () => { - if (!document.hidden) { - schedule(); - } - }); - - schedule(); })(); diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index 5c0f8c0e..8d518a5b 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -364,67 +364,4 @@ public function test_time_left_in_hours() $this->assertEqualWithinDelta(99 * 3600, $data['time_left'], 100); } - - public function test_ajax_widget_refuses_an_invalid_nonce_with_a_403() - { - $this->wp->stub('check_ajax_referer', function () { - return false; - }); - $this->wp->stub('current_user_can', function () { - return true; - }); - - $this->assert_ajax_widget_refuses_with_a_403(); - } - - public function test_ajax_widget_refuses_a_user_without_permission_with_a_403() - { - $this->wp->stub('current_user_can', function () { - return false; - }); - - $this->assert_ajax_widget_refuses_with_a_403(); - } - - private function assert_ajax_widget_refuses_with_a_403() - { - $this->wp->addMethod('status_header'); - $this->wp->addMethod('wp_die'); - $this->wp->stub('wp_die', function () { - throw new Exception('wp_die'); - }); - - $dashboard = new Tiny_Dashboard($this->settings, $this->background_optimizer); - try { - $dashboard->ajax_widget(); - } catch (Exception $e) { - // wp_die() ends the request. - } - - $this->assertEquals(array(array(403)), $this->wp->getCalls('status_header')); - $this->assertEquals(array(array(-1, 403)), $this->wp->getCalls('wp_die')); - } - - public function test_ajax_widget_sends_the_rendered_widget() - { - $this->wp->stub('current_user_can', function () { - return true; - }); - $this->wp->addMethod('wp_send_json_success'); - - $dashboard = $this->getMockBuilder(Tiny_Dashboard::class) - ->setConstructorArgs(array($this->settings, $this->background_optimizer)) - ->onlyMethods(array('add_widget_view')) - ->getMock(); - $dashboard->method('add_widget_view')->willReturnCallback(function () { - echo '
'; - }); - - $dashboard->ajax_widget(); - - $this->assertEquals( - array(array(array('html' => '
'))), - $this->wp->getCalls('wp_send_json_success') - ); - } } From 99c77e7c0af25efa43507c7a47d4b051b5c1b4f6 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 19 Oct 2026 21:55:49 +0200 Subject: [PATCH 37/68] test: allow 15s for the background run --- test/integration/dashboardwidget.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/dashboardwidget.spec.ts b/test/integration/dashboardwidget.spec.ts index f672888c..d498b0b6 100644 --- a/test/integration/dashboardwidget.spec.ts +++ b/test/integration/dashboardwidget.spec.ts @@ -80,7 +80,7 @@ test.describe('dashboardwidget', () => { await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization&start=1'); await expect(page).toHaveURL(/page=tiny-bulk-optimization$/); - await expect(page.locator('#compression-progress-bar')).toHaveText('1 / 1 (100%)'); + await expect(page.locator('#compression-progress-bar')).toHaveText('1 / 1 (100%)', { timeout: 15000 }); }); test('upgrade shows how to get more credits', async () => { From bcaa6a189c8eb92301344d4e3161e8d9b4263c20 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 19 Oct 2026 22:13:10 +0200 Subject: [PATCH 38/68] style: slide between the widget views --- src/css/dashboard-widget.css | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/css/dashboard-widget.css b/src/css/dashboard-widget.css index d4201224..95f72372 100644 --- a/src/css/dashboard-widget.css +++ b/src/css/dashboard-widget.css @@ -5,6 +5,7 @@ .tiny-widget { container-type: inline-size; + overflow: hidden; color: #12141d; font-size: 14px; line-height: 20px; @@ -25,6 +26,32 @@ flex-direction: column; gap: 16px; padding: 24px 12px; + animation: tiny-widget-slide-from-left 0.25s ease-out; +} + +.tiny-widget-credits { + animation-name: tiny-widget-slide-from-right; +} + +@keyframes tiny-widget-slide-from-left { + from { + opacity: 0; + transform: translateX(-24px); + } +} + +@keyframes tiny-widget-slide-from-right { + from { + opacity: 0; + transform: translateX(24px); + } +} + +@media (prefers-reduced-motion: reduce) { + .tiny-widget-main, + .tiny-widget-credits { + animation: none; + } } .tiny-widget-top { From 38258fbb7f29a18ae23f57ba70d7d7a90d3631cb Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 09:23:05 +0200 Subject: [PATCH 39/68] simplify timeleft calculation --- src/class-tiny-background-optimize.php | 11 ---- src/class-tiny-dashboard.php | 13 ++--- test/unit/TinyBackgroundOptimizeTest.php | 19 ------- test/unit/Tiny_Dashboard_Test.php | 67 ++---------------------- 4 files changed, 7 insertions(+), 103 deletions(-) diff --git a/src/class-tiny-background-optimize.php b/src/class-tiny-background-optimize.php index f7ca9a88..006e5c3e 100644 --- a/src/class-tiny-background-optimize.php +++ b/src/class-tiny-background-optimize.php @@ -54,9 +54,6 @@ class Tiny_Background_Optimize extends Tiny_WP_Base { /* Transient per worker, set each time it starts on an attachment. */ const WORKER_TRANSIENT = 'tiny_bulk_queue_worker_'; - /* Option with when the current run started and how many attachments it had. */ - const OPTION_STARTED = 'tinypng_bulk_queue_started'; - /* Seconds without starting on an attachment before a worker counts as dead. */ const STALLED_AFTER = 300; @@ -103,13 +100,6 @@ public function queue( array $ids ) { self::clear(); $ids = array_values( array_unique( array_filter( array_map( 'intval', $ids ) ) ) ); - update_option( - self::OPTION_STARTED, - array( - 'time' => time(), - 'remaining' => count( $ids ), - ) - ); Tiny_Logger::debug( 'queue images start', array( @@ -148,7 +138,6 @@ public function queue( array $ids ) { public static function clear() { delete_post_meta_by_key( self::META_KEY_STATUS ); delete_post_meta_by_key( self::META_KEY_RESULT ); - delete_option( self::OPTION_STARTED ); for ( $worker = 1; $worker <= self::WORKERS; $worker++ ) { delete_transient( self::WORKER_TRANSIENT . $worker ); diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index ca87a58e..41556f43 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -124,16 +124,9 @@ public function get_widget_data( $optimization_stats ) { } elseif ( $this->background_optimizer->is_running() ) { $state = 'compressing'; - // Expect the rest of the run to go as fast as it has gone so far, - // once there is enough of it to go on. - $started = get_option( Tiny_Background_Optimize::OPTION_STARTED ); - if ( is_array( $started ) ) { - $elapsed = time() - intval( $started['time'] ); - $done = intval( $started['remaining'] ) - $images_remaining; - if ( $done >= 1 && $elapsed >= 30 ) { - $time_left = intval( round( $images_remaining * $elapsed / $done ) ); - } - } + $time_left = intval( + round( $estimated_credit_use / Tiny_Background_Optimize::WORKERS ) + ); } elseif ( 0 === $images_remaining ) { $state = 'done'; } elseif ( 0 === $remaining_credits ) { diff --git a/test/unit/TinyBackgroundOptimizeTest.php b/test/unit/TinyBackgroundOptimizeTest.php index 82992c7b..e913f8cc 100644 --- a/test/unit/TinyBackgroundOptimizeTest.php +++ b/test/unit/TinyBackgroundOptimizeTest.php @@ -17,7 +17,6 @@ public function set_up() { $functions = array( 'wp_cache_delete', 'delete_post_meta_by_key', - 'delete_option', 'wp_create_nonce', 'admin_url', 'wp_unslash', @@ -216,24 +215,6 @@ public function test_worker_request_sends_cookies_without_the_slashes_wordpress_ $this->assertEquals( array( 'preferences' => '{"theme":"dark"}' ), $this->requests[0]['cookies'] ); } - public function test_queue_stores_when_the_run_started() { - $this->subject->queue( array( 7, 8, 8 ) ); - - $calls = $this->wp->getCalls( 'update_option' ); - $this->assertEquals( Tiny_Background_Optimize::OPTION_STARTED, $calls[0][0] ); - $this->assertEquals( 2, $calls[0][1]['remaining'] ); - $this->assertEqualWithinDelta( time(), $calls[0][1]['time'], 2 ); - } - - public function test_clear_deletes_when_the_run_started() { - Tiny_Background_Optimize::clear(); - - $this->assertEquals( - array( array( Tiny_Background_Optimize::OPTION_STARTED ) ), - $this->wp->getCalls( 'delete_option' ) - ); - } - public function test_clear_deletes_queue_results_and_workers_state() { $this->activate_workers( array( 1, 2, 3, 4, 5 ) ); diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index 8d518a5b..3c6e8846 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -58,21 +58,6 @@ private function connect($remaining_credits = false, $free = true) $this->settings->method('get_remaining_credits')->willReturn($remaining_credits); } - /** - * helper to mark a run as started - * - * @param int $seconds_ago when the run started - * @param int $remaining images the run started with - */ - private function start_run($seconds_ago, $remaining) - { - $this->background_optimizer->method('is_running')->willReturn(true); - $this->wp->addOption(Tiny_Background_Optimize::OPTION_STARTED, array( - 'time' => time() - $seconds_ago, - 'remaining' => $remaining, - )); - } - private function widget_data($stats) { $dashboard = new Tiny_Dashboard($this->settings, $this->background_optimizer); @@ -122,7 +107,6 @@ public function test_is_compressing_while_a_run_is_going() $data = $this->widget_data($this->stats(10, 4)); $this->assertSame('compressing', $data['state']); - $this->assertNull($data['time_left']); } public function test_is_done_when_no_images_remain() @@ -312,56 +296,13 @@ public function test_images_affordable_is_zero_without_limited_credits() $this->assertSame(0, $data['images_affordable']); } - public function test_time_left_is_unknown_in_the_first_30_seconds() - { - $this->connect(); - $this->start_run(29, 20); - - $data = $this->widget_data($this->stats(20, 10)); - - $this->assertNull($data['time_left']); - } - - public function test_time_left_is_unknown_before_the_first_image_is_done() - { - $this->connect(); - $this->start_run(120, 20); - - $data = $this->widget_data($this->stats(20, 20)); - - $this->assertNull($data['time_left']); - } - - public function test_time_left_in_minutes() - { - $this->connect(); - $this->start_run(120, 30); - - // 10 done in 120 seconds, so the 20 left take 240 seconds. - $data = $this->widget_data($this->stats(30, 20)); - - $this->assertEqualWithinDelta(240, $data['time_left'], 12); - } - - public function test_time_left_under_a_minute() - { - $this->connect(); - $this->start_run(60, 20); - - // 19 done in 60 seconds, so the last one takes about 3 seconds. - $data = $this->widget_data($this->stats(20, 1)); - - $this->assertEqualWithinDelta(3, $data['time_left'], 1); - } - - public function test_time_left_in_hours() + public function test_time_left_spreads_compressions_over_the_workers() { $this->connect(); - $this->start_run(3600, 1000); + $this->background_optimizer->method('is_running')->willReturn(true); - // 10 done in an hour, so the 990 left take 99 hours. - $data = $this->widget_data($this->stats(1000, 990)); + $data = $this->widget_data($this->stats(30, 20, 0, 0, 1200)); - $this->assertEqualWithinDelta(99 * 3600, $data['time_left'], 100); + $this->assertSame(240, $data['time_left']); } } From 7a34a89af801debb6daa258b97f28f44c679abfe Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 09:33:02 +0200 Subject: [PATCH 40/68] css tuning --- src/css/dashboard-widget.css | 11 ++++++----- src/views/dashboard-widget.php | 2 +- test/integration/dashboardwidget.spec.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/css/dashboard-widget.css b/src/css/dashboard-widget.css index 95f72372..701f3c0b 100644 --- a/src/css/dashboard-widget.css +++ b/src/css/dashboard-widget.css @@ -24,7 +24,7 @@ .tiny-widget-credits { display: flex; flex-direction: column; - gap: 16px; + gap: 8px; padding: 24px 12px; animation: tiny-widget-slide-from-left 0.25s ease-out; } @@ -65,7 +65,7 @@ flex: 1; flex-direction: column; align-items: flex-start; - gap: 12px; + gap: 4px; min-width: 0; } @@ -78,6 +78,7 @@ border-radius: 9999px; font-size: 13px; font-weight: 600; + margin-bottom: 8px; } .tiny-widget-badge-red { @@ -111,7 +112,7 @@ letter-spacing: 0; } -.tiny-widget-heading { +#tinypng_dashboard_widget .tiny-widget-heading { margin: 0; padding: 0; font-size: 20px; @@ -122,7 +123,7 @@ .tiny-widget-below { display: flex; flex-direction: column; - gap: 20px; + gap: 12px; } .tiny-widget-library { @@ -204,7 +205,7 @@ text-decoration: underline; } -.tiny-widget-credits-heading { +#tinypng_dashboard_widget .tiny-widget-credits-heading { margin: 0; padding: 0; font-size: 16px; diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index aabc0f77..aaa08ba6 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -87,7 +87,7 @@ ?>

-

+

diff --git a/test/integration/dashboardwidget.spec.ts b/test/integration/dashboardwidget.spec.ts index d498b0b6..92ce9f07 100644 --- a/test/integration/dashboardwidget.spec.ts +++ b/test/integration/dashboardwidget.spec.ts @@ -45,7 +45,7 @@ test.describe('dashboardwidget', () => { await page.goto('/wp-admin/index.php'); - await expect(widget().getByText('No images yet')).toBeVisible(); + await expect(widget().getByText('Upload your first image')).toBeVisible(); await expect(widget().getByRole('link', { name: 'Upload images' })).toHaveAttribute('href', /media-new\.php/); }); From 8cec312d6940b8468debb3faa6de3ec35a76a664 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 09:34:41 +0200 Subject: [PATCH 41/68] show auto compress when option is enabled --- src/class-tiny-dashboard.php | 1 + src/views/dashboard-widget.php | 2 +- test/unit/Tiny_Dashboard_Test.php | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 41556f43..7f399d49 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -149,6 +149,7 @@ public function get_widget_data( $optimization_stats ) { 'remaining_credits' => $remaining_credits, 'time_left' => $time_left, 'email_address' => $this->settings->get_email_address(), + 'auto_compress' => $this->settings->auto_compress_enabled(), ); } } diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index aaa08ba6..7911df1e 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -101,7 +101,7 @@

- +

diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index 3c6e8846..64d14727 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -120,6 +120,26 @@ public function test_is_done_when_no_images_remain() $this->assertSame(2000, $data['bytes_saved']); } + public function test_auto_compress_is_on_when_the_setting_is() + { + $this->connect(); + $this->settings->method('auto_compress_enabled')->willReturn(true); + + $data = $this->widget_data($this->stats(10, 0)); + + $this->assertTrue($data['auto_compress']); + } + + public function test_auto_compress_is_off_when_the_setting_is() + { + $this->connect(); + $this->settings->method('auto_compress_enabled')->willReturn(false); + + $data = $this->widget_data($this->stats(10, 0)); + + $this->assertFalse($data['auto_compress']); + } + public function test_is_out_of_credits_when_none_are_left() { $this->connect(0); From 9b52a85a06a5ad188e1d576bcdf7ae921ef7b90d Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 09:43:51 +0200 Subject: [PATCH 42/68] PR fixes --- src/class-tiny-settings.php | 2 +- src/css/admin.css | 4 ---- src/images/widget/panda-astronaut.png | Bin 56668 -> 14874 bytes src/images/widget/panda-coffee.png | Bin 40136 -> 12144 bytes src/images/widget/panda-duck.png | Bin 46530 -> 12937 bytes src/images/widget/panda-juggle.png | Bin 39511 -> 11695 bytes src/images/widget/panda-rocket.png | Bin 51896 -> 14028 bytes src/images/widget/panda-skate.png | Bin 45906 -> 13329 bytes src/images/widget/panda-unbox.png | Bin 54456 -> 13736 bytes src/views/dashboard-widget.php | 32 ++++++++++++++++---------- test/unit/Tiny_Dashboard_Test.php | 4 ++-- 11 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 03bd17d6..7dc13a6e 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -228,7 +228,7 @@ public function has_api_key() { return (bool) $this->get_api_key(); } - public function get_api_key_pending() { + protected function get_api_key_pending() { if ( defined( 'TINY_API_KEY' ) ) { return false; } else { diff --git a/src/css/admin.css b/src/css/admin.css index dcdf1ec6..cfaa00ba 100644 --- a/src/css/admin.css +++ b/src/css/admin.css @@ -1,7 +1,3 @@ -:root { - --tiny-color-text-muted: #6a7282 -} - div.misc-pub-section.tiny-compress-images { border-top: 1px solid #e1e1e1; padding-bottom: 16px; diff --git a/src/images/widget/panda-astronaut.png b/src/images/widget/panda-astronaut.png index 14ef64a46ee655ae918c6f7996db2f25c47111e4..02c5f81e028f125034687190a40019a68667ab4f 100644 GIT binary patch literal 14874 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
L_%#@^*d!WU4HxZaq870?wX*$M8)%%G?yJcaPIB zp;hUHuRGwgAwX?$vr@UyAvhhBE@w+pVlEIvVcFPYMvs+Hb{Du#a{{eYbhneJJA!zFWB&tQUTiju~N_Rq_Qvwtl0tQ8jH5J7#5K7vm%;H*sA6X0mTX|7? zdtswMkN|Uv>D-EhSP6JR$*5|j7^4v}jR(9)fF%n`LyFV%iE9=|BI=;>L_r>aHOocp z1oEGa-7T;_D3eNy2--P-Jm_|7WpR^3$KqgjmqJYP25X5u0iNbIGhq&;SJa5yA*Wqn zS7iYNpk2m9;GP1KK=vvC39veV5^rV!Feq>!&LN4|5)V^y6Q#{KbqR;k+usCWz_(*_UtC_yPu`Xdp0IBsi zllvDmrsgRF3yc9_i^#s)RN4iw0LNZ{m%P6{*zllcz`<{uJ11wTbsExua81z!*tf&@ zCa)`cTg#h3DaJ0`2Y34yjzVU5P18!lU!UWANDGJdn1;_^V~B2cEQY z5X^+w4YIE9IEDY#TW>K6zIuOV6SbKTP2d+YKCdlG19A^UFbB%7O1y^GiXi6!>d(Si zg0G%3Ft@P9k6F-Y%1G~ln)!*dR>a`3`Z-`=we|`m!uiC@R*V7DJRtPzegMz$gYEz5 z*fC1Mq{a@|S9;W3bG(p>;!058X=1N?^YsWtp{>=?(71l;pq)B#uu?n)D&M}XQ$4-AvQ ziiMi#BkPh=T^lq4>T6OsG&PyJB{)5obUKBJdd5^u%}V;tj$V=X$So=t*%uH$oe6&M z5TAa|YUq)G{U6P6{8$OyQrMk{<8piKxE+BxAak@UB?S6Gg6W#+#dT;@sl zWK+SON|XQ`ZSof;@H15{1khd^@)jAiYYLU{djq)vYd32=nJyR0MBlBS8nw18j`$2%0AW$^^^-xVcAZ41fsE83-8B8apDF_!_4Y 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 diff --git a/src/images/widget/panda-coffee.png b/src/images/widget/panda-coffee.png index 23873d6e4031c863d145fbfa9c6f34f3b16777d2..3197512d3051e16f4ac452a3d4ca7e532d2317f5 100644 GIT binary patch literal 12144 zcmX9^1yCH%)4e<3aCbl4U4nBE++7mfHMj*kJh+4qLV~*lw*&}>yGw9)hv540`+r?q zJw31APQRJ0t=+BJXbm-aOf)hy004lgs34;S003V@AOHp7wQ;O4&;bBI85$}&vaj8z zr>B>f=iA%c`}>E-$H(2Bz0J+d&d%5GehuY|k1yS=@=*WmvC{*`leb+x*( z@){o=9{xXgd3iZMzj$+Vb8&HzkofsEb$xyP3cjBB%76Huy~eNh%6Y|KY3JwXuc_11 z(^urxzjj}P2tq}}T3y{JA|mt7*h)-HZ02OMw`Z7`jLy#=hDSj8 zTJGiLWnyfWg_ZxckgURcTzm>_TryO20wYOIbW9>lY?8CHv)9FWm5NVD#mXiyKf63W zI`b-CZ^Vc zZzNICuv%LF`1%Dc&96Cs@KjURRaDXv6_W`J3U8?Y?e5_>JH0qNJ2yT)si9@a#vxQz z_A@3X@xsG1JR*8(ddA+tRYXkn^XISae>yn1h4=(z8JPu!hDIc%b-KIznwwiHD{IYV z1x7~3)6z2P>YHk68W0PNLy;+Q38)H-%JTAyGBUF7e0-#34YUOqvU3W6U$xV}W&X&_ z@pz|@=Qqu-JJ^yFe&*Ui2w*`d%e(qU3|E4|e(s*`%`#kJ#P`@=lnU(IKC?>Sb z0ej+!VR?>Rd*vrQe}4Xw{M!6y=f`UUF7H%mF`t`DViTo?7XbivenlB69p8l`<9!!$ zS%M~?&smC#sVm6hd$J*+gUH>O!2s$bO}&=<<>Q6P1tN*rG|S2GGzz7RBxe2cAF6ru z{7QLQ^$-P|0!$9-ccmN$K$Kfkk}4muIunJ5@^R~G>&=d_V@uYi@P9|X zhJoAKjKJaSPvO?!(nG`U$%e&csQmc}akdniw-YkV@NC+I##BX{b73k@XE6Dte>WoWBAkA;I;uDsfB`BL*J+uFv;-2*K4PbF%-QQZ47e-928EzUiK$5sgFiVYQAkIGXZay4Zr7`6p~{c(=LUE zxwLJ36sdlJ;I4wet@W$2o8#UNFN7{+s44)kK_G19Nh{BUASvkBuj`6ntp{%{3p-~^ zb};G28PL5p6RsbXq70c!7q}pNFNhQL^IrE1@X_A>PM+^WgwjyrtrHFK{uCpO%sCNdyoqFeA$2^N5 z<)fKQzKW!Tc^Hh}OkHY<)Lj-26CC`4PuD=1Ig)wYuuDb=UK+pWPqTs`jZL zF*P7AY>OXGzp()KYd97+PmJ{+T$mp5yPWu#cw9^#UZ9Xjk;4SlXZs z#h0YzhX8JoQ`?Z+(a_*3KEAjhP5~)Y*_1%j+NIMG`OBtI?BlSY)Wuc^y%!m-Yp)s=AfZ;eG`Pv+!=G9?+Rn9arO#5jY}d=e41iz=t|SR&gmj2q zk_m5xb<#Cm7y+E6IZX9*hBM6eY)~=t7*9Zf$lQHvIsnM*r8Xk10b$D^UX` zAmRJzrWBwqg!2}K0kz#?SE=_5lu#sl_{NoVrKL+Ot$oQfA>?`LHjqj%TfZ$li?zfg#S~Y9tbShiRcBb|RdE zy#(KE3LTfP5x{mgqL{1FI0^SrzYc5+5Sh3jV)(~Hg45686;81|7mKj9;CMF?vK2?1 zYLzn_kjh22MyooJ`b$gK>jf!9a5z(K55q1k3QCuNI?#UphTX_N1@{$ae1K*C~LDhha>u;PO3InH- zrG78u{qFB!*T6{pxIbn>9UQOfqxrPPy(cyhrTLuxjKtcZqo7;sPSE;Q>a#gY&uZs9 zrf(L*bMZzMz%+VqCDUF~S$8?V>mJG#-!rx79-nvHZfAXdddmN9t;|^HbV8ps-rrp4 zFnca!wlCFnz{rp&Op4+~q3h9|=$Y+^eV)fGv-mL6HxAmK!@g2fB)Ee^yUv4|}) z!_wZkE4XI5!WF3`+L>NfQ>#uz?~1+{Wh~hwVCJ;4q1sCK_U3$x|RqA&eQkOo$7yc z2uon-c6Akl^!x=jZQ?dcWPS(~LWV`wgKx#w$AM@zl2)5(3Gx^*h~cw{be z0w&O*an`Sb)?*CgjTE(wI56ac-2pRpgxi&sLc@6o-#CsWSy$$@0U#>CLV!?;*|zKa z9)ErvU(EQJ8|#Z(dI;@;V!41p63z^-9Kl}gnS{GhMlxAA{ZB}fYz;0(Z7NzlR@Lxe zqIk~cTnLkn&__gQ3++2b@Lmnjd@>Rs`1zfz2RR@&juK_SEu#8|E8hoRT3v_}N5^S@ z|0Svhjp6^O`_kQ!uyuZ50bGeENi&3ON)c}UuxL`h6eYR$~RS@r@?@*;S@We zj62X6n>O%5uIlQ0%#ehRSaGgB{0N|=>S$?^Jj)~LUjZM-I~R~rSQ948A_V~IpM(@bXedSD%G>?n1~g|PdVqLl*d!&M>$f?%)at5<1XzbJ{G>5`423RnfQXRUyNJq( z19Q{kQ$mOvN|I@crxkvj_ad_Nx+h|4_M0r3ZmY(nyLSL_2J2#SBS|X~~lhK+Mo&}5lLcH}_*W~R^#55Js3*5Syf4As)yEhk4 zCm(qz_wnsMMNAS@Bm`yShU^#JcZ^>YV3t^SRzi?f?3UE$vp-dS`$LgZkq<>cT<(-w z4%F*WN?|+-WHx{D9QZ>37&QnVsKqz)Ucn8i7Kn#PFwh;TNC?G7u*?N4_)6h)bCD-N z;_fCA9qWXCHqZ)iM{z#Z@}>Rxy{?S9JcRr?L}M5NC6~13^B<9jneeo*eL*2wP)-R-GnMH|O^%S8I z!En!q-Wf18D49N$4lU!J$?NLQ$i6F?7q0!tHdjgBu1&n!`su?9O7(ZHCIQQB+ACWT zg0-bl4Aghn9jU+64D__6iqlzw_|7d@|jU`?}r1JG^iQn))e?3Msj?^LE6(3zL8ELj9#< zkFvQ0`VE?1Pqeks8GteI@dpaajyo7gfw+fvR#OQgJ{>l0@piu6>G}T5#XDJ+p*1h= zR{L_XT{=^p%aycq>Rh#mMkEm^vMze@BVMjZ5#n!_C*$;M;T2(??yJp7(qgi4S?c579)vyoxCS6$oJeVE^6BL`j|TpTj$qC3eS^ zhLgaA#Zz}Y|9%#Q0BDvQ3Q2jUuq2Pf{gZ111fHPcNH@uqw<5o%Vwz3kzxqvMnyH)j zS#v*H(V{kR&1!7?_AX?FzTW$rx&B}Zp6C)4R|6g#PhD0Drm^9N`gHlpvKPb6N^A0a zu!Jdh9L{hn28#fBCiQiw`q~v>j;W)S3#*GQ6-*#XjxvXza}}F)2ZNFX?!nV0nc=Sa4gABxMkG%#5ipO{FUAi|JH8J) zpYAZzxkreoU9!ei3@2)Lgj^m5g$@f*A*WcPpE&4oXf+c5?%D#t$oLMU4@vQDDgBno z0nVl}?q~&lQAj*oU#q`tVbSBTa=KmD&3L=g6BLo!;W3n7DIX8<&!^m$YEx1%7c!vD zvQOzKNASDn;_vtwxWeg!r8j?M5-=kCqbH}=n4#{49IyGJqFrh8))>A+-Ln2U(u(8g ztdrXMvvcs94K7;IGVy}EN3#lHk!ZaGapkA&(R=ErB05%SX4;(Wj+jOw`cmWjF^;#z z)EZ8v6eUM4th>3-{Fk3^{$>qtYjJXp$H7I)iMz}7qVAES96v5PIsb9O{ms^TVz zJpXf0+=`v}HoK6qvQnhIE0_45Doq1jfYFB}DZ`9YhoeW1KzBmRd(x7b15{4~qab1b z7?+o0`#KY8HWkG<0>q^XpL307bUY`vg#H!TPy^UzSe})d`$V}u9e&q#D9-V*d}NzY z()FIn*C`4>U8Nk#`l*8 z93&Z5FPR`ANrty*n??>itU0p+vF)_`Q_Yu$ua6w(8Y=jmQF^PmB35XGbejKq)$dyo z1pVMk7d>J%XbfHcPdL`wwu~EYzeyT=aw^4~A|YBs!z}p|}AGh&IG#^TW;DY;z|c zHfPjFSkJ2Sv`qS+hhz=!d_=w>8%7nzSGY=j_o4M3(g0W>bkrS4Q)#AB5^}Pw$;Y)L zFBwuAd;;+Y#T!H1!X^tYZXeVyvp3N!0b4B~qIKj{MO1v(D~J2+as`AE8h5rM$pFIE zV^;dvQ}C?1GE=oW$O}|y^4tIB`sty`Wwq^cpTnNF7WNMtA-K}B!_^F-2fisMbD(iC z%Rv8p>|fkI<95HY{Jwer#qP>hnD(VNG_ziqHY=BKc;{D zgrIwEyyuWpJ zcu{{LsM4jDe-Q9IvpJs*ker`=LmCr8E11We=xO=ZawEIAUBLCF#aDGZA4Ow6)q>*L zSFn1`v^vDi4xtBd)+orK&3~u44O_YGl5|;Z_c?veUd`Wh6%Z zb=oDIS)Nk7q|cB{&L#TUn3iT-6OUI8r?eU>%_HB8xLyP|Q^SYo3UWp%QM7N-DC%CM z^gU(_S9SdAVR}u5yGI^C1yH?EC$345ttrQe;$_RuIUhoN<&pQb2b}eMAdT8R4kI`25 zBgMP&7#JA*BS#$re|G$tkX0NKG{@Ut3qoFc3^rR!NX75wK2FoZH%w`_ZK=(bG3_)W z1)BEF+Ht9=;->U8(68>igpsNwQ!B}*G}*Xf{Wzcha}t>{h529^vRZdq=jkk`HlXqm zJkWx$_p*snG)SGGaWw`=L%GJjQm+c%6WOVoncev#|MLq`vdNEqdpF$BIsxZ&0lE{k z$0iY1%b3SZ=kCEI#n7#?*zBrzrw16U(R>+)4t6D~Qg6dXis`2v-g*SKU(0{YOvf>7 zlBRVCdui>#SjF76mb~BO|7*J&5$-qMeqj; z*}R?}o)z*F3*7Bp5gZGQ9MNnMtpKqBa@8-w+pPqq9KN}B777F%{q81wA>AoyI9Z%Q z`Gw@vJMn2t7k`{g@sqibmb}`!YHqCxm_7!%)(2a8ds`I*Uk21O@e+`q{PaLB;c!|g z=Ai$)%}h!vre$@e=C3h9yKVH;`n=x1HhkSvd5*I@mzIHq*aA~2oVIS%sk}6<%qw4K zsZ#lr8V1I*{#g`mVT*jHYO&`VXK>>RlL>Zm{kPFv7>-&7B&iK*5ipo<5+=FXWJEpf zfuo=d;}A7zTz;?tL`+iUF^PA0B}X)vl`=x?a>R=hkU6-tbm(&e>Jby)q@v`&Uh0Jn z^aS?lWxgV4{ss+*@Zc z#qH_7!7=#h?m;s6(R<@dO!XMzLRDVEP%?}YX>JC&=w z_hRsi-|_v8Y4E?z#8r)epUB(P!38hRPgjn?&rjFUqwfkNK)Tn5oOKtaYG%(G=UP^M zIBX-Ne+>cE!3a1r*o$nzkA6?etY2uazCIv58Ae2NRlVF@vkBs;0IWZVQ$pORS>30k zvIylHn+y2Ztv{gsS*;9w+I*vP(FwJ`JwJ48XYqp=K>SHMX;({n4r$F~Yz^|1f9+wd z0au)t!G5f2QmmI#olG6N+bumb?H%0!1qy%6c@w$!Uk`5v$1FgPL674;5)*b#v zbax>ktT9NqA(LG<5uXYtpUFfEB@TXgA`6W6o5~>#acqCNriDmV8~&MMf-g*C7t!je z{4>da>i*3HWJNObf9j@gfAM4R8gV)*nvRz&SwI&|kZ0FJ(HrkL^>Y znSi%0@p239kTma2GC_sQ#%#9hgK z5255}pq$0z1uZF5TK+vGqoNk=HG(Y=2{Qqak(r?M-o=ZQ)k=m<@>T^3dTY$+VQ&d* zh>`()3wPO!3mmzlU-st}-wdP&%+1Hg)Z&PR%;7aN6Gy=Cq9Q}M7wPg6GSk@)O95gQ zW?3+5(nvOcMqqUv85)Zya@xNQ(er z@PTK=>!$+G?=cD3@B*hnEm0I~7AOaYS6X|C2F9{C*#V`k=A2mrz$nt;M`({MI6cbV zEl;kf%#+82nIg95ffj-MO&2o7EgHYfv=(8{j>~nn$|<)>l}_O=8gf`R?hwu2f+VpNGPb_9O1Z3X)te_|8z% z>~HVByBWiTFf>X5dh4s zCy7ONSX?de20;h4aZST$Jw%iAut&-~40)%3hMSkY+kfQU9BX=5s7HHhM+a)og>4$O zMG;6^@%!-Gu*j9#VbncWi^Cw-eIrX`k+Tog{!&C&c`zp|Zjg$cNpT0Noh{;)O%5_D zGQAnZ|D6UI9-^~)w*X}Hca=n6q*ELw%ENh(a_Fcr3_&jZx4*)5`sZ02Y+Zf}IcRu; z34cF$DPBdS9QKElL?j&z#fA)PGz;Cp_U4}PpSIQbxGwAgXp@H9kI9~pkAMqbSg?Ur zdjS|M@vVSyt(uYkp#d8A)sDA~XwCd6*T|!!d8dCztA|kNwWn2wMVnFHA>FMHjnaiK zy-Y{la$v@n2;I!!Sk%JCCv=OV8aNX$(L=3}dbt)p@6m1Rpq*L#6wJsTs2mq+_3nl& zAuW`&T5y8@Sh&`?Ed<3hU^MOL{8gk+?l{RdazWy_z179D`bt^{!pg(bsOF-0~*pmKK?DDaD)Z^l(4>Tz(zY=*L(h>wCT0g(>02O5hEW z_Um4_Y9!&P1pG&0L?9{9IyFxS=grK--Xbg%K{hBq-;pq zJ^;~^`%i~}Wm+5jW8v~c*()0Ciui$7+~mGo*6uD;7-AnF70_pW9em3OBf z)6v8T<&*>lC^UYUBJ*LWy%jP+&wN{K?v4L0N(6W>54kt)q~!(89Z99J4pfGwDDiRK zYRSm}gdfxEBa+S0a#mg6M*)AF88MeI6*w7&hl2sm0<%?k+yyw}8IT-2Gm8?BNif>Z zBvGf()69v$n}6Z^+U+B?lrrR_j6tx$TizO`Tg}qiBY7mQLZQxfPud={`kx3rYgJ!x zJv)rB_Xl<88;j5GKI^5Nf3PLt z%91G?-e%i=e0=_{PTBHO(?{k1e9n|5tfT9DP}p+99|FclmKGHg|0X5<*(L)KD4UlP zHPSQj2}uW|$S;%*T3B9H>0Kde%_tVd&tjM5>Ogcd`W*sXpDlI?zW&vfaosf4XM^pG zY8JiE4H1-0KzJxk(B{iQm~PNTXD!p}YNwZ5wp!060xMh8lt(KB}7!M_Hw z`q}fmm0+Fl-n(Ue?H_1)GN0~S6p)T^wOjWa5J9uWNkJ5{LdYdOYNY87d8wHkPg_lhX3ZXZoPiyd!vxH&ay-bh=lvmtT=TWtj45} zxlSbx);$q&9TTI5bfmoDh$Q<)R^A7crbR@;K{ZB2?d&33|ez&d$AT%&*OcEQA1> zj2r+qNocG+5Z_wjz{VzpSM1MgB5=HKAI4N+IkixECc9wUZjEXeM)~;qL{Hpt8kmy< z}X{P+HJ-@l+Cjqi3oaHbLA zL_i=|&-z%ZA4ZXC_i!LLvkqw7M9I^nn);|Qx0|}3In=6#4xRSDRc;f&hkOWvB(gvb zwg)K5JVZQcsHm4J0G<2oz_da47>PmF-q?zU_)mdv+DEg&XHh_y~Y#JtDL^(R90Qz zPcb7SX%3Ab==>(^QqU|@3WUf^}&MKuC5 z_WT?p@DXW3n-sz_ll^Vllc;SOvCa*sJV0;+Cq-MD)N5QP**bLlOl7D!`k^}oz%6Tx@x?9yatz_ zSh-0J2_gyt3u1+ABxAn5pb|{CG;Su*Sf!;E>aQ-K?df`3!Moz;mF~`K>FEOWTHkJ~ zEmPNbOhuklj~|R;2t!@tgN0E+1b}uQ?HhIezVX2<=1@BlH@=F=yK%tmDH|#)gP9Gs zIITr~#g!y4z|qKGbAWaSC0=wekf{R>%+TPjWDLUvrD^Z_cD}?>hzE+Ik;xuiyMnrV zM<21Z#0rIh3(<%Z4H?gSy|g%MpoTloR%(T2y=Dx|`zFHsz&u5)jXHkGL4 zOIgzy9Z;nhItU;#=45|o{EsSex8efMl32_v2v>OvB*kFXIFkCOGMgHnnNZuSi0or; zLdt-tIyDh{!F@PzEA!_8z}&SlUtVr|d?}@^JcOEYxbxLW4iEkpN-31lWI0cVYq2?* zLffuOdXma}P*`66Vg4s3IAQw`+#wrn7>H}RgA(105(IVh&;w;qCd9M3X-@jQbZ<%Z zc9*RgHu(32IDfh@LNbpPa`cSL;z8Vd54c*J?(G?|i)BCd;P*9bhyecWmO?#axAZ18 zi#fGk+jr||d>Ap^i=vnZ{HUO7{kNT;l=F#4imr?tzu2nt$7(Lr-~_8R&(M9 zG7oS4MU6R-B3S+>Ko#TH*x!y4cnVg1}K<{fcwl``3{asm6COEM^c59WstZ>pdeHYYwF#%yML z>GYkRXSNvzG){1b0|<&Xh@=7fTF)uIM5@5nFX}Wnjun)j=j8Y@VSX(%h#Gh3^w8zv zB05N|)`%D}Fowy1z`7_}^ozY~3>XI%Iun5hJM@fXcCM+j;@Z+C?vR%DFiFNwl0e4F z1avH!m4k8kqY!$U#@TBPs=+67@nHeOK+b;fuq_iT4#bwrUcyaPqzn3S zl)HpNQHzNa&VBWQMi24Gv~XjaSkax6${=^yET;b!!IJ{enN$rEM~1)~GQ7ekaYW@@ zS0^4ncRdCq37!6zbuh1b(cp)@XSqXOYZ@j@rI6_(B!mx*)egJSpQS*p6~a9VaHzBi5@_?du6h&nn+G#;fI3NIMlm|!N~DnLzz>?d-cUZ zbuhyBB01@Ub;Z7_%M8LV^bSst|U-uXtqs*>_`Xn_z)2SOYzOkp=n|l zB*ovLD0?Sdn#OX`4JOpy&h;CX;+b6<#uK~Ck%&tv%vi6T_q7z1#Xyr3aQ5-IH0(PT*9Y!>%Hd%$1y!oYH%bRH^ zqvIiUgNZ#r=*DO)W`z--qPIRZ`>!}o+E%zVhJaRme{W#SX*3e* zY{Rn$LP~<{V{|VhbjB#<`~$0HtXURYvmXTzVYOdHXRvhsQY(C9eO5eX*mK3Xvi*kM zz2Xw~)_yGba`k%jgFrkaW>YlZCjZ1I{sZCWfkPgn9XGKSC@^{oLls_qDN@KFi_ru1 zpFoU}*5Xo9riK(=7Tv-!4QsqVyXDvBGTgS{>+Sw{8NM@^-=;U4tbYtxv~W~KGjV*` z_)CW|w@Wl8Y}xQZ^G1Di1BH&78@l_@LOh)s7HwRW9sCRs%Gqz#Bp)Y1F*ZG-rbw`B z`$b{o<9mvSdvrH`GWk*coByf$Xp6ISYch6tvDD4f+J*Jucm&bLGb@N-PG;~Y=+Rl) z*2`C55Bm>h6?K#lQ#L8fz6l?XJ@o_)aLh)x<7YhS9E*5>9ebRQFK)gw zr`Ugj?r@P&+{Gld;VrWyo##}#*7-!n`s+4h>YZvg^?eK3xJK=y6&?rOT}>zSkO67K zib4)b0FLc34+)Z3R$w2vJ7lwMdH55E&eCJ6gG5%k9#c&G^cQCGkOA5(^VO)Hh`ic& zlYt4r_s{rWg#C!k1i$n1R8LGk17waq`r$bbYDYg%@_r-|!ozAZr4&{Bu`V=v?#4_Z zmo9}ehTE`yF2l1ew&)NHn29j^G{L7Dpnd+q{$J#*HQNRk`T0guVv12q8{02Yeu#!Z z1iXa4=+|3-Cr4jweO#d$UQZ`L;hoLk0Kb6*d`gE+HUh$1OaN1w8TSdIQla{ucP$Sol)yJm9Xh1JS ziloxm+fun1yW9Pp8lk6n>EWHzMzkibZCO6~J6-pP@3y(9vmMOihON@=su{{wq>9=HGi literal 40136 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 diff --git a/src/images/widget/panda-duck.png b/src/images/widget/panda-duck.png index 497e9c3f86a5dafd5a8191af4a1f4edcd99ad076..0fa09a5393143389a6ad1c670532f2cdc8516763 100644 GIT binary patch literal 12937 zcmV;4GIq_0P)FMWp z@9+Qr{{R30^>YRN#2)LBj@$n1~ z7y|i)wP2MH5JNnHKQA0i|z{nQ^dH$eT&9{v9Q zg@%g#)EfTIA4W-21_ufl8Y1;?0sht>{>dKx^v2uT-7hdY>g((7?(RQ9N;*769Umz4 zt`h#~iT&3uVPa@VM^69SAN|%P*45hgbp-v{H~q;j|H~i>3lQby=38B3LqtsA;Ng7+ z98*)RgQvCk^ zgv9oL!Swv#VEx`#fPscG|_vqCA=YFn>7FezD{MTkFB_#L591eTa z8gRDs&mJ3(>iW#8$f6iDSbF{BbGw!obYBtne+x`K3vjvdFk+41xheL8CHdUEK2c`* zxfhFW5HFPEHZ?Y03LG338Ui2_1xG403>sW~nQc}M`m%TUqFb^{QUi)k1bIdGltX@L z7k94NYMR1p#+@XqZO&9%J3BlDV>$&hAZS$|k9QJ;%&bbeh&i%)^rdazXK8mmLzN*i z9I9y^c~RSONVuRr_RMNhFE)s79_O>E^Z)<=GIUZ-Qvm(`{tp>a{{HnUAqf89GS_PU z=gwdG@1r{H$H0$+v~)szNR_#*n~JLbhyMQlM*jE?SkO%X0526uL_t(|+U%NdOdDk! z$J;BSfC3Xx#-B0&ATCa$rhQ1Hmp#qp&V-(%OVf1Z>aWJ!H9UXaYVg*PtQG|@zT<$Hh6{psCxsPRoLY#&|_4qov6KEJ=u z)%KXjJmxWv`G09TesW}Jcwo5q#pX8KqsQ^VPCL>F_6;9dld?yu2&x+ z3z`O75M{T5PmVut9 zZAXgc7G%nOfT9csy4%$LaO~BgJ}43nB`^k#+l~;R-%!to=hx;F4up&tXtH&@+zwBW z$(ELrwj)Dp7t&?ng;HS3=?wX$We=)89e#!M2P;AJn(e4CjP&DQh;a-@JDpCN^My*` zssjfX$X9JggC0#CVpllMX~6gwko})PCu~Q7rcR{FiR67w3!HQN00$`eQlY3LF(n*B zsv4XI{Z?pa?qLVKEUwmpz7E@=r>R>DfMs2O2+(6djF__Dp`1PIin3lxFOP?R9(X~M zGOvlA%D92dlvBZX4prr|E*3i|FaW4JFle%}qvyoPE5oNo4%a3*s0F|bqny6qt>IUb zz#XOZ&;uiPN{l>Tvq?TbayY`Ett+U=xaw2l-)(~A1pWRB48IPq7h^B$Qs6ZsD0|g{ zp;sQ>B!h=!lhjMV3}X!dV2Y-l?wL*Abs$j;lK**73icj?>x3SpgseBlkqTg_7Xz`F zC<+^%2#;CUfj~k07f^rWSAt`z0jx-yGax3%;{p(utrBf%e(1TJi+tm;`$E}NTonKsGpM$du+B0v=4 zyX6Vs#v*WiXHS+&vwu?wun`4_%9X?r&2b@dWt~F$(_UL+qt^i0r~$?JE|Gup*5cCA z()Ee!w|3)FGG$~zZ4{`W*);8=)#1VCOwQ^KH2S{qQqWF7D?Y6YWCFroxvKy6#O=i! z6P37hj<=*gk1@|`{ZI)4l=U;_O>$~mD+R&!#!iCP7S(`FMx6sPPyi~R|Mt=%eBGY7 z4*Dl{1R)>hSv?4NKDCz1t%V~Pv+8sR`a_&`kD})^2hhv5Mn+qPsR&d-z#k9#>Z)p0ZMG9cjS{Z!N*2t(K0HEcWYy`7-&K)bp&sO#y+%A{PJ3AFY zkj0n>lhzlWQ);9-B`v9KVrgHNwjwOQ4dGuUqf~*Zl)7u5vNbfl`mH$hHKoa~y2Y3z z%W>iCSN~)HLop>?k;iKUzrX28_F4RzC&qAm4q1706v1@HE zDS>i8jLmFAWavbavanOte+zOz856|I*p>36{ni}tZK1{=274&258|jxhxa-h(ePSs zb7Nz3Jr`6%?ZtbEr%--&IK|S1DI0d8_>}g)bBiXysov?WIPtj zU&*qFjQnQ!HE0sa`=tEcT!I<^kV#q0uk(C3Jm(D)J1G*FuWIIFPE_)wxU|A%0W&+$A z0lR18LQI4m3WmgMo>WN-0euem|1U+F+FCn~1FdaM5C5)T4*)i*=wEO%it3PC^mB|N z!XIX99pH0Gw>v;41%e<4zz~5Tm)3Kl8UU6_uTmDrd(I9#-__pz%HXk= z+MYfj0lbQSJm)0G&$w4-Bd)g=(n=Kg=De<2a5P(jf-i~z0OX6y%f+JNKsvYLC;I>Q zU7+cO7l+zg5FtpJZ*1*-{e#U<=m|iX5`g8eFtl=R351kC-U!j;N8VKn??sOA_EsLW z1A&ZG%Nr0%#sH)}>_4Ut%d+(2qe!sAl7ine&TjD<o*2I@#;hJ-?3shV+nvwPWwDS1fe$yg*&68qnikS4^pmL zx`0=`JES28w1YPLgFPik1HX?>d#YjBY^xVN?TD(;{^YY?UHs(3ZwViMa`CIDo-|yr z1^`YossW;lLO&IL90ihz>^B#jQy$hF04X<321GGgN@s`#G`(Rqh)-ORgjh0Xycrs_ z)rr<2bM6!IAAEV~`-)7D%qte4_Xqk}j z_Afr0oCNh_)1O`X^vs#}-aGT@wBdlkPIg~IEI!ZD7l{nikOV!J}U-ift#8~UHUq{#p1{O3gbU%Xv?Oq6vT z*CWbOv$AQkT&YFP*4p5B9w5L6uRDb2Y2CO8sN;_4gd^zSNVo{%tr8iVNd$t#n?{fz zE=CQK(7n^L;E_PiDqB@kpB8Y#D@ca~Uw_~Xyo@6)X~0AK-(bbVDln8z=*zr#|rQ;#&m9V0%V zTCyf+rNlof>b=}VF!22H4}iTue_J``?l!1qIe{x*sJhn^e&$Aa>a zqk;mcz`+veq1LY{V7T3RuhuwvI+`qk227U*u@?k5s)8VZj3(QqUkF;d8X)*#iT@XS zQ0&Y9P);BCdqLuX0Wos5>U0Yv&>PCaIc`o5Wp=A?qrv25b(6b|Gj*~KOgw>AO7CLd~gU~ zNc`X^uJVdIN~5jm=>}MZlsHXZ8)uE-cisR)mj!Xl`V|^Qjm2>^Uqt~jo$ia&kf3#59zaP?p{7}UEN4JV09zUCkgS zC8hcpJ~8O_F+x9_?)dE)M8C=b{5=Yw6)wb{T^3N>Pl@p#;vbLP+)z~glOyr{0gnP? zs(V=eHoU>AhNooK(rQkah$QQDhSJWm&R5fM@sw=wSO^4m77%=Iije=yMgG|FNs)$w zfJ@h7&Ey%w`IMujx`1QESXu3SRj1c4$eO5WUU~sGic|e>5((Lo`vB0?*A%nP$XKd} z{zxlQLknV!+69_sCVa_VV9nhsApk=w@c-W@qPS-kH<&6r(pYY*mf1f#at>2K|EOsTF?csSsKl$U^9G z!2mwvDzT+%dFKsNoGc}KvU=JnRW>gK$3bqgb|k$VgpcxD^}eUqUD@n7mvc;yDc z&Gupg@DtlV_T&UiMGOcaU}g^3LW9_{TrzSdv$-o9ZmUbnGI1Y(yTO2;$8DyB76>Ok zzmf5^2LZUMbR+=Q09-*;Wl(JPq1N z`APw1+sSLE`_2+cup=zYT>WD^Gx|=Jj6WCnmlCTUr1%60E7T~z?yYJ5tz6b|Ip)Tu@fIpU$v1Wg2>2( zFT-6VU_10TCH^h zwd!vQPB1@ftsvtMDPRd^!jDjV8(6rA2bd2Z87rm=hL8!IA#sAFNKoJ{mx@TsHK=EA z&d<-^9MiuID-vP{2>5m6mUTXg05E`h7+7T?6F73#OyUDz0|{Y=cFHAyvzKV-ebcjB zEQI{=7Yp34VB^1K^OGSVAsaW}xh6O`c;%L-HVA`&Hxfh59zS2(ak`YEv`!zOPZ9b6 za)VEse?Tb{9YdJxU_L z%e(-QANSI0tf{FywXQY7|R>XWB@j7*QLSYFAaZuPW4A7k=m^Fkj;I8Mt9fLMTC|IkG`BQ0X+?bhnd zaF)fHz$HVl+JcUnA=(&6Nnv{9Dy5tLs1=u{faBDa>su!#CbnL>GG)T_?RLQlWIWBs z_$Wa4q6k1913&;HS`Zh-(^!NHj?{xqnZ@A@%LcI^2E(uj@J_6$x##C08etzL@L#WB z0kmnIz@H~8Fb3gjXMFNEC6|MNLcnD4KR#DV?Wn8>N`_gI+_Ou zJ6cj(^J*^4VpECcdtlWDB`4vJ@v2r{!i3$>78~1c=S?9&ZUY&o&YvGWf%y~E0f6U0 z01+A^O^o>cl(Gw9{Iov>3}8|I?Xi*orpY9^0^}1RKt`A-z^oc0Mq`Yp$xu%zKL_NO zzm?No44}WQu?>C`6iBdz`iYmGmjoDswI6>8E&2kH2xH;=DEtYOm?XfP^{EZ}9ML+>LQ4P@jPYJ|h_9gV^9V%+sGA0o?Tw9X?GZj<8cs0# zWd++s0TMpd1_9XOYKOS}#xkJmp`s!qk9Y)`4=6qd3E|_)>M2uyV=SPp-|ka^h~aZP zTs@yW27&;eb6Nx_fU3ISD#SZLk|NPV#9|=AsWP$4@69@okgm~v$g2|jDo4+9d z24e$S0W1ZJVKo7uYQT9w$$i+JDZBt9cF1--+Psp-vEX(+AW{gt*9UO;#End7I=_l=$!9c}1zWLtH3`%erbU4g$XK=Ie@l@n7Y zP{6kl^!M8dO~5vOty?2}lQ=|kwEfnjCAc2_%ok!j2r$${In7nIMZqPobP5gw04N3| zBj{hOEb0e!aChj9|FLfJkJ&x$y9WVvb zCwp~jzxl_z--#J2Sn)0*WSN54g#Yi0%DR!Qf5&18+Cc-mj6D1itfY}Z0Q1@2`2WG5 zcH^Ji#KKTK5Idnw$Oa@U2pXBV{&%C`3Q!$`2tXWwtiQdztr2u-BZvX!(@?n>HGcVk z4kqp{if9}q48In|m4I?y;G7F#4Js?yi76Zoph<87RFTEUb7pV+5BKurn^7hKam^$D zR~l;z#|7}IOz=ahg%U)mwoXd?F?jkBcA`qiHfqFQ6mokoBH3j0V;pfTUW_Vy8G&B~ z<9*O|Q@c0%cs%4qfb($c>7V)Y?@6)ot7|Ga4nLI%(6`0}Keb+*h(lG_?t?z?hbg)D z5a6Ex{EVzfk^?U1cWarzzZAi5Lr`DP@4^1t7ScCO=4|&-1YY$=0Q6u?bO1CONY6^G zVi*tCK@bI%7eL@YA@xNVjV^W3aLx%|Rq!ZXH%^`rtGE4eyy!GBk@4x@idvCqY91Q@{&%X1{ zJ9td2UVZ>yz!_NlXYgj;g4qMw>#KV5@o&+zj9&A=-PaNcx9{0ebcbZAQWJnc=MT#d zfD|A zPgPY<9{xBwf!sg^aN|ANkxn3+U91;{%Hfb@=Z{}L3ABIwxV)_76%k{|zwoPowC(GQ zn@{IKd;daJQx%}8x!^Kc>s`BG`8AJN;#?KR_i(U0Mk%+fh7EaT}NA)jA1FYBXx^7Q~_TvyIjFBwKaGgaLj-Bhs-^hKSC!Suvyzx!f zFNub2)d2mg3-djcz5ep+w@Tb`Gf@roSsGunfC!2^F4%n=$svKppPv7Te~#ro(39lf zt{Pk%UKp%jU0z+Co?ToRoge9GqU4djApu}5C(v#@-T~8`_D-!iihZGN#|=3oaPpH{ zw);Rpda&~8{(&CgOwj|Nw2jioFom=&qQZ4e)^cAlvuVErw6 zxjT}LJv^$>*91cqXo*xIRfBby_XsUbLqK0aY_80N`8wA;xcl)Z_S|#NJ$oR%zHj%A z8+Sb_Dn-eJu@>66T~>fkg;S2})QATpKUlZJ)SClI<)(}YAh}Hdzs_ga{(L7E$f)279vf`gueTXq6o={z5}4|d zrKz3spDQu@0WRDqmJG3*fPm#DW&H=k?i`!MuB`n-IFZa1?z1jMVp;ueqeHX-%!kc* zBLsU04S-iWK~#aB)BQRpCHNvUnt^8CCcwS&6{x=!5hy@$nBG&kn@E#nVhm+57zP2I zO#=TDZSH)x1Bv1N*+&jYzy7yQHaM8VHGyv;#OpH@(A^`S=6F z@W{a|0_b#0zkKmIUB9y?3Sf`vUBu0y0X&~y5x2zsP4iLYp9?kbAJD{r)u5~(|LF?A|F#vKfQcm} zj;(H|@%mttK>G3(;b>&_Rd-&zz-5?;H zUjOu)^P3F?SH;!P(Q4Z!?#lenf9}x_y;}|w$7}4alZT1n`Wuaes0H!(hP&`0fn~J~ z?4M64>hWn>UjUE{npaSI-OY74ONd0gT-0GFJ9o0I0^ch`7_dVPcN)82bPfs1Nl} z?N8d07d8u20GCi5jsqox>GWO~!0Y{N!vpcvrz-#@6}r`gN3xV@dWJm!R*QcB&qb&c zy|Qt^!(DV2S|zq!0Pl`}{`KGIKl|+b-y7>`kIl~OA4J=G%N^!C#Ce_EL|;0=tN<^r zfAe9`8x+#O@BZ90c2oXT27jABo&J1%{quC%0~|e(9J!aj(P2t8;q}l@qD&EB1aub$ zsY2JdL3@MHZSE~#`Q_vDemM%f_ui7-PJJlA2Cye1Ioc914470#>^Qa8$;|()py1J6 zN(GcV5BrQxI{D>^cbhK-YzVuJkL28b1kRe03_pCEl{Erlll^x!LRR}yMs#y$=lv3( zL3Ll67^oJP|HrvNCjBIrXa5!Wz+pm%;Wf$?0doX|VnLza$wd|4rP#MN5YSd)Ev64p z`tN>x$>z^s&-?OT#mKt>>w{*rQaHw$`NN=*h6bSSf@;xlDj`dtL7Ver!!Iyr`rY?F zKHH1S?};P(TmqOYExw-gR^{Nmn>_+@=YtIuiDT{Fio|P&Uu%~o;4OrIV&uSk&Es#| z0(NEjLy^MvpZ4CJMQ?|8N%Lf_I8W9Ya~gI5=iLnz(Zh#RE)c-ssABL1@K4Quy!3Xj z-)}?k1!vwKOazKG0Gy=;4@w+y8We!$nP_7 z2IW8Hz@u^Y!5SC=f&avzeTSx;hND0bTwwUM!<8=7d^IrcZJxjK^QV_DtlQFYNcPn9 zJ)D74NEE<5MW#R)0V)4|`wBM!Y#OMDMiUhY%0AH!|IrHoHQ#Mq_?&jtc@*xb{2nf1 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 literal 46530 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

dk#8hqt(x}UDkv2 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 diff --git a/src/images/widget/panda-rocket.png b/src/images/widget/panda-rocket.png index a5a8a2599a7566e89b1bfbdedf42121b55407542..76da09d2c2f40cdfdb1202d0a3f3c24902446a79 100644 GIT binary patch literal 14028 zcmV;-HZ#eIP)ihfq^Yioa^78%t z{rmg-^z`)k`T70j)A#rH{Ppkk_4WGt`u*+U`uh6%`uhC*{P*|w{QUg+`T6+x`1ttv z`T6<$+rj(ItN8f%@$vG=>e`UiwW6Y-solkJaB%JI?eFjJ5)>UtG^zjp|MhbP0002d z&(>v1-~fZ^{ly;<6B{WiGzttA{?;EzGN%j<7_y}B4-p#o_xA`267}}=V@Kco|Nmx7 z;uIAgeFhy65Eb+D^YQWV_HhFsA}jWACKnka933Y0ZUFlE`L?O?Ha9>2|Nido?n5o6 z{m36nHm=mt*x1+IB_}XnL*MJ`?AO)T1qKN(F*)ey=>dP|+}z#dBh*(adLN2Q(0C%!SZr*TSLo|lb2*txn*W-os8+i!^Lt~<7-ml z_G}%mudw?s=3ZZB78)*^ znx9BZVE2g(rKYJvF_!zkk$-@MX=-q#mg@tYRT&>W`ll6QV`%x85EY8(_44rfcXw=U zbNHiVmzbM8Fn{-iE1jO9Fehe05+2;x>vLnh`mcB1*!ZHNrr721&B*2avKYg;^PIro zesI7GPKJ?z+MuAM3_xuUFHSEmEB?$MM4spzWzqSZP%M(=jDN^7OuPkOr(VL82!2cu zRXkq{9ni@2S*Pc`wBKAdD6z=ks-e_{bkRGreZJc7pOwxerfb+-VQ{wYhqBsgqS=>< z&H0sF7CkeL7AgM8AB4T?uTWKaX32v?NYk+&N{`QY%%xLCnFm#rVO@l|y3mDl9&BA6 zr->aWfX0-Nv5vK-*l7%%P7X6FDpUXf055b>PE!E={{H>`^b-W_GYUy49@11k=E+{C z{&D_ixBkDd+I--Qg_EHE{+j;&{{H^{Yil3bF#rHFUP(kjRCwC#TzgDgRTzicmTiE0 z!7{gOy6F-(Uu7qVxxJy>2U(@fO`CF8!YD26id`0vH$?^mR9+IuAaj@@iw2k>&Shp! zvuS*5G(P4#zKurXBk}Q{|9Z~7=k)aUc2(2?Mt>&4;BwR7@BF^+eCIpo-i-h8KmN!6 z_#ev~IqR<8ux0a(joBIhN#tx?lL=I0ZM`DnzlYpB0L+;h!1}cr|1qq%)(kQ!Kvr(X ze+ui?00wg>9$1$gA*-|3=I7_9!Y|fr{}-gm6`S&4R!`!Txy2aVS2GFx;rA2(Y*>-8`ns$*dHRc0*DiMn^4Fk2 zGXP|6xFQXIL6Xe6%k!>TPj90WbJfO`8Os-|H{iiHBI%QFqWl@J#p?43I=)mzqXZk4 zZ$8Z3M(G>CfF1E9cExrxB`8@DEPBT2?z3jO){OaCATu4n))nduarG9O{u#5yhxq%P zmmG2vfG{QAXWQ~rU{k`VGJDa7W|BTS*qohvOo;^)@8*%IgpzBJepk>{|USj`OXsOe@lmGFQ8yWPrunjys;@` zd0_{k2&|`h{ITgLS6WjkV0QVe1Qwqz89;zKnJdtP=LRiAf%U61mJ`;Q3IEy-ku69D z=V{j|pyfNKH5KrkK)q})FhFb*umWIv#xlan&4BQ4;0jW}?&$%#!q@DTTq*fu1DJNE zzL7X-(k@_DEvK0vm&Csm6RGnds0Wk)F)zyYE|~DFDPfVkXgUQ=V*EY@4hR*57k9Kw!`glyB%=}#2NJ($lgN8rw06;z`E45f9#&Jb31BNNpZ3v4fX&^; zVg4Rl97Geb-{h4j{q*oTeP{e43&$VwC(sn&Lq5#{;F^r(0-ORtD;{oEwh>ST#0kl| z0Jyx7LDpX2*WF1=CpZg$Ez6}CTD=}ez@$jWpTe(>n|*4Z%eoNwEK+BK{!X$cz@Q12 z0?Q={pjqG&UB+_u!ZoP5^l)Fu1WMS%ViZ+OOUv;eQ*rE}IYSrq1M05}CYSR4R) z_#I+Py*JU`f;HG0PA`GWxvwWGc$<|(1!Pt=SOllRWswDQHmxCZ;02BvKnHdzoEZO7 zZGVf$q4cCxATaB8_y=1-eN0Y}Qd77NE1sXRjt93mvaGFagz_gIaOd7MZDhqdAIsq&ZMda0$jpukLinKPp*;I-3fI8UYOgv*Zin>@^^PzW0MC zcUKfwKICSTVnCh>xRR##`m@bd0#PM>As|UkNeI_k)XXWz7X#uXj({~ww^_Pw8=&;f z9}HAf6z|@>yV%d_E#Pm77^pf0$pZf;IGyl+mNe5qxV5gXJ|H+?Vr8v9Q_Sy2JW7Z>lYyr0#r1^l+uiB53VPtW$n`Ua;Xg6k6Q_l+rTmUTBYMFmZ_ zpyI*Jr54;Y0vj`y2y3$_|NGw9t}97sReWn`lSf zaJy)m)~YCPKUbhz3^G}ZodPI-CeHuq0YrcIzzdD##@w8)$=OotGV-r0U=uFUGKtiVT8wr%NV+debfPMIJs`t>^bMH%Dh|B>=|ld| z2)ipEkAHBMJL5H0H-SMs`jp+uvD)~a;0+)PElYoBS6siMDyg7KSo`2;F=Uy0`b-YtF4>@RzT9vwx!t_%V%`_4-H}dum~Wigi*l5Bsgpk zK$zhQQh|F=NQ#u09j6gH+*?rR410@OQhGB9mL>qQ$ppY0Me$z=`6K**`4b5qdzi0j zGx8s0Su(Rhi1v84IGrRwK+z^V&unK^G}t`lhX3To)RcH{STg`m}o&dgvoGX4%(|;q3g=AEG#2Bi4X^_)w-Q8&c2u!fojU<8GqAr~P5kC+4&wAqt zZzr4<#YqA09WVY$kZyos{vV+7Z=ezJpEL4@x#0x(kFdX943|H?o z2*C9voRtCA4vzJxS2>r?0xP!y%>M~A=M}%8mOqE!w*~{eVVnV@Y5=eW59$t0MHTg@ z`bxkRwehT6rR%n}x>;^eZ-GUh268hQoB-AO|4<`J|40fWo^~1xFez&DInbYn49YyT zMWG-7~Rw z3kl=TpmTI*IHLfr4$jd^D&AceKl$Y1E-=iJ+S0s4XJj@3G6R0BMg7149)4pAlnkre z7CUL^Q~H5jyCh&y>^KA{gn3cH18v&%`N_B6`TUa`g%HdO{a!c`ERh9PY-8{Y_zceb zc=U}hra+;IQ~4{BDb8Q|>GP8(KffL{iL9f?nRIzg8(#8RK0o=6yW`ZZ&%+aNDwJ0&&aGLYk>26ii%1Pm(Vp}3OsEw)u10fu)E`kc6C{WA56ecJh2qcm5HP}gm*A_6vXTeY4{Qk{5 zZ~xR4Upc!ZL4)Lynr&fx5JGKIIrDWS@6YlRysH z2Q(i?20#iN(K?|e9~*LE#b?PWpp&Pky+Z+737L0YfBi1dRMX;9+r;0{~*! ztv19gk(eyoDCE$-d9lk0Obnv$9V=k<4MYpGh})wphyjEnrEu(rj;kIRIb4qW!2=b= zX>%Z4?oeM*sJ*j5$nJ1^WDOp-gBANhGjHeQj#!7^ zPLe21f>!fll|s}2%u#57J#!@`SO6FXL)Zk3Sc24bU>&RP0o$4)s{5_&6Ly}{_D?0) zFlQ;$CJ|~Pvv$tT>$XU61J%1|(*QLgS0H{c@c1wTiBFHWGJyL_{Tjl?!27@h|g<(L#TKx4H!{~g`~ z`BMd8QX~?T4E=DZxT4Y^fU{m(3>zW#(bECKzCODhx5@2;VT)=W%M7bC1{bQr0tlIl zb4G$@fcuaEN+BqF90y0{%CQ8<28XJQ4dEAgHU)jy#0Bun9CZLypg%s46r8)sV$ombYCY4&`87-9g#zkEoe4{Lz)N6qG==bt%Tq)7nN zVWSoa?@<9LgvhuykO({{y8AjQ8wwZGT+>Dbpb`ka+Gwpya2g&iG+*We^H*%oVyFT3 z%#~|XVD*t_0I=2%_XNEFoIhM$s!1?%d7v{=+ zMrvdrqx)Lnlkj0lNO>?SGH&C`9K5GDD*fRZQs%NZhSzP#LiA}3Fw&?Mfz^#5JjHYB zk!QQ;8TWzrXk}1cd1&D2Q)v!=LRhRRA+(1?$GZ^cM5R8x0%$dOnOj0v>>%_>5r_IUBn3!kH5h0_-&Q7~7H1-P>qw}ci7Y1o7KV+FY0^dh=0@6JH(8bY5e1F->y z;8ge?NUqSu2`>r}gahhw-~;D^`CDog#Gl|CTnnX*fXmqvT(MpEeluq8-usS21C&4< zDXl)v^ssDlNizx>t5pNsRg9Zr3x&`tLjDwGQ0dK=&BL8;2??4(v%V0D3ks z39LI}K2iz|aDZ-)FAUBJ?p>V#@4{toIs;s`Cr9(M0HvS#^mA~9TYM)rz#N?Ao&j*1 z&j79y9In<LwnuJRlKwvJ%96;X$M4tmFR!>6QqZyzaW`g5pWB>!WX)sg` z4Nw{19$Z)u2!l8SP?Sv>HKZ?Dxh%)!={b1%8~_A104joz0nip@Y5{NxR3DwF7)TSs zMn(~tClNq!uI17JKn$?spXQ%U&%y8gK<)Ao12n3gu+k&upgYyd-rk7>D6LeluY42X zD{DFh42^TgZQp*Y7XWU6qzeH3I$*_$)hkx4{M*&vRr+)A5QtAHF+eFa0PJqDoQV2a zx+GY|9501cAZiM~w*OXy{qI}~p3o0q844uE@V`%eM9F z*Kf<)uc4~lb^L-;Y1s=N{vd0Rf^ML+f z=!cKq4e{uscYi@7IERnT7-qms44}S2BxmjBRRDrv7yyyAW$ns;;27u=2|M4FrF%+` zBLm!v4A5KS>52k`oy{#A8$av}o~c&nz~VO{b*jLrKQ{-~7yO6>&@{jjoMVTj)D-{; zfLxTc@|dJ!cg&XDzk3E|?|ICh7@&w4;Aq4hY6S$sn1k00pg7^Cp_T$)yOm=9t55wY z1*CTFdnf<~R^VJg3J3Tk%Jdrek+)`o%wz!b_ME>J0DE^r{uBpLBM2FwsJa~V$`O!& zW(PjA0NyLbDe%~>i3+^_>6L#b2R?`epbDTI5VRPtq%=2Ytlpmb?S%~3y!x-b2L|Ig z${)^wdx}bj%83Cy?LdbnPBnlF8UUq0(L!{v%@k#rHpc_~E&8=RW)pHAM`M97>5CS7jx=xYmUB zk^jcq2CoAo0n+1Nv+`sk zsj>E8*yWU*u0W)blaBrWi8*j+&qN-3Van)aZNsHRwy|EQ3t|HZAlNAUz0AaR63>eQ*75*>X5Od!%$sKR#Q z1opvASS^sZfGn_iYp;x+Hx|lLLFd4OhOMN?An*f9mo*jc<9+bl-*a|sN8ULGyjjP47=e4Tf_G1O2Lz#WC zH7p4*)ul-Zl2@u7{_fRB_V3?+aI6*pCKY|_*;fh)8cv+>7Z!?gSz)2yN?tCo@Kb@H49fiMEF0h$_+0la-peRwWxoq_?;k!*m+`2qvjf;+GR&zG@wj&mz*U8D827QqX3 zu*5gLTrP`Kfqoo#Y>s2vpVasV>%2q*I`KuDD1AuX<|!;>51u$E78W*>*Gnw; z6rd?S1=19FTs6SReLmYLK&b7u_apCHCr{4+&@R{FMgRtSdfte#m-pi+Q2l{6NA2!V z_h8qHojv;^(b{kTB3v7-s;_&nX*L#e+eMBqdrMXAn42#wRGR9&>Wiu&Oz;~^-MpjF z0OiEN6VL*K^aUdeJOS`@(y7k_Y6PH0&>R?R@B$UHT~o?fpsBv2F8~cN3C{09+d;Yv zXapofED*N^552(g4v%aLg%pTT$R@j4PDESCTI$gL=4F;eQ69RfIT(=4nL;4ac@rFb z3em5GF zTF|D+TE=Jqk^+lHN{03z1DsI=lmQy1M{5B@pIQ=`V$=Y%1V{;-1>krR3;Z$MS`xSe zt~LrU4e_9g6CIGdhO#Ko8V0KuRs)!^0cZ+D4mdmlw}tO>hAsevXs2K4ss&+KaX}1w zBG>?i3}~DR4KZMZF>Y|)VABZTIe`_hA&)qq5gfG(a=^MwQUoI!`V8%fGqKa){78ZU9=fyv*auJ=MB{0^k(!M31K`$pC3am&a-F7!@f!XcG9P%#kJrxPt^-p#x3> z{=&8e%>q|sF{v}aotQo{z=e<#sAzAhM{N*oMx2-hs1-`8VDti+^uvjhx}GIWfE)x& zf~>(c$B1e8G%=tM3zQX#9Va@(!ci>1)`dL{NNWHZ0V?*K7nEtB;zCESGSyl&BdCRt zCy0&(>@gT1eGI%rCql@a^@JK?6K!o1-3=iR%W*mtSeQAnY0|_1i}|A(NOaf02rwC* zrARvmlIOvbUV(6c8sI@}0AV5u0%HxfX3YTe&;X_B4PazLvLMgd<&NIzx?ru(DM2`W zwZXbGgGvF%CzQ}63*sb@8uAI81odkHbM~L=gso!e3lWmmK^W(~N6 zz;g>V0BwVCX<`6JG-A&yy`xoDL69u2gm=dYLU?#wv2(2cPhLhzAPqbnun z@FiX(CwaroF?_6)eRw~K8on?cYJTVKT7%lCqVQycRvjO-zQ@t})_>4j6WOlBO+vG? z1tuv5gbhu2MUrVN@(Ps4P#Ca-POD%msihWL9c*#hV)50gRGmJw>K~cX89O8ONBv>P zw~qev-p$^eEDH%CSY6|RGeJ+m14a^zlwqkMkX#jwNP{J&z5OyK=X=3yORDcrj zNpWX~oc!IP4nK(l-FAe{Lj<5r0oYghIH_>#mshK&8C(#l?LT_Z?c!}D{aNsr%6h+D z-38awiX(ye%QH$I6l{yZFODEXlGm!2-9yisKf3V4S0~?pzI_#8Vv9Mt2&yTsLB#As zjqZV3v^`P{Jv@kZss+F*1XzSPnLu=oof>Q&Y+WN@)G=D&ZSFZIfp+g<3#&xIX9X6b zU>qw9QT)t`8D21GiZl#5}g zzFRpAAr4UMjvNSVZDHmJKmj7+{YZAQCh#`w;(d&E>cklAp(_%(e|-_mCRmyLT!6WK zkx>FV21)Key1CAe8V-05dlBIQ9}zt@?;?|+_BhlU;wVjQ+sh|mz)Kw>YCm4CH7WX0RF;|N&xMz zL+@+_q=AG6^YR2io-AqAbWS`=6%f}4S~eqN^7ugmchfElxEnxi!?*Uz22zET@DjjX zH^d-p2U;_T0D7aVroS8MeJ{ZVQ7~DvxHV1IcT87D2@n@l|Mu9+xXk^@_sCq6dAHnW zV^EA-5r?f%2Q7ypU&smqfI2{KyUEno>cn|%sZkJa1kJ=Fv^KkQ> zOB@uMx$@SVGZ#f1gVt0?32?^KX*LWRg76roBVWEuF1} z>=MumcrjG2=?r{(iV*NDZBCu5fyR-mRPfQQH>Unr5UCCZfB;APCe+~E>ZS0l2b>{X z3Cx4Tpr@ZVDJFS{)edk=L61M)O6}?B46P%=f`OWITfag55b26L)AM3r@x?MTSl-W@ zQCD4geGNIDsv2=u_M=@dZ*YJBp1$Za#hTQ$hEG!a$|rl!sv+PzWitd+iJYyXqC#jn zHs{C?F{!`Ze;=Ypq+4Pn5cstp8Acil-Q9zY<(2jM=);$xEtrJBCX?Dc9Z5=n#~*7& zg{`8&t|eg3agtm{Thn~3hEX3HBXkq2ep4pk{90mX>j8lz>&30Y{Vp z^Ur&Z`s7?_sJ-y=hCF&PfV72!2Y`7-geAm5Zm(6_BtQswe5z|x+sNLddq+Y|ev*id zn#Z^wfZ&%70>}wL?v^}Q4+aB2Py9MiU*GZm^MO1w+zk2pi?4Iba1PKgu$4<5e>dP( z6EJ=PQIlt?XyJqNr%C{{Nni#7zqZcETzUc8OpQL4=tCLG64|e(}evJ!Me_uR5dbHxf z<=3S1x={4GOtF=;OM@Gzjif*zfY|hmmI7&Wv$)tu$TFu9YJ$Wh$AOd0+h+d5tpPrG_9Qb^{UHa51#>EYj6#AhktWAUCyBJl; zigYL5b1R@v+jSvC@muj;fbMnWNT8+wPJ`uR3)%!YJ7e-;lO*z`Y4!^4m;UAyn@9va z=Nt^J1NmzSh=u@0&cj!)xcR}`m#Z8<%~R8j_Jd(FY5O221=J6Kg4lkLuL%Rd!MU@S zW~Z>tUb-^=Y{Wht;}>=W)?(w`15GOU+Ld7SRI$<^|G>&SGq1mHnLhXBGXejAO`Ocb z3j|2v8&DOP9dZN&E5mjLYkz*LRtUIqqR4C7zGG{1OKW3e zV`ulCp&i?s{OjU&%tAfj@e}&LDFmHjOiAZhZ_weG;KkwGphFe`P_U&p&w(Q#z#p9q zhudb(E<{1~t5^kpO_4@Wa`J7L0h3d~IDN93k{A|%?(>4+!VubP6A1&sQ9)!U%t14W z1V91ygdV^@8Wu!RX!A)^=N41}zAEu{RtlCsvy;*PnQ_<%qocNLS^dGXVH^m02?Hb; zLf8ZR6C}&Cu8?H%nWm=4tAPVZ3zx`cnN+N#=>HiYeBC`t2q4oz_~CZUKyO$ShesU| z3P1&bUx+*ayh*MH`kH3Xj?*k4e;+@0Y0Bg)$x6|R^c#?N1U+FkLP1b22;>ENwv>?$icu$B(v5hOinyt3Q)p9@BpEeYtx5YHS6E{&Zr1kt7f_=Z3RIF?(#HJwP}hJp&9H;pkR= z$b<18Z)GEs@^}lE?XGW%Qc#rwdi{q6UUMHrKL&sL3jBh7FP-`6w1w$6Hboflq~-zZRP(d- z#Q)GM7(Oxl@t5Wh26q2>nrvc4AzYS6!l9#QG(4P5NU(Jm8~ykIl;*)^Zk{TSJLE|{ z3YJ)PnHB>za0=hBe>KH_C`ZO$y8DSIcKvV^lEHbGz(>a1vlYi=_Ke1cI-ZML@fRAf1f(TziHmf5MdL>LbUt$j^?wKe z-~eEk&z#x!&%fv2b@80d*61}xM_26O<4T}YB8#CV)%2K-rZt^lX{Y#Mcd{eXY{AqD^C`3ZQd0E^_E zB2{|=W9W<@2Dla+yXTN_h7z!Tzls3VmZ%qq8}OKx!hqjY z%joo?9<)QQ{Q%>K6qrL7LAy)ms-Tp(fK0#M601ztbpW~#5E?#&gfMPyFR)C z*a-MR0GH2z8-NEW1QfiY?ont-L;zdZuP{(kvS<-hVbyqzx;-a%D-}R&1}ONL5-?93 zC|>n<1sp!ERtT9B-YcSnA-PbQ!sHVvRYTjK7Q zH#{b=nyUCyHodiy%#@YUtrWEE9uNRn0bK;Cmjagw0m}bG0>=7>V+b%dbBPIPCIo=_ zYP}0_P*PQ+{0O$1@s%%+L0Q4_!0YPEiY z2W8a5x)9csvJ_&pL8a89sZ=~f5v?CZDvgICLNurc5fMc_s0S6jh~P<3@Nf7>oY~Io zGuz$GuHxjqSTv%~o0;eRocHCQ^4mdU_oN-KfQM26XemE`_GAG3>2p)#vb+HN8+j^B z3k44M*V&Oq7~t|;>z$y&Cm?^Jld(6W0R_-G;7oV|pad~INX`!$2T^>#N4@s<{~rcs zR}nbDaD(5tmcGt@g#tK!$n$bg0hdb&6mSO$NFt}^ojIuhynfUW2lFTp@@;Ia^}JkW zze*1D;~#774_pB-(fd}C128?F6#l_^HXy8IvSqu{ z1=1kvJsaTj0_r|@=*bfS`uQ!eyU}8IbPQS*Um}LVr=mrNP zBG2^K#Sc)C2#1N0>`6%J0X0%X%)#Xk>Ow99|NVpa9$YGM_%)NSB^G%Qy6gYLM<7&v z1TRRHmf!M~_qXH^u!15AD4IzQz>z6~Ym21s-D-Ti&blZ3a`5hp*@qJ~F%{0$*emG- z6qaa^d?*Frf(Klmmf`~`!61EMn~4sRT>zkYuN!s#Iwk|RA)y-R&wC4Pz4A_7{MQN zkhmgTfg5D(o(2K7H-TPM^SK@T5e8o#020W9XyL$5alyjan`0%QqbfpECeODqMr)NJuEGRz^Jhg7?0O^A8(z}--b`YeWmXhGNUQw?ayljakSuQ%`Hhf~=CW0c^05>rfE@hbtGR{tz zZGiA+&;p8hgk&Yc-ymKsNZ<3oLRz#1)PKqPu<8YI{855zuyHcl53)-~?_j7G%BKnN zSB>B#ObrTsRP+^p~&>Ab<_XhCj6;27!G)C*VV9Bc1_@&O9Z`hAe%Oqv8tmlR$yE z#pw_CeTUx%W=95?X03?ep9uI6(x!s~UDY>%f50CF>$w6cBG4c+R({9n5BJ?4E(x0% zQx7qZoIepzKy|tpJ3HePVg`)_h`JyIFazhE*+<~#HWOk@h1)@M-yD$8wuAw(oL7ex z{F-7QwK5Fxcggv`Z)6OBAK&UsI4IkTW$5b7nRcHAZO$m$(da7R*CYij6$S@}8aybV zTnGO4MPX$0dzXpBMvU858~BsYh7^~10OwzuY=(~l4h%7Pa1lr4{fAJjo;K|e1<*lw z-So8;<@#Ea_mw4Dgs#@ff6xGybbyAZuR`px0w-LF8#M zXTEdzz`qvuPpcIAGL(2680ztY9hf@$fq(THaf9d!%Ts`@J?Mz1T+FaE) z2{N-D{*P|y8SEy(>Hr82?7*&r;{U8%E=kmoDFL?jVMH;5=R{dEhvXAqNEu!*A%IUX z2(&Y@5_ypz0m^`xYvX0ghkr>9t^j5T!x1`6@WLrC2yrMhePZ1vPykJD({cRcljEsJ zL64uHe`NHNOMh5ni#kC%&(r zqy{~T&Zp#Jw(2}va5&<4F8#H`2C8}pJyR6#3yX@yxJXd|=&;?^&;Yyg9{zQ| zcB)^0cW;*gS)>VWw z7kNCSAI1-}s`1_oJ3ohRzMp1O6AsPHPD!hdoc=b+7jGpE9w<4k9!ypQoLcyNrt=C| z<~7PSD^i+GU&KF506*ZN6}qW9)3JK?{Q0wKiimD-@yo0eXO4+^D^dYP$3Aq@z+%{r z3X%f9n-yr_k%B*FR(0OD@}3ySYaC(ap~o&+X;GWVg`9zRX*iaeg#ZMX(Lm%b-F{a|!8nA5-(5Q!}b)-$SkLR@^a zbpI#dS0X+_sf#7fLG9U;p>z@a3|x8`0%X8HlEWXGpnoPEs7b8o?OR2tkPMb0 zbW{eZOnA8TM|=rC{j%auyLOYqAP7VOc+xb1+NP1jhD}X>(75L)Ud@AeC@&%;Oc*?X zo5#0uOLPW&!^65)@b4N;XX7xKv#@2%?LQuWAh`SiY~u7Ewtoz%0|cuq|64~O8cu@7 zRQ}xlQJA#qxtMo635LlrKR;X?Nc)pXKrxagB>W>JZ{%QUi}lC+4vZe;M59*(NA=!w y`F}J4y4$ahu5X;(|3J0BX|e|L^;cC@f!YBkMB{2pQg?O$0000yE%1%O3b10esiJv;mZO5 zq5xS*F%2)U3qu$`%*7><##6Y{rdeN>`NWbulYXPVEAn`-XBsJ0NXVgx7!#;s zoZ{y#TT)6gGPqOsW6;;NMbgyOg#`vW`u4<>V`C$S=T*1s@q_DCJ2_Xe1+&8STo8R3B^!oZZkhczcd6C>(*HckJtvr95uBxgs z-`(9^cUJlu5!9Fxwf)aQ8#8@9{-BV?#>SC@!^2Ck2L0fR5-Jf95e^!fYT#PJ$f05eK|5jh@%;DDx0YRqpNp$GP*k+fa%*er zGJ2BHJX;R|K1x*F$LCG44&hyM2^9C1$!!mBx7FoMsqxb%KR+MIBoG$T^e*J1KjvwH z%sOlEMrpB9n`Nu*xc9U(0`Sh$t=MUqZ$yNJwKzR7QCVGLZ4a150-JRY_96pVA&so= z)ZDgVqoBRB_Mm{TB;@cqlXqCoO)o_!`k*voC8l)k~GQ;Nal!V)^i5sXO*o2?_!rpGL)zF4X*= z@K^g@2CKv}r7>rFyfFS3;sV#9D{f8~g-4!Kh*{5g0BLxL=K$Q%PN+UZ$SQ{*{PZk% zw7$_Y-#-<;-iN zSHia@pu&1&hy(Xn{biTZJ>@i9OYHD_cqu%8?PJ=?^{ZD=9j$e9G(%qoQn2C-AAgizBEjNhSmk;=b(dUWa zq7}Qs^j&ih15XtB;N9l_XzGiY)kHL-(u3}|;M+-Ib!celb!5Ih;@Mo93OzXbZLp*g zE1Y96F(#&l1^AAQU#fEsWRNQ)cne0@ol+OcH%2Yc9_Q*}z~I+DL>R9>0nmoN>ZF-I z@w_v`oC*oh7Z^F}Ybhx?s9Q+>$Lj-icpWdxhZfZX7nrY~U%br}OuiSiZtKPDLmegg zE%_{SgFr1Fc}A=l9q{xMMSz7bh#g)#h5yE=Am3*Lv2`y39Yq}}kXP7_i}3ptFcyy% zvy^6s=WthzuOh@!kr7~D2p52n=w{&hS6irr2GWJ}QV=yn+a$0I39=hfCXf!bM~E4! z4ui9#=VeB7_a*Axi@5@(WYKF&0jh4-=9a1Eilt`PFRcEq=nW>am+Mp^DJ{uGtHIS} zaCt;pTs(wIklX+T1%V-hL7BSTDIi{)2-m37I-Z99^37yXqFrb_yj#2;vtSVt=hwk^dCj!H~L z<+ai*8cQbIL`g%VpU$LT&ZN_(u^!A9lOV!`_xm?^BxzZR)ceN=6+655T8n+Pv7l8D zB7sNwR)r=)!cmkY;Jyn_@(#XC9L_K8OveUR)ZLE(*$kWp51jN33072Uh3XDMB#0GT zUQ4UR{qtR_kapvApVWnbPtg&&L=fF1YgREG5);Tdnu&ocQ8;8Ilg4Ti1?48$fdv$ zd8z;mHjc)IDr3LT=BL#MmZs3icv|tj%Y7yzN<>_OCgCIIyIHj8g`<^*>j$r`pezUjG1JtO$h#zjt^^;R_@ zEN}m}2pp}7vwr)N+a(YkA%4m*A2X=KVMH!$qusUj^FW=&s#2>Ki)1n`p|!QsLf&9s z$3%;g%|-Nl0PNrIqD@719cN;KbMJsL(_&DtF4&O?|+r=ei$Z-4V!y@2uatD?F?`&;fbkJ>;FCcd4ScAUrYTK z7HA?Ynr)fItaTebZ$3azyz^!AJdw`w9H9gv49cw9pt>6w9@drKa!EH|tY{Vu>4O&w znC1iH$HTr=eHN;!Htfv##+zUo4r@&+#7hwuPu~UuS^Xz5*K9~o4D;EAOFAhd!-7cY z$Xfo-X&Agjz!O3Nh3oMrIZN+5G#(xCYF2JY(D_YL>>u&6mabZUtOR2lcl?L1KRP~- zXIzlHp3w|*NiV;C|2FsE$!AMr(r;CVWOmmBL}K>;6fWM}ff&$nafuOp8g#`+jMnnx z>=X4N7i`OBzY%+Go*f!N3H5WTZepHr&;F?Q$A`c5i;uGU&41}?KM*k$Q`UYS%wRnRH|-axJs*(t=$B*YKm&_p}`GhN1fa2ZyXG8T?52(}!7bjli*|l!`jXS(eh9r6`DC#|P2Xu8=-ZpnJB0 zP(g9K1uv*<1-g%Y1#1M7UBAVCJzx3LEkoZ7J9v6zUHXss048f>WO$`n0098`ylKzP zqR+ky1wFR5C!?4sL0Al+{Y#;brWIx$?UYGUn4DbRoT7`38RQt+cf%*+XQw8emIeft zk&!Fkp@D$Lyuu*RU&3JAZ(-7~$01juX7BG$Pj^}c!pA=c7wmFm6i^6xX>$W_o9PmN z1hyr(E`z)Kt~?trj&MQdRcr^zexYKqz|@89B_&TPj+D`Hx76;FE4Qin=%+#%=9}loF2t9u$D$_}@#G z57!-gm-E=$Q@~l75su!~K%k1Zwg`a6BZ1RNE`l|Hc7RX`=YtZ}K76{@YECVEBR7c9 zfI)}010BzRjGN$)i^U2b(gD1_vg7sDyTN1Ahg79xuLko~H~mt3`A_}a{?6rPaa_kU zv;F6_t41uuNG8Oeq4QD1qPDKe zLV=2%?SJ1Zgyz8@v-5e&_dHbp*$Di8Y55CoM5CD3*!_Gd5pI7w)v+gsd6VUY{xje+>eW;6VKOH! z3A32G@ek=#_|G&TfR_NlYo2??K7mM}1U>avvvbePB5KgR(0=g)jDIshP!(~|knB6n zO>wEEPCAn@97Vo&UP3z0;2S$>FB>5^4Ie=?OoA>hLf>d#0(B2du2K%|6e{z@IJ0S! z*_UF0I9KRK;)teh>?hx+JPRJ9t3@Ew^QI?HA^PITLcOzt6>hP8_*t<3?z{bFheRI! zDLw1LCwaUxiz96C_~Od0TIxp?89zkw*8!K-86$q(;9(I64P7CntpR>}tmWnRvao2Y=a}SM4!7s@V^o#om9~+;e88u9&KZF%;g8w8&$~YV=TSu-BN`@s?(}-I?Gz#3 zr-7QiHA5>ATo>PwKRtaPRMga3wu=?T`{s`X*HJCWHv90Lg=!@bwS2m_9DPQsgdB260eL7&x;b3nph5up9LvFPedv;(mq(Y+Dpu-05ab+gF3v5#y z{%9Nf>i?_x7()Wd&EMNv&3F1fZHA1!rNzi?upLddiH}xw{pxC+h!bpK`@FO4Ji;{= zgLfp&&ALx6*Dvq!k2hPDQzhhFkbSq88hehE_ZOjE-UwiBwS}3$ z22$a>>59Zfc)FH(0pvw275=5huPI-ktA37;P1A<=F;m_9I=Jt}d7Ho!L<0x)Zd~h@ zb_6#;X={5|)Qbk4&(j69u|J>U+tX!r)X&Z*`Zs*E9^#Ea<3KJ$V*i5xNzn)fh*Hx? z(zzl5r}-kf2A9L_Q2-{hWA8_d+tr5HRCwj>O+e$T1%18BAa)xAP-|Ww-BBLmzetp(cNCK6tVY?J={xVCcC(ee!VtE z90fWW5SI}+`6X)}~&Vpp1AG z%rmLuX6^`+t@f~vQto&%$M1G@)Ds#g&Z70xg@YfIfCI0b4zOq-h4cn3im+1x`%`MT zR~eo7*Fo5+wRH@tlc4+gVk!d*34QCfuv&-5X;Bn-F?>KpgOgE11ANe5)w`9G$ip60 zPlP4)KK0woDx*+XX`O4Bhh7!C z1rNsOwuxH#)EnQF-8<#YAru@j^o&ob)^9fHM?wcX(4z3di~iJ+34Y z`l8(mK}UHexLZf6ay%1qYH@0HJq(%lwvj5-S?gkA&^(76VGV3|mdp%FVn~1|J|l{m z>0|^_<_`oQjj*uMohW3~yZhPS2-UhyL_9$mdZ=0=N;JXk*Gu z?bibvmE(_ZX>yYJTmy%?-e`Zc$SQKbQ#hOSPG$0>j*$3DIuLndSl1_0_6h!65Y8+Q z$*ju_@#m2m$y&x+pgFHApPfCHoV&@v1^WedG~3BPEd9utG?n^HSkFaN3~LT?%k%YzK?&RN!v0H1dqznneSCknm;P z6%SH5{_%DtiT}ISPd~qQ#);DJ5P)D!lVzmkBESX1CRVly?6$I^L^A zp@!B1h6-uqs#(Sl1R&wBC<}jjWpUcg2EEl+o|y|P%N~58ruV%-{bcv>)5VeV5mC6ZLB{5Ls!aEni|XOmWtj)e~y5Qqqk*zriRB z>U??{HXOCm=SMr-2@Z}DJ+W4aC(rnD_VIrT`}>T=TIb4ql=)Ca0pQ>-0j-(;pvoFiS_eSv``L=4<|lV#Rt4dlNS!0}i|EEDeAW`v9fUR` zp7rY+h^3}c;mb)N2nrVdU?%c}1YY$k#+DgaS#wQ>gddKB|2L0^U{oZqbH0#IXyw!> zq$^Wa<3wt<)o>nvDA;;MoZCoNMggc=c!h3fuL)i^A+SlwxaxE%^!oSy4xN{2z-A)m z{UUSkaX2pXAlp-f7ISVwfE)yJlS-jA#f`EFTwG*p{9yGyDT5&%a*!LN8kRu&+WQGT z9>-&#Uc|3Tzr&&Yb^?(;I@7}neO26M4tl!$Y4B*Md2CA=DD>b%OxNF z3uoH2<*2I1?=Nu=r<>}hSH;`rMxkfZ(HJy`4GcBf!zydw<9f8I2A-Erzwb^X&$J|p zj$K`4Zx@$ifh%pi&1!dMq#{qytcUMi?LYvV=boVn`gV#tW2)h{g>%J)(Wm_ScDJu* zby-=NE-IgIhjhRcI! zOtzdjZS;E!T(i{{`rh(4c7%9&EhX?Z*MRH@{Gco^Ru3-qj*Ip#WO7{htw`bk1*z#o z+Z(#>8WC&CQQKcF2b)(G= zcTL2;a`k$4`!h=amzxPga*=DgzaPgvU!S1bYMuH&&27WunkpB%a#(I(Ggs)}vZDcM zBO4UGI(ue~)hr3R)_hGOP!8->tuV{a_s@xB1N^d?$Ve%>C<=9DsIQ)OLd*;;<1Yzk+DA#o4M~VlWeL>$rw4_Y;nh&7q z)_d`!`nQhGY@t#GeY8syDRzUX=5Li)nm?XOO+>}B{7pA(pzU~Jx^v6$!8+X1SIX&7<3YRp~Cv)#S6(KQe_$WEEx%v zzkN&V`h4qrnI3c`P(5@D2IP?CJepJ z++!c|w(Doo6{U4Y%w9{@jF6meuG>mRO)GWkS+Nvs0dSx$^<>+vh~vI`&h%aZb+-fZ zzncB>A8S*8RxzY~L|^_9DQ2#X0^5ht!Ch^2_<(+W%er6x>!yi(Rg@^MzV2#!po$#t+Giiz)+M z&cH}QVN8_Up(rXnEYx}4Dc8FBU@viWrnk5Tl}WRaOM z>^tHyQB=5;**B3YV@|6eVhx5-(Yk_)GRw_I&)lciW8*QN?a#hAsVqtVX(>clMfSZX z3Q<7=QZ3a?3z*o8!gvScsCUn8_fCbZn;a}y`;t~1Q`SG;Od?bN;M1F3wzTbl%-X2F zXbd)XqIzV5ZI zKGzZo;Foicj&^Hsqb~NlpF-~ap>W)H5d=g3$HG5F(z)0>c|#E1S z{{l{#h2-C-RHIPx-LDziJ)JJCoIg-Pfy_FPh1(nG-&xnmd5UV@-zr(odO!HrW5QYW zNIhsvejMnGS_ybq)%FwQPkr3#ce|gbMN!cHCJD07R#Z$a;*gcgpq=qr6!LH!*?Gqp zhIsY&lUrC{T#*nDVN$0KwCYB!ggO;BFQOR8e7+J=39&*$oE7GAVI!j74XY>9G3Q-t z66fO8l>i9(!TsZ_pF&8U-MeOCdvqGt0ljJdok06(Q z1TcyPe42(14i}MJJE|<}zrAQdPAHc1j zbK!#2&pqY`iawd#)f+AWl9uXDjR$A1NoGTx18j=)qZDPEdE{TTP%jkKFOCf!ml5c; zVDKPkIw+Hi4Td^o%8~nA)Va{;N-_Yk0y>7b_%qQ@oM=X&BLgge?Qf*|!0mXBy?tAe zYA1r=&UH86A7w(BbU%;m)6Ee)*CefA;`jQU47Bon=1L^mn(Rm->P%R z%ZcQ*O;0Jw%KTb-Kgz82^u-uyq&Y15+{u`E5DtuQe$ZoGase5WjJ<_HoJnnaOu%N_ zC-p5j+!7~6-o3uA)4I`hPy}^Fyb@{>6$jx{!Gtr^@dMb{V;(aCfNe_PiD@ zHg2@X$2UaND;>U6x*RNKN*};E)h75d)`Zr6G9{BQ)RR;GIBs7b*QFn-Ji>YtHL=_4SHlOh?j2ahLorZ(r7f zMjF=|A7|MZqmSXI_7xzaBPmDjHmKq&&~rx|wO zw)-uImuTvF#&EP+FQB^uYq5p-M$shs4RuM5>*y!E|&{xKHZ_neI zq^|p-u)qM(j?Wxwvon;$T9oR))I>UED0sYeQRm5^NHU(>On^LyIV+y8M2Sd%{-8>I z9jQi)K$o!5a6K8Dg3Nb;%1NCZk#;L7DV14z56Ex#Oc$;1t8$dJR>oyLTPHJEYMO!< zPp$M0xn6-&hyn_q>Mv#rx(W5oBoi4ZRtl~8gE6G65*}JsW4JHn2_-HVn{HY0g7N$Q zp7Y~oi_j{miI@UIxvtkBUZz)1XI1)n`<0$hJ{Rm!?xf`KG?V;g5Je>TQKa8MtzV%@ zdN!5@ir3<|t6TTe<}DYxo1pSpfTu=NcQktw%>_*Q7Na9~&$lg|m*zBL(?tH2-;w<) zh{PdK#NQMa=vbQd^$zLs|Hj8U8ROhH^FUcI?&LfOrP8fT@R78iJ{CV5h584?Kl?QS=_x@|si>?R~dNYq-Tdj(%4$m;1|AbDQY|3GOtv z(;wQomRmc%j}N}{{YhP2JyPts7oKI2@RjT>SJ=Gylb1s3$=>qB##ut)TvLQzqo%#Q z^luHu#SaYH8eKMNC|CgpsENRApU*?=Y(8`s6Y5#FCKrMD`Jt4QvTuPtIb6mG6AI8S z{kRzsFK^<^1Ox;uEZy(WOW2GU+l+=vKk|{`qiI6IQ*sOo>e)Z@HouPof1!Rd%6{)uhDnDt>06^~7 zhpzmaZY80}FACq*LjY>bwveGqqRf%^N(t%i)PR4VniOb;v1B^t?_1F z<_~Ebm!qY$qy=`Js(#@YC9f0%S_90 zHUt9d9mnl@gkHf@`9_1SG6pS1eX8z2|8N66hhQsG$TY%>KJ{heE?@2x>{Bsxm`n+c zkGJ{mbtpM3+H2PvVRIO(^>1sfj-?@f~s&92~hE$D-34@z+8cM<| zYI_cjjBx_ZKwTV>l54|mMWs+6Zm?l^Yb6VPgaPLd5ge1d2iP`sh%)Y`^YvCo2vAGK zS(~0peua-$V}NoNFB;(XO1F#h{)BDTW7DSo^YcPE8WXQX>dhYEsL?F!6CB7vnwEK!sU$s(glK?Y>%`iV@~F?1$8nBk6Bnv}E)s$YB*7YX216?X4dhcG_TmkkcWuwk_?2#p$%X_K;2dM^F}mQtfSTQ<}*w8KlH#a zx5`MP$|_GxwC!-&bVfIjuSZp%xD#PD^{z-?QoX%-QB;U?Tly;ZHhc({iMgZxCg|E} z`!h7^oOIXH4x>?Ul^ynerD{h|6TOD=GVFZL!hQOf@7WRL7hja|5S}ti0XXm{3Le7E zfr{v@wr$*b9;KA4l-{Y@(l}=F2dXzh} zAyI4~>?3mBB>wxa&)Ev=HMI!`K7S!xlAGCWlxVr2A2U213N@dn&{#db_lnE>9;K); z^l(z=FE5a($t?JMUweCdi#-sC8hh;DeURIJTmC$nf;1hL+0>M->H1y6N-)zp}^U1QZc2 z0n*RMCegLbn{QA6FGhfozBx4@ItnqZ((#13a~ET~?FbdSCkUv5Uk8?Loq45%ev%>P z3B{P!iCV4gkf>F8JrNV> zt3Capd_m4<$-2Dz>l4!d_)3V~MAVp)`LY(=CKfbyi8mt>_zC{HKQk1wo+Finp?|{K z&P1GXA92bBOmJv-y0}^|mY2r+IDxpE{}Q6$*>DqB0<|uY5Zu##JoL>ZasGUsr|t`g z{`;QsddPD(c2KT!eNBka56>8e;XpE+fUS22l>`V%{1u$ofit7UBnZX@DcX&^E>gAH zgT*p@_$|i`WN(yROtO}(KKNmZ!GJD-q)j>yY*y$>#nCP5g9w{)vnKPRTb8@PEGj-< ztgmiPXwZ6=cd?C8sCBg}sox3a?KG+xiG5lU*PGG zr)ex#AITAsDXgtZphH_-I|M{R|3B)HAA1~t0%{bZmc!8W3KHg089mtLve`;=@OX7a;~ zq-j{Lxn{a$^Ok#P4aPi>k$LiN@31pUrjv!mKAW8);RB1&1P{NMjm&H=3!M@r|AF#1 z#6C0L^cGc3PmG0SN?3I3@c5ic%*n7FoLd=;0TtFhc0JiQiVO1Hd0!+cnT>7DwzjK? zB1#$!f*HBxc5yEa{uH8CKhZ!kaQDk-ZV#>OpNyO6wHGH>vm!EaERt7tU@b=ogoU0X zE3PC(VoU{9M>LJJj~M$$dpN0aDbz`)9$a;p?mk52!Kh6 z{NX1+A9t+!=TQkcd(aaYpf{KLvSSSxu_sjhWuZor7?Vo@ayghh^*fzs5Iy65P$lo} zcgEuoz3tVXv6wG0Ou5){7WZ%vA)_0^<5iZ(|HEMUOB8}q_?!ZmDLK^ttaW;KN<}^dIec{7W7YUskwEN4|FEWshOvkCeRq$xl!{ zp-zY4tQ1o-*BdDt0z5pBIa?qE_Ck|9&;yy9o$0seXxY`nlyiL?YZw*^;jFSfs>{@( zwz&OjY1%!sXvWU82%@Kj&{FBR*mu=5aec^<>25Tu*d`V`97u7APK(+IKJa%mR7r4^ z;(zd)$y+`s!ENFLjjqSWG$MeWUztpJN(wAE1CsQS=n%@0L=k;I@h3CEcM8;{D%w=i zA$r?13z_?tfccij+!qNfE;|TFTxbO6-k_}yJ=sX+xE~_eMHk>~GI9#q{EdZiK|rXL zW@iTuRt|!wF+P{ce@a8z3BGpr#C*nZF`>!B=kZF%`Lh~#tL^_vXY|r@lQSu364gr=x zp6-m%NLSwM{O0IYmC@GePWw||0CAj z5dll3HS1dG8Y|>e1czmk`NC1P+@;FBPTClKl|1;s9xH zL#3%>^w0{MmHgZoJ?~2{4ZsV`GlXIj#(4_UzYN6k!lt<1Kri2g@bNh))N|j|2<5_E zF6vM%apFCE(Q(fEn3s&|r2fg8k8I73;Tz>0E9d8L8OFe?8;1s!9-#vnn_& zVgTI`@tiompbbCxR|FgNT+w0H5aL+OHSIduI?djOGl+@Z`MpyPk|pR&RWIKM9SyC# zjY<2ZI7?AXbk@2VKfyk!?Ix2L^K9QS`1}jBjZ$%MQNz2>Nh-q zU5aS<{Y#KTGvM`&(am*TgRP9F09lcyqbRHX^+7(9i=0KIEAo38IVCd3jGGZQ?ma%| zlPY(}+G7_cIKG(VlmAVCi&%Vy_m?lqQ{t#k%l6abxT}Ka`d@2~!^Pz-wKx9Y7Xt*O zAF+RZ@1p0%w`ZOvfeVHrl;2`uCnu)TKUC=If+O{!?$@saL!1^9J+}fBp^XJm!>B~t zIX9cl4GJ$qZc!#*zdlf04-dwY&xF{pL(maGl=BNRa^jNNxfK&D={d>&l!0{aBUTf) zna^bFiOAr^TV4C^O^#ymeK6z{6e6x&9>ReFLA$RP9X6mpF)b!eUt9pEg+3CwK3O;| zZ!@>7@B-mL3_Jp^$J87Mh(iVOo+`bR{OL>~xH#V*PCY6F;C+i95Oz^Bth zNYQ>nO9l{xKhK%y@Qmwc^y`c|E|CS-p`jI)T$P311`ZRNz)Bn>IFd$`z~V3%s}v%=WSPaN9*HN3)H{=aL4K- zhRAKwgQMQ}_w2pti&n<)D5XDtsKzJKY6opbn_XaAP}c~pJa@Gm9?zDN9X311Zx|wE zYmJ03RY}EYtAPNMEd>}!Z~#Hy)F>)vX_E*2{o7X+4uIu2fLsJHoB|5f*Vmeqhd=|M z27xfZ&cF3vqa4tPH>^<9+$JGb2JENxxQK0wS_g{daaxI+k)0KyJBgz!ACK*JuQu2l zmgtGefP(95f<|Z1J<%h?2eDXVfVa>{_#kni9WMPNGKlHld^7?BOD!Gs;GczTxK>sVLcGk&Xm%ko40$A zloRNL>O?BQCk;`frDPe+r2@7F*wm{ML|<;~TjTqVEgm!BM1Fn7Ms%4B!q2*jaScrF zjCf4OFkr#&Yut{uz0krppUTBO;_lhe@N=;{@Plae~x0bxx3QVKS&%g@OGpiG=1y=^%_F`GfK_|DhJm%h zr;%yHOeA*mv0sB48|;}79mkJr9R}EX6WiG9MUzlPoJ^$S{|0l;=9MR?iGiE&QU)EG zI-Qmu%?DQ(-+fsAAk_wSzt7*he3b>#$-kd**_yM2xb6Wll*wQj^Ro!#U=9j&WQudD zm9KMLPN_mQZI~kz)zJH>hmQ?bP&}ShGXv)*>fBc0%M^{AFiOVR7=PHz7bWhknQOA} zvZ8|zq$}@XhYSgQV~YyAT~Bsw34Y#3G-$&+hU3Iz)f@Ji*D_zCi`W{!D8_F>8oXAI zdRc}5{&`hXRcIG+|9agnhWn?7*oidAR`nz5fazPblz5w}Kp?whb3 zt43Lj2s9>DssTFoyowDKx(ay{KUMDAq6E>-R_S82-;JBPFz_l>rZN4!V0`6LJPOEx zBo_~J$zgpG3z1kcMHK%bfj`R(>uYG@^G>P$-pC@GPb6LgKyd=3KlT^J=XFWwEd? zi&@hnr0@@;MBHFg%JKcgdWG_Sq-DnMF(H_1jV_l&G%6hWm=(ky#EK0cQ7n@2X+-{B95%(10lT3`C(Z5iacsN_9;&-aqgu<)e7ErAD??P?2s zb9g%PnFCm%)cWj}V?taDya6`d-6cQqHy{Q3sfQKgeAW%oXTmq2nk>p%^ob{EY*A@p zueEBgj$}df5prX)ZS&zeS@nay&i^r5c$=rjE>NN@*6fhCWBg_ReFvz@EAc=|U5x#p#8#PTGSxhwy@j}$l&0JHH8y?RUMf=fOB0Uz5J+xyR0$cIwC(=<5yDj0zJV#@$U}=038@k@ z{nyg5{nFv2ex&#sNZRh@Ri`I;u*aPhK|>~>YDiu8N|yVP_IML#rYx@f=Dz9h*dbmY zI1r(DH+oV^Nd$sIMkT=u1A<6*u$+wiWv09*HL~JNfA#9Vn{O{&vJ;n2$y!ww+;k`1 zbTR+|TAiH%JvATNXn>PfZEmYs6TY@#dC^!{a$)KQ&Ujt^kxBqea7(*C&&pVK*}<82FKPIVFsJo0SFhqn%a>J_pzyo z)Jg}W3J2NDSOwBodBM=)B{A2m3@==1Ip#Wh887m)b)Pm6TT{ikEdNj}X7ug2$W#-fBS2-3^k=zyUZ*m@EeqGsj z^`r2&pRNIKQ%vk>U5(!Z(10e-Y+Rr9k>cQW4&y0wBMc=YuC|9H$^cY_IjDZjpJZ1e z5o3?c2XDpG@LL#LsTO?6z+$HN$Fk4)litI2)y(E(>3SJy-KVjSkC^v+w+Sj!G!&fA zGOR#AlPOOGt*psiDMw1>&r$E1Lsy;l-#(qod89HJ+$f>`nH@%?zxh^v4CJ#o$hVjq zhFq+sg|U4#8Z#i3+9pm}9`S6;n{5NyQNITUN2<$%qk->jB1`UjqW(QNXr#P(QrEE_ zIrv0Wq(*bnHsSaUI;*Vp8O+;gR!3W&uJzMEqiC^(!2Yx)6IKpx)7i!tq?radzj##n zw&c#?dmmu6$yvtrTPVoRbvwm~ za?@Nl-z}h`R~dA$I^?I^aSZ5Gd%aPM@20G-Wwn zVEzZHKvloy9XY0KGJSgYfJdM#EqK~f$$BKpuv@q^Hxc&e{)6~m<;g&ek-H~VMy+c2 z4dfpM1KM|ZTu{lAX zHGPj|>$-SwaqLltb@YDzHY6cJ*9ySKn)suhPu;&^GoK>epWHP1aIW&Plc}}@_os-y z72N-~-~K3<;m_5yko(0V;DseP)aH8RF~^n%<6m~}StSYZoLQlva@Mp1(xyY0v}lVw z0+0&+NrmD%G7Ks1-`x@*ftYaDn{Amt8Q)PYJaz=y+JTHhoYTrK6#YTG+;M+~|E9tE zKfSWYQkM4raS}jsa`N@y{FCsIoNc#nmO6eye6~z{W3&Fk!z;8+YhslppWKm1%|goU z=NpVX_2G)Mk^nSsQ_TITFl3|^NDMp!)cqCrzaHElq;txY87e1yMR0%HXpH{^VFo1? z4w64G;LMyv0JF0wi){CTy}HFh!iM9Fq%4{8_BP2(D!E-5o2kx)mVd4}SiE$(1cCdv zh7mL$&%adgYFKce+7KHj0lM5ifk?+dQ)T(E4@zpmn{T*ML_2JYY7 zma~s_+181}NcNd&>#lJNUnBwzlD+%($?w=A+8@5^iY(lYus(LTWywOH2BD(WKQjxy zf8zwM6Y=@U!ZOwDK!3?avXBBGkriV;jzA@uogi=C*AN?E!mi;t{;0mI;vd~-t5>g= z7)U^kKmhm&z=kK>DL5-T7b^*K6(Qih0wsu}$zU0U9|Y=s8v7WgW4{B&_E&}^K*B`i z2l2w8`6Lth(RV81Q~qNz)Dov)9JGucJ-QZL+5xZ?_@do>Fud#|M~}0xqX}Y8? z%9D>Tg=HGIq4{cENYfWDT_GVL1Ro6@B)ySw*TUz*vyuRuPE3}=M^0gJRjiy%wJm}4 zrcuVEaGC-!AE{UqnM40H^u@(w>hHa{&a!>eX%!(?h%XK`Z9gGcg8SD2as$ZFtRL3wbG022 zk%c1v$)h=vfvi1vjnbs0k6Z}SKPr zLx+y2wph2cLL$-|7V8!*nyXY{@i8C(WZx?Ck2~^mTs8tgPQSHxCrPdw1}hn+1i+}M z28U`C;Knz*kZ2U&@uH6cE(S+jdBw2KD5!=1n9A?od7!3p4rFjtG$s zZJJ^Sqb!L&885r`9hD-L(ahHNsZrDd4FF&({@y`pA z#;L~jB)N7dEM)c=?>GYd#v7ioy+E)TuY3eafFS~TE=j1#{paZv#d@yqkHu2sTROE< zWX>SO90C!-ApL=md^)ykCLP)~mBYtQ$--qDB`GBhs}Sv^0T2!fLzK!2kl3Rl@!vpx zFeSIh55$F_re_0DpNNWzA_Zr`4n?WgL2Y;*2;Q5>O`hfsw%MOU2?Rb2fz&X#OP4OI z5DW7fq~oOybv*iMCop06RWgnAitjnE-*G1 z=pO+p>kq!lEIe3Lf|!5$_*uyPqoMmV8xZR@XyPM%2M1w6%2D}t)@wt+(Dhs)|!aeX|3OCjQ$!gT4QD5_x)5FZeMCp&cL@I!QT zG`3&%yi{uffP{(nfx-Ca6@Ah>n=SiyWBVu%I6oVqvB}RD;=DHqW+9|C zgYnN$Bgy?w94X}fc-7?o11_s2M~@wqALsmxbkO6G5w@k%cuG5QcA zhC$=7w z>77K_8Z_qF^2@A)`ih0oFvfWPD0B_f3WTc-fW=&YA#nZG!zQ29ISGK|{@luoOMa>Q zUxekkT=DnGYtyAi_X|{Bd$U=i5o^wzpRh&NT}1{Q$9hazJ#XG0vTgg$qJ=8t{trEP zzuIGdEA|oGzcX9q9aM4uT=vUBIg}3D56THx!n1<>#S5Y@mNdzkfPBfxPsX@`KpN)5 z2b|Oo;xr;0#TzlsimK#F8ay1&uE>{#$E@=D0B`A8ANv%5&_SZEvO?9UQKN>i`uoV1 z(}{9PlZG%_;{5>mQjy)~BwTs>AR!!vRX-Y^1ne)s^Z6i#f!JXs3@ORNuzT=n?2~Av zkr0oci16PRKy;bS*GTtOo(BZ-s^lKL*Bv|>ZLT7r{`GXrjg3H1jFA8n7jtACJr!eIeIA7`t{UZfEmvP z8H)VAK3Hf234oFSb^b>1`*X=JSN$=PF8Ts+zT9`;Jud4|B)#K~Td*_DHbnrKOru@9HbUuu((BUSkmv*76p1sj>Mu7h zqX-a;Mri{G!sZSu@K>#+y=E{9tyyTJYUeY84gaGPJRd@r%iF6~OA37c!9eI8 z35l{D1mPr-r+_45Z-ii}i%d$9QBe{S91O!BpB;f(AP_r~QzSJsK+?UC#ToB))Ezgg zM4u`rp)q+LeiP})^&#%-kV5gZRK{=LGUEcmagR#=X@9}haUsGN0WzdSt05`U=72G% zYp(FYXqVSfw=bmUkC!iBen)As1J#lMz)IQ=4{;Zs#dOw57z+wC>x>V#SCnFEY@-wn7rR{(OM=4Uy{Gk^3vZKazhi+fOYZ##`@xCY?KVP@7Gfwa*y-A7;-% zkgGSf7j-0*|$B%#{EI4(z6&c&M9z~ z0EqZ>1+rMc?T;n@30uK&s4=t+fP(M?}JN_q^tRPKd= zv}1?1(zIz4wIeU>Dnw9{Kbsu~o(>QV<|<4|PKIjWh5ZhjtN8&Osc%pJL4Q|^dWiT$ z%rYXs>IV1l#hJpd{WuK7hlFBXzka>`*I$1LjCq2@HWtJODB@qcc5Ug{v7>(X-FHj> z{{2Y^@JOzoiFkvtkL=sGFO82g?fY{)c7`m+8t3^p=FJO~?>C75SGsyiAg5*7pV9g| zFRazd!u|Ou^!e9|=nMeyQ{q2G{|he(Quspde`t3O7Std^FJ63j9WQz1%a$!<#j-y^ z5W;2R*m&8wAxlXkxq0cx`B!?>s73RUq|6<%FYdEKNuiWi3cXk>$dmkf?Im;2QFo+CJ=i>bND$rvU!qFo@Am{em%&?|-Y{`PC z$A{7+Ei(>4?3&86VT%5F1*vlU%rE%G>GEJgs22DjS7E|I3I6%t60qtc+kG@7!ftr< ztS)2!Dv*n2<;fGv@?}drL}6SC#JGqcm0gImM0D=<6BSio#Y8YgIrkJKhvzj{K+p5M zPR~GT$ZyOP?;+8^`_N(JvyuSt8C~^J5zkNL1n_DL7A(+*3>jj%;f5Qu)vH$*AwR>x z8#QSot=n7x`$e&5k8t+F3omGc1`V>zoHpTE!ri?*) z>gS#xEBlZr)Ui;vOUK3&jQG2Cb!`04_CF z)kr1$Qvp0~ki9%z5?mM+PHmcD)4s4VzDabCOn z>Z=vvJKjvh@7%SYv~Js7+IQ^ZG|wA1ZiI??kM{J_PczWS>AHP;AZT}O+O)~`vh6Pv z9#<IS+OdfjZK_&VR9(=J1{awCdCGO`c zJYTg|;K2vS$Zx;SRyw|Me>|eyxa#dG>{nkKn{OQ0l_R@0LsuvFNB`+u^N%oC5-eAR zqW{_K0}`LQ3P9!Z{kpo{b{>6E8t~sf8@~~7H1uWFzaj?g8Xsgnm*vN;viz8jM6I1F zy?u_!MVAhh{{8xbfHlLeIkkAJ;=1m*v-^Qm&Q&5DqXWH>Q6L)z-or@uzUrh^797^4 zmQTJ+8tQAU9f_BW;tJ*}Vq_c#3bz8YPMtbcr??**8*AFMH#{2kqMCsjP<`PZ5VaH> z&?Dqn#*ZJbU2wq#NG*RS34xQi$Y%mW>E5bUtIoLBbQ|(&LjVfn{h!8wm2Ttsu>4IP zHT#Rbl7eNf##(-}dalkf?q5MGTB3`O`ThXAD%j`bfn2rKH&u*?IzHHPJ6ICWB+A!F zOEq!ayYLPabJ$Eot1VctM3ygGgv65vRT7V8GFck3RayvTfTow@q{2a6 zak3$Qt>7>)j0V^VDN&M>POEm_e*10hnrp7HaLq#2 zVd!)u0vMBCr?prIJ}g1Y-&Z>J9&8h~1DTL#emP5pJvVIFK-#ovg`lSPYGG9K=1tW? zDd^Tp+~)HUND1UryZBuUv=qM`237cz_)4P3`}rY9RiDE4a-s95XQa#N_yjp}^r-B@ zmfwuC*uQVT#3Uq3%7|G=5!4E8fU7E6iH`h3<&b{|dGUp@+9y+IYL^V|r{8wlNa@@6 zLK*_gO$-XhsP0Epo<4i_Y#sW#1?p|#)42a4vhUil1~!0JSjK!-Vq=b|8zLg336Od03F zz9GkBA``p;0joa-5$J9UB%;h^UqBRcx*+rZ&Y#4RbX3^`XcJ(eul*pr8hf!X0^=ok zo`}!gj~X_J!oGct)t1_H>(#AON5Zj3A~)R(z;bH3|GY?43lZDCOA-m%1M>5clL39u zgOZ$-toA27dGeG*N1uetEE;hdr?5baYyZ=gIzj@$F?eB4eNzr#J#9O>1&W)71Ym75 zMEo{Rmqg?YnEKfaZN`jg(z9nT?Zz8#)Q1ioD%iHGh!_;!=p-Ew;ZYRA^8jo3l{@eI z@4rXBh~KriIJ$DnRx&cq%Kp8Zi*8~cEg{AGB4H)xfog&;SEUt}Wy_W!iWIga7X@?C z3U+`%tQyR8tWqrq03w!d0aB@S-i`z0Z^Fgqb#eOozfK{9x9mVq1DS2rpG{5TJFD9O zMl8IxtaMw{AB}(%!-s(T*9LJIKk-|opAR2?nc0v4%ng;FnLFPyk>?NJ|0p9y+=P{Z zBZZlLhh27wN*Tsrm6yjpui7B@|IY^>%FQ=l5C3)pwYMNQ1?2{$L~JhlVa|Vd+#iCj zoJjfuuDN80{-rN5HXXdHldxO(#B3FxL(3$${nbF2?2es~bGI?8*)F|%J9b7}C!A|HM4-o3JD(IQ!~ zVuj-NeAk|qz@T8jLrVlXg)6D(Y)YcUoII>Jy=p_vtlE5CMw+Az>C7dR-`V_p=I#Ump8{0#KtZes9~pLmD6ojX40GfBq@x zy^Yl6HEY&G)SoQVrhg$9bnPsUKmMp%1xUaou&}ILxe8l=9hB+QK32aO^Ur+-$^9vr z*aClSbyWq2e;P#p9Q_{~dEBx2-whqwbvB=28jR_=QbPD10`%+lvnQ z+&08?CfY<0a&z!Zr3L^_QH(cK)C2`I6cR}M$3K3E@QjZ0sDMa$$L)lblCbYEx88nG zclwLZ@pZ_%zztyhp?`Bsz!V_%h7B9|(I!loptf?u@^6hc4!UtU4oW?gII!4V4($N(E0$(x zP^7&Hs}20v3vQ5l}<`9LGh1 zaO8+hA9uV~-rqq%q0*sKUr0p0O3JZsCom`kuE74XVeLXlJQ<4Xlk=Mu?w|w$pn(8z zLTzGhVMWX_R}6Z=5NZ0NigXvVhAaCV{gdSW7$gVoL;!deT;KZRm;11~syw5i@edn& z`ZD3Ct$DV|4L$d6%@QuWG1S7KU<*=xhk~M~sbrsHMn9q`y?w6~{l1?y69Fpq3P)mx^?R!1NvWRf15g9y?QNFf*n}&GfMql3fV#@;IEhq~!aSe#>48aHkv@d*37&&FmSIk`vx zLZgI9fzXSLK1s0ruRtAVaoXgTb2>$??t6G85Qi%fO~wS^%!72GLxlcE6d;)QsjV0) zalx+Oz3A`;$Md{INh;;8cM0)of zCUxpIRJU-g01zBtR>ky0q{yWj&#vTt%jx1B~%wkGX;&^38 z^z)}ACrBiMdyHV8l6NZ$zH*WBd`3Fd#;kNj5Hd4TB|bJv=VT$>*Hn4r;rrpgE?$6P-}cwvd?zz!ej{DFbWp~?Hf>tU=zl+qAea!9d3N}f zm)loY$D1G-tX{oN7XHZvJ6P}kdzy+lVCr!ey8eg=Ab9Gx<3AFBc8W*T&AE z1VUF3)<~%WS~fNkrO^-{cbwT>S7o_IB6IY}Zi$Gjuin2iFNEQjUKhAOSs3`Uaou9f zS)_^tBr#wp@THetN&;ZYNY#xZYYV@fzN&-(96Wf?56C~vX*7i=@V+dE_9g3E*T+Nm zFOSYk%859Cto(DH)Z$*r{d-*$C{0@VAkpVf%C~&mt>%lT7~1>C9}AEWWQwxlCnlaj znDBS<#FNjdnEzMc>o;>veK77r8G7kpB_*6jn(y_?(v>}fgo%28R(6siQpKYxJ|gmS zp-+6;+Vjf&)d&>Vj1lkny^_}yMolgmwl5feK`3-kgKgVi!!Z$_zIw(6L`FoYu;DIU zI>MjcL0V!FRDG=U3j^WwN3_jBI4E}n)~hFw#Y+FH1QDnqgvM8rNy zD_jEY6~9mNT3l2D|G|0@+W`N2tvceB#cWDY7nD`r;dx8zpq$swB*x0&gWIK5n{H@< zQc$tJ%jb$Yc}ThbjOH06#E(&)c;X42;y>oA_(tO*CKRW05jU~C_*BWG(r2z@{R;U7 zqeT>Slji1QCKzb4=-2;m?>YdZso$tRWmf}L#G9c|Y7rV548~S1I z^uzQ1*4^JLmtRk#ACAxItW*+YpC+63Cx9kq%{MNIzeUY@Vn?s5)a_GMN-MPt9EZlj zefsDl#{lRD!0frBTdqQvU9kOlmaIR=V&}Tc^DDVACQD%;5SMnv075_l)ivwnf3xQ( zpA6boa4(q#I$oVJe}MCd%w2C>_U{NNNhe%_u=&r6tE~*4Ct-8#gS+ zyj4l>zC(c!;}sV~L_j})^=m1-v@YYvkC#c4CSeM>oBa#sPs7|UMF@M_N?HT~AZTGK zSirXEvR}tZ3G#MU7(dU>)*5s6H>V*M*?s~QCHWs0Cp|NwW#-IJk!hw_{sLQYtHSwx z^s%R4+WDmlP;uAaZ&N<}e3n?6UVWruzUA5HUQ$BAAwveqt{pWpZ%!Gq{!;iz>R$|( z-(b{#tK^q0!t>sBb8|SWpsI^z;%vVu^zBBYf72!)YTf@NV%Wt}o0{Rx1rT^aIq6nQ zpr<0IJFFv5IR02U`Q!;;O@~l2ttcA(^NAdoM8&h%9ed1YIPd&((YAWPC8srf_+hZy zKU}WA_G+2?(=Un}`{kG4(H9^s#0T^(v|5bF-v||F1!NZ3_Nce6;2z}}iW|V?2uR&Y zgwT53BhCFKd&@eQGUs4lby9K&p7HbZx2y46waq}MPe1)M;}_UbfAt#X{hf@A3?J{V z`WjmV0bt>I$d1IPpKUc(hT*-9f?X9@h=vQ72oTEgCz{?-R$LKU#=6FU3ZJN`zf+$2 z&kKm-cPXT-$@Mei@r}0ov=8|B;}2!pw6|o!#4}_P%zlqLY7Byaej*P)e80!juCFUs zt`-UmKmFtbb>YXaaGuRamL50tFD~Dz`bT77Rd{_nB>%NKqZ4^E~bNX{;q} zE~1dXEy7bc$+48~5UqTd7>NLOPdNa7859nx!s8=k5s)z$9@cj5o6Y(`FTm~FvVyij zdC5yJy=1_=*B1CO?+yU}2ISRvH&BHwf&kDV+GW;aA-Vf~(X7#-6JoE&MQT+Quy})& zUPB5u2NQl!24IH(=|q!{?z^31Al~6 zRPU7h(mw(G-qfG6LMF?kH6Umsz{eVanElw(PfEw5HvK9IU*0ZdC*F&*GT45~1CWj^ z1L?b-``|4(eAFn#-V-Qk9t-)7`px;Lxo;kVdS+&AQo&J}GA%c6mlQ#;$0$EU5EKMv zV2($QJRHbmgtED3J;4wG$Hw)hZve|N5crWAjOTkB3WqUZUNMJ{ckS9WKR|UZ z=g2@0G{-%7iIt***hS)}bj6U2F5MEe3$7Swy!qU6trFgU-1Pj1A3P$^m)|8b!gnA1 zK*1S=@%R2VRKwRInBaVDMp{SWfd^mo*?AHPDN$~=?$3#|TN-;GUYivZy8 zlMBJ0Q!n+Q{;nqYE~#apI_f&p1Yd{*qSt>17J7qJ4xcR5u%FkX5vX!VZ#jPaP#`l` z2rlkN%1SnG&Vifo3Pe6$Br8{~5!$K~p^`o4dU4!p9o>t^_n1QM9}xJ#aXBy--_4yn_swAa=UDf8LGX|ENMNu4{p<}4?uW%(n?#cp zi+5>jSLDmC+zP19s?Ylij*IFC(J)RfSdAxyfxDH-HR|j5FBs-)sV526vGm-m6X1H`;zkO#~pW^E!)qo zV$OMg2Q(+gAvE}^VBK$#BS5!q-3oxAe#OQh0`Ti2FY)@|LsPWDhmxAJxSpeDV0oES zN=p@aG41}+od|>r!SXFD*V-Z_3Eka z`Tj$ef53qLDz6{?&7Xr%@9cB`A|nnTrl{H*ue*HuJ>SdB+$5iV`lY=0?(6FEPv4ZF zf1cDoh~ys}%#Px@0rmbaUWl-0p2t0V(2UfV5GPRs0^t6O;CCP}tNq!Kel*3i6DLlDmg;$2X@${(Ozp1^(GMHs15sZI0Y+ z(D|}fi$c{?Ji=Xr!;`Gc&C0Qd6w0bhpZ>9oACI6B5MWVv{nV3>2+y$RoqsW60Zviw zm%i^k_rl9?2Og>fW5ozC`qMY1*wj3#Adm;n{uMza|2+HW@$4TU&Y$V9QVWyN7AY7D zrT>6)r0Z&m9&mmjTEKX!;fUl!t^%67u3fzZwijQ?b=O_1jt~uPiAM|C65Mk04T=+a z@LvxA0U&V-0-Lb^b$bh2jKHrp4dg?-?lK69+A9V@cH?5?Xodl&u0NQxA9WD;HONE$ z1?|g+c6It*Z(a$KZ)+aE5!v)dEY8=U7NPNm9`6z>yN|(KWBlf43X>hGD~NS(|`K(rET4HU}kTVp?K z0Fb4{`8eL~fCXTYI(suHDiPgFFTV_J%Itb!UIQE9{7^`E!}V9o)T^dQbv`(ND$Fl2 zj%QK7>j?p12}HtAMCJKLvwmj~5`_9P?zrO)`pj^X+io28m2iY3>vNAh^2om%(yuhW#%qa<<(L1Js(>Tr z>4MpX0#WOj7{qx?SqUxyy6PaRJt7ertI&bO%HLHWuOr=BV|_w6ZUPZ46d$*SPE&z2KUJQc2&hr(K`eciL>msehUU1<`IKjBza{|{e6=d4_gT}eKx zs_pguq&74OKK<;`GV<^dO6pBXxE;da7^tRVq0>sRF`IpCjh{qjYRT0gaJ0i@xW-L@ zbQK!)FzzC43igB|lM5KoFGG$#99klLuP>NTA_QMEVe~0BHmU9ySpR&}ej7P*Bm~Ew z8Z&3k)Q1io8Vc3tJb;;1aS8v8uw~brciwpo27ZpBaXeMij-TxG8Z7#mz+|W5Ony23 z#$Z!;K^c&tFN&_~1=)WD_%LN-b=U2_5U(!$r9cinB3;fs=S&s0`}9*!hI-Itbio z+W**T_K!nj0@9HqhREn6o{%4Z`dL1Q+3|9)y`?yIIKW0Q!G#Mqy56GSIuc~7^KzRu zE`M>ezWwc!Vxr>W5~bElPG)51dgRd1vC_@CTOxtogKOef0>AHZ3hhKe4$vkx5h`cO zWtz4O88Sq!zy5mTqKhsvaMYwfKT9yG&wW5`KnY|UcY;%RVNZJ1Di8n%0HC6thd#5P zB6Ch}_zE0`YlAV?e)u~Ge}nOx`J4E7T_L|fBO6B9i3rhZkO@T>&EEx`b(9MJ@$P%m z<>_ahm)mZ=sjgn%F9Z7b6aHBhMg!v6pLXz-<;bD~!ylTP6H$~_Nf-mHv}en-;L4I4JV>u|SA9fo?%?Mr=i4X7EzYVV)L zB|~9S(1xl4t>%Nr!5&tJchuu_t)vJqC&A435t)4HmCBC&;)|%6 z481&u7y@6<`k#FB)yGPsz#M-$S@O|aSbF#B zg&-msGU@#Dk@O;0HfCn3*!wwKw@O)gnNpk8AlmKP^_$^0&v*eL3_egtTFX5*f+O%T zS3(t}_>mDQO0U1CT_pKPrHO*il4#X9Uii8^do&iGfV>ir2~;8~uXXSakB2S3Qrm>2 zo-%dnRO6IWPGLU6h5){z`m7d5!}norc`HJcZ?kBo!IxSk0`MILg&RPSwmcYx;=Knt zjk#Y}B3(FF*PBc5t&hJMYUz*JntVU(Cz){K@$&35kIRiW-iF-l%jM2HZc#Y_tll%P zQML5Y!%re}@au>X@S-|0WUi@_FW=h@!4atza_zz7H&~qi8t9!f1|~??92XfxIAV}#=q>mq{6`5Y&Hn9+pPVxSeGS~RYoHyVW`OnpKbEKghs?u-FLhyXlu9r)Hlc>py7)ritt1$%|yb{LV;rE3>C z_0&^f-h81kdh{p*NV-9Qk3J}>k8$T>&;9eU#~ypNp^|>zad`gTClCNTjKLR}Dml*q znBQ}tF3K;?macJwa7oRvdCTUrM&e|Uyz%VUaPduah3iJZ&s%T5TgHq%PA~ zL;0c8jFg3&kAXmFw@z2zDkQ0(xi9_Hcjh32?qj>4$JTLfWNtcS8$yb2Zt6e z)gDL#slJhv)UJ^IwPJyZASO`mPi3D=QH72f#)3rf*^7 z8?L{vOR?{B!G5C|Nn+ej&t)M3D2F;2@*2}0z^Wehk)DD)610g+QUX}^m9Y)DHZEkX zDQBh;BS*;@r=Ma>IPnA{Jw1&ZlF2(lW%X6_L>6olRDUK^(05Z-X4S7fxwg+B0I*QG z_5(Fw23)Dp!>*usqqI-zi$}S_-W1jMeX4?^%Erk<|N20#y{TA^8hf0Bj0psJ9RpTNHz@&0J_$F@rm=DQXY zCD7TQ!oQAbZDi1)*i1-z(wIV|l#*hkpbjV_gxj0yqrXdEx zP&w|{aRxj_jXr&Qa|bFu18Zcq6r^_7Z2~^OL2I!b$H506Czu}6i;Z|_pFseiYynq? z&Ow|v#@M4CyHM?R-^x|1W#Pib zDwQ{}d`fDH(h6{)W8s!rSy?OJepD=9fbC~?ArttS;Daf?0|7tRiY$MxgW@G2F%nq5 zL3@O+*A>bPPCjXZd^77?S-O0=3X@fLbD#KP0C7bkGgBvp08FllpVieh(yw1%Ir7M{ zq=b7s8t#TTFmw#bSj8RX-Xc-uxk}qot%Qw;dQ42gzq$g;K%_3?kt-=F5lLe^Nd^+3 zA`6r;9ID~|{SPugp$WLGQKjla9SvPn1^YlQ+p(t4;qQ50$eW95lPa?xJ+hG|3QBH=^;7#*n#l-KSKGa z4;nbY>s6JOd&@RiJikyD%ubN)Suxlc(5EWO&-O*B{YcS#5kLe&VR2I-X}jp|U=@A( z(=B<=3dcv6*S}slRc^fHRtO)F>MY37W6xS_zPC-_XA2w`S?nvPUaI^qD0kV@!mZE- z)IXXUBW3rG8sU5J#6PYz4vo7&ib{~4y{t?Hd4-W0sBjI|7RV_f5ync%irYf6Q-fR= zkbw#C>{f%=d(UxT%u1(^JzfN$|1ZY*G%Nx$J)dc=@B0!0u*IeXASYO8qFxpPUK!MH zG_D~M2oxNI&l3soowV2qQdKZQzJYe&tC{afN}4X6IwvB6Z5#j!65uk2?9Ppo;vMNy zTh>jYka9dKx*mL4hn2$*(@yE&PPX()m-2*IX^o;BXd;ef`$tnppolDMhrnEur$qGlvJOMfYr~zxIO^j zzY4Y9y5?@!s(xFbvU<2BuL0pAW|M6(jz6UbTqc>&p?(F41ge~_032mVzRBNMe%nf1 zH|T?mvnK44q9PI`J~~|z+w_oxHfcyS5)UCU>er~6t8a(zvF-}A!C;@Bzz>rx$?Mc! zvU_x<-7fxsIB+dHqnrG8*dW>`0Q452QJPpVVF*@Ui+B&wOw+*TV5HM*>va4vF6c%UJvHSH;1o}ov z0%g#y_RRbFnvN_9>TjT@-1J8FSe!y2%+ds1byze{d~_7=C? za)Z3{_G{7&1~g3#{N^Bd;;K7!0Rl#(n+HepiAI0A$h@NU%3ePoWB3wdyBySh1orV2 zQ0dJn zYFrPH1bV9I@(Nc;LR@EQ8{Z|UfH2tn68L${C{;#3)_@*Y3dB&~4eu%e?8sIw?`({f zueZj?sa>n&jP6x(P*N>q4zP;T!Cl}!{tv0}Y#Rj$HwB>E%AxN*`YNd@L=L~jGsJ<^ zSIqp|S_+RW6z&^Od(BbEh|%N%L5btHy>$rpLW}_#XAaTheN<7&4&Iz1*~B};ID?+ z==(44a?Jgl>Nscv=sgCCTvWQ*Jr4h25}!mtFxWPsn@S-@7Ciut2{<2lyVoExu63{v zY5=O?>p$H8&%LiTSWiShllTzFJ={ziz3JBG?y1A+2;o!6u1W{Gmi_Tk5KS@%>t;kV7GW zlS?@Y`u)obMV%ORBGxxW@N02j;e zU5#tW;q4XO9*CeT3}_NT33xR$V!%3Sc$8nXUICzY?e)JX2rO!sB!7+`A{B86MiB@J zn6Cj5up4pFy7Y+CrDtNTWZ=k;tsyBx2VF*fi`0a54*Xq(U0xCK_AF)??iiu=A6^ z%`jJe`}CI4NczF#9ZVb6wryMWOmngNcKv6r*qWjBrk^v!o|ZSM{4;trUs6G16qI}ne= zA_;M6>WIJwt&Ro+lH$^B0Dfk-2~I(4Vfoj#utY}wyhK*OCSYer#t_ zN;ZO?00ArDWUU-0$LD(8bKby#C}4Me@;=RZ>9GfsShzCxP#KY7DyuvtyF#cJ7YC0= zAU*>9o;vlIBW~y?@nbO!3Sk9!7TEu;NeCcsL;Zok%JBDHL)+Mwo^N#s;OL`|?g@5l z6gQVu0qkq}1-ZtP_bqVbtQa7P@kkWe`|oOlX95XqEu1Sqt+`G{^uAA$;|~H7Aa#yZ z7J)I*ZDH!U1!rYm^9Nd9JzCi?F&k!7|&VNW7TiP zeIT?|96V5l&tEN$vj)ibS_%*jo^B#L0Pl98yo~RJ3_b}GS(J^Wn5FL9E+BRyhB^i$ zXOHeH51oFZ^hk+SQFpc@4fn>(O_G_JCD~hYkj5(yiBn6II+3oqER;S(!zP{p-L`F# z@_y?AXBcMi?a`wfT$ekk>lE%0d6M;KKERd&diTKHeHY0sH*gd|2BBfG6smY)wYo>K z-VD6)``2H8y;m*s>N>EOzE}=^FSTvi3?%<&LHIWlz-G$3>YgJIGFSYC7hURD`DdjZ zJ>=gwBX`Coa~b9=&wfExZ+#1ET8rx)WLU2|rCSQU$Pfn}{}EV~n{F8bYJeMHl$SsN z>^d4CFePLIJRY=(P6m}jCLXk~t8g`9{4>s9;3+hZ9p%;AL3xnty=oiUtwa!#8>PHs zFL`D~wEVOaYAC9qn*$LL(ZQ0@QBfccWF^vJ_pT#pM!yb`a{F;z<-9{XsQImd5R791 z@>PF8wCXz9cv5ZtnMj!uKg6Lsf?GB=y&NO9dUW5y@O?AbpddTf-;U44U$ z?e~}@#rDF+tCoX%+$ixe>9Tn9Q%J6vC%>(`O9pmbF9W+=p=|ke1EI4V(aKXWzD)-h z?qtIzV7F?^3K5vsXy4DjhzL-0~g;7=Vb8eKpwV{nHfI(0#g@3dI2#i-en+g1#cohBBV>^l-(^0x6>T=}} zT`n6M1ryk4sf13<jM{nG0G{&cO?ApqF?cMUYb+<4rG5lBs4RK7ueUh_9O;-H76UHkyW?q{S; z!Wq7+EXcecY&_1j*)Ji>?kYK~=dIEkD9h)$FaQ3C+TyOr-gsX5QjCeVBK z!MsK!!yq3l<~7gfJiin8^UIdV#$E5LL?03O%{1TSM4}?$M1cKgDZ_N0$ZMQ8S;4|VT?y&r|BFYf{g^ulH{ z2~*vDvZcAXd2-t6=Q)ixLr zjxxC0)zZ7eX#ift)HhtdC^!^?>ty#xH8~bLv~a+q z))75>_T0X|&r01^YRQ4-;Z^`PMX}DIww1<(5Hz4GPbpR+Y_L$dFY2XlNAU7m}@{ubu@sOJG2N8{r z&qc9Y7_-0Xlaz1ppn=*)GyZEF*1rb?ZItFm;Ljl|aOVGQ{hbhQ&FTYflL32=9y$fNdV-?px_MbrNG867Do!SqTj>!X+T>yoE zyk|aR#YcnQ%C6Ey3ek9V+T%wx^x$-Uv7pYOZbI$GN9oK33mkZ(F@&jd#>JO)Tam1kdqhSd)11$dp z7eE23LMS?PPX;ZscdjvN|9nr{&3{sx7{6SyAirBtfIMzMXJol|m#>rUg}=auzl*eu z>kVL`^gl+@+l`TqZASp$cS;$g^VPM86;QlDvJ1Wkl`n<{p)(AKQm{eDA`=&}TgX`- z8LMmps5xj8odm=JYdX*h1^}T-5TRiZ&=Tr0u;rD`0@+slE#Bk%E((n=b%mRcRR8#6 zkC85&JA26h%!jByXGT~)2cHPRhD6-|B4sDfP+wqA)qU2*`3tr1`NTxTG*H%pp}w{M zJjc1hyc!@lmV*L!z_eVyfB*gWugsV+BlL;2tZm=8=)Xgox!>5(7lY;h4<@@ECYw+a zv>=?816-~lIg6xr{_9e+_(RPoL4XecJma-FK>;85BSD^rORWP=_2h7Qwx=ARPp7j$ z`KJP~DR8UAHP>-r8;%8Qw!JO8ikGNo39GSDsnVtWG14RTBuPme46iyQXhc1X7E3^9 zaUBr|c+_`StK&gTT&0W{7h^=g4`K20U$wVCz85C7{_MXw(5k9x`S<YVWci~o*2Kgl>53@Dg9Z*%A;9__)DPjZ+bHA^ z92sbcaGa`Apap-{?A8AB$uUy^2n36-{_u@$<^X5*F!tx)_n%P*9?4!s0I&qR8=L$- zP$C9M2nzh9_^N}O=NmOYJfYRD{swWcV9`b?Hlg2LP?@wrVvV+b#Ap!?H z6j;MSAea=}QwBls*FEI~#Uao+i1q+P2;0CZtl#mW!7G$4UYM zfiNtXUE!YZ)HwwR!*!Igdv1Te9!LW~1c3AZSx8v>$^JYCo@2A-g*=~Vg6}{4@I&O7 zF=HOaCclM5KN#>+q-9X}p1lZw|D;yC;uARC!>69C8vv!Q5QSh@YdsL}?~r7fe559W zhKk($j4lgSgQCZ{>;+0-4=``t|H-E0FJKsS1=2$g!)tum0ZYN-rAxb`6avV~{X(e? zDZS4xSth&i7rFHfWn7e+c(6hSDG5W=Z>kyzlulp(O4S*a2*ttE2> z|NF{ng#gU=52R1PH|Nfu^t&d32{##nd)0w7C-pn2nMS>E;lik4!-hQr%6|hUn3Hd} z0ICOM_ZhfC|KI)MoN{BIy%_!-7UE8tI_4J|>DwCz+bCm<#v092!$!bdYd z)jWaJYHFGB_vDi&A{$V(+LA%RwK2Ua2HOi{BU0DAVpx#tN0|8+ru zAHc27`Wt>Us^7UptNrsszyYBbRNoWuxhMesh;FeGbwr9dIw8-K$6iDo>$LEroUL@zAcMhOdGos<|{^187X=L+FitW3Pc%52+ zd|*Gl7&@tG#022Xe?M5+yMqD00kY(PVP?&oM>XfS z55Nwy41n*!>U*|L;O~Rb+{17tCt^@ch5G^GcEUIb9A3vUAJTJ?=RYvyl@ASs0)uP- z*Ia@H$_HG5LfXTOxO?gZ90iV4)SupiE(aqvf$zXD)y_gGs>lS=SS7p5)=3$hda7!6 zBLQfMoO$-~#;dP9MHLcIktP>Up5plUi@G&wNxNRbX3g9rb0 zuM9;Fdj2*GDPc;7WTg$@_XDXw|4#&9IcQvWz!7Z zT+2!4M3d@Al;-KxA6@6DT@2*wBjEE|44AYGvOVFV9oPnrYD%P>PMTPJI z^y@Q4o_W`hkG?fzcL}n?fN?OjVWjT#3~UpL%r7|W6A^TPoFEZC1rBfqWHC&c0Zy7Hy&vxi*V0Z=Lm!j%c^AF1J=p3VfU!!T9CraUWiZj`o54@4c z(b_k)oybHS3&xM3qX)u{(;G%2Iqe}B(YykRg)tCTKGYY z@)0Jx4`9J|GD-O*XNlo_{T$8Mw#)_mc2i8?Pl=YOF)-3$Oeas^=R1TWQvLv=VNWO@ zNJ|wt^O zHbN*^2%dm)A_yL9Bc%VqNHjjog#d7oNWwtMaAWoAwHhV#6g~yw1o%#K6e5Ab!riid z!v@G3j#2%Azq*fqsB-6@FJj<*o1%i^f&k|4 z5}Ea@A@6@B^2Z7T9)Yf-0f{3Cv^hbWLlBc zjhR#hI%VV5Tkq1|eSbRln6lop=}xm=W~QAhF1(KNbs<_|b3jE9pIRXm(8dwxZfTKY?j`%|dX)OY5I$n5A5d`n{4It^YgpHgX$;DXD?4m=rw;JsajQuRK0qdLtp=+w^5JRgYF+> z{X4<#{b=y*7T8-+d;&k^bpFWQsz%#uG&Rsb{ape?O?G{oFInrI@W+pqMTpe13cd!J zWwBCNQl)^H0L1WDqehL8nKRx+Zuk^ti}kCYz=c1WnCkQ9FVNn2^BwKePrqn3;h$dz z+!v?`7z-nz#~*z}`7XHnZ%EtZ1W8G4i?QtC1ll#+lGm}jDYOmX{YN{idb(V?&VG4Pq+oDH1GBQtPN=NTX8cfZ2xU<~#Y_*pOU z3x$QMF3d`D=O{U(pj?Kh)yQSIT#1Mr+xkwDEkkcKvNvT)&em=P{-7d`4UaQ?5!&yt$#Wd`q z>E#|H0ND9Y0Pv5;WLg6P&R`LhyY-q+{)R{u@Z`hqpaoUY+D}UYpjg-H0!~jjqE^nD z3lG|ydVuVIzyiR4-M+D9ffr&3_=@*U4Q{?#em=r;H>3XFyGid~q#%z;P58l`3SGh&+sKlanmvG8{M7fC%7+S+iyxaH>CZ-PJsJ z{%GiTI{JXB{0);yG;0Z};G!KhKR%`D*^7fq{MiB2qQ%3(r5_x8Y;cO|C-DgX2>7t< zQ-7r5jUiw}97F&f?@~)(Rg4|W`IzNct)BP1w(w8799s!9JfCXb??gU-ELflfnVv1x zApvj#CD4WP_r6lhzUJ>Ll3jU4O2C@dxkI2eBJk_b{Xc)+dFQq4g0%1?hd_?)d)U8! z|8X#KIogi;D;xjZwYu}C7vS)2%Zhn7K-yst5 z-3F99__mKB)NWk?uMr*s8rB%jq59G#%culJV=Y%GeB7`xQ)sE^+ZO^7&&#`V3nd?p z6IfR;Yz-Ud-X0nIT#W!LJGSqVl45X}C~4^(3JJ#vYUVzLLm8}XLSg+mJJ@ep8uWU;z~?!0+>-=)A^?6j_b5LDy@%U= zh0oJh#;k)6@H=7Lw{Q%_TSdz9&`jtg68lZD{%h8)-|Ol>-ysm_VX6%+29k%`2qOtp z}SBLwx=+9H8QM;oIb z&sTk0CC~;M4eyiE^Unl!eiHaC&i_W4FH3;u06a!np%}Y!G(;gYYr&0RMbp-iFakWY{*W7>fUvT%N+E%kLC!=QW)0$BM9zB3V zj91NAL`ORW++-4WE7hOZ!#+QPfg{iKBxbZ5;2)nS;3IH|A1LElqnMb&x8S8(r1vUE z!Wh2qi-de1_xQ~)Uo^>OLe17twr$^rZUmk*6WFOztE{L(I<_{-jhN~}QsBL1H(>UI z2#Fj?8T9)#?v!M_M;gRFb?=d`EdFe05~rPd|6OqVy%*mbuzGxT|16C{0HFSD0sLp$ zO|*)QwRMS6yYyp6$Y+1|{5sO$r`yoNrQ|_`1kG+)3H(F?=6w?(@V74*w1M69B1Rqi#JqI#Lo6<6vJOD-p_l z8*gA9L#@xZe&63_d%R9+Pxii~q)cfjlw1O{Z$85|>2cYkXIBPe!B2C6eQU*Xf`dbh zibs)z1~%y7!Wn230)QZC91uVTCYxa7SFi+{{>K~AQ0lM6!V@nQ2*6kRPq-oQ@Vedl z+HtddmsH+7?Xk!FgDY^I@DN|?3fj>@{f#mp06TcCfcs#Gg`2LZxY$^=a`j%f{tMJa z#v*X>&ViotzGnhmHL?pAK;ll78zUgaAOb664A8zIg09+@6X#ku{_C1n>&Yd6lhQlU zMkN5Bf28&VY_@Oqfjz?>RGdi9-rWqiHwOcLCj6WOqqXPwZn(H+piu|_W~Jw1A-tSl z%n7CBUn|~jIF}-jCj<3|T6q3%2e;WckaAB1zzv0%`!yR&RroJQdmH(H+IT+LfqRUC zLQ`1CzVHzOzo#sK*Uf@1>$$)d)p!sg#;uBhblcWHK?3}GFE&w!pMC(HJ-=gK9mltYty_Wc|0|?0+p1ev%x7i+ctdi~x4* z*wGOSJx(p4#WYelW~}t zWW#48QGw?c;57>Pe3#pl?V0W15w8N-gT5Uv+1=;Ep=vbT70>q;%oIpZq0AO>IbN}deH|! z`93WL`w0rJs5|!pz8mG(OiPQTc8hyAA$6|e4!rk@t5);;Z??g2XjYQ?F#ii_9~_R4<#lhe(YCa_(H>F0I>X< z2rNvj>UaKEZdcn^h`#v`9?(LcUM?SO{~6|+fT!=M6z9U-07mfXWbMIL@HnBh0e|j8 zE!5JJRi{6%xeX}rBlT}+LG`scz#7#U8r!uhY%123B*f~r_chJ&%{TuumMvQWme|vA z!TYJb{fn%6_wHSlTkzg)yD{yVR6i>#QyzcvQTgt>Z^eP|Y~v?Pq^mD!j^AEnJ7oQ# z^85<^D*tXwy9dHM4dMW@va*sfr(*)L|7-teNCi^!gsS@EEaUj*;Q1dWz_sg3#kmBb zd~q(U140137KO6~)q}o;aEjE}s_-Mw`QG)E^}ncxTt{stDgY9)E@&Wv{YOsAn$~8?gCXY@qOsc1|fiyl$1e00KKi*e{6c# zUsbQ31*uQNXMohdW-StNEZXe?Ku;jVGHZ$GDiMG$2S7%Hqo7cal%HpO-z~x4{IjGJ zxXuEKU%RnP9Rciwf2!>$L?DSnRAO$uz{T;(t8W^M7cUJM9z1XrO@G%3>3;?y6m?EZ zQ^K~UZ(+}CB;YfCK~+_yqV}&%ds&t)TcRqCi%$kO)ke}fb(E1K54T+fA^=GJzYnYY z0sc*iVU zewqzX#Yf<0@qHKd8937$VCx+;F}4yG^BJ7|Yk&aixDHos-v8p%L-t=wO6Q@(cJpD5 z90{O6e$G;ZY9RCGw#j~O>kX(SjWh``obN<;)=KZ0{CDK3`T5c0kM!Mku@#&Hsb z7UyvZ?SL5KR6fPAV~;S9_{38B4+6y_DxdqPwT!K`_M<@v0B6UMb^}q;|Ezh?pTq9o zE~$sz%Y>#1w|L%aKLXU0e8Bg8avB7FPo&`c3;`o#9Cyp*jqnDjQdRUl??2l!tXWqowYl(dPsUK4Zn=WzmccW%o66N+K;UQJ0Vj^m0}MSP z(m~0S?{HkyRFk{!zR&T)k3Y34)}MVP#XsllGnu!5v#qD3CL2gqu2Dq^qaKYqeF7L$ zn@0f1bZ|U07~)WQeNPJK#sqi*Jqt{7B@2SRg?}!Pxj+3Vix&L}xe47n>q|5!eq4Mz z#R0Gn>`$LQz2)em#;`+{onkxa^VbM~npa;__?y)Xgp2@SK+zi$n{Ki1fro*~YpV2` zEq@~VhgCCsc1;NYc?4+4CL~*5=u|cY%5J?1I%gOZDOIA`9X?Y8)_*aCj@(LtkPzR& zeXYAK6T}Vfc=p+s44nO273F8wN&VB(I?3giU#x(}Tt`~a!F3j1bS@9NufO`n@#0G_ z$$)+Xg#0tx=6Svtto^oa+mNSV z9Woj(mu1VB0s&;f+RtBK3%hC9O|*rDA)-R5;%bMEOlO{PssU#nJLx}<1+`H9&2YaM z{s=GwAtL~&u?9f~5Rb|AqkJ^dGzzzfo}UR4*~A!tXLdve(%PV2-@RrxFz!1T^f)O{ z1kfwF0+EO3``pO1K>HKkeU(92f40N-+aO9&_YvOpxcdOM)A85$q{Kmepur!@5k!J5(} z#Kp$J6gUP^-mr~0pV%6-=BofemzI>sE+k#pxpN03_jy9+qa8c8sfa{QC(mv6B|17* zVj=7!C*sL@@OyitJ3IgUvprYRt0Fi1zZ_Y9fAhK#{$V)-4M6~hTGoJzJpaqi)rOP< z;Ot|t*}We4I+mJQfdp#6kUa!J*=v>|#rRHWe`q6sI#fC_^L&p>+_5!_ce|c3uLtT0 zLV!Cu4v>hB2PyjJ`6z+^`|p1=ZoTa;)tD)x{XqUS8dsgle=6LSElQCSEoptWe&_Y%+andML^ z;w(wvXCd{bC823YKm@V8SgHMjp8H)jDCFZf=vbpRs*TtApTNI#>2l-Bt8c(ry1doc z`|+1E8iodVgUFF&;T$=31TjAy?pQ# zuQ8wD6_-!uO)jh-BI6i<#CAjXAC~@yxN;#OfX$mX(*UTqZJk&OW9JIjve-V<$Qz)} z3=$Ghhi_JmXN^20?f_-SPBO2mt)d~!w?YWGT(hPGQhyjLg+lpNEf^pSQXB(M_1bor z6S%3C=r`PWn`7tBol19I-)QUjRtdr1KW@EAjy!SgoarIJJVVBe8HGozbh$1hh9Q1=Ag1^-=c%EeAt3++|LB0t z-WfCRhjj^Pj+zSHnYW=)20#HjjCH2;-$5fF>ou=`odP}h@K?`=t1hMe_+3}fYe!ob z0;pM8jN<`--xER9J!tc#wniM?4wH!P!#M?>bKrPw+J6ybb0HH@*u30wm!SreQ%^Zb zZoTD(fKhVXJ=8z>q3L*)ReIMD{$)1uOH zfHJS+qj#I;nl;3ej&Pg;LmIH}0nh&gehB-V^9o#+e7=+&rxL~)sDX*G()SZLc;E-` zj#~VpjPS5YUhF?NZ*g&n{`NcXI~Z@jwH2!Th7KJp&pz|Gj{XHaGh-}{wQJWJ3lOz9 z0cN(ujkPsSsdh5*PL@w1BYbq4_b?K5WufFoU(Wzrc+jGBXpJ#phJ%WXn)^Rcs z0NS`HAU4cB2`+)3Qhpsd)?J^#&Wai0;(;CDZ+JPR8N z{CpQa?h%KcXXwdYy@Y?f_1o|BmD;N{ApinQ#||Cj&DUQxh72BPOEKAh76L2u^ZGmQ zeh8Ok&vhZNx}G6LCqRRYhvYtL0z2W=tix4P!~P}4<=ozL&t1^_C)px0Qh#s>vtS!A zyJ0PapZ0-R+X?Avdj~fRhRXImqvPBxZIUJWtfvia_$3+>gn%cs!{GkaqduztG`I=- z)y=1gc%a9xo`?ALTcPpsW&3?=G)a-~^+3OQY)NP@5o7*p)o&eczSw&Kjy-|uZiagb z_&auxx88ik7(IGKP~dlW!STqWPa7*&u7>5Jjj6QRR{*5dM3}dm`jbIaufFPXW5S8Y zTXLUl&&`>Z0RcP!ZAX~;H*gU`LIBw0R&jXhnlg5S1Mn=hPPoi=l<14zF^v8vz%LVG zTk?a9rrUtxpzS^Z-M8?}59c1m_HP5_4+i|c?}z%^Su2raE;5Xc{k*6@DPmb!nQYp; zMcJ~4T3vHKM_}pQyQfTh?FD1xh~XgtKe5+GAAM>(|H8`}Rcx)PxLE(e@{hakB+dad zV2yf+008`Ng8I*IP5s|j`Vy3UVd7yH?ntv6kcz`mw1cKVt^&%hfPeA_3i!#l@djwW zt{3N#4+vhc)(rmP=m7TLm$M-7!*b90Yrg2s3H&&|XzjX66#STVdRG$KA?v4nu054mP4z#t1|NA9?zzM~wFE z+nHO)uO{?a#ri{(>PP)gU%KjKbgvCE_3Xi0xr*8>mTZNzTpMju9fMbt6mN@{DxiEeOfNg-{t3(;R>4=f& z^ItWz0Vk?(EcMR=aGmh?FWZS{LZCEw#L>kkfF=Zd1bXKmu-%96ezO8U0LzhatT>LC zN-37bz%g!0#NGIZ2$fT$^G};ZJct-NnDALfS*89Q(J4?a_irr#aP;k z0+lL0Um?{yq4K-@(u-}+{hVb|f3W_uVSq)wf4DSq27+<`g@uKQfB|v=)=ktx`d00^j+s}0ZKh_2~!KR}=t46??Htj8K z`izfTCGcN;)fD;1Kkmekz;@XTiDSTk3vl$grB|d*WD_)cK2-B9K-@8y9a z6b_=Xv%w*f^*{LmL+g5&A0qRp)@TDSI9UIIh2GWdasaZ#pmvg+oGj;_dxmk{wO7f| zA%n?Eg+%quenXbStibxS&%NlQ@-v@knNMyR9;X2O#-oqiuVTvv;I6P8l@RuB?9F8@ z)8qZ8)u0Ffn~(XHB01^4g@CP9ml+b9Dv=Za4JH8cLh{DGg|EU`NFj@0$wEMMBYFYf zpmP2(nolhqd)U5z7wTK0{DJS#HMOy&x<(>KUMdksTn&+>KO!@$<%W%gD=f`ZH*MN% zUT*SF0zS|A>FJ&2jMGn%OE1017&LHzngsxe|2zlpf#b)yKO0$DTa;r>@W-3~2@Zo} zy#2Pn$vyx4dobW9vZck}>#+EHx%qpy|F;knTHp$b91?Nl+x<2i-~g=sZX@!r3k{=F zzj~pc#k}d;*Dy>A?pRq1x?ey}zKA~Y%KJ~pIp4VuI{r{3{V-dN7;p-c#7V8nNECEf z{ypTmzxQZ~I_qgL+C+E0>WBJQhyY?@q8;73b&>h=7c@)AZvuZ80RHW_|IIkz_~VT9 z^fazPgD8G|kL$nv{`()Og9chHUziPuF#sR9|DVRS*IcQz5rOa;fS+N$=Od^HS%1I% z*zzOV_j(W%QXnDbyju#qz>VwDwzD`!O=ehr+XW%XGIp*BOur?c1jhZ~^0kHhrNg z3{jZnl8Y}SRpgo1c78)?ohS``)nU2}6a4^4IF!no;2E;~GJqe#q;P4983-bggFGxgz5siVLAU)ky0Vn(B$C`65N@+SvGEX}S=aN{ z;rt$;%OJRsu>04yS4s6;$O}T1^urGzYTRvxk)EMNr1Umug8XWQ+B*I!<__|^ALd0|K&d>|b<3@6FlAWe7^qMT5gM7%oiTm8BWw2+(TjEm&WJ0U3bW>!EB=PV_cH}{QqlUv*E`>n1P@OfOPz4b{@A2Rl zfGB`0BFEn+(sx9Ifmd+mm*^x#`5nV9Z20@=AOMZj%yGi;#~94E6IyB5_;sj3Nj2>X zkOa@pTkyk@(?_OXG?h9>K%IfB_$;WQgB$k*63?4z^@P@N}Bb4`Q=P~?AXzY z`ghETnhpS_Q1uW-qGu6{x$h z2VbbJJLD3HIQBZ-K}U5}&_oS@1r~=qb=Vdh8??l9iN18YA%~tHNY`&x5uh@W6UQGf ziHMv_gb=8(o3%td4Jl|Dc}8sCAfRJiK7tqAOT&i`F9$-ZLO%+u;NRUp2UBVV13udZ zL%6|q&?iOld-due|9a*_ze$+7!;mJ;hlh1+>nhihF z$QcM3m>)rb<<-4tr-}=NPy3x|c7}^t>(q_y2s9aTOXkZqpFH<>IYOe(c@iFmF3z7% z^6+3(!d{@lZ8Ko?I#_D0(*TK{`h_9=#|NeS949t3A=`4SxTOysJkS_%_%Ib0z^X}J zGLOUYa)?k053V_do zoPF}b^G_OcW`C{UbmO&JYD!8-R3EPb-)RmUecsK@%{>{h{no1r!~Znf41^4p_uhN2 z4voNl2!eSsSi5i0BNGwW)Xu1bUQ30;KxQ>47cCO0Q6F9Og|(*+`wbNMHfvXE(o|t1_X|^ z@SD&XC&9lezjs-86r%DZw{7cp&+`JbK8Su`_6VJE6BPvYskrmgPd}ZEJOq#&hf8zMfGzOa zHH`Dv_YXe!;6$9w#^LPwBsOZH6>#u<0;REi6`X|{5C+VyVWrwbcAB%FHS}&sQf$FW z8e9HUfbLZV0TTu%5u+~$<^NRIlY3ac>-i2hBY=N7IG%ICg1!Tw`r2-cc#rn@#!!T< zVp0sdQg3_{6c$t!L;y)i3DUW98h=~8#1PmB*H@e4*(TnD!G(Q6Tsy61ZZ=KB;Fojr2idFM4ik84wL_;N@y&|n0>TFDJC z0K>x%KYSbDaEl#qkYwsv(A+5C^&_Ambc@&Yn9pvtjl{Z!+w zBB_wfn>U|h4a^F8RL{A_^G*cEN`K z>rmk8`sR5E3g~|?^eX@s3jIc0D-kE&VAKo!>T574DTAeH*J33^;Apo)rA9kn#0Uv?Hvr6?HeIb=4_21@s6LNrM=&PkBfc4OBvG{}KjlUT%1$26T zj%FYqoH)D_JT_=31pYyjBIv)j{bqCTUDy)@pur!0f?ZeD z`G3n2@Xv^vqj$j{&awuKbnN%De^sD@j$S88)I~3VeQ)D-Ch~rah{jQvt=InfwhIj< zbVg8;SB&V%@9BC{deHMeYEx%WP|gnk{O9)W-Mdbz?%5Kg((eHYtmFpvyl#Fc(6&oX zcKr9vR}CiPzPS+ZL9+njp-x-^>7vV)+uDA&2!jVoZz$f_rSxpg~^9 z%d5ihkG(PjmYX@0mSJ>~js+bVXhZ88<^d>qB*Y#ykXctx2OFO3uHI|k`Zr17Pd`$k zCr{J$_;y|rf6s@BXlj3Z37Uo-5-}W9|AwD*89fy&KNt@y*JO{Exgq%zXV51yGcyA^ zne>7K3ZAvg{(K+~*=`9WfeKz%=D%m1 zahm+|AAje>@z1J|io&eFnA#Y>f_vX#UHGnFgKPtS^bXkI8`ahJMn-0(&T1NPg;vn6 zR902`wdwgbDF5@|THqKGF0Ek(8jS#ufZ+(RksaL|&3i1^=#FX-qO8R@|C_9)dq3(( z5CTLX2KC##W`PK(>+f)wL|^u{uD9=OOT`uS-@XDT;bmI%)t?zrli$~kls>NKLty#Q z_adC{ufiGhR!}3C65D$uUca7r;)zc{!Dg6^P-VvVzV(z-cs>Xj z#;>S*Gx})@jDPvdc`C(sAOueQQCU%pln;!3=wFpmX?iqFQH%|P#HXmW;9@te@WG?~ z@YjaVfd8t7SO+lqs{ouS*l2!KN@xD3Ez1n&f6j-AKG{s)X80SgIf|hwB+E$k8TSUR ze5BW=dxzu31Kx!MydV>SNZX1Yp8~)q)w4h-zHdR82LaRyu>IEp=zj9P z9rzd6*PeLi2Oz(mR%7>k8^FMUQZS|?5QjEv)@*Ib(&e&a$4-jx6;Q>;$4R%YU1Z$2 zqm1*_3+o` zo`J~5Gyp+U5_G*|eK$m1UD)=<#y`MY!zc~sUjO0-b{%Z7BmxQ0d>8C!O*t|F4VI|O z-!p;&KPv^i8|{0OHW^lS0lw{G(<_b#fd4)Wnr;RK-QoL8u;1<4wc7;Xy8^;R1Q;2sBR5Wps$bfShoQhU9ipirHcae9HfbsSjocFZrpzA1}2zH3*A08q!vfq$RA-pq!Sg_VB-ZV+IsJG_)aXzJmcveX;143yn&3eeEyc2Tk_ht_8jh z-M9hicvXTpk`I$MSG=nmT?bg``mO6wsy%hwwZ8AZssw#tL32SF{|bQoOJjiFYytKG zb5PG@)K_XE74x3eC#Q*sf`tw_X=$CbUOjs_diLz*=+GfmvCXc#{@j#jeQXPWyikPGoEz)kvq0sXaGZ@s~&s`7_P04snSk(|+YE6YLmm~a$v z89$*d>D{X*Q+Qb-3?eRcq5{X0I?F}BPK7V*^%-as0ssJw$HpS};D-QsE;n{T{kM5J zbn+oG7&SO!rgoL6DK8qeT?g8p`5QAk1R4}(kNF&I_c)j{zhu?#hSm)SsZT*UF9H(C zV*{bS?*<%(@kLP|mH^{hAKSnSTOqTU+AD;JIJBn2m|sSFJfc}50p7drnyZZS&p*3f zb?I*4xB89%015s{L_t&-ZQ+;#zX}v)_w`+97iT~@hD(!xP~&p^@y8IES=ucS{xMhE zGcz+A%yqfD6#i(283=jfnr&xiXUBqFJ;nU(`>E7_8-7RlZX^K-CGreB__Wj>5`E<> zu+bkBGUfMe*W$NH^)~}(F1z^Ri_gN@eYM4NjlP8Az-KrPoC4}cBO%UZgXc4p##uK2 zavR2R0osITRcHlkH4A;4i`VTC09k+SnWrDsPdRylGGZcvBCuAJBN(ePUWx%8N1O!@ zW={dL3c^axrdAmhb?eea&N}Nf;0ccheY%Od7gJ5?b2eb$Q^JSf3xocp!R9ut~>3@kr1hH`enh0h0ZSm>5O?W(T9UExkOw9(O`WjukbOEBW zM*wK+8@s-SueZz$_^xcwUO=#PA@-6j`!5AsH9hlBO-MBY6#{?vgF*RU(~Zs|v`KTE zc(4q|mgj(Aj>pl(*2X_jg+v+v&{t5W?|jw0MkIjx8MH&2@xhzM;lmGB_s9*v+XxiC z8p1#b1SxdICx2H}y1b4fBBJCU|96Kmb?T*f+*%mJ@nBwZfQ&<=40T-#e`)3!u-z0^ z?Lzp}6Gj{hu(?yX+P=@|xFNrNU^w5qLz5`#`E81`04yl?*yfI$aWK`2+Af9es%cuoVM2Y?w7`*80}uN{Tahdr;sJFqu9INZ@evw+H@G zG1tlXWTAF|M-#eK?*Py*$KM z7Q1_PYvIC$WV5dVVET}C_fxp+s3_5EmwXM||0vH_ffeAF4|zb;g%2CrgzH`J+aE&} z#lfblz;WX$Af5dN_`N5k<$mEv@&@LXMoa|+(B|q1>xTAX9ZaXMq&szUwG*y)&t@Q` z4bZP&zf-~bA8AK15Q);EulhkVc5d`G{&7ObpPVL9Q(rc;k>}tciji#zziC8L0)f$` z*r>1X+0epo+syztfe&yTp#6gB-W<|Cu&dAWI%x!fAA4mD*6|$3GO#JarM1pL(1p*+ z%0edWnA@?i5!Qpig43XF-VEIKU=X0@b95Ulk$-*5F#3&ghu;ni{HP@lsRngRL}fI1%!AbkNGR~dm8YaDbx1Zv-`12T0Hue2Viw)bcP9jX3&JBl7e+4I?Usl;580qf6X9*nA7Y zl3oO4v(~bg;fs4^2B3-Pj^n|}K=?fJ4MU?Hu{;6W24N`0-!cIHbRd%V!m<4VPFJhD z84v+L1@{C5aW~sje?b4%l}0uF{%IK&gRtGF-(kqui^)sUY%I`#m5v|m;w%9FWqabC z7pRf&y~fP|qV#qH5*Q5o3wUQadg6OKAZn#G!Zl<=tJw;ounJUv$>Wbdz6z0|!+|~; zH`T54Ex2tC!QvL-&%mE$slg7Ye*X@=d};@y;-0Za&D!5|C$71|)my%zE)t>OF#~G8 z*Ve3A!=R$!5}twZ478>h0B}+`WDERA_+`{=S)rHT(8s9!&jm(p-sV~t@Y@4E@32n5 ze+|q{{|TxQn7?dI6B6!Acm@uX8K4O(So16rYHM(YiwOR&eC=wZ>K)_;sVZj%K$~al zYj7i!0vMxQcA(5xSbth-H^b%3WB-_`O9n!DAuliQ%%=8mYweR8?q7HY zTKf!GIs?I0JR8<{MF3!ic(sP`0QUSGH1+%7A}XLtyc1D`o@wn95$<1j1`fm-u;c*N zu3ftoz`Hn@5s2M{5%_Tgpjq#vF!0;WQuum!23qk9z^dykAOQq>wUGmO9P&NCQrHI# z!cwsO!&~w2!d(l`KzIfM%>dw-i5%g{qttuW!az^Rcd7UhW4>x8gngX?)g8VUo`LWT z>;p4EdjJRoKOque@rL)hUrNdk)6jAN|6M=)@PnmXVILT7xQpQ#2+x4;3?L0y38PGq`*Uv z4k4LP@%@6B0Skr?AMVN#<@r+hdw2%IGZ3DE@C<}!AUp%%83@lncm~2V5T1eX41{MO xJOkkw2+u%x2EsECo`LWTgl8Z;11&cL{|~r(zj1gQLZScw002ovPDHLkV1hN+yeI$w diff --git a/src/images/widget/panda-skate.png b/src/images/widget/panda-skate.png index 98ac8051ae931e8e7dbdfa1639f781643347876e..f2917005a9a211bc1dbfb0df67e447959b37b393 100644 GIT binary patch literal 13329 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 XW10Q^bJ;%syZ}f`D2UgH8U_6y3Q-M( literal 45906 zcmafbWl$VVxb?EQF9dgYhu|6(PjCqmB!u7&!54RT*PuZI!QI{6-DPo?%X_PCeLue+ zUEMv?(_J&&^>jbyIcGwZ6=l#-h)@6k0J@wkSQP+(c`w2MkPzN8J%{3-|J58-Wj+Ba z#z+p|D`1naazDR(0WiInkpM8k<^Z_=n!G2X_XGgI=D+}8-*cG%uH^v#?=B1=2loG! z|7&P^L?j0Qhy&!n66&rnC*Keaais7e9tp~lsIC4^2^e8MvbZ?PI5;2`ED1PV;xKr1 zFnlMlJ%m9j-(NmHPc@&pRSvy1C}2Wu=Z(>7*>Bo-HoG)=O3zorV)&Q=j#US8mQ z6)~Sp#=k|Y{!0DUCd=M1++ZP>Gmlh~MMZYEvPZO$48m^o2O)X=F5= z&-W_Jf7NCl>(1fx=aEOt`HEH|EG(6yTmR2FQtuD-f%u(|)CX>k=hqRtf{6|kd-`ff z+i768mLi=(Jn5L2j&wnOLbk>+@M(BH9j7q9!^!L}z`M2mfDSpTmLensR`Co}3MT)0 z+x4ugTOait-1knUK?}_;wl;Q0Z!kuQ8BpXBwaZZoI108>@gILyrE^euXpxcN5`5$U z2b$h(cAKA4GXxwJeZE5>R7^+R*-F5K0Nw<9l&~&HXJ=>oeSVC1Aq3tR0CQe?Caafv zwLi``5Klk;!|a|JhVwME{c(>m3JEMpbdW9LaeL9mNE>4b0Ky=-1_1cI)yz)D?c1P{ zUojtJuDN_%v{%9Uf)LIaICrH8q?)sls3)$(Uu&~79-yZr%7bDLbS>e znbfM#b3;%aa1w)4%aJ#KpM4lvSc*auJn^P7Q2YLm(X`r3dYZuEvG3OXQJGar>7okh ze73pLJ?+0voBm*cQk-CjU`gMcB_OKRKakBAt5aXE)mHPRBZX$Q5{ydJD6l&2kU+kg zZdZG&Wn37~jpY;|3IJp-6Vz+~xO<~R-l^~G8W;U_aZ+-E_rl!Yye3jF5F&{J>r zp%5F`O$j5DJeEl|xej@9X4J_?qJ>vr^cRHrEHxJ#7+A}oS+?*oybQLIn*k08M}bR< zPei2CVA$z*2Yeucxd@|X9?QhsuE)}IG|l}K7`5^8#Wvg!QXrqW1jt~9t*{PD01s4E zUEQ|5AS~dq>9I&iNW?L!(bKl#e7|G?0R`zkGkn=wppuL(e zcNJEHkU^WLjGFpaidchB6ykumMONiH=PplooCX_Yy4p{go>Vn;Bcz9U5+Dpe*=IDh zl}T}~a&cc^dTJ%%ovA)}fj--PjMw|s7R8>GJNn7TQ&V* z255yA5i8m^wb3k>NPM4V|KCIn9xzk9eb|_Y_bHVi1FbKUeB4Oz69aiL$9%-udj75X zfDP0CY@6}A*WvP!BG-fvVaid*$Ni6M#uN4Wz3F@p4Um!&{>P+Wqx5Gv7{&3_cS%DlM!6aet+vC4d-Is*+tpT~Zf-OWa4UAf6##Ne;J?q@yN zwdEY}2|Cq%=5c+8V_$$zZA2R9@^-uqxfn!P2;s#n;*CcJqL~shzL9&m)FUTmPM>qi zr*@B}-3W{kGk^?cGS~kY%%H`J`;hCnJ5tc*C@_K6$f&`hdt1b!^AGOYw+?;}X4hr; zpSc>|Ri$q|Av!RLG;@+@YxwcI%^D)o91AkdjT~-B3qHGk^_!rrFCI?9>_4==!F2jc z9TXaet87b-5O7<|169B$qtcO6RsA%T2o z9wVQizR&DfzQXWS5rk8&^4q(7%XQX5|GI;tnb@FdK{s7Lb6s~_Ue2CJ8p^0c15;@_ zT!`P+Xxcb)+y_82=~Cr$90p_C$fgwF_ajF_vcgDv zT(zjnl@Xl>8X3iVx6#Weaci}>%HLE}E&hjw-=%7bkiXxU^zT|_A#e=(4T@D+c-;Ko z2Y&C)^`M^HbPNZ0=bf4{%>;Vzvz)T8j{Jz>WQF@Z3^jok4n`d4!b zc>#*h62GW{FFgoT%y6_^0+x#pqzay4;^H2P`KlM+V#g$LXXwpdDPz*Ni4(mU(QzKW zN$!oL?wrT|cA(^%N;u#Ub;9U%fv%A%!!-ffVMP&7obW>2N0}6R!TnTQtE)5|I zkqkwOSw90;xuQ$Gu|WNL(rFzZw?9$ro=|VsEtaN9PJbgFP(~lHV0?=&ZKeXn#D_@6 z8+>H7dl@sOBCJH<3~BEBfB@U5t+Ir218FN-add$d@Oq3O5rce+%I0U}LEdYESbZ*A z8E~h5mf*Uz27_=Q}9}C_@oAH%PLlg3QIyzv9n}yLaG< zpJ8&KmQha|p%^Msj$p&DJ+S`oh?Z5`<*Yp`)dUA;1b+88SDl?-R0SIvO7%NpcG@K_I$~A($!EQpob!lUuBPGWdGUnuyE%8h5pc6*v36z-JoK|2MsQf5jy#V@!6Q zFL5pvjCh)*GDJ`~nuZ2##Y7xwB?%7DCnQkSqk$*i61K5}YtM?3KN>`SE;y~BhiM3c z_7bf5zdRRZKA|gko5bFdQUz&K04Z7v8f+5BSStUy_jAdi-T(exslU23l>;Fac(ihP za9*R*t}^_aA?&Q-GzMjOSGgC$fuP-h=6mZA^H~h?z26dlhJ(x% zZmUg(_rT<;oTbpkntklgIh9(anxiWNUBS4Q$z`hyE$!+ojW-Rh7vCWi?#vYTum|gc zAg|$#HB~iqn!+YgwCxRYhE|B=b3p@MfWxs6g$g?J*|@t(v+c)zC7V_+Lh@6syk|y= zw-N33fee8wINfO6;3D9~)UJZfG!AxPFqs84caah=Jj@2z7TgXy7f^%idu~!AyeINw z0HoUvc?tXesD^U0?H2mcjy2i>U&>$~=Ceb;iMVMg{sk)eXu>Rj&mVk1|5<3%Y2Z4kG@mk9`kY66@{XyPh5$_%%*~A;Uv)UZ$JK|s z21x*pA0`^C1KEbo_a}0dAB?(iQV~liPCQfG_jT;$Z{LVT}&E8VXu>l-`|Sg z^A^jH{$tHnA-_e3oaF5MQf-MwkcC~Q!1eUGxG9Z=p1OWS@CvdZ-a8ba?1I3MJ3EFx zgFS=PdHoLKNBr}=rNNM{pfCkA3-h@X(TCmr!^bp zYF7=x4+Sm@P0p73_a+A+?qlF}TL26Ja*wSqXUsS!ki=U>=GNFDHhVNzNd`B@_R9g{ z9zZ{voZpUup>;V;f7gT`8K7yg%b`Rb-1rUE=^x4=91Hr^-|A|EtK z0~DQ%>D?cQ3rl1g$Zlt^!e>(t*=lD5N&q%+HiFTKd9URv8@Xs&hYp}N8@HK0DT&I6 zl7ez^hDF#R@>D+hKM+XjZvCn`s2N3DE!=~s0H7x#z(bKCNSz|}_D^6*L{BFIlVqt7 zQ~OH7&ytbXBzk(R9HU7gD1@S1=i}W0$xJaz2%^!&>R>#*L6Bx9hLRVy&pos6_CSEt+adw^y)6s_ z2(hMj@Ibk**n7?(=N{K3jS!^KfbPu1PXS=jgMIAey5LlBP2sTajryZV*=Ndi=Z#`= z9OQ1u)0FF_#qMNUb+(deqvncIHu@vsHAfm@VLlZwpBHxhX{7+#`oMUdeesLH?kA*x z=$ewqtDrqyCi`5ir{Y{LZ@CluPeaZPi|cIPBo@ZWlTq=hG<4sO`K8H>-{k+OmzPD2 zbOE{#_Gj2RDGhl^DC%{#$K5ABfXc7Fqmx&9g!)SWZ9K=QYzRY*3V2;T%I|Ig3pi3cKQdadvK`2PsQLc>wy1gmY1P<|IsL= zqKH$zo}^&d9bTYe6MsJpe@3LD4fF&=BJ4EXk{oe!7I5TsYg|Jq5|#-~;B=ByhLZ410q&3Z)muq0hO(fYi%Fb%OtS{!IPXYfxnu>M453 z{JtV9Ro!Fl2yZC!s?mEAPZs_2trn}Nnlv2U%8U`Ea1zuFjVdzKzoqgSp^R0)GG3TP zh8JVTBAmfe=>`V`JjbiAjji9EF5{~feolR5@ZS>s_%QhCnP0k6@aZ7PZ7 zMRK{xx%u70)s*{eg}B*Q3L`Y()QXN$P@>T%gWXaRC>#6?$>_UU=Y2`#xZ#O~$sCW+6$ zJ21m12{JfH^<`TXt)CFUb-j%>Fi&|#ui;}H%C332JNldDLH}e~fk~^PCsM|uiav4e zNa)=OE5W_j;JSth-NnlwJoia9MKIfVjQ+HK4s%%{5A-)^xi-TlJ?HtI2hkU+cN2}+Ka>?RL|T)J*&7>%`*6I^@-#4N&sJdg^?t9$TZ@O9)Ovs^E zrQ#P7aakW>sN&fVwwc7fhd$} zJEmR&3~gj0n(4g8buv5AAJ`N3GVU~ervYK3cf2i6NfctoQj^&pk8gpO*r)Y>{%Ao5 zSq4YzY?j$po5biV(Of?W0hLNz5USl1RrF{mc&)g*J;WX7X?1p|%1v@hclhB+tCz)I-X*<3C~w-Mo< zW*SM1`sGgf&3x_4b zOjQjm1HYJA`H7D3C#%pJS6* zKIk>_)A-ECLWe2fG&r?h;hfFJ9X@OSQGj2-d$wX2Z}WU$B1KGGc)fRoAJ)VsDspQ> zGfTe=Z7}Ly*9k<~l>_K456#B1_;4ZvXlKw!pW^_A8|prnl}#l`g&pOG2A-Tc+fx{g z8I~IqT^(w#my5Zcyuho7sL;Jfh%n{GK1^jxNI|DzM(#d$H}7whBrT>+#wEe|`Hx&! zvC{#0Qm6{seRqC#t0j(d;g8{~9=B#Zha$krwy)A!LmY*skbvn%$9?$V@FCmq8KEh5^nY!8%uDEP;I@xXES} z;U%2Ce*yAl92nOpyEFQ@D4RT0>c?%-TOff8ppU}Qbb-FYlGR9MCUnC^$8vSZw9^0% zPWlK?8#(P(=!_0{mb1L?4i%DLbFCJ?8I36J4)T%kfbkHvhdct&_+_arlgjKo2^o_m zkj^ZpWOeFokbBq5B_Y4FETXc+EAItGK_pfx(EaR0Eq%91{U&ues?T`~n^;)CvY>bE zwtbfGUX!Yx8oCpBXNtj_S*s#8xZWjp9Zh$c~FXjnU4})1ThG}VoB#$YMC0-HX@}o9|CzjNfrd4g?O-R294=fyQW_1M!SaQ z*>@PFTTtyN;ZUCWUNF$@Bai*wTlI1mD+Pa#zpzSLF@-K<3CDc;DmE{^v!CHIGM{~H z5b>xU@(gC1SElfWxc%|aI=w5nI$b%H`AsQQh&txWjILFwm*}$o29lpip1C9}LRo{O z!bAoj`O^C3yjp0HvS(fX&^N1L6&C*Vw$ZJWKMQ+Wd&q6djPW_J%mgNj>t;)L=4RM| z@iIcMnFzUZXnt4P3Jo%uqWZ178TGt~fN{P8OqUp6`6pSu(fm<_6QRI-j&ay(u1q_X z;!_f@!YE8POuNMm(WqP2a056kr%WP_+5ZK_&WRc$;D1#BgVo4dF$Zt}d0IF%^5FGko^B>hA-~&E;goQJd-y zrZTthj6@o+k)@@fMs((S7JTt3^5IOY-o;T$UGuYr@WB_WmtdO=Z~d&==m?2uL5g2c z?(O`xP2-(aT>1k2SG(WxsENqLP!d5C{0l>G%yO-TQOes#8h(Gg@GhnQlP>Gyv`E&! zP7HnW`#Fy^!sH@VbTuZoLQ{iOQD?sdCXK054Ui%{13Un0r5AUaNI)M5bu(UWeKL6I z&dpweJXx2dB|Ydg?lX|$MJc1~qp*c=k=p9LshYj-lGqt#b3dC|zE7$-It3X3e=NT! z0)67gKossF%>7}<49ksG947OpOfYtaghbGW1~PVVT^y~#fXLm9jH!DOIz3F6k5*oT zz)^_l2u)6B3I*z-5RrNaL{~7!Q=g8A@gkj`uyX=lBz*suh{2ygW-hc{%>z z|LA9&e!W}daztM#ReX0aa}S}l0$JI%+=gX7#x|Jlf1edu{_B3D^YHV;^)oz6XEwvP zl{kwy93Q)`@gPZ=8^mQ13u56N;{s2U)K|QQm4(*j4*>$sEH-d}(G8pv2F=*p2i;XQ zRr2<9py9(nkgvs{_V@3`Jk7{mOo~0Z2XiKShPjo`Pf*(}UcO(EUw&*jY%kcF7C&(D zW{PX$Fn>jfx0q!bj{ioUTxYGzJm@o!wj|!#(@jbiS2F#R@rOwkF7ukiE}cO1*mjGJ zAI9gUc0KYMk5KFN-f3*(=)}*i1{}IoP7E4aYsD8;t)DCWcst~<(DG~MJI4A8?>_b+ z{O+|;L;F1@A+fmAPhKRK%oc4_WTaxkZRE+_9G8*?5eoQp6H)D_=Tc|_Phoj z-ad7(wTY~m#omebHJPCTwD4g{mFIOon|119(uV8D07vgbqj2x_0zO-*A?IAFi?>_d zKB~pbn(kO?18-q69IG_mH^WjPPvL6{ zJcRmkdx7g^Qzom*3jrwpHT{rsWUA;+XfBetr0vzAfec&Kr)RDV#nT%WY}K^bA8|kC z=5sIg@*cVI#uDG#nQ9f?;D7i#A~iXgx?SvRhG@V8<*D~%7@F^q6Lg#0)HMH!fUeRc zx~P`+umQ-eAL{w%5@NW>6%=W_y!|dL|63<-1dIJ1X6PU&K&sik}EA= z-*c!$Q6=$#cSta+W4qUyRYy94zzk%Uta_39#7f@18skc z@^gUiW`6cj&(s?VmDl^ibu_Z4V7Ov}%$K6o3Xd^sq4}LvGS)L(v@2_PJKe5&FnOB` z4Yuut1^}u?#@m{2W>BL0Z(p~&kMb?&F8ry#DcmR%AOVyz(COnE;Yq+Sq`88Pea`NE zzOrZLX=Ak1OPMjvsch@JT7=;OJk=oxbA4yx?!K zEGc#1?_Zu0Z{q(c@KrA7lKgP@`1@TdaoJXDp=4zH6$BBsj8Vg~1;&zBMMGIALL=4a zIut$rt^*?DR4qdD_-x`!9PNCCJweDId13lz) z@=*LoGXw9J+B1u%9C8f&rzPcBmZ*wvu4r%oUvIN5cS$S}%X`ot7tP8ete}x`ft+@L z!|3fWJL)wCrdY1^V)d8PiR&56vBT-BtS51#W$8$wp|Vu5qxI-F>EIvvWlZHq5?w*O zWIp~xkD{N2&&#k)V(uU^03<$&I}0s17r&x4l(W+CF7m8J^)C;Ah;3O#^DSH3l?F!K zGlt5&{0b90#*3a%HLi#L5=Lo5Dp6zr-_FFD=tp0otE_QR+EY8tb(eLeneS}+iI#}t zvSkp-!F?x(!zF~IB4~etZ#NFHABLVF^W^Q;Jc}GK&;Q+86)Q>wjjbY4y3w?H#yoT~=g0eJqX?Aa4Jted`3`*#`IYxZb&<${dl~5u zTo{P~EX^pMXSnS8pRrJzGI^a)R(g4j`$&+{MXXYj9WzB%*8#qr)i|EB=b9tZo)nF9bxZv*hxG|^`Cjhi$ga^E6k;9`QD3ix#R<};rRFk zbQgy*+bt7SOurFcRDAdvc}sMSc|VrJcT*7VT`P8b(EU%_aGkloGK&ek(@%gFyfcA5 z&_1EI67f9R?mmJXC;pFoQmMzL9+~;6^2gv--QBtes*JF4xD`n~cN}p5HHzhJ0zwyc z7p}yH7fV9$&uK&qw5H7^cyh;|g(V5R^4r3`x#Z|`Z_i%2Z5F-QLKVOCli5;>yg7cv zDEgE383&GMh|oKFr_yV;teBY2te*Ud`9RmjE&8N$R+cj+@i83lO|kSFmCcm5S{i=o zn1}V_^&(NrURv1xNOm()`>O?tr!fOvI55|i?tG}m3 z5*agg9Y|#`jtpmd&6?=wLxQK{Vt7k`VU_khf*!8$nf)o}pSMuI^r0UsBZD{Q-LCQ_ z5iPwF>VixH+ZT!n7~_kIgVlp7+5-r+YG6rYnD7I?YB#fb0OzzuP=r zX6ja~VAuczj*5YyPPk9h>ygC9!BSaMc+_nEL;hMf0b*_)CI~H4O6lAlf8GfQ=DGbk zB%h6#R0wwI_T{NMX2ah>@!^43>VmI-zenw4{KXk%O%YHdOMPaGm@wqG<#6? zCJYI>-BBAiSC3K^>+GnTp7U{ru9W;9$>i41Ca*3ZMDD>q8xtl;dn{3O7^)2$W+aLv zM{Iwq6E)xB_vnlPMK5_#lT(Sp_PjV#m|1t;Jgs41h(+GIHKi&25-E`Fw=LJHMPb!% zas6VqKSc1)CSI#;C{Cc}R{S_g5MA;0)wCuKZz8#{Hs4IQz=HPh(zOVT4T#OkI7zqd zV-Ai-$TJj|y*ZlQ>6hC+S*Va#+|oqE>-pw(ANYyB=|Cmw}jn|r_ zl6=F(7Pu@vt*4)x_8>v zZ?L0$_;r%}STio%3)zU_JZ1ll)`4ZHGUpZCDZaK^XT4myJCrD7==sL3_o85O474W` z^V;kR>=Yk(nox0@%nsfC)kCj3r5cSWXh)5RF+Fjh6%9oL^H!TU*ugh=4YBZT5Og7d z8L(q&_Q#AU=qJEb%L*?~2OO^)yEI@=3K5sxMNB>6^6WM;iBA+J4)}3F=)`7~?NbH@ zxBDokH}m?uVVABZUZLt4)iK60U@+4ssW=RB}DUNEZ2q2TVuohR@v8RF9y>_xs`s1MEvIqcq>C_8r#bE{KV#6v04>41fE`74@GLni z06h^lHYPYkbfO8qF@%`j*R7m&2+}PIfs#K4ybN1ERR+pkj}kPx?Kb@wPy4o{VM8(Q zY{Ayf{vxTEDazXGTQ)My0+QpT*j>2zFcf3<^4OlJK^cl&kVGYg66OFK^hf~qdEgMk z_S5TZ%tM_ zpd>AQ^?kvn;i!KnN04_;?Y>DzS4*-R%NJ)JBk-#=kE4rl=P*2@c_{o6@P4aYU2n=# zK*;}lb4!eNJwyR~VVt9EDA*HvPWU~7)g3%FT=}|xnP?$7etX*d&vD~SWxf(76{Wd= zcIutvRRQWF7y-vD)ml1S#V+S;X(nGyYMqRi5n1cHdZH>4kFwN}no7Mr70<9LOIu0I z|CsBtH8JjA)j8u@+;KhNWYowDAcn~a8TV&0KN51>8@IqG8;v%96{n`crlYzT((p*M zpDfDuj0ph{pi>%gD{@hBB8?H3ArTf}Nworq`!+Fk9V35~G&wLjy*x&qgP)!?hA;?`l-4fE8o!+Yy04Jp`ByC-U!H7xXH6 zR2mTwHE+lb|8kdcdanNf9bb_R_EYv#!E`t2ruQ4YP@`L=smBr>W(J*VQAUOU{@z5K z&}fZ0s|yCS-&;(s94{svyM*B=zS+SizS*G7T|4wbCYlrxMsCFl+{p(bPmm!+@b^79 z>MZhhdN4owT(G=RcX*A4u@fDeYyeRqf86x2@MxHX{=A`>@4ri*IU^VKbd^nH(y$5l z7a3hjTXET2s@~a)!?<8pF9x-~2c6c$*BDQfaZ-^uzm@u6xVVn>p!0$3Z59X=KCNH{ zYlY@riL0=gU>!z^)8xlSTXuLXXH48IvCHtvCy_Mvyb39v!C!K(EdL87OW#cW2J|vHnpu=5q2G$%uF<37w#H-o)|O94UWVTS zXg=gA-v8S2BNdHI7^kB{EdNV%$LUbI5w!i}ZdZOjj?9F}1oY6^X)>`~dE6a@q1iKD zD;C+%(nsk{W4QEzGADur7CpjBaspTE`SBN4N!fID~kKyWYU_Z#gp#_Wq11#TZh{T&)Je!s6b3+l@ zj=Mv%%oi6QEKbseu+#0g=~9+H-xq>qD!>q(yVke0<)H?|@e}1?s?g_&)RSPg0uh@2 z!6dA=ZgQ>>oQ{Lv@8(&0`}GS0!ku59x1T5*c%`oy?$#Q7dnw;blxUjaLG0^)I#bdU zW^}m_Qat>ag-YLp(3=Ti`E-psA3;;?_4Lbp=^x{Mn!G2UXiPJ;P;aNCWc0u}mVs~h zYQ9)L_*I|jk_Q>5-0%B8MvH+RU?qW%&<`3z+K)&fHQ zU19ZatOu8AD?bS`__n$N!6eyGmy?CViM(FZKbBgy;6YlmCtN=VwX9)+{HZ8Mmwlf^ zw7`X#+v$Y^Witl;TN4o=-4KsjVO=&!cBi=KT72_vfcInly8Gx1Dt0-ZOP7SX01I?? zB=j%@(PrRTl^Dm!pUV0ETm^+N^Ehp(MWlc}?}I3`^(jg8d{is`6XYYFIRAd8h)11B z%N<!62lE&^Or}HU@w}b;fD7_U1#0NmYv3p&{a}%*L2n<0EJ!jXFqMw?w;r#nn8R z%`V1^m8hxU1Kx7KIoc3zBRld@6?J6I4)6`|5kt)Fz(pm^Bs(r1gK-l17vQ}88mwaQ zqI6<*^iKavgo$B~jT>mUS(SdcEag1>bH6S4HZ9U*^kEJ}CF)O@@}Nj5*4Hs06^?gP z*fzlQeZva~hb`^d)r{sgUuD#NtbF|$_T~-XPooXzgCMRa<5ECOV!8fq0{yp;RRN~3 z?;B;p>|E22FM@DB_tEh`$x0}7CJhx*X022W!f@EiK$)=(eggNc^*^rXsS|ZCRSV>c zuK@l&hX0h&`WAf}uXcJ)^yhVXZ2zo86Z>b~{1)|{^MGB47`y}b^rN(;KicqU!|n8` zPEkCuiVgUkA0t|B`zRP*RiS4i%YxVstsi=ea4ZM%!Xs){iXcdPrdSg>aRH z((kCL)o<(qzgYFEaRwMu5mwl57ngh5t`cMux(oH0vt+IxY4g33$Et7#fYZkPDfwGb zAuHty^lmNF)cm>kajHAt3J5SmDF_gg&emFWk8eD^AIuKyO1^GlnA8n-j;lFqR_fDJ zcRui0J?rWmEbfpMgO$EFRig}tWenLJZNaEyq@T`;6i{Jjz*M#sw2;LE3S|Ucg0BcIoO{8V=&dh@Ejz7yO1OP>{YdFomgou4lQL!?XXj?uE?C6bA29gV_k@e4U$ zr^VsuI#bbYKlR$H-)yU-JblknvPeP>8DqvHhsT5c)296wlajp$vOLNlfZPmks*5lU zY;lz%0FnKcj*N}{EnSq}m)#RH)b|!iR-#p@IlEmUdQDyXV!T0gYRxkUOw;GN6(gfH zf*xA~LlDVaH>3ySXqP3OSYda55fhNCY;ajTjGA$Iq6}m-Uae{ZBcLs+^8EfUK(V*y z(mEF?#KD}j4fbYaf=_cmQ`SP>i1ohX6rt_^Dc5(~sW2#)5YphdHmd zeOxeh8gSOvN$#`CbXui#7Hi}sz??*#$6t6D@dB9Wqi!m+TU-8_slL-anAxW>0_49~ zh3>`~Srh_jVrHn%87eoa+tlxVf+ri-%^Kl} z?sd6v=^q`!HbTfgqHrAi2Q#@P+TQ#ikmEJ~&UT_ApXF@JhcVu0$zj_s9|my+lubup zwIQ!2Z9&F$Jnr~;-=Qc;SnS_F`d-aHemx=v?5E+FX2N1UPmfD83b|Lnsh8?VVF9Ul zx6hVdD$$;t@>%q6i+Eo8r>!jBc~%x7Z}%ijmZ%i}M(5B6p1pmlwV3s^ecn*N zJ$3b1#sd7pj#=6!v$ZqGRQ2I(5IAov^6c!QmAmDfCP=emBcH-a_I2BcpTH%^w7f(U zT`Cts9HLI#l)F#=yRJ|=M>?~K<3ux5MUEhH%x9hW6%?n5P2-%?Yu5*K=zo6jE3giK zRINbsLS2yHvDtXWOwZ_c(8dXo#JU&cz;e$hHFQ%74d?^gVm`_?^6dZX_lY*i<9QU% zLq=q}Rt}(Zq|bL8{(wSx`FowW%i+?z;lu$Ty6L#V1`ldrMFxO3Mk#GdNDJ256P^G3xUUr(e=nKO2h7LV{pkAa@_Y8LaZu9w{TMU4x9hdb zt~~CJu2rFSn`dHKpN{C=!G0GZ(D{Z%_2Fj>PKTb@=0A}YNx852b`ZC+Zy)Y?&@@AA zchU)+7o^C6Uuh{geJfG7DjDTI8UAUFhG9vr5R}7;@@E{2dH{FriyWG#YN&j&_n+@kV(vE z!9XqJnb(G;QVv99+dtV^;m-z`2VFR6TMaQDV?9JZrzAb>k7cTzF=#1Dd)~$-H2lsO z8Np$t-<;%gq)L^F$Ge-2jRCrCMTSOrI*4oYz2l8X2Xbz=C2UM$bEE0vhk<9Ekkoo* zvg79jtL4Ac-vq>tWmBe0`hSxOxvD4AJbB#6=JyWixki?d0I)0S9W}o*4Ep{xu zE?f65VBv#nASJ@MGot;gc20_xwkD3G1K;#liVCX%B~d=~8pcWti-rgf@+Qt$k5$;= zv?8%n^u6+P>XgGfBQRgMK}0W*T0cTdHW^1x&h?Ygz%+E0Z`U@1V`U)7MD(D+}F65dXFoZspye~}Z$ zm1p#C3Pt`>L ziAm#vHUA*l;dD+PwY9GFe#SszQq7k|WEs8b<8Q=or=X&Pkj1W>;UWPLlP_F{D~sEy zgq=vZoFAnnwy>#$H&1Ya}-0OaYkKBq5|SS$kOf@`nx zuIjQA%RvY~Uz>Noug$z4(k7QM?QO=8+YvTKPSD>swWO>8&m6Cm?Za6AFTk$nE zC#Uekf-pT5|2BDWmf=agScmR~lcJlAz&u|mtCouB^M=UFJK9#A0E~$;zMz<)B z_eZbs1436QVm6Tg8Gb+gYY?d*-e{LWBnNV#j}_&63CV5#_he~iUgKHb{~;dDhrWihkkez!*&t| z3Vu#y4FwpAXO7a5tSsWFlGl47eqy4GF+vj0D1PJUnNPk@!0M;RraX^^Y-~_^Emn(t zbUm2mwOylQzdogfVz_@x%`e0*tfvvc%9aJ&2zqzgR`HTlYT_NJ5P0CJYS8y5polv* zNGb<}Knc*01HiLb2NMZ!bDIk@4;DQf%?`D@6+)%Mw&9REwM7f59a*@EzGNf6ms)L6 zUzb6DanE{McJ0UBwRcHXl6)eQbAEAjTYIoni!38#I_CLVP(M(Tb)`QZ2v&YLsKd8}`VU|B!1=j|ETc?XJ6(CYA^R zTP5|n*XTx&XXi%yLfb{To@;WGydqqAPy})D@P64&=1E1nF1LvbJ0jhGgz+hCqGfnl zCK$M@c|35f+`lJLCSmzpZ#hrqHCL8xufOqWH#T`%uAfBL>nF}f4n~V;l8e7izWC%0 zs{X?zNRZoLaJY4jkR#ayr}?E4hjAaL36lCHE$#v@mEhe6W$P|;*s(b^orky-j6_B? z`GblG#2CD;R6n;1^f3W-;iPorfnjZ&%@IQosNp1FwChW)s>9=qKxm7d92W2_ePal= zl|BCavIWdCKa^UtKXc^_icD8_ilY#xEPe-CR<_jv;GZlZssP z(@!GHeZ0yzVonE0;1{WdK4GO>s2CFXGttGM*I=NzI@rT!ir?xVMuh#*Y;V$*JZ|FM zcWjt6#O19*^v}l6Xf#@<2zDda(FhV7H$iq|`v{C|auJ0T?MI2vk1 z{L#CyYhI7n32aKjecVVhElIF5$-V($s!03u`QG5mQQf+scd?K?+5*x2i;(XfUm{Hh z?>m=53%mW9KOuk~Rb=57<}1fs^1G2?Y*4=5zx(&;SB-njvP_Uc7te-6wI+pnv$*h3 z5_`e^Kq{$*6TPg@hXNl<0=_SXNV_RdDH>GgW7KfZegH$SG(^73luExfYEiea!c6!r zrBtqO>HPL#c<%QhTS?%oe@Nh8OJ(o!V~Hl=HMw_``ghMyszY>=rB0EDpZ?R!)v1_> zLReX1W4(tDcmF~0=1Ai&+qXL(K#`$kIB%pEBMKB*%8Swi>gB40q8LlC7rKl!yPxeo z_SM~|`3THMoEoQ^Dh9$Rjv2(Y(Z68!vB`p9hW*6>Lh>+TpHL2BouYgReu5eb-~b99 zop$Rt$Oyj-Fz{?+vXT4^yI-B30z$>dZ z^UgWd?TRB+Bm{w(keV|ZxQuk-8oYg&ap?2kvlcG9b>lOrd4O=QE_Fr z8D=!9an3yy`H(Q!MC~{W9xiWF1byeQs7YS!>-=uudvKrP*t-~Z_KK`&Ue!>qa9 z*{E4QnK5^N6yHh^R~(Yzzhn7-{{m3Q(f4QDAUnZXIkax`bwvg>n7{${>k?&(yrLg0 z)tsmv{AI{GJN>iKNv7U47gpBSDYleHK0ank6Qu`IhaNP$*-$Zb>vOtg|=lbkqa4|dm z@O?e{TW#ysZSjbb+Pb7PJ!uxXI7MpSQ;9{yCAa1^PBo#BkkSL=krNxuMU&#if8HlI zkPvYVo`+}je*PJC{;3HyN4mpq<{h;vstpAv;e&V6yP@7qDZ~e6|Q7z>aBG2}~>7r6BwNbdq!-07s7=g?=pG zBxtlNdgA=Rdo@BveKAIV^wF*wwc_-MG*Q>AX-SKQ zICt(`E_BFHbQo=NO$h*z|IndOJCI*n18=+(`7>hRn2e6T1`#)Io|+O_7Y*l9VHPa! z;fy?g^n}T-e9n3FpSZ=_jum6W9Kfl=RBkK3!4}N0$>DkYw{^m zs%J!UxpH}rn{&SYa=5f<(@JeZ@^`LJghwAMiH$Z0+;w>#rwnnM@)bBZRZF6vj&z``k-A1PsAmZM0 zr2}rR=q6k4!KNL~|NS{osYg!F6O*}FY2CVwvVF%c_#ix?%$TXXR3^v<1q6(khSNJL zHH#H5E>$a6lo~be!dZvqlpg}Nm&Cw|=phTh879=%aHvXfP7qfk^LR*c8ju;|t|i_C z2tYhotZz&wQ`XVF|AM)HJ1oomiq14;gy<;S*l)krUwi#+4e`9s*e_#pej4U9{};)X zyMP2`!yxryDiDJuzS3~OK`npHns+JA@0ZO)r7}a4PYcAIJ9o=ZQ)eh=Bqw0nOlKb8 zzUoJ*z)DOfJjm_2w8>>XrU?njk0aG;ORJVGq+Xpm@H&)JnOvJm1$rPV~;KZshzWOO}uyCy$rv)vEY4@{@aWqtgGr84pJ! zzba18xjvCNHGxBfoS*sd+{E?|J*0?1UbsLfe4NJx?>U{QP_eAtVoA`3IF~RLX@G-7 z_Ij$3*QimWF51u>NZknIvO4Nez*8FMZy;h(cs`B#A3~Xbfgmg%F=E6P5FWQN z@0`w`?tMZ4aDppMGyefV?*L%jfPwe6LGOHk11iQSA9EC)W3hgoISV$?WU|y3`V-vZ z>q1V)rN66}BjVrjCR_I0*cg;A(cn!K0S_GX++jFr;<&g&MLC}QFQB`WxIc5|92xe> zNFm3k%W=L>>ktb`g3?6!a^>X7Ze8SoR;`qdfv|E8*dS!-D}dt*5@=U&^XblMjC*kU zyI_>|1dzQ0eiad2O@-rlmD_kV(wSW06)nLq0qLVK-q*vI!~`(F`S2m(_eYrfgaE+g zw;q&PYk?dDY@&%80H&N=G`ar)+lgbxAvRx8^Jj|7IdbMfbe~kor0>$^6$!wV%i$6o zmDo#l)}S1ir-oP(0E)mEpg{g_)uE*RI_D=>=3M@R4?mS3CQOE_Fc1SsY`zXGldj7e z)U6B4$KG;h_3Fy<5eTNH5G6_$(L)LrFx?=8F-AWDBe3%DrgJ^9#kv7R`&ZDW2l30z zZ$Mg(&qQO?IZZO}S+q)m`tL#?k3Dka$dt;JE7LN}FGJdsa5NJ@t_lEKv2xqmwHvg< zp$FyamGkJ-s|xYSEi)SOvqx$46C3N!xf6_m7%Oogry*jE{Ct?-BR@Eq^ndAf8TZ`; z#fj4c`3Ws57=tjq`1_wt^5RRc$d5lwRT75-!9aAcT%$*z#DH~rLcHq6BNWnQ!Ii&< zZeb=a8AkI|{_No9uHgozG}H~a2Ij>) z-g)~Cc?4(s`77tAWW%}+eCvIg`|~`k(qy+(?76lvEuXoIkVNQUxY)B3hM&x|iF%dv|_J1)ha2U=5J5C)$*a7>YE>5%aBz@c7=K1Y8CO;rSW;{5=R! zA&-e}!AGCSau9z^8_Ge2pofMYQcdMNIa{_|mSS>x!NWjsJG9btX>AxS8hiXX-_4OD zr{vC^3v1YUBp6rdI3T%Xhj-oVFx(-sxFh@GrK<$K3KPwhNjRQ@$DZEsI!xl>uYra; zJU$%GS8n+dExA68iGKO@R|T{82EC<-5eTVu>dBDz2XR2Ad)qC>fZJw z2@aOm2E3vUAt7;g4I~I)HbLON4FG5A2@+EX*91<_ibvs(qjw#D9r-a*+%snl{O>|| zoU(DfRdv8vs{sbG2o7<2VLbip8tGO%`-A`h!NScNLx6!AYfygank_3esL27MS(YB( zu{eY3+^MZeTy(kc!r``l*4ZYs6=p`D5SG>>5T)JTMjt>R8P<2A%^zDL}z6zyNd-9-NM((=LL6 z<1DFwICe-R`7tG!f+;~xv}H*5@r)X4P>Xk|zC$ok)ad z$8p`d6p;NcIPk1nx3*rZRt+gvwv5iDHz6l(QL(UTxU9hejTU_!7K|X)97m2|3=uxXzXS7vWno9) zmyk9t3#SW-0LsmQ@%J5$Lc0Np(sZfPDTz;SeL?_0JrAORRu#uy|Ht%izMZUHhOIa| zGqu4P>GR~tt=80=HEXIjZq!h!Rj;DM^wb&I*}3EnNt5ies2>KeBFlmb7h^cG7?^1Kjz#Y8&wq&V*03^F0wv)Jj<;r!9?#Ae}l*^8e z_YP@*Wl%!p&v?&*6mo+&aEbEf4LiI#U*u1NRG{U{pGVJMATOB<$CqWjIQ)<&)EYtK zV6YU9CG%yLk$wEZCj)qa>%lYuaR{PsG!}q{{S)4I+Dv51MxX#&YcOjMMhpyqB}Pk5z(PDPz;II zhjiB-cK*CTX(w35Q=Xks7?hFOlmeK9JtU-n@&rvC52tu%&z#pH!Xx1>K14tWbe3n; z-*`_&Wo}3S<3R+Pfe1J><1Tgf^`lP+K=I1*Kfqj_sxAvpwu};0MB?oKsZ#mLR=z8(2rQ-*#v9s(Od^ZMCvxN-OT_ z9LL}8i3AH4E>X*FJRi`X1Ci^}#Y-TrLT+k_XsQk1_BJ4SH0Ji_&qrt%A}*;Z8O3;V zdP=LDHtyWL8=IQeV^h-(bvO$g)Iib5e#?_H%z&! z(gp^{p`F87l$W*QB?{}9hFVGkltMvtN`VM`d;IwE_BbOW-RFkR6Pz^dZ#eOM22#KT zHqtC(4mK)U`o1{8Hg(!8HDBjDPk~ucc}4>fZkK)S)t7+yHB}-K6(XGv0>+mLmRWmh zl>$dGm@kydUum1f>_oSFrDKWvr;qn=A50icd&kp%(Z7~*cj zNX*Z}&V_4~7+EfV__+_XL;0IUe+Hm$JfVm=UtkTq>RI|{+JXU|^yFTXCZ z@kC#qAy1Kv#vhz#-El{G9%HT7u2nGK2D7swAHkjGLI!1&?*h3&_V9czMd zmTsGfd@AQryNM;QQJ5FK4dh^O>)1HNuve{G*@hp#+ezK|p3(qBD~0fQkE?EQeD{pp za*lsN*v3DgV=jTX97SDr;<^I^W*6!hij5+tHgDd1rE}-b?smQLsoihB`R1E*Z@>Na z4%C$dz%2p?BovZ5+QfGFZ6J(}9Xp{0uCFUeC}ql=Rc>63R34PQ**5K3C&D^k-aJ&a zk+>>70OLTTuMq$06$)+?uNC~&SlYX9pF;chGOg=mm7h-u01L%b;6o@%Dxz_ZqT!ZuFaf~$ zL>SJejDXi1FYcISL@>X`BRvrQDk$-s`tRu=ji5 zz=3O#pp{u7b~f8XqUO(mT$1M$n$WPcuQqy=%G=>wx%+AS$lGQqF#eRX#g359O>vySN#E?8L1B=v2C@@@qW+>1-sHzAT(D97;;92puqyB( z@_5%dA79=3oB*)mrAwE-uy5bKu4T%UnE;C1j?^2$QX1gLWCSYklz2@}55%7a0x%o8 zhyBUOBUMo$+Aa z@y5*82E)q3Oq!7a@0p2?jYZd{YHuwDJIvU-RC=UcAD_cTd+WS z_3104z8ozOrPaDThRH1lJKM`T{xESe2*FG|!Z5)+aKAtyED63~{yA;mrcZCX)EQdw zR-n}HprMV4!~6`&=Z!=_oL9Ml%U{R9Spfy!IJkIP>Pr#drTV6i;5u!v$!QTjx`}p7 zfV%R4Q;$w8OfycWmmHkWJ=a%$o&TG%tn_uUM2IVJqZSQ!Y7AWF&6Br?($c$@P5lW8 zXyZor%2VCCaT6EDi{rR;a{L=u+h4P8txTRWRT=YS!WdzEe+*z0N_X+cvIX{H#foxT z=r&$R957x^;;_?tzSafY5-0&tmW>-XZbhd~omzlncSUD4LT8mWh=End0qMh`$U6Yw zaCKomRv9*1#ZB+`aD%oEbGL&aY86mFH)4ji=^U((R7m~PyLw5M$0}vV#uf|um1O#q zM935;0Wd9{r_i$!U8w8GBQ`t|B5DJmu=T8Y#YtN+=w8Qy|^Ql5ht zmqua?#4GxCKn98!n87@2)*wtje5M*w^>F<|!bHca*lnqe89kB%!HocL{9wEkhZOK6 zzK?LtBQ2l(VkBY?T?mArG8$bC04j}+&kJPFicX6K($EF-2~f&|K%Tv0$BsQVBzf+h z(-K}D^FsZ;1}E)rCC%Wyk^($ta*IAr)qzOx78;?M!}EbRrpghg5gKe za12_da%Jh>t*bO`dY>}ARgwV2eI7FU@4tJMo3NFCtyVT8B(4mAv3jQCmeQq4s`)=m z&S8dqP3Z}YvUm*%DFl5%B;u0@q#r7fP(cI2GavQ)?rUT$Z97+ub)|dr-JzkO_xRGM z;4P5=615Z$I1qzIIQ;$P`Yj_pW01|lK;$|u*O=TWJEQ|81z;ej-)Qp^fRq3V6)Nan zX)n{KB$~4X!1O#>>FU)h*s@(-x;)WY+O%$^9H-L!o1TKH$UA~1y{R*1%95qa5ZAG! zXCOZ%1`@KTp6n`ZA7~@=@j!{-kL4@m-N8fRt4IVS_ossq5{&Thuq5>l@rl#mhQyEh zjNv1`(C)qWZqE7Rr5+=DG7&Jts#rpAfp@gU zDeHljWn;ys3H1PFi+`yx%U zhNxB=I*AGBvwUWqX%qsgjvZpzl`en;!CwNVTuNjnmu0<(46Gi_8|dKl#trU@!?9gJ zB(B#}gymX3?fJ82#W{aCEy$HXc-uC@lU=ow&(YE8f4C3z z9up@`(H>~s!gNO?>k8?h$?4Ol3;OExp@0MsKQvN)gRPtupsk&a&Z+@U<3`DioXPMo zFl}%Yim5;rCDO8!{UMM5lqgYL?Y%e+2PSqqjylI2o%3T8=7cIcxOZ$!l-k&n71n$~ z*>hpQCRlNLY8S(_maXOa=lZ~FQw_zjq1;u74}FR(T=bhV-Q9oSfRdc7*76BM ze!HVwImP99j};gB6QcjO-;IYumeVRd+mRzjE*!v`a9|75QVQUdAiZ?~SwY~|KnmEu z{~(TluRtjv(O}>+q?V%aA6Of(T}5B!Anp_zi|&nx@4~DAr)Vy=*k~?=^cy-R}mKD=;N|4^V01`kt9$EJLpEeKx)+-SK z;4|t5zLKdS?gIpX5b~#R`0(Lupw8nkaBF+w{6K#0_qGrDU>LRR8j;|evE!w6tLET7 z^d{pS^7yjt6t`(O6M5mBLVg?8<#}3@67O+OBr!r_J{9+tpG`kFzEi@WlCDyvidf6< zD)%>Ss>FGv*$0ABk;fzAC;vD_)~;W#Ty9ZH@-_fTu$_6Y?A*0WB_Yyt?oXV`k|nD` zd~$jcAJ@Ql4k;k3($6@z)irKfKht_~)n99*f4@GKg8;*)PFk01Gu)ZA+K_uI8m2oZGkWQm5^_HsB>CZkr9v6jUiiNhmU7C#3Z0 z(?@mzfp}g6cj(bl&w(%C@Fs|ps4#cDQlBYV5XnoGEU7g6ZQHbw+&B`A?>Gm}jaDzHw@$m&3Phht8r%?!Onu3R{yF=s9{HSp91=0kl3>y@5? zb>6-EUl8B(Qm|l%sbLTZKsoGZ3HHTVg8>4N!rq3TxDFVo12MoYhQ7no%aJ3;^zJ>L z(>8D3n&^NHZdMsP_Is&avyR+zPhE)FzIBmq)l4GWKmYtA*app=o01FX83x4}qlvV9GyQPk0M^KZ80mu106Suo+j^DUn2kU6DJh`K&FYt6A38VRRrzGk8f%2 zCm=uoQqYaC`YR5rKkjMBih*Uy{n25zlP6EIAZGo#PYNVY52j*ocs=maLSEWl1 zm%RCdu_G>r+KmTSC(coQc26#gwkXa|RKIf>0WT&uTI@R^mvGKl;I3l_qa)`E^Mpe}(N)sP+- z&#Eo1`4Z7$W7C)WvkshDQGam|{xRY3#WboIw89G04hc z&{!cq_nq5&_j%d2W$QLKbSgr(Q!F02*RfN>M4-kN4LJxDXYCznlG0@yG0C^b$=*@xe*|-b^V&Sm_ zBEb(6CP}p_Ritj6Is&H_P`+iA;NYAf1liPSG{iOP*-dcHW8SVGRoyVYDPhFM+>rfy zcgo~RlTlu7*x+YZ*~i3OQ_ec5`8Nt=x*M&cB7=iY|*D9wKDS~V5t zB~p>d5md`ptW-;SRMJuUNe;(%Z3mxO-ev5s&z?PJJj~7FCH0Q^5CJbpMH;s zyy!81)YEakoX1$n{}>Bh!1}{&}sqKRU`be*8rJ$0<`SIlps}LnM3W5T)kN`0pHT8OwndTyWP z={HzilEsUcz^X1>@)anq5SpU&wW}9EwDL)2XwIFH+@N<{E6B;*g5vz<$-UkSP2~ezFwQAL>894T%7#s%HC5no{ zV%xTDhd$)PVHy#@7*L5KnLIG=vEwIY$cIDa^AVq6{+wHh&atsLj{M>k_`l}~O0>Ge z(iVPnZkZ_yO| zb~ramTu}#Vh}ynOyL{RLR;pB4dUWq0En9FoGrJ;WaFVS|clW_~XUb30>SD4*T&@ai*|t?)e`A0Q|MYWMtL0Thz=5ug?X6Le3WUEnELI2;H!Ko! zYc|E1EW{xf5iG8i9Ox&GAH(2IU@QjW--Ow3LO>dYU5=C_Fd-p%<;iY6(d%m3;ipGHG$APGK%qR0uol9FWs-au26Tjy3&+TJetcBGI~j{i<5(W8IPpBs@IUs}ZIvg$oss(f|8KmCyIg zuWGgGa^HPTv5}~ll4Mq|{!9K^wZi8_fCS!C01m2BiUs=#Hdb?es2i~XLLPd^_Z6#!D-~HsfwMt1FWFPuHFA? z%K^{7R~N{y}MmEyhIprOSSo zJ^%hIWy_Y6`bMt#-ywEd$g0%nyb+k~lS;?A;) zoXqzD0^lXUVDZ-x5`J!ot!|W<^F++i?4!qgOY6=Q2X=Jce1+h*eyj9){u%l3gO8=* zJ@+aiU^cK*To4j+D=vJ_K@3mug3b*+L@2(yd?{Rs1;p=g5&g4%xXpM_g5Z62X(O zq~f$<#R@k3q~jy)X(M1?y6g{a!o(@sh7EtKW>YFK0;P)x>N4^bFy++r7*xD?QLIk1 z!VzBeVHKE1ad%25J)Y_g%fr8=Ui}8Dz9bSxU{{k!HGxEM^ym@ewGXbk+WlyiF#!cQ z^Gu2~4*>$;1xRV~i-Gy5hp4s%3m5A=)P#d7H9-Sn(irC$xK7^}pO-$pUsQ-kWJ*gb zHR=*7RHz8E)j(spLN96HfhnksSFs$fZH<@n>CV6TmDe!O#_WnbO6jZJXAreg+(QZQ7(U z;GJK1DwQ+x8};J5^5yT4idfS87t5t_Qj769O|Fz&NT4hNSxPh*%vp=?sd}9XewC_n zGgM+&{WXFJwj6_!1T)bTfQqV^m{@u6p+{{SHvXfKBP|+t<o_a&p1T{$s{`Ip zJLbskh-jvEChHLy)f}E&m-p1@ zPlC<<7M!p{k%vgZdXZz+t5-(`ywXp9ux)D{^Hz0eM{4V8q>n>(TSUYKeHip4-+wk3lgBXOIz6a-*+y1TrPW;3nW0`h9}(J?(EpkC-do!ZK7F=#-dK`dN8nQ zDl%lqr~uB4Vm%v|>u(gEEe2Q_N7K)p>ZT2FxeMA!!dFW2Z9c(z@ql|sgdwbl|pzSamOvR!y|}e;qw_Y`r%lT z14dJa(AKl#hhyEy{w8Ab@kxjF(-U)r!(JQ@`o9h?)U}~NWIGP6??C_&EZm+wd)@(s zDdno#;>CX|RTt07QBx2I0-KDiAt^Eo_1%-FOca0qxmeVyRaZ&ii3mvW2+Z8*ktwW? z@aaefT1^}qazqKgS~PDZDpjnkjxjvLb3anDep{!?#6{}Y(fuM2Bc?iH~+VjBn ztz`3NjV0tH(E|96^8#K`z=C6e1wuX9ym>qA8cdoEBw*AhS3)FJpg0*GLhXo86ilHH7$apNGPtG;35W{czIi=bK8x3SqCJ-BNF ze*4PTZ(N5L;jd!O+?k?G>2f&NRuy^k<%8`&Vub`qtvFV95CW-trHUUZL_ol&aEyS@ zO-aCKAdNZm<}34EB&tw|fv&X-u!(gMty(sfty?vdTq2Ay$|=76yv@F2o;orFTc%7I zFB`$<;?~Vuiqey+@>q~JZ-6KPPR7T_N397FnxW~iZ;$JhDn&Ap+$)K=0snlySI0s` zOoW>|cOJ2C-`;S@#<9M;zxkfZmidqfjjW3)7Dt`k?zR`%dSUsc$UglR)JKNna-eJs z#t`lWVWU`f?%E?OSE)%MmpVJY=#r4K@GO4cE?TauHd#MYrp%CT7Z*kGN5NhyILVM3 zu}~1ke;Au0n)qa>Y;Jg?aI+J65gD+Mx+5Mvfc{VAu*2v;Olrw~m|{CglEf6q$xfZx ziOiY&)S93@(~WEN5#67B4@)70ZQioIinTx^p2}6Ks&(Pqi4YX4oi??|?Vr`U77l}= z@zK@mH^u&-BTnBVk;+x5IDeZkP9e${Gj#K1YAUF>?5;lVSLmxDwWc|)yM-J4^yyRTZ`$-J zh-{Mx=Sg2ht^9obkUb|2*vk~~G)x4_rm1W?sZyn~ApuT{z)$`9Jw(!33C~Qh+ry|FDrWV=q$l*lOj1qhW72g zg713QE*-?dgNHQ+`Q$OiCKIz2uo41`+QSUlcN^iH0SWX)W zy}^h_O`A62uW;O@@houLYGksG76Bmp@E`zVrAkXKHh$fa1ickd(@{INnylqjJMNaMifAw3X) z?u`70E;!prmMn=#1uMlX2-5MaTWbX?qL)ZGdNJI+&?eme;BgABC8E@aC4pm22gW18 z6L4R%-EQ_rPTjE^2U_XvBQ_KOsL4~9e? zAR8!w$B}>&hB9P@DH%V2fSZ$%Qfu4x9SRXBgaE`qm0m8W^gvBz-8wax$mFF+_RZ!8 z03>D9UW8`eV=cv!7t_-Ea_!f`MbWKS4M5xH^Pj!$y#K*T$c-FUm> zy{P={K>#jR6XC49@FEi6g_)cjHKlsGbNAj09|1^Nm?rBf&i_$SvSi6B+O`Q)68<=l z+W!N1ZBQ1PFN*NF*6rH0lqE|PGc){AL*$mj`F|YLf6?LtV61}& z0T?S`@(F4f7cZMR3Qg_`M9{sX&dH=SFH-ojjV!q@(hk*K^wMLJ4SEwQl^&1^0sq2< z5P0d$6-$;aL)h$l3h+twN%2!6C0Lg(jb&iFRuFP|bFxvQ(hDWv2K%n2hPeV3P4H>x z#7X(6d6+zPhMY8Ms^uK~3z)HJ!uU}VegSyY#lvWW)HHKuKRDOmCh&AS325`CjR@IwQdJ-a^&*8 z%Lru5;l*ZSwDN|20`ODfkH-C`6zAIYYf8QJA_#!Uh2D2hV9fKpg(2A{F+V*OcH7l6~s^n>2195t7=VtWg5^oCh~CD4o81#VQGJ zKFBuy(>{2=gsfTXV-?T99*$9!NJn8=SX9co^_yzv&RtMRN(gZN{@IyBLHQHdKj&<{ zfV3@HGG|1;do*SmqDv4{t{)3>ci5BA@_F)tc0x(v>b;l)(0@pZ z`81r7cWs>dKWHSP^>ID0Sce!v_q5KZe2UVN-jVF z9x3PZjKS;~0)J4@VcDfyFAIU6QG$r*ew#Q&J0B7vKKryAfmx-)!gUok{m`K!^1~0` zmq1Wj8Wxd&t|^o#gckA&Jy<`2k&v|BSodKmBU9bN%7KXT%<$doZX z5F@NCVIx75Lw>?+>Jq>T7G1?JVj@lHbz|XY6#*Xrq}+SUmoJSRdY$2(TO!HK~_}uV&|{JwuF3V>5+#(fBGNVJq8XUr&^;6u=l@u?S`Vl@qs*v z2ooht0In$o+!Y0420U}J;_-q04du#|QNc}^p!9hQ5ey>`efRB`G?`Y&&#WyVL&^m1 z<6V9k-DiKJe-8pMRwDEhR&cptOfv*PR)LrBLYz`YQnlv={Lt={S`Hi4_!;46i4rA6 z8|2cXgrDW{KcOkLwAf~}!_KC)BC z_6qnpKC?mu01j>xj%Lwj`s>)Q2Lafv2!bv&1;zOZFD#WSz&9SDGtF}ne$@mwl*+j4 zWJ4JJ@G~GFzi8dEoeEdQjZ2EoPg4B@K|#>v&wzU`y!3#tsOIB&lhWp#IkSr{odRXu zy0t(}qsL3n7$@fg`vHCT?tPXx;5ukOfO|^PjWlQ${E7MV7m1D?duUr=f54+ZV*mok z73pN8~Xva^S1P9>UILGMU@iSZYY~sxDU&W!IgQ7seLh6XbK4ZtW zrUUt+Z@FNiIhH;dsv4^aq*YsW&M_eUIniWSO>`3wF~!c@mTT>a*8jLA@j z4gFEps8QV|@MF)B_1}SzYW-cc8P)eZ2mmVzj7-e?Edb{$ya%VM8OOy>n>MY|H9KC9 z%x@w9SB2E8WsBB|G3$=1H+g0?c2zf&6~)i zNnf5y59_CN+#DkT_oI(0C~8dM-nsJ^MBBhFif^g_WUz1F0Z{f^V)VG*G-x7Z*Dis; z2NrS&>Rg^6L42j5I0!f1n{d*JY)S3SL?`bc`tdRmAC{0*k8=Hp5VmdGim+oL3JEa+ z5yOH}OVYVx2erONUqq;l>em+=Hf&UhTsXgo3g=EU-}m1yE`|&qAoJwT>2gn@O$(m6 z1i4M?tXZ>0tuaUhgMI4}07HFaQw#w>bp;}bloXuUol;#G1cE(`V5Obhrm)GZq)V3$ z68h#!rRRlo)@1cbkqG$6H7I7!oeR7DKNV#pt53610)8@t`D)j;mFU#5t?uKKj=MEd zb21x?{Wa`W&Q#6TkxL?Li=(@xe7Q1m)21!jW1i6s2XV2HB&zPQ(z;xb>Z;zeE5J zAKn+UW=>ae3>i6yF$?JxNDj&^)mPSU0V$i=C^kL`fdA@JXanz9vg{~fk(`(=E8wgNAsx7VmhnJ-)@T-B?P1g@FfDLvFD4x)@r2PzH=M-4$>gBSwmU1N+pg>QAB7U zEc540mpyxZsm-1}PtfS+%9U%{FCz!*04lZ4j35jQCazqGJOY3qQ2{!S83g2Wi0j8= z3bhiBg>$=d?HV*EOGT#+?QIBv_4sV13KhgW90Qav)ehUUy#xsoDUOAfmi6k^694<+ zQ<*JW7S1ywt&blEAg^N@Cy5bp+#o^kdffiDexOq4=kFFEV^>% z&Yh639~YM|U$*>x`2w*1e~6`rIQEFK9}854vGo{kTU|p?4{j2pkYX5x-xv;?g;{Jr zu3kelMVx&keU2^At;Qcf_56uxckYmGUS&Xr|SSbe`as)-MYEK&a+PFqG)2*u05KspRf3J z)Xy?gCSSzeU#lHGc0&88QUwV$p7JjU(6 zM5$A!(!gH3Jx#nnZS|^kV)dGJ8sz})76S6oqsLU>69zw_Su#VO|Bm!#EZi3yFA*Ls zFpc{8j_owGc0o z^A88n#!K$ox3AW}e}B!4;=jnK3nE5co7N1x`2je9SXRKtCjp<5bDs0p!Rzc_NRq99 zud8#uuWts#-)kdzmd57fCUa?5{~}{__AHU2ac|YCbu##DFoKA-fV;32IJj1Q-o`@$>*3}tySxeT2Rm-;SGSI9e@6S0I_`8AFu|D zZ6FNe5z|k$)4EMZIb-HrWOQ;(ksTZ05NR&V6m4Yr0j%mh82f?J94ugx1F(AcPR=j`@uvwp>Zo7`Sk>}2xD+df15b;j4d(PEYAD{H%>#zEX zX;Wq@K_52~g?t2jnz;TtW~^w{E>O&zJzG&6>hmetCjw~Qx|v*snDHCE~ zh^y|R?H(Ytr=D53nxlcx|3>NisP^r&0r`JF5!Davj5w^N-rYwkP|5)z_VOeNXJeFA>X zPpYYCJOvBpR~z1JypH348NYER)>5VL5}je!&e(#TyL_r`*}NUbHY>I2)vJWDb0=WY z`ml57_Hx&rz1r&4>%`i18#LGngsEpXZq66SG|N|Ce$HSZ8jnNjC`Jyz9CwFlX6dq( zigl0gB2+uaX9(>0UaZYpZ8`|Z6!Os*A%6S>>a5TDPDDnwzBxRrw!!>(8Cp@jQ`$DQSzP>^8j_&$dap*rbB#%cB}kswMK&JY`49SfH9r~m*mq)9|UR5$P``+U<| z!odfjv%FNDEnBwB(PJiPu>aR!-KTSo1Qet2S?K-+Rg~-3ZxTa>j?^$Wb(Y8UR2!^g zJVUB$d`BCS5_rl%EXd%)u{~?q=ppPU>p+dD!|%XiXi~z~c=n5ZQA>~#G5&~Ltg;@f zfKO>`AeXU@hd3vqo~`Y&jRFPop)wkGGFr41d9%i6!;aE#Zyf@_3(e?a1@$FMmW0{- zF6x@zDqXs)XxFAaZ1)SO4Ml+G27dBHiVYh#DV1IjGVE}p67UU`9w@ys;`z9G6_rv8 zn}k5&-mWtpN#rhaqvOwV@7{fV`;MIw!8IWW(?x-Re4QF$ay* zebM5j+O};wV5_i1Yf!&V80yX`VE&fRKkLElNg5D_m_2)e*0^y!dI0JOs;bpSi~wua zU#lt;?HWc*8uI$d2N1%g&yXH!#rW<(qGk4+`SR4MGs-wBqE(oTCR*Fk;4OZN(E$+pkxCdx)x8hE5cYpKTKj6(wzT{KpnrrVlWvyeO z-gYlCp=-{zUW~`_nmG#JOVU8z{)Cqxk7%c(SFGw;Z zX1W7p;MG{1hc$)u7A|tYe9w4#NWj}qLT-Cp??JE3(u|9Pbfv{84U{n+2_1bnoOm>r zvP5f)v1FSqISppLfwQc1Ow?g%&DMu;0~PlBxD936;=$tnL3_8o@oLzV>2;sRrP-m1 zw5F>@14=2zICm~+N)ZBj@E4ATO`E+Mbl&PtrUg%4J0;Aws|g~pcUTJC5NY>078Xoe z%YFFbWcLOLhg+ap`w4nMmU_U{oos|>eJX^6=k zZZ@b^rts>9P-9eOHbL@;@Lkoh z?p$j6CiEiW=)PQ1U!HLhQ;)(lZd|Pt4>5_KOP>XunOC4@AD1JxJj7_mEat0o zUrJ^cvTz02u5JUPx`L4}qD?wlhqn4vqFvq;e~!TeEl9zbuHk@u?Dm&3e7yO8j%!4J z$sz)gM*^G{O#@Tc*7%WNXLH4?0?RWi;?R@eNt?!eLm+A}sMa}5oEE9sC4e)z%@OR`JDL&a$53gn*p@s*N zj1O8@5xy-~83@}eVKD>u=Of%wFxh!>nf0}P*?gmaw%(vY9H)2FqMEMu!$-wvqSzhJ z=YW}y&%!zuN8(PWS{41*jo>gQ>#@voOXT2rjd=%MBW}cDKUsaC!wE z_fDnOcRb!m6X(caQSr;s24*XIqwR)}Ai6GxMgq)teF9xgQUiYE^zSbu-9CPrgu%ge2~ef1gmiftRNPZmxj_#(TGWm>wE)BA0;Gec{>23&Nx| ze*tjtPN?i*UBE>30aZ8uH4JCPGE9ML_?@xupx}8DHzYhsq=q7GqSa@sxYDY^Gil&f zqJlbzYa-h?WX|UyEFs#b@#ubA{Y% zauX<@T$FsiS(2d7-PbMs^-#cZ8I2dEk=yS#iI`$zFpp{{KHkgDh_TkEK^^ei&sn{b z#Rh?q*6-NK#}=otzAMx!F4omcx%n2NYNtgX3UerPe;-c-AUuW9MHkZce#K5+Y4gNw zdWVirFXMC4de&T5yxUk7n*voF#L=lRV)z7(A7^fK8@2jmO7u2~z`q&|3;FqQkzW;687f#AoU0QMZ_TyjgllV)xb1>-L{3 zZxcP!P2jh?G2-^SgABqLxULEF>_Cp_XM$3$VvQ_th zIy~MOufuv=oii~2szSH#9j3sWUcvP?`{$ITkBxWxH!0I~?71yvlx97e@IpYlSOwu7E!w`=K2c3wKdx7WMrtX>cpEQ4iA z!5vdy^Mnh*+Xy@l_ru&4j52bAnX$twhnB2z@)Bhlnv6=@9AtcsEO^W^>K7CDgWi|K zthSje5)!-zL)#=4v}!AUz(4dcN%ro?kK3*8hc7Lg2ns3eOtsk?2eo5kS-x�+G4~ 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 TF_!)dfPdsasK``FL4yAeao1PY diff --git a/src/images/widget/panda-unbox.png b/src/images/widget/panda-unbox.png index e1e0bc99fcbdb59d5a08c910ac8c12d2b75c00bb..25cfdb7a10a34b16058860ef1e555ae5fa7f62f2 100644 GIT binary patch literal 13736 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 IQnU>FA7fl%Pyhe` literal 54456 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�<>Rj&+du?{4cW!zYAgGOqyUtzIjjDGv{jT>^<8 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 VCNFjd@W=oF002ovPDHLkV1hYn8t4E3 diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index 7911df1e..6a0c220d 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -44,20 +44,20 @@ $has_credits_line = null !== $widget['remaining_credits'] && ! in_array( $state, array( 'not_connected', 'pending' ), true ); -$time_left_text = ''; -if ( null !== $widget['time_left'] ) { - if ( $widget['time_left'] < 60 ) { - $time_left_text = __( 'Less than a minute left.', 'tiny-compress-images' ); - } elseif ( $widget['time_left'] < 90 * 60 ) { - $minutes = intval( round( $widget['time_left'] / 60 ) ); - $time_left_text = sprintf( +$seconds_left_text = ''; +if ( null !== $widget['seconds_left'] ) { + if ( $widget['seconds_left'] < 60 ) { + $seconds_left_text = __( 'Less than a minute left.', 'tiny-compress-images' ); + } elseif ( $widget['seconds_left'] < 90 * 60 ) { + $minutes = intval( round( $widget['seconds_left'] / 60 ) ); + $seconds_left_text = sprintf( /* translators: %s: number of minutes */ _n( 'About %s minute left.', 'About %s minutes left.', $minutes, 'tiny-compress-images' ), number_format_i18n( $minutes ) ); } else { - $hours = intval( round( $widget['time_left'] / 3600 ) ); - $time_left_text = sprintf( + $hours = intval( round( $widget['seconds_left'] / 3600 ) ); + $seconds_left_text = sprintf( /* translators: %s: number of hours */ _n( 'About %s hour left.', 'About %s hours left.', $hours, 'tiny-compress-images' ), number_format_i18n( $hours ) @@ -95,10 +95,18 @@

-

+

+ +

- +

@@ -289,7 +297,7 @@ class="tiny-widget-panda" if ( $widget['remaining_credits'] <= Tiny_Config::MONTHLY_FREE_COMPRESSIONS ) { printf( /* translators: %1$s: number of credits left, %2$s: monthly free credits */ - esc_html( _n( '%1$s of %2$s free credit left', '%1$s of %2$s free credits left', Tiny_Config::MONTHLY_FREE_COMPRESSIONS, 'tiny-compress-images' ) ), + esc_html( _n( '%1$s of %2$s free credits left', '%1$s of %2$s free credits left', $widget['remaining_credits'], 'tiny-compress-images' ) ), esc_html( number_format_i18n( $widget['remaining_credits'] ) ), esc_html( number_format_i18n( Tiny_Config::MONTHLY_FREE_COMPRESSIONS ) ) ); diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index 64d14727..258eb65a 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -316,13 +316,13 @@ public function test_images_affordable_is_zero_without_limited_credits() $this->assertSame(0, $data['images_affordable']); } - public function test_time_left_spreads_compressions_over_the_workers() + public function test_seconds_left_spreads_compressions_over_the_workers() { $this->connect(); $this->background_optimizer->method('is_running')->willReturn(true); $data = $this->widget_data($this->stats(30, 20, 0, 0, 1200)); - $this->assertSame(240, $data['time_left']); + $this->assertSame(240, $data['seconds_left']); } } From 5cf97813c5d7ef45462ef26e577bb0bacbef0028 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 09:44:06 +0200 Subject: [PATCH 43/68] translation --- src/class-tiny-settings.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 7dc13a6e..045e38e7 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -872,7 +872,10 @@ public function render_account_status() { $status = (object) array( 'ok' => true, 'pending' => true, - 'message' => 'An email has been sent to activate your account', + 'message' => __( + 'An email has been sent to activate your account', + 'tiny-compress-images' + ), ); } else { $status = $this->compressor->get_status(); From 745e330a73659a537629ea62e457b8af54c8b4cf Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 09:44:51 +0200 Subject: [PATCH 44/68] time_left to seconds_left --- src/class-tiny-dashboard.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 7f399d49..7b6e000e 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -114,7 +114,7 @@ public function get_widget_data( $optimization_stats ) { ); } - $time_left = null; + $seconds_left = null; if ( ! $this->settings->has_api_key() ) { $state = 'not_connected'; } elseif ( $this->settings->refresh_api_key_pending() ) { @@ -124,7 +124,7 @@ public function get_widget_data( $optimization_stats ) { } elseif ( $this->background_optimizer->is_running() ) { $state = 'compressing'; - $time_left = intval( + $seconds_left = intval( round( $estimated_credit_use / Tiny_Background_Optimize::WORKERS ) ); } elseif ( 0 === $images_remaining ) { @@ -147,7 +147,7 @@ public function get_widget_data( $optimization_stats ) { 'percentage' => $percentage, 'estimated_credit_use' => $estimated_credit_use, 'remaining_credits' => $remaining_credits, - 'time_left' => $time_left, + 'seconds_left' => $seconds_left, 'email_address' => $this->settings->get_email_address(), 'auto_compress' => $this->settings->auto_compress_enabled(), ); From c847cc16789912158c68d1650a771112d53cf0f8 Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 10:02:45 +0200 Subject: [PATCH 45/68] fix: require a nonce to start the bulk run from the widget A plain &start=1 link could start a bulk run for any logged-in user who clicked it. The widget link now carries a nonce that the bulk page checks before starting. --- src/class-tiny-plugin.php | 6 ++++++ src/js/bulk-optimization.js | 22 +++++++++++++--------- src/views/bulk-optimization.php | 2 +- src/views/dashboard-widget.php | 6 +++--- test/integration/dashboardwidget.spec.ts | 19 ++++++++++++++++--- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index dd6bef90..4a00d97b 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -934,6 +934,12 @@ public function render_bulk_optimization_page() { $email_address = $this->settings->get_email_address(); $bulk_running = $this->background_optimizer->is_running(); + /* The dashboard widget links here with a nonce to start right away. */ + $start_on_load = isset( $_GET['start'], $_GET['_wpnonce'] ) && wp_verify_nonce( + sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), + 'tiny-bulk-start' + ); + include __DIR__ . '/views/bulk-optimization.php'; } diff --git a/src/js/bulk-optimization.js b/src/js/bulk-optimization.js index df0c7366..fb725050 100644 --- a/src/js/bulk-optimization.js +++ b/src/js/bulk-optimization.js @@ -188,24 +188,28 @@ }); } - function prepareBulkOptimization(items, running) { + function prepareBulkOptimization(items, running, startOnLoad) { window.allBulkOptimizationItems = items; updateProgressBar(0); if (running) { startBulkOptimization(items, true); } - startFromUrl(items, running); + startFromUrl(items, running, startOnLoad); } - // The dashboard widget opens this page with &start=1. Start right away, then - // drop the flag so a reload does not start again. - function startFromUrl(items, running) { - if (new URLSearchParams(location.search).get('start') !== '1') { + // The dashboard widget opens this page with &start=1 and a nonce, which the + // server checks. Start right away, then drop both from the URL so a reload + // does not start again. + function startFromUrl(items, running, startOnLoad) { + const url = new URL(location.href); + if (url.searchParams.has('start')) { + url.searchParams.delete('start'); + url.searchParams.delete('_wpnonce'); + history.replaceState(null, '', url); + } + if (!startOnLoad) { return; } - const url = new URL(location.href); - url.searchParams.delete('start'); - history.replaceState(null, '', url); const start = document.getElementById('id-start'); if (!running && start && start.offsetParent !== null) { diff --git a/src/views/bulk-optimization.php b/src/views/bulk-optimization.php index 3ba98ec4..025dc298 100644 --- a/src/views/bulk-optimization.php +++ b/src/views/bulk-optimization.php @@ -327,7 +327,7 @@ ?>
diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index 6a0c220d..09a96ca7 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -8,7 +8,7 @@ $state = $widget['state']; $bulk_url = admin_url( 'upload.php?page=tiny-bulk-optimization' ); -$start_url = $bulk_url . '&start=1'; +$start_url = wp_nonce_url( $bulk_url . '&start=1', 'tiny-bulk-start' ); $settings_url = admin_url( 'options-general.php?page=tinify' ); $upload_url = admin_url( 'media-new.php' ); $credits_url = 'https://tinify.com/checkout/credits?utm_source=wordpress-plugin&utm_medium=referral&utm_campaign=upgrade&utm_content=dashboard-widget-credits'; @@ -49,14 +49,14 @@ if ( $widget['seconds_left'] < 60 ) { $seconds_left_text = __( 'Less than a minute left.', 'tiny-compress-images' ); } elseif ( $widget['seconds_left'] < 90 * 60 ) { - $minutes = intval( round( $widget['seconds_left'] / 60 ) ); + $minutes = intval( round( $widget['seconds_left'] / 60 ) ); $seconds_left_text = sprintf( /* translators: %s: number of minutes */ _n( 'About %s minute left.', 'About %s minutes left.', $minutes, 'tiny-compress-images' ), number_format_i18n( $minutes ) ); } else { - $hours = intval( round( $widget['seconds_left'] / 3600 ) ); + $hours = intval( round( $widget['seconds_left'] / 3600 ) ); $seconds_left_text = sprintf( /* translators: %s: number of hours */ _n( 'About %s hour left.', 'About %s hours left.', $hours, 'tiny-compress-images' ), diff --git a/test/integration/dashboardwidget.spec.ts b/test/integration/dashboardwidget.spec.ts index 92ce9f07..51928b69 100644 --- a/test/integration/dashboardwidget.spec.ts +++ b/test/integration/dashboardwidget.spec.ts @@ -57,7 +57,7 @@ test.describe('dashboardwidget', () => { await page.goto('/wp-admin/index.php'); await expect(widget().getByText('Ready to compress')).toBeVisible(); - await expect(widget().getByRole('link', { name: 'Compress 1 image' })).toHaveAttribute('href', /page=tiny-bulk-optimization&start=1$/); + await expect(widget().getByRole('link', { name: 'Compress 1 image' })).toHaveAttribute('href', /page=tiny-bulk-optimization&start=1&_wpnonce=\w+$/); }); test('all done', async () => { @@ -72,17 +72,30 @@ test.describe('dashboardwidget', () => { await expect(widget().getByText('1 compressed')).toBeVisible(); }); - test('start flag starts the bulk optimization', async () => { + test('compress link starts the bulk optimization', async () => { await setAPIKey(page, 'JPG123'); await setCompressionTiming(page, 'manual'); await uploadImages(page, 'input-example.jpg', 1, { generateSizes: false }); - await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization&start=1'); + await page.goto('/wp-admin/index.php'); + await widget().getByRole('link', { name: 'Compress 1 image' }).click(); await expect(page).toHaveURL(/page=tiny-bulk-optimization$/); await expect(page.locator('#compression-progress-bar')).toHaveText('1 / 1 (100%)', { timeout: 15000 }); }); + test('start flag without a nonce does not start the bulk optimization', async () => { + await setAPIKey(page, 'JPG123'); + await setCompressionTiming(page, 'manual'); + await uploadImages(page, 'input-example.jpg', 1, { generateSizes: false }); + + await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization&start=1'); + + await expect(page).toHaveURL(/page=tiny-bulk-optimization$/); + await expect(page.locator('#id-start')).toBeVisible(); + await expect(page.locator('#compression-progress-bar')).toHaveText('0 / 1 (0%)'); + }); + test('upgrade shows how to get more credits', async () => { await setAccount('INSUFFICIENTCREDITS123'); await setCompressionTiming(page, 'auto'); From 0a02b15846dc4447d43abca15828058ce8b0f83d Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 10:10:53 +0200 Subject: [PATCH 46/68] load widget async --- src/class-tiny-dashboard.php | 22 +++++++++++++ src/css/dashboard-widget.css | 9 ++++++ src/js/dashboard-widget.js | 26 +++++++++++++-- src/views/dashboard-widget-loading.php | 12 +++++++ src/views/dashboard-widget.php | 8 +++-- test/integration/dashboardwidget.spec.ts | 13 ++++++++ test/unit/Tiny_Dashboard_Test.php | 40 ++++++++++++++++++++++++ 7 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 src/views/dashboard-widget-loading.php diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php index 7b6e000e..196f3339 100644 --- a/src/class-tiny-dashboard.php +++ b/src/class-tiny-dashboard.php @@ -39,6 +39,13 @@ public function __construct( $settings, $background_optimizer ) { $this->background_optimizer = $background_optimizer; } + public function ajax_init() { + add_action( + 'wp_ajax_tiny_dashboard_widget', + array( $this, 'ajax_dashboard_widget' ) + ); + } + public function admin_init() { if ( current_user_can( 'upload_files' ) ) { add_action( @@ -71,10 +78,25 @@ public function add_dashboard_widget() { ); } + /** + * The statistics scan the whole library, so the dashboard shows a spinner + * and the widget JS fetches the real content from ajax_dashboard_widget(). + */ public function add_widget_view() { + include __DIR__ . '/views/dashboard-widget-loading.php'; + } + + public function ajax_dashboard_widget() { + if ( ! check_ajax_referer( 'tiny-dashboard-widget', '_nonce', false ) || + ! current_user_can( 'upload_files' ) ) { + status_header( 403 ); + wp_die( -1, 403 ); + } + $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); $widget = $this->get_widget_data( $stats ); include __DIR__ . '/views/dashboard-widget.php'; + wp_die(); } /** diff --git a/src/css/dashboard-widget.css b/src/css/dashboard-widget.css index 701f3c0b..02248212 100644 --- a/src/css/dashboard-widget.css +++ b/src/css/dashboard-widget.css @@ -3,6 +3,15 @@ padding: 0; } +.tiny-widget-loading { + padding: 24px 12px; +} + +.tiny-widget-loading .spinner { + float: none; + margin: 0; +} + .tiny-widget { container-type: inline-size; overflow: hidden; diff --git a/src/js/dashboard-widget.js b/src/js/dashboard-widget.js index 9cb8cab7..4e49b183 100644 --- a/src/js/dashboard-widget.js +++ b/src/js/dashboard-widget.js @@ -1,12 +1,32 @@ -(() => { +(function () { const container = document.querySelector('#tinypng_dashboard_widget .inside'); if (!container) { return; } + // The statistics scan the whole library, so the server renders the widget + // after the page has loaded and all state rules stay in PHP. + async function load() { + const loading = container.querySelector('.tiny-widget-loading'); + try { + const response = await fetch(window.ajaxurl, { + method: 'POST', + credentials: 'same-origin', + body: new URLSearchParams({ action: 'tiny_dashboard_widget', _nonce: loading.dataset.nonce }), + }); + if (!response.ok) { + throw new Error(response.statusText); + } + container.innerHTML = await response.text(); + } catch (error) { + loading.querySelector('.spinner').remove(); + loading.querySelector('p').hidden = false; + } + } + // Get more credits is a second view in the same HTML. Nothing is stored, so // a reload shows the main view again. - container.addEventListener('click', (event) => { + container.addEventListener('click', function (event) { const action = event.target.closest('[data-tiny-action]'); if (!action) { return; @@ -15,4 +35,6 @@ container.querySelector('.tiny-widget-main').hidden = showCredits; container.querySelector('.tiny-widget-credits').hidden = !showCredits; }); + + load(); })(); diff --git a/src/views/dashboard-widget-loading.php b/src/views/dashboard-widget-loading.php new file mode 100644 index 00000000..eed8daab --- /dev/null +++ b/src/views/dashboard-widget-loading.php @@ -0,0 +1,12 @@ + + +
+ + +
diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index 09a96ca7..719217f9 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -88,7 +88,11 @@

-

+ +

+ +

+
% @@ -99,7 +103,7 @@ diff --git a/test/integration/dashboardwidget.spec.ts b/test/integration/dashboardwidget.spec.ts index 51928b69..35e54d32 100644 --- a/test/integration/dashboardwidget.spec.ts +++ b/test/integration/dashboardwidget.spec.ts @@ -42,13 +42,26 @@ test.describe('dashboardwidget', () => { test('no images yet', async () => { await setAPIKey(page, 'JPG123'); + await setCompressionTiming(page, 'auto'); await page.goto('/wp-admin/index.php'); await expect(widget().getByText('Upload your first image')).toBeVisible(); + await expect(widget().getByText('Tinify compresses them automatically')).toBeVisible(); await expect(widget().getByRole('link', { name: 'Upload images' })).toHaveAttribute('href', /media-new\.php/); }); + test('no images yet without auto compress', async () => { + await setAPIKey(page, 'JPG123'); + await setCompressionTiming(page, 'manual'); + + await page.goto('/wp-admin/index.php'); + + await expect(widget().getByText('Upload your first image')).toBeVisible(); + await expect(widget().getByText('then compress them with the Bulk Optimizer')).toBeVisible(); + await expect(widget().getByText('automatically')).not.toBeVisible(); + }); + test('ready to compress', async () => { await setAccount('JPG123'); await setCompressionTiming(page, 'manual'); diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index 258eb65a..8f267df6 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -325,4 +325,44 @@ public function test_seconds_left_spreads_compressions_over_the_workers() $this->assertSame(240, $data['seconds_left']); } + + public function test_widget_request_refuses_an_invalid_nonce_with_a_403() + { + $this->wp->stub('check_ajax_referer', function () { + return false; + }); + $this->wp->stub('current_user_can', function () { + return true; + }); + + $this->assert_widget_request_refused_with_a_403(); + } + + public function test_widget_request_refuses_a_user_without_permission_with_a_403() + { + $this->wp->stub('current_user_can', function () { + return false; + }); + + $this->assert_widget_request_refused_with_a_403(); + } + + private function assert_widget_request_refused_with_a_403() + { + $this->wp->addMethod('status_header'); + $this->wp->addMethod('wp_die'); + $this->wp->stub('wp_die', function () { + throw new Exception('wp_die'); + }); + + $dashboard = new Tiny_Dashboard($this->settings, $this->background_optimizer); + try { + $dashboard->ajax_dashboard_widget(); + } catch (Exception $e) { + // wp_die() ends the request. + } + + $this->assertEquals(array(array(403)), $this->wp->getCalls('status_header')); + $this->assertEquals(array(array(-1, 403)), $this->wp->getCalls('wp_die')); + } } From 72014b6e11941b498eafdb1ea96d08cf7a7b19fc Mon Sep 17 00:00:00 2001 From: tijmen Date: Tue, 20 Oct 2026 10:14:53 +0200 Subject: [PATCH 47/68] show buttons conditionally --- src/views/dashboard-widget.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/views/dashboard-widget.php b/src/views/dashboard-widget.php index 719217f9..1f77d80e 100644 --- a/src/views/dashboard-widget.php +++ b/src/views/dashboard-widget.php @@ -14,6 +14,7 @@ $credits_url = 'https://tinify.com/checkout/credits?utm_source=wordpress-plugin&utm_medium=referral&utm_campaign=upgrade&utm_content=dashboard-widget-credits'; $api_url = 'https://tinify.com/checkout/api?utm_source=wordpress-plugin&utm_medium=referral&utm_campaign=upgrade&utm_content=dashboard-widget-api'; $strong = array( 'strong' => array() ); +$can_manage = current_user_can( 'manage_options' ); $badges = array( 'not_connected' => array( 'red', __( 'Not connected', 'tiny-compress-images' ) ), @@ -171,11 +172,11 @@ class="tiny-widget-panda"
- +
- +
@@ -284,7 +285,9 @@ class="tiny-widget-panda"
- - - - - - -
-

- -

-

- > - -

-
- - -
-
diff --git a/src/views/settings-modern-formats.php b/src/views/settings-modern-formats.php index e68cd32e..63f39941 100644 --- a/src/views/settings-modern-formats.php +++ b/src/views/settings-modern-formats.php @@ -6,6 +6,7 @@ * @var string $convert_to smallest, webp or avif * @var bool $server_rules whether Apache can rewrite, which server rules need * @var string $delivery htaccess or picture + * @var string $convert_name name of the convert format option */ ?>
@@ -13,7 +14,7 @@

diff --git a/test/integration/settings.spec.ts b/test/integration/settings.spec.ts index e059c38f..dd64e132 100644 --- a/test/integration/settings.spec.ts +++ b/test/integration/settings.spec.ts @@ -25,137 +25,124 @@ test.describe('settings', () => { }); test('can load settings page', async () => { - const showsPageTitle = await page.getByRole('heading', { name: 'TinyPNG - JPEG, PNG & WebP image compression' }).isVisible(); - expect(showsPageTitle).toBe(true); + await expect(page.getByRole('heading', { name: 'Tinify', exact: true })).toBeVisible(); }); test('show notice if key is missing', async () => { await expect(page.getByText('Please register or provide an API key to start compressing images.')).toBeVisible(); }); + test('show account connect if key is missing', async () => { + await expect(page.getByRole('heading', { name: 'Create a free account' })).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Already have an account?' })).toBeVisible(); + }); + test('invalid keys should not be stored', async () => { - await page.locator('#tinypng_api_key').click(); await page.locator('#tinypng_api_key').fill('INVALID123'); - await page.getByRole('button', { name: 'Save', exact: true }).click(); + await page.getByRole('button', { name: 'Connect', exact: true }).click(); - await expect(page.getByText('The key that you have entered is not valid')).toBeVisible(); + await expect(page.getByText('This API key isn’t valid.')).toBeVisible(); await page.reload(); - await expect(page.getByText('Register new account')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Already have an account?' })).toBeVisible(); }); - test('store valid api key', async () => { - await page.locator('#tinypng_api_key').click(); + test('connect with an api key', async () => { await page.locator('#tinypng_api_key').fill('PNG123'); - await page.getByRole('button', { name: 'Save', exact: true }).click(); + await page.getByRole('button', { name: 'Connect', exact: true }).click(); - await expect(page.getByText('Your account is connected')).toBeVisible(); + await expect(page.getByText('test@example.com')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Already have an account?' })).not.toBeVisible(); + }); - await page.reload(); + test('store valid api key', async () => { + await setAPIKey(page, 'PNG123'); - await expect(page.getByText('Your account is connected')).toBeVisible(); + await expect(page.getByText('test@example.com')).toBeVisible(); + await expect(page.getByText('Pay per compression', { exact: true })).toBeVisible(); }); test('not show notice if key is set', async () => { await expect(page.getByText('Please register or provide an API key to start compressing images.')).not.toBeVisible(); }); - test('allow changing api key', async () => { - await page.getByText('Change API key').click(); - - await page.locator('#tinypng_api_key').click(); - await page.locator('#tinypng_api_key').fill('JPG123'); - await page.getByRole('button', { name: 'Save', exact: true }).click(); + test('keep the api key when saving settings', async () => { + await page.locator('#submit').click(); - await expect(page.getByText('Your account is connected')).toBeVisible(); + await expect(page.getByText('test@example.com')).toBeVisible(); }); - test('show upgrade notice', async () => { - await page.getByText('Change API key').click(); - - await page.locator('#tinypng_api_key').click(); - await page.locator('#tinypng_api_key').fill('LIMIT123'); - await page.getByRole('button', { name: 'Save', exact: true }).click(); + test('show account connect to change the account', async () => { + await page.getByRole('button', { name: 'Change account' }).click(); - await expect(page.getByText('Upgrade account')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Already have an account?' })).toBeVisible(); + await expect(page.locator('#tinypng_api_key')).toBeFocused(); }); - test('not show upgrade notice for paid users', async () => { - await page.getByText('Change API key').click(); + test('show credits for free accounts', async () => { + await setAPIKey(page, 'LIMIT123'); - await page.locator('#tinypng_api_key').click(); - await page.locator('#tinypng_api_key').fill('PAID123'); - await page.getByRole('button', { name: 'Save', exact: true }).click(); + await expect(page.getByText('500 free credits')).toBeVisible(); + await expect(page.getByText('Get more credits')).toBeVisible(); + }); + + test('not show credits for paid accounts', async () => { + await setAPIKey(page, 'PAID123'); - await expect(page.getByText('Upgrade account')).not.toBeVisible(); - await page.getByText('Change API key').click(); - await page.locator('#tinypng_api_key').fill(''); - await page.getByRole('button', { name: 'Save', exact: true }).click(); + await expect(page.getByText('test@example.com')).toBeVisible(); + await expect(page.getByText('Get more credits')).not.toBeVisible(); }); test('have prefilled registration form', async () => { + await setAPIKey(page, ''); + await expect(page.locator('#tinypng_api_key_name')).toHaveValue(''); await expect(page.locator('#tinypng_api_key_email')).toHaveValue('wordpress@example.com'); }); test('should not send registration without name', async () => { - await expect(page.locator('#tinypng_api_key_name')).toHaveValue(''); - await expect(page.locator('#tinypng_api_key_email')).toHaveValue('wordpress@example.com'); - await page.getByText('Register account').click(); + await page.getByRole('button', { name: 'Create account' }).click(); await expect(page.getByText('Please enter your name')).toBeVisible(); - - await page.reload(); - - await page.waitForLoadState('networkidle'); - - await expect(page.getByText('Register new account')).toBeVisible(); }); test('should not send registration without email', async () => { await page.locator('#tinypng_api_key_email').fill(''); await page.locator('#tinypng_api_key_name').fill('John'); - await page.getByText('Register account').click(); + await page.getByRole('button', { name: 'Create account' }).click(); await expect(page.getByText('Please enter your email address')).toBeVisible(); - - await page.reload(); - - await expect(page.getByText('Register new account')).toBeVisible(); }); test('store registration key', async () => { await page.locator('#tinypng_api_key_name').fill('John'); await page.locator('#tinypng_api_key_email').fill('john@example.com'); - await page.getByText('Register account').click(); - - await expect(page.getByText('An email has been sent to activate your account')).toBeVisible(); + await page.getByRole('button', { name: 'Create account' }).click(); - await page.reload(); - - await page.waitForLoadState('networkidle'); - - await expect(page.getByText('An email has been sent to activate your account')).toBeVisible(); + await expect(page.getByText('Your API key is not confirmed yet. Click the link we sent to john@example.com to activate it.')).toBeVisible(); }); test('allow key reset', async () => { - await page.getByText('Change API key').click(); - await page.locator('#tinypng_api_key').fill(''); - await page.locator('.update .button').click(); + await setAPIKey(page, ''); - await expect(page.getByText('Register new account')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Already have an account?' })).toBeVisible(); }); test('store compression timing', async () => { - await page.locator('#tinypng_compression_timing_auto').check(); + await page.locator('#tinypng_auto_compress').uncheck(); await page.locator('#submit').click(); - await expect(page.locator('#tinypng_compression_timing_auto')).toBeChecked(); + await expect(page.locator('#tinypng_auto_compress')).not.toBeChecked(); + + await page.locator('#tinypng_auto_compress').check(); + await page.locator('#submit').click(); + + await expect(page.locator('#tinypng_auto_compress')).toBeChecked(); }); test('have all sizes enabled by default', async () => { - const sizes = await page.locator('.sizes input[type=checkbox]').all(); + const sizes = await page.locator('.tiny-sizes input[type=checkbox]').all(); await Promise.all( sizes.map(async (size) => { await expect(size).toBeChecked(); @@ -168,7 +155,7 @@ test.describe('settings', () => { await page.locator('#submit').click(); - const sizesDisabled = await page.locator('.sizes input[type=checkbox]').all(); + const sizesDisabled = await page.locator('.tiny-sizes input[type=checkbox]').all(); await Promise.all( sizesDisabled.map(async (size) => { await expect(size).not.toBeChecked(); @@ -176,35 +163,44 @@ test.describe('settings', () => { ); }); - test('show free compressions', async () => { + test('show credits per image', async () => { await enableCompressionSizes(page, ['0', 'thumbnail', 'medium', 'large']); - await page.locator('#submit').click(); + await expect(page.getByText('4 sizes selected. Each new image uses 4 credits.')).toBeVisible(); + await expect(page.getByText('With your settings, each new image uses 4 credits.')).toBeVisible(); + }); + + test('update credits per image', async () => { + await page.locator('#tinypng_sizes_medium').uncheck(); - await expect(page.getByText('With these settings you can compress at least 100 images for free each month.')).toBeVisible(); + await expect(page.getByText('3 sizes selected. Each new image uses 3 credits.')).toBeVisible(); + await expect(page.getByText('With your settings, each new image uses 3 credits.')).toBeVisible(); }); - test('update free compressions', async () => { - await enableCompressionSizes(page, ['0', 'thumbnail', 'large'], false); + test('count modern formats in credits per image', async () => { + await page.locator('#tiny-convert').check(); - await expect(page.getByText('With these settings you can compress at least 125 images for free each month.')).toBeVisible(); + await expect(page.getByText('3 sizes selected. Each new image uses 6 credits.')).toBeVisible(); + + await page.locator('#tiny-convert').uncheck(); }); test('show no compressions', async () => { await enableCompressionSizes(page, []); // disable all sizes - await page.locator('#submit').click(); await expect(page.getByText('With these settings no images will be compressed.')).toBeVisible(); }); test('not show resizing when original is disabled', async () => { await expect(page.getByText('Enable compression of the original image size for more options.')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Resize large originals' })).not.toBeVisible(); }); test('show resizing options when original is enabled', async () => { await page.locator('#tinypng_sizes_0').check(); - await expect(page.getByText('Resize the original image')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Resize large originals' })).toBeVisible(); + await expect(page.getByText('Enable compression of the original image size for more options.')).not.toBeVisible(); }); test('store resizing settings', async () => { @@ -219,7 +215,7 @@ test.describe('settings', () => { }); test('will not convert by default', async () => { - await expect(page.locator('#tinypng_conversion_convert')).not.toBeChecked(); + await expect(page.locator('#tiny-convert')).not.toBeChecked(); }); test('will store conversion settings', async () => { @@ -227,6 +223,6 @@ test.describe('settings', () => { convert: true, }); - await expect(page.locator('#tinypng_conversion_convert')).toBeChecked(); + await expect(page.locator('#tiny-convert')).toBeChecked(); }); }); diff --git a/test/integration/utils.ts b/test/integration/utils.ts index 88260d7e..d36b6d32 100644 --- a/test/integration/utils.ts +++ b/test/integration/utils.ts @@ -47,18 +47,21 @@ export async function clearMediaLibrary(page: Page) { }); } +/** + * Stores the key the way the account connect view does. Keys the API rejects are not stored. + * @param {Page} page the page context + * @param {string} key the API key, or '' to remove it + */ export async function setAPIKey(page: Page, key = '') { await page.goto('/wp-admin/options-general.php?page=tinify'); - - await page.waitForLoadState('networkidle'); - const changeAPIKey = await page.getByText('Change API key'); - const isVisible = await changeAPIKey.isVisible(); - if (isVisible) { - await changeAPIKey.click(); - } - await page.locator('#tinypng_api_key').fill(key); - - await page.locator('#submit').click(); + await page.evaluate(async (apiKey) => { + const { ajaxurl, tinyCompress } = window as any; + await fetch(ajaxurl, { + method: 'POST', + body: new URLSearchParams({ _nonce: tinyCompress.nonce, action: 'tiny_settings_update_api_key', key: apiKey }), + }); + }, key); + await page.reload(); } /** Sets the compression timing to the preferred value @@ -70,7 +73,16 @@ export async function setAPIKey(page: Page, key = '') { */ export async function setCompressionTiming(page: Page, timing: 'background' | 'auto' | 'manual') { await page.goto('/wp-admin/options-general.php?page=tinify'); - await page.locator(`#tinypng_compression_timing_${timing}`).check({ force: true }); + const toggle = page.locator('#tinypng_auto_compress'); + if (timing === 'manual') { + await toggle.uncheck(); + } else { + await toggle.check(); + // The settings page only offers background; auto is still a stored option. + await toggle.evaluate((element: HTMLInputElement, value) => { + element.value = value; + }, timing); + } await page.locator('#submit').click(); } @@ -83,7 +95,7 @@ type DefaultSizes = '0' | 'thumbnail' | 'medium' | 'medium_large' | 'large' | '1 export async function enableCompressionSizes(page: Page, sizes: DefaultSizes[], enableOtherSizes: boolean = false) { await page.goto('/wp-admin/options-general.php?page=tinify'); - const allSizes = await page.locator('.sizes input[type="checkbox"]').all(); + const allSizes = await page.locator('.tiny-sizes input[type="checkbox"]').all(); for (const size of allSizes) { const sizeID = await size.getAttribute('id'); if (!sizeID) continue; @@ -220,27 +232,15 @@ export async function setConversionSettings(page: Page, settings: { convert: boo await page.goto('/wp-admin/options-general.php?page=tinify'); if (settings.convert) { - await page.locator('#tinypng_conversion_convert').check(); - - switch (settings.output) { - case 'webp': - await page.locator('#tinypng_convert_convert_to_webp').check(); - break; - case 'avif': - await page.locator('#tinypng_convert_convert_to_avif').check(); - break; - case 'smallest': - default: - await page.locator('#tinypng_convert_convert_to_smallest').check(); - } + await page.locator('#tiny-convert').check(); - if (settings.delivery === 'htaccess') { - await page.getByTestId('tinypng_convert_delivery_htaccess').check(); - } else { - await page.getByTestId('tinypng_convert_delivery_picture').check(); - } + const output = settings.output || 'smallest'; + await page.locator(`input[name="tinypng_convert_format[convert_to]"][value="${output}"]`).check(); + + const delivery = settings.delivery || 'picture'; + await page.locator(`input[name="tinypng_convert_format[delivery_method]"][value="${delivery}"]`).check(); } else { - await page.locator('#tinypng_conversion_convert').uncheck(); + await page.locator('#tiny-convert').uncheck(); } await page.locator('#submit').click(); diff --git a/test/unit/TinySettingsAdminTest.php b/test/unit/TinySettingsAdminTest.php index f29541ac..b49d15ff 100644 --- a/test/unit/TinySettingsAdminTest.php +++ b/test/unit/TinySettingsAdminTest.php @@ -13,8 +13,6 @@ public function set_up() { public function test_admin_init_should_register_keys() { $this->assertEquals(array( - array( 'tinify', 'tinypng_api_key' ), - array( 'tinify', 'tinypng_api_key_pending' ), array( 'tinify', 'tinypng_compression_timing' ), array( 'tinify', 'tinypng_sizes' ), array( 'tinify', 'tinypng_resize_original' ), @@ -461,22 +459,23 @@ public function test_should_not_return_preserve_options_when_disabled() { public function test_will_not_render_delivery_if_apache_is_unavailable() { $GLOBALS['is_apache'] = false; ob_start(); - $this->subject->render_delivery_method(); + $this->subject->render_modern_formats(); $output = ob_get_clean(); - $this->assertEmpty( $output ); + $this->assertStringNotContainsString( 'Server rules', $output ); } public function test_will_not_render_delivery_apache_mod_loaded_is_unavailable() { $GLOBALS['is_apache'] = true; ob_start(); - $this->subject->render_delivery_method(); + $this->subject->render_modern_formats(); $output = ob_get_clean(); - $this->assertEmpty( $output ); + $this->assertStringNotContainsString( 'Server rules', $output ); } /** * we are defining the apache functions here so run in a seperate process to not affect other tests * @runInSeparateProcess + * @preserveGlobalState disabled */ public function test_will_not_render_delivery_if_apache_get_modules_is_unavailable() { $GLOBALS['is_apache'] = true; @@ -486,13 +485,14 @@ function apache_mod_loaded() {}; } ob_start(); - $this->subject->render_delivery_method(); + $this->subject->render_modern_formats(); $output = ob_get_clean(); - $this->assertEmpty( $output ); + $this->assertStringNotContainsString( 'Server rules', $output ); } /** * @runInSeparateProcess + * @preserveGlobalState disabled */ public function test_will_render_delivery() { $GLOBALS['is_apache'] = true; @@ -505,8 +505,44 @@ function apache_get_modules() { } } ob_start(); - $this->subject->render_delivery_method(); + $this->subject->render_modern_formats(); $output = ob_get_clean(); - $this->assertStringContainsString( 'Conversion delivery', $output ); + $this->assertStringContainsString( 'Server rules', $output ); + } + + public function test_should_label_size_with_width_and_height() { + $this->assertEquals( + 'Thumbnail (150 × 150)', + Tiny_Settings::get_size_label( 'thumbnail', array( 'width' => 150, 'height' => 150 ) ) + ); + } + + public function test_should_label_size_without_height_as_wide() { + $this->assertEquals( + 'Medium large (768 wide)', + Tiny_Settings::get_size_label( 'medium_large', array( 'width' => 768, 'height' => 0 ) ) + ); + } + + public function test_should_label_size_without_width_as_tall() { + $this->assertEquals( + 'Banner (400 tall)', + Tiny_Settings::get_size_label( 'banner', array( 'width' => 0, 'height' => 400 ) ) + ); + } + + public function test_should_label_size_named_after_dimensions_with_dimensions_only() { + $this->assertEquals( + '1536 × 1536', + Tiny_Settings::get_size_label( '1536x1536', array( 'width' => 1536, 'height' => 1536 ) ) + ); + } + + public function test_should_count_credits_per_image_for_each_size() { + $this->assertEquals( 5, Tiny_Settings::get_credits_per_image( 5, false, false, false ) ); + } + + public function test_should_count_credits_per_image_with_resize_and_conversion() { + $this->assertEquals( 12, Tiny_Settings::get_credits_per_image( 5, true, false, true ) ); } } From 337bc1991104678906c0116066a40ec018324149 Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 23 Oct 2026 20:48:48 +0200 Subject: [PATCH 54/68] refactor step rendering --- src/class-tiny-onboarding.php | 56 ++++++++++++----------------------- src/js/admin.js | 11 ++++--- 2 files changed, 24 insertions(+), 43 deletions(-) diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index 5f9f5319..efdfd61e 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -53,7 +53,7 @@ public function __construct( $settings ) { public function admin_init() { add_action( 'admin_post_tiny_onboarding_save_settings', - $this->get_method( 'save_settings' ) + array( $this, 'save_settings' ) ); if ( $this->is_onboarded() ) { @@ -76,44 +76,40 @@ private static function is_bulk_activation() { return filter_has_var( INPUT_GET, 'activate-multi' ); } - /** - * Set the sub menu pages - * - * @param int $step onboarding step - */ - private function add_sub_menu( $step ) { - $slug = $this->get_step_slug( $step ); + public function admin_menu() { + $this->page_title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); $hook = add_submenu_page( 'options-general.php', $this->page_title, $this->page_title, 'manage_options', - $slug, - function () use ( $step ) { - include __DIR__ . '/views/onboarding-' . $step . '.php'; - } + self::PAGE_SLUG, + array( $this, 'render_step' ) ); if ( ! $hook ) { return; } - remove_submenu_page( 'options-general.php', $slug ); + remove_submenu_page( 'options-general.php', self::PAGE_SLUG ); /** * because title is retrieved from submenu, which is not part of the menu, * resolve it through globals */ - add_action( 'load-' . $hook, $this->get_method( 'set_page_title' ) ); + add_action( 'load-' . $hook, array( $this, 'set_page_title' ) ); } - public function admin_menu() { - $this->page_title = __( 'Welcome to TinyPNG', 'tiny-compress-images' ); - - $this->add_sub_menu( 1 ); - $this->add_sub_menu( 2 ); - $this->add_sub_menu( 3 ); + /** + * Renders the step from the `step` query arg, or step 1 when it is not a known step. + */ + public function render_step() { + $step = filter_input( INPUT_GET, 'step', FILTER_VALIDATE_INT ); + if ( ! in_array( $step, array( 1, 2, 3 ), true ) ) { + $step = 1; + } + include __DIR__ . '/views/onboarding-' . $step . '.php'; } /** @@ -137,26 +133,12 @@ private function is_onboarded() { } /** - * Returns the page slug of the given onboarding step - * - * @param int $step - * @return string - */ - private function get_step_slug( $step ) { - return self::PAGE_SLUG . '-' . $step; - } - - /** - * Whether the current admin request is one of the onboarding steps. - * - * Reads the page WordPress itself resolved, so no request input is touched. + * Whether the current admin request is the onboarding page. * * @return bool */ public static function is_onboarding_page() { - $page = isset( $GLOBALS['plugin_page'] ) ? $GLOBALS['plugin_page'] : ''; - - return 0 === strpos( $page, self::PAGE_SLUG . '-' ); + return isset( $GLOBALS['plugin_page'] ) && self::PAGE_SLUG === $GLOBALS['plugin_page']; } /** @@ -166,7 +148,7 @@ public static function is_onboarding_page() { * @return string */ public function get_step_url( $step ) { - return admin_url( 'options-general.php?page=' . $this->get_step_slug( $step ) ); + return admin_url( 'options-general.php?page=' . self::PAGE_SLUG . '&step=' . $step ); } /** diff --git a/src/js/admin.js b/src/js/admin.js index d92899eb..d7c066ae 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -368,18 +368,17 @@ case 'post-php': eventOn('click', 'button.tiny-compress', compressImage); break; - case 'settings_page_tiny-onboarding-1': + case 'settings_page_tiny-onboarding': changeEnterKeyTarget('#tinypng_api_key_name, #tinypng_api_key_email', '[data-tiny-action=create-key]'); changeEnterKeyTarget('#tinypng_api_key', '[data-tiny-action=update-key]'); eventOn('click', '[data-tiny-action=create-key]', submitAccountConnect); eventOn('click', '[data-tiny-action=update-key]', submitAccountConnect); - break; - case 'settings_page_tiny-onboarding-2': - setTimeout(continueWhenActivated, 5000); - break; - case 'settings_page_tiny-onboarding-3': eventOn('change', '#tiny-convert', showFormatOptions); + + if (document.querySelector('[data-activated-next]')) { + setTimeout(continueWhenActivated, 5000); + } break; case 'settings_page_tinify': changeEnterKeyTarget('#tinypng_api_key_name, #tinypng_api_key_email', '[data-tiny-action=create-key]'); From 071c11bf0452577c7c8eb5d4a836494de7fec751 Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 23 Oct 2026 21:08:54 +0200 Subject: [PATCH 55/68] convert arrow func to plain func --- src/js/admin.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/js/admin.js b/src/js/admin.js index d7c066ae..8740de9d 100644 --- a/src/js/admin.js +++ b/src/js/admin.js @@ -146,7 +146,6 @@ if (action === 'update') { field = document.querySelector('#tinypng_api_key').closest('.tiny-field'); } else if (!name) { - // The server only rejects the name when it is missing. field = document.querySelector('#tinypng_api_key_name').closest('.tiny-field'); } else { field = document.querySelector('#tinypng_api_key_email').closest('.tiny-field'); @@ -154,16 +153,14 @@ column.querySelectorAll('.tiny-field').forEach((f) => f.classList.remove('tiny-field-invalid')); - // The server saves a blank key as "no key", which is not a connection. if (action === 'update' && !key) { field.classList.add('tiny-field-invalid'); return; } - const showError = (message) => { + function showError(message) { button.disabled = false; spinner.classList.remove('is-active'); - // The API key field keeps the invalid key message from the view. if (action === 'create') { field.querySelector('.tiny-field-error').textContent = message; } From b776b56ffc300e16f19c543cd3fdad4679706ccd Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 23 Oct 2026 21:13:04 +0200 Subject: [PATCH 56/68] redirect after activation --- src/class-tiny-onboarding.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/class-tiny-onboarding.php b/src/class-tiny-onboarding.php index efdfd61e..07ce43e3 100644 --- a/src/class-tiny-onboarding.php +++ b/src/class-tiny-onboarding.php @@ -55,8 +55,16 @@ public function admin_init() { 'admin_post_tiny_onboarding_save_settings', array( $this, 'save_settings' ) ); + add_action( 'load-plugins.php', array( $this, 'redirect_after_activation' ) ); + } - if ( $this->is_onboarded() ) { + /** + * Sends a new user to the first onboarding step after activating the plugin. + * + * Hooked to `load-plugins.php`, the screen WordPress shows after activation. + */ + public function redirect_after_activation() { + if ( $this->is_onboarded() || ! current_user_can( 'manage_options' ) ) { return; } @@ -65,6 +73,9 @@ public function admin_init() { if ( self::is_bulk_activation() ) { return; } + + wp_safe_redirect( $this->get_step_url( 1 ) ); + exit(); } /** From 4cc6f5fdeaecff4ae95fe3cb954579dfcb1be85b Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 23 Oct 2026 21:17:50 +0200 Subject: [PATCH 57/68] show 2 steps when connecting with an api key --- src/views/onboarding-3.php | 3 ++- src/views/onboarding-steps.php | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/views/onboarding-3.php b/src/views/onboarding-3.php index e4353ca2..527150b3 100644 --- a/src/views/onboarding-3.php +++ b/src/views/onboarding-3.php @@ -3,13 +3,14 @@ $tiny_auto_compress = $this->settings->auto_compress_enabled(); $tiny_stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); $tiny_uncompressed = count( $tiny_stats['available-for-optimization'] ); +$tiny_confirm_email = 'api-key' !== filter_input( INPUT_GET, 'path' ); ?>
- render_steps( 3 ); ?> + render_steps( 3, $tiny_confirm_email ); ?>
diff --git a/src/views/onboarding-steps.php b/src/views/onboarding-steps.php index 4338c951..2a33a1c6 100644 --- a/src/views/onboarding-steps.php +++ b/src/views/onboarding-steps.php @@ -4,12 +4,16 @@ * Without the confirm email step, the steps are numbered by their position. * * @var int $current_step + * @var bool $confirm_email */ $tiny_steps = array( 1 => __( 'Account', 'tiny-compress-images' ), 2 => __( 'Confirm email', 'tiny-compress-images' ), 3 => __( 'Settings', 'tiny-compress-images' ), ); +if ( ! $confirm_email ) { + unset( $tiny_steps[2] ); +} $tiny_number = 0; ?>
    From 9b5d071e85f819ac6deaf09a657235c902182ccf Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 23 Oct 2026 21:21:43 +0200 Subject: [PATCH 58/68] is_api_key_pending will show when key is actually valid --- src/class-tiny-settings.php | 21 ++++++++++++++++++++- src/views/onboarding-3.php | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 09e279c0..adc76406 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -228,7 +228,7 @@ protected function get_api_key() { } } - public function get_api_key_pending() { + protected function get_api_key_pending() { if ( defined( 'TINY_API_KEY' ) ) { return false; } else { @@ -236,6 +236,25 @@ public function get_api_key_pending() { } } + /** + * Whether the API key still waits for the user to confirm their email. + * Clears the pending flag once the key works. + * + * @return bool + */ + public function is_api_key_pending() { + if ( ! $this->get_api_key_pending() ) { + return false; + } + + if ( $this->compressor->get_status()->ok ) { + $this->clear_api_key_pending(); + return false; + } + + return true; + } + protected function clear_api_key_pending() { delete_option( self::get_prefixed_name( 'api_key_pending' ) ); } diff --git a/src/views/onboarding-3.php b/src/views/onboarding-3.php index 527150b3..600c5268 100644 --- a/src/views/onboarding-3.php +++ b/src/views/onboarding-3.php @@ -1,5 +1,5 @@ settings->get_api_key_pending(); +$tiny_key_pending = $this->settings->is_api_key_pending(); $tiny_auto_compress = $this->settings->auto_compress_enabled(); $tiny_stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); $tiny_uncompressed = count( $tiny_stats['available-for-optimization'] ); From adb9fbdc3657bc8edd9b88ca13684fcc5f064de3 Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 23 Oct 2026 21:57:34 +0200 Subject: [PATCH 59/68] keep the three compression timing options --- src/views/settings.php | 28 +++++++++++++++++++++------- test/integration/settings.spec.ts | 9 ++------- test/integration/utils.ts | 11 +---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/views/settings.php b/src/views/settings.php index 83959a86..7d56372c 100644 --- a/src/views/settings.php +++ b/src/views/settings.php @@ -6,6 +6,7 @@ $tiny_convert = $this->get_conversion_enabled(); $tiny_logging_name = self::get_prefixed_name( 'logging_enabled' ); $tiny_timing_name = self::get_prefixed_name( 'compression_timing' ); +$tiny_timing = $this->get_compression_timing(); ?>

    @@ -36,15 +37,28 @@

    - + +
diff --git a/test/integration/settings.spec.ts b/test/integration/settings.spec.ts index dd64e132..48c0000f 100644 --- a/test/integration/settings.spec.ts +++ b/test/integration/settings.spec.ts @@ -130,15 +130,10 @@ test.describe('settings', () => { }); test('store compression timing', async () => { - await page.locator('#tinypng_auto_compress').uncheck(); + await page.locator('#tinypng_compression_timing_auto').check(); await page.locator('#submit').click(); - await expect(page.locator('#tinypng_auto_compress')).not.toBeChecked(); - - await page.locator('#tinypng_auto_compress').check(); - await page.locator('#submit').click(); - - await expect(page.locator('#tinypng_auto_compress')).toBeChecked(); + await expect(page.locator('#tinypng_compression_timing_auto')).toBeChecked(); }); test('have all sizes enabled by default', async () => { diff --git a/test/integration/utils.ts b/test/integration/utils.ts index d36b6d32..ec15ef58 100644 --- a/test/integration/utils.ts +++ b/test/integration/utils.ts @@ -73,16 +73,7 @@ export async function setAPIKey(page: Page, key = '') { */ export async function setCompressionTiming(page: Page, timing: 'background' | 'auto' | 'manual') { await page.goto('/wp-admin/options-general.php?page=tinify'); - const toggle = page.locator('#tinypng_auto_compress'); - if (timing === 'manual') { - await toggle.uncheck(); - } else { - await toggle.check(); - // The settings page only offers background; auto is still a stored option. - await toggle.evaluate((element: HTMLInputElement, value) => { - element.value = value; - }, timing); - } + await page.locator(`#tinypng_compression_timing_${timing}`).check({ force: true }); await page.locator('#submit').click(); } From 69386adc7d4539fe8b3844c24805ec8db0c3a935 Mon Sep 17 00:00:00 2001 From: tijmen Date: Mon, 26 Oct 2026 13:08:00 +0100 Subject: [PATCH 60/68] Move tinify link to account card --- src/class-tiny-settings.php | 1 + src/views/account-status-connect.php | 9 +++++++++ src/views/account-status-connected.php | 3 --- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index adc76406..76aedac5 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -812,6 +812,7 @@ public function render_account_connect() { $user = wp_get_current_user(); $name = trim( $user->user_firstname . ' ' . $user->user_lastname ); $email = trim( $user->user_email ); + $has_api_key = (bool) $this->get_api_key(); include __DIR__ . '/views/account-status-connect.php'; } diff --git a/src/views/account-status-connect.php b/src/views/account-status-connect.php index 0aa338ba..c2e4e4e2 100644 --- a/src/views/account-status-connect.php +++ b/src/views/account-status-connect.php @@ -5,6 +5,7 @@ * @var bool $can_create_key whether this server can register new accounts * @var string $name full name to prefill * @var string $email email address to prefill + * @var bool $has_api_key whether an account is connected already */ $tiny_dashboard_link = sprintf( @@ -91,5 +92,13 @@

+ + + +
diff --git a/src/views/account-status-connected.php b/src/views/account-status-connected.php index c94dff1d..a640acb9 100644 --- a/src/views/account-status-connected.php +++ b/src/views/account-status-connected.php @@ -102,9 +102,6 @@

'; printf( @@ -817,7 +833,11 @@ public function after_compress_callback( $compressor ) { } } - public function render_account_status() { + /** + * @param bool $link_to_settings Whether Change account links to the settings + * page, for pages other than the settings page. + */ + public function render_account_status( $link_to_settings = false ) { $key = $this->get_api_key(); if ( ! empty( $key ) ) { if ( $this->refresh_api_key_pending() ) { diff --git a/src/css/bulk-optimization.css b/src/css/bulk-optimization.css index 2b22e15b..6602ab93 100644 --- a/src/css/bulk-optimization.css +++ b/src/css/bulk-optimization.css @@ -1,356 +1,267 @@ -div.tiny-bulk-optimization div.dashboard { - min-width: 750px; - margin-top: 10px; - border: 1px solid #e5e5e5; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); - background-color: #fff; -} - -@media only screen and (max-width: 799px) { - div.tiny-bulk-optimization div.dashboard { - min-width: 250px; - } -} - -div.tiny-bulk-optimization div.available { - float: left; - width: 50%; -} - -@media only screen and (max-width: 799px) { - div.tiny-bulk-optimization div.available { - width: 100%; - } -} - -div.tiny-bulk-optimization div.available div.inner { - max-width: 600px; - padding: 4px 23px 23px; -} - -div.tiny-bulk-optimization div.available table.totals { - max-width: 500px; - width: 100%; - margin: 18px 0; - border: 1px solid #e5e5e5; - border-spacing: 1px; - box-shadow: inset 0 0 0 25px #fff; - background-color: #e5e5e5; -} - -/*ie6-8*/ div.tiny-bulk-optimization div.available table.totals { - border-collapse: collapse \9; - border-spacing: 0 \9; -} - -/*ie6-8*/ div.tiny-bulk-optimization div.available table.totals td { - border: 1px solid #e5e5e5 \9; -} - -div.tiny-bulk-optimization div.available table.totals td.item { - width: 33%; - padding: 1em 8px; - vertical-align: top; +.tiny-bulk-hero { + align-items: center; + gap: 0; + padding: 40px 24px; text-align: center; - background-color: #fff; } -@media only screen and (max-width: 400px) { - div.tiny-bulk-optimization div.available table.totals td.item.costs { - display: none; - } -} - -div.tiny-bulk-optimization div.available table.totals td.item h3 { - margin-top: 0; - text-transform: uppercase; - color: #bbb; - font-size: 1.1em; - font-weight: normal; -} - -div.tiny-bulk-optimization div.available table.totals td.item span { - font-size: 1.8em; - font-weight: bold; - line-height: 1em; -} - -div.tiny-bulk-optimization div.available table.totals td.item div.tooltip { - position: relative; - display: inline-block; - vertical-align: super; -} - -div.tiny-bulk-optimization div.available table.totals td.item div.tooltip span.dashicons { - font-weight: normal; - font-size: 1.3em; - /* WordPress color embedded in webpage */ -} - -* + html div.tiny-bulk-optimization div.available table.totals td.item div.tooltip span.dashicons { +.tiny-bulk-hero[hidden] { display: none; } -div.tiny-bulk-optimization div.available table.totals td.item div.tooltip div.tip { - position: absolute; - z-index: 10; - display: none; - top: 50%; - left: 130%; - width: 18em; - padding: 0 1em; - background-color: #fff; - box-shadow: 1px 1px 4px rgba(0,0,0,0.2); - border: 1px solid #e5e5e5; - text-align: left; +.tiny-bulk-panda { + width: 128px; + height: 128px; + margin-bottom: 16px; } -div.tiny-bulk-optimization div.available div.notes { - display: table; +.tiny-bulk-badge { + padding: 2px 10px; + border: 1px solid currentcolor; + border-radius: 6px; + font-size: 13px; + font-weight: 500; + line-height: 20px; } -div.tiny-bulk-optimization div.available div.notes h4 { - display: table-cell; - font-size: 1.1em; - padding-right: 1.2em; - white-space: nowrap; +.tiny-bulk-badge-red { + background: #fef2f2; + color: #dc2626; } -div.tiny-bulk-optimization div.available div.notes p { - display: table-cell; +.tiny-bulk-badge-amber { + background: #fef3c7; + color: #b45309; } -div.tiny-bulk-optimization div.savings { - margin-left: 50%; +.tiny-bulk-badge-green { + background: #e8faf0; + color: #00b075; } -@media only screen and (max-width: 799px) { - div.tiny-bulk-optimization div.savings { - margin-left: 0; - } +.tiny-bulk-optimization .tiny-bulk-title { + margin: 12px 0 0; + padding: 0; + color: var(--tiny-text-primary); + font-size: 30px; + font-weight: 600; + line-height: 38px; } -div.tiny-bulk-optimization div.savings div.inner { - max-width: 600px; - padding: 4px 23px 23px; +.tiny-bulk-hero p { + max-width: 540px; + margin: 12px 0 0; + color: var(--tiny-text-secondary); + font-size: 16px; + line-height: 24px; } -div.tiny-bulk-optimization div.savings div.legend { - margin-left: 50%; -} - -div.tiny-bulk-optimization div.savings div.legend { - /* margin-left defined inline */ - padding: 22px 0; +.tiny-bulk-hero .tiny-bulk-actions { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 12px; + margin-top: 16px; } -div.tiny-bulk-optimization div.savings table { - margin: 0 auto; +.tiny-bulk-hero .tiny-bulk-caption { + font-size: 14px; + line-height: 20px; } -div.tiny-bulk-optimization div.savings table td.value { - font-size: 1.4em; - vertical-align: top; - text-align: right; - padding: 15px 8px 0 5px; - white-space: nowrap; +.tiny-bulk-hero .tiny-bulk-caption:empty { + display: none; } -div.tiny-bulk-optimization div.savings table td.description { - padding: 19px 0 0; - line-height: 14px; - vertical-align: top; - text-align: left; - color: #bbb; +.tiny-bulk-progress { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + max-width: 360px; + margin-top: 16px; + color: var(--tiny-text-primary); + font-size: 14px; + font-weight: 600; } -@media only screen and (max-width: 400px) { - div.tiny-bulk-optimization div.savings div.legend { - margin-left: 0 !important; - padding: 10px 0; - } +.tiny-bulk-progress .tiny-bulk-bar { + flex: 1; } -div.tiny-bulk-optimization div.optimize { - margin: 4px 23px 32px; - text-align: center; - clear: both; +.tiny-bulk-bar { + height: 6px; + overflow: hidden; + background: var(--tiny-surface-subtle); + border-radius: 3px; } -div.tiny-bulk-optimization div.optimize div.progressbar { - position: relative; - height: 32px; - margin-bottom: 32px; - line-height: 32px; - border-radius: 32px; - font-size: 1.2em; - font-weight: bold; - color: #fff; - background-color: #ebebeb; -} - -div.tiny-bulk-optimization div.optimize div.progressbar div.progress { - position: absolute; - left: 0; - min-width: 32px; - width: 0; - height: 32px; - z-index: 2; - border-radius: 16px; - transition: width 1s ease; - background-size: 40px 80px; - -webkit-backface-visibility: hidden; - -webkit-perspective: 1000; - backface-visibility: hidden; - perspective: 1000; +.tiny-bulk-bar span { + display: block; + height: 100%; + background: var(--tiny-green-500); + transition: width 0.3s; } -@keyframes progress-bar { - to { - background-position: 3200px 0; - } +.tiny-bulk-library { + gap: 12px; } -div.tiny-bulk-optimization div.optimize div.progressbar div.numbers { - position: relative; - z-index: 3; - text-shadow: 1px 1px 3px rgba(0,0,0,0.2); +.tiny-bulk-library-head, +.tiny-bulk-legend { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 8px; } -div.tiny-bulk-optimization div.optimize div.optimization-buttons input.button-hero { - display: none; +.tiny-bulk-optimization h3 { + margin: 0; + color: var(--tiny-text-primary); + font-size: 16px; + font-weight: 600; + line-height: 24px; } -div.tiny-bulk-optimization div.optimize div.optimization-buttons input.button-hero.visible { - display: inline; +.tiny-bulk-library-head span, +.tiny-bulk-legend-todo { + color: var(--tiny-text-secondary); } -div.tiny-bulk-optimization div.optimize div.optimization-buttons input.button-hero { - min-width: 230px; +.tiny-bulk-legend { + color: var(--tiny-text-primary); + font-size: 14px; } -div.tiny-bulk-optimization div.optimize div.optimization-buttons input.button-hero.red { - /* WP < 3.8 */ background-image: none; - border-color: #920011; - background-color: #d0021b; - box-shadow: 0 2px 0 #920011 !important; - text-shadow: 0 -1px 1px #920011, 1px 0 1px #920011, 0 1px 1px #920011, -1px 0 1px #920011; +.tiny-bulk-legend span:before { + content: ""; + display: inline-block; + width: 10px; + height: 10px; + margin-right: 8px; + border-radius: 2px; } -div.tiny-bulk-optimization div.optimize div.optimization-buttons input.button-hero.red:focus, -div.tiny-bulk-optimization div.optimize div.optimization-buttons input.button-hero.red:hover { - background-color: #e00016; +.tiny-bulk-legend-done:before { + background: var(--tiny-green-500); } -div.tiny-bulk-optimization div.optimize div.optimization-buttons input.button-hero.red:active { - background-color: #d0021b; - box-shadow: 0 3px 0 #920011 inset !important; +.tiny-bulk-legend-todo:before { + background: var(--tiny-border-emphasis); } -div.tiny-bulk-optimization div.optimize div.optimization-buttons p.optimization-buttons_notice { - max-width: 420px; - margin: 10px auto 0 auto; -} -div.tiny-bulk-optimization div.optimize div#optimization-spinner { - position: absolute; +.tiny-bulk-legend span span:before { display: none; - width: 20px; - height: 20px; - margin-top: 15px; - background-size: 20px 20px; -} - -div.tiny-bulk-optimization table.whitebox { - min-width: 750px; - margin-top: 16px; - border: 1px solid #e5e5e5; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); - background-color: #fff; } -@media only screen and (max-width: 799px) { - div.tiny-bulk-optimization table.whitebox { - min-width: 250px; - } +.tiny-bulk-list { + gap: 8px; } -div.tiny-bulk-optimization table.whitebox th.column-primary { - width: 30%; +.tiny-bulk-items { + margin: 0; } -@media only screen and (max-width: 782px) { - div.tiny-bulk-optimization table.whitebox th.column-primary { - width: 100%; - } +.tiny-bulk-item { + display: flex; + align-items: center; + gap: 12px; + margin: 0; + padding: 8px 0; + border-top: 1px solid var(--tiny-border-default); } -div.tiny-bulk-optimization table.whitebox th.column-author { - /* WP 3.1-4.2 */ width: auto; +.tiny-bulk-item:first-child { + border-top: 0; } -div.tiny-bulk-optimization table.whitebox thead th.thumbnail { - width: 30px; -} - -div.tiny-bulk-optimization table.whitebox th.thumbnail { - width: 30px; +.tiny-bulk-item img { + flex: none; + width: 32px; height: 32px; - padding-top: 6px; - vertical-align: top; -} - -div.tiny-bulk-optimization table.whitebox td { - padding-top: 12px; + object-fit: cover; + background: var(--tiny-surface-subtle); + border-radius: 4px; } -div.tiny-bulk-optimization table.whitebox td.name, -div.tiny-bulk-optimization table.whitebox td.status { - padding-bottom: 12px; +.tiny-bulk-item-name { + display: flex; + flex: 1; + flex-direction: column; + min-width: 0; } -div.tiny-bulk-optimization table.whitebox td.column-primary button { - margin-top: 6px; +.tiny-bulk-item-name strong, +.tiny-bulk-item-name span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } -div.tiny-bulk-optimization button.toggle-row { - /* WP < 4.3 */ display: none; +.tiny-bulk-item-name strong { + color: var(--tiny-text-primary); + font-size: 14px; + font-weight: 600; } -div.tiny-bulk-optimization table.whitebox tr.success button.toggle-row:before { - color: #7acb44; - content: "\f147"; /* yes */ +.tiny-bulk-item-name span { + color: var(--tiny-text-secondary); + font-size: 12px; } -div.tiny-bulk-optimization table.whitebox tr.failed button.toggle-row:before { - color: #d54e21; - content: "\f158"; /* more compatibility*/ +.tiny-bulk-item-status { + flex: none; + max-width: 50%; + overflow: hidden; + color: var(--tiny-text-secondary); + font-size: 14px; + text-overflow: ellipsis; + white-space: nowrap; } -div.tiny-bulk-optimization table.whitebox tr.no-action button.toggle-row:before { - color: gray; - content: "\f158"; /* more compatibility*/ +.tiny-bulk-item[data-status="compressing"] .tiny-bulk-item-status, +.tiny-bulk-item[data-status="compressed"] .tiny-bulk-item-status { + color: var(--tiny-text-primary); } -div.tiny-bulk-optimization table.whitebox tr.failed.is-expanded span.icon { - display: none; +.tiny-bulk-item[data-status="compressing"] .tiny-bulk-item-status:before { + content: ""; + display: inline-block; + width: 12px; + height: 12px; + margin-right: 8px; + vertical-align: -2px; + border: 2px solid var(--tiny-surface-subtle); + border-top-color: var(--tiny-green-500); + border-radius: 50%; + animation: tiny-bulk-spin 1s linear infinite; } -div.tiny-bulk-optimization div.upgrade-account-notice { - padding: 22px 28px; - background-color: #F5F9FA; - text-align: center; +.tiny-bulk-item[data-status="error"] .tiny-bulk-item-status { + color: var(--tiny-red-500); } -div.tiny-bulk-optimization div.upgrade-account-notice div.introduction { - padding-bottom: 10px; +@keyframes tiny-bulk-spin { + to { + transform: rotate(360deg); + } } -div.tiny-bulk-optimization div.upgrade-account-notice p { - margin: 5px 0; +@media (prefers-reduced-motion: reduce) { + .tiny-bulk-item[data-status="compressing"] .tiny-bulk-item-status:before { + animation: none; + } } -div.tiny-bulk-optimization div.upgrade-account-notice p a { - display: block; - margin-top: 10px; - color: #858A93; +.tiny-bulk-footer { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 8px; + padding: 16px 24px; + color: var(--tiny-text-secondary); + font-size: 14px; + background: var(--tiny-surface-page); + border-top: 1px solid var(--tiny-border-default); + border-radius: 0 0 12px 12px; } diff --git a/src/css/optimization-chart.css b/src/css/optimization-chart.css deleted file mode 100644 index 8d3b6f4a..00000000 --- a/src/css/optimization-chart.css +++ /dev/null @@ -1,52 +0,0 @@ -div.tiny-optimization-chart { - float: left; - position: relative; - width: 50%; - text-align: center; -} - -.ie8 div.tiny-optimization-chart { - margin: 0; -} - -div.tiny-optimization-chart svg circle.main { - fill: #ebebeb; - animation: shwoosh 2s ease; - transition: stroke-dasharray 1s ease; -} - -div.tiny-optimization-chart svg circle.inner { - fill: #fff; -} - -div.tiny-optimization-chart div.value { - position: absolute; - top: 0; - left: 0; - width: 100%; - text-align: center; -} - -div.tiny-optimization-chart div.value div.percentage { - width: 50%; - margin-left: auto; - margin-right: auto; - margin-top: 56px; - font-size: 2.1em; - line-height: 1em; -} - -div.tiny-optimization-chart div.value div.label { - width: 50%; - margin-left: auto; - margin-right: auto; - font-size: 1.4em; - line-height: 1.2em; -} - -@media only screen and (max-width: 400px) { - div.tiny-bulk-optimization div.tiny-optimization-chart { - float: none; - width: 100%; - } -} diff --git a/src/js/bulk-optimization.js b/src/js/bulk-optimization.js index 5da2a34e..2f6d0f48 100644 --- a/src/js/bulk-optimization.js +++ b/src/js/bulk-optimization.js @@ -2,351 +2,311 @@ const POLL_INTERVAL = 2000; const POLL_WINDOW = 10; const PAGE_WORKERS = 5; + const config = window.tinyBulk; + const items = config.items; let pending = []; - let stoppedEarly = false; let pageWorkers = 0; + let finished = 0; + let compressed = 0; + let savedBytes = 0; + let creditsUsed = 0; - function updateProgressBar(successFullCompressions) { - var totalToOptimize = parseInt(jQuery('div#compression-progress-bar').data('number-to-optimize'), 10); - - var optimizedSoFar = parseInt(jQuery('#optimized-so-far').text(), 10); - jQuery('#optimized-so-far').html(successFullCompressions + optimizedSoFar); + function element(name) { + return document.querySelector('[data-tiny-bulk="' + name + '"]'); + } - var percentage = '100%'; - if (totalToOptimize > 0) { - percentage = Math.round((successFullCompressions + optimizedSoFar) / totalToOptimize * 100, 1) + '%'; + function setText(name, text) { + const target = element(name); + if (target) { + target.textContent = text; } - jQuery('div#compression-progress-bar #progress-size').css('width', percentage); - jQuery('div#compression-progress-bar #percentage').html('(' + percentage + ')'); - - var numberToOptimize = parseInt(jQuery('#optimizable-image-sizes').html(), 10); - jQuery('#optimizable-image-sizes').html(numberToOptimize - successFullCompressions); } - function updateSavings(successFullCompressions, successFullSaved, newHumanReadableLibrarySize) { - window.currentLibraryBytes = window.currentLibraryBytes + successFullSaved; + // Fills in %s, or %1$s, %2$s, like PHP's sprintf. + function format(template) { + const values = Array.prototype.slice.call(arguments, 1); + let next = 0; + return template.replace(/%(?:(\d)\$)?s/g, function(match, position) { + return position ? values[position - 1] : values[next++]; + }); + } - var imagesSizedOptimized = parseInt(jQuery('#optimized-image-sizes').text(), 10) + successFullCompressions; - var initialLibraryBytes = parseInt(jQuery('#unoptimized-library-size').data('bytes'), 10); - var percentage = (1 - window.currentLibraryBytes / initialLibraryBytes); - var chartSize = jQuery('div#optimization-chart').data('full-circle-size'); + function plural(count, singular, pluralForm) { + return format(count === 1 ? singular : pluralForm, count.toLocaleString()); + } - jQuery('#optimized-image-sizes').html(imagesSizedOptimized); - jQuery('#optimized-library-size').attr('data-bytes', window.currentLibraryBytes); - jQuery('#optimized-library-size').html(newHumanReadableLibrarySize); - jQuery('#savings-percentage').html(Math.round(percentage * 1000) / 10 + '%'); - jQuery('div#optimization-chart svg circle.main').css('stroke-dasharray', '' + (chartSize * percentage) + ' ' + chartSize); + function formatBytes(bytes) { + const units = ['B', 'KB', 'MB', 'GB', 'TB']; + let unit = 0; + while (bytes >= 1024 && unit < units.length - 1) { + bytes /= 1024; + unit++; + } + return bytes.toLocaleString(undefined, { maximumFractionDigits: 1 }) + ' ' + units[unit]; } - function handleCancellation() { - jQuery('div#bulk-optimization-actions').hide(); - jQuery('div.progress').css('animation', 'none'); + async function post(action, data) { + const body = new URLSearchParams(Object.assign({ _nonce: tinyCompress.nonce, action: action }, data)); + const response = await fetch(ajaxurl, { method: 'POST', body: body, credentials: 'same-origin' }); + if (!response.ok) { + const error = new Error(response.statusText); + error.status = response.status; + throw error; + } + const json = await response.json(); + return json.data; } - function updateRowAfterCompression(row, data) { - var successFullCompressions = parseInt(data.success, 10); - var successFullSaved = parseInt(data.size_change, 10); - var newHumanReadableLibrarySize = data.human_readable_library_size; - if (successFullCompressions === 0) { - row.addClass('no-action'); - row.find('.status').html('' + tinyCompress.L10nNoActionTaken).attr('data-status', 'no-action-taken'); - } else { - row.addClass('success'); - const rowResultElement = row.find('.status'); - rowResultElement.attr('data-status', 'compressed'); - const icon = ''; - - let successHTML = ''; - if (data.image_sizes_compressed > 0) { - successHTML += `

${icon} ${data.image_sizes_compressed} ${tinyCompress.L10nCompressed}

`; - } + function showHero(state) { + document.querySelectorAll('[data-tiny-bulk-hero]').forEach(function(hero) { + hero.hidden = hero.getAttribute('data-tiny-bulk-hero') !== state; + }); + } - if (data.image_sizes_converted > 0) { - successHTML += `

${icon} ${data.image_sizes_converted} ${tinyCompress.L10nConverted}

`; + function drawRows() { + const list = document.getElementById('tiny-bulk-items'); + if (!list) { + return; + } + items.forEach(function(item, i) { + const row = document.createElement('li'); + row.className = 'tiny-bulk-item'; + row.setAttribute('data-status', 'waiting'); + + const thumbnail = document.createElement('img'); + thumbnail.loading = 'lazy'; + thumbnail.alt = ''; + if (item.thumbnail) { + thumbnail.src = item.thumbnail; } - rowResultElement.html(successHTML); - - updateProgressBar(successFullCompressions); - updateSavings(successFullCompressions, successFullSaved, newHumanReadableLibrarySize); - } + const name = document.createElement('div'); + name.className = 'tiny-bulk-item-name'; + const title = document.createElement('strong'); + title.textContent = item.post_title; + const details = document.createElement('span'); + details.textContent = item.file + ', ' + + plural(item.sizes, tinyCompress.L10nSize, tinyCompress.L10nSizes) + ', ' + + formatBytes(item.bytes); + name.append(title, details); + + const status = document.createElement('span'); + status.className = 'tiny-bulk-item-status'; + status.setAttribute('data-testid', 'bulk-item-status-' + i); + status.textContent = tinyCompress.L10nWaiting; + + row.append(thumbnail, name, status); + list.append(row); + }); } - function bulkOptimizationCallback(data, items, i) { - var row = jQuery('#optimization-items tr').eq(parseInt(i, 10)+1); + function setRowStatus(i, status, text) { + const row = document.getElementById('tiny-bulk-items').children[i]; + row.setAttribute('data-status', status); + row.querySelector('.tiny-bulk-item-status').textContent = text; + return row; + } - if (data.failed > 0) { - row.addClass('failed'); - row.find('.status').html('' + tinyCompress.L10nLatestError + ': ' + data.message + ''); - row.find('.status').attr('title', data.message); - row.find('.status').attr('data-status', 'error'); + function applyResult(i, result) { + finished++; + if (result.failed > 0) { + setRowStatus(i, 'error', result.message).title = result.message; + } else if (parseInt(result.success, 10) === 0) { + setRowStatus(i, 'no-action', tinyCompress.L10nNoActionTaken); } else { - updateRowAfterCompression(row, data); + compressed++; + savedBytes -= parseInt(result.size_change, 10); + setRowStatus(i, 'compressed', format( + tinyCompress.L10nSmaller, + result.optimized_total_size, + Math.round(result.savings) + '%' + )); } + } - row.find('.name').html(items[i].post_title + ''); - - if (!data.image_sizes_compressed) { - data.image_sizes_compressed = '-'; - } - if (!data.initial_total_size) { - data.initial_total_size = '-'; + function secondsLeftText() { + const sizesLeft = pending.reduce(function(sum, i) { + return sum + items[i].sizes; + }, 0); + const seconds = Math.round(sizesLeft / config.workers); + if (seconds < 60) { + return tinyCompress.L10nLessThanMinute; } - if (!data.optimized_total_size) { - data.optimized_total_size = '-'; - } - if (!data.savings || data.savings === 0) { - data.savings = '-'; - } else { - data.savings += '%'; + if (seconds < 90 * 60) { + return plural(Math.round(seconds / 60), tinyCompress.L10nMinuteLeft, tinyCompress.L10nMinutesLeft); } + return plural(Math.round(seconds / 3600), tinyCompress.L10nHourLeft, tinyCompress.L10nHoursLeft); + } - row.find('.thumbnail').html(data.thumbnail); - row.find('.sizes-compressed').html(data.image_sizes_compressed); - row.find('.initial-size').html(data.initial_total_size); - row.find('.optimized-size').html(data.optimized_total_size); - row.find('.savings').html(data.savings); + function updateNumbers() { + const runPercentage = Math.floor(finished / items.length * 100) + '%'; + setText('run-done', finished.toLocaleString()); + setText('run-percentage', runPercentage); + element('run-bar').style.width = runPercentage; + setText('run-status', secondsLeftText() + ' ' + format( + tinyCompress.L10nRunStatus, + formatBytes(savedBytes), + plural(creditsUsed, tinyCompress.L10nCredit, tinyCompress.L10nCredits) + )); + + const libraryCompressed = config.imagesOptimized + compressed; + const libraryPercentage = Math.floor(libraryCompressed / config.imagesTotal * 100); + setText('library-percentage', libraryPercentage.toLocaleString()); + setText('library-compressed', libraryCompressed.toLocaleString()); + setText('library-todo', format(tinyCompress.L10nToGo, (config.imagesRemaining - compressed).toLocaleString())); + element('library-bar').style.width = libraryPercentage + '%'; + setText('waiting', pending.length.toLocaleString()); + + const librarySaved = config.bytesSaved + savedBytes; + setText('stat-compressed', libraryCompressed.toLocaleString()); + setText('stat-saved', formatBytes(librarySaved)); + setText('stat-average', Math.round(librarySaved / config.initialSize * 100) + '%'); + setText('done-saved', formatBytes(librarySaved)); } - function finishOptimization(message) { - if (message) { - const notice = jQuery('

'); - notice.find('p').text(message); - notice.insertAfter(jQuery('#tiny-bulk-optimization h2')); + // Shows the done hero when every image was compressed. Otherwise the run was + // paused or stopped, or some images failed, and the page reloads to show + // what is left. + function finishRun() { + if (pending.length > 0 || compressed < items.length) { + location.reload(); + return; } - jQuery('div#optimization-spinner').css('display', 'none'); - handleCancellation(); + const title = element('list-title'); + title.textContent = title.getAttribute('data-done'); + element('list-waiting').hidden = true; + setText('library-todo', format(tinyCompress.L10nToCompress, '0')); + showHero('done'); } // The queue works through the images in the order they are listed, so only // the first few waiting ones need asking about. - function pollStatus(items) { + async function pollStatus() { const batch = pending.slice(0, POLL_WINDOW); - drawSomeRows(items, batch[batch.length - 1] + 1); - jQuery.post(ajaxurl, { - _nonce: tinyCompress.nonce, - action: 'tiny_bulk_queue_status', - ids: batch.map(function(i) { return items[i].ID; }).join(','), - current_size: window.currentLibraryBytes - }, function(response) { - const data = response.data; + try { + const data = await post('tiny_bulk_queue_status', { + ids: batch.map(function(i) { return items[i].ID; }).join(',') + }); const running = data.running || pageWorkers > 0; - let finished = 0; - const waiting = batch.filter(function(i) { + const finishedBefore = finished; + creditsUsed = data.compression_count - config.compressionCount; + + batch.forEach(function(i) { const item = data.items[items[i].ID] || {}; if (item.status === 'done' || item.status === 'failed') { - bulkOptimizationCallback(item.result, items, i); - finished++; - } else if (running && (item.status === 'queued' || item.status === 'processing')) { - return true; - } else { - // Unless this page cancelled, the run ended because every worker stopped. - const label = window.optimizationCancelled ? tinyCompress.L10nCancelled : tinyCompress.L10nStopped; - jQuery('#optimization-items tr').eq(i + 1).find('.status').html(label).attr('data-status', 'cancelled'); - stoppedEarly = true; + applyResult(i, item.result); + pending = pending.filter(function(p) { return p !== i; }); + } else if (item.status === 'processing') { + setRowStatus(i, 'compressing', tinyCompress.L10nCompressing); } - return false; }); - pending = waiting.concat(pending.slice(batch.length)); + updateNumbers(); - if (pending.length > 0 && (running || finished > 0)) { - setTimeout(pollStatus, POLL_INTERVAL, items); - } else if (window.optimizationCancelled) { - finishOptimization(null); + if (pending.length > 0 && (running || finished > finishedBefore)) { + setTimeout(pollStatus, POLL_INTERVAL); } else { - finishOptimization(stoppedEarly ? tinyCompress.L10nStoppedNotice : tinyCompress.L10nAllDone); + finishRun(); } - }, 'json').fail(function(xhr) { - if (xhr.status === 403) { - finishOptimization(tinyCompress.L10nInternalError); + } catch (error) { + if (error.status === 403) { + setText('run-notice', tinyCompress.L10nInternalError); } else { - setTimeout(pollStatus, POLL_INTERVAL, items); + setTimeout(pollStatus, POLL_INTERVAL); } - }); + } } /** * When the page cannot reach itself (loopbacks are not supported), * the page works through the queue one image per request until none are left */ - function optimizeInPage() { - jQuery.post(ajaxurl, { - _nonce: tinyCompress.nonce, - action: 'tiny_bulk_queue_optimize_next' - }, function(response) { - if (response.data.optimized) { + async function optimizeInPage() { + try { + const data = await post('tiny_bulk_queue_optimize_next'); + if (data.optimized) { optimizeInPage(); } else { pageWorkers--; } - }, 'json').fail(function(xhr) { - if (xhr.status === 403) { + } catch (error) { + if (error.status === 403) { pageWorkers--; } else { setTimeout(optimizeInPage, POLL_INTERVAL); } - }); - } - - function prepareBulkOptimization(items, running, startOnLoad) { - window.allBulkOptimizationItems = items; - updateProgressBar(0); - if (running) { - startBulkOptimization(items, true); } - startFromUrl(items, running, startOnLoad); } - // The dashboard widget opens this page with &start=1 and a nonce, which the - // server checks. Start right away, then drop both from the URL so a reload - // does not start again. - function startFromUrl(items, running, startOnLoad) { - const url = new URL(location.href); - if (url.searchParams.has('start')) { - url.searchParams.delete('start'); - url.searchParams.delete('_wpnonce'); - history.replaceState(null, '', url); - } - if (!startOnLoad || running) { - return; - } - - const start = document.getElementById('id-start'); - if (start && start.offsetParent !== null) { - jQuery('#hide-warning').trigger('click'); - startBulkOptimization(items); - } + function showRun() { + const title = element('list-title'); + title.textContent = title.getAttribute('data-compressing'); + showHero('compressing'); + updateNumbers(); } - function startBulkOptimization(items, running) { - window.optimizationCancelled = false; - window.totalRowsDrawn = 0; - window.currentLibraryBytes = parseInt(jQuery('#optimized-library-size').data('bytes'), 10); + async function startRun() { pending = items.map(function(item, i) { return i; }); - stoppedEarly = false; - - const notice = jQuery('div#bulk-optimization-actions p.optimization-buttons_notice'); - jQuery('div#bulk-optimization-actions input').removeClass('visible'); - jQuery('div.progress').css('animation', 'progress-bar 80s linear infinite'); - jQuery('div#optimization-spinner').css('display', 'inline-block'); - updateProgressBar(0); - - if (running) { - notice.text(tinyCompress.L10nBackgroundNotice); - jQuery('div#bulk-optimization-actions input#id-optimizing').addClass('visible'); - pollStatus(items); - return; - } - - jQuery.post(ajaxurl, { - _nonce: tinyCompress.nonce, - action: 'tiny_bulk_queue_start' - }, function(response) { - if (response.data.background) { - notice.text(tinyCompress.L10nBackgroundNotice); + showRun(); + try { + const data = await post('tiny_bulk_queue_start'); + if (data.background) { + setText('run-notice', tinyCompress.L10nBackgroundNotice); } else { - notice.text(tinyCompress.L10nInPageNotice); + setText('run-notice', tinyCompress.L10nInPageNotice); for (let i = 0; i < PAGE_WORKERS; i++) { pageWorkers++; optimizeInPage(); } } - jQuery('div#bulk-optimization-actions input#id-optimizing').addClass('visible'); - pollStatus(items); - }, 'json').fail(function() { - finishOptimization(tinyCompress.L10nInternalError); - }); - } - - function drawSomeRows(items, end) { - const list = jQuery('#optimization-items tbody'); - const start = window.totalRowsDrawn; - end = Math.min(end, items.length); - for (let i = start; i < end; i++) { - const tableRow = ` - - ${items[i].post_title} - - - - ${tinyCompress.L10nWaiting} - `; - list.append(tableRow); + pollStatus(); + } catch (error) { + setText('run-notice', tinyCompress.L10nInternalError); } - window.totalRowsDrawn = Math.max(start, end); } - async function cancelOptimization() { + async function pauseRun() { + const button = element('pause'); + button.disabled = true; + button.textContent = tinyCompress.L10nPausing; try { - window.optimizationCancelled = true; - jQuery('div#optimization-spinner').css('display', 'none'); - jQuery('div#bulk-optimization-actions input').removeClass('visible'); - jQuery('div#bulk-optimization-actions input#id-cancelling').addClass('visible'); - await jQuery.post(ajaxurl, { - _nonce: tinyCompress.nonce, - action: 'tiny_bulk_queue_cancel', - }); - } catch (err) { - // Cancel failed, revert state - window.optimizationCancelled = false; - jQuery('div#optimization-spinner').css('display', 'inline-block'); - jQuery('div#bulk-optimization-actions input').removeClass('visible'); - jQuery('div#bulk-optimization-actions input#id-optimizing').addClass('visible'); - jQuery('div#bulk-optimization-actions p.optimization-buttons_notice').text(tinyCompress.L10nInternalError); + await post('tiny_bulk_queue_cancel'); + } catch (error) { + button.disabled = false; + button.textContent = tinyCompress.L10nPause; + setText('run-notice', tinyCompress.L10nInternalError); } } - jQuery('.tiny-bulk-optimization .upgrade-account-notice a#hide-warning').click(function() { - jQuery('.tiny-bulk-optimization .upgrade-account-notice').hide(); - jQuery('.tiny-bulk-optimization .optimize').children().show(); - }); - - jQuery('div#bulk-optimization-actions input').click(function() { - if ((jQuery(this).attr('id') === 'id-start') && jQuery(this).hasClass('visible')) { - startBulkOptimization(window.allBulkOptimizationItems); - } - if ((jQuery(this).attr('id') === 'id-cancel') && jQuery(this).hasClass('visible')) { - cancelOptimization(); - } - }); - - jQuery('div#bulk-optimization-actions input').hover(function() { - if ((jQuery(this).attr('id') === 'id-optimizing') && jQuery(this).hasClass('visible')) { - window.lastActiveButton = jQuery('div#bulk-optimization-actions input.visible'); - window.lastActiveButton.removeClass('visible'); - jQuery('div#bulk-optimization-actions input#id-cancel').addClass('visible'); + // The dashboard widget opens this page with &start=1 and a nonce, which the + // server checks. Start right away, then drop both from the URL so a reload + // does not start again. + function startFromUrl() { + const url = new URL(location.href); + if (url.searchParams.has('start')) { + url.searchParams.delete('start'); + url.searchParams.delete('_wpnonce'); + history.replaceState(null, '', url); } - }, function() { - if ((jQuery(this).attr('id') === 'id-cancel') && jQuery(this).hasClass('visible')) { - window.lastActiveButton.addClass('visible'); - jQuery('div#bulk-optimization-actions input#id-cancel').removeClass('visible'); + if (config.startOnLoad && !config.running && element('start')) { + startRun(); } - }); - - function attachToolTipEventHandlers() { - var tooltip = '#tiny-bulk-optimization div.tooltip'; - var tip = 'div.tip'; - var toolTipTimeout = null; - jQuery(tooltip).mouseleave(function(){ - var that = this; - toolTipTimeout = setTimeout(function() { - if (jQuery(that).find(tip).is(':visible')) { - jQuery(tooltip).find(tip).hide(); - } - }, 100); - }); - jQuery(tooltip).mouseenter(function(){ - jQuery(this).find(tip).show(); - clearTimeout(toolTipTimeout); - }); - jQuery(tooltip).find(tip).mouseenter(function(){ - clearTimeout(toolTipTimeout); - }); } - attachToolTipEventHandlers(); + drawRows(); - window.bulkOptimizationAutorun = startBulkOptimization; - window.bulkOptimization = prepareBulkOptimization; + document.querySelectorAll('[data-tiny-bulk="start"]').forEach(function(button) { + button.addEventListener('click', startRun); + }); + if (element('pause')) { + element('pause').addEventListener('click', pauseRun); + } + if (config.running) { + pending = items.map(function(item, i) { return i; }); + setText('run-notice', tinyCompress.L10nBackgroundNotice); + showRun(); + pollStatus(); + } else { + startFromUrl(); + } }).call(); diff --git a/src/views/account-status-connected.php b/src/views/account-status-connected.php index a640acb9..be6e57b4 100644 --- a/src/views/account-status-connected.php +++ b/src/views/account-status-connected.php @@ -9,6 +9,7 @@ * @type string|null $message Optional status message. * } * @var string $key The API key. + * @var bool $link_to_settings Whether Change account links to the settings page. */ // Only free accounts have a limited number of credits, including @@ -112,6 +113,10 @@ ); ?> + + + + + + + = 1 ) { ?> + + + +

+

+ +

+ + +

+ 0', + esc_html( number_format_i18n( count( $items ) ) ) + ); + ?> +

+
+
+ +
+ 0% +
+

+

+ +

+

+ + +

+ +

+

+ ' . esc_html( size_format( $widget['bytes_saved'], 0 ) ) . '' + ); + if ( $widget['auto_compress'] ) { + echo ' '; + esc_html_e( 'New uploads are compressed automatically.', 'tiny-compress-images' ); + } + ?> +

+ +
diff --git a/src/views/bulk-optimization-upgrade-notice.php b/src/views/bulk-optimization-upgrade-notice.php deleted file mode 100644 index f2272b27..00000000 --- a/src/views/bulk-optimization-upgrade-notice.php +++ /dev/null @@ -1,51 +0,0 @@ - - diff --git a/src/views/bulk-optimization.php b/src/views/bulk-optimization.php index 025dc298..a7ae20a4 100644 --- a/src/views/bulk-optimization.php +++ b/src/views/bulk-optimization.php @@ -2,346 +2,187 @@ /** * Bulk optimization view. * - * @var array $admin_colors - * @var array $stats - * @var array $active_tinify_sizes - * @var float $estimated_costs - * @var string $email_address - * @var bool $is_on_free_plan - * @var int $remaining_credits - * @var bool $bulk_running + * @var array $stats See Tiny_Bulk_Optimization::get_optimization_statistics(). + * @var array $widget See Tiny_Dashboard::get_widget_data(). + * @var string $state The widget state, or no_sizes. + * @var string $account_status The rendered account card. + * @var int $compression_count Compressions made this month so far. + * @var bool $start_on_load * @var Tiny_Plugin $this */ -$total_sizes = $stats['optimized-image-sizes'] + $stats['available-unoptimized-sizes']; -$settings_url = admin_url( 'options-general.php?page=tinify' ); -$friendly_name = $this->friendly_user_name(); -?> - +$has_library_bar = ! in_array( $state, array( 'pending', 'empty', 'no_sizes' ), true ); +$has_list = count( $items ) > 0 && 'pending' !== $state; +$strong = array( 'strong' => array() ); +?> +
+

+

+ +

+
+ +
+
+
+ -
-

-

-
-
-
-
-

-

- '; - require __DIR__ . '/request-review.php'; - } elseif ( $stats['optimized-image-sizes'] > 0 ) { - if ( $percentage_of_files > 75 ) { - /* translators: %s: friendly user name */ - printf( esc_html__( '%s, you are doing great!', 'tiny-compress-images' ), esc_html( $friendly_name ) ); + +

+
+

+ + ' . esc_html( number_format_i18n( $widget['percentage'] ) ) . '' + ); + ?> + +
+
+ +
+
+ + ' . esc_html( number_format_i18n( $widget['images_optimized'] ) ) . '', + esc_html( number_format_i18n( $widget['images_total'] ) ) + ); + ?> + + + + +
+
+ + + +
+

+ -

- -

- -

- - - - - - - -
-

- images', 'tiny-compress-images' ), - array( - 'br' => array(), - ) - ) - ?> -

- - - -
-

- image sizes', 'tiny-compress-images' ), - array( - 'br' => array(), - ) - ) - ?> -

- - - -
- -
- 0 && count( $active_tinify_sizes ) > 0 && $stats['available-unoptimized-sizes'] > 0 ) { ?> -

- -

- -

- '; - $active_tinify_sizes_count = count( $active_tinify_sizes ); - for ( $i = 0; $i < $active_tinify_sizes_count; ++$i ) { - $name = $active_tinify_sizes[ $i ]; - if ( '0' == $name ) { - echo '

  • - ' . esc_html__( 'Original image', 'tiny-compress-images' ) . '
  • '; - } else { - echo '
  • - ' . esc_html( ucfirst( $name ) ) . '
  • '; - } - } - echo ''; - } - ?> -

    -

    - 0 ) { ?> - %d size is optimized.', 'For each uploaded image %d sizes are optimized.', count( $active_tinify_sizes ), 'tiny-compress-images' ), - array( - 'strong' => array(), - ) - ), - count( $active_tinify_sizes ) - ) - ?> - - array( - 'href' => array(), - ), - ) - ), - '' . esc_html__( 'here', 'tiny-compress-images' ) . '' - ) - ?> -

    -
    -
    -
    -

    - cost', 'tiny-compress-images' ), - array( - 'br' => array(), - ) - ) - ?> -

    - $ - USD - 0 ) { ?> -
    - -
    -

    - %1$d %2$s a month and you are still on a free account %3$s.', 'tiny-compress-images' ), - array( - 'strong' => array(), - 'a' => array( - 'href' => array(), - ), - ) - ), - (int) Tiny_Config::MONTHLY_FREE_COMPRESSIONS, - esc_html__( 'image sizes', 'tiny-compress-images' ), - '' . esc_html__( ' upgrade here', 'tiny-compress-images' ) . '' - ); - ?> -

    -
    -
    - -
    -
    - array( - 'href' => array(), - ), - ) - ), - '' . esc_html__( 'here', 'tiny-compress-images' ) . '' - ) - ?> + ?> +

    +
      -
      -
      -
      -
      -

      -

      - -

      - -
      - - - - - - - - - - - - - -
      - - - -
      - - - -
      - - - -
      + + + + -
      +
      - $remaining_credits; ?> -
      -
      -
      -
      -
      - - / - - -
      -
      + +
      0 ) { - require_once __DIR__ . '/bulk-optimization-form.php'; - } + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Rendered by Tiny_Settings::render_account_status(), which escapes its output. + echo $account_status; ?> + +
      +
      +
      +

      +
      + +
      +
      + + settings->render_credits( $can_manage ); ?>
      -
      - - - - - - - - - - - - - - - -
      + diff --git a/src/views/optimization-chart.php b/src/views/optimization-chart.php deleted file mode 100644 index d9cb1931..00000000 --- a/src/views/optimization-chart.php +++ /dev/null @@ -1,55 +0,0 @@ - - - -
      - - - - -
      -
      %
      -
      -
      -
      diff --git a/src/views/request-review.php b/src/views/request-review.php deleted file mode 100644 index 0d43993f..00000000 --- a/src/views/request-review.php +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/views/settings-credits.php b/src/views/settings-credits.php index 03966b13..b5100c53 100644 --- a/src/views/settings-credits.php +++ b/src/views/settings-credits.php @@ -1,7 +1,7 @@
      -
      -
      -

      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - +
      +
      +

      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      \ No newline at end of file diff --git a/test/integration/bulkoptimization.spec.ts b/test/integration/bulkoptimization.spec.ts index 369279e5..3a79753b 100644 --- a/test/integration/bulkoptimization.spec.ts +++ b/test/integration/bulkoptimization.spec.ts @@ -47,85 +47,63 @@ test.describe('bulkoptimization', () => { }]); } - test('display upgrade button for account with insufficient credits', async () => { + test('offer an upgrade next to a smaller run for an account with insufficient credits', async () => { await setAPIKey(page, 'INSUFFICIENTCREDITS123'); - await setCompressionTiming(page, 'auto'); - await enableCompressionSizes(page, ['0', 'thumbnail', 'medium']); - - await uploadImages(page, 'input-example.jpg'); + await setCompressionTiming(page, 'manual'); + await enableCompressionSizes(page, ['0']); + await uploadImages(page, 'input-example.jpg', 2, { generateSizes: false }); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await expect(page.getByText('Upgrade account')).toBeVisible(); - await expect(page.getByRole('link', { name: 'No thanks, continue anyway' })).toBeVisible(); + await expect(page.getByText('Not enough credits')).toBeVisible(); + await expect(page.getByRole('link', { name: 'Upgrade' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Compress 1 image' })).toBeVisible(); }); - test('not display dismiss link for no credits', async () => { + test('only offer an upgrade for an account without credits', async () => { await setAPIKey(page, 'NOCREDITS123'); - await setCompressionTiming(page, 'auto'); - await enableCompressionSizes(page, ['0', 'thumbnail', 'medium']); - - await uploadImages(page, 'input-example.jpg'); + await setCompressionTiming(page, 'manual'); + await enableCompressionSizes(page, ['0']); + await uploadImages(page, 'input-example.jpg', 1, { generateSizes: false }); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await expect(page.getByText('Upgrade account')).toBeVisible(); - await expect(page.getByRole('link', { name: 'No thanks, continue anyway' })).not.toBeVisible(); + await expect(page.getByText('Out of credits')).toBeVisible(); + await expect(page.getByRole('link', { name: 'Upgrade' })).toBeVisible(); + await expect(page.getByRole('button', { name: /^Compress/ })).toHaveCount(0); }); - test('show bulk optimization button after dismissing notice', async () => { - await setAPIKey(page, 'INSUFFICIENTCREDITS123'); - await setCompressionTiming(page, 'auto'); - await enableCompressionSizes(page, ['0', 'thumbnail', 'medium']); - - await uploadImages(page, 'input-example.jpg'); + test('not offer an upgrade to paid accounts', async () => { + await setAPIKey(page, 'PAID123'); + await setCompressionTiming(page, 'manual'); + await enableCompressionSizes(page, ['0']); + await uploadImages(page, 'input-example.jpg', 1, { generateSizes: false }); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await page.getByRole('link', { name: 'No thanks, continue anyway' }).click(); - - await expect(page.getByRole('button', { name: 'Start Bulk Optimization' })).toBeVisible(); + await expect(page.getByText('Ready to compress')).toBeVisible(); + await expect(page.getByRole('link', { name: 'Upgrade' })).toHaveCount(0); }); - test('show notice after dismissing notice and refreshing page', async () => { - await setAPIKey(page, 'INSUFFICIENTCREDITS123'); - await setCompressionTiming(page, 'auto'); + test('show the empty library', async () => { await enableCompressionSizes(page, ['0', 'thumbnail', 'medium']); - await uploadImages(page, 'input-example.jpg'); - await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await page.getByRole('link', { name: 'No thanks, continue anyway' }).click(); - - await page.reload(); - - await expect(page.getByRole('button', { name: 'Start Bulk Optimization' })).not.toBeVisible(); - await expect(page.getByRole('link', { name: 'Upgrade account' })).toBeVisible(); - await expect(page.getByRole('link', { name: 'No thanks, continue anyway' })).toBeVisible(); + await expect(page.getByRole('heading', { name: 'No images yet' })).toBeVisible(); + await expect(page.getByRole('link', { name: 'Upload images' })).toBeVisible(); }); - test('not display upgrade button for paid accounts', async () => { - await setAPIKey(page, 'PAID123'); - - await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - - await expect(page.getByText('Upgrade account')).not.toBeVisible(); - }); - - test('summary should display correct values for empty library', async () => { - await enableCompressionSizes(page, ['0', 'thumbnail', 'medium']); + test('show that no image sizes are selected', async () => { + await setAPIKey(page, 'JPG123'); + await setCompressionTiming(page, 'manual'); + await uploadImages(page, 'input-example.jpg', 1, { generateSizes: false }); + await enableCompressionSizes(page, []); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await expect(page.locator('#uploaded-images')).toHaveText('0'); - await expect(page.locator('#optimizable-image-sizes')).toHaveText('0'); - await expect(page.locator('#estimated-cost')).toHaveText('$ 0.00'); - await expect(page.locator('#optimized-image-sizes')).toHaveText('0'); - await expect(page.locator('#unoptimized-library-size')).toHaveText('-'); - await expect(page.locator('#optimized-library-size')).toHaveText('-'); - await expect(page.locator('#savings-percentage')).toHaveText('0%'); - await expect(page.locator('#compression-progress-bar')).toHaveText('0 / 0 (100%)'); + await expect(page.getByRole('heading', { name: 'No image sizes selected' })).toBeVisible(); + await expect(page.getByRole('link', { name: 'Change settings' }).first()).toBeVisible(); }); test('bulk optimize webp images', async () => { @@ -147,9 +125,8 @@ test.describe('bulkoptimization', () => { await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await expect(page.locator('#uploaded-images')).toHaveText('3'); - await expect(page.locator('#optimizable-image-sizes')).toHaveText('5'); - await expect(page.locator('#optimized-image-sizes')).toHaveText('4'); + await expect(page.getByRole('heading', { name: '2 images to compress' })).toBeVisible(); + await expect(page.getByText('1 of 3 compressed')).toBeVisible(); }); test('summary should display correct values', async () => { @@ -167,18 +144,12 @@ test.describe('bulkoptimization', () => { await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - // We uploaded 3 images - await expect(page.locator('#uploaded-images')).toHaveText('3'); - await expect(page.locator('#optimizable-image-sizes')).toHaveText('5'); - await expect(page.locator('#optimized-image-sizes')).toHaveText('4'); - - // Comparing byte sizes is unreliable at the moment. We need to figure out - // why there are differences between environments and versions. - // await expect(page.locator('#unoptimized-library-size')).toHaveText('3.03 MB'); - // await expect(page.locator('#optimized-library-size')).toHaveText('2.36 MB'); - // await expect(page.locator('#savings-percentage')).toHaveText('22.2%'); - - await expect(page.locator('#compression-progress-bar')).toHaveText('4 / 9 (44%)'); + await expect(page.getByRole('heading', { name: '2 images to compress' })).toBeVisible(); + await expect(page.getByText('1 of 3 compressed')).toBeVisible(); + await expect(page.getByText('2 to compress')).toBeVisible(); + await expect(page.getByTestId('bulk-item-status-0')).toHaveText('Waiting'); + await expect(page.getByTestId('bulk-item-status-1')).toHaveText('Waiting'); + await expect(page.getByText('2 waiting')).toBeVisible(); }); test('start bulk optimization should optimize remaining images', async () => { @@ -196,14 +167,13 @@ test.describe('bulkoptimization', () => { await setBulkBehaviour(page, { loopbackSupported: true }); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); + await page.getByRole('button', { name: 'Compress 2 images' }).click(); - await expect(page.locator('#optimizable-image-sizes')).toHaveText('5'); - await expect(page.locator('#compression-progress-bar')).toHaveText('4 / 9 (44%)'); - - await page.getByRole('button', { name: 'Start Bulk Optimization' }).click(); - - await expect(page.locator('.optimization-buttons_notice')).toContainText('continues in the background'); - await expect(page.locator('#compression-progress-bar')).toHaveText('9 / 9 (100%)'); + // A short run can be done before the notice is checked, so it may already be hidden. + await expect(page.locator('[data-tiny-bulk="run-notice"]')).toContainText('continues in the background'); + await expect(page.getByRole('heading', { name: 'All 3 images are compressed' })).toBeVisible({ timeout: 15000 }); + await expect(page.getByRole('heading', { name: 'Recently compressed' })).toBeVisible(); + await expect(page.getByTestId('bulk-item-status-0')).toContainText('smaller'); }); test('start bulk optimization without loopback should optimize remaining images in the page', async () => { @@ -221,14 +191,10 @@ test.describe('bulkoptimization', () => { await setBulkBehaviour(page, { loopbackSupported: false }); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); + await page.getByRole('button', { name: 'Compress 2 images' }).click(); - await expect(page.locator('#optimizable-image-sizes')).toHaveText('5'); - await expect(page.locator('#compression-progress-bar')).toHaveText('4 / 9 (44%)'); - - await page.getByRole('button', { name: 'Start Bulk Optimization' }).click(); - - await expect(page.locator('.optimization-buttons_notice')).toContainText('keep this page open'); - await expect(page.locator('#compression-progress-bar')).toHaveText('9 / 9 (100%)'); + await expect(page.locator('[data-tiny-bulk="run-notice"]')).toContainText('keep this page open'); + await expect(page.getByRole('heading', { name: 'All 3 images are compressed' })).toBeVisible({ timeout: 15000 }); }); test('background optimization continues when page is refreshed', async () => { @@ -239,16 +205,17 @@ test.describe('bulkoptimization', () => { await setBulkBehaviour(page, { loopbackSupported: true, compressionDuration: 10 }); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await page.getByRole('button', { name: 'Start Bulk Optimization' }).click(); - await expect(page.locator('.optimization-buttons_notice')).toContainText('continues in the background'); + await page.getByRole('button', { name: 'Compress 1 image' }).click(); + await expect(page.getByText('continues in the background')).toBeVisible(); await page.reload(); - await expect(page.locator('.optimization-buttons_notice')).toContainText('continues in the background'); - await expect(page.locator('#compression-progress-bar')).toHaveText('1 / 1 (100%)', { timeout: 15000 }); + await expect(page.getByRole('heading', { name: 'Compressing 0 of 1 image' })).toBeVisible(); + await expect(page.getByText('continues in the background')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'All 1 image is compressed' })).toBeVisible({ timeout: 15000 }); }); - test('cancel will clear the queue', async () => { + test('pause returns to the images that are left', async () => { await setAPIKey(page, 'JPG123'); await setCompressionTiming(page, 'manual'); await enableCompressionSizes(page, ['0']); @@ -256,17 +223,16 @@ test.describe('bulkoptimization', () => { await setBulkBehaviour(page, { loopbackSupported: false, compressionDuration: 5 }); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await page.getByRole('button', { name: 'Start Bulk Optimization' }).click(); - await expect(page.locator('.optimization-buttons_notice')).toContainText('keep this page open'); + await page.getByRole('button', { name: 'Compress 6 images' }).click(); + await expect(page.getByText('keep this page open')).toBeVisible(); - // The cursor still rests where Start was clicked, so Optimizing can already have turned into Cancel. - await page.locator('#id-optimizing, #id-cancel').filter({ visible: true }).hover(); - await page.locator('#id-cancel').click(); + await page.getByRole('button', { name: 'Pause' }).click(); + await expect(page.getByRole('button', { name: 'Pausing...' })).toBeDisabled(); - // Images that were being compressed finish, the others are cancelled. - await expect(page.locator('#bulk-optimization-actions')).toBeHidden({ timeout: 15000 }); - await expect(page.locator('[data-status="cancelled"]').first()).toHaveText('Cancelled'); - await expect(page.getByText('All images are processed')).not.toBeVisible(); + // Images that were being compressed finish, then the page shows what is left. + await expect(page.getByText('Ready to compress')).toBeVisible({ timeout: 20000 }); + await expect(page.getByRole('heading', { name: /^\d images? to compress$/ })).toBeVisible(); + await expect(page.getByTestId('bulk-item-status-0')).toHaveText('Waiting'); }); test('stop when the account runs out of credits', async () => { @@ -276,17 +242,11 @@ test.describe('bulkoptimization', () => { await uploadImages(page, 'input-example.jpg', 6, { generateSizes: false }); await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await page.getByRole('button', { name: 'Start Bulk Optimization' }).click(); - - // The first image to hit the limit takes the rest off the queue. - await expect(page.getByText('Optimization stopped early.')).toBeVisible({ timeout: 15000 }); - await expect(page.locator('[data-status="cancelled"]').first()).toHaveText('Stopped'); - }); + await page.getByRole('button', { name: 'Compress 6 images' }).click(); + await expect(page.getByText('Compressing', { exact: true })).toBeVisible(); - test('should display tooltips', async () => { - await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - const tooltips = await page.locator('div.tip').all(); - await expect(tooltips.length).toEqual(1); + // The first image to hit the limit takes the rest off the queue, and the page shows what is left. + await expect(page.getByRole('heading', { name: '6 images to compress' })).toBeVisible({ timeout: 30000 }); }); test('will only apply a conversion when images are already compressed but not converted', async ({ page }) => { @@ -305,23 +265,10 @@ test.describe('bulkoptimization', () => { // apply bulk optimization await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization'); - await Promise.all([ - page.waitForResponse(res => - res.url().includes('admin-ajax.php') && res.status() === 200 - ), - page.locator('#id-start').click(), - ]); - - // we are expecting 2 unoptimized images sizes = 2 conversion and 1 compression - // expect two rows in the optimization items table - const optimizationRows = page.locator('#optimization-items tbody tr'); - await expect(optimizationRows).toHaveCount(2); - - // first row should have "1 compressed and 1 converted" - // second row should have "1 converted" - await expect(page.getByTestId(`bulk-item-status-1`)).toContainText('1 compressed 1 converted'); - await expect(page.getByTestId(`bulk-item-status-0`)).toContainText('1 converted'); - - // this should have cost us 3 credits + await page.getByRole('button', { name: 'Compress 2 images' }).click(); + + // both images end up optimized: one only converted, the other compressed and converted + await expect(page.getByRole('heading', { name: 'All 2 images are compressed' })).toBeVisible({ timeout: 15000 }); + await expect(page.locator('.tiny-bulk-item[data-status="compressed"]')).toHaveCount(2); }); }); diff --git a/test/integration/dashboardwidget.spec.ts b/test/integration/dashboardwidget.spec.ts index 6850042d..f27c76d2 100644 --- a/test/integration/dashboardwidget.spec.ts +++ b/test/integration/dashboardwidget.spec.ts @@ -95,7 +95,7 @@ test.describe('dashboardwidget', () => { await widget().getByRole('link', { name: 'Compress 1 image' }).click(); await expect(page).toHaveURL(/page=tiny-bulk-optimization$/); - await expect(page.locator('#compression-progress-bar')).toHaveText('1 / 1 (100%)', { timeout: 15000 }); + await expect(page.getByRole('heading', { name: 'All 1 image is compressed' })).toBeVisible({ timeout: 15000 }); }); test('start flag without a nonce does not start the bulk optimization', async () => { @@ -106,8 +106,8 @@ test.describe('dashboardwidget', () => { await page.goto('/wp-admin/upload.php?page=tiny-bulk-optimization&start=1'); await expect(page).toHaveURL(/page=tiny-bulk-optimization$/); - await expect(page.locator('#id-start')).toBeVisible(); - await expect(page.locator('#compression-progress-bar')).toHaveText('0 / 1 (0%)'); + await expect(page.getByRole('button', { name: 'Compress 1 image' })).toBeVisible(); + await expect(page.getByTestId('bulk-item-status-0')).toHaveText('Waiting'); }); test('upgrade shows how to get more credits', async () => { diff --git a/test/unit/TinyBulkOptimizationTest.php b/test/unit/TinyBulkOptimizationTest.php index 505b40dd..6c1200fb 100644 --- a/test/unit/TinyBulkOptimizationTest.php +++ b/test/unit/TinyBulkOptimizationTest.php @@ -217,10 +217,18 @@ public function test_get_optimization_statistics() array( 'ID' => 1, 'post_title' => 'I am uncompressed and unconverted', + 'file' => 'image-4350.png', + 'sizes' => 3, + 'bytes' => 233568, + 'thumbnail' => '/wp-content/uploads/2023/05/image-4350-150x150.png', ), array( 'ID' => 4350, 'post_title' => 'I am compressed but not converted', + 'file' => 'image-4351.jpg', + 'sizes' => 3, + 'bytes' => 223568, + 'thumbnail' => '/wp-content/uploads/2023/05/image-4351-150x150.jpg', ), ), 'display-percentage' => 21.7, diff --git a/test/unit/TinyCompressTest.php b/test/unit/TinyCompressTest.php deleted file mode 100644 index a2488e65..00000000 --- a/test/unit/TinyCompressTest.php +++ /dev/null @@ -1,33 +0,0 @@ -assertEqualsWithDelta( - 150 * 0, - Tiny_Compress::estimate_cost(150, 0), - 0.001 - ); - } - - public function test_estimate_cost_normal_and_free() - { - $this->assertEqualsWithDelta( - 350 * 0 + 2650 * 0.009, - Tiny_Compress::estimate_cost(3000, 150), - 0.001 - ); - } - - public function test_estimate_cost_cheap_and_normal_and_free() - { - $this->assertEqualsWithDelta( - 500 * 0 + 9500 * 0.009 + 40000 * 0.002, - Tiny_Compress::estimate_cost(50000, 0), - 0.001 - ); - } -} diff --git a/test/unit/TinyPluginAjaxTest.php b/test/unit/TinyPluginAjaxTest.php index 562247aa..53a1c6ed 100644 --- a/test/unit/TinyPluginAjaxTest.php +++ b/test/unit/TinyPluginAjaxTest.php @@ -37,6 +37,26 @@ public function test_bulk_queue_handlers_refuse_a_user_without_permission_with_a $this->assert_bulk_queue_handlers_refuse_with_a_403(); } + public function test_bulk_queue_status_includes_the_compression_count() { + $this->wp->addOption( 'tinypng_status', 42 ); + $this->wp->addMethod( 'update_meta_cache' ); + $this->wp->stub( 'check_ajax_referer', function () { + return true; + } ); + $this->wp->stub( 'current_user_can', function () { + return true; + } ); + $response = null; + $this->wp->addMethod( 'wp_send_json_success' ); + $this->wp->stub( 'wp_send_json_success', function ( $data ) use ( &$response ) { + $response = $data; + } ); + + $this->subject->ajax_bulk_queue_status(); + + $this->assertEquals( 42, $response['compression_count'] ); + } + private function assert_bulk_queue_handlers_refuse_with_a_403() { $this->wp->addMethod( 'status_header' ); $this->wp->addMethod( 'wp_die' ); diff --git a/test/unit/TinyPluginTest.php b/test/unit/TinyPluginTest.php index 5971aaf8..190fee16 100644 --- a/test/unit/TinyPluginTest.php +++ b/test/unit/TinyPluginTest.php @@ -261,42 +261,6 @@ public function test_wrong_metadata_should_save_tiny_metadata() $this->assertEquals(2, count($this->wp->getCalls('update_post_meta'))); } - public function test_get_bulk_cost() - { - $virtual_compressed_image = array( - 'path' => '2015/09', - 'images' => array( - array( - "file" => "uncompressed.png", - "size" => 137856, - ), - ) - ); - $this->wp->createImagesFromJSON($virtual_compressed_image); - - $wpdb_results = array( - array( - 'ID' => 1, - 'post_title' => 'Uncompressed Image', - 'meta_value' => serialize(array( - 'width' => 1256, - 'height' => 1256, - 'file' => '2015/09/uncompressed.png', - 'sizes' => array() - )), - 'tiny_meta_value' => '' - ), - ); - - $stats = Tiny_Bulk_Optimization::get_optimization_statistics(new Tiny_Settings(), $wpdb_results); - $free_limit = 500; - $cost = Tiny_Compress::estimate_cost( - $stats['available-unoptimized-sizes'], - $free_limit, - ); - - $this->assertEquals($cost, 0.01, 0.0001, 'one compression is $0,009, rounded to 0.01',); - } public function test_when_image_is_uncompressed_and_conversion_enabled_cost_two_credits() { @@ -328,25 +292,8 @@ public function test_when_image_is_uncompressed_and_conversion_enabled_cost_two_ ), ); - // Mock settings with compression count - $mock_settings = $this->createMock(Tiny_Settings::class); - $mock_settings->method('get_conversion_enabled')->willReturn(true); - $mock_settings->method('get_compression_count')->willReturn(500); - - $tiny_plugin = new Tiny_Plugin(); - - // because settings is private we need reflection - $ref = new \ReflectionClass($tiny_plugin); - $settings_prop = $ref->getProperty('settings'); - $settings_prop->setAccessible(true); - $settings_prop->setValue($tiny_plugin, $mock_settings); - $stats = Tiny_Bulk_Optimization::get_optimization_statistics(new Tiny_Settings(), $wpdb_results); $this->assertEquals($stats['estimated_credit_use'], 2, 'one uncompressed image that will be converted is 2 credits'); - - $cost = $tiny_plugin->get_estimated_bulk_cost($stats['estimated_credit_use']); - - $this->assertEquals($cost, 0.02, 0.0001, 'a conversion will cost 2 credits at $0.009 each when 500 compressions already used'); } /** @@ -405,23 +352,8 @@ public function test_when_files_is_compressed_will_only_cost_1_credit() ), ); - // Mock settings with compression count - $mock_settings = $this->createMock(Tiny_Settings::class); - $mock_settings->method('get_conversion_enabled')->willReturn(true); - $mock_settings->method('get_compression_count')->willReturn(500); - - $tiny_plugin = new Tiny_Plugin(); - - // because settings is private we need reflection - $ref = new \ReflectionClass($tiny_plugin); - $settings_prop = $ref->getProperty('settings'); - $settings_prop->setAccessible(true); - $settings_prop->setValue($tiny_plugin, $mock_settings); - $stats = Tiny_Bulk_Optimization::get_optimization_statistics(new Tiny_Settings(), $wpdb_results); - $cost = $tiny_plugin->get_estimated_bulk_cost($stats['estimated_credit_use']); - - $this->assertEquals($cost, 0.01, 0.0001, 'a compressed image that will be converted will cost 1 credit at $0.009 (rounded $0.01) each when 500 compressions already used'); + $this->assertEquals($stats['estimated_credit_use'], 1, 'a compressed image that will be converted costs 1 credit'); } public function test_conversion_enabled_but_filtered_off_not_load_picture() diff --git a/test/unit/TinySettingsAdminTest.php b/test/unit/TinySettingsAdminTest.php index ef639e3a..e37f57c5 100644 --- a/test/unit/TinySettingsAdminTest.php +++ b/test/unit/TinySettingsAdminTest.php @@ -586,4 +586,26 @@ public function test_should_count_credits_per_image_for_each_size() { public function test_should_count_credits_per_image_with_resize_and_conversion() { $this->assertEquals( 12, Tiny_Settings::get_credits_per_image( 5, true, false, true ) ); } + + public function test_render_credits_links_to_settings_when_asked() { + $this->assertStringContainsString( 'Change settings', $this->render_credits( true ) ); + } + + public function test_render_credits_does_not_link_to_settings_by_default() { + $output = $this->render_credits( false ); + $this->assertStringContainsString( 'How credits are used', $output ); + $this->assertStringNotContainsString( 'Change settings', $output ); + } + + private function render_credits( $show_settings_link ) { + $this->wp->addMethod( '_n' ); + $this->wp->stub( '_n', function ( $single, $plural, $number ) { + return 1 === $number ? $single : $plural; + } ); + $this->wp->addMethod( 'number_format_i18n' ); + $this->wp->addMethod( 'esc_url' ); + ob_start(); + $this->subject->render_credits( $show_settings_link ); + return ob_get_clean(); + } } From 5da248da46906ef8d926aa8e9e30ad1ec063ca12 Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 6 Nov 2026 16:49:47 +0100 Subject: [PATCH 62/68] divide by zero fix --- src/js/bulk-optimization.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/js/bulk-optimization.js b/src/js/bulk-optimization.js index 2f6d0f48..d0bec2cf 100644 --- a/src/js/bulk-optimization.js +++ b/src/js/bulk-optimization.js @@ -139,7 +139,9 @@ } function updateNumbers() { - const runPercentage = Math.floor(finished / items.length * 100) + '%'; + const hasItems = items.length > 0; + const itemsRunningPerc = hasItems ? Math.floor(finished / items.length * 100) : 0; + const runPercentage = `${itemsRunningPerc}%`; setText('run-done', finished.toLocaleString()); setText('run-percentage', runPercentage); element('run-bar').style.width = runPercentage; @@ -165,10 +167,10 @@ } // Shows the done hero when every image was compressed. Otherwise the run was - // paused or stopped, or some images failed, and the page reloads to show - // what is left. + // paused or stopped, some images failed, or the page had no images listed, + // and the page reloads to show what is left. function finishRun() { - if (pending.length > 0 || compressed < items.length) { + if (items.length === 0 || pending.length > 0 || compressed < items.length) { location.reload(); return; } @@ -202,7 +204,9 @@ }); updateNumbers(); - if (pending.length > 0 && (running || finished > finishedBefore)) { + // A run can still be going when this page has no images waiting for it, + // e.g. when the page loaded just as the run was finishing up. + if (running || (pending.length > 0 && finished > finishedBefore)) { setTimeout(pollStatus, POLL_INTERVAL); } else { finishRun(); @@ -239,7 +243,9 @@ function showRun() { const title = element('list-title'); - title.textContent = title.getAttribute('data-compressing'); + if (title) { + title.textContent = title.getAttribute('data-compressing'); + } showHero('compressing'); updateNumbers(); } From 6d93798b37fe67dc0d2fdc557865ad70a82eb2bb Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 6 Nov 2026 20:15:02 +0100 Subject: [PATCH 63/68] simplify rendering --- src/class-tiny-plugin.php | 12 +++--------- src/class-tiny-settings.php | 7 +++---- src/views/bulk-optimization.php | 6 +----- src/views/settings-credits.php | 1 + 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index c93bf199..ccdd2f27 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -912,15 +912,9 @@ private function render_compress_details( $tiny_image ) { } public function render_bulk_optimization_page() { - /* - * The account card asks the API for the account status, which also - * refreshes the credits left, so it renders before the rest. - */ - ob_start(); - $this->settings->render_account_status( true ); - $account_status = ob_get_clean(); - - $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); + $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); + $this->settings->get_compressor()->get_status(); + $widget = $this->dashboard->get_widget_data( $stats ); $state = $widget['state']; $compression_count = intval( $this->settings->get_compression_count() ); diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 45ae2e54..e31ff1ce 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -193,9 +193,7 @@ public function image_sizes_notice() { } public function account_status() { - if ( current_user_can( 'manage_options' ) ) { - $this->render_account_status(); - } + $this->render_account_status(); exit(); } @@ -821,8 +819,9 @@ public function after_compress_callback( $compressor ) { * page, for pages other than the settings page. */ public function render_account_status( $link_to_settings = false ) { + $is_allowed = current_user_can( 'manage_options' ); $key = $this->get_api_key(); - if ( ! empty( $key ) ) { + if ( $is_allowed && ! empty( $key ) ) { if ( $this->refresh_api_key_pending() ) { $status = (object) array( 'ok' => true, diff --git a/src/views/bulk-optimization.php b/src/views/bulk-optimization.php index a7ae20a4..99315392 100644 --- a/src/views/bulk-optimization.php +++ b/src/views/bulk-optimization.php @@ -5,7 +5,6 @@ * @var array $stats See Tiny_Bulk_Optimization::get_optimization_statistics(). * @var array $widget See Tiny_Dashboard::get_widget_data(). * @var string $state The widget state, or no_sizes. - * @var string $account_status The rendered account card. * @var int $compression_count Compressions made this month so far. * @var bool $start_on_load * @var Tiny_Plugin $this @@ -133,10 +132,7 @@
      - + settings->render_account_status( true ); ?>
      diff --git a/src/views/settings-credits.php b/src/views/settings-credits.php index b5100c53..e5f136f0 100644 --- a/src/views/settings-credits.php +++ b/src/views/settings-credits.php @@ -2,6 +2,7 @@ /** * Settings section for showing credit cost per image * + * @var bool $show_settings_link boolean wether to link to the settings page * @var int $tiny_sizes_count number of sizes that are compressed * @var bool $tiny_resize wether or not the original size is resized * @var bool $tiny_wr2x plugin wr2x compressed causes images to be compressed twice From 828a4302acb2fc05e89baf018e5d40aa88e9c7d3 Mon Sep 17 00:00:00 2001 From: tijmen Date: Fri, 6 Nov 2026 20:38:42 +0100 Subject: [PATCH 64/68] fix translations --- src/class-tiny-plugin.php | 39 +++++++++-------- src/js/bulk-optimization.js | 63 ++++++++++++++++------------ src/views/bulk-optimization-hero.php | 2 +- 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index ccdd2f27..7a1b9b10 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -321,9 +321,7 @@ public function enqueue_scripts( $hook ) { 'L10nPause' => __( 'Pause', 'tiny-compress-images' ), 'L10nPausing' => __( 'Pausing...', 'tiny-compress-images' ), /* translators: %s: number of image sizes */ - 'L10nSize' => __( '%s size', 'tiny-compress-images' ), - /* translators: %s: number of image sizes */ - 'L10nSizes' => __( '%s sizes', 'tiny-compress-images' ), + 'L10nSizeCount' => __( 'Sizes: %s', 'tiny-compress-images' ), /* translators: %1$s: compressed size, e.g. 1.4 MB, %2$s: percentage saved, e.g. 56% */ 'L10nSmaller' => __( '%1$s, %2$s smaller', 'tiny-compress-images' ), /* translators: %s: number of images still to compress */ @@ -334,23 +332,30 @@ public function enqueue_scripts( $hook ) { 'Less than a minute left.', 'tiny-compress-images' ), - /* translators: %s: number of minutes */ - 'L10nMinuteLeft' => __( 'About %s minute left.', 'tiny-compress-images' ), - /* translators: %s: number of minutes */ - 'L10nMinutesLeft' => __( 'About %s minutes left.', 'tiny-compress-images' ), - /* translators: %s: number of hours */ - 'L10nHourLeft' => __( 'About %s hour left.', 'tiny-compress-images' ), - /* translators: %s: number of hours */ - 'L10nHoursLeft' => __( 'About %s hours left.', 'tiny-compress-images' ), - /* translators: %1$s: bytes saved, e.g. 14.9 MB, %2$s: credits used, e.g. 165 credits */ + /* translators: %s: number of minutes, with the unit abbreviated so it needs no plural */ + 'L10nMinutesLeft' => __( 'About %s min left.', 'tiny-compress-images' ), + /* translators: %s: number of hours, with the unit abbreviated so it needs no plural */ + 'L10nHoursLeft' => __( 'About %s h left.', 'tiny-compress-images' ), + /* translators: %1$s: bytes saved, e.g. 14.9 MB, %2$s: number of credits used */ 'L10nRunStatus' => __( - '%1$s saved so far, %2$s used.', + '%1$s saved so far. Credits used: %2$s.', 'tiny-compress-images' ), - /* translators: %s: number of credits */ - 'L10nCredit' => __( '%s credit', 'tiny-compress-images' ), - /* translators: %s: number of credits */ - 'L10nCredits' => __( '%s credits', 'tiny-compress-images' ), + /* + * For Intl.NumberFormat, which only takes the language and region: + * WordPress variants like pt_PT_ao90 make it throw. + */ + 'locale' => implode( + '-', + array_slice( explode( '_', get_locale() ), 0, 2 ) + ), + 'L10nUnits' => array( + _x( 'B', 'unit symbol' ), + _x( 'KB', 'unit symbol' ), + _x( 'MB', 'unit symbol' ), + _x( 'GB', 'unit symbol' ), + _x( 'TB', 'unit symbol' ), + ), 'L10nInternalError' => __( 'Internal error', 'tiny-compress-images' ), 'L10nBackgroundNotice' => __( // phpcs:ignore Generic.Files.LineLength diff --git a/src/js/bulk-optimization.js b/src/js/bulk-optimization.js index d0bec2cf..e6fe7e31 100644 --- a/src/js/bulk-optimization.js +++ b/src/js/bulk-optimization.js @@ -12,7 +12,7 @@ let creditsUsed = 0; function element(name) { - return document.querySelector('[data-tiny-bulk="' + name + '"]'); + return document.querySelector(`[data-tiny-bulk="${name}"]`); } function setText(name, text) { @@ -31,18 +31,29 @@ }); } - function plural(count, singular, pluralForm) { - return format(count === 1 ? singular : pluralForm, count.toLocaleString()); - } + // Numbers follow the WordPress locale, like PHP's number_format_i18n. + const numberFormat = new Intl.NumberFormat(tinyCompress.locale); + const sizeFormat = new Intl.NumberFormat(tinyCompress.locale, { + minimumFractionDigits: 1, + maximumFractionDigits: 1 + }); + /** + * Formats bytes in the largest unit that keeps the value at 1 or more, with + * one decimal like PHP's size_format( $bytes, 1 ). Nothing or less than + * nothing shows as 0 bytes. + * @param number bytes + */ function formatBytes(bytes) { - const units = ['B', 'KB', 'MB', 'GB', 'TB']; + const units = tinyCompress.L10nUnits; + let value = Math.max(0, bytes || 0); let unit = 0; - while (bytes >= 1024 && unit < units.length - 1) { - bytes /= 1024; + while (value >= 1024 && unit < units.length - 1) { + value /= 1024; unit++; } - return bytes.toLocaleString(undefined, { maximumFractionDigits: 1 }) + ' ' + units[unit]; + const valueFormat = unit === 0 ? numberFormat : sizeFormat; + return `${valueFormat.format(value)} ${units[unit]}`; } async function post(action, data) { @@ -85,14 +96,13 @@ const title = document.createElement('strong'); title.textContent = item.post_title; const details = document.createElement('span'); - details.textContent = item.file + ', ' + - plural(item.sizes, tinyCompress.L10nSize, tinyCompress.L10nSizes) + ', ' + - formatBytes(item.bytes); + const sizeCount = format(tinyCompress.L10nSizeCount, numberFormat.format(item.sizes)); + details.textContent = `${item.file}, ${sizeCount}, ${formatBytes(item.bytes)}`; name.append(title, details); const status = document.createElement('span'); status.className = 'tiny-bulk-item-status'; - status.setAttribute('data-testid', 'bulk-item-status-' + i); + status.setAttribute('data-testid', `bulk-item-status-${i}`); status.textContent = tinyCompress.L10nWaiting; row.append(thumbnail, name, status); @@ -119,7 +129,7 @@ setRowStatus(i, 'compressed', format( tinyCompress.L10nSmaller, result.optimized_total_size, - Math.round(result.savings) + '%' + `${Math.round(result.savings)}%` )); } } @@ -133,36 +143,37 @@ return tinyCompress.L10nLessThanMinute; } if (seconds < 90 * 60) { - return plural(Math.round(seconds / 60), tinyCompress.L10nMinuteLeft, tinyCompress.L10nMinutesLeft); + return format(tinyCompress.L10nMinutesLeft, numberFormat.format(Math.round(seconds / 60))); } - return plural(Math.round(seconds / 3600), tinyCompress.L10nHourLeft, tinyCompress.L10nHoursLeft); + return format(tinyCompress.L10nHoursLeft, numberFormat.format(Math.round(seconds / 3600))); } function updateNumbers() { const hasItems = items.length > 0; const itemsRunningPerc = hasItems ? Math.floor(finished / items.length * 100) : 0; const runPercentage = `${itemsRunningPerc}%`; - setText('run-done', finished.toLocaleString()); + setText('run-done', numberFormat.format(finished)); setText('run-percentage', runPercentage); element('run-bar').style.width = runPercentage; - setText('run-status', secondsLeftText() + ' ' + format( + const runStatus = format( tinyCompress.L10nRunStatus, formatBytes(savedBytes), - plural(creditsUsed, tinyCompress.L10nCredit, tinyCompress.L10nCredits) - )); + numberFormat.format(creditsUsed) + ); + setText('run-status', `${secondsLeftText()} ${runStatus}`); const libraryCompressed = config.imagesOptimized + compressed; const libraryPercentage = Math.floor(libraryCompressed / config.imagesTotal * 100); - setText('library-percentage', libraryPercentage.toLocaleString()); - setText('library-compressed', libraryCompressed.toLocaleString()); - setText('library-todo', format(tinyCompress.L10nToGo, (config.imagesRemaining - compressed).toLocaleString())); - element('library-bar').style.width = libraryPercentage + '%'; - setText('waiting', pending.length.toLocaleString()); + setText('library-percentage', numberFormat.format(libraryPercentage)); + setText('library-compressed', numberFormat.format(libraryCompressed)); + setText('library-todo', format(tinyCompress.L10nToGo, numberFormat.format(config.imagesRemaining - compressed))); + element('library-bar').style.width = `${libraryPercentage}%`; + setText('waiting', numberFormat.format(pending.length)); const librarySaved = config.bytesSaved + savedBytes; - setText('stat-compressed', libraryCompressed.toLocaleString()); + setText('stat-compressed', numberFormat.format(libraryCompressed)); setText('stat-saved', formatBytes(librarySaved)); - setText('stat-average', Math.round(librarySaved / config.initialSize * 100) + '%'); + setText('stat-average', `${Math.round(librarySaved / config.initialSize * 100)}%`); setText('done-saved', formatBytes(librarySaved)); } diff --git a/src/views/bulk-optimization-hero.php b/src/views/bulk-optimization-hero.php index ec25b7c0..d9b51cb6 100644 --- a/src/views/bulk-optimization-hero.php +++ b/src/views/bulk-optimization-hero.php @@ -189,7 +189,7 @@ } elseif ( null !== $widget['remaining_credits'] ) { printf( /* translators: %1$s: estimated number of credits, %2$s: number of credits left */ - esc_html( _n( 'Uses about %1$s of your %2$s credits.', 'Uses about %1$s of your %2$s credits.', $widget['estimated_credit_use'], 'tiny-compress-images' ) ), + esc_html__( 'Uses about %1$s of your %2$s credits.', 'tiny-compress-images' ), esc_html( number_format_i18n( $widget['estimated_credit_use'] ) ), esc_html( number_format_i18n( $widget['remaining_credits'] ) ) ); From c02d2c5d9c998d45960b6d3a90d584ee3116c3d0 Mon Sep 17 00:00:00 2001 From: tijmen Date: Sat, 7 Nov 2026 22:35:32 +0100 Subject: [PATCH 65/68] refactor --- src/js/bulk-optimization.js | 50 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/js/bulk-optimization.js b/src/js/bulk-optimization.js index e6fe7e31..d9cf3530 100644 --- a/src/js/bulk-optimization.js +++ b/src/js/bulk-optimization.js @@ -11,12 +11,12 @@ let savedBytes = 0; let creditsUsed = 0; - function element(name) { + function findPageElement(name) { return document.querySelector(`[data-tiny-bulk="${name}"]`); } function setText(name, text) { - const target = element(name); + const target = findPageElement(name); if (target) { target.textContent = text; } @@ -154,7 +154,7 @@ const runPercentage = `${itemsRunningPerc}%`; setText('run-done', numberFormat.format(finished)); setText('run-percentage', runPercentage); - element('run-bar').style.width = runPercentage; + findPageElement('run-bar').style.width = runPercentage; const runStatus = format( tinyCompress.L10nRunStatus, formatBytes(savedBytes), @@ -167,7 +167,7 @@ setText('library-percentage', numberFormat.format(libraryPercentage)); setText('library-compressed', numberFormat.format(libraryCompressed)); setText('library-todo', format(tinyCompress.L10nToGo, numberFormat.format(config.imagesRemaining - compressed))); - element('library-bar').style.width = `${libraryPercentage}%`; + findPageElement('library-bar').style.width = `${libraryPercentage}%`; setText('waiting', numberFormat.format(pending.length)); const librarySaved = config.bytesSaved + savedBytes; @@ -185,9 +185,9 @@ location.reload(); return; } - const title = element('list-title'); + const title = findPageElement('list-title'); title.textContent = title.getAttribute('data-done'); - element('list-waiting').hidden = true; + findPageElement('list-waiting').hidden = true; setText('library-todo', format(tinyCompress.L10nToCompress, '0')); showHero('done'); } @@ -253,7 +253,7 @@ } function showRun() { - const title = element('list-title'); + const title = findPageElement('list-title'); if (title) { title.textContent = title.getAttribute('data-compressing'); } @@ -282,7 +282,11 @@ } async function pauseRun() { - const button = element('pause'); + const button = findPageElement('pause'); + if ( !button ) { + return; + } + button.disabled = true; button.textContent = tinyCompress.L10nPausing; try { @@ -294,19 +298,13 @@ } } - // The dashboard widget opens this page with &start=1 and a nonce, which the - // server checks. Start right away, then drop both from the URL so a reload - // does not start again. - function startFromUrl() { - const url = new URL(location.href); - if (url.searchParams.has('start')) { - url.searchParams.delete('start'); - url.searchParams.delete('_wpnonce'); - history.replaceState(null, '', url); - } - if (config.startOnLoad && !config.running && element('start')) { - startRun(); - } + // The dashboard widget opens this page with &start=1 and a nonce. + // Both are removed from the URL so a reload does not start again. + const url = new URL(location.href); + if (url.searchParams.has('start')) { + url.searchParams.delete('start'); + url.searchParams.delete('_wpnonce'); + history.replaceState(null, '', url); } drawRows(); @@ -314,8 +312,10 @@ document.querySelectorAll('[data-tiny-bulk="start"]').forEach(function(button) { button.addEventListener('click', startRun); }); - if (element('pause')) { - element('pause').addEventListener('click', pauseRun); + + const pauseElement = findPageElement('pause'); + if (pauseElement) { + pauseElement.addEventListener('click', pauseRun); } if (config.running) { @@ -323,7 +323,7 @@ setText('run-notice', tinyCompress.L10nBackgroundNotice); showRun(); pollStatus(); - } else { - startFromUrl(); + } else if (config.startOnLoad && findPageElement('start')) { + startRun(); } }).call(); From 66439cb9cdada07001fe2e1a0b078df2b151d185 Mon Sep 17 00:00:00 2001 From: tijmen Date: Sat, 7 Nov 2026 22:46:16 +0100 Subject: [PATCH 66/68] stop polling on 5 consecutive failures --- src/js/bulk-optimization.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/js/bulk-optimization.js b/src/js/bulk-optimization.js index d9cf3530..8cec388e 100644 --- a/src/js/bulk-optimization.js +++ b/src/js/bulk-optimization.js @@ -1,6 +1,7 @@ (function() { const POLL_INTERVAL = 2000; const POLL_WINDOW = 10; + const POLL_ATTEMPTS = 5; const PAGE_WORKERS = 5; const config = window.tinyBulk; const items = config.items; @@ -10,6 +11,7 @@ let compressed = 0; let savedBytes = 0; let creditsUsed = 0; + let failedPolls = 0; function findPageElement(name) { return document.querySelector(`[data-tiny-bulk="${name}"]`); @@ -214,6 +216,7 @@ } }); updateNumbers(); + failedPolls = 0; // A run can still be going when this page has no images waiting for it, // e.g. when the page loaded just as the run was finishing up. @@ -223,10 +226,11 @@ finishRun(); } } catch (error) { - if (error.status === 403) { - setText('run-notice', tinyCompress.L10nInternalError); - } else { + failedPolls++; + if (failedPolls < POLL_ATTEMPTS) { setTimeout(pollStatus, POLL_INTERVAL); + } else { + setText('run-notice', tinyCompress.L10nInternalError); } } } From 64bb2f0dc8c323b06a4cb0eb915cb6e5a45fd571 Mon Sep 17 00:00:00 2001 From: tijmen Date: Sat, 7 Nov 2026 22:52:55 +0100 Subject: [PATCH 67/68] remove unused strong and stats --- src/class-tiny-plugin.php | 36 +++------------------------------ src/views/bulk-optimization.php | 1 - 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index 7a1b9b10..0bbdadcb 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -634,31 +634,12 @@ private function bulk_image_result( $tiny_image, array $result ) { $this->settings->get_active_tinify_sizes() ); - $result['image_sizes_compressed'] = $image_statistics['image_sizes_compressed']; - $result['image_sizes_converted'] = $image_statistics['image_sizes_converted']; - $result['image_sizes_optimized'] = $image_statistics['image_sizes_optimized']; - - $result['initial_total_size'] = size_format( - $image_statistics['initial_total_size'], - 1 - ); - $result['optimized_total_size'] = size_format( $image_statistics['compressed_total_size'], 1 ); - $result['savings'] = $tiny_image->get_savings( $image_statistics ); - $result['status'] = $this->settings->get_status(); - $result['thumbnail'] = wp_get_attachment_image( - $tiny_image->get_id(), - array( '30', '30' ), - true, - array( - 'class' => 'pinkynail', - 'alt' => '', - ) - ); + $result['savings'] = $tiny_image->get_savings( $image_statistics ); return $result; } @@ -731,10 +712,7 @@ public function ajax_bulk_queue_optimize_next() { } /** - * Where the images the bulk optimization page is waiting for stand. - * - * Finished images come with the same details the page gets when it - * compresses an image itself, so it can show them the same way. + * Show a running background optimize status if any is running */ public function ajax_bulk_queue_status() { if ( ! check_ajax_referer( 'tiny-compress', '_nonce', false ) || @@ -743,12 +721,9 @@ public function ajax_bulk_queue_status() { wp_die( -1, 403 ); } - $ids = isset( $_POST['ids'] ) ? + $ids = isset( $_POST['ids'] ) ? explode( ',', sanitize_text_field( wp_unslash( $_POST['ids'] ) ) ) : array(); - $library_size = isset( $_POST['current_size'] ) ? - intval( wp_unslash( $_POST['current_size'] ) ) - : 0; $running = $this->background_optimizer->is_running(); @@ -767,11 +742,6 @@ public function ajax_bulk_queue_status() { $item['result'] ) ); - - /* The page applies the results in order, each on top of the last. */ - $library_size += $item['result']['size_change']; - - $item['result']['human_readable_library_size'] = size_format( $library_size, 2 ); } $items[ $id ] = $item; diff --git a/src/views/bulk-optimization.php b/src/views/bulk-optimization.php index 99315392..9c91fe55 100644 --- a/src/views/bulk-optimization.php +++ b/src/views/bulk-optimization.php @@ -24,7 +24,6 @@ $has_library_bar = ! in_array( $state, array( 'pending', 'empty', 'no_sizes' ), true ); $has_list = count( $items ) > 0 && 'pending' !== $state; -$strong = array( 'strong' => array() ); ?>

      From 0e8e855f2ed26755a3d98481c34c92f019ba30df Mon Sep 17 00:00:00 2001 From: tijmen Date: Sat, 7 Nov 2026 22:54:39 +0100 Subject: [PATCH 68/68] cleanup unused stats --- src/class-tiny-bulk-optimization.php | 22 +++++++++------------- test/unit/TinyBulkOptimizationTest.php | 2 -- test/unit/Tiny_Dashboard_Test.php | 2 -- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/class-tiny-bulk-optimization.php b/src/class-tiny-bulk-optimization.php index bf96bf90..10c12811 100644 --- a/src/class-tiny-bulk-optimization.php +++ b/src/class-tiny-bulk-optimization.php @@ -24,14 +24,12 @@ class Tiny_Bulk_Optimization { const PAGING_SIZE = 25000; public static function get_optimization_statistics( $settings, $result = null ) { - $stats = array(); - $stats['uploaded-images'] = 0; - $stats['optimized-image-sizes'] = 0; - $stats['available-unoptimized-sizes'] = 0; - $stats['optimized-library-size'] = 0; - $stats['unoptimized-library-size'] = 0; - $stats['estimated_credit_use'] = 0; - $stats['available-for-optimization'] = array(); + $stats = array(); + $stats['uploaded-images'] = 0; + $stats['optimized-library-size'] = 0; + $stats['unoptimized-library-size'] = 0; + $stats['estimated_credit_use'] = 0; + $stats['available-for-optimization'] = array(); if ( is_null( $result ) ) { $last_image_id = null; @@ -127,11 +125,9 @@ private static function populate_optimization_statistics( $settings, $result, $s $image_stats = $tiny_image->get_statistics( $active_sizes, $active_tinify_sizes ); ++$stats['uploaded-images']; - $stats['estimated_credit_use'] += $image_stats['available_uncompressed_sizes']; - $stats['available-unoptimized-sizes'] += $image_stats['available_unoptimized_sizes']; - $stats['optimized-image-sizes'] += $image_stats['image_sizes_optimized']; - $stats['optimized-library-size'] += $image_stats['compressed_total_size']; - $stats['unoptimized-library-size'] += $image_stats['initial_total_size']; + $stats['estimated_credit_use'] += $image_stats['available_uncompressed_sizes']; + $stats['optimized-library-size'] += $image_stats['compressed_total_size']; + $stats['unoptimized-library-size'] += $image_stats['initial_total_size']; if ( $conversion_enabled ) { $stats['estimated_credit_use'] += $image_stats['available_unconverted_sizes']; diff --git a/test/unit/TinyBulkOptimizationTest.php b/test/unit/TinyBulkOptimizationTest.php index 6c1200fb..742150a6 100644 --- a/test/unit/TinyBulkOptimizationTest.php +++ b/test/unit/TinyBulkOptimizationTest.php @@ -209,8 +209,6 @@ public function test_get_optimization_statistics() $this->assertEquals( array( 'uploaded-images' => 3, - 'optimized-image-sizes' => 3, - 'available-unoptimized-sizes' => 6, 'optimized-library-size' => 529136, 'unoptimized-library-size' => 676136, 'available-for-optimization' => array( diff --git a/test/unit/Tiny_Dashboard_Test.php b/test/unit/Tiny_Dashboard_Test.php index 71c26962..f0f4b7e8 100644 --- a/test/unit/Tiny_Dashboard_Test.php +++ b/test/unit/Tiny_Dashboard_Test.php @@ -35,8 +35,6 @@ private function stats($uploaded, $remaining, $unoptimized_size = 0, $optimized_ { return array( 'uploaded-images' => $uploaded, - 'optimized-image-sizes' => 0, - 'available-unoptimized-sizes' => 0, 'optimized-library-size' => $optimized_size, 'unoptimized-library-size' => $unoptimized_size, 'estimated_credit_use' => $credit_use,